From 61628a74fc24f8098e73dc173994d4b849eb671e Mon Sep 17 00:00:00 2001 From: Mike Welsh Date: Mon, 18 Jan 2021 16:46:20 -0800 Subject: [PATCH] swf: Rename and organize some util methods * SwfRead -> SwfReadExt * SwfWrite -> SwfWriteExt * read_swf_header -> decompress_swf * read_swf -> parse_swf --- core/src/display_object/movie_clip.rs | 2 +- core/src/tag_utils.rs | 6 +- scanner/src/main.rs | 6 +- swf/examples/reading.rs | 4 +- swf/src/avm1/read.rs | 71 ++++++- swf/src/avm1/write.rs | 90 +++++++-- swf/src/avm2/read.rs | 74 ++++++-- swf/src/avm2/write.rs | 69 ++++++- swf/src/lib.rs | 2 +- swf/src/read.rs | 257 +++++++++++--------------- swf/src/test_data.rs | 6 +- swf/src/types.rs | 6 +- swf/src/write.rs | 117 +++++------- 13 files changed, 419 insertions(+), 291 deletions(-) diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index bafc54af7..0f64ba8bd 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -31,7 +31,7 @@ use std::cell::{Ref, RefCell}; use std::collections::HashMap; use std::convert::TryFrom; use std::sync::Arc; -use swf::read::SwfRead; +use swf::read::SwfReadExt; use swf::{FillStyle, FrameLabelData, LineStyle}; type FrameNumber = u16; diff --git a/core/src/tag_utils.rs b/core/src/tag_utils.rs index df875e78b..aae3c0f4f 100644 --- a/core/src/tag_utils.rs +++ b/core/src/tag_utils.rs @@ -73,10 +73,10 @@ impl SwfMovie { /// Construct a movie based on the contents of the SWF datastream. pub fn from_data(swf_data: &[u8], url: Option) -> Result { - let swf_stream = swf::read::read_swf_header(&swf_data[..])?; + let swf_buf = swf::read::decompress_swf(&swf_data[..])?; Ok(Self { - header: swf_stream.header, - data: swf_stream.data, + header: swf_buf.header, + data: swf_buf.data, url, parameters: PropertyMap::new(), }) diff --git a/scanner/src/main.rs b/scanner/src/main.rs index c90cdb476..8859caee4 100644 --- a/scanner/src/main.rs +++ b/scanner/src/main.rs @@ -1,7 +1,7 @@ use clap::Clap; use indicatif::{ProgressBar, ProgressStyle}; use path_slash::PathExt; -use ruffle_core::swf::{read_swf, read_swf_header}; +use ruffle_core::swf::{decompress_swf, parse_swf}; use serde::Serialize; use std::path::{Path, PathBuf}; @@ -65,8 +65,8 @@ fn scan_file(file: DirEntry, name: String) -> FileResults { } }; - let swf_stream = read_swf_header(&data[..]).unwrap(); - match catch_unwind(|| read_swf(&swf_stream)) { + let swf_buf = decompress_swf(&data[..]).unwrap(); + match catch_unwind(|| parse_swf(&swf_buf)) { Ok(swf) => match swf { Ok(_swf) => FileResults { name, error: None }, Err(e) => FileResults { diff --git a/swf/examples/reading.rs b/swf/examples/reading.rs index 771d76417..c3318a671 100644 --- a/swf/examples/reading.rs +++ b/swf/examples/reading.rs @@ -4,8 +4,8 @@ use std::io::BufReader; fn main() { let file = File::open("tests/swfs/SimpleRedBackground.swf").unwrap(); let reader = BufReader::new(file); - let swf_stream = swf::read_swf_header(reader).unwrap(); - let swf = swf::read_swf(&swf_stream).unwrap(); + let swf_buf = swf::decompress_swf(reader).unwrap(); + let swf = swf::parse_swf(&swf_buf).unwrap(); println!("The SWF has {} frame(s).", swf.header.num_frames); println!("The SWF has {} tag(s).", swf.tags.len()); } diff --git a/swf/src/avm1/read.rs b/swf/src/avm1/read.rs index cf7883bba..d5688d942 100644 --- a/swf/src/avm1/read.rs +++ b/swf/src/avm1/read.rs @@ -2,9 +2,10 @@ use crate::avm1::{opcode::OpCode, types::*}; use crate::error::{Error, Result}; -use crate::read::SwfRead; +use crate::read::SwfReadExt; use crate::string::SwfStr; -use std::io; +use byteorder::{LittleEndian, ReadBytesExt}; +use std::io::{self, Read}; #[allow(dead_code)] pub struct Reader<'a> { @@ -13,12 +14,6 @@ pub struct Reader<'a> { encoding: &'static encoding_rs::Encoding, } -impl<'a> SwfRead<&'a [u8]> for Reader<'a> { - fn get_inner(&mut self) -> &mut &'a [u8] { - &mut self.input - } -} - impl<'a> Reader<'a> { pub fn new(input: &'a [u8], version: u8) -> Self { Self { @@ -75,6 +70,19 @@ impl<'a> Reader<'a> { 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()?; @@ -394,6 +402,53 @@ 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::*; diff --git a/swf/src/avm1/write.rs b/swf/src/avm1/write.rs index 410e40ee2..6c97828da 100644 --- a/swf/src/avm1/write.rs +++ b/swf/src/avm1/write.rs @@ -2,24 +2,86 @@ use crate::avm1::opcode::OpCode; use crate::avm1::types::*; -use crate::write::SwfWrite; -use std::io::{Result, Write}; +use crate::string::SwfStr; +use crate::write::SwfWriteExt; +use byteorder::{LittleEndian, WriteBytesExt}; +use std::io::{self, Result, Write}; #[allow(dead_code)] pub struct Writer { - inner: W, + output: W, version: u8, } -impl SwfWrite for Writer { - fn get_inner(&mut self) -> &mut W { - &mut self.inner +impl SwfWriteExt for Writer { + #[inline] + fn write_u8(&mut self, n: u8) -> io::Result<()> { + self.output.write_u8(n) + } + + #[inline] + fn write_u16(&mut self, n: u16) -> io::Result<()> { + self.output.write_u16::(n) + } + + #[inline] + fn write_u32(&mut self, n: u32) -> io::Result<()> { + self.output.write_u32::(n) + } + + #[inline] + fn write_u64(&mut self, n: u64) -> io::Result<()> { + self.output.write_u64::(n) + } + + #[inline] + fn write_i8(&mut self, n: i8) -> io::Result<()> { + self.output.write_i8(n) + } + + #[inline] + fn write_i16(&mut self, n: i16) -> io::Result<()> { + self.output.write_i16::(n) + } + + #[inline] + fn write_i32(&mut self, n: i32) -> io::Result<()> { + self.output.write_i32::(n) + } + + #[inline] + fn write_f32(&mut self, n: f32) -> io::Result<()> { + self.output.write_f32::(n) + } + + #[inline] + fn write_f64(&mut self, n: f64) -> io::Result<()> { + self.output.write_f64::(n) + } + + #[inline] + fn write_string(&mut self, s: SwfStr<'_>) -> io::Result<()> { + self.output.write_all(s.as_bytes())?; + self.write_u8(0) } } impl Writer { - pub fn new(inner: W, version: u8) -> Writer { - Writer { inner, version } + pub fn new(output: W, version: u8) -> Writer { + Writer { output, version } + } + + #[inline] + fn write_f64_me(&mut self, n: f64) -> 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]; + (&mut num[..]).write_f64::(n)?; + num.swap(0, 4); + num.swap(1, 5); + num.swap(2, 6); + num.swap(3, 7); + self.output.write_all(&num) } #[allow(clippy::inconsistent_digit_grouping)] @@ -66,7 +128,7 @@ impl Writer { self.write_string(*param)?; } self.write_u16(actions.len() as u16)?; - self.inner.write_all(actions)?; + self.output.write_all(actions)?; } Action::DefineFunction2(ref function) => { let len = function.name.len() @@ -111,7 +173,7 @@ impl Writer { self.write_string(param.name)?; } self.write_u16(function.actions.len() as u16)?; - self.inner.write_all(&function.actions)?; + self.output.write_all(&function.actions)?; } Action::DefineLocal => self.write_action_header(OpCode::DefineLocal, 0)?, Action::DefineLocal2 => self.write_action_header(OpCode::DefineLocal2, 0)?, @@ -304,7 +366,7 @@ impl Writer { Some((CatchVar::Register(i), _)) => self.write_u8(i)?, _ => (), } - self.inner.write_all(&action_buf)?; + self.output.write_all(&action_buf)?; } Action::TypeOf => self.write_action_header(OpCode::TypeOf, 0)?, Action::WaitForFrame { @@ -323,11 +385,11 @@ impl Writer { } Action::With { ref actions } => { self.write_action_header(OpCode::With, actions.len())?; - self.inner.write_all(&actions)?; + self.output.write_all(&actions)?; } Action::Unknown { opcode, ref data } => { self.write_opcode_and_length(opcode, data.len())?; - self.inner.write_all(data)?; + self.output.write_all(data)?; } } @@ -376,7 +438,7 @@ impl Writer { } Value::Double(v) => { self.write_u8(6)?; - self.write_f64(v)?; + self.write_f64_me(v)?; } Value::Int(v) => { self.write_u8(7)?; diff --git a/swf/src/avm2/read.rs b/swf/src/avm2/read.rs index b496b9a26..65aa1b34f 100644 --- a/swf/src/avm2/read.rs +++ b/swf/src/avm2/read.rs @@ -1,16 +1,11 @@ use crate::avm2::types::*; use crate::error::{Error, Result}; -use crate::read::SwfRead; -use std::io::{Read, Seek, SeekFrom}; +use crate::read::SwfReadExt; +use byteorder::{LittleEndian, ReadBytesExt}; +use std::io::{self, Read, Seek, SeekFrom}; pub struct Reader { - inner: R, -} - -impl SwfRead for Reader { - fn get_inner(&mut self) -> &mut R { - &mut self.inner - } + input: R, } impl Reader @@ -19,13 +14,13 @@ where { #[inline] pub fn seek(&mut self, relative_offset: i64) -> std::io::Result { - self.inner.seek(SeekFrom::Current(relative_offset as i64)) + self.input.seek(SeekFrom::Current(relative_offset as i64)) } } impl Reader { - pub fn new(inner: R) -> Reader { - Reader { inner } + pub fn new(input: R) -> Reader { + Reader { input } } pub fn read(&mut self) -> Result { @@ -128,7 +123,7 @@ impl Reader { fn read_string(&mut self) -> Result { let len = self.read_u30()? as usize; let mut s = String::with_capacity(len); - self.inner + self.input .by_ref() .take(len as u64) .read_to_string(&mut s)?; @@ -501,7 +496,7 @@ impl Reader { // Read the code data. let code_len = self.read_u30()?; let mut code = Vec::with_capacity(code_len as usize); - self.inner + self.input .by_ref() .take(code_len.into()) .read_to_end(&mut code)?; @@ -866,6 +861,53 @@ 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::*; @@ -874,8 +916,8 @@ pub mod tests { pub fn read_abc_from_file(path: &str) -> Vec { use crate::types::Tag; let data = std::fs::read(path).unwrap(); - let swf_stream = crate::read_swf_header(&data[..]).unwrap(); - let swf = crate::read_swf(&swf_stream).unwrap(); + let swf_buf = crate::decompress_swf(&data[..]).unwrap(); + let swf = crate::parse_swf(&swf_buf).unwrap(); for tag in swf.tags { if let Tag::DoAbc(do_abc) = tag { return do_abc.data.to_vec(); diff --git a/swf/src/avm2/write.rs b/swf/src/avm2/write.rs index 781975ae2..8114134ea 100644 --- a/swf/src/avm2/write.rs +++ b/swf/src/avm2/write.rs @@ -1,21 +1,70 @@ use crate::avm2::opcode::OpCode; use crate::avm2::types::*; -use crate::write::SwfWrite; -use std::io::{Result, Write}; +use crate::string::SwfStr; +use crate::write::SwfWriteExt; +use byteorder::{LittleEndian, WriteBytesExt}; +use std::io::{self, Result, Write}; pub struct Writer { - inner: W, + output: W, } -impl SwfWrite for Writer { - fn get_inner(&mut self) -> &mut W { - &mut self.inner +impl SwfWriteExt for Writer { + #[inline] + fn write_u8(&mut self, n: u8) -> io::Result<()> { + self.output.write_u8(n) + } + + #[inline] + fn write_u16(&mut self, n: u16) -> io::Result<()> { + self.output.write_u16::(n) + } + + #[inline] + fn write_u32(&mut self, n: u32) -> io::Result<()> { + self.output.write_u32::(n) + } + + #[inline] + fn write_u64(&mut self, n: u64) -> io::Result<()> { + self.output.write_u64::(n) + } + + #[inline] + fn write_i8(&mut self, n: i8) -> io::Result<()> { + self.output.write_i8(n) + } + + #[inline] + fn write_i16(&mut self, n: i16) -> io::Result<()> { + self.output.write_i16::(n) + } + + #[inline] + fn write_i32(&mut self, n: i32) -> io::Result<()> { + self.output.write_i32::(n) + } + + #[inline] + fn write_f32(&mut self, n: f32) -> io::Result<()> { + self.output.write_f32::(n) + } + + #[inline] + fn write_f64(&mut self, n: f64) -> io::Result<()> { + self.output.write_f64::(n) + } + + #[inline] + fn write_string(&mut self, s: SwfStr<'_>) -> io::Result<()> { + self.output.write_all(s.as_bytes())?; + self.write_u8(0) } } impl Writer { - pub fn new(inner: W) -> Writer { - Writer { inner } + pub fn new(output: W) -> Writer { + Writer { output } } pub fn write(&mut self, abc_file: AbcFile) -> Result<()> { @@ -105,7 +154,7 @@ impl Writer { fn write_string(&mut self, s: &str) -> Result<()> { self.write_u30(s.len() as u32)?; - self.inner.write_all(s.as_bytes())?; + self.output.write_all(s.as_bytes())?; Ok(()) } @@ -525,7 +574,7 @@ impl Writer { self.write_u30(method_body.max_scope_depth)?; self.write_u30(method_body.code.len() as u32)?; - self.inner.write_all(&method_body.code)?; + self.output.write_all(&method_body.code)?; self.write_u30(method_body.exceptions.len() as u32)?; for exception in &method_body.exceptions { diff --git a/swf/src/lib.rs b/swf/src/lib.rs index de5b538d2..0fe0ec17e 100644 --- a/swf/src/lib.rs +++ b/swf/src/lib.rs @@ -30,7 +30,7 @@ pub mod write; mod test_data; /// Reexports -pub use read::{read_swf, read_swf_header}; +pub use read::{decompress_swf, parse_swf}; pub use string::*; pub use tag_code::TagCode; pub use types::*; diff --git a/swf/src/read.rs b/swf/src/read.rs index da6194c6b..6b0a0956e 100644 --- a/swf/src/read.rs +++ b/swf/src/read.rs @@ -16,36 +16,21 @@ use enumset::EnumSet; use std::collections::HashSet; use std::io::{self, Read}; -/// Convenience method to parse an SWF. -/// -/// Decompresses the SWF in memory and returns a `Vec` of tags. -/// If you would like to stream the SWF instead, use `read_swf_header` and -/// `read_tag`. +/// Parse a decompressed SWF and return a `Vec` of tags. /// /// # Example /// ``` /// # std::env::set_current_dir(env!("CARGO_MANIFEST_DIR")); /// let data = std::fs::read("tests/swfs/DefineSprite.swf").unwrap(); -/// let stream = swf::read_swf_header(&data[..]).unwrap(); -/// let swf = swf::read_swf(&stream).unwrap(); +/// let stream = swf::decompress_swf(&data[..]).unwrap(); +/// let swf = swf::parse_swf(&stream).unwrap(); /// println!("Number of frames: {}", swf.header.num_frames); /// ``` -pub fn read_swf<'a>(swf_stream: &'a SwfStream) -> Result> { - // // Some SWF streams may not be compressed correctly, - // // (e.g. incorrect data length in the stream), so decompressing - // // may throw an error even though the data otherwise comes - // // through the stream. - // // We'll still try to parse what we get if the full decompression fails. - // if let Err(e) = reader.get_mut().read_to_end(&mut data) { - // log::warn!("Error decompressing SWF stream, may be corrupt: {}", e); - // } - // if data.len() != header.uncompressed_length.try_into().unwrap() { - // log::warn!("SWF length doesn't match header, may be corrupt"); - // } - let mut reader = Reader::new(&swf_stream.data[..], swf_stream.header.version); +pub fn parse_swf<'a>(swf_buf: &'a SwfBuf) -> Result> { + let mut reader = Reader::new(&swf_buf.data[..], swf_buf.header.version); Ok(Swf { - header: swf_stream.header.clone(), + header: swf_buf.header.clone(), tags: reader.read_tag_list()?, }) } @@ -59,22 +44,18 @@ pub fn read_swf<'a>(swf_stream: &'a SwfStream) -> Result> { /// ``` /// # std::env::set_current_dir(env!("CARGO_MANIFEST_DIR")); /// let data = std::fs::read("tests/swfs/DefineSprite.swf").unwrap(); -/// let swf_stream = swf::read_swf_header(&data[..]).unwrap(); +/// let swf_stream = swf::decompress_swf(&data[..]).unwrap(); /// println!("FPS: {}", swf_stream.header.frame_rate); /// ``` -pub fn read_swf_header<'a, R: Read + 'a>(mut input: R) -> Result { +pub fn decompress_swf<'a, R: Read + 'a>(mut input: R) -> Result { // Read SWF header. let compression = read_compression_type(&mut input)?; let version = input.read_u8()?; let uncompressed_length = input.read_u32::()?; // Now the SWF switches to a compressed stream. - let decompressed_input: Vec = match compression { - Compression::None => { - let mut data = Vec::with_capacity(uncompressed_length as usize); - input.read_to_end(&mut data)?; - data - } + let mut decompress_stream: Box = match compression { + Compression::None => Box::new(input), Compression::Zlib => { if version < 6 { log::warn!( @@ -82,10 +63,7 @@ pub fn read_swf_header<'a, R: Read + 'a>(mut input: R) -> Result { version ); } - let mut reader = make_zlib_reader(input)?; - let mut data = Vec::with_capacity(uncompressed_length as usize); - reader.read_to_end(&mut data)?; - data + make_zlib_reader(input)? } Compression::Lzma => { if version < 13 { @@ -96,13 +74,24 @@ pub fn read_swf_header<'a, R: Read + 'a>(mut input: R) -> Result { } // Uncompressed length includes the 4-byte header and 4-byte uncompressed length itself, // subtract it here. - let mut reader = make_lzma_reader(input, uncompressed_length - 8)?; - let mut data = Vec::with_capacity(uncompressed_length as usize); - reader.read_to_end(&mut data)?; - data + make_lzma_reader(input, uncompressed_length - 8)? } }; + // Some SWF streams may not be compressed correctly, + // (e.g. incorrect data length in the stream), so decompressing + // may throw an error even though the data otherwise comes + // through the stream. + // We'll still try to parse what we get if the full decompression fails. + let mut decompressed_input = Vec::with_capacity(uncompressed_length as usize); + if let Err(e) = decompress_stream.read_to_end(&mut decompressed_input) { + log::error!("Error decompressing SWF: {}", e); + } + + if decompressed_input.len() as u64 != uncompressed_length as u64 { + log::warn!("SWF length doesn't match header, may be corrupt"); + } + let mut reader = Reader::new(&decompressed_input, version); let stage_size = reader.read_rectangle()?; let frame_rate = reader.read_fixed8()?; @@ -116,7 +105,7 @@ pub fn read_swf_header<'a, R: Read + 'a>(mut input: R) -> Result { num_frames, }; let data = reader.get_ref().to_vec(); - Ok(SwfStream { header, data }) + Ok(SwfBuf { header, data }) } #[cfg(feature = "flate2")] @@ -191,64 +180,16 @@ fn make_lzma_reader<'a, R: Read + 'a>( )) } -pub trait SwfRead { - fn get_inner(&mut self) -> &mut R; - - fn read_u8(&mut self) -> io::Result { - self.get_inner().read_u8() - } - - fn read_u16(&mut self) -> io::Result { - self.get_inner().read_u16::() - } - - fn read_u32(&mut self) -> io::Result { - self.get_inner().read_u32::() - } - - fn read_u64(&mut self) -> io::Result { - self.get_inner().read_u64::() - } - - fn read_i8(&mut self) -> io::Result { - self.get_inner().read_i8() - } - - fn read_i16(&mut self) -> io::Result { - self.get_inner().read_i16::() - } - - fn read_i32(&mut self) -> io::Result { - self.get_inner().read_i32::() - } - - fn read_fixed8(&mut self) -> io::Result { - self.read_i16().map(|n| f32::from(n) / 256f32) - } - - fn read_fixed16(&mut self) -> io::Result { - self.read_i32().map(|n| f64::from(n) / 65536f64) - } - - fn read_f32(&mut self) -> io::Result { - self.get_inner().read_f32::() - } - - fn read_f64(&mut self) -> io::Result { - self.get_inner().read_f64::() - } - - 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.get_inner().read_exact(&mut num)?; - num.swap(0, 4); - num.swap(1, 5); - num.swap(2, 6); - num.swap(3, 7); - (&num[..]).read_f64::() - } +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> { @@ -316,44 +257,6 @@ pub struct Reader<'a> { encoding: &'static encoding_rs::Encoding, } -impl<'a> SwfRead<&'a [u8]> for Reader<'a> { - fn get_inner(&mut self) -> &mut &'a [u8] { - &mut self.input - } - - fn read_u8(&mut self) -> io::Result { - self.input.read_u8() - } - - fn read_u16(&mut self) -> io::Result { - self.input.read_u16::() - } - - fn read_u32(&mut self) -> io::Result { - self.input.read_u32::() - } - - fn read_i8(&mut self) -> io::Result { - self.input.read_i8() - } - - fn read_i16(&mut self) -> io::Result { - self.input.read_i16::() - } - - fn read_i32(&mut self) -> io::Result { - self.input.read_i32::() - } - - fn read_f32(&mut self) -> io::Result { - self.input.read_f32::() - } - - fn read_f64(&mut self) -> io::Result { - self.input.read_f64::() - } -} - impl<'a> Reader<'a> { pub fn new(input: &'a [u8], version: u8) -> Reader<'a> { Reader { @@ -386,12 +289,22 @@ impl<'a> Reader<'a> { fn bits<'b>(&'b mut self) -> BitReader<'a, 'b> { BitReader { - input: self.get_inner(), + input: &mut self.input, byte: 0, bit_index: 0, } } + #[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]; @@ -442,8 +355,8 @@ impl<'a> Reader<'a> { /// ``` /// # std::env::set_current_dir(env!("CARGO_MANIFEST_DIR")); /// let data = std::fs::read("tests/swfs/DefineSprite.swf").unwrap(); - /// let mut swf_stream = swf::read_swf_header(&data[..]).unwrap(); - /// let mut reader = swf::read::Reader::new(&swf_stream.data[..], swf_stream.header.version); + /// let mut swf_buf = swf::decompress_swf(&data[..]).unwrap(); + /// let mut reader = swf::read::Reader::new(&swf_buf.data[..], swf_buf.header.version); /// while let Ok(tag) = reader.read_tag() { /// println!("Tag: {:?}", tag); /// } @@ -2932,17 +2845,6 @@ pub fn read_compression_type(mut input: R) -> Result { Ok(compression) } -// pub fn read_rectangle(mut input: R) -> Result { -// let mut bits = self.bits(); -// let num_bits: u32 = bits.read_ubits(5)?; -// Ok(Rectangle { -// x_min: bits.read_sbits_twips(num_bits)?, -// x_max: bits.read_sbits_twips(num_bits)?, -// y_min: bits.read_sbits_twips(num_bits)?, -// y_max: bits.read_sbits_twips(num_bits)?, -// }) -// } - #[cfg(test)] pub mod tests { use super::*; @@ -2971,15 +2873,15 @@ pub mod tests { file.read_to_end(&mut data).unwrap(); // Halfway parse the SWF file until we find the tag we're searching for. - let swf_stream = super::read_swf_header(&data[..]).unwrap(); - let data = swf_stream.data; + let swf_buf = super::decompress_swf(&data[..]).unwrap(); + let data = swf_buf.data; let mut pos = 0; let mut tag_header_length; dbg!(tag_code); loop { let (swf_tag_code, length) = { - let mut tag_reader = Reader::new(&data[pos..], swf_stream.header.version); + let mut tag_reader = Reader::new(&data[pos..], swf_buf.header.version); let ret = tag_reader.read_tag_code_and_length().unwrap(); tag_header_length = tag_reader.get_ref().as_ptr() as usize - (pos + data.as_ptr() as usize); @@ -3023,9 +2925,9 @@ pub mod tests { #[test] fn read_swfs() { - fn read_from_file(path: &str) -> SwfStream { + fn read_from_file(path: &str) -> SwfBuf { let data = std::fs::read(path).unwrap(); - read_swf_header(&data[..]).unwrap() + decompress_swf(&data[..]).unwrap() } assert_eq!( @@ -3049,7 +2951,7 @@ pub mod tests { #[test] fn read_invalid_swf() { let junk = [0u8; 128]; - let result = read_swf_header(&junk[..]); + let result = decompress_swf(&junk[..]); // TODO: Verify correct error. assert!(result.is_err()); } @@ -3427,3 +3329,50 @@ 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/test_data.rs b/swf/src/test_data.rs index 69f6aba7f..bab003be0 100644 --- a/swf/src/test_data.rs +++ b/swf/src/test_data.rs @@ -4,7 +4,7 @@ use crate::avm1::types::*; use crate::avm2::read::tests::read_abc_from_file; use crate::avm2::types::*; use crate::read::tests::{read_tag_bytes_from_file, read_tag_bytes_from_file_with_index}; -use crate::read::{read_swf, read_swf_header}; +use crate::read::{decompress_swf, parse_swf}; use crate::string::SwfStr; use crate::tag_code::TagCode; use crate::types::*; @@ -16,8 +16,8 @@ use std::vec::Vec; #[allow(dead_code)] pub fn echo_swf(filename: &str) { let in_data = std::fs::read(filename).unwrap(); - let swf_stream = read_swf_header(&in_data[..]).unwrap(); - let swf = read_swf(&swf_stream).unwrap(); + let swf_buf = decompress_swf(&in_data[..]).unwrap(); + let swf = parse_swf(&swf_buf).unwrap(); let out_file = File::create(filename).unwrap(); write_swf(&swf, out_file).unwrap(); } diff --git a/swf/src/types.rs b/swf/src/types.rs index 8ae79ce74..74f361820 100644 --- a/swf/src/types.rs +++ b/swf/src/types.rs @@ -19,9 +19,9 @@ pub struct Swf<'a> { pub tags: Vec>, } -/// Returned by `read::read_swf_header`. Includes the decompress -/// stream as well as the uncompressed data length. -pub struct SwfStream { +/// Returned by `read::decompress_swf`. +/// Owns the decompressed SWF data, which will be referenced when parsed by `parse_swf`. +pub struct SwfBuf { pub header: Header, //pub reader: crate::read::Reader<'a>, pub data: Vec, diff --git a/swf/src/write.rs b/swf/src/write.rs index 9a71ed1c8..15547792d 100644 --- a/swf/src/write.rs +++ b/swf/src/write.rs @@ -133,73 +133,17 @@ fn write_lzma_swf(_output: W, _swf_body: &[u8]) -> Result<()> { )) } -pub trait SwfWrite { - fn get_inner(&mut self) -> &mut W; - - fn write_u8(&mut self, n: u8) -> io::Result<()> { - self.get_inner().write_u8(n) - } - - fn write_u16(&mut self, n: u16) -> io::Result<()> { - self.get_inner().write_u16::(n) - } - - fn write_u32(&mut self, n: u32) -> io::Result<()> { - self.get_inner().write_u32::(n) - } - - fn write_u64(&mut self, n: u64) -> io::Result<()> { - self.get_inner().write_u64::(n) - } - - fn write_i8(&mut self, n: i8) -> io::Result<()> { - self.get_inner().write_i8(n) - } - - fn write_i16(&mut self, n: i16) -> io::Result<()> { - self.get_inner().write_i16::(n) - } - - fn write_i32(&mut self, n: i32) -> io::Result<()> { - self.get_inner().write_i32::(n) - } - - fn write_fixed8(&mut self, n: f32) -> io::Result<()> { - self.write_i16((n * 256f32) as i16) - } - - fn write_fixed16(&mut self, n: f64) -> io::Result<()> { - self.write_i32((n * 65536f64) as i32) - } - - fn write_f32(&mut self, n: f32) -> io::Result<()> { - self.get_inner().write_f32::(n) - } - - fn write_f64(&mut self, n: f64) -> 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]; - (&mut num[..]).write_f64::(n)?; - num.swap(0, 4); - num.swap(1, 5); - num.swap(2, 6); - num.swap(3, 7); - self.get_inner().write_all(&num) - } - - fn write_string(&mut self, s: SwfStr<'_>) -> io::Result<()> { - self.get_inner().write_all(s.as_bytes())?; - self.write_u8(0) - } - - fn bits(&mut self) -> BitWriter<&mut W> { - BitWriter { - output: self.get_inner(), - byte: 0, - bit_index: 8, - } - } +pub trait SwfWriteExt { + fn write_u8(&mut self, n: u8) -> io::Result<()>; + fn write_u16(&mut self, n: u16) -> io::Result<()>; + fn write_u32(&mut self, n: u32) -> io::Result<()>; + fn write_u64(&mut self, n: u64) -> io::Result<()>; + fn write_i8(&mut self, n: i8) -> io::Result<()>; + fn write_i16(&mut self, n: i16) -> io::Result<()>; + fn write_i32(&mut self, n: i32) -> io::Result<()>; + fn write_f32(&mut self, n: f32) -> io::Result<()>; + fn write_f64(&mut self, n: f64) -> io::Result<()>; + fn write_string(&mut self, s: SwfStr<'_>) -> io::Result<()>; } pub struct BitWriter { @@ -272,43 +216,53 @@ struct Writer { pub version: u8, } -impl SwfWrite for Writer { - fn get_inner(&mut self) -> &mut W { - &mut self.output - } - +impl SwfWriteExt for Writer { + #[inline] fn write_u8(&mut self, n: u8) -> io::Result<()> { self.output.write_u8(n) } + #[inline] fn write_u16(&mut self, n: u16) -> io::Result<()> { self.output.write_u16::(n) } + #[inline] fn write_u32(&mut self, n: u32) -> io::Result<()> { self.output.write_u32::(n) } + #[inline] + fn write_u64(&mut self, n: u64) -> io::Result<()> { + self.output.write_u64::(n) + } + + #[inline] fn write_i8(&mut self, n: i8) -> io::Result<()> { self.output.write_i8(n) } + #[inline] fn write_i16(&mut self, n: i16) -> io::Result<()> { self.output.write_i16::(n) } + #[inline] fn write_i32(&mut self, n: i32) -> io::Result<()> { self.output.write_i32::(n) } + #[inline] fn write_f32(&mut self, n: f32) -> io::Result<()> { self.output.write_f32::(n) } + #[inline] fn write_f64(&mut self, n: f64) -> io::Result<()> { self.output.write_f64::(n) } + #[inline] fn write_string(&mut self, s: SwfStr<'_>) -> io::Result<()> { self.output.write_all(s.as_bytes())?; self.write_u8(0) @@ -325,6 +279,23 @@ impl Writer { self.output } + #[inline] + fn bits(&mut self) -> BitWriter<&mut W> { + BitWriter { + output: &mut self.output, + byte: 0, + bit_index: 8, + } + } + + fn write_fixed8(&mut self, n: f32) -> io::Result<()> { + self.write_i16((n * 256f32) as i16) + } + + fn write_fixed16(&mut self, n: f64) -> io::Result<()> { + self.write_i32((n * 65536f64) as i32) + } + fn write_encoded_u32(&mut self, mut n: u32) -> Result<()> { loop { let mut byte = (n & 0b01111111) as u8; @@ -2722,7 +2693,7 @@ impl Writer { } fn write_debug_id(&mut self, debug_id: &DebugId) -> Result<()> { - self.get_inner().write_all(debug_id)?; + self.output.write_all(debug_id)?; Ok(()) }