Add test helper to read tag bytes from an SWF file.
This commit is contained in:
parent
f4e070feda
commit
f8f38450eb
88
src/read.rs
88
src/read.rs
|
@ -6,7 +6,14 @@ use types::*;
|
||||||
use xz2::read::XzDecoder;
|
use xz2::read::XzDecoder;
|
||||||
|
|
||||||
/// Reads SWF data from a stream.
|
/// Reads SWF data from a stream.
|
||||||
pub fn read_swf<R: Read>(mut input: R) -> Result<Swf> {
|
pub fn read_swf<R: Read>(input: R) -> Result<Swf> {
|
||||||
|
let (mut swf, mut reader) = try!(read_swf_header(input));
|
||||||
|
swf.tags = try!(reader.read_tag_list());
|
||||||
|
Ok(swf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_swf_header<'a, R: Read + 'a>(mut input: R) -> Result<(Swf, Reader<Box<Read + 'a>>)>
|
||||||
|
{
|
||||||
// Read SWF header.
|
// Read SWF header.
|
||||||
let compression = try!(Reader::read_compression_type(&mut input));
|
let compression = try!(Reader::read_compression_type(&mut input));
|
||||||
let version = try!(input.read_u8());
|
let version = try!(input.read_u8());
|
||||||
|
@ -35,24 +42,20 @@ pub fn read_swf<R: Read>(mut input: R) -> Result<Swf> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut reader = Reader::new(decompressed_input, version);
|
let mut reader = Reader::new(decompressed_input, version);
|
||||||
|
|
||||||
let stage_size = try!(reader.read_rectangle());
|
let stage_size = try!(reader.read_rectangle());
|
||||||
let frame_rate = try!(reader.read_fixed88());
|
let frame_rate = try!(reader.read_fixed88());
|
||||||
let num_frames = try!(reader.read_u16());
|
let num_frames = try!(reader.read_u16());
|
||||||
|
let swf = Swf {
|
||||||
let tags = try!(reader.read_tag_list());
|
|
||||||
|
|
||||||
Ok(Swf {
|
|
||||||
version: version,
|
version: version,
|
||||||
compression: compression,
|
compression: compression,
|
||||||
stage_size: stage_size,
|
stage_size: stage_size,
|
||||||
frame_rate: frame_rate,
|
frame_rate: frame_rate,
|
||||||
num_frames: num_frames,
|
num_frames: num_frames,
|
||||||
tags: tags,
|
tags: vec![],
|
||||||
})
|
};
|
||||||
|
Ok((swf, reader))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct Reader<R: Read> {
|
pub struct Reader<R: Read> {
|
||||||
input: R,
|
input: R,
|
||||||
version: u8,
|
version: u8,
|
||||||
|
@ -243,13 +246,7 @@ impl<R: Read> Reader<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_tag(&mut self) -> Result<Option<Tag>> {
|
fn read_tag(&mut self) -> Result<Option<Tag>> {
|
||||||
let tag_code_and_length = try!(self.read_u16());
|
let (tag_code, length) = try!(self.read_tag_code_and_length());
|
||||||
let tag_code = tag_code_and_length >> 6;
|
|
||||||
let mut length = (tag_code_and_length & 0b111111) as u32;
|
|
||||||
if length == 0b111111 {
|
|
||||||
// Extended tag.
|
|
||||||
length = try!(self.read_u32());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut tag_reader = Reader::new(self.input.by_ref().take(length as u64), self.version);
|
let mut tag_reader = Reader::new(self.input.by_ref().take(length as u64), self.version);
|
||||||
use tag_codes::TagCode;
|
use tag_codes::TagCode;
|
||||||
|
@ -278,9 +275,10 @@ impl<R: Read> Reader<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
let mut data = Vec::new();
|
let size = length as usize;
|
||||||
data.resize(length as usize, 0);
|
let mut data = Vec::with_capacity(size);
|
||||||
try!(tag_reader.input.read_exact(data.as_mut_slice()));
|
data.resize(size, 0);
|
||||||
|
try!(tag_reader.input.read_exact(&mut data[..]));
|
||||||
Tag::Unknown {
|
Tag::Unknown {
|
||||||
tag_code: tag_code,
|
tag_code: tag_code,
|
||||||
data: data,
|
data: data,
|
||||||
|
@ -291,6 +289,17 @@ impl<R: Read> Reader<R> {
|
||||||
Ok(Some(tag))
|
Ok(Some(tag))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_tag_code_and_length(&mut self) -> Result<(u16, usize)> {
|
||||||
|
let tag_code_and_length = try!(self.read_u16());
|
||||||
|
let tag_code = tag_code_and_length >> 6;
|
||||||
|
let mut length = (tag_code_and_length & 0b111111) as usize;
|
||||||
|
if length == 0b111111 {
|
||||||
|
// Extended tag.
|
||||||
|
length = try!(self.read_u32()) as usize;
|
||||||
|
}
|
||||||
|
Ok((tag_code, length))
|
||||||
|
}
|
||||||
|
|
||||||
fn read_define_scene_and_frame_label_data(&mut self) -> Result<Tag> {
|
fn read_define_scene_and_frame_label_data(&mut self) -> Result<Tag> {
|
||||||
let num_scenes = try!(self.read_encoded_u32()) as usize;
|
let num_scenes = try!(self.read_encoded_u32()) as usize;
|
||||||
let mut scenes = Vec::with_capacity(num_scenes);
|
let mut scenes = Vec::with_capacity(num_scenes);
|
||||||
|
@ -555,11 +564,37 @@ mod tests {
|
||||||
read_swf(&data[..]).unwrap()
|
read_swf(&data[..]).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reader_from_file(path: &str, version: u8) -> Reader<Cursor<Vec<u8>>> {
|
fn read_tag_bytes_from_file(path: &str, tag_code: TagCode) -> Vec<u8> {
|
||||||
|
use std::io::Cursor;
|
||||||
let mut file = File::open(path).unwrap();
|
let mut file = File::open(path).unwrap();
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
file.read_to_end(&mut data).unwrap();
|
file.read_to_end(&mut data).unwrap();
|
||||||
Reader::new(Cursor::new(data), version)
|
|
||||||
|
// Halfway parse the SWF file until we find the tag we're searching for.
|
||||||
|
let (swf, mut reader) = super::read_swf_header(&data[..]).unwrap();
|
||||||
|
|
||||||
|
let mut data = Vec::new();
|
||||||
|
reader.input.read_to_end(&mut data).unwrap();
|
||||||
|
let mut cursor = Cursor::new(data);
|
||||||
|
loop {
|
||||||
|
let pos = cursor.position();
|
||||||
|
let (swf_tag_code, length) = {
|
||||||
|
let mut tag_reader = Reader::new(&mut cursor, swf.version);
|
||||||
|
tag_reader.read_tag_code_and_length().unwrap()
|
||||||
|
};
|
||||||
|
let tag_header_length = cursor.position() - pos;
|
||||||
|
let mut data = Vec::new();
|
||||||
|
data.resize(length + tag_header_length as usize, 0);
|
||||||
|
cursor.set_position(pos);
|
||||||
|
cursor.read_exact(&mut data[..]).unwrap();
|
||||||
|
if swf_tag_code == 0 {
|
||||||
|
panic!("Tag not found");
|
||||||
|
} else {
|
||||||
|
if swf_tag_code == tag_code as u16 {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_tag_from_file(path: &str, version: u8) -> Tag {
|
fn read_tag_from_file(path: &str, version: u8) -> Tag {
|
||||||
|
@ -795,7 +830,10 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn read_define_shape() {
|
fn read_define_shape() {
|
||||||
let tag_bytes = read_tag_from_file("test/swfs/define_shape.bin", 1);
|
let tag_bytes = read_tag_bytes_from_file(
|
||||||
|
"test/swfs/define_shape.swf",
|
||||||
|
TagCode::DefineShape
|
||||||
|
);
|
||||||
let expected_tag = Tag::DefineShape(Shape {
|
let expected_tag = Tag::DefineShape(Shape {
|
||||||
version: 1,
|
version: 1,
|
||||||
id: 1,
|
id: 1,
|
||||||
|
@ -803,10 +841,10 @@ mod tests {
|
||||||
edge_bounds: Rectangle { x_min: 0f32, x_max: 20f32, y_min: 0f32, y_max: 20f32 },
|
edge_bounds: Rectangle { x_min: 0f32, x_max: 20f32, y_min: 0f32, y_max: 20f32 },
|
||||||
styles: ShapeStyles {
|
styles: ShapeStyles {
|
||||||
fill_styles: vec![
|
fill_styles: vec![
|
||||||
FillStyle::Color(Color { r: 0, g: 0, b: 0, a: 255 })
|
FillStyle::Color(Color { r: 255, g: 0, b: 0, a: 255 })
|
||||||
],
|
],
|
||||||
line_styles: vec![],
|
line_styles: vec![],
|
||||||
num_fill_bits: 4,
|
num_fill_bits: 1,
|
||||||
num_line_bits: 0,
|
num_line_bits: 0,
|
||||||
},
|
},
|
||||||
shape: vec![
|
shape: vec![
|
||||||
|
@ -836,7 +874,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
assert_eq!(read_tag_from_file("test/swfs/define_shape.bin", 8), expected_tag);
|
assert_eq!(reader(&tag_bytes).read_tag().unwrap().unwrap(), expected_tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
enum_from_primitive! {
|
enum_from_primitive! {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug,PartialEq,Clone)]
|
#[derive(Debug,PartialEq,Clone,Copy)]
|
||||||
pub enum TagCode {
|
pub enum TagCode {
|
||||||
End = 0,
|
End = 0,
|
||||||
ShowFrame = 1,
|
ShowFrame = 1,
|
||||||
|
|
|
@ -64,9 +64,6 @@ pub fn write_swf<W: Write>(swf: &Swf, mut output: W) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
static write_raw_tags: bool = false;
|
|
||||||
|
|
||||||
struct Writer<W: Write> {
|
struct Writer<W: Write> {
|
||||||
pub output: W,
|
pub output: W,
|
||||||
pub version: u8,
|
pub version: u8,
|
||||||
|
@ -580,7 +577,7 @@ fn count_fbits(n: f32) -> u8 {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use super::Writer;
|
use super::Writer;
|
||||||
use std::io::{Read, Result};
|
use std::io::{Read, Result, Write};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use types::*;
|
use types::*;
|
||||||
|
|
||||||
|
@ -988,6 +985,7 @@ mod tests {
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//write_tag_to_file("define_shape_test., 1)
|
||||||
assert_eq!(write_tag_to_buf(&tag, 1),
|
assert_eq!(write_tag_to_buf(&tag, 1),
|
||||||
get_file_contents("test/swfs/define_shape.bin"));
|
get_file_contents("test/swfs/define_shape.bin"));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue