swf: Fix compiling with lzma feature
This commit is contained in:
parent
160ec4d0c3
commit
1ab5211bfe
|
@ -26,4 +26,5 @@ default-features = false # can't use rayon on web
|
|||
approx = "0.3.2"
|
||||
|
||||
[features]
|
||||
default = ["minimp3"]
|
||||
default = ["minimp3", "lzma"]
|
||||
lzma = ["swf/lzma"]
|
||||
|
|
|
@ -71,15 +71,26 @@ impl<Audio: AudioBackend, Renderer: RenderBackend, Navigator: NavigatorBackend>
|
|||
let swf_stream = swf::read::read_swf_header(&swf_data[..]).unwrap();
|
||||
let header = swf_stream.header;
|
||||
let mut reader = swf_stream.reader;
|
||||
// Decompress the entire SWF in memory.
|
||||
let mut data = Vec::with_capacity(swf_stream.uncompressed_length);
|
||||
|
||||
// Decompress the entire SWF in memory.
|
||||
// Sometimes SWFs will have an incorrectly compressed stream,
|
||||
// but will otherwise decompress fine up to the End tag.
|
||||
// So just warn on this case and try to continue gracefully.
|
||||
let data = if header.compression == swf::Compression::Lzma {
|
||||
// TODO: The LZMA decoder is still funky.
|
||||
// It always errors, and doesn't return all the data if you use read_to_end,
|
||||
// but read_exact at least returns the data... why?
|
||||
// Does the decoder need to be flushed somehow?
|
||||
let mut data = vec![0u8; swf_stream.uncompressed_length];
|
||||
let _ = reader.get_mut().read_exact(&mut data);
|
||||
data
|
||||
} else {
|
||||
let mut data = Vec::with_capacity(swf_stream.uncompressed_length);
|
||||
if let Err(e) = reader.get_mut().read_to_end(&mut data) {
|
||||
log::error!("Error decompressing SWF, may be corrupt: {}", e);
|
||||
}
|
||||
data
|
||||
};
|
||||
|
||||
let swf_len = data.len();
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ num-traits = "0.2"
|
|||
libflate = {version = "0.1", optional = true}
|
||||
log = "0.4"
|
||||
flate2 = {version = "1.0", optional = true}
|
||||
xz2 = {version = "0.1.5", optional = true}
|
||||
xz2 = {version = "0.1.6", optional = true}
|
||||
|
||||
[features]
|
||||
default = ["libflate"]
|
||||
lzma-support = ["xz2"]
|
||||
lzma = ["xz2"]
|
|
@ -15,7 +15,7 @@ extern crate libflate;
|
|||
#[macro_use]
|
||||
extern crate num_derive;
|
||||
extern crate num_traits;
|
||||
#[cfg(feature = "lzma-support")]
|
||||
#[cfg(feature = "lzma")]
|
||||
extern crate xz2;
|
||||
|
||||
pub mod avm1;
|
||||
|
|
|
@ -29,7 +29,21 @@ pub fn read_swf<R: Read>(input: R) -> Result<Swf> {
|
|||
let mut reader = swf_stream.reader;
|
||||
|
||||
// Decompress all of SWF into memory at once.
|
||||
let mut data = if header.compression == Compression::Lzma {
|
||||
// TODO: The LZMA decoder is still funky.
|
||||
// It always errors, and doesn't return all the data if you use read_to_end,
|
||||
// but read_exact at least returns the data... why?
|
||||
// Does the decoder need to be flushed somehow?
|
||||
let mut data = vec![0u8; swf_stream.uncompressed_length];
|
||||
let _ = reader.get_mut().read_exact(&mut data);
|
||||
data
|
||||
} else {
|
||||
let mut data = Vec::with_capacity(swf_stream.uncompressed_length);
|
||||
if let Err(e) = reader.get_mut().read_to_end(&mut data) {
|
||||
log::error!("Error decompressing SWF, may be corrupt: {}", e);
|
||||
}
|
||||
data
|
||||
};
|
||||
let version = header.version;
|
||||
|
||||
// Some SWF streams may not be compressed correctly,
|
||||
|
@ -66,7 +80,10 @@ pub fn read_swf_header<'a, R: Read + 'a>(mut input: R) -> Result<SwfStream<'a>>
|
|||
// Read SWF header.
|
||||
let compression = Reader::read_compression_type(&mut input)?;
|
||||
let version = input.read_u8()?;
|
||||
let uncompressed_length = input.read_u32::<LittleEndian>()?;
|
||||
|
||||
// Uncompressed length includes the 4-byte header and 4-byte uncompressed length itself,
|
||||
// subtract it here.
|
||||
let uncompressed_length = input.read_u32::<LittleEndian>()? - 8;
|
||||
|
||||
// Now the SWF switches to a compressed stream.
|
||||
let decompressed_input: Box<dyn Read> = match compression {
|
||||
|
@ -87,7 +104,7 @@ pub fn read_swf_header<'a, R: Read + 'a>(mut input: R) -> Result<SwfStream<'a>>
|
|||
version
|
||||
);
|
||||
}
|
||||
make_lzma_reader(input)?
|
||||
make_lzma_reader(input, uncompressed_length)?
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -129,26 +146,57 @@ fn make_zlib_reader<'a, R: Read + 'a>(_input: R) -> Result<Box<dyn Read + 'a>> {
|
|||
))
|
||||
}
|
||||
|
||||
#[cfg(feature = "lzma-support")]
|
||||
fn make_lzma_reader<'a, R: Read + 'a>(mut input: R) -> Result<Box<dyn Read + 'a>> {
|
||||
// Flash uses a mangled LZMA header, so we have to massage it into the normal
|
||||
// format.
|
||||
#[cfg(feature = "lzma")]
|
||||
fn make_lzma_reader<'a, R: Read + 'a>(
|
||||
mut input: R,
|
||||
uncompressed_length: u32,
|
||||
) -> Result<Box<dyn Read + 'a>> {
|
||||
use byteorder::WriteBytesExt;
|
||||
use std::io::{Cursor, Write};
|
||||
use xz2::stream::{Action, Stream};
|
||||
input.read_u32::<LittleEndian>()?; // Compressed length
|
||||
use xz2::{
|
||||
read::XzDecoder,
|
||||
stream::{Action, Stream},
|
||||
};
|
||||
// Flash uses a mangled LZMA header, so we have to massage it into the normal format.
|
||||
// https://helpx.adobe.com/flash-player/kb/exception-thrown-you-decompress-lzma-compressed.html
|
||||
// LZMA SWF header:
|
||||
// Bytes 0..3: ZWS header
|
||||
// Byte 3: SWF version
|
||||
// Bytes 4..8: Uncompressed length
|
||||
// Bytes 8..12: Compressed length
|
||||
// Bytes 12..17: LZMA properties
|
||||
//
|
||||
// LZMA standard header
|
||||
// Bytes 0..5: LZMA properties
|
||||
// Bytes 5..13: Uncompressed length
|
||||
|
||||
// Read compressed length
|
||||
let _ = input.read_u32::<LittleEndian>()?;
|
||||
|
||||
// Read LZMA propreties to decoder
|
||||
let mut lzma_properties = [0u8; 5];
|
||||
input.read_exact(&mut lzma_properties)?;
|
||||
|
||||
// Rearrange above into LZMA format
|
||||
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)?;
|
||||
lzma_header.write_u64::<LittleEndian>(uncompressed_length.into())?;
|
||||
|
||||
// Create LZMA decoder stream and write header
|
||||
let mut lzma_stream = Stream::new_lzma_decoder(u64::max_value()).unwrap();
|
||||
lzma_stream
|
||||
.process(&lzma_header.into_inner(), &mut [0u8; 1], Action::Run)
|
||||
.unwrap();
|
||||
|
||||
// Decoder is ready
|
||||
Ok(Box::new(XzDecoder::new_stream(input, lzma_stream)))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "lzma-support"))]
|
||||
fn make_lzma_reader<'a, R: Read + 'a>(_input: R) -> Result<Box<dyn Read + 'a>> {
|
||||
#[cfg(not(feature = "lzma"))]
|
||||
fn make_lzma_reader<'a, R: Read + 'a>(
|
||||
_input: R,
|
||||
_uncompressed_length: u32,
|
||||
) -> Result<Box<dyn Read + 'a>> {
|
||||
Err(Error::unsupported(
|
||||
"Support for Zlib compressed SWFs is not enabled.",
|
||||
))
|
||||
|
@ -2862,7 +2910,7 @@ pub mod tests {
|
|||
read_from_file("tests/swfs/zlib.swf").header.compression,
|
||||
Compression::Zlib
|
||||
);
|
||||
if cfg!(feature = "lzma-support") {
|
||||
if cfg!(feature = "lzma") {
|
||||
assert_eq!(
|
||||
read_from_file("tests/swfs/lzma.swf").header.compression,
|
||||
Compression::Lzma
|
||||
|
|
|
@ -104,13 +104,15 @@ fn write_zlib_swf<W: Write>(_output: W, _swf_body: &[u8]) -> Result<()> {
|
|||
))
|
||||
}
|
||||
|
||||
#[cfg(feature = "lzma-support")]
|
||||
#[cfg(feature = "lzma")]
|
||||
fn write_lzma_swf<W: Write>(mut output: W, swf_body: &[u8]) -> Result<()> {
|
||||
use xz2::stream::{Action, LzmaOptions, Stream};
|
||||
use xz2::write::XzEncoder;
|
||||
let mut stream = Stream::new_lzma_encoder(&LzmaOptions::new_preset(9)?)?;
|
||||
use xz2::{
|
||||
stream::{Action, LzmaOptions, Stream},
|
||||
write::XzEncoder,
|
||||
};
|
||||
let mut stream = Stream::new_lzma_encoder(&LzmaOptions::new_preset(9).unwrap()).unwrap();
|
||||
let mut lzma_header = [0; 13];
|
||||
stream.process(&[], &mut lzma_header, Action::Run)?;
|
||||
stream.process(&[], &mut lzma_header, Action::Run).unwrap();
|
||||
// Compressed length. We just write out a dummy value.
|
||||
output.write_u32::<LittleEndian>(0xffffffff)?;
|
||||
output.write_all(&lzma_header[0..5])?; // LZMA property bytes.
|
||||
|
@ -119,7 +121,7 @@ fn write_lzma_swf<W: Write>(mut output: W, swf_body: &[u8]) -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "lzma-support"))]
|
||||
#[cfg(not(feature = "lzma"))]
|
||||
fn write_lzma_swf<W: Write>(_output: W, _swf_body: &[u8]) -> Result<()> {
|
||||
Err(Error::unsupported(
|
||||
"Support for LZMA compressed SWFs is not enabled.",
|
||||
|
@ -2792,7 +2794,7 @@ mod tests {
|
|||
write_dummy_swf(Compression::Zlib).is_ok(),
|
||||
"Failed to write zlib SWF."
|
||||
);
|
||||
if cfg!(feature = "lzma-support") {
|
||||
if cfg!(feature = "lzma") {
|
||||
assert!(
|
||||
write_dummy_swf(Compression::Lzma).is_ok(),
|
||||
"Failed to write LZMA SWF."
|
||||
|
|
Loading…
Reference in New Issue