Simplified filter function and moved to read.rs

Filter now occurs only if SWF fails to parse and re-calls the parse method
This commit is contained in:
theDecimeter 2024-04-01 19:45:08 -07:00
parent a3d3959652
commit 6a3d4017db
2 changed files with 30 additions and 50 deletions

View File

@ -151,62 +151,15 @@ impl SwfMovie {
Self::from_data(&data, url.into(), loader_url)
}
/// Construct a movie based on the contents of a datastream.
/// Construct a movie based on the contents of the SWF datastream.
pub fn from_data(
swf_data: &[u8],
url: String,
loader_url: Option<String>,
) -> Result<Self, Error> {
match Self::filter_from_projector_bundle(swf_data) {
Some(extracted_swf) => Self::from_swf_data(&extracted_swf, url, loader_url),
None => Self::from_swf_data(swf_data, url, loader_url),
}
}
/// Get an SWF from data if the data is a swf/projector bundle
fn filter_from_projector_bundle(data: &[u8]) -> Option<Vec<u8>> {
let len = data.len();
if len < 8 {
return None;
}
let signature = u32::from_le_bytes(
data[len - 8..len - 4]
.try_into()
.expect("4 bytes make a u32"),
);
if signature != 0xFA123456 {
return None;
}
let swf_size = usize::try_from(u32::from_le_bytes(
data[len - 4..len].try_into().expect("4 bytes make a u32"),
))
.expect("size should be at least 32 bits");
if swf_size > len - 8 {
//catch possible overflow
return None;
}
let offset = len - swf_size - 8;
let mut swf_data = Vec::with_capacity(swf_size);
for i in 0..swf_size {
swf_data.push(data[i + offset]);
}
Some(swf_data)
}
/// Construct a movie based on the contents of the SWF datastream.
fn from_swf_data(
swf_data: &[u8],
url: String,
loader_url: Option<String>,
) -> Result<Self, Error> {
let compressed_len = swf_data.len();
let swf_buf = swf::read::decompress_swf(swf_data)?;
let swf_buf = swf::read::decompress_swf(swf_data)
.or_else(|_| swf::read::decompress_projector_bundle(swf_data))?;
let encoding = swf::SwfStr::encoding_for_version(swf_buf.header.version());
let mut movie = Self {
header: swf_buf.header,

View File

@ -52,6 +52,33 @@ pub fn extract_swz(input: &[u8]) -> Result<Vec<u8>> {
Err(Error::invalid_data("Invalid ASN1 blob"))
}
/// Parses an SWF from data in an SWF projector bundle
/// Returns an `Error` if this is not a valid SWF projector bundle.
pub fn decompress_projector_bundle(data: &[u8]) -> Result<SwfBuf> {
let len = data.len();
if len < 8 {
return Err(Error::invalid_data("Invalid SWF projector bundle data"));
}
if data[len - 8..len - 4] != [0x56, 0x34, 0x12, 0xFA] {
return Err(Error::invalid_data(
"Invalid SWF projector bundle signature",
));
}
let swf_size = u32::from_le_bytes(
data[len - 4..]
.try_into()
.unwrap_or([0xFF, 0xFF, 0xFF, 0xFF]),
) as usize;
if swf_size > len - 8 {
//catch possible overflow
return Err(Error::invalid_data("Invalid SWF projector bundle size"));
}
decompress_swf(&data[len - 8 - swf_size..len - 8])
}
/// Parses an SWF header and returns a `Reader` that can be used
/// to read the SWF tags inside the SWF file.
///