Merge branch 'ruffle'

This commit is contained in:
Mike Welsh 2019-08-18 16:30:07 -07:00
commit e11a8d416e
6 changed files with 341 additions and 200 deletions

View File

@ -193,7 +193,7 @@ impl<R: Read> Reader<R> {
OpCode::With => {
let code_length = action_reader.read_u16()?;
let mut with_reader = Reader::new(
(&mut action_reader.inner as &mut Read).take(code_length.into()),
(&mut action_reader.inner as &mut dyn Read).take(code_length.into()),
self.version,
);
Action::With {
@ -258,7 +258,7 @@ impl<R: Read> Reader<R> {
}
let code_length = self.read_u16()?;
let mut fn_reader = Reader::new(
(&mut self.inner as &mut Read).take(code_length.into()),
(&mut self.inner as &mut dyn Read).take(code_length.into()),
self.version,
);
Ok(Action::DefineFunction {
@ -283,7 +283,7 @@ impl<R: Read> Reader<R> {
}
let code_length = self.read_u16()?;
let mut fn_reader = Reader::new(
(&mut self.inner as &mut Read).take(code_length.into()),
(&mut self.inner as &mut dyn Read).take(code_length.into()),
self.version,
);
Ok(Action::DefineFunction2(Function {
@ -314,21 +314,21 @@ impl<R: Read> Reader<R> {
};
let try_actions = {
let mut fn_reader = Reader::new(
(&mut self.inner as &mut Read).take(try_length.into()),
(&mut self.inner as &mut dyn Read).take(try_length.into()),
self.version,
);
fn_reader.read_action_list()?
};
let catch_actions = {
let mut fn_reader = Reader::new(
(&mut self.inner as &mut Read).take(catch_length.into()),
(&mut self.inner as &mut dyn Read).take(catch_length.into()),
self.version,
);
fn_reader.read_action_list()?
};
let finally_actions = {
let mut fn_reader = Reader::new(
(&mut self.inner as &mut Read).take(finally_length.into()),
(&mut self.inner as &mut dyn Read).take(finally_length.into()),
self.version,
);
fn_reader.read_action_list()?

View File

@ -47,14 +47,16 @@ pub fn read_swf<R: Read>(input: R) -> Result<Swf> {
/// let (header, _reader) = swf::read_swf_header(&data[..]).unwrap();
/// println!("FPS: {}", header.frame_rate);
/// ```
pub fn read_swf_header<'a, R: Read + 'a>(mut input: R) -> Result<(Header, Reader<Box<Read + 'a>>)> {
pub fn read_swf_header<'a, R: Read + 'a>(
mut input: R,
) -> Result<(Header, Reader<Box<dyn Read + 'a>>)> {
// Read SWF header.
let compression = Reader::read_compression_type(&mut input)?;
let version = input.read_u8()?;
let _uncompressed_length = input.read_u32::<LittleEndian>()?;
// Now the SWF switches to a compressed stream.
let decompressed_input: Box<Read> = match compression {
let decompressed_input: Box<dyn Read> = match compression {
Compression::None => Box::new(input),
Compression::Zlib => make_zlib_reader(input)?,
Compression::Lzma => make_lzma_reader(input)?,
@ -75,20 +77,20 @@ pub fn read_swf_header<'a, R: Read + 'a>(mut input: R) -> Result<(Header, Reader
}
#[cfg(feature = "flate2")]
fn make_zlib_reader<'a, R: Read + 'a>(input: R) -> Result<Box<Read + 'a>> {
fn make_zlib_reader<'a, R: Read + 'a>(input: R) -> Result<Box<dyn Read + 'a>> {
use flate2::read::ZlibDecoder;
Ok(Box::new(ZlibDecoder::new(input)))
}
#[cfg(feature = "libflate")]
fn make_zlib_reader<'a, R: Read + 'a>(input: R) -> Result<Box<Read + 'a>> {
fn make_zlib_reader<'a, R: Read + 'a>(input: R) -> Result<Box<dyn Read + 'a>> {
use libflate::zlib::Decoder;
let decoder = Decoder::new(input)?;
Ok(Box::new(decoder))
}
#[cfg(not(any(feature = "flate2", feature = "libflate")))]
fn make_zlib_reader<'a, R: Read + 'a>(_input: R) -> Result<Box<Read + 'a>> {
fn make_zlib_reader<'a, R: Read + 'a>(_input: R) -> Result<Box<dyn Read + 'a>> {
Err(Error::new(
ErrorKind::InvalidData,
"Support for Zlib compressed SWFs is not enabled.",
@ -96,7 +98,7 @@ fn make_zlib_reader<'a, R: Read + 'a>(_input: R) -> Result<Box<Read + 'a>> {
}
#[cfg(feature = "lzma-support")]
fn make_lzma_reader<'a, R: Read + 'a>(mut input: R) -> Result<Box<Read + 'a>> {
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.
use byteorder::WriteBytesExt;
@ -114,7 +116,7 @@ fn make_lzma_reader<'a, R: Read + 'a>(mut input: R) -> Result<Box<Read + 'a>> {
}
#[cfg(not(feature = "lzma-support"))]
fn make_lzma_reader<'a, R: Read + 'a>(_input: R) -> Result<Box<Read + 'a>> {
fn make_lzma_reader<'a, R: Read + 'a>(_input: R) -> Result<Box<dyn Read + 'a>> {
Err(Error::new(
ErrorKind::InvalidData,
"Support for LZMA compressed SWFs is not enabled.",
@ -136,6 +138,10 @@ pub trait SwfRead<R: Read> {
self.get_inner().read_u32::<LittleEndian>()
}
fn read_u64(&mut self) -> Result<u64> {
self.get_inner().read_u64::<LittleEndian>()
}
fn read_i8(&mut self) -> Result<i8> {
self.get_inner().read_i8()
}
@ -279,8 +285,6 @@ impl<R: Read> Reader<R> {
/// }
/// ```
pub fn read_tag(&mut self) -> Result<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);
@ -310,8 +314,12 @@ impl<R: Read> Reader<R> {
}
Some(TagCode::DefineBitsJpeg3) => tag_reader.read_define_bits_jpeg_3(3)?,
Some(TagCode::DefineBitsJpeg4) => tag_reader.read_define_bits_jpeg_3(4)?,
Some(TagCode::DefineButton) => tag_reader.read_define_button()?,
Some(TagCode::DefineButton2) => tag_reader.read_define_button_2()?,
Some(TagCode::DefineButton) => {
Tag::DefineButton(Box::new(tag_reader.read_define_button_1()?))
}
Some(TagCode::DefineButton2) => {
Tag::DefineButton2(Box::new(tag_reader.read_define_button_2()?))
}
Some(TagCode::DefineButtonCxform) => {
let id = tag_reader.read_u16()?;
// SWF19 is incorrect here. It seems you can have many color transforms in this
@ -365,22 +373,34 @@ impl<R: Read> Reader<R> {
}))
}
Some(TagCode::DefineEditText) => tag_reader.read_define_edit_text()?,
Some(TagCode::DefineFont) => tag_reader.read_define_font()?,
Some(TagCode::DefineFont2) => tag_reader.read_define_font_2(2)?,
Some(TagCode::DefineFont3) => tag_reader.read_define_font_2(3)?,
Some(TagCode::DefineFont4) => tag_reader.read_define_font_4()?,
Some(TagCode::DefineFont) => {
Tag::DefineFont(Box::new(tag_reader.read_define_font_1()?))
}
Some(TagCode::DefineFont2) => {
Tag::DefineFont2(Box::new(tag_reader.read_define_font_2(2)?))
}
Some(TagCode::DefineFont3) => {
Tag::DefineFont2(Box::new(tag_reader.read_define_font_2(3)?))
}
Some(TagCode::DefineFont4) => Tag::DefineFont4(tag_reader.read_define_font_4()?),
Some(TagCode::DefineFontAlignZones) => tag_reader.read_define_font_align_zones()?,
Some(TagCode::DefineFontInfo) => tag_reader.read_define_font_info(1)?,
Some(TagCode::DefineFontInfo2) => tag_reader.read_define_font_info(2)?,
Some(TagCode::DefineFontName) => tag_reader.read_define_font_name()?,
Some(TagCode::DefineMorphShape) => tag_reader.read_define_morph_shape(1)?,
Some(TagCode::DefineMorphShape2) => tag_reader.read_define_morph_shape(2)?,
Some(TagCode::DefineShape) => tag_reader.read_define_shape(1)?,
Some(TagCode::DefineShape2) => tag_reader.read_define_shape(2)?,
Some(TagCode::DefineShape3) => tag_reader.read_define_shape(3)?,
Some(TagCode::DefineShape4) => tag_reader.read_define_shape(4)?,
Some(TagCode::DefineSound) => tag_reader.read_define_sound()?,
Some(TagCode::DefineText) => tag_reader.read_define_text()?,
Some(TagCode::DefineMorphShape) => {
Tag::DefineMorphShape(Box::new(tag_reader.read_define_morph_shape(1)?))
}
Some(TagCode::DefineMorphShape2) => {
Tag::DefineMorphShape(Box::new(tag_reader.read_define_morph_shape(2)?))
}
Some(TagCode::DefineShape) => Tag::DefineShape(tag_reader.read_define_shape(1)?),
Some(TagCode::DefineShape2) => Tag::DefineShape(tag_reader.read_define_shape(2)?),
Some(TagCode::DefineShape3) => Tag::DefineShape(tag_reader.read_define_shape(3)?),
Some(TagCode::DefineShape4) => Tag::DefineShape(tag_reader.read_define_shape(4)?),
Some(TagCode::DefineSound) => {
Tag::DefineSound(Box::new(tag_reader.read_define_sound()?))
}
Some(TagCode::DefineText) => Tag::DefineText(Box::new(tag_reader.read_define_text()?)),
Some(TagCode::DefineVideoStream) => tag_reader.read_define_video_stream()?,
Some(TagCode::EnableTelemetry) => {
tag_reader.read_u16()?; // Reserved
@ -438,25 +458,28 @@ impl<R: Read> Reader<R> {
Some(TagCode::SoundStreamHead) => Tag::SoundStreamHead(
// TODO: Disallow certain compressions.
Box::new(tag_reader.read_sound_stream_info()?),
Box::new(tag_reader.read_sound_stream_head()?),
),
Some(TagCode::SoundStreamHead2) => {
Tag::SoundStreamHead2(Box::new(tag_reader.read_sound_stream_info()?))
Tag::SoundStreamHead2(Box::new(tag_reader.read_sound_stream_head()?))
}
Some(TagCode::StartSound) => Tag::StartSound {
id: tag_reader.read_u16()?,
sound_info: Box::new(tag_reader.read_sound_info()?),
},
Some(TagCode::StartSound) => Tag::StartSound(tag_reader.read_start_sound_1()?),
Some(TagCode::StartSound2) => Tag::StartSound2 {
class_name: tag_reader.read_c_string()?,
sound_info: Box::new(tag_reader.read_sound_info()?),
},
Some(TagCode::DefineBitsLossless) => tag_reader.read_define_bits_lossless(1)?,
Some(TagCode::DefineBitsLossless2) => tag_reader.read_define_bits_lossless(2)?,
Some(TagCode::DebugId) => Tag::DebugId(tag_reader.read_debug_id()?),
Some(TagCode::DefineBitsLossless) => {
Tag::DefineBitsLossless(tag_reader.read_define_bits_lossless(1)?)
}
Some(TagCode::DefineBitsLossless2) => {
Tag::DefineBitsLossless(tag_reader.read_define_bits_lossless(2)?)
}
Some(TagCode::DefineScalingGrid) => Tag::DefineScalingGrid {
id: tag_reader.read_u16()?,
@ -548,46 +571,40 @@ impl<R: Read> Reader<R> {
})
}
Some(TagCode::DefineSceneAndFrameLabelData) => {
tag_reader.read_define_scene_and_frame_label_data()?
}
Some(TagCode::DefineSceneAndFrameLabelData) => Tag::DefineSceneAndFrameLabelData(
tag_reader.read_define_scene_and_frame_label_data()?,
),
Some(TagCode::FrameLabel) => {
let label = tag_reader.read_c_string()?;
Tag::FrameLabel {
is_anchor: tag_reader.version >= 6
&& length > label.len() + 1
&& tag_reader.read_u8()? != 0,
label,
}
}
Some(TagCode::FrameLabel) => Tag::FrameLabel(tag_reader.read_frame_label(length)?),
Some(TagCode::DefineSprite) => {
// TODO: There's probably a better way to prevent the infinite type recursion.
// Tags can only be nested one level deep, so perhaps I can implement
// read_tag_list for Reader<Take<R>> to enforce this.
let mut sprite_reader =
Reader::new(&mut tag_reader.input as &mut Read, self.version);
Reader::new(&mut tag_reader.input as &mut dyn Read, self.version);
sprite_reader.read_define_sprite()?
}
Some(TagCode::PlaceObject) => tag_reader.read_place_object()?,
Some(TagCode::PlaceObject2) => tag_reader.read_place_object_2_or_3(2)?,
Some(TagCode::PlaceObject3) => tag_reader.read_place_object_2_or_3(3)?,
Some(TagCode::PlaceObject4) => tag_reader.read_place_object_2_or_3(4)?,
Some(TagCode::PlaceObject) => {
Tag::PlaceObject(Box::new(tag_reader.read_place_object(length)?))
}
Some(TagCode::PlaceObject2) => {
Tag::PlaceObject(Box::new(tag_reader.read_place_object_2_or_3(2)?))
}
Some(TagCode::PlaceObject3) => {
Tag::PlaceObject(Box::new(tag_reader.read_place_object_2_or_3(3)?))
}
Some(TagCode::PlaceObject4) => {
Tag::PlaceObject(Box::new(tag_reader.read_place_object_2_or_3(4)?))
}
Some(TagCode::RemoveObject) => Tag::RemoveObject {
character_id: Some(tag_reader.read_u16()?),
depth: tag_reader.read_i16()?,
},
Some(TagCode::RemoveObject) => Tag::RemoveObject(tag_reader.read_remove_object_1()?),
Some(TagCode::RemoveObject2) => Tag::RemoveObject {
depth: tag_reader.read_i16()?,
character_id: None,
},
Some(TagCode::RemoveObject2) => Tag::RemoveObject(tag_reader.read_remove_object_2()?),
Some(TagCode::VideoFrame) => tag_reader.read_video_frame()?,
Some(TagCode::ProductInfo) => Tag::ProductInfo(tag_reader.read_product_info()?),
_ => {
let size = length as usize;
let mut data = vec![0; size];
@ -605,7 +622,7 @@ impl<R: Read> Reader<R> {
Ok(tag)
}
fn read_compression_type(mut input: R) -> Result<Compression> {
pub fn read_compression_type(mut input: R) -> Result<Compression> {
let mut signature = [0u8; 3];
input.read_exact(&mut signature)?;
let compression = match &signature {
@ -617,7 +634,7 @@ impl<R: Read> Reader<R> {
Ok(compression)
}
fn read_rectangle(&mut self) -> Result<Rectangle> {
pub fn read_rectangle(&mut self) -> Result<Rectangle> {
self.byte_align();
let num_bits = self.read_ubits(5)? as usize;
Ok(Rectangle {
@ -628,7 +645,7 @@ impl<R: Read> Reader<R> {
})
}
fn read_bit(&mut self) -> Result<bool> {
pub fn read_bit(&mut self) -> Result<bool> {
if self.bit_index == 0 {
self.byte = self.input.read_u8()?;
self.bit_index = 8;
@ -638,11 +655,11 @@ impl<R: Read> Reader<R> {
Ok(val)
}
fn byte_align(&mut self) {
pub fn byte_align(&mut self) {
self.bit_index = 0;
}
fn read_ubits(&mut self, num_bits: usize) -> Result<u32> {
pub fn read_ubits(&mut self, num_bits: usize) -> Result<u32> {
let mut val = 0u32;
for _ in 0..num_bits {
val <<= 1;
@ -651,7 +668,7 @@ impl<R: Read> Reader<R> {
Ok(val)
}
fn read_sbits(&mut self, num_bits: usize) -> Result<i32> {
pub fn read_sbits(&mut self, num_bits: usize) -> Result<i32> {
if num_bits > 0 {
self.read_ubits(num_bits)
.map(|n| (n as i32) << (32 - num_bits) >> (32 - num_bits))
@ -660,15 +677,15 @@ impl<R: Read> Reader<R> {
}
}
fn read_sbits_twips(&mut self, num_bits: usize) -> Result<Twips> {
pub fn read_sbits_twips(&mut self, num_bits: usize) -> Result<Twips> {
self.read_sbits(num_bits).map(Twips::new)
}
fn read_fbits(&mut self, num_bits: usize) -> Result<f32> {
pub fn read_fbits(&mut self, num_bits: usize) -> Result<f32> {
self.read_sbits(num_bits).map(|n| (n as f32) / 65536f32)
}
fn read_encoded_u32(&mut self) -> Result<u32> {
pub fn read_encoded_u32(&mut self) -> Result<u32> {
let mut val = 0u32;
for i in 0..5 {
let byte = self.read_u8()?;
@ -680,18 +697,18 @@ impl<R: Read> Reader<R> {
Ok(val)
}
fn read_character_id(&mut self) -> Result<CharacterId> {
pub fn read_character_id(&mut self) -> Result<CharacterId> {
self.read_u16()
}
fn read_rgb(&mut self) -> Result<Color> {
pub fn read_rgb(&mut self) -> Result<Color> {
let r = self.read_u8()?;
let g = self.read_u8()?;
let b = self.read_u8()?;
Ok(Color { r, g, b, a: 255 })
}
fn read_rgba(&mut self) -> Result<Color> {
pub fn read_rgba(&mut self) -> Result<Color> {
let r = self.read_u8()?;
let g = self.read_u8()?;
let b = self.read_u8()?;
@ -699,7 +716,7 @@ impl<R: Read> Reader<R> {
Ok(Color { r, g, b, a })
}
fn read_color_transform_no_alpha(&mut self) -> Result<ColorTransform> {
pub fn read_color_transform_no_alpha(&mut self) -> Result<ColorTransform> {
self.byte_align();
let has_add = self.read_bit()?;
let has_mult = self.read_bit()?;
@ -822,7 +839,7 @@ impl<R: Read> Reader<R> {
Ok((tag_code, length))
}
fn read_define_button(&mut self) -> Result<Tag> {
pub fn read_define_button_1(&mut self) -> Result<Button> {
let id = self.read_u16()?;
let mut records = Vec::new();
while let Some(record) = self.read_button_record(1)? {
@ -830,7 +847,7 @@ impl<R: Read> Reader<R> {
}
let mut action_data = Vec::new();
self.input.read_to_end(&mut action_data)?;
Ok(Tag::DefineButton(Box::new(Button {
Ok(Button {
id,
is_track_as_menu: false,
records,
@ -841,10 +858,10 @@ impl<R: Read> Reader<R> {
key_code: None,
action_data: action_data,
}],
})))
})
}
fn read_define_button_2(&mut self) -> Result<Tag> {
pub fn read_define_button_2(&mut self) -> Result<Button> {
let id = self.read_u16()?;
let flags = self.read_u8()?;
let is_track_as_menu = (flags & 0b1) != 0;
@ -866,12 +883,12 @@ impl<R: Read> Reader<R> {
}
}
Ok(Tag::DefineButton2(Box::new(Button {
Ok(Button {
id,
is_track_as_menu,
records,
actions,
})))
})
}
fn read_button_record(&mut self, version: u8) -> Result<Option<ButtonRecord>> {
@ -1001,11 +1018,21 @@ impl<R: Read> Reader<R> {
}))
}
fn read_define_scene_and_frame_label_data(&mut self) -> Result<Tag> {
pub fn read_frame_label(&mut self, length: usize) -> Result<FrameLabel> {
let label = self.read_c_string()?;
Ok(FrameLabel {
is_anchor: self.version >= 6 && length > label.len() + 1 && self.read_u8()? != 0,
label,
})
}
pub fn read_define_scene_and_frame_label_data(
&mut self,
) -> Result<DefineSceneAndFrameLabelData> {
let num_scenes = self.read_encoded_u32()? as usize;
let mut scenes = Vec::with_capacity(num_scenes);
for _ in 0..num_scenes {
scenes.push(FrameLabel {
scenes.push(FrameLabelData {
frame_num: self.read_encoded_u32()?,
label: self.read_c_string()?,
});
@ -1014,19 +1041,19 @@ impl<R: Read> Reader<R> {
let num_frame_labels = self.read_encoded_u32()? as usize;
let mut frame_labels = Vec::with_capacity(num_frame_labels);
for _ in 0..num_frame_labels {
frame_labels.push(FrameLabel {
frame_labels.push(FrameLabelData {
frame_num: self.read_encoded_u32()?,
label: self.read_c_string()?,
});
}
Ok(Tag::DefineSceneAndFrameLabelData {
Ok(DefineSceneAndFrameLabelData {
scenes,
frame_labels,
})
}
fn read_define_font(&mut self) -> Result<Tag> {
pub fn read_define_font_1(&mut self) -> Result<FontV1> {
let id = self.read_u16()?;
let num_glyphs = self.read_u16()? / 2;
@ -1048,10 +1075,10 @@ impl<R: Read> Reader<R> {
}
}
Ok(Tag::DefineFont(Box::new(FontV1 { id, glyphs })))
Ok(FontV1 { id, glyphs })
}
fn read_define_font_2(&mut self, version: u8) -> Result<Tag> {
pub fn read_define_font_2(&mut self, version: u8) -> Result<Font> {
let id = self.read_character_id()?;
let flags = self.read_u8()?;
@ -1149,7 +1176,7 @@ impl<R: Read> Reader<R> {
None
};
Ok(Tag::DefineFont2(Box::new(Font {
Ok(Font {
version,
id,
name,
@ -1161,10 +1188,10 @@ impl<R: Read> Reader<R> {
is_ansi,
is_bold,
is_italic,
})))
})
}
fn read_define_font_4(&mut self) -> Result<Tag> {
pub fn read_define_font_4(&mut self) -> Result<Font4> {
let id = self.read_character_id()?;
let flags = self.read_u8()?;
let name = self.read_c_string()?;
@ -1176,13 +1203,13 @@ impl<R: Read> Reader<R> {
} else {
None
};
Ok(Tag::DefineFont4(Font4 {
Ok(Font4 {
id,
is_italic: flags & 0b10 != 0,
is_bold: flags & 0b1 != 0,
name,
data,
}))
})
}
fn read_kerning_record(&mut self, has_wide_codes: bool) -> Result<KerningRecord> {
@ -1290,7 +1317,7 @@ impl<R: Read> Reader<R> {
})
}
fn read_define_morph_shape(&mut self, shape_version: u8) -> Result<Tag> {
pub fn read_define_morph_shape(&mut self, shape_version: u8) -> Result<DefineMorphShape> {
let id = self.read_character_id()?;
let start_shape_bounds = self.read_rectangle()?;
let end_shape_bounds = self.read_rectangle()?;
@ -1354,7 +1381,7 @@ impl<R: Read> Reader<R> {
while let Some(record) = self.read_shape_record(1)? {
end_shape.push(record);
}
Ok(Tag::DefineMorphShape(Box::new(DefineMorphShape {
Ok(DefineMorphShape {
id,
version: shape_version,
has_non_scaling_strokes,
@ -1373,7 +1400,7 @@ impl<R: Read> Reader<R> {
fill_styles: end_fill_styles,
line_styles: end_line_styles,
},
})))
})
}
fn read_morph_line_style(&mut self, shape_version: u8) -> Result<(LineStyle, LineStyle)> {
@ -1518,7 +1545,7 @@ impl<R: Read> Reader<R> {
)
}
0x40...0x43 => {
0x40..=0x43 => {
let id = self.read_character_id()?;
(
FillStyle::Bitmap {
@ -1573,7 +1600,7 @@ impl<R: Read> Reader<R> {
))
}
fn read_define_shape(&mut self, version: u8) -> Result<Tag> {
pub fn read_define_shape(&mut self, version: u8) -> Result<Shape> {
let id = self.read_u16()?;
let shape_bounds = self.read_rectangle()?;
let (edge_bounds, has_fill_winding_rule, has_non_scaling_strokes, has_scaling_strokes) =
@ -1594,7 +1621,7 @@ impl<R: Read> Reader<R> {
while let Some(record) = self.read_shape_record(version)? {
records.push(record);
}
Ok(Tag::DefineShape(Shape {
Ok(Shape {
version,
id,
shape_bounds,
@ -1604,24 +1631,24 @@ impl<R: Read> Reader<R> {
has_scaling_strokes,
styles,
shape: records,
}))
})
}
fn read_define_sound(&mut self) -> Result<Tag> {
pub fn read_define_sound(&mut self) -> Result<Sound> {
let id = self.read_u16()?;
let format = self.read_sound_format()?;
let num_samples = self.read_u32()?;
let mut data = Vec::new();
self.input.read_to_end(&mut data)?;
Ok(Tag::DefineSound(Box::new(Sound {
Ok(Sound {
id,
format,
num_samples,
data,
})))
})
}
fn read_sound_stream_info(&mut self) -> Result<SoundStreamInfo> {
pub fn read_sound_stream_head(&mut self) -> Result<SoundStreamHead> {
// TODO: Verify version requirements.
let playback_format = self.read_sound_format()?;
let stream_format = self.read_sound_format()?;
@ -1632,7 +1659,7 @@ impl<R: Read> Reader<R> {
} else {
0
};
Ok(SoundStreamInfo {
Ok(SoundStreamHead {
stream_format,
playback_format,
num_samples_per_block,
@ -1698,7 +1725,7 @@ impl<R: Read> Reader<R> {
}
}
0x40...0x43 => FillStyle::Bitmap {
0x40..=0x43 => FillStyle::Bitmap {
id: self.read_u16()?,
matrix: self.read_matrix()?,
is_smoothed: (fill_style_type & 0b10) == 0,
@ -1895,7 +1922,7 @@ impl<R: Read> Reader<R> {
Ok(shape_record)
}
fn read_define_sprite(&mut self) -> Result<Tag> {
pub fn read_define_sprite(&mut self) -> Result<Tag> {
Ok(Tag::DefineSprite(Sprite {
id: self.read_u16()?,
num_frames: self.read_u16()?,
@ -1903,14 +1930,23 @@ impl<R: Read> Reader<R> {
}))
}
fn read_place_object(&mut self) -> Result<Tag> {
pub fn read_place_object(&mut self, tag_length: usize) -> Result<PlaceObject> {
// TODO: What's a best way to know if the tag has a color transform?
Ok(Tag::PlaceObject(Box::new(PlaceObject {
// You only know if there is still data remaining after the matrix.
// This sucks.
let mut vector = [0; 128];
self.get_mut().read_exact(&mut vector[..tag_length])?;
let mut reader = Reader::new(&vector[..], self.version);
Ok(PlaceObject {
version: 1,
action: PlaceObjectAction::Place(self.read_u16()?),
depth: self.read_i16()?,
matrix: Some(self.read_matrix()?),
color_transform: self.read_color_transform_no_alpha().ok(),
action: PlaceObjectAction::Place(reader.read_u16()?),
depth: reader.read_i16()?,
matrix: Some(reader.read_matrix()?),
color_transform: if !reader.get_ref().is_empty() {
Some(reader.read_color_transform_no_alpha()?)
} else {
None
},
ratio: None,
name: None,
clip_depth: None,
@ -1923,10 +1959,10 @@ impl<R: Read> Reader<R> {
is_bitmap_cached: false,
is_visible: true,
amf_data: None,
})))
})
}
fn read_place_object_2_or_3(&mut self, place_object_version: u8) -> Result<Tag> {
pub fn read_place_object_2_or_3(&mut self, place_object_version: u8) -> Result<PlaceObject> {
let flags = if place_object_version >= 3 {
self.read_u16()?
} else {
@ -2014,7 +2050,7 @@ impl<R: Read> Reader<R> {
} else {
None
};
Ok(Tag::PlaceObject(Box::new(PlaceObject {
Ok(PlaceObject {
version: place_object_version,
action,
depth,
@ -2032,10 +2068,24 @@ impl<R: Read> Reader<R> {
background_color,
blend_mode,
amf_data,
})))
})
}
fn read_blend_mode(&mut self) -> Result<BlendMode> {
pub fn read_remove_object_1(&mut self) -> Result<RemoveObject> {
Ok(RemoveObject {
character_id: Some(self.read_u16()?),
depth: self.read_i16()?,
})
}
pub fn read_remove_object_2(&mut self) -> Result<RemoveObject> {
Ok(RemoveObject {
depth: self.read_i16()?,
character_id: None,
})
}
pub fn read_blend_mode(&mut self) -> Result<BlendMode> {
Ok(match self.read_u8()? {
0 | 1 => BlendMode::Normal,
2 => BlendMode::Layer,
@ -2164,7 +2214,7 @@ impl<R: Read> Reader<R> {
Ok(event_list)
}
fn read_filter(&mut self) -> Result<Filter> {
pub fn read_filter(&mut self) -> Result<Filter> {
self.byte_align();
let filter = match self.read_u8()? {
0 => Filter::DropShadowFilter(Box::new(DropShadowFilter {
@ -2293,7 +2343,7 @@ impl<R: Read> Reader<R> {
Ok(filter)
}
fn read_sound_format(&mut self) -> Result<SoundFormat> {
pub fn read_sound_format(&mut self) -> Result<SoundFormat> {
let flags = self.read_u8()?;
let compression = match flags >> 4 {
0 => AudioCompression::UncompressedUnknownEndian,
@ -2323,7 +2373,7 @@ impl<R: Read> Reader<R> {
})
}
fn read_sound_info(&mut self) -> Result<SoundInfo> {
pub fn read_sound_info(&mut self) -> Result<SoundInfo> {
let flags = self.read_u8()?;
let event = match (flags >> 4) & 0b11 {
0b10 | 0b11 => SoundEvent::Stop,
@ -2369,7 +2419,14 @@ impl<R: Read> Reader<R> {
})
}
fn read_define_text(&mut self) -> Result<Tag> {
pub fn read_start_sound_1(&mut self) -> Result<StartSound> {
Ok(StartSound {
id: self.read_u16()?,
sound_info: Box::new(self.read_sound_info()?),
})
}
pub fn read_define_text(&mut self) -> Result<Text> {
let id = self.read_character_id()?;
let bounds = self.read_rectangle()?;
let matrix = self.read_matrix()?;
@ -2381,12 +2438,12 @@ impl<R: Read> Reader<R> {
records.push(record);
}
Ok(Tag::DefineText(Box::new(Text {
Ok(Text {
id,
bounds,
matrix,
records,
})))
})
}
fn read_text_record(
@ -2600,7 +2657,7 @@ impl<R: Read> Reader<R> {
}))
}
fn read_define_bits_lossless(&mut self, version: u8) -> Result<Tag> {
pub fn read_define_bits_lossless(&mut self, version: u8) -> Result<DefineBitsLossless> {
let id = self.read_character_id()?;
let format = match self.read_u8()? {
3 => BitmapFormat::ColorMap8,
@ -2617,7 +2674,7 @@ impl<R: Read> Reader<R> {
};
let mut data = Vec::new();
self.input.read_to_end(&mut data)?;
Ok(Tag::DefineBitsLossless(DefineBitsLossless {
Ok(DefineBitsLossless {
version,
id,
format,
@ -2625,7 +2682,28 @@ impl<R: Read> Reader<R> {
height,
num_colors,
data,
}))
})
}
pub fn read_product_info(&mut self) -> Result<ProductInfo> {
// Not documented in SWF19 reference.
// See http://wahlers.com.br/claus/blog/undocumented-swf-tags-written-by-mxmlc/
Ok(ProductInfo {
product_id: self.read_u32()?,
edition: self.read_u32()?,
major_version: self.read_u8()?,
minor_version: self.read_u8()?,
build_number: self.get_mut().read_u64::<LittleEndian>()?,
compilation_date: self.get_mut().read_u64::<LittleEndian>()?,
})
}
pub fn read_debug_id(&mut self) -> Result<DebugId> {
// Not documented in SWF19 reference.
// See http://wahlers.com.br/claus/blog/undocumented-swf-tags-written-by-mxmlc/
let mut debug_id = [0u8; 16];
self.get_mut().read_exact(&mut debug_id)?;
Ok(debug_id)
}
}

View File

@ -42,6 +42,8 @@ pub enum TagCode {
DefineSprite = 39,
ProductInfo = 41,
FrameLabel = 43,
SoundStreamHead2 = 45,
@ -57,6 +59,7 @@ pub enum TagCode {
VideoFrame = 61,
DefineFontInfo2 = 62,
DebugId = 63,
EnableDebugger2 = 64,
ScriptLimits = 65,
SetTabIndex = 66,
@ -87,3 +90,9 @@ pub enum TagCode {
EnableTelemetry = 93,
PlaceObject4 = 94,
}
impl TagCode {
pub fn from_u16(n: u16) -> Option<Self> {
num_traits::FromPrimitive::from_u16(n)
}
}

View File

@ -1190,40 +1190,40 @@ pub fn tag_tests() -> Vec<TagTestData> {
),
(
1, // Minimum version not listed in SWF19.
Tag::DefineSceneAndFrameLabelData {
Tag::DefineSceneAndFrameLabelData(DefineSceneAndFrameLabelData {
scenes: vec![
FrameLabel {
FrameLabelData {
frame_num: 0,
label: "Scene 1".to_string(),
},
FrameLabel {
FrameLabelData {
frame_num: 25,
label: "Scene2Scene2Scene2Scene2Scene2".to_string(),
},
FrameLabel {
FrameLabelData {
frame_num: 26,
label: "test日本語test".to_string(),
},
],
frame_labels: vec![
FrameLabel {
FrameLabelData {
frame_num: 0,
label: "a".to_string(),
},
FrameLabel {
FrameLabelData {
frame_num: 9,
label: "b".to_string(),
},
FrameLabel {
FrameLabelData {
frame_num: 17,
label: "❤😁aaa".to_string(),
},
FrameLabel {
FrameLabelData {
frame_num: 25,
label: "frameInScene2".to_string(),
},
],
},
}),
read_tag_bytes_from_file(
"tests/swfs/DefineSceneAndFrameLabelData.swf",
TagCode::DefineSceneAndFrameLabelData,
@ -1793,10 +1793,10 @@ pub fn tag_tests() -> Vec<TagTestData> {
),
(
3,
Tag::FrameLabel {
Tag::FrameLabel(FrameLabel {
label: "test".to_string(),
is_anchor: false,
},
}),
read_tag_bytes_from_file_with_index(
"tests/swfs/FrameLabel-CS6.swf",
TagCode::FrameLabel,
@ -1805,10 +1805,10 @@ pub fn tag_tests() -> Vec<TagTestData> {
),
(
6, // Anchor tags supported in SWF version 6 and later.
Tag::FrameLabel {
Tag::FrameLabel(FrameLabel {
label: "anchor_tag".to_string(),
is_anchor: true,
},
}),
read_tag_bytes_from_file_with_index(
"tests/swfs/FrameLabel-CS6.swf",
TagCode::FrameLabel,
@ -2156,7 +2156,7 @@ pub fn tag_tests() -> Vec<TagTestData> {
(1, Tag::ShowFrame, vec![0b01_000000, 0]),
(
3,
Tag::SoundStreamHead2(Box::new(SoundStreamInfo {
Tag::SoundStreamHead2(Box::new(SoundStreamHead {
stream_format: SoundFormat {
compression: AudioCompression::Uncompressed,
sample_rate: 5512,
@ -2190,7 +2190,7 @@ pub fn tag_tests() -> Vec<TagTestData> {
),
(
4,
Tag::StartSound {
Tag::StartSound(StartSound {
id: 1,
sound_info: Box::new(SoundInfo {
event: SoundEvent::Start,
@ -2199,7 +2199,7 @@ pub fn tag_tests() -> Vec<TagTestData> {
num_loops: 3,
envelope: None,
}),
},
}),
read_tag_bytes_from_file("tests/swfs/DefineSound.swf", TagCode::StartSound),
),
(

View File

@ -236,6 +236,18 @@ pub struct FileAttributes {
#[derive(Debug, PartialEq)]
pub struct FrameLabel {
pub label: String,
pub is_anchor: bool,
}
#[derive(Debug, PartialEq)]
pub struct DefineSceneAndFrameLabelData {
pub scenes: Vec<FrameLabelData>,
pub frame_labels: Vec<FrameLabelData>,
}
#[derive(Debug, PartialEq)]
pub struct FrameLabelData {
pub frame_num: u32,
pub label: String,
}
@ -442,6 +454,7 @@ pub enum Tag {
Protect(Option<String>),
CsmTextSettings(CsmTextSettings),
DebugId(DebugId),
DefineBinaryData {
id: CharacterId,
data: Vec<u8>,
@ -489,7 +502,7 @@ pub enum Tag {
DefineText(Box<Text>),
DefineVideoStream(DefineVideoStream),
DoAbc(DoAbc),
DoAction(Vec<u8>),
DoAction(DoAction),
DoInitAction {
id: CharacterId,
action_data: Vec<u8>,
@ -504,40 +517,30 @@ pub enum Tag {
url: String,
imports: Vec<ExportedAsset>,
},
JpegTables(Vec<u8>),
SetBackgroundColor(Color),
JpegTables(JpegTables),
SetBackgroundColor(SetBackgroundColor),
SetTabIndex {
depth: Depth,
tab_index: u16,
},
SoundStreamBlock(Vec<u8>),
SoundStreamHead(Box<SoundStreamInfo>),
SoundStreamHead2(Box<SoundStreamInfo>),
StartSound {
id: CharacterId,
sound_info: Box<SoundInfo>,
},
SoundStreamBlock(SoundStreamBlock),
SoundStreamHead(Box<SoundStreamHead>),
SoundStreamHead2(Box<SoundStreamHead>),
StartSound(StartSound),
StartSound2 {
class_name: String,
sound_info: Box<SoundInfo>,
},
SymbolClass(Vec<SymbolClassLink>),
PlaceObject(Box<PlaceObject>),
RemoveObject {
depth: Depth,
character_id: Option<CharacterId>,
},
RemoveObject(RemoveObject),
VideoFrame(VideoFrame),
FileAttributes(FileAttributes),
FrameLabel {
label: String,
is_anchor: bool,
},
DefineSceneAndFrameLabelData {
scenes: Vec<FrameLabel>,
frame_labels: Vec<FrameLabel>,
},
FrameLabel(FrameLabel),
DefineSceneAndFrameLabelData(DefineSceneAndFrameLabelData),
ProductInfo(ProductInfo),
Unknown {
tag_code: u16,
@ -551,6 +554,14 @@ pub struct ExportedAsset {
pub name: String,
}
#[derive(Debug, PartialEq, Clone)]
pub struct RemoveObject {
pub depth: Depth,
pub character_id: Option<CharacterId>,
}
pub type SetBackgroundColor = Color;
#[derive(Debug, PartialEq, Clone)]
pub struct SymbolClassLink {
pub id: CharacterId,
@ -603,6 +614,12 @@ pub struct SoundEnvelopePoint {
pub right_volume: f32,
}
#[derive(Clone, Debug, PartialEq)]
pub struct StartSound {
pub id: CharacterId,
pub sound_info: Box<SoundInfo>,
}
#[derive(Debug, PartialEq)]
pub struct Sprite {
pub id: CharacterId,
@ -750,13 +767,15 @@ pub struct SoundFormat {
}
#[derive(Debug, PartialEq, Clone)]
pub struct SoundStreamInfo {
pub struct SoundStreamHead {
pub stream_format: SoundFormat,
pub playback_format: SoundFormat,
pub num_samples_per_block: u16,
pub latency_seek: i16,
}
pub type SoundStreamBlock = Vec<u8>;
#[derive(Debug, PartialEq, Clone)]
pub struct Button {
pub id: CharacterId,
@ -1068,3 +1087,23 @@ pub struct DoAbc {
pub is_lazy_initialize: bool,
pub data: Vec<u8>,
}
pub type DoAction = Vec<u8>;
pub type JpegTables = Vec<u8>;
/// `ProductInfo` contains information about the software used to generate the SWF.
/// Not documented in the SWF19 reference. Emitted by mxmlc.
/// See http://wahlers.com.br/claus/blog/undocumented-swf-tags-written-by-mxmlc/
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ProductInfo {
pub product_id: u32,
pub edition: u32,
pub major_version: u8,
pub minor_version: u8,
pub build_number: u64,
pub compilation_date: u64,
}
/// `DebugId` is a UUID written to debug SWFs and used by the Flash Debugger.
pub type DebugId = [u8; 16];

View File

@ -142,6 +142,10 @@ pub trait SwfWrite<W: Write> {
self.get_inner().write_u32::<LittleEndian>(n)
}
fn write_u64(&mut self, n: u64) -> Result<()> {
self.get_inner().write_u64::<LittleEndian>(n)
}
fn write_i8(&mut self, n: i8) -> Result<()> {
self.get_inner().write_i8(n)
}
@ -891,7 +895,7 @@ impl<W: Write> Writer<W> {
// TODO: Allow clone of color.
Tag::SetBackgroundColor(ref color) => {
self.write_tag_header(TagCode::SetBackgroundColor, 3)?;
self.write_rgb(color)?;
self.write_rgb(&color)?;
}
Tag::ScriptLimits {
@ -922,17 +926,14 @@ impl<W: Write> Writer<W> {
}
},
Tag::RemoveObject {
depth,
character_id,
} => {
if let Some(id) = character_id {
Tag::RemoveObject(ref remove_object) => {
if let Some(id) = remove_object.character_id {
self.write_tag_header(TagCode::RemoveObject, 4)?;
self.write_u16(id)?;
} else {
self.write_tag_header(TagCode::RemoveObject2, 2)?;
}
self.write_i16(depth)?;
self.write_i16(remove_object.depth)?;
}
Tag::SoundStreamBlock(ref data) => {
@ -940,15 +941,16 @@ impl<W: Write> Writer<W> {
self.output.write_all(data)?;
}
Tag::SoundStreamHead(ref sound_stream_info) => {
self.write_sound_stream_head(sound_stream_info, 1)?;
Tag::SoundStreamHead(ref sound_stream_head) => {
self.write_sound_stream_head(sound_stream_head, 1)?;
}
Tag::SoundStreamHead2(ref sound_stream_info) => {
self.write_sound_stream_head(sound_stream_info, 2)?;
Tag::SoundStreamHead2(ref sound_stream_head) => {
self.write_sound_stream_head(sound_stream_head, 2)?;
}
Tag::StartSound { id, ref sound_info } => {
Tag::StartSound(ref start_sound) => {
let sound_info = &start_sound.sound_info;
let length = 3
+ if sound_info.in_sample.is_some() { 4 } else { 0 }
+ if sound_info.out_sample.is_some() {
@ -963,7 +965,7 @@ impl<W: Write> Writer<W> {
0
};
self.write_tag_header(TagCode::StartSound, length)?;
self.write_u16(id)?;
self.write_u16(start_sound.id)?;
self.write_sound_info(sound_info)?;
}
@ -1032,10 +1034,10 @@ impl<W: Write> Writer<W> {
self.write_u32(flags)?;
}
Tag::FrameLabel {
Tag::FrameLabel(FrameLabel {
ref label,
is_anchor,
} => {
}) => {
// TODO: Assert proper version
let is_anchor = is_anchor && self.version >= 6;
let length = label.len() as u32 + if is_anchor { 2 } else { 1 };
@ -1046,10 +1048,9 @@ impl<W: Write> Writer<W> {
}
}
Tag::DefineSceneAndFrameLabelData {
ref scenes,
ref frame_labels,
} => self.write_define_scene_and_frame_label_data(scenes, frame_labels)?,
Tag::DefineSceneAndFrameLabelData(ref data) => self.write_define_scene_and_frame_label_data(data)?,
Tag::ProductInfo(ref product_info) => self.write_product_info(product_info)?,
Tag::DebugId(ref debug_id) => self.write_debug_id(debug_id)?,
Tag::Unknown { tag_code, ref data } => {
self.write_tag_code_and_length(tag_code, data.len() as u32)?;
@ -1492,19 +1493,18 @@ impl<W: Write> Writer<W> {
fn write_define_scene_and_frame_label_data(
&mut self,
scenes: &[FrameLabel],
frame_labels: &[FrameLabel],
data: &DefineSceneAndFrameLabelData,
) -> Result<()> {
let mut buf = Vec::with_capacity((scenes.len() + frame_labels.len()) * 4);
let mut buf = Vec::with_capacity((data.scenes.len() + data.frame_labels.len()) * 4);
{
let mut writer = Writer::new(&mut buf, self.version);
writer.write_encoded_u32(scenes.len() as u32)?;
for scene in scenes {
writer.write_encoded_u32(data.scenes.len() as u32)?;
for scene in &data.scenes {
writer.write_encoded_u32(scene.frame_num)?;
writer.write_c_string(&scene.label)?;
}
writer.write_encoded_u32(frame_labels.len() as u32)?;
for frame_label in frame_labels {
writer.write_encoded_u32(data.frame_labels.len() as u32)?;
for frame_label in &data.frame_labels {
writer.write_encoded_u32(frame_label.frame_num)?;
writer.write_c_string(&frame_label.label)?;
}
@ -2261,7 +2261,7 @@ impl<W: Write> Writer<W> {
fn write_sound_stream_head(
&mut self,
stream_info: &SoundStreamInfo,
stream_head: &SoundStreamHead,
version: u8,
) -> Result<()> {
let tag_code = if version >= 2 {
@ -2270,17 +2270,17 @@ impl<W: Write> Writer<W> {
TagCode::SoundStreamHead
};
// MP3 compression has added latency seek field.
let length = if stream_info.stream_format.compression == AudioCompression::Mp3 {
let length = if stream_head.stream_format.compression == AudioCompression::Mp3 {
6
} else {
4
};
self.write_tag_header(tag_code, length)?;
self.write_sound_format(&stream_info.playback_format)?;
self.write_sound_format(&stream_info.stream_format)?;
self.write_u16(stream_info.num_samples_per_block)?;
if stream_info.stream_format.compression == AudioCompression::Mp3 {
self.write_i16(stream_info.latency_seek)?;
self.write_sound_format(&stream_head.playback_format)?;
self.write_sound_format(&stream_head.stream_format)?;
self.write_u16(stream_head.num_samples_per_block)?;
if stream_head.stream_format.compression == AudioCompression::Mp3 {
self.write_i16(stream_head.latency_seek)?;
}
Ok(())
}
@ -2672,6 +2672,21 @@ impl<W: Write> Writer<W> {
Ok(())
}
fn write_product_info(&mut self, product_info: &ProductInfo) -> Result<()> {
self.write_tag_header(TagCode::ProductInfo, 26)?;
self.write_u32(product_info.product_id)?;
self.write_u32(product_info.edition)?;
self.write_u8(product_info.major_version)?;
self.write_u8(product_info.minor_version)?;
self.write_u64(product_info.build_number)?;
self.write_u64(product_info.compilation_date)?;
Ok(())
}
fn write_debug_id(&mut self, debug_id: &DebugId) -> Result<()> {
self.get_inner().write_all(debug_id)
}
fn write_tag_header(&mut self, tag_code: TagCode, length: u32) -> Result<()> {
self.write_tag_code_and_length(tag_code as u16, length)
}