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"
num-derive = "0.2"
num-traits = "0.2"
xz2 = "0.1.5"
xz2 = {version = "0.1.5", optional = true}
[features]
default = []
default = []
lzma-support = ["xz2"]

View File

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

View File

@ -5,7 +5,6 @@ use flate2::read::ZlibDecoder;
use std::collections::HashSet;
use std::io::{Error, ErrorKind, Read, Result};
use types::*;
use xz2::read::XzDecoder;
/// Reads SWF data from a stream.
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 {
Compression::None => Box::new(input),
Compression::Zlib => Box::new(ZlibDecoder::new(input)),
Compression::Lzma => {
// 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))
}
Compression::Lzma => make_lzma_reader(input)?,
};
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))
}
#[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> {
fn get_inner(&mut self) -> &mut R;
@ -409,7 +416,7 @@ impl<R: Read> Reader<R> {
fn read_tag(&mut self) -> Result<Option<Tag>> {
use num_traits::FromPrimitive;
let (tag_code, length) = self.read_tag_code_and_length()?;
let mut tag_reader = Reader::new(self.input.by_ref().take(length as u64), self.version);
@ -2669,10 +2676,12 @@ pub mod tests {
read_from_file("tests/swfs/zlib.swf").compression,
Compression::Zlib
);
assert_eq!(
read_from_file("tests/swfs/lzma.swf").compression,
Compression::Lzma
);
if cfg!(feature = "lzma-support") {
assert_eq!(
read_from_file("tests/swfs/lzma.swf").compression,
Compression::Lzma
);
}
}
#[test]

View File

@ -9,7 +9,6 @@ use std::collections::HashSet;
use std::io::{Error, ErrorKind, Result, Write};
use tag_codes::TagCode;
use types::*;
use xz2::write::XzEncoder;
pub fn write_swf<W: Write>(swf: &Swf, mut output: W) -> Result<()> {
let signature = match swf.compression {
@ -52,22 +51,32 @@ 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
// standard LZMA header to SWF format.
// https://adobe.ly/2s8oYzn
Compression::Lzma => {
use xz2::stream::{Action, LzmaOptions, Stream};
let mut stream = Stream::new_lzma_encoder(&LzmaOptions::new_preset(9)?)?;
let mut lzma_header = [0; 13];
stream.process(&[], &mut lzma_header, Action::Run)?;
// Compressed length. We just write out a dummy value.
output.write_u32::<LittleEndian>(0xffffffff)?;
output.write_all(&lzma_header[0..5])?; // LZMA property bytes.
let mut encoder = XzEncoder::new_stream(&mut output, stream);
encoder.write_all(&swf_body)?;
}
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};
let mut stream = Stream::new_lzma_encoder(&LzmaOptions::new_preset(9)?)?;
let mut lzma_header = [0; 13];
stream.process(&[], &mut lzma_header, Action::Run)?;
// Compressed length. We just write out a dummy value.
output.write_u32::<LittleEndian>(0xffffffff)?;
output.write_all(&lzma_header[0..5])?; // LZMA property bytes.
let mut encoder = XzEncoder::new_stream(&mut output, stream);
encoder.write_all(&swf_body)?;
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> {
fn get_inner(&mut self) -> &mut W;
@ -2691,10 +2700,12 @@ mod tests {
write_dummy_swf(Compression::Zlib).is_ok(),
"Failed to write zlib SWF."
);
assert!(
write_dummy_swf(Compression::Lzma).is_ok(),
"Failed to write LZMA SWF."
);
if cfg!(feature = "lzma-support") {
assert!(
write_dummy_swf(Compression::Lzma).is_ok(),
"Failed to write LZMA SWF."
);
}
}
#[test]