diff --git a/core/src/avm1/activation.rs b/core/src/avm1/activation.rs index 4d43ef138fb6..8b532f580cd6 100644 --- a/core/src/avm1/activation.rs +++ b/core/src/avm1/activation.rs @@ -1460,7 +1460,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { ) -> Result, Error<'gc>> { let val = self.context.avm1.pop(); if val.as_bool(self.current_swf_version()) { - self.seek(jump_offset, reader, data)?; + reader.seek(data.as_ref(), jump_offset); } Ok(FrameControl::Continue) } @@ -1543,7 +1543,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { reader: &mut Reader<'b>, data: &'b SwfSlice, ) -> Result, Error<'gc>> { - self.seek(jump_offset, reader, data)?; + reader.seek(data.as_ref(), jump_offset); Ok(FrameControl::Continue) } @@ -3008,18 +3008,4 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { Ok(FrameControl::Continue) } } - - fn seek<'b>( - &self, - jump_offset: i16, - reader: &mut Reader<'b>, - data: &'b SwfSlice, - ) -> Result<(), Error<'gc>> { - let slice = data.movie.data(); - let mut pos = reader.get_ref().as_ptr() as usize - slice.as_ptr() as usize; - pos = (pos as isize + isize::from(jump_offset)) as usize; - pos = pos.min(slice.len()); - *reader.get_mut() = &slice[pos as usize..]; - Ok(()) - } } diff --git a/core/src/avm2/activation.rs b/core/src/avm2/activation.rs index 5ac0042ed248..416a92ec6bca 100644 --- a/core/src/avm2/activation.rs +++ b/core/src/avm2/activation.rs @@ -15,7 +15,6 @@ use crate::avm2::{value, Avm2, Error}; use crate::context::UpdateContext; use gc_arena::{Gc, GcCell, MutationContext}; use smallvec::SmallVec; -use std::io::Cursor; use swf::avm2::read::Reader; use swf::avm2::types::{ Class as AbcClass, Index, Method as AbcMethod, Multiname as AbcMultiname, @@ -507,10 +506,11 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { let body: Result<_, Error> = method .body() .ok_or_else(|| "Cannot execute non-native method without body".into()); - let mut read = Reader::new(Cursor::new(body?.code.as_ref())); + let body = body?; + let mut reader = Reader::new(&body.code); loop { - let result = self.do_next_opcode(method, &mut read); + let result = self.do_next_opcode(method, &mut reader, &body.code); match result { Ok(FrameControl::Return(value)) => break Ok(value), Ok(FrameControl::Continue) => {} @@ -520,10 +520,11 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { } /// Run a single action from a given action reader. - fn do_next_opcode( + fn do_next_opcode<'b>( &mut self, method: Gc<'gc, BytecodeMethod<'gc>>, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { if self.context.update_start.elapsed() >= self.context.max_execution_duration { return Err( @@ -635,21 +636,21 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { Op::SubtractI => self.op_subtract_i(), Op::Swap => self.op_swap(), Op::URShift => self.op_urshift(), - Op::Jump { offset } => self.op_jump(offset, reader), - Op::IfTrue { offset } => self.op_if_true(offset, reader), - Op::IfFalse { offset } => self.op_if_false(offset, reader), - Op::IfStrictEq { offset } => self.op_if_strict_eq(offset, reader), - Op::IfStrictNe { offset } => self.op_if_strict_ne(offset, reader), - Op::IfEq { offset } => self.op_if_eq(offset, reader), - Op::IfNe { offset } => self.op_if_ne(offset, reader), - Op::IfGe { offset } => self.op_if_ge(offset, reader), - Op::IfGt { offset } => self.op_if_gt(offset, reader), - Op::IfLe { offset } => self.op_if_le(offset, reader), - Op::IfLt { offset } => self.op_if_lt(offset, reader), - Op::IfNge { offset } => self.op_if_nge(offset, reader), - Op::IfNgt { offset } => self.op_if_ngt(offset, reader), - Op::IfNle { offset } => self.op_if_nle(offset, reader), - Op::IfNlt { offset } => self.op_if_nlt(offset, reader), + Op::Jump { offset } => self.op_jump(offset, reader, full_data), + Op::IfTrue { offset } => self.op_if_true(offset, reader, full_data), + Op::IfFalse { offset } => self.op_if_false(offset, reader, full_data), + Op::IfStrictEq { offset } => self.op_if_strict_eq(offset, reader, full_data), + Op::IfStrictNe { offset } => self.op_if_strict_ne(offset, reader, full_data), + Op::IfEq { offset } => self.op_if_eq(offset, reader, full_data), + Op::IfNe { offset } => self.op_if_ne(offset, reader, full_data), + Op::IfGe { offset } => self.op_if_ge(offset, reader, full_data), + Op::IfGt { offset } => self.op_if_gt(offset, reader, full_data), + Op::IfLe { offset } => self.op_if_le(offset, reader, full_data), + Op::IfLt { offset } => self.op_if_lt(offset, reader, full_data), + Op::IfNge { offset } => self.op_if_nge(offset, reader, full_data), + Op::IfNgt { offset } => self.op_if_ngt(offset, reader, full_data), + Op::IfNle { offset } => self.op_if_nle(offset, reader, full_data), + Op::IfNlt { offset } => self.op_if_nlt(offset, reader, full_data), Op::StrictEquals => self.op_strict_equals(), Op::Equals => self.op_equals(), Op::GreaterEquals => self.op_greater_equals(), @@ -1834,219 +1835,234 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { Ok(FrameControl::Continue) } - fn op_jump( + fn op_jump<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); Ok(FrameControl::Continue) } - fn op_if_true( + fn op_if_true<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value = self.context.avm2.pop().coerce_to_boolean(); if value { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_false( + fn op_if_false<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value = self.context.avm2.pop().coerce_to_boolean(); if !value { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_strict_eq( + fn op_if_strict_eq<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if value1 == value2 { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_strict_ne( + fn op_if_strict_ne<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if value1 != value2 { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_eq( + fn op_if_eq<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if value1.abstract_eq(&value2, self)? { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_ne( + fn op_if_ne<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if !value1.abstract_eq(&value2, self)? { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_ge( + fn op_if_ge<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if value1.abstract_lt(&value2, self)? == Some(false) { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_gt( + fn op_if_gt<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if value2.abstract_lt(&value1, self)? == Some(true) { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_le( + fn op_if_le<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if value2.abstract_lt(&value1, self)? == Some(false) { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_lt( + fn op_if_lt<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if value1.abstract_lt(&value2, self)? == Some(true) { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_nge( + fn op_if_nge<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if value1.abstract_lt(&value2, self)?.unwrap_or(true) { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_ngt( + fn op_if_ngt<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if !value2.abstract_lt(&value1, self)?.unwrap_or(false) { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_nle( + fn op_if_nle<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if value2.abstract_lt(&value1, self)?.unwrap_or(true) { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_nlt( + fn op_if_nlt<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if !value1.abstract_lt(&value2, self)?.unwrap_or(false) { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index 092cb36d9b15..e1835d89b0b2 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -32,7 +32,7 @@ use std::cell::{Ref, RefCell}; use std::collections::HashMap; use std::convert::TryFrom; use std::sync::Arc; -use swf::read::SwfReadExt; +use swf::extensions::ReadSwfExt; use swf::{FillStyle, FrameLabelData, LineStyle, Tag}; type FrameNumber = u16; @@ -484,7 +484,7 @@ impl<'gc> MovieClip<'gc> { // giving us a `SwfSlice` for later parsing, so we have to replcate the // *entire* parsing code here. This sucks. let flags = reader.read_u32()?; - let name = reader.read_string()?.to_string_lossy(reader.encoding()); + let name = reader.read_str()?.to_string_lossy(reader.encoding()); let is_lazy_initialize = flags & 1 != 0; let domain = library.avm2_domain(); @@ -524,7 +524,7 @@ impl<'gc> MovieClip<'gc> { for _ in 0..num_symbols { let id = reader.read_u16()?; - let class_name = reader.read_string()?.to_string_lossy(reader.encoding()); + let class_name = reader.read_str()?.to_string_lossy(reader.encoding()); if let Some(name) = Avm2QName::from_symbol_class(&class_name, activation.context.gc_context) diff --git a/swf/src/avm1/read.rs b/swf/src/avm1/read.rs index 68ab53d67d3c..aebcef49429b 100644 --- a/swf/src/avm1/read.rs +++ b/swf/src/avm1/read.rs @@ -2,40 +2,34 @@ use crate::avm1::{opcode::OpCode, types::*}; use crate::error::{Error, Result}; -use crate::read::SwfReadExt; -use crate::string::{Encoding, SwfStr, UTF_8, WINDOWS_1252}; -use byteorder::{LittleEndian, ReadBytesExt}; -use std::io::{self, Read}; +use crate::extensions::ReadSwfExt; #[allow(dead_code)] pub struct Reader<'a> { input: &'a [u8], version: u8, - encoding: &'static Encoding, +} + +impl<'a> ReadSwfExt<'a> for Reader<'a> { + #[inline(always)] + fn as_mut_slice(&mut self) -> &mut &'a [u8] { + &mut self.input + } } impl<'a> Reader<'a> { #[inline] - pub fn new(input: &'a [u8], version: u8) -> Self { - Self { - input, - version, - encoding: if version > 5 { - UTF_8 - } else { - // TODO: Allow configurable encoding - WINDOWS_1252 - }, - } + pub const fn new(input: &'a [u8], version: u8) -> Self { + Self { input, version } } #[inline] - pub fn encoding(&self) -> &'static Encoding { - SwfStr::encoding_for_version(self.version) + pub fn seek(&mut self, data: &'a [u8], jump_offset: i16) { + ReadSwfExt::seek(self, data, jump_offset as isize) } #[inline] - pub fn get_ref(&self) -> &'a [u8] { + pub const fn get_ref(&self) -> &'a [u8] { self.input } @@ -44,41 +38,6 @@ impl<'a> Reader<'a> { &mut self.input } - fn read_slice(&mut self, len: usize) -> io::Result<&'a [u8]> { - if self.input.len() >= len { - let slice = &self.input[..len]; - self.input = &self.input[len..]; - Ok(slice) - } else { - Err(io::Error::new( - io::ErrorKind::UnexpectedEof, - "Not enough data for slice", - )) - } - } - - pub fn read_string(&mut self) -> io::Result<&'a SwfStr> { - // Same implementation as in `swf::read::Reader` - let s = SwfStr::from_bytes_null_terminated(&self.input).ok_or_else(|| { - io::Error::new(io::ErrorKind::UnexpectedEof, "Not enough data for string") - })?; - self.input = &self.input[s.len() + 1..]; - Ok(s) - } - - #[inline] - fn read_f64_me(&mut self) -> io::Result { - // Flash weirdly stores f64 as two LE 32-bit chunks. - // First word is the hi-word, second word is the lo-word. - let mut num = [0u8; 8]; - self.input.read_exact(&mut num)?; - num.swap(0, 4); - num.swap(1, 5); - num.swap(2, 6); - num.swap(3, 7); - (&num[..]).read_f64::() - } - #[inline] pub fn read_action(&mut self) -> Result>> { let (opcode, mut length) = self.read_opcode_and_length()?; @@ -143,7 +102,7 @@ impl<'a> Reader<'a> { OpCode::ConstantPool => { let mut constants = vec![]; for _ in 0..self.read_u16()? { - constants.push(self.read_string()?); + constants.push(self.read_str()?); } Action::ConstantPool(constants) } @@ -165,8 +124,8 @@ impl<'a> Reader<'a> { OpCode::GetProperty => Action::GetProperty, OpCode::GetTime => Action::GetTime, OpCode::GetUrl => Action::GetUrl { - url: self.read_string()?, - target: self.read_string()?, + url: self.read_str()?, + target: self.read_str()?, }, OpCode::GetUrl2 => { let flags = self.read_u8()?; @@ -201,7 +160,7 @@ impl<'a> Reader<'a> { }, } } - OpCode::GotoLabel => Action::GotoLabel(self.read_string()?), + OpCode::GotoLabel => Action::GotoLabel(self.read_str()?), OpCode::Greater => Action::Greater, OpCode::If => Action::If { offset: self.read_i16()?, @@ -238,7 +197,7 @@ impl<'a> Reader<'a> { OpCode::Return => Action::Return, OpCode::SetMember => Action::SetMember, OpCode::SetProperty => Action::SetProperty, - OpCode::SetTarget => Action::SetTarget(self.read_string()?), + OpCode::SetTarget => Action::SetTarget(self.read_str()?), OpCode::SetTarget2 => Action::SetTarget2, OpCode::SetVariable => Action::SetVariable, OpCode::StackSwap => Action::StackSwap, @@ -303,7 +262,7 @@ impl<'a> Reader<'a> { fn read_push_value(&mut self) -> Result> { let value = match self.read_u8()? { - 0 => Value::Str(self.read_string()?), + 0 => Value::Str(self.read_str()?), 1 => Value::Float(self.read_f32()?), 2 => Value::Null, 3 => Value::Undefined, @@ -319,11 +278,11 @@ impl<'a> Reader<'a> { } fn read_define_function(&mut self, action_length: &mut usize) -> Result> { - let name = self.read_string()?; + let name = self.read_str()?; let num_params = self.read_u16()?; let mut params = Vec::with_capacity(num_params as usize); for _ in 0..num_params { - params.push(self.read_string()?); + params.push(self.read_str()?); } // code_length isn't included in the DefineFunction's action length. let code_length = usize::from(self.read_u16()?); @@ -336,7 +295,7 @@ impl<'a> Reader<'a> { } fn read_define_function_2(&mut self, action_length: &mut usize) -> Result> { - let name = self.read_string()?; + let name = self.read_str()?; let num_params = self.read_u16()?; let register_count = self.read_u8()?; // Number of registers let flags = self.read_u16()?; @@ -344,7 +303,7 @@ impl<'a> Reader<'a> { for _ in 0..num_params { let register = self.read_u8()?; params.push(FunctionParam { - name: self.read_string()?, + name: self.read_str()?, register_index: if register == 0 { None } else { Some(register) }, }); } @@ -375,7 +334,7 @@ impl<'a> Reader<'a> { let finally_length = usize::from(self.read_u16()?); *length += try_length + catch_length + finally_length; let catch_var = if flags & 0b100 == 0 { - CatchVar::Var(self.read_string()?) + CatchVar::Var(self.read_str()?) } else { CatchVar::Register(self.read_u8()?) }; @@ -398,56 +357,10 @@ impl<'a> Reader<'a> { } } -impl<'a> SwfReadExt for Reader<'a> { - #[inline] - fn read_u8(&mut self) -> io::Result { - self.input.read_u8() - } - - #[inline] - fn read_u16(&mut self) -> io::Result { - self.input.read_u16::() - } - - #[inline] - fn read_u32(&mut self) -> io::Result { - self.input.read_u32::() - } - - #[inline] - fn read_u64(&mut self) -> io::Result { - self.input.read_u64::() - } - - #[inline] - fn read_i8(&mut self) -> io::Result { - self.input.read_i8() - } - - #[inline] - fn read_i16(&mut self) -> io::Result { - self.input.read_i16::() - } - - #[inline] - fn read_i32(&mut self) -> io::Result { - self.input.read_i32::() - } - - #[inline] - fn read_f32(&mut self) -> io::Result { - self.input.read_f32::() - } - - #[inline] - fn read_f64(&mut self) -> io::Result { - self.input.read_f64::() - } -} - #[cfg(test)] pub mod tests { use super::*; + use crate::string::{SwfStr, WINDOWS_1252}; use crate::test_data; #[test] diff --git a/swf/src/avm2/read.rs b/swf/src/avm2/read.rs index 65aa1b34febf..9c0ebeb7d9f8 100644 --- a/swf/src/avm2/read.rs +++ b/swf/src/avm2/read.rs @@ -1,26 +1,27 @@ use crate::avm2::types::*; use crate::error::{Error, Result}; -use crate::read::SwfReadExt; -use byteorder::{LittleEndian, ReadBytesExt}; -use std::io::{self, Read, Seek, SeekFrom}; +use crate::extensions::ReadSwfExt; +use std::io::Read; -pub struct Reader { - input: R, +pub struct Reader<'a> { + input: &'a [u8], } -impl Reader -where - R: Read + Seek, -{ - #[inline] - pub fn seek(&mut self, relative_offset: i64) -> std::io::Result { - self.input.seek(SeekFrom::Current(relative_offset as i64)) +impl<'a> ReadSwfExt<'a> for Reader<'a> { + #[inline(always)] + fn as_mut_slice(&mut self) -> &mut &'a [u8] { + &mut self.input } } -impl Reader { - pub fn new(input: R) -> Reader { - Reader { input } +impl<'a> Reader<'a> { + pub fn new(input: &'a [u8]) -> Self { + Self { input } + } + + #[inline] + pub fn seek(&mut self, data: &'a [u8], relative_offset: i32) { + ReadSwfExt::seek(self, data, relative_offset as isize) } pub fn read(&mut self) -> Result { @@ -91,10 +92,6 @@ impl Reader { Ok(n) } - fn read_u32(&mut self) -> Result { - self.read_u30() - } - fn read_i24(&mut self) -> Result { Ok(i32::from(self.read_u8()? as i8) | (i32::from(self.read_u8()? as i8) << 8) @@ -211,7 +208,7 @@ impl Reader { let mut uints = Vec::with_capacity(len as usize); if len > 0 { for _ in 0..len - 1 { - uints.push(self.read_u32()?); + uints.push(self.read_u30()?); } } @@ -861,53 +858,6 @@ impl Reader { } } -impl<'a, R: 'a + Read> SwfReadExt for Reader { - #[inline] - fn read_u8(&mut self) -> io::Result { - self.input.read_u8() - } - - #[inline] - fn read_u16(&mut self) -> io::Result { - self.input.read_u16::() - } - - #[inline] - fn read_u32(&mut self) -> io::Result { - self.input.read_u32::() - } - - #[inline] - fn read_u64(&mut self) -> io::Result { - self.input.read_u64::() - } - - #[inline] - fn read_i8(&mut self) -> io::Result { - self.input.read_i8() - } - - #[inline] - fn read_i16(&mut self) -> io::Result { - self.input.read_i16::() - } - - #[inline] - fn read_i32(&mut self) -> io::Result { - self.input.read_i32::() - } - - #[inline] - fn read_f32(&mut self) -> io::Result { - self.input.read_f32::() - } - - #[inline] - fn read_f64(&mut self) -> io::Result { - self.input.read_f64::() - } -} - #[cfg(test)] pub mod tests { use super::*; diff --git a/swf/src/error.rs b/swf/src/error.rs index 14c8bf3ab5e5..aa2a4df45fcb 100644 --- a/swf/src/error.rs +++ b/swf/src/error.rs @@ -1,3 +1,4 @@ +use crate::tag_code::TagCode; use std::{borrow, error, fmt, io}; /// A `Result` from reading SWF data. @@ -19,7 +20,7 @@ pub enum Error { /// This can contain sub-errors with further information (`Error::source`) SwfParseError { tag_code: u16, - source: Option>, + source: Box, }, /// An IO error occurred (probably unexpected EOF). IoError(io::Error), @@ -51,18 +52,10 @@ impl Error { } /// Helper method to create `Error::SwfParseError`. #[inline] - pub fn swf_parse_error(tag_code: u16) -> Self { - Error::SwfParseError { - tag_code, - source: None, - } - } - /// Helper method to create `Error::SwfParseError`. - #[inline] - pub fn swf_parse_error_with_source(tag_code: u16, source: impl error::Error + 'static) -> Self { + pub fn swf_parse_error(tag_code: u16, source: impl error::Error + 'static) -> Self { Error::SwfParseError { tag_code, - source: Some(Box::new(source)), + source: Box::new(source), } } /// Helper method to create `Error::Unsupported`. @@ -90,16 +83,13 @@ impl fmt::Display for Error { Ok(()) } Error::SwfParseError { tag_code, source } => { - let tag = crate::tag_code::TagCode::from_u16(*tag_code); "Error parsing SWF tag ".fmt(f)?; - if let Some(tag) = tag { - write!(f, "{:?}", tag)?; + if let Some(tag_code) = TagCode::from_u16(*tag_code) { + write!(f, "{:?}", tag_code)?; } else { write!(f, "Unknown({})", tag_code)?; }; - if let Some(source) = source { - write!(f, ": {}", source)?; - } + write!(f, ": {}", source)?; Ok(()) } Error::IoError(e) => e.fmt(f), @@ -116,7 +106,7 @@ impl error::Error for Error { Error::Avm1ParseError { source, .. } => source.as_ref().map(|s| s.deref()), Error::IoError(e) => e.source(), Error::InvalidData(_) => None, - Error::SwfParseError { source, .. } => source.as_ref().map(|s| s.deref()), + Error::SwfParseError { source, .. } => Some(source.as_ref()), Error::Unsupported(_) => None, } } diff --git a/swf/src/extensions.rs b/swf/src/extensions.rs new file mode 100644 index 000000000000..84219afa6c47 --- /dev/null +++ b/swf/src/extensions.rs @@ -0,0 +1,132 @@ +use crate::byteorder::{LittleEndian, ReadBytesExt}; +use crate::error::Result; +use crate::string::SwfStr; +use std::io::{self, Read}; + +pub trait ReadSwfExt<'a> { + fn as_mut_slice(&mut self) -> &mut &'a [u8]; + + // TODO: Make this fallible? + fn seek(&mut self, data: &'a [u8], relative_offset: isize) { + let mut pos = self.as_mut_slice().as_ptr() as usize - data.as_ptr() as usize; + pos = (pos as isize + relative_offset) as usize; + pos = pos.min(data.len()); + *self.as_mut_slice() = &data[pos..]; + } + + #[inline] + fn read_u8(&mut self) -> Result { + Ok(ReadBytesExt::read_u8(self.as_mut_slice())?) + } + + #[inline] + fn read_u16(&mut self) -> Result { + Ok(ReadBytesExt::read_u16::(self.as_mut_slice())?) + } + + #[inline] + fn read_u32(&mut self) -> Result { + Ok(ReadBytesExt::read_u32::(self.as_mut_slice())?) + } + + #[inline] + fn read_u64(&mut self) -> Result { + Ok(ReadBytesExt::read_u64::(self.as_mut_slice())?) + } + + #[inline] + fn read_i8(&mut self) -> Result { + Ok(ReadBytesExt::read_i8(self.as_mut_slice())?) + } + + #[inline] + fn read_i16(&mut self) -> Result { + Ok(ReadBytesExt::read_i16::(self.as_mut_slice())?) + } + + #[inline] + fn read_i32(&mut self) -> Result { + Ok(ReadBytesExt::read_i32::(self.as_mut_slice())?) + } + + #[inline] + fn read_f32(&mut self) -> Result { + Ok(ReadBytesExt::read_f32::(self.as_mut_slice())?) + } + + #[inline] + fn read_f64(&mut self) -> Result { + Ok(ReadBytesExt::read_f64::(self.as_mut_slice())?) + } + + #[inline] + fn read_fixed8(&mut self) -> Result { + ReadSwfExt::read_i16(self).map(|n| f32::from(n) / 256f32) + } + + #[inline] + fn read_fixed16(&mut self) -> Result { + ReadSwfExt::read_i32(self).map(|n| f64::from(n) / 65536f64) + } + + #[inline] + fn read_encoded_u32(&mut self) -> Result { + let mut val = 0u32; + for i in 0..5 { + let byte = ReadSwfExt::read_u8(self)?; + val |= u32::from(byte & 0b01111111) << (i * 7); + if byte & 0b10000000 == 0 { + break; + } + } + Ok(val) + } + + #[inline] + fn read_f64_me(&mut self) -> Result { + // Flash weirdly stores (some?) f64 as two LE 32-bit chunks. + // First word is the hi-word, second word is the lo-word. + let mut num = [0u8; 8]; + self.as_mut_slice().read_exact(&mut num)?; + num.swap(0, 4); + num.swap(1, 5); + num.swap(2, 6); + num.swap(3, 7); + Ok(ReadBytesExt::read_f64::(&mut &num[..])?) + } + + fn read_slice(&mut self, len: usize) -> Result<&'a [u8]> { + let slice = self.as_mut_slice(); + if slice.len() >= len { + let new_slice = &slice[..len]; + *slice = &slice[len..]; + Ok(new_slice) + } else { + Err(io::Error::new(io::ErrorKind::UnexpectedEof, "Not enough data for slice").into()) + } + } + + fn read_slice_to_end(&mut self) -> &'a [u8] { + let slice = self.as_mut_slice(); + let res = &slice[..]; + *slice = &[]; + res + } + + #[inline] + fn read_str(&mut self) -> Result<&'a SwfStr> { + let slice = self.as_mut_slice(); + let s = SwfStr::from_bytes_null_terminated(slice).ok_or_else(|| { + io::Error::new(io::ErrorKind::UnexpectedEof, "Not enough data for string") + })?; + *slice = &slice[s.len() + 1..]; + Ok(s) + } + + #[inline] + fn read_str_with_len(&mut self, len: usize) -> Result<&'a SwfStr> { + let bytes = &self.read_slice(len)?; + // TODO: Maybe just strip the possible trailing null char instead of looping here. + Ok(SwfStr::from_bytes_null_terminated(bytes).unwrap_or_else(|| SwfStr::from_bytes(bytes))) + } +} diff --git a/swf/src/lib.rs b/swf/src/lib.rs index 802916e75c90..99c5e51c7b24 100644 --- a/swf/src/lib.rs +++ b/swf/src/lib.rs @@ -25,6 +25,8 @@ extern crate num_traits; pub mod avm1; pub mod avm2; pub mod error; +// TODO: Make this private? +pub mod extensions; pub mod read; mod string; mod tag_code; diff --git a/swf/src/read.rs b/swf/src/read.rs index fb4630271a22..becf10060eca 100644 --- a/swf/src/read.rs +++ b/swf/src/read.rs @@ -6,9 +6,11 @@ clippy::unreadable_literal )] +use crate::extensions::ReadSwfExt; use crate::{ error::{Error, Result}, string::{Encoding, SwfStr}, + tag_code::TagCode, types::*, }; use bitstream_io::BitRead; @@ -181,18 +183,6 @@ fn make_lzma_reader<'a, R: Read + 'a>( )) } -pub trait SwfReadExt { - fn read_u8(&mut self) -> io::Result; - fn read_u16(&mut self) -> io::Result; - fn read_u32(&mut self) -> io::Result; - fn read_u64(&mut self) -> io::Result; - fn read_i8(&mut self) -> io::Result; - fn read_i16(&mut self) -> io::Result; - fn read_i32(&mut self) -> io::Result; - fn read_f32(&mut self) -> io::Result; - fn read_f64(&mut self) -> io::Result; -} - pub struct BitReader<'a, 'b> { bits: bitstream_io::BitReader<&'b mut &'a [u8], bitstream_io::BigEndian>, } @@ -248,9 +238,16 @@ pub struct Reader<'a> { version: u8, } +impl<'a> ReadSwfExt<'a> for Reader<'a> { + #[inline(always)] + fn as_mut_slice(&mut self) -> &mut &'a [u8] { + &mut self.input + } +} + impl<'a> Reader<'a> { #[inline] - pub fn new(input: &'a [u8], version: u8) -> Reader<'a> { + pub const fn new(input: &'a [u8], version: u8) -> Reader<'a> { Reader { input, version } } @@ -264,13 +261,13 @@ impl<'a> Reader<'a> { } #[inline] - pub fn version(&self) -> u8 { + pub const fn version(&self) -> u8 { self.version } /// Returns a reference to the underlying `Reader`. #[inline] - pub fn get_ref(&self) -> &'a [u8] { + pub const fn get_ref(&self) -> &'a [u8] { self.input } @@ -288,50 +285,6 @@ impl<'a> Reader<'a> { } } - #[inline] - fn read_fixed8(&mut self) -> io::Result { - self.read_i16().map(|n| f32::from(n) / 256f32) - } - - #[inline] - fn read_fixed16(&mut self) -> io::Result { - self.read_i32().map(|n| f64::from(n) / 65536f64) - } - - fn read_slice(&mut self, len: usize) -> io::Result<&'a [u8]> { - if self.input.len() >= len { - let slice = &self.input[..len]; - self.input = &self.input[len..]; - Ok(slice) - } else { - Err(io::Error::new( - io::ErrorKind::UnexpectedEof, - "Not enough data for slice", - )) - } - } - - fn read_slice_to_end(&mut self) -> &'a [u8] { - let len = self.input.len(); - let slice = &self.input[..len]; - self.input = &self.input[len..]; - slice - } - - pub fn read_string(&mut self) -> io::Result<&'a SwfStr> { - let s = SwfStr::from_bytes_null_terminated(&self.input).ok_or_else(|| { - io::Error::new(io::ErrorKind::UnexpectedEof, "Not enough data for string") - })?; - self.input = &self.input[s.len() + 1..]; - Ok(s) - } - - fn read_string_with_len(&mut self, len: usize) -> io::Result<&'a SwfStr> { - let bytes = &self.read_slice(len)?; - // TODO: Maybe just strip the possible trailing null char instead of looping here. - Ok(SwfStr::from_bytes_null_terminated(bytes).unwrap_or_else(|| SwfStr::from_bytes(bytes))) - } - /// Reads the next SWF tag from the stream. /// # Example /// ``` @@ -345,90 +298,78 @@ impl<'a> Reader<'a> { /// ``` pub fn read_tag(&mut self) -> Result> { let (tag_code, length) = self.read_tag_code_and_length()?; - let tag = self.read_tag_with_code(tag_code, length); - if let Err(e) = tag { - return Err(Error::swf_parse_error_with_source(tag_code, e)); + if let Some(tag_code) = TagCode::from_u16(tag_code) { + self.read_tag_with_code(tag_code, length) + } else { + self.read_slice(length) + .map(|data| Tag::Unknown { tag_code, data }) } - - tag + .map_err(|e| Error::swf_parse_error(tag_code, e)) } - fn read_tag_with_code(&mut self, tag_code: u16, length: usize) -> Result> { + fn read_tag_with_code(&mut self, tag_code: TagCode, length: usize) -> Result> { let mut tag_reader = Reader::new(self.read_slice(length)?, self.version); - use crate::tag_code::TagCode; - let tag = match TagCode::from_u16(tag_code) { - Some(TagCode::End) => Tag::End, - Some(TagCode::ShowFrame) => Tag::ShowFrame, - Some(TagCode::CsmTextSettings) => { - Tag::CsmTextSettings(tag_reader.read_csm_text_settings()?) - } - Some(TagCode::DefineBinaryData) => { + let tag = match tag_code { + TagCode::End => Tag::End, + TagCode::ShowFrame => Tag::ShowFrame, + TagCode::CsmTextSettings => Tag::CsmTextSettings(tag_reader.read_csm_text_settings()?), + TagCode::DefineBinaryData => { let id = tag_reader.read_u16()?; tag_reader.read_u32()?; // Reserved let data = tag_reader.read_slice_to_end(); Tag::DefineBinaryData { id, data } } - Some(TagCode::DefineBits) => { + TagCode::DefineBits => { let id = tag_reader.read_u16()?; let jpeg_data = tag_reader.read_slice_to_end(); Tag::DefineBits { id, jpeg_data } } - Some(TagCode::DefineBitsJpeg2) => { + TagCode::DefineBitsJpeg2 => { let id = tag_reader.read_u16()?; let jpeg_data = tag_reader.read_slice_to_end(); Tag::DefineBitsJpeg2 { id, jpeg_data } } - Some(TagCode::DefineBitsJpeg3) => tag_reader.read_define_bits_jpeg_3(3)?, - Some(TagCode::DefineBitsJpeg4) => tag_reader.read_define_bits_jpeg_3(4)?, - Some(TagCode::DefineButton) => { + TagCode::DefineBitsJpeg3 => tag_reader.read_define_bits_jpeg_3(3)?, + TagCode::DefineBitsJpeg4 => tag_reader.read_define_bits_jpeg_3(4)?, + TagCode::DefineButton => { Tag::DefineButton(Box::new(tag_reader.read_define_button_1()?)) } - Some(TagCode::DefineButton2) => { + TagCode::DefineButton2 => { Tag::DefineButton2(Box::new(tag_reader.read_define_button_2()?)) } - Some(TagCode::DefineButtonCxform) => { + TagCode::DefineButtonCxform => { Tag::DefineButtonColorTransform(tag_reader.read_define_button_cxform(length)?) } - Some(TagCode::DefineButtonSound) => { + TagCode::DefineButtonSound => { Tag::DefineButtonSound(Box::new(tag_reader.read_define_button_sound()?)) } - Some(TagCode::DefineEditText) => { + TagCode::DefineEditText => { Tag::DefineEditText(Box::new(tag_reader.read_define_edit_text()?)) } - Some(TagCode::DefineFont) => { - Tag::DefineFont(Box::new(tag_reader.read_define_font_1()?)) - } - Some(TagCode::DefineFont2) => { - Tag::DefineFont2(Box::new(tag_reader.read_define_font_2(2)?)) - } - Some(TagCode::DefineFont3) => { - Tag::DefineFont2(Box::new(tag_reader.read_define_font_2(3)?)) - } - Some(TagCode::DefineFont4) => Tag::DefineFont4(tag_reader.read_define_font_4()?), - Some(TagCode::DefineFontAlignZones) => tag_reader.read_define_font_align_zones()?, - Some(TagCode::DefineFontInfo) => tag_reader.read_define_font_info(1)?, - Some(TagCode::DefineFontInfo2) => tag_reader.read_define_font_info(2)?, - Some(TagCode::DefineFontName) => tag_reader.read_define_font_name()?, - Some(TagCode::DefineMorphShape) => { + TagCode::DefineFont => Tag::DefineFont(Box::new(tag_reader.read_define_font_1()?)), + TagCode::DefineFont2 => Tag::DefineFont2(Box::new(tag_reader.read_define_font_2(2)?)), + TagCode::DefineFont3 => Tag::DefineFont2(Box::new(tag_reader.read_define_font_2(3)?)), + TagCode::DefineFont4 => Tag::DefineFont4(tag_reader.read_define_font_4()?), + TagCode::DefineFontAlignZones => tag_reader.read_define_font_align_zones()?, + TagCode::DefineFontInfo => tag_reader.read_define_font_info(1)?, + TagCode::DefineFontInfo2 => tag_reader.read_define_font_info(2)?, + TagCode::DefineFontName => tag_reader.read_define_font_name()?, + TagCode::DefineMorphShape => { Tag::DefineMorphShape(Box::new(tag_reader.read_define_morph_shape(1)?)) } - Some(TagCode::DefineMorphShape2) => { + TagCode::DefineMorphShape2 => { Tag::DefineMorphShape(Box::new(tag_reader.read_define_morph_shape(2)?)) } - Some(TagCode::DefineShape) => Tag::DefineShape(tag_reader.read_define_shape(1)?), - Some(TagCode::DefineShape2) => Tag::DefineShape(tag_reader.read_define_shape(2)?), - Some(TagCode::DefineShape3) => Tag::DefineShape(tag_reader.read_define_shape(3)?), - Some(TagCode::DefineShape4) => Tag::DefineShape(tag_reader.read_define_shape(4)?), - Some(TagCode::DefineSound) => { - Tag::DefineSound(Box::new(tag_reader.read_define_sound()?)) - } - Some(TagCode::DefineText) => Tag::DefineText(Box::new(tag_reader.read_define_text(1)?)), - Some(TagCode::DefineText2) => { - Tag::DefineText(Box::new(tag_reader.read_define_text(2)?)) - } - Some(TagCode::DefineVideoStream) => tag_reader.read_define_video_stream()?, - Some(TagCode::EnableTelemetry) => { + TagCode::DefineShape => Tag::DefineShape(tag_reader.read_define_shape(1)?), + TagCode::DefineShape2 => Tag::DefineShape(tag_reader.read_define_shape(2)?), + TagCode::DefineShape3 => Tag::DefineShape(tag_reader.read_define_shape(3)?), + TagCode::DefineShape4 => Tag::DefineShape(tag_reader.read_define_shape(4)?), + TagCode::DefineSound => Tag::DefineSound(Box::new(tag_reader.read_define_sound()?)), + TagCode::DefineText => Tag::DefineText(Box::new(tag_reader.read_define_text(1)?)), + TagCode::DefineText2 => Tag::DefineText(Box::new(tag_reader.read_define_text(2)?)), + TagCode::DefineVideoStream => tag_reader.read_define_video_stream()?, + TagCode::EnableTelemetry => { tag_reader.read_u16()?; // Reserved let password_hash = if length > 2 { tag_reader.read_slice(32)? @@ -437,20 +378,20 @@ impl<'a> Reader<'a> { }; Tag::EnableTelemetry { password_hash } } - Some(TagCode::ImportAssets) => { - let url = tag_reader.read_string()?; + TagCode::ImportAssets => { + let url = tag_reader.read_str()?; let num_imports = tag_reader.read_u16()?; let mut imports = Vec::with_capacity(num_imports as usize); for _ in 0..num_imports { imports.push(ExportedAsset { id: tag_reader.read_u16()?, - name: tag_reader.read_string()?, + name: tag_reader.read_str()?, }); } Tag::ImportAssets { url, imports } } - Some(TagCode::ImportAssets2) => { - let url = tag_reader.read_string()?; + TagCode::ImportAssets2 => { + let url = tag_reader.read_str()?; tag_reader.read_u8()?; // Reserved; must be 1 tag_reader.read_u8()?; // Reserved; must be 0 let num_imports = tag_reader.read_u16()?; @@ -458,59 +399,59 @@ impl<'a> Reader<'a> { for _ in 0..num_imports { imports.push(ExportedAsset { id: tag_reader.read_u16()?, - name: tag_reader.read_string()?, + name: tag_reader.read_str()?, }); } Tag::ImportAssets { url, imports } } - Some(TagCode::JpegTables) => { + TagCode::JpegTables => { let data = tag_reader.read_slice_to_end(); Tag::JpegTables(data) } - Some(TagCode::Metadata) => Tag::Metadata(tag_reader.read_string()?), + TagCode::Metadata => Tag::Metadata(tag_reader.read_str()?), - Some(TagCode::SetBackgroundColor) => Tag::SetBackgroundColor(tag_reader.read_rgb()?), + TagCode::SetBackgroundColor => Tag::SetBackgroundColor(tag_reader.read_rgb()?), - Some(TagCode::SoundStreamBlock) => { + TagCode::SoundStreamBlock => { let data = tag_reader.read_slice_to_end(); Tag::SoundStreamBlock(data) } - Some(TagCode::SoundStreamHead) => Tag::SoundStreamHead( + TagCode::SoundStreamHead => Tag::SoundStreamHead( // TODO: Disallow certain compressions. Box::new(tag_reader.read_sound_stream_head()?), ), - Some(TagCode::SoundStreamHead2) => { + TagCode::SoundStreamHead2 => { Tag::SoundStreamHead2(Box::new(tag_reader.read_sound_stream_head()?)) } - Some(TagCode::StartSound) => Tag::StartSound(tag_reader.read_start_sound_1()?), + TagCode::StartSound => Tag::StartSound(tag_reader.read_start_sound_1()?), - Some(TagCode::StartSound2) => Tag::StartSound2 { - class_name: tag_reader.read_string()?, + TagCode::StartSound2 => Tag::StartSound2 { + class_name: tag_reader.read_str()?, sound_info: Box::new(tag_reader.read_sound_info()?), }, - Some(TagCode::DebugId) => Tag::DebugId(tag_reader.read_debug_id()?), + TagCode::DebugId => Tag::DebugId(tag_reader.read_debug_id()?), - Some(TagCode::DefineBitsLossless) => { + TagCode::DefineBitsLossless => { Tag::DefineBitsLossless(tag_reader.read_define_bits_lossless(1)?) } - Some(TagCode::DefineBitsLossless2) => { + TagCode::DefineBitsLossless2 => { Tag::DefineBitsLossless(tag_reader.read_define_bits_lossless(2)?) } - Some(TagCode::DefineScalingGrid) => Tag::DefineScalingGrid { + TagCode::DefineScalingGrid => Tag::DefineScalingGrid { id: tag_reader.read_u16()?, splitter_rect: tag_reader.read_rectangle()?, }, - Some(TagCode::DoAbc) => { + TagCode::DoAbc => { let flags = tag_reader.read_u32()?; - let name = tag_reader.read_string()?; + let name = tag_reader.read_str()?; let abc_data = tag_reader.read_slice_to_end(); Tag::DoAbc(DoAbc { name, @@ -519,91 +460,85 @@ impl<'a> Reader<'a> { }) } - Some(TagCode::DoAction) => { + TagCode::DoAction => { let action_data = tag_reader.read_slice_to_end(); Tag::DoAction(action_data) } - Some(TagCode::DoInitAction) => { + TagCode::DoInitAction => { let id = tag_reader.read_u16()?; let action_data = tag_reader.read_slice_to_end(); Tag::DoInitAction { id, action_data } } - Some(TagCode::EnableDebugger) => Tag::EnableDebugger(tag_reader.read_string()?), - Some(TagCode::EnableDebugger2) => { + TagCode::EnableDebugger => Tag::EnableDebugger(tag_reader.read_str()?), + TagCode::EnableDebugger2 => { tag_reader.read_u16()?; // Reserved - Tag::EnableDebugger(tag_reader.read_string()?) + Tag::EnableDebugger(tag_reader.read_str()?) } - Some(TagCode::ScriptLimits) => Tag::ScriptLimits { + TagCode::ScriptLimits => Tag::ScriptLimits { max_recursion_depth: tag_reader.read_u16()?, timeout_in_seconds: tag_reader.read_u16()?, }, - Some(TagCode::SetTabIndex) => Tag::SetTabIndex { + TagCode::SetTabIndex => Tag::SetTabIndex { depth: tag_reader.read_u16()?, tab_index: tag_reader.read_u16()?, }, - Some(TagCode::SymbolClass) => { + TagCode::SymbolClass => { let num_symbols = tag_reader.read_u16()?; let mut symbols = Vec::with_capacity(num_symbols as usize); for _ in 0..num_symbols { symbols.push(SymbolClassLink { id: tag_reader.read_u16()?, - class_name: tag_reader.read_string()?, + class_name: tag_reader.read_str()?, }); } Tag::SymbolClass(symbols) } - Some(TagCode::ExportAssets) => Tag::ExportAssets(tag_reader.read_export_assets()?), + TagCode::ExportAssets => Tag::ExportAssets(tag_reader.read_export_assets()?), - Some(TagCode::FileAttributes) => { - Tag::FileAttributes(tag_reader.read_file_attributes()?) - } + TagCode::FileAttributes => Tag::FileAttributes(tag_reader.read_file_attributes()?), - Some(TagCode::Protect) => { + TagCode::Protect => { Tag::Protect(if length > 0 { tag_reader.read_u16()?; // TODO(Herschel): Two null bytes? Not specified in SWF19. - Some(tag_reader.read_string()?) + Some(tag_reader.read_str()?) } else { None }) } - Some(TagCode::DefineSceneAndFrameLabelData) => Tag::DefineSceneAndFrameLabelData( + TagCode::DefineSceneAndFrameLabelData => Tag::DefineSceneAndFrameLabelData( tag_reader.read_define_scene_and_frame_label_data()?, ), - Some(TagCode::FrameLabel) => Tag::FrameLabel(tag_reader.read_frame_label(length)?), + TagCode::FrameLabel => Tag::FrameLabel(tag_reader.read_frame_label(length)?), - Some(TagCode::DefineSprite) => tag_reader.read_define_sprite()?, + TagCode::DefineSprite => tag_reader.read_define_sprite()?, - Some(TagCode::PlaceObject) => { + TagCode::PlaceObject => { Tag::PlaceObject(Box::new(tag_reader.read_place_object(length)?)) } - Some(TagCode::PlaceObject2) => { + TagCode::PlaceObject2 => { Tag::PlaceObject(Box::new(tag_reader.read_place_object_2_or_3(2)?)) } - Some(TagCode::PlaceObject3) => { + TagCode::PlaceObject3 => { Tag::PlaceObject(Box::new(tag_reader.read_place_object_2_or_3(3)?)) } - Some(TagCode::PlaceObject4) => { + TagCode::PlaceObject4 => { Tag::PlaceObject(Box::new(tag_reader.read_place_object_2_or_3(4)?)) } - Some(TagCode::RemoveObject) => Tag::RemoveObject(tag_reader.read_remove_object_1()?), + TagCode::RemoveObject => Tag::RemoveObject(tag_reader.read_remove_object_1()?), - Some(TagCode::RemoveObject2) => Tag::RemoveObject(tag_reader.read_remove_object_2()?), + TagCode::RemoveObject2 => Tag::RemoveObject(tag_reader.read_remove_object_2()?), - Some(TagCode::VideoFrame) => tag_reader.read_video_frame()?, - Some(TagCode::ProductInfo) => Tag::ProductInfo(tag_reader.read_product_info()?), - _ => { - let data = tag_reader.read_slice_to_end(); - Tag::Unknown { tag_code, data } - } + TagCode::VideoFrame => tag_reader.read_video_frame()?, + TagCode::ProductInfo => Tag::ProductInfo(tag_reader.read_product_info()?), }; if !tag_reader.input.is_empty() { @@ -612,11 +547,7 @@ impl<'a> Reader<'a> { // But sometimes tools will export SWF tags that are larger than they should be. // TODO: It might be worthwhile to have a "strict mode" to determine // whether this should error or not. - log::warn!( - "Data remaining in buffer when parsing {} ({})", - TagCode::name(tag_code), - tag_code - ); + log::warn!("Data remaining in buffer when parsing {:?}", tag_code); } Ok(tag) @@ -633,18 +564,6 @@ impl<'a> Reader<'a> { }) } - pub fn read_encoded_u32(&mut self) -> Result { - let mut val = 0u32; - for i in 0..5 { - let byte = self.read_u8()?; - val |= u32::from(byte & 0b01111111) << (i * 7); - if byte & 0b10000000 == 0 { - break; - } - } - Ok(val) - } - pub fn read_character_id(&mut self) -> Result { let id = self.read_u16()?; Ok(id) @@ -970,7 +889,7 @@ impl<'a> Reader<'a> { } pub fn read_frame_label(&mut self, length: usize) -> Result> { - let label = self.read_string()?; + let label = self.read_str()?; Ok(FrameLabel { is_anchor: self.version >= 6 && length > label.len() + 1 && self.read_u8()? != 0, label, @@ -985,7 +904,7 @@ impl<'a> Reader<'a> { for _ in 0..num_scenes { scenes.push(FrameLabelData { frame_num: self.read_encoded_u32()?, - label: self.read_string()?, + label: self.read_str()?, }); } @@ -994,7 +913,7 @@ impl<'a> Reader<'a> { for _ in 0..num_frame_labels { frame_labels.push(FrameLabelData { frame_num: self.read_encoded_u32()?, - label: self.read_string()?, + label: self.read_str()?, }); } @@ -1052,7 +971,7 @@ impl<'a> Reader<'a> { let name_len = self.read_u8()?; // SWF19 states that the font name should not have a terminating null byte, // but it often does (depends on Flash IDE version?) - let name = self.read_string_with_len(name_len.into())?; + let name = self.read_str_with_len(name_len.into())?; let num_glyphs = self.read_u16()? as usize; let mut glyphs = Vec::with_capacity(num_glyphs); @@ -1169,7 +1088,7 @@ impl<'a> Reader<'a> { pub fn read_define_font_4(&mut self) -> Result> { let id = self.read_character_id()?; let flags = self.read_u8()?; - let name = self.read_string()?; + let name = self.read_str()?; let has_font_data = flags & 0b100 != 0; let data = if has_font_data { Some(self.read_slice_to_end()) @@ -1236,7 +1155,7 @@ impl<'a> Reader<'a> { let id = self.read_u16()?; let font_name_len = self.read_u8()?; - let font_name = self.read_string_with_len(font_name_len.into())?; + let font_name = self.read_str_with_len(font_name_len.into())?; let flags = self.read_u8()?; let use_wide_codes = flags & 0b1 != 0; // TODO(Herschel): Warn if false for version 2. @@ -1276,8 +1195,8 @@ impl<'a> Reader<'a> { fn read_define_font_name(&mut self) -> Result> { Ok(Tag::DefineFontName { id: self.read_character_id()?, - name: self.read_string()?, - copyright_info: self.read_string()?, + name: self.read_str()?, + copyright_info: self.read_str()?, }) } @@ -1934,7 +1853,7 @@ impl<'a> Reader<'a> { for _ in 0..num_exports { exports.push(ExportedAsset { id: self.read_u16()?, - name: self.read_string()?, + name: self.read_str()?, }); } Ok(exports) @@ -1993,7 +1912,7 @@ impl<'a> Reader<'a> { let has_character_id = (flags & 0b10) != 0; let has_class_name = (flags & 0b1000_00000000) != 0 || (is_image && !has_character_id); let class_name = if has_class_name { - Some(self.read_string()?) + Some(self.read_str()?) } else { None }; @@ -2020,7 +1939,7 @@ impl<'a> Reader<'a> { None }; let name = if (flags & 0b10_0000) != 0 { - Some(self.read_string()?) + Some(self.read_str()?) } else { None }; @@ -2549,7 +2468,7 @@ impl<'a> Reader<'a> { None }; let font_class_name = if flags2 & 0b10000000 != 0 { - Some(self.read_string()?) + Some(self.read_str()?) } else { None }; @@ -2585,9 +2504,9 @@ impl<'a> Reader<'a> { } else { None }; - let variable_name = self.read_string()?; + let variable_name = self.read_str()?; let initial_text = if flags & 0b10000000 != 0 { - Some(self.read_string()?) + Some(self.read_str()?) } else { None }; @@ -2714,8 +2633,8 @@ impl<'a> Reader<'a> { edition: self.read_u32()?, major_version: self.read_u8()?, minor_version: self.read_u8()?, - build_number: self.get_mut().read_u64::()?, - compilation_date: self.get_mut().read_u64::()?, + build_number: self.read_u64()?, + compilation_date: self.read_u64()?, }) } @@ -3048,24 +2967,24 @@ pub mod tests { { let buf = b"Testing\0More testing\0\0Non-string data"; let mut reader = Reader::new(&buf[..], 1); - assert_eq!(reader.read_string().unwrap(), "Testing"); - assert_eq!(reader.read_string().unwrap(), "More testing"); - assert_eq!(reader.read_string().unwrap(), ""); - assert!(reader.read_string().is_err()); + assert_eq!(reader.read_str().unwrap(), "Testing"); + assert_eq!(reader.read_str().unwrap(), "More testing"); + assert_eq!(reader.read_str().unwrap(), ""); + assert!(reader.read_str().is_err()); } { let mut reader = Reader::new(&[], 1); - assert!(reader.read_string().is_err()); + assert!(reader.read_str().is_err()); } { let buf = b"\0Testing"; let mut reader = Reader::new(&buf[..], 1); - assert_eq!(reader.read_string().unwrap(), ""); + assert_eq!(reader.read_str().unwrap(), ""); } { let buf = "12🤖12\0"; let mut reader = Reader::new(buf.as_bytes(), 1); - assert_eq!(reader.read_string().unwrap(), "12🤖12"); + assert_eq!(reader.read_str().unwrap(), "12🤖12"); } } @@ -3231,50 +3150,3 @@ pub mod tests { } } } - -impl<'a> SwfReadExt for Reader<'a> { - #[inline] - fn read_u8(&mut self) -> io::Result { - self.input.read_u8() - } - - #[inline] - fn read_u16(&mut self) -> io::Result { - self.input.read_u16::() - } - - #[inline] - fn read_u32(&mut self) -> io::Result { - self.input.read_u32::() - } - - #[inline] - fn read_u64(&mut self) -> io::Result { - self.input.read_u64::() - } - - #[inline] - fn read_i8(&mut self) -> io::Result { - self.input.read_i8() - } - - #[inline] - fn read_i16(&mut self) -> io::Result { - self.input.read_i16::() - } - - #[inline] - fn read_i32(&mut self) -> io::Result { - self.input.read_i32::() - } - - #[inline] - fn read_f32(&mut self) -> io::Result { - self.input.read_f32::() - } - - #[inline] - fn read_f64(&mut self) -> io::Result { - self.input.read_f64::() - } -} diff --git a/swf/src/string.rs b/swf/src/string.rs index 58ce7ff80df5..c9b3b4489865 100644 --- a/swf/src/string.rs +++ b/swf/src/string.rs @@ -157,7 +157,7 @@ impl SwfStr { /// assert_eq!(s.as_bytes(), [0xF0, 0x9F, 0x92, 0x96]); /// ``` #[inline] - pub fn as_bytes(&self) -> &[u8] { + pub const fn as_bytes(&self) -> &[u8] { &self.string } @@ -174,7 +174,7 @@ impl SwfStr { /// let s = SwfStr::from_utf8_str("💖"); /// assert!(!s.is_empty()); #[inline] - pub fn is_empty(&self) -> bool { + pub const fn is_empty(&self) -> bool { self.string.is_empty() } @@ -195,7 +195,7 @@ impl SwfStr { /// assert_eq!(s.len(), 4); /// ``` #[inline] - pub fn len(&self) -> usize { + pub const fn len(&self) -> usize { self.string.len() } diff --git a/swf/src/tag_code.rs b/swf/src/tag_code.rs index d1a3ed8af6a4..3e0017b0ae78 100644 --- a/swf/src/tag_code.rs +++ b/swf/src/tag_code.rs @@ -95,12 +95,4 @@ impl TagCode { pub fn from_u16(n: u16) -> Option { num_traits::FromPrimitive::from_u16(n) } - - pub fn name(n: u16) -> String { - if let Some(n) = TagCode::from_u16(n) { - format!("{:?}", n) - } else { - format!("Unknown({})", n) - } - } } diff --git a/swf/src/types.rs b/swf/src/types.rs index e6a7ba4163a7..e6177d97cf76 100644 --- a/swf/src/types.rs +++ b/swf/src/types.rs @@ -98,7 +98,7 @@ impl Twips { /// let twips = Twips::zero(); /// assert_eq!(twips.get(), 0); /// ``` - pub fn zero() -> Self { + pub const fn zero() -> Self { Self(0) } @@ -112,7 +112,7 @@ impl Twips { /// let twips = Twips::new(47); /// assert_eq!(twips.get(), 47); /// ``` - pub fn get(self) -> i32 { + pub const fn get(self) -> i32 { self.0 } @@ -170,7 +170,7 @@ impl Twips { /// assert_eq!(Twips::new(i32::MIN).saturating_sub(Twips::new(5)), Twips::new(i32::MIN)); /// assert_eq!(Twips::new(i32::MAX).saturating_sub(Twips::new(-100)), Twips::new(i32::MAX)); /// ``` - pub fn saturating_sub(self, rhs: Self) -> Self { + pub const fn saturating_sub(self, rhs: Self) -> Self { Self(self.0.saturating_sub(rhs.0)) } } @@ -287,7 +287,7 @@ impl Color { /// let green = Color::from_rgb(0x00FF00, 255); /// let blue = Color::from_rgb(0x0000FF, 255); /// ``` - pub fn from_rgb(rgb: u32, alpha: u8) -> Self { + pub const fn from_rgb(rgb: u32, alpha: u8) -> Self { Self { r: ((rgb & 0xFF_0000) >> 16) as u8, g: ((rgb & 0x00_FF00) >> 8) as u8, @@ -318,7 +318,7 @@ impl Color { /// let color2 = Color::from_rgb(0xFF00FF, 0); /// assert_eq!(color1.to_rgb(), color2.to_rgb()); /// ``` - pub fn to_rgb(&self) -> u32 { + pub const fn to_rgb(&self) -> u32 { ((self.r as u32) << 16) | ((self.g as u32) << 8) | (self.b as u32) } } @@ -336,7 +336,7 @@ pub struct ColorTransform { } impl ColorTransform { - pub fn new() -> ColorTransform { + pub const fn new() -> ColorTransform { ColorTransform { r_multiply: 1f32, g_multiply: 1f32, @@ -874,7 +874,7 @@ pub struct LineStyle { } impl LineStyle { - pub fn new_v1(width: Twips, color: Color) -> LineStyle { + pub const fn new_v1(width: Twips, color: Color) -> LineStyle { LineStyle { width, color,