refactor: make LZMA support an optional feature

This commit is contained in:
Mike Welsh 2018-06-10 11:58:08 -07:00
parent 120f94711a
commit 5a0e7a8fd3
4 changed files with 62 additions and 40 deletions

View File

@ -14,7 +14,8 @@ byteorder = "1.0"
flate2 = "1.0" flate2 = "1.0"
num-derive = "0.2" num-derive = "0.2"
num-traits = "0.2" num-traits = "0.2"
xz2 = "0.1.5" xz2 = {version = "0.1.5", optional = true}
[features] [features]
default = [] default = []
lzma-support = ["xz2"]

View File

@ -14,6 +14,7 @@ extern crate flate2;
#[macro_use] #[macro_use]
extern crate num_derive; extern crate num_derive;
extern crate num_traits; extern crate num_traits;
#[cfg(feature = "lzma-support")]
extern crate xz2; extern crate xz2;
pub mod avm1; pub mod avm1;

View File

@ -5,7 +5,6 @@ use flate2::read::ZlibDecoder;
use std::collections::HashSet; use std::collections::HashSet;
use std::io::{Error, ErrorKind, Read, Result}; use std::io::{Error, ErrorKind, Read, Result};
use types::*; use types::*;
use xz2::read::XzDecoder;
/// Reads SWF data from a stream. /// Reads SWF data from a stream.
pub fn read_swf<R: Read>(input: R) -> Result<Swf> { pub fn read_swf<R: Read>(input: R) -> Result<Swf> {
@ -24,22 +23,7 @@ fn read_swf_header<'a, R: Read + 'a>(mut input: R) -> Result<(Swf, Reader<Box<Re
let decompressed_input: Box<Read> = match compression { let decompressed_input: Box<Read> = match compression {
Compression::None => Box::new(input), Compression::None => Box::new(input),
Compression::Zlib => Box::new(ZlibDecoder::new(input)), Compression::Zlib => Box::new(ZlibDecoder::new(input)),
Compression::Lzma => { Compression::Lzma => make_lzma_reader(input)?,
// Flash uses a mangled LZMA header, so we have to massage it into the normal
// format.
use std::io::{Cursor, Write};
use xz2::stream::{Action, Stream};
use byteorder::WriteBytesExt;
input.read_u32::<LittleEndian>()?; // Compressed length
let mut lzma_properties = [0u8; 5];
input.read_exact(&mut lzma_properties)?;
let mut lzma_header = Cursor::new(Vec::with_capacity(13));
lzma_header.write_all(&lzma_properties)?;
lzma_header.write_u64::<LittleEndian>(uncompressed_length as u64)?;
let mut lzma_stream = Stream::new_lzma_decoder(u64::max_value())?;
lzma_stream.process(&lzma_header.into_inner(), &mut [0u8; 1], Action::Run)?;
Box::new(XzDecoder::new_stream(input, lzma_stream))
}
}; };
let mut reader = Reader::new(decompressed_input, version); let mut reader = Reader::new(decompressed_input, version);
@ -57,6 +41,29 @@ fn read_swf_header<'a, R: Read + 'a>(mut input: R) -> Result<(Swf, Reader<Box<Re
Ok((swf, reader)) Ok((swf, reader))
} }
#[cfg(feature = "lzma-support")]
fn make_lzma_reader<'a, R: Read + 'a>(mut input: R) -> Result<Box<Read + 'a>> {
// Flash uses a mangled LZMA header, so we have to massage it into the normal
// format.
use std::io::{Cursor, Write};
use xz2::stream::{Action, Stream};
use byteorder::WriteBytesExt;
input.read_u32::<LittleEndian>()?; // Compressed length
let mut lzma_properties = [0u8; 5];
input.read_exact(&mut lzma_properties)?;
let mut lzma_header = Cursor::new(Vec::with_capacity(13));
lzma_header.write_all(&lzma_properties)?;
lzma_header.write_u64::<LittleEndian>(uncompressed_length as u64)?;
let mut lzma_stream = Stream::new_lzma_decoder(u64::max_value())?;
lzma_stream.process(&lzma_header.into_inner(), &mut [0u8; 1], Action::Run)?;
Box::new(XzDecoder::new_stream(input, lzma_stream))
}
#[cfg(not(feature = "lzma-support"))]
fn make_lzma_reader<'a, R: Read + 'a>(_: R) -> Result<Box<Read + 'a>> {
Err(Error::new(ErrorKind::InvalidData, "Support for LZMA compressed SWFs is not enabled."))
}
pub trait SwfRead<R: Read> { pub trait SwfRead<R: Read> {
fn get_inner(&mut self) -> &mut R; fn get_inner(&mut self) -> &mut R;
@ -2669,11 +2676,13 @@ pub mod tests {
read_from_file("tests/swfs/zlib.swf").compression, read_from_file("tests/swfs/zlib.swf").compression,
Compression::Zlib Compression::Zlib
); );
if cfg!(feature = "lzma-support") {
assert_eq!( assert_eq!(
read_from_file("tests/swfs/lzma.swf").compression, read_from_file("tests/swfs/lzma.swf").compression,
Compression::Lzma Compression::Lzma
); );
} }
}
#[test] #[test]
fn read_invalid_swf() { fn read_invalid_swf() {

View File

@ -9,7 +9,6 @@ use std::collections::HashSet;
use std::io::{Error, ErrorKind, Result, Write}; use std::io::{Error, ErrorKind, Result, Write};
use tag_codes::TagCode; use tag_codes::TagCode;
use types::*; use types::*;
use xz2::write::XzEncoder;
pub fn write_swf<W: Write>(swf: &Swf, mut output: W) -> Result<()> { pub fn write_swf<W: Write>(swf: &Swf, mut output: W) -> Result<()> {
let signature = match swf.compression { let signature = match swf.compression {
@ -52,7 +51,15 @@ pub fn write_swf<W: Write>(swf: &Swf, mut output: W) -> Result<()> {
// SWF format has a mangled LZMA header, so we have to do some magic to conver the // SWF format has a mangled LZMA header, so we have to do some magic to conver the
// standard LZMA header to SWF format. // standard LZMA header to SWF format.
// https://adobe.ly/2s8oYzn // https://adobe.ly/2s8oYzn
Compression::Lzma => { Compression::Lzma => write_lzma_swf(&mut output)?,
};
Ok(())
}
#[cfg(feature = "lzma-support")]
fn write_lzma_swf<W: Write>(mut output: W) -> Result<()> {
use xz2::write::XzEncoder;
use xz2::stream::{Action, LzmaOptions, Stream}; use xz2::stream::{Action, LzmaOptions, Stream};
let mut stream = Stream::new_lzma_encoder(&LzmaOptions::new_preset(9)?)?; let mut stream = Stream::new_lzma_encoder(&LzmaOptions::new_preset(9)?)?;
let mut lzma_header = [0; 13]; let mut lzma_header = [0; 13];
@ -62,12 +69,14 @@ pub fn write_swf<W: Write>(swf: &Swf, mut output: W) -> Result<()> {
output.write_all(&lzma_header[0..5])?; // LZMA property bytes. output.write_all(&lzma_header[0..5])?; // LZMA property bytes.
let mut encoder = XzEncoder::new_stream(&mut output, stream); let mut encoder = XzEncoder::new_stream(&mut output, stream);
encoder.write_all(&swf_body)?; encoder.write_all(&swf_body)?;
}
};
Ok(()) Ok(())
} }
#[cfg(not(feature = "lzma-support"))]
fn write_lzma_swf<W: Write>(_: W) -> Result<()> {
Err(Error::new(ErrorKind::InvalidData, "Support for LZMA compressed SWFs is not enabled."))
}
pub trait SwfWrite<W: Write> { pub trait SwfWrite<W: Write> {
fn get_inner(&mut self) -> &mut W; fn get_inner(&mut self) -> &mut W;
@ -2691,11 +2700,13 @@ mod tests {
write_dummy_swf(Compression::Zlib).is_ok(), write_dummy_swf(Compression::Zlib).is_ok(),
"Failed to write zlib SWF." "Failed to write zlib SWF."
); );
if cfg!(feature = "lzma-support") {
assert!( assert!(
write_dummy_swf(Compression::Lzma).is_ok(), write_dummy_swf(Compression::Lzma).is_ok(),
"Failed to write LZMA SWF." "Failed to write LZMA SWF."
); );
} }
}
#[test] #[test]
fn write_fixed8() { fn write_fixed8() {