core: Allow callers of `decode_tags` to flag when they would like decoding to stop

This commit is contained in:
David Wendt 2021-07-27 20:08:26 -04:00 committed by kmeisthax
parent f7f5316b71
commit 85cf383c84
4 changed files with 380 additions and 331 deletions

View File

@ -14,7 +14,7 @@ use crate::avm2::Multiname;
use crate::avm2::Namespace;
use crate::avm2::QName;
use crate::string::AvmString;
use crate::tag_utils::{self, SwfMovie, SwfSlice, SwfStream};
use crate::tag_utils::{self, ControlFlow, SwfMovie, SwfSlice, SwfStream};
use gc_arena::{Collect, GcCell, MutationContext};
use std::sync::Arc;
use swf::TagCode;
@ -680,10 +680,10 @@ fn load_playerglobal<'gc>(
tag_code
)
}
Ok(())
Ok(ControlFlow::Continue)
};
let _ = tag_utils::decode_tags(&mut reader, tag_callback, TagCode::End, None);
let _ = tag_utils::decode_tags(&mut reader, tag_callback);
macro_rules! avm2_system_classes_playerglobal {
($activation:expr, $script:expr, [$(($package:expr, $class_name:expr, $field:ident)),* $(,)?]) => {
$(

View File

@ -16,7 +16,7 @@ pub use mp3::symphonia::{mp3_metadata, Mp3Decoder};
pub use nellymoser::NellymoserDecoder;
pub use pcm::PcmDecoder;
use crate::tag_utils::SwfSlice;
use crate::tag_utils::{ControlFlow, SwfSlice};
use std::io::{Cursor, Read};
use swf::{AudioCompression, SoundFormat, TagCode};
use thiserror::Error;
@ -319,18 +319,17 @@ impl Iterator for StreamTagReader {
audio_block = &audio_block[4..];
}
*audio_data = swf_data.to_subslice(audio_block);
Ok(())
Ok(ControlFlow::Exit)
}
TagCode::ShowFrame if compression == AudioCompression::Mp3 => {
self.mp3_samples_buffered -= i32::from(self.mp3_samples_per_block);
Ok(())
Ok(ControlFlow::Continue)
}
_ => Ok(()),
_ => Ok(ControlFlow::Continue),
};
let mut reader = self.swf_data.read_from(self.pos as u64);
let _ =
crate::tag_utils::decode_tags(&mut reader, tag_callback, TagCode::ShowFrame, None);
let _ = crate::tag_utils::decode_tags(&mut reader, tag_callback);
self.pos = reader.get_ref().as_ptr() as usize - swf_data.as_ref().as_ptr() as usize;
// If we hit a SoundStreamBlock within this frame, return it. Otherwise, the stream should end.

View File

@ -34,7 +34,7 @@ use crate::font::Font;
use crate::frame_lifecycle::catchup_display_object_to_frame;
use crate::prelude::*;
use crate::string::{AvmString, WStr, WString};
use crate::tag_utils::{self, DecodeResult, Error, SwfMovie, SwfSlice, SwfStream};
use crate::tag_utils::{self, ControlFlow, Error, SwfMovie, SwfSlice, SwfStream};
use crate::vminterface::{AvmObject, Instantiator};
use gc_arena::{Collect, Gc, GcCell, MutationContext};
use smallvec::SmallVec;
@ -361,7 +361,7 @@ impl<'gc> MovieClip<'gc> {
pub fn preload(
self,
context: &mut UpdateContext<'_, 'gc, '_>,
chunk_limit: Option<usize>,
mut chunk_limit: Option<usize>,
) -> bool {
use swf::TagCode;
// TODO: Re-creating static data because preload step occurs after construction.
@ -374,7 +374,9 @@ impl<'gc> MovieClip<'gc> {
(read.cur_preload_frame, read.last_frame_start_pos)
};
let tag_callback = |reader: &mut SwfStream<'_>, tag_code, tag_len| match tag_code {
let mut is_finished = false;
let tag_callback = |reader: &mut SwfStream<'_>, tag_code, tag_len| {
match tag_code {
TagCode::CsmTextSettings => self
.0
.write(context.gc_context)
@ -493,11 +495,11 @@ impl<'gc> MovieClip<'gc> {
.0
.write(context.gc_context)
.export_assets(context, reader),
TagCode::FrameLabel => {
self.0
.write(context.gc_context)
.frame_label(reader, cur_frame, &mut static_data)
}
TagCode::FrameLabel => self.0.write(context.gc_context).frame_label(
reader,
cur_frame,
&mut static_data,
),
TagCode::JpegTables => self
.0
.write(context.gc_context)
@ -530,10 +532,24 @@ impl<'gc> MovieClip<'gc> {
.0
.write(context.gc_context)
.define_binary_data(context, reader),
TagCode::End => {
is_finished = true;
return Ok(ControlFlow::Exit);
}
_ => Ok(()),
}?;
if let Some(ref mut chunk_limit) = chunk_limit {
if *chunk_limit < 1 {
return Ok(ControlFlow::Exit);
}
*chunk_limit -= 1;
}
Ok(ControlFlow::Continue)
};
let is_finished =
tag_utils::decode_tags(&mut reader, tag_callback, TagCode::End, chunk_limit);
let _ = tag_utils::decode_tags(&mut reader, tag_callback);
// These variables will be persisted to be picked back up in the next
// chunk.
@ -555,7 +571,7 @@ impl<'gc> MovieClip<'gc> {
self.0.write(context.gc_context).static_data =
Gc::allocate(context.gc_context, static_data);
is_finished.unwrap_or(true)
is_finished
}
#[inline]
@ -564,7 +580,7 @@ impl<'gc> MovieClip<'gc> {
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'_>,
tag_len: usize,
) -> DecodeResult {
) -> Result<(), Error> {
if context.is_action_script_3() {
log::warn!("DoInitAction tag in AVM2 movie");
return Ok(());
@ -596,7 +612,7 @@ impl<'gc> MovieClip<'gc> {
self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'_>,
) -> DecodeResult {
) -> Result<(), Error> {
if !context.is_action_script_3() {
log::warn!("DoABC tag in AVM1 movie");
return Ok(());
@ -620,7 +636,7 @@ impl<'gc> MovieClip<'gc> {
self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'_>,
) -> DecodeResult {
) -> Result<(), Error> {
let movie = self.movie().ok_or(Error::NoSymbolClasses)?;
let mut activation = Avm2Activation::from_nothing(context.reborrow());
@ -711,7 +727,7 @@ impl<'gc> MovieClip<'gc> {
self,
reader: &mut SwfStream<'_>,
static_data: &mut MovieClipStatic<'gc>,
) -> DecodeResult {
) -> Result<(), Error> {
let mut sfl_data = reader.read_define_scene_and_frame_label_data()?;
sfl_data
.scenes
@ -1104,7 +1120,7 @@ impl<'gc> MovieClip<'gc> {
match tag_code {
TagCode::ShowFrame => {
cur_frame += 1;
Ok(())
Ok(ControlFlow::Exit)
}
TagCode::DoAction if cur_frame == frame => {
// On the target frame, add any DoAction tags to the array.
@ -1112,13 +1128,13 @@ impl<'gc> MovieClip<'gc> {
if !slice.is_empty() {
actions.push(slice);
}
Ok(())
Ok(ControlFlow::Continue)
}
_ => Ok(()),
_ => Ok(ControlFlow::Continue),
}
};
let _ = tag_utils::decode_tags(&mut reader, tag_callback, TagCode::ShowFrame, None);
let _ = tag_utils::decode_tags(&mut reader, tag_callback);
}
}
@ -1168,7 +1184,8 @@ impl<'gc> MovieClip<'gc> {
drop(mc);
use swf::TagCode;
let tag_callback = |reader: &mut SwfStream<'_>, tag_code, tag_len| match tag_code {
let tag_callback = |reader: &mut SwfStream<'_>, tag_code, tag_len| {
match tag_code {
TagCode::DoAction => self.do_action(context, reader, tag_len),
TagCode::PlaceObject if run_display_actions && !context.is_action_script_3() => {
self.place_object(context, reader, tag_len, 1)
@ -1209,9 +1226,13 @@ impl<'gc> MovieClip<'gc> {
TagCode::SetBackgroundColor => self.set_background_color(context, reader),
TagCode::StartSound if run_sounds => self.start_sound_1(context, reader),
TagCode::SoundStreamBlock if run_sounds => self.sound_stream_block(context, reader),
TagCode::ShowFrame => return Ok(ControlFlow::Exit),
_ => Ok(()),
}?;
Ok(ControlFlow::Continue)
};
let _ = tag_utils::decode_tags(&mut reader, tag_callback, TagCode::ShowFrame, None);
let _ = tag_utils::decode_tags(&mut reader, tag_callback);
// On AS3, we deliberately run all removals before the frame number or
// tag position updates. This ensures that code that runs gotos when a
@ -1505,30 +1526,59 @@ impl<'gc> MovieClip<'gc> {
frame_pos = reader.get_ref().as_ptr() as u64 - tag_stream_start;
use swf::TagCode;
let tag_callback = |reader: &mut _, tag_code, tag_len| match tag_code {
let tag_callback = |reader: &mut _, tag_code, tag_len| {
match tag_code {
TagCode::PlaceObject => {
index += 1;
let mut mc = self.0.write(context.gc_context);
mc.goto_place_object(reader, tag_len, 1, &mut goto_commands, is_rewind, index)
mc.goto_place_object(
reader,
tag_len,
1,
&mut goto_commands,
is_rewind,
index,
)
}
TagCode::PlaceObject2 => {
index += 1;
let mut mc = self.0.write(context.gc_context);
mc.goto_place_object(reader, tag_len, 2, &mut goto_commands, is_rewind, index)
mc.goto_place_object(
reader,
tag_len,
2,
&mut goto_commands,
is_rewind,
index,
)
}
TagCode::PlaceObject3 => {
index += 1;
let mut mc = self.0.write(context.gc_context);
mc.goto_place_object(reader, tag_len, 3, &mut goto_commands, is_rewind, index)
mc.goto_place_object(
reader,
tag_len,
3,
&mut goto_commands,
is_rewind,
index,
)
}
TagCode::PlaceObject4 => {
index += 1;
let mut mc = self.0.write(context.gc_context);
mc.goto_place_object(reader, tag_len, 4, &mut goto_commands, is_rewind, index)
mc.goto_place_object(
reader,
tag_len,
4,
&mut goto_commands,
is_rewind,
index,
)
}
TagCode::RemoveObject => self.goto_remove_object(
reader,
@ -1548,9 +1598,13 @@ impl<'gc> MovieClip<'gc> {
from_frame,
&mut removed_frame_scripts,
),
TagCode::ShowFrame => return Ok(ControlFlow::Exit),
_ => Ok(()),
}?;
Ok(ControlFlow::Continue)
};
let _ = tag_utils::decode_tags(&mut reader, tag_callback, TagCode::ShowFrame, None);
let _ = tag_utils::decode_tags(&mut reader, tag_callback);
}
let hit_target_frame = self.0.read().current_frame == frame;
@ -1925,7 +1979,7 @@ impl<'gc> MovieClip<'gc> {
is_rewind: bool,
from_frame: FrameNumber,
removed_frame_scripts: &mut Vec<DisplayObject<'gc>>,
) -> DecodeResult {
) -> Result<(), Error> {
let remove_object = if version == 1 {
reader.read_remove_object_1()
} else {
@ -2703,7 +2757,7 @@ impl<'gc> MovieClipData<'gc> {
goto_commands: &mut Vec<GotoPlaceObject<'a>>,
is_rewind: bool,
index: usize,
) -> DecodeResult {
) -> Result<(), Error> {
let tag_start =
reader.get_ref().as_ptr() as u64 - self.static_data.swf.as_ref().as_ptr() as u64;
let place_object = if version == 1 {
@ -2790,7 +2844,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
version: u8,
) -> DecodeResult {
) -> Result<(), Error> {
let define_bits_lossless = reader.read_define_bits_lossless(version)?;
let bitmap_info = context
.renderer
@ -2815,7 +2869,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
version: u8,
) -> DecodeResult {
) -> Result<(), Error> {
let movie = self.movie();
let tag = reader.read_define_morph_shape(version)?;
let id = tag.id;
@ -2833,7 +2887,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
version: u8,
) -> DecodeResult {
) -> Result<(), Error> {
let movie = self.movie();
let swf_shape = reader.read_define_shape(version)?;
let id = swf_shape.id;
@ -2851,7 +2905,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
reader: &mut SwfStream<'a>,
static_data: &mut MovieClipStatic,
_version: u8,
) -> DecodeResult {
) -> Result<(), Error> {
static_data.audio_stream_info = Some(reader.read_sound_stream_head()?);
Ok(())
}
@ -2860,7 +2914,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
let settings = reader.read_csm_text_settings()?;
let library = context.library.library_for_movie_mut(self.movie());
match library.character_by_id(settings.id) {
@ -2891,7 +2945,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream,
) -> DecodeResult {
) -> Result<(), Error> {
let vframe = reader.read_video_frame()?;
let library = context.library.library_for_movie_mut(self.movie());
match library.character_by_id(vframe.stream_id) {
@ -2909,7 +2963,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
let id = reader.read_u16()?;
let jpeg_data = reader.read_slice_to_end();
let bitmap_info = context.renderer.register_bitmap_jpeg(
@ -2938,7 +2992,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
let id = reader.read_u16()?;
let jpeg_data = reader.read_slice_to_end();
let bitmap_info = context.renderer.register_bitmap_jpeg_2(jpeg_data)?;
@ -2962,7 +3016,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
version: u8,
) -> DecodeResult {
) -> Result<(), Error> {
let id = reader.read_u16()?;
let jpeg_len = reader.read_u32()? as usize;
if version == 4 {
@ -2992,7 +3046,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
let swf_button = reader.read_define_button_1()?;
self.define_button_any(context, swf_button)
@ -3003,7 +3057,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
let swf_button = reader.read_define_button_2()?;
self.define_button_any(context, swf_button)
@ -3014,7 +3068,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
swf_button: swf::Button<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
let movie = self.movie();
let button = if movie.is_action_script_3() {
Character::Avm2Button(Avm2Button::from_swf_tag(
@ -3039,7 +3093,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
let button_colors = reader.read_define_button_cxform()?;
match context
.library
@ -3070,7 +3124,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
let button_sounds = reader.read_define_button_sound()?;
match context
.library
@ -3102,7 +3156,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
let swf_edit_text = reader.read_define_edit_text()?;
let edit_text = EditText::from_swf_tag(context, self.movie(), swf_edit_text);
context
@ -3117,7 +3171,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
let font = reader.read_define_font_1()?;
let glyphs = font
.glyphs
@ -3158,7 +3212,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
let font = reader.read_define_font_2(2)?;
let font_id = font.id;
let font_object = Font::from_swf_tag(
@ -3179,7 +3233,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
let font = reader.read_define_font_2(3)?;
let font_id = font.id;
let font_object = Font::from_swf_tag(
@ -3201,7 +3255,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
_context: &mut UpdateContext<'_, 'gc, '_>,
_reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
log::warn!("DefineFont4 tag (TLF text) is not implemented");
Ok(())
}
@ -3211,7 +3265,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
let sound = reader.read_define_sound()?;
if let Ok(handle) = context.audio.register_sound(&sound) {
context
@ -3232,7 +3286,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream,
) -> DecodeResult {
) -> Result<(), Error> {
let streamdef = reader.read_define_video_stream()?;
let id = streamdef.id;
let video = Video::from_swf_tag(self.movie(), streamdef, context.gc_context);
@ -3248,7 +3302,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
tag_len: usize,
) -> DecodeResult {
) -> Result<(), Error> {
let start = reader.as_slice();
let id = reader.read_character_id()?;
let num_frames = reader.read_u16()?;
@ -3286,7 +3340,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
version: u8,
) -> DecodeResult {
) -> Result<(), Error> {
let text = reader.read_define_text(version)?;
let text_object = Text::from_swf_tag(context, self.movie(), &text);
context
@ -3301,7 +3355,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
let tag_data = reader.read_define_binary_data()?;
let binary_data = BinaryData::from_swf_tag(self.movie(), &tag_data);
context
@ -3312,7 +3366,11 @@ impl<'gc, 'a> MovieClipData<'gc> {
}
#[inline]
fn script_limits(&mut self, reader: &mut SwfStream<'a>, avm: &mut Avm1<'gc>) -> DecodeResult {
fn script_limits(
&mut self,
reader: &mut SwfStream<'a>,
avm: &mut Avm1<'gc>,
) -> Result<(), Error> {
let max_recursion_depth = reader.read_u16()?;
let _timeout_in_seconds = reader.read_u16()?;
@ -3326,7 +3384,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
let exports = reader.read_export_assets()?;
for export in exports {
let name = export.name.to_str_lossy(reader.encoding());
@ -3355,7 +3413,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
reader: &mut SwfStream<'a>,
cur_frame: FrameNumber,
static_data: &mut MovieClipStatic<'gc>,
) -> DecodeResult {
) -> Result<(), Error> {
let frame_label = reader.read_frame_label()?;
let mut label = frame_label
.label
@ -3379,7 +3437,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
let jpeg_data = reader.read_slice_to_end();
context
.library
@ -3396,7 +3454,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
_tag_len: usize,
cur_frame: &mut FrameNumber,
_start_pos: &mut u64,
) -> DecodeResult {
) -> Result<(), Error> {
*cur_frame += 1;
Ok(())
}
@ -3409,7 +3467,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
tag_len: usize,
cur_frame: &mut FrameNumber,
start_pos: &mut u64,
) -> DecodeResult {
) -> Result<(), Error> {
let tag_stream_start = self.static_data.swf.as_ref().as_ptr() as u64;
let end_pos = reader.get_ref().as_ptr() as u64 - tag_stream_start;
@ -3434,7 +3492,7 @@ impl<'gc, 'a> MovieClip<'gc> {
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
tag_len: usize,
) -> DecodeResult {
) -> Result<(), Error> {
if context.is_action_script_3() {
log::warn!("DoAction tag in AVM2 movie");
return Ok(());
@ -3463,7 +3521,7 @@ impl<'gc, 'a> MovieClip<'gc> {
reader: &mut SwfStream<'a>,
tag_len: usize,
version: u8,
) -> DecodeResult {
) -> Result<(), Error> {
let mut write = self.0.write(context.gc_context);
let tag_start =
reader.get_ref().as_ptr() as u64 - write.static_data.swf.as_ref().as_ptr() as u64;
@ -3494,7 +3552,7 @@ impl<'gc, 'a> MovieClip<'gc> {
reader: &mut SwfStream<'a>,
tag_len: usize,
version: u8,
) -> DecodeResult {
) -> Result<(), Error> {
let place_object = if version == 1 {
reader.read_place_object(tag_len)
} else {
@ -3528,7 +3586,7 @@ impl<'gc, 'a> MovieClip<'gc> {
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
version: u8,
) -> DecodeResult {
) -> Result<(), Error> {
let remove_object = if version == 1 {
reader.read_remove_object_1()
} else {
@ -3553,7 +3611,7 @@ impl<'gc, 'a> MovieClip<'gc> {
reader: &mut SwfStream<'a>,
tag_len: usize,
version: u8,
) -> DecodeResult {
) -> Result<(), Error> {
let mut write = self.0.write(context.gc_context);
let tag_start =
reader.get_ref().as_ptr() as u64 - write.static_data.swf.as_ref().as_ptr() as u64;
@ -3583,7 +3641,7 @@ impl<'gc, 'a> MovieClip<'gc> {
self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
// Set background color if none set
// bgcolor attribute on the HTML embed would override this
// Also note that a loaded child SWF could change background color only
@ -3602,7 +3660,7 @@ impl<'gc, 'a> MovieClip<'gc> {
self,
context: &mut UpdateContext<'_, 'gc, '_>,
_reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
let mc = self.0.read();
if mc.playing() {
if let (Some(stream_info), None) = (&mc.static_data.audio_stream_info, mc.audio_stream)
@ -3631,7 +3689,7 @@ impl<'gc, 'a> MovieClip<'gc> {
self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
) -> DecodeResult {
) -> Result<(), Error> {
let start_sound = reader.read_start_sound_1()?;
if let Some(handle) = context
.library

View File

@ -24,7 +24,16 @@ pub enum Error {
InvalidSwfUrl,
}
pub type DecodeResult = Result<(), Error>;
/// Whether or not to end tag decoding.
pub enum ControlFlow {
/// Stop decoding after this tag.
Exit,
/// Continue decoding the next tag.
Continue,
}
pub type DecodeResult = Result<ControlFlow, Error>;
pub type SwfStream<'a> = swf::read::Reader<'a>;
/// An open, fully parsed SWF movie ready to play back, either in a Player or a
@ -350,34 +359,19 @@ impl SwfSlice {
///
/// Decoding will terminate when the following conditions occur:
///
/// * After the given `stop_tag` is encountered and passed to the callback
/// * The `tag_callback` calls for the decoding to finish.
/// * The decoder encounters a tag longer than the underlying SWF slice
/// * The decoder decodes more than `chunk_limit` tags (if provided), in which
/// case this function also returns `false`
/// * The SWF stream is otherwise corrupt or unreadable (indicated as an error
/// result)
///
/// Decoding will also log tags longer than the SWF slice, error messages
/// yielded from the tag callback, and unknown tags. It will *only* return an
/// error message if the SWF tag itself could not be parsed. Otherwise, it
/// returns `true` if decoding progressed to the stop tag or EOF, or `false` if
/// the chunk limit was reached.
pub fn decode_tags<'a, F>(
reader: &mut SwfStream<'a>,
mut tag_callback: F,
stop_tag: TagCode,
mut chunk_limit: Option<usize>,
) -> Result<bool, Error>
/// error message if the SWF tag itself could not be parsed.
pub fn decode_tags<'a, F>(reader: &mut SwfStream<'a>, mut tag_callback: F) -> Result<(), Error>
where
F: for<'b> FnMut(&'b mut SwfStream<'a>, TagCode, usize) -> DecodeResult,
F: for<'b> FnMut(&'b mut SwfStream<'a>, TagCode, usize) -> Result<ControlFlow, Error>,
{
loop {
if let Some(chunk_limit) = chunk_limit {
if chunk_limit < 1 {
return Ok(false);
}
}
let (tag_code, tag_len) = reader.read_tag_code_and_length()?;
if tag_len > reader.get_ref().len() {
log::error!("Unexpected EOF when reading tag");
@ -391,24 +385,22 @@ where
*reader.get_mut() = tag_slice;
let result = tag_callback(reader, tag, tag_len);
if let Err(e) = result {
log::error!("Error running definition tag: {:?}, got {}", tag, e);
match result {
Err(e) => {
log::error!("Error running definition tag: {:?}, got {}", tag, e)
}
if stop_tag == tag {
Ok(ControlFlow::Exit) => {
*reader.get_mut() = end_slice;
break;
}
Ok(ControlFlow::Continue) => {}
}
} else {
log::warn!("Unknown tag code: {:?}", tag_code);
}
*reader.get_mut() = end_slice;
if let Some(ref mut chunk_limit) = chunk_limit {
*chunk_limit -= 1;
}
}
Ok(true)
Ok(())
}