From 08569ae979367589337aeb96b83371fa236c72fa Mon Sep 17 00:00:00 2001 From: Mike Welsh Date: Fri, 3 Jul 2020 17:06:45 -0700 Subject: [PATCH] core: Limit tag parsing to slice of tag data --- core/src/display_object/movie_clip.rs | 517 ++++++++++++++------------ swf/src/read.rs | 4 + 2 files changed, 290 insertions(+), 231 deletions(-) diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index 351b8d7e4..a5e00975c 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -146,195 +146,204 @@ impl<'gc> MovieClip<'gc> { let mut reader = data.read_from(self.0.read().tag_stream_pos); let mut cur_frame = 1; let mut ids = fnv::FnvHashMap::default(); - let tag_callback = |reader: &mut SwfStream<&[u8]>, tag_code, tag_len| match tag_code { - TagCode::FileAttributes => { - let attributes = reader.read_file_attributes()?; - if attributes.is_action_script_3 { - log::warn!("This SWF contains ActionScript 3 which is not yet supported by Ruffle. The movie may not work as intended."); + let version = reader.version(); + let tag_callback = |reader: &mut SwfStream<&[u8]>, tag_code, tag_len| { + let data = *reader.get_inner().get_ref(); + let tag_pos = reader.get_inner().position() as usize; + let tag_slice = &data[tag_pos..tag_pos + tag_len]; + let reader = &mut SwfStream::new(std::io::Cursor::new(tag_slice), version); + match tag_code { + TagCode::FileAttributes => { + let attributes = reader.read_file_attributes()?; + if attributes.is_action_script_3 { + log::warn!("This SWF contains ActionScript 3 which is not yet supported by Ruffle. The movie may not work as intended."); + } + Ok(()) } - Ok(()) - } - TagCode::DefineBits => self - .0 - .write(context.gc_context) - .define_bits(context, reader, tag_len), - TagCode::DefineBitsJpeg2 => self - .0 - .write(context.gc_context) - .define_bits_jpeg_2(context, reader, tag_len), - TagCode::DefineBitsJpeg3 => self - .0 - .write(context.gc_context) - .define_bits_jpeg_3(context, reader, tag_len), - TagCode::DefineBitsJpeg4 => self - .0 - .write(context.gc_context) - .define_bits_jpeg_4(context, reader, tag_len), - TagCode::DefineBitsLossless => self - .0 - .write(context.gc_context) - .define_bits_lossless(context, reader, 1), - TagCode::DefineBitsLossless2 => self - .0 - .write(context.gc_context) - .define_bits_lossless(context, reader, 2), - TagCode::DefineButton => self - .0 - .write(context.gc_context) - .define_button_1(context, reader), - TagCode::DefineButton2 => self - .0 - .write(context.gc_context) - .define_button_2(context, reader), - TagCode::DefineButtonCxform => self - .0 - .write(context.gc_context) - .define_button_cxform(context, reader, tag_len), - TagCode::DefineButtonSound => self - .0 - .write(context.gc_context) - .define_button_sound(context, reader), - TagCode::DefineEditText => self - .0 - .write(context.gc_context) - .define_edit_text(context, reader), - TagCode::DefineFont => self - .0 - .write(context.gc_context) - .define_font_1(context, reader), - TagCode::DefineFont2 => self - .0 - .write(context.gc_context) - .define_font_2(context, reader), - TagCode::DefineFont3 => self - .0 - .write(context.gc_context) - .define_font_3(context, reader), - TagCode::DefineFont4 => unimplemented!(), - TagCode::DefineMorphShape => self.0.write(context.gc_context).define_morph_shape( - context, - reader, - morph_shapes, - 1, - ), - TagCode::DefineMorphShape2 => self.0.write(context.gc_context).define_morph_shape( - context, - reader, - morph_shapes, - 2, - ), - TagCode::DefineShape => self - .0 - .write(context.gc_context) - .define_shape(context, reader, 1), - TagCode::DefineShape2 => self - .0 - .write(context.gc_context) - .define_shape(context, reader, 2), - TagCode::DefineShape3 => self - .0 - .write(context.gc_context) - .define_shape(context, reader, 3), - TagCode::DefineShape4 => self - .0 - .write(context.gc_context) - .define_shape(context, reader, 4), - TagCode::DefineSound => self - .0 - .write(context.gc_context) - .define_sound(context, reader, tag_len), - TagCode::DefineSprite => self.0.write(context.gc_context).define_sprite( - avm, - context, - reader, - tag_len, - morph_shapes, - ), - TagCode::DefineText => self - .0 - .write(context.gc_context) - .define_text(context, reader, 1), - TagCode::DefineText2 => self - .0 - .write(context.gc_context) - .define_text(context, reader, 2), - TagCode::DoInitAction => self.do_init_action(avm, context, reader, tag_len), - TagCode::ExportAssets => self - .0 - .write(context.gc_context) - .export_assets(context, reader), - TagCode::FrameLabel => self.0.write(context.gc_context).frame_label( - context, - reader, - tag_len, - cur_frame, - &mut static_data, - ), - TagCode::JpegTables => self - .0 - .write(context.gc_context) - .jpeg_tables(context, reader, tag_len), - TagCode::PlaceObject => self.0.write(context.gc_context).preload_place_object( - context, - reader, - tag_len, - &mut ids, - morph_shapes, - 1, - ), - TagCode::PlaceObject2 => self.0.write(context.gc_context).preload_place_object( - context, - reader, - tag_len, - &mut ids, - morph_shapes, - 2, - ), - TagCode::PlaceObject3 => self.0.write(context.gc_context).preload_place_object( - context, - reader, - tag_len, - &mut ids, - morph_shapes, - 3, - ), - TagCode::PlaceObject4 => self.0.write(context.gc_context).preload_place_object( - context, - reader, - tag_len, - &mut ids, - morph_shapes, - 4, - ), - TagCode::RemoveObject => self - .0 - .write(context.gc_context) - .preload_remove_object(context, reader, &mut ids, 1), - TagCode::RemoveObject2 => self - .0 - .write(context.gc_context) - .preload_remove_object(context, reader, &mut ids, 2), - TagCode::ShowFrame => { - self.0 + TagCode::DefineBits => self + .0 .write(context.gc_context) - .preload_show_frame(context, reader, &mut cur_frame) + .define_bits(context, reader, tag_len), + TagCode::DefineBitsJpeg2 => self + .0 + .write(context.gc_context) + .define_bits_jpeg_2(context, reader, tag_len), + TagCode::DefineBitsJpeg3 => self + .0 + .write(context.gc_context) + .define_bits_jpeg_3(context, reader, tag_len), + TagCode::DefineBitsJpeg4 => self + .0 + .write(context.gc_context) + .define_bits_jpeg_4(context, reader, tag_len), + TagCode::DefineBitsLossless => self + .0 + .write(context.gc_context) + .define_bits_lossless(context, reader, 1), + TagCode::DefineBitsLossless2 => self + .0 + .write(context.gc_context) + .define_bits_lossless(context, reader, 2), + TagCode::DefineButton => self + .0 + .write(context.gc_context) + .define_button_1(context, reader), + TagCode::DefineButton2 => self + .0 + .write(context.gc_context) + .define_button_2(context, reader), + TagCode::DefineButtonCxform => self + .0 + .write(context.gc_context) + .define_button_cxform(context, reader, tag_len), + TagCode::DefineButtonSound => self + .0 + .write(context.gc_context) + .define_button_sound(context, reader), + TagCode::DefineEditText => self + .0 + .write(context.gc_context) + .define_edit_text(context, reader), + TagCode::DefineFont => self + .0 + .write(context.gc_context) + .define_font_1(context, reader), + TagCode::DefineFont2 => self + .0 + .write(context.gc_context) + .define_font_2(context, reader), + TagCode::DefineFont3 => self + .0 + .write(context.gc_context) + .define_font_3(context, reader), + TagCode::DefineFont4 => unimplemented!(), + TagCode::DefineMorphShape => self.0.write(context.gc_context).define_morph_shape( + context, + reader, + morph_shapes, + 1, + ), + TagCode::DefineMorphShape2 => self.0.write(context.gc_context).define_morph_shape( + context, + reader, + morph_shapes, + 2, + ), + TagCode::DefineShape => self + .0 + .write(context.gc_context) + .define_shape(context, reader, 1), + TagCode::DefineShape2 => self + .0 + .write(context.gc_context) + .define_shape(context, reader, 2), + TagCode::DefineShape3 => self + .0 + .write(context.gc_context) + .define_shape(context, reader, 3), + TagCode::DefineShape4 => self + .0 + .write(context.gc_context) + .define_shape(context, reader, 4), + TagCode::DefineSound => self + .0 + .write(context.gc_context) + .define_sound(context, reader, tag_len), + TagCode::DefineSprite => self.0.write(context.gc_context).define_sprite( + avm, + context, + reader, + tag_len, + morph_shapes, + ), + TagCode::DefineText => self + .0 + .write(context.gc_context) + .define_text(context, reader, 1), + TagCode::DefineText2 => self + .0 + .write(context.gc_context) + .define_text(context, reader, 2), + TagCode::DoInitAction => self.do_init_action(avm, context, reader, tag_len), + TagCode::ExportAssets => self + .0 + .write(context.gc_context) + .export_assets(context, reader), + TagCode::FrameLabel => self.0.write(context.gc_context).frame_label( + context, + reader, + tag_len, + cur_frame, + &mut static_data, + ), + TagCode::JpegTables => self + .0 + .write(context.gc_context) + .jpeg_tables(context, reader, tag_len), + TagCode::PlaceObject => self.0.write(context.gc_context).preload_place_object( + context, + reader, + tag_len, + &mut ids, + morph_shapes, + 1, + ), + TagCode::PlaceObject2 => self.0.write(context.gc_context).preload_place_object( + context, + reader, + tag_len, + &mut ids, + morph_shapes, + 2, + ), + TagCode::PlaceObject3 => self.0.write(context.gc_context).preload_place_object( + context, + reader, + tag_len, + &mut ids, + morph_shapes, + 3, + ), + TagCode::PlaceObject4 => self.0.write(context.gc_context).preload_place_object( + context, + reader, + tag_len, + &mut ids, + morph_shapes, + 4, + ), + TagCode::RemoveObject => self + .0 + .write(context.gc_context) + .preload_remove_object(context, reader, &mut ids, 1), + TagCode::RemoveObject2 => self + .0 + .write(context.gc_context) + .preload_remove_object(context, reader, &mut ids, 2), + TagCode::ShowFrame => self.0.write(context.gc_context).preload_show_frame( + context, + reader, + &mut cur_frame, + ), + TagCode::SoundStreamHead => self + .0 + .write(context.gc_context) + .preload_sound_stream_head(context, reader, cur_frame, &mut static_data, 1), + TagCode::SoundStreamHead2 => self + .0 + .write(context.gc_context) + .preload_sound_stream_head(context, reader, cur_frame, &mut static_data, 2), + TagCode::SoundStreamBlock => { + self.0.write(context.gc_context).preload_sound_stream_block( + context, + reader, + cur_frame, + &mut static_data, + tag_len, + ) + } + _ => Ok(()), } - TagCode::SoundStreamHead => self.0.write(context.gc_context).preload_sound_stream_head( - context, - reader, - cur_frame, - &mut static_data, - 1, - ), - TagCode::SoundStreamHead2 => self - .0 - .write(context.gc_context) - .preload_sound_stream_head(context, reader, cur_frame, &mut static_data, 2), - TagCode::SoundStreamBlock => self - .0 - .write(context.gc_context) - .preload_sound_stream_block(context, reader, cur_frame, &mut static_data, tag_len), - _ => Ok(()), }; let _ = tag_utils::decode_tags(&mut reader, tag_callback, TagCode::End); self.0.write(context.gc_context).static_data = @@ -643,30 +652,41 @@ impl<'gc> MovieClip<'gc> { let mut has_stream_block = false; drop(mc); + let version = reader.version(); use swf::TagCode; - let tag_callback = |reader: &mut _, tag_code, tag_len| match tag_code { - TagCode::DoAction => self.do_action(self_display_object, context, reader, tag_len), - TagCode::PlaceObject if run_display_actions => { - self.place_object(self_display_object, avm, context, reader, tag_len, 1) + let tag_callback = |reader: &mut SwfStream<&[u8]>, tag_code, tag_len| { + let data = *reader.get_inner().get_ref(); + let tag_pos = reader.get_inner().position() as usize; + let tag_slice = &data[tag_pos..tag_pos + tag_len]; + let reader = &mut SwfStream::new(std::io::Cursor::new(tag_slice), version); + match tag_code { + TagCode::DoAction => self.do_action(self_display_object, context, reader, tag_len), + TagCode::PlaceObject if run_display_actions => { + self.place_object(self_display_object, avm, context, reader, tag_len, 1) + } + TagCode::PlaceObject2 if run_display_actions => { + self.place_object(self_display_object, avm, context, reader, tag_len, 2) + } + TagCode::PlaceObject3 if run_display_actions => { + self.place_object(self_display_object, avm, context, reader, tag_len, 3) + } + TagCode::PlaceObject4 if run_display_actions => { + self.place_object(self_display_object, avm, context, reader, tag_len, 4) + } + TagCode::RemoveObject if run_display_actions => { + self.remove_object(context, reader, 1) + } + TagCode::RemoveObject2 if run_display_actions => { + self.remove_object(context, reader, 2) + } + TagCode::SetBackgroundColor => self.set_background_color(context, reader), + TagCode::StartSound => self.start_sound_1(context, reader), + TagCode::SoundStreamBlock => { + has_stream_block = true; + self.sound_stream_block(context, reader) + } + _ => Ok(()), } - TagCode::PlaceObject2 if run_display_actions => { - self.place_object(self_display_object, avm, context, reader, tag_len, 2) - } - TagCode::PlaceObject3 if run_display_actions => { - self.place_object(self_display_object, avm, context, reader, tag_len, 3) - } - TagCode::PlaceObject4 if run_display_actions => { - self.place_object(self_display_object, avm, context, reader, tag_len, 4) - } - TagCode::RemoveObject if run_display_actions => self.remove_object(context, reader, 1), - TagCode::RemoveObject2 if run_display_actions => self.remove_object(context, reader, 2), - TagCode::SetBackgroundColor => self.set_background_color(context, reader), - TagCode::StartSound => self.start_sound_1(context, reader), - TagCode::SoundStreamBlock => { - has_stream_block = true; - self.sound_stream_block(context, reader) - } - _ => Ok(()), }; let _ = tag_utils::decode_tags(&mut reader, tag_callback, TagCode::ShowFrame); @@ -807,31 +827,66 @@ impl<'gc> MovieClip<'gc> { frame_pos = reader.get_inner().position(); let mut mc = self.0.write(context.gc_context); + let version = reader.version(); use swf::TagCode; - let tag_callback = |reader: &mut _, tag_code, tag_len| match tag_code { - TagCode::PlaceObject => { - index += 1; - mc.goto_place_object(reader, tag_len, 1, &mut goto_commands, is_rewind, index) + let tag_callback = |reader: &mut SwfStream<&[u8]>, tag_code, tag_len| { + let data = *reader.get_inner().get_ref(); + let tag_pos = reader.get_inner().position() as usize; + let tag_slice = &data[tag_pos..tag_pos + tag_len]; + let reader = &mut SwfStream::new(std::io::Cursor::new(tag_slice), version); + match tag_code { + TagCode::PlaceObject => { + index += 1; + mc.goto_place_object( + reader, + tag_len, + 1, + &mut goto_commands, + is_rewind, + index, + ) + } + TagCode::PlaceObject2 => { + index += 1; + mc.goto_place_object( + reader, + tag_len, + 2, + &mut goto_commands, + is_rewind, + index, + ) + } + TagCode::PlaceObject3 => { + index += 1; + mc.goto_place_object( + reader, + tag_len, + 3, + &mut goto_commands, + is_rewind, + index, + ) + } + TagCode::PlaceObject4 => { + index += 1; + mc.goto_place_object( + reader, + tag_len, + 4, + &mut goto_commands, + is_rewind, + index, + ) + } + TagCode::RemoveObject => { + mc.goto_remove_object(reader, 1, context, &mut goto_commands, is_rewind) + } + TagCode::RemoveObject2 => { + mc.goto_remove_object(reader, 2, context, &mut goto_commands, is_rewind) + } + _ => Ok(()), } - TagCode::PlaceObject2 => { - index += 1; - mc.goto_place_object(reader, tag_len, 2, &mut goto_commands, is_rewind, index) - } - TagCode::PlaceObject3 => { - index += 1; - mc.goto_place_object(reader, tag_len, 3, &mut goto_commands, is_rewind, index) - } - TagCode::PlaceObject4 => { - index += 1; - mc.goto_place_object(reader, tag_len, 4, &mut goto_commands, is_rewind, index) - } - TagCode::RemoveObject => { - mc.goto_remove_object(reader, 1, context, &mut goto_commands, is_rewind) - } - TagCode::RemoveObject2 => { - mc.goto_remove_object(reader, 2, context, &mut goto_commands, is_rewind) - } - _ => Ok(()), }; let _ = tag_utils::decode_tags(&mut reader, tag_callback, TagCode::ShowFrame); } diff --git a/swf/src/read.rs b/swf/src/read.rs index 480c03322..fad0c5c7f 100644 --- a/swf/src/read.rs +++ b/swf/src/read.rs @@ -342,6 +342,10 @@ impl Reader { } } + pub fn version(&self) -> u8 { + self.version + } + /// Returns a reference to the underlying `Reader`. pub fn get_ref(&self) -> &R { &self.input