swf: Add `avm1::Action::End`

Returning an `Action::End` instead of `None` when reading the end
of an action.
This commit is contained in:
Mike Welsh 2022-01-16 17:19:45 -08:00
parent d5862809c7
commit 2b2346b65e
4 changed files with 19 additions and 15 deletions

View File

@ -458,7 +458,8 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
if reader.get_ref().as_ptr() as usize >= data.as_ref().as_ptr_range().end as usize { if reader.get_ref().as_ptr() as usize >= data.as_ref().as_ptr_range().end as usize {
//Executing beyond the end of a function constitutes an implicit return. //Executing beyond the end of a function constitutes an implicit return.
Ok(FrameControl::Return(ReturnType::Implicit)) Ok(FrameControl::Return(ReturnType::Implicit))
} else if let Some(action) = reader.read_action()? { } else {
let action = reader.read_action()?;
avm_debug!( avm_debug!(
self.context.avm1, self.context.avm1,
"({}) Action: {:?}", "({}) Action: {:?}",
@ -492,6 +493,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
Action::Delete => self.action_delete(), Action::Delete => self.action_delete(),
Action::Delete2 => self.action_delete_2(), Action::Delete2 => self.action_delete_2(),
Action::Divide => self.action_divide(), Action::Divide => self.action_divide(),
Action::End => self.action_end(),
Action::EndDrag => self.action_end_drag(), Action::EndDrag => self.action_end_drag(),
Action::Enumerate => self.action_enumerate(), Action::Enumerate => self.action_enumerate(),
Action::Enumerate2 => self.action_enumerate_2(), Action::Enumerate2 => self.action_enumerate_2(),
@ -568,9 +570,6 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
Action::With(action) => self.action_with(action, data), Action::With(action) => self.action_with(action, data),
_ => self.unknown_op(action), _ => self.unknown_op(action),
} }
} else {
//The explicit end opcode was encountered so return here
Ok(FrameControl::Return(ReturnType::Implicit))
} }
} }
@ -1015,6 +1014,10 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
fn action_end(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> {
Ok(FrameControl::Return(ReturnType::Implicit))
}
fn action_end_drag(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> { fn action_end_drag(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> {
*self.context.drag_object = None; *self.context.drag_object = None;
Ok(FrameControl::Continue) Ok(FrameControl::Continue)

View File

@ -49,7 +49,7 @@ impl<'a> Reader<'a> {
} }
#[inline] #[inline]
pub fn read_action(&mut self) -> Result<Option<Action<'a>>> { pub fn read_action(&mut self) -> Result<Action<'a>> {
let (opcode, mut length) = self.read_opcode_and_length()?; let (opcode, mut length) = self.read_opcode_and_length()?;
let start = self.input; let start = self.input;
@ -87,11 +87,9 @@ impl<'a> Reader<'a> {
/// The `length` passed in should be the length excluding any sub-blocks. /// The `length` passed in should be the length excluding any sub-blocks.
/// The final `length` returned will be total length of the action, including sub-blocks. /// The final `length` returned will be total length of the action, including sub-blocks.
#[inline] #[inline]
fn read_op(&mut self, opcode: u8, length: &mut usize) -> Result<Option<Action<'a>>> { fn read_op(&mut self, opcode: u8, length: &mut usize) -> Result<Action<'a>> {
let action = if let Some(op) = OpCode::from_u8(opcode) { let action = if let Some(op) = OpCode::from_u8(opcode) {
match op { match op {
OpCode::End => return Ok(None),
OpCode::Add => Action::Add, OpCode::Add => Action::Add,
OpCode::Add2 => Action::Add2, OpCode::Add2 => Action::Add2,
OpCode::And => Action::And, OpCode::And => Action::And,
@ -124,6 +122,7 @@ impl<'a> Reader<'a> {
OpCode::EndDrag => Action::EndDrag, OpCode::EndDrag => Action::EndDrag,
OpCode::Enumerate => Action::Enumerate, OpCode::Enumerate => Action::Enumerate,
OpCode::Enumerate2 => Action::Enumerate2, OpCode::Enumerate2 => Action::Enumerate2,
OpCode::End => Action::End,
OpCode::Equals => Action::Equals, OpCode::Equals => Action::Equals,
OpCode::Equals2 => Action::Equals2, OpCode::Equals2 => Action::Equals2,
OpCode::Extends => Action::Extends, OpCode::Extends => Action::Extends,
@ -200,7 +199,7 @@ impl<'a> Reader<'a> {
Action::Unknown(self.read_unknown_action(opcode, *length)?) Action::Unknown(self.read_unknown_action(opcode, *length)?)
}; };
Ok(Some(action)) Ok(action)
} }
fn read_constant_pool(&mut self) -> Result<ConstantPool<'a>> { fn read_constant_pool(&mut self) -> Result<ConstantPool<'a>> {
@ -420,7 +419,7 @@ pub mod tests {
fn read_action() { fn read_action() {
for (swf_version, expected_action, action_bytes) in test_data::avm1_tests() { for (swf_version, expected_action, action_bytes) in test_data::avm1_tests() {
let mut reader = Reader::new(&action_bytes[..], swf_version); let mut reader = Reader::new(&action_bytes[..], swf_version);
let parsed_action = reader.read_action().unwrap().unwrap(); let parsed_action = reader.read_action().unwrap();
assert_eq!( assert_eq!(
parsed_action, expected_action, parsed_action, expected_action,
"Incorrectly parsed action.\nRead:\n{:?}\n\nExpected:\n{:?}", "Incorrectly parsed action.\nRead:\n{:?}\n\nExpected:\n{:?}",
@ -450,7 +449,7 @@ pub mod tests {
0x00, 0x74, 0x65, 0x73, 0x74, 0x00, 0x26, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x00, 0x26, 0x00,
]; ];
let mut reader = Reader::new(&action_bytes[..], 5); let mut reader = Reader::new(&action_bytes[..], 5);
let action = reader.read_action().unwrap().unwrap(); let action = reader.read_action().unwrap();
assert_eq!( assert_eq!(
action, action,
Action::DefineFunction(DefineFunction { Action::DefineFunction(DefineFunction {
@ -462,7 +461,7 @@ pub mod tests {
if let Action::DefineFunction(DefineFunction { actions, .. }) = action { if let Action::DefineFunction(DefineFunction { actions, .. }) = action {
let mut reader = Reader::new(actions, 5); let mut reader = Reader::new(actions, 5);
let action = reader.read_action().unwrap().unwrap(); let action = reader.read_action().unwrap();
assert_eq!( assert_eq!(
action, action,
Action::Push(Push { Action::Push(Push {
@ -480,7 +479,7 @@ pub mod tests {
// until the end of the action. Ensure we don't read extra values. // until the end of the action. Ensure we don't read extra values.
let action_bytes = [0x96, 2, 0, 2, 3, 3]; // Extra 3 at the end shouldn't be read. let action_bytes = [0x96, 2, 0, 2, 3, 3]; // Extra 3 at the end shouldn't be read.
let mut reader = Reader::new(&action_bytes[..], 5); let mut reader = Reader::new(&action_bytes[..], 5);
let action = reader.read_action().unwrap().unwrap(); let action = reader.read_action().unwrap();
assert_eq!( assert_eq!(
action, action,
Action::Push(Push { Action::Push(Push {
@ -504,7 +503,7 @@ pub mod tests {
]; ];
let mut reader = Reader::new(&action_bytes[..], 5); let mut reader = Reader::new(&action_bytes[..], 5);
let action = reader.read_action().unwrap().unwrap(); let action = reader.read_action().unwrap();
assert_eq!( assert_eq!(
action, action,
Action::ConstantPool(ConstantPool { Action::ConstantPool(ConstantPool {
@ -512,7 +511,7 @@ pub mod tests {
}) })
); );
let action = reader.read_action().unwrap().unwrap(); let action = reader.read_action().unwrap();
assert_eq!(action, Action::Subtract); assert_eq!(action, Action::Subtract);
} }
} }

View File

@ -28,6 +28,7 @@ pub enum Action<'a> {
Delete, Delete,
Delete2, Delete2,
Divide, Divide,
End,
EndDrag, EndDrag,
Enumerate, Enumerate,
Enumerate2, Enumerate2,

View File

@ -103,6 +103,7 @@ impl<W: Write> Writer<W> {
Action::Divide => self.write_small_action(OpCode::Divide), Action::Divide => self.write_small_action(OpCode::Divide),
Action::Delete => self.write_small_action(OpCode::Delete), Action::Delete => self.write_small_action(OpCode::Delete),
Action::Delete2 => self.write_small_action(OpCode::Delete2), Action::Delete2 => self.write_small_action(OpCode::Delete2),
Action::End => self.write_small_action(OpCode::End),
Action::EndDrag => self.write_small_action(OpCode::EndDrag), Action::EndDrag => self.write_small_action(OpCode::EndDrag),
Action::Enumerate => self.write_small_action(OpCode::Enumerate), Action::Enumerate => self.write_small_action(OpCode::Enumerate),
Action::Enumerate2 => self.write_small_action(OpCode::Enumerate2), Action::Enumerate2 => self.write_small_action(OpCode::Enumerate2),