2021-01-18 21:17:17 +00:00
|
|
|
use crate::avm1::{opcode::OpCode, types::*};
|
2019-10-09 23:20:31 +00:00
|
|
|
use crate::error::{Error, Result};
|
2021-02-10 17:51:00 +00:00
|
|
|
use crate::extensions::ReadSwfExt;
|
2017-06-24 19:56:49 +00:00
|
|
|
|
2019-09-09 19:47:54 +00:00
|
|
|
pub struct Reader<'a> {
|
2021-01-18 21:17:17 +00:00
|
|
|
input: &'a [u8],
|
2021-06-26 14:23:09 +00:00
|
|
|
#[allow(dead_code)]
|
2017-06-24 19:56:49 +00:00
|
|
|
version: u8,
|
|
|
|
}
|
|
|
|
|
2021-02-10 17:51:00 +00:00
|
|
|
impl<'a> ReadSwfExt<'a> for Reader<'a> {
|
|
|
|
#[inline(always)]
|
|
|
|
fn as_mut_slice(&mut self) -> &mut &'a [u8] {
|
|
|
|
&mut self.input
|
|
|
|
}
|
2021-04-02 22:17:28 +00:00
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
fn as_slice(&self) -> &'a [u8] {
|
2021-06-05 10:53:23 +00:00
|
|
|
self.input
|
2021-04-02 22:17:28 +00:00
|
|
|
}
|
2021-02-10 17:51:00 +00:00
|
|
|
}
|
|
|
|
|
2019-09-09 19:47:54 +00:00
|
|
|
impl<'a> Reader<'a> {
|
2021-01-20 20:46:22 +00:00
|
|
|
#[inline]
|
2021-02-20 12:05:15 +00:00
|
|
|
pub const fn new(input: &'a [u8], version: u8) -> Self {
|
|
|
|
Self { input, version }
|
2017-06-24 19:56:49 +00:00
|
|
|
}
|
|
|
|
|
2021-02-10 17:51:00 +00:00
|
|
|
#[inline]
|
2021-02-10 21:56:17 +00:00
|
|
|
pub fn seek(&mut self, data: &'a [u8], jump_offset: i16) {
|
2021-02-10 17:51:00 +00:00
|
|
|
ReadSwfExt::seek(self, data, jump_offset as isize)
|
2021-02-10 21:56:17 +00:00
|
|
|
}
|
|
|
|
|
2021-01-20 20:46:22 +00:00
|
|
|
#[inline]
|
2021-02-11 02:36:23 +00:00
|
|
|
pub const fn get_ref(&self) -> &'a [u8] {
|
2021-01-18 21:17:17 +00:00
|
|
|
self.input
|
2017-06-24 19:56:49 +00:00
|
|
|
}
|
|
|
|
|
2021-01-20 20:46:22 +00:00
|
|
|
#[inline]
|
2021-01-18 21:17:17 +00:00
|
|
|
pub fn get_mut(&mut self) -> &mut &'a [u8] {
|
|
|
|
&mut self.input
|
2019-09-09 19:47:54 +00:00
|
|
|
}
|
2019-04-23 07:31:12 +00:00
|
|
|
|
2021-07-09 14:05:13 +00:00
|
|
|
#[inline]
|
|
|
|
fn read_f64_me(&mut self) -> Result<f64> {
|
|
|
|
// Flash weirdly stores (some?) f64 as two LE 32-bit chunks.
|
|
|
|
// First word is the hi-word, second word is the lo-word.
|
|
|
|
let mut bytes = self.read_u64()?.to_le_bytes();
|
|
|
|
bytes.swap(0, 4);
|
|
|
|
bytes.swap(1, 5);
|
|
|
|
bytes.swap(2, 6);
|
|
|
|
bytes.swap(3, 7);
|
|
|
|
Ok(f64::from_le_bytes(bytes))
|
|
|
|
}
|
|
|
|
|
2019-09-09 19:47:54 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn read_action(&mut self) -> Result<Option<Action<'a>>> {
|
2019-10-09 23:20:31 +00:00
|
|
|
let (opcode, mut length) = self.read_opcode_and_length()?;
|
2021-01-20 04:18:53 +00:00
|
|
|
let start = self.input;
|
2019-10-09 23:20:31 +00:00
|
|
|
|
|
|
|
let action = self.read_op(opcode, &mut length);
|
2021-01-18 21:17:17 +00:00
|
|
|
|
|
|
|
let end_pos = (start.as_ptr() as usize + length) as *const u8;
|
2019-10-09 23:20:31 +00:00
|
|
|
if let Err(e) = action {
|
|
|
|
return Err(Error::avm1_parse_error_with_source(opcode, e));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify that we parsed the correct amount of data.
|
2021-01-18 21:17:17 +00:00
|
|
|
if self.input.as_ptr() != end_pos {
|
|
|
|
self.input = &start[length.min(start.len())..];
|
2019-10-09 23:20:31 +00:00
|
|
|
// We incorrectly parsed this action.
|
|
|
|
// Re-sync to the expected end of the action and throw an error.
|
|
|
|
return Err(Error::avm1_parse_error(opcode));
|
|
|
|
}
|
|
|
|
action
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn read_opcode_and_length(&mut self) -> Result<(u8, usize)> {
|
|
|
|
let opcode = self.read_u8()?;
|
|
|
|
let length = if opcode >= 0x80 {
|
2021-06-26 14:23:09 +00:00
|
|
|
self.read_u16()?.into()
|
2019-10-09 23:20:31 +00:00
|
|
|
} else {
|
|
|
|
0
|
|
|
|
};
|
|
|
|
Ok((opcode, length))
|
|
|
|
}
|
2017-06-24 19:56:49 +00:00
|
|
|
|
2019-10-09 23:20:31 +00:00
|
|
|
/// Reads an action with the given opcode.
|
|
|
|
/// `length` is an in-out parameter and will be modified in the case of instructions
|
|
|
|
/// that contain sub-blocks of code, such as `DefineFunction`.
|
|
|
|
/// 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.
|
|
|
|
#[inline]
|
|
|
|
fn read_op(&mut self, opcode: u8, length: &mut usize) -> Result<Option<Action<'a>>> {
|
|
|
|
use num_traits::FromPrimitive;
|
2017-06-24 19:56:49 +00:00
|
|
|
let action = if let Some(op) = OpCode::from_u8(opcode) {
|
2018-06-10 08:23:11 +00:00
|
|
|
match op {
|
|
|
|
OpCode::End => return Ok(None),
|
2017-06-24 19:56:49 +00:00
|
|
|
|
2018-06-10 08:23:11 +00:00
|
|
|
OpCode::Add => Action::Add,
|
|
|
|
OpCode::Add2 => Action::Add2,
|
|
|
|
OpCode::And => Action::And,
|
|
|
|
OpCode::AsciiToChar => Action::AsciiToChar,
|
|
|
|
OpCode::BitAnd => Action::BitAnd,
|
|
|
|
OpCode::BitLShift => Action::BitLShift,
|
|
|
|
OpCode::BitOr => Action::BitOr,
|
|
|
|
OpCode::BitRShift => Action::BitRShift,
|
|
|
|
OpCode::BitURShift => Action::BitURShift,
|
|
|
|
OpCode::BitXor => Action::BitXor,
|
|
|
|
OpCode::Call => Action::Call,
|
|
|
|
OpCode::CallFunction => Action::CallFunction,
|
|
|
|
OpCode::CallMethod => Action::CallMethod,
|
|
|
|
OpCode::CastOp => Action::CastOp,
|
|
|
|
OpCode::CharToAscii => Action::CharToAscii,
|
|
|
|
OpCode::CloneSprite => Action::CloneSprite,
|
2017-06-24 19:56:49 +00:00
|
|
|
OpCode::ConstantPool => {
|
|
|
|
let mut constants = vec![];
|
2019-09-09 19:47:54 +00:00
|
|
|
for _ in 0..self.read_u16()? {
|
2021-02-10 17:51:00 +00:00
|
|
|
constants.push(self.read_str()?);
|
2017-06-24 19:56:49 +00:00
|
|
|
}
|
|
|
|
Action::ConstantPool(constants)
|
2018-06-10 08:23:11 +00:00
|
|
|
}
|
|
|
|
OpCode::Decrement => Action::Decrement,
|
2019-10-09 23:20:31 +00:00
|
|
|
OpCode::DefineFunction => self.read_define_function(length)?,
|
|
|
|
OpCode::DefineFunction2 => self.read_define_function_2(length)?,
|
2018-06-10 08:23:11 +00:00
|
|
|
OpCode::DefineLocal => Action::DefineLocal,
|
|
|
|
OpCode::DefineLocal2 => Action::DefineLocal2,
|
|
|
|
OpCode::Delete => Action::Delete,
|
|
|
|
OpCode::Delete2 => Action::Delete2,
|
|
|
|
OpCode::Divide => Action::Divide,
|
|
|
|
OpCode::EndDrag => Action::EndDrag,
|
|
|
|
OpCode::Enumerate => Action::Enumerate,
|
|
|
|
OpCode::Enumerate2 => Action::Enumerate2,
|
|
|
|
OpCode::Equals => Action::Equals,
|
|
|
|
OpCode::Equals2 => Action::Equals2,
|
|
|
|
OpCode::Extends => Action::Extends,
|
|
|
|
OpCode::GetMember => Action::GetMember,
|
|
|
|
OpCode::GetProperty => Action::GetProperty,
|
|
|
|
OpCode::GetTime => Action::GetTime,
|
2017-06-24 19:56:49 +00:00
|
|
|
OpCode::GetUrl => Action::GetUrl {
|
2021-02-10 17:51:00 +00:00
|
|
|
url: self.read_str()?,
|
|
|
|
target: self.read_str()?,
|
2018-06-10 08:23:11 +00:00
|
|
|
},
|
2017-06-24 19:56:49 +00:00
|
|
|
OpCode::GetUrl2 => {
|
2019-09-09 19:47:54 +00:00
|
|
|
let flags = self.read_u8()?;
|
2017-06-24 19:56:49 +00:00
|
|
|
Action::GetUrl2 {
|
2020-01-17 00:16:48 +00:00
|
|
|
is_load_vars: flags & 0b10_0000_00 != 0,
|
|
|
|
is_target_sprite: flags & 0b01_0000_00 != 0,
|
|
|
|
send_vars_method: match flags & 0b11 {
|
2018-06-10 08:23:11 +00:00
|
|
|
0 => SendVarsMethod::None,
|
|
|
|
1 => SendVarsMethod::Get,
|
|
|
|
2 => SendVarsMethod::Post,
|
2017-06-24 19:56:49 +00:00
|
|
|
_ => {
|
2019-10-09 23:20:31 +00:00
|
|
|
return Err(Error::invalid_data(
|
2017-06-24 19:56:49 +00:00
|
|
|
"Invalid HTTP method in ActionGetUrl2",
|
2019-10-09 23:20:31 +00:00
|
|
|
));
|
2018-06-10 08:23:11 +00:00
|
|
|
}
|
2017-06-24 19:56:49 +00:00
|
|
|
},
|
|
|
|
}
|
2018-06-10 08:23:11 +00:00
|
|
|
}
|
|
|
|
OpCode::GetVariable => Action::GetVariable,
|
2017-06-24 19:56:49 +00:00
|
|
|
OpCode::GotoFrame => {
|
2019-09-09 19:47:54 +00:00
|
|
|
let frame = self.read_u16()?;
|
2017-06-24 19:56:49 +00:00
|
|
|
Action::GotoFrame(frame)
|
2018-06-10 08:23:11 +00:00
|
|
|
}
|
2017-06-24 19:56:49 +00:00
|
|
|
OpCode::GotoFrame2 => {
|
2019-09-09 19:47:54 +00:00
|
|
|
let flags = self.read_u8()?;
|
2017-06-24 19:56:49 +00:00
|
|
|
Action::GotoFrame2 {
|
|
|
|
set_playing: flags & 0b1 != 0,
|
|
|
|
scene_offset: if flags & 0b10 != 0 {
|
2019-09-09 19:47:54 +00:00
|
|
|
self.read_u16()?
|
2017-06-24 19:56:49 +00:00
|
|
|
} else {
|
|
|
|
0
|
|
|
|
},
|
|
|
|
}
|
2018-06-10 08:23:11 +00:00
|
|
|
}
|
2021-02-10 17:51:00 +00:00
|
|
|
OpCode::GotoLabel => Action::GotoLabel(self.read_str()?),
|
2018-06-10 08:23:11 +00:00
|
|
|
OpCode::Greater => Action::Greater,
|
2019-04-23 07:31:12 +00:00
|
|
|
OpCode::If => Action::If {
|
2019-09-09 19:47:54 +00:00
|
|
|
offset: self.read_i16()?,
|
2019-04-23 07:31:12 +00:00
|
|
|
},
|
2018-06-10 08:23:11 +00:00
|
|
|
OpCode::ImplementsOp => Action::ImplementsOp,
|
|
|
|
OpCode::Increment => Action::Increment,
|
|
|
|
OpCode::InitArray => Action::InitArray,
|
|
|
|
OpCode::InitObject => Action::InitObject,
|
|
|
|
OpCode::InstanceOf => Action::InstanceOf,
|
2019-04-23 07:31:12 +00:00
|
|
|
OpCode::Jump => Action::Jump {
|
2019-09-09 19:47:54 +00:00
|
|
|
offset: self.read_i16()?,
|
2019-04-23 07:31:12 +00:00
|
|
|
},
|
2018-06-10 08:23:11 +00:00
|
|
|
OpCode::Less => Action::Less,
|
|
|
|
OpCode::Less2 => Action::Less2,
|
|
|
|
OpCode::MBAsciiToChar => Action::MBAsciiToChar,
|
|
|
|
OpCode::MBCharToAscii => Action::MBCharToAscii,
|
|
|
|
OpCode::MBStringExtract => Action::MBStringExtract,
|
|
|
|
OpCode::MBStringLength => Action::MBStringLength,
|
|
|
|
OpCode::Modulo => Action::Modulo,
|
|
|
|
OpCode::Multiply => Action::Multiply,
|
|
|
|
OpCode::NewMethod => Action::NewMethod,
|
|
|
|
OpCode::NewObject => Action::NewObject,
|
|
|
|
OpCode::NextFrame => Action::NextFrame,
|
|
|
|
OpCode::Not => Action::Not,
|
|
|
|
OpCode::Or => Action::Or,
|
|
|
|
OpCode::Play => Action::Play,
|
|
|
|
OpCode::Pop => Action::Pop,
|
|
|
|
OpCode::PreviousFrame => Action::PreviousFrame,
|
2017-06-24 19:56:49 +00:00
|
|
|
// TODO: Verify correct version for complex types.
|
2019-10-09 23:20:31 +00:00
|
|
|
OpCode::Push => self.read_push(*length)?,
|
2018-06-10 08:23:11 +00:00
|
|
|
OpCode::PushDuplicate => Action::PushDuplicate,
|
|
|
|
OpCode::RandomNumber => Action::RandomNumber,
|
|
|
|
OpCode::RemoveSprite => Action::RemoveSprite,
|
|
|
|
OpCode::Return => Action::Return,
|
|
|
|
OpCode::SetMember => Action::SetMember,
|
|
|
|
OpCode::SetProperty => Action::SetProperty,
|
2021-02-10 17:51:00 +00:00
|
|
|
OpCode::SetTarget => Action::SetTarget(self.read_str()?),
|
2018-06-10 08:23:11 +00:00
|
|
|
OpCode::SetTarget2 => Action::SetTarget2,
|
|
|
|
OpCode::SetVariable => Action::SetVariable,
|
|
|
|
OpCode::StackSwap => Action::StackSwap,
|
|
|
|
OpCode::StartDrag => Action::StartDrag,
|
|
|
|
OpCode::Stop => Action::Stop,
|
|
|
|
OpCode::StopSounds => Action::StopSounds,
|
2019-09-09 19:47:54 +00:00
|
|
|
OpCode::StoreRegister => Action::StoreRegister(self.read_u8()?),
|
2018-06-10 08:23:11 +00:00
|
|
|
OpCode::StrictEquals => Action::StrictEquals,
|
|
|
|
OpCode::StringAdd => Action::StringAdd,
|
|
|
|
OpCode::StringEquals => Action::StringEquals,
|
|
|
|
OpCode::StringExtract => Action::StringExtract,
|
|
|
|
OpCode::StringGreater => Action::StringGreater,
|
|
|
|
OpCode::StringLength => Action::StringLength,
|
|
|
|
OpCode::StringLess => Action::StringLess,
|
|
|
|
OpCode::Subtract => Action::Subtract,
|
|
|
|
OpCode::TargetPath => Action::TargetPath,
|
|
|
|
OpCode::Throw => Action::Throw,
|
|
|
|
OpCode::ToggleQuality => Action::ToggleQuality,
|
|
|
|
OpCode::ToInteger => Action::ToInteger,
|
|
|
|
OpCode::ToNumber => Action::ToNumber,
|
|
|
|
OpCode::ToString => Action::ToString,
|
|
|
|
OpCode::Trace => Action::Trace,
|
2019-10-09 23:20:31 +00:00
|
|
|
OpCode::Try => self.read_try(length)?,
|
2018-06-10 08:23:11 +00:00
|
|
|
OpCode::TypeOf => Action::TypeOf,
|
2017-06-24 19:56:49 +00:00
|
|
|
OpCode::WaitForFrame => Action::WaitForFrame {
|
2019-09-09 19:47:54 +00:00
|
|
|
frame: self.read_u16()?,
|
|
|
|
num_actions_to_skip: self.read_u8()?,
|
2018-06-10 08:23:11 +00:00
|
|
|
},
|
2017-06-24 19:56:49 +00:00
|
|
|
OpCode::With => {
|
2021-06-22 10:04:27 +00:00
|
|
|
let code_length: usize = (self.read_u16()?).into();
|
2019-10-09 23:20:31 +00:00
|
|
|
*length += code_length;
|
2019-04-23 07:31:12 +00:00
|
|
|
Action::With {
|
2019-10-09 23:20:31 +00:00
|
|
|
actions: self.read_slice(code_length)?,
|
2019-04-23 07:31:12 +00:00
|
|
|
}
|
2018-06-10 08:23:11 +00:00
|
|
|
}
|
2017-06-24 19:56:49 +00:00
|
|
|
OpCode::WaitForFrame2 => Action::WaitForFrame2 {
|
2019-09-09 19:47:54 +00:00
|
|
|
num_actions_to_skip: self.read_u8()?,
|
2018-06-10 08:23:11 +00:00
|
|
|
},
|
2017-06-24 19:56:49 +00:00
|
|
|
}
|
|
|
|
} else {
|
2019-10-09 23:20:31 +00:00
|
|
|
self.read_unknown_action(opcode, *length)?
|
2017-06-24 19:56:49 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(Some(action))
|
|
|
|
}
|
|
|
|
|
2019-09-09 19:47:54 +00:00
|
|
|
fn read_unknown_action(&mut self, opcode: u8, length: usize) -> Result<Action<'a>> {
|
|
|
|
Ok(Action::Unknown {
|
|
|
|
opcode,
|
2019-10-09 23:20:31 +00:00
|
|
|
data: self.read_slice(length)?,
|
2019-09-09 19:47:54 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_push(&mut self, length: usize) -> Result<Action<'a>> {
|
2021-01-18 21:17:17 +00:00
|
|
|
let end_pos = (self.input.as_ptr() as usize + length) as *const u8;
|
2020-12-17 20:47:22 +00:00
|
|
|
let mut values = Vec::with_capacity(4);
|
2021-01-18 21:17:17 +00:00
|
|
|
while self.input.as_ptr() < end_pos {
|
2019-09-09 19:47:54 +00:00
|
|
|
values.push(self.read_push_value()?);
|
|
|
|
}
|
|
|
|
Ok(Action::Push(values))
|
2017-06-24 19:56:49 +00:00
|
|
|
}
|
|
|
|
|
2019-09-09 19:47:54 +00:00
|
|
|
fn read_push_value(&mut self) -> Result<Value<'a>> {
|
2019-04-23 06:22:19 +00:00
|
|
|
let value = match self.read_u8()? {
|
2021-02-10 17:51:00 +00:00
|
|
|
0 => Value::Str(self.read_str()?),
|
2019-04-23 06:22:19 +00:00
|
|
|
1 => Value::Float(self.read_f32()?),
|
2018-06-10 08:23:11 +00:00
|
|
|
2 => Value::Null,
|
|
|
|
3 => Value::Undefined,
|
2019-04-23 06:22:19 +00:00
|
|
|
4 => Value::Register(self.read_u8()?),
|
|
|
|
5 => Value::Bool(self.read_u8()? != 0),
|
2020-06-23 23:19:36 +00:00
|
|
|
6 => Value::Double(self.read_f64_me()?),
|
2019-08-26 21:54:09 +00:00
|
|
|
7 => Value::Int(self.read_i32()?),
|
2019-04-23 07:24:33 +00:00
|
|
|
8 => Value::ConstantPool(self.read_u8()?.into()),
|
2019-04-23 06:22:19 +00:00
|
|
|
9 => Value::ConstantPool(self.read_u16()?),
|
2019-10-09 23:20:31 +00:00
|
|
|
_ => return Err(Error::invalid_data("Invalid value type in ActionPush")),
|
2017-06-24 19:56:49 +00:00
|
|
|
};
|
|
|
|
Ok(value)
|
|
|
|
}
|
|
|
|
|
2019-10-09 23:20:31 +00:00
|
|
|
fn read_define_function(&mut self, action_length: &mut usize) -> Result<Action<'a>> {
|
2021-02-10 17:51:00 +00:00
|
|
|
let name = self.read_str()?;
|
2017-06-24 19:56:49 +00:00
|
|
|
let num_params = self.read_u16()?;
|
|
|
|
let mut params = Vec::with_capacity(num_params as usize);
|
|
|
|
for _ in 0..num_params {
|
2021-02-10 17:51:00 +00:00
|
|
|
params.push(self.read_str()?);
|
2017-06-24 19:56:49 +00:00
|
|
|
}
|
2019-09-09 19:47:54 +00:00
|
|
|
// code_length isn't included in the DefineFunction's action length.
|
2021-06-22 10:04:27 +00:00
|
|
|
let code_length: usize = (self.read_u16()?).into();
|
2019-10-09 23:20:31 +00:00
|
|
|
*action_length += code_length;
|
2017-06-24 19:56:49 +00:00
|
|
|
Ok(Action::DefineFunction {
|
2019-04-23 07:24:33 +00:00
|
|
|
name,
|
|
|
|
params,
|
2019-10-09 23:20:31 +00:00
|
|
|
actions: self.read_slice(code_length)?,
|
2017-06-24 19:56:49 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-10-09 23:20:31 +00:00
|
|
|
fn read_define_function_2(&mut self, action_length: &mut usize) -> Result<Action<'a>> {
|
2021-02-10 17:51:00 +00:00
|
|
|
let name = self.read_str()?;
|
2017-06-24 19:56:49 +00:00
|
|
|
let num_params = self.read_u16()?;
|
2021-05-31 00:22:49 +00:00
|
|
|
let register_count = self.read_u8()?;
|
|
|
|
let flags = FunctionFlags::from_bits_truncate(self.read_u16()?);
|
2019-10-16 00:09:14 +00:00
|
|
|
let mut params = Vec::with_capacity(num_params as usize);
|
2017-06-24 19:56:49 +00:00
|
|
|
for _ in 0..num_params {
|
|
|
|
let register = self.read_u8()?;
|
|
|
|
params.push(FunctionParam {
|
2021-02-10 17:51:00 +00:00
|
|
|
name: self.read_str()?,
|
2017-06-24 19:56:49 +00:00
|
|
|
register_index: if register == 0 { None } else { Some(register) },
|
|
|
|
});
|
|
|
|
}
|
2019-09-09 19:47:54 +00:00
|
|
|
// code_length isn't included in the DefineFunction's length.
|
2021-06-22 10:04:27 +00:00
|
|
|
let code_length: usize = (self.read_u16()?).into();
|
2019-10-09 23:20:31 +00:00
|
|
|
*action_length += code_length;
|
2017-06-24 19:56:49 +00:00
|
|
|
Ok(Action::DefineFunction2(Function {
|
2019-04-23 07:24:33 +00:00
|
|
|
name,
|
|
|
|
params,
|
2019-10-16 00:09:14 +00:00
|
|
|
register_count,
|
2021-05-31 00:22:49 +00:00
|
|
|
flags,
|
2019-10-09 23:20:31 +00:00
|
|
|
actions: self.read_slice(code_length)?,
|
2017-06-24 19:56:49 +00:00
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
2019-10-09 23:20:31 +00:00
|
|
|
fn read_try(&mut self, length: &mut usize) -> Result<Action<'a>> {
|
2017-06-24 19:56:49 +00:00
|
|
|
let flags = self.read_u8()?;
|
2021-06-22 10:04:27 +00:00
|
|
|
let try_length: usize = (self.read_u16()?).into();
|
|
|
|
let catch_length: usize = (self.read_u16()?).into();
|
|
|
|
let finally_length: usize = (self.read_u16()?).into();
|
2019-10-09 23:20:31 +00:00
|
|
|
*length += try_length + catch_length + finally_length;
|
2020-06-21 16:37:56 +00:00
|
|
|
let catch_var = if flags & 0b100 == 0 {
|
2021-02-10 17:51:00 +00:00
|
|
|
CatchVar::Var(self.read_str()?)
|
2017-06-24 19:56:49 +00:00
|
|
|
} else {
|
|
|
|
CatchVar::Register(self.read_u8()?)
|
|
|
|
};
|
2019-10-09 23:20:31 +00:00
|
|
|
let try_actions = self.read_slice(try_length)?;
|
|
|
|
let catch_actions = self.read_slice(catch_length)?;
|
|
|
|
let finally_actions = self.read_slice(finally_length)?;
|
2017-06-24 19:56:49 +00:00
|
|
|
Ok(Action::Try(TryBlock {
|
2019-04-23 06:22:19 +00:00
|
|
|
try_actions,
|
2017-06-24 19:56:49 +00:00
|
|
|
catch: if flags & 0b1 != 0 {
|
|
|
|
Some((catch_var, catch_actions))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
},
|
|
|
|
finally: if flags & 0b10 != 0 {
|
|
|
|
Some(finally_actions)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
},
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
pub mod tests {
|
|
|
|
use super::*;
|
2021-02-20 12:05:15 +00:00
|
|
|
use crate::string::{SwfStr, WINDOWS_1252};
|
2019-04-23 06:09:06 +00:00
|
|
|
use crate::test_data;
|
2017-06-24 19:56:49 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn read_action() {
|
|
|
|
for (swf_version, expected_action, action_bytes) in test_data::avm1_tests() {
|
|
|
|
let mut reader = Reader::new(&action_bytes[..], swf_version);
|
2020-12-17 20:47:22 +00:00
|
|
|
let parsed_action = reader.read_action().unwrap().unwrap();
|
2017-06-24 19:56:49 +00:00
|
|
|
if parsed_action != expected_action {
|
|
|
|
// Failed, result doesn't match.
|
|
|
|
panic!(
|
|
|
|
"Incorrectly parsed action.\nRead:\n{:?}\n\nExpected:\n{:?}",
|
2019-04-23 07:31:12 +00:00
|
|
|
parsed_action, expected_action
|
2017-06-24 19:56:49 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-09-09 19:47:54 +00:00
|
|
|
|
2019-10-10 07:41:14 +00:00
|
|
|
/// Ensure that we return an error on invalid data.
|
|
|
|
#[test]
|
|
|
|
fn read_parse_error() {
|
|
|
|
let action_bytes = [0xff, 0xff, 0xff, 0x00, 0x00];
|
|
|
|
let mut reader = Reader::new(&action_bytes[..], 5);
|
2020-12-17 20:47:22 +00:00
|
|
|
match reader.read_action() {
|
2019-10-10 07:41:14 +00:00
|
|
|
Err(crate::error::Error::Avm1ParseError { .. }) => (),
|
|
|
|
result => {
|
|
|
|
panic!("Expected Avm1ParseError, got {:?}", result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-09 19:47:54 +00:00
|
|
|
#[test]
|
|
|
|
fn read_define_function() {
|
|
|
|
// Ensure we read a function properly along with the function data.
|
|
|
|
let action_bytes = vec![
|
|
|
|
0x9b, 0x08, 0x00, 0x66, 0x6f, 0x6f, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x96, 0x06, 0x00,
|
|
|
|
0x00, 0x74, 0x65, 0x73, 0x74, 0x00, 0x26, 0x00,
|
|
|
|
];
|
|
|
|
let mut reader = Reader::new(&action_bytes[..], 5);
|
|
|
|
let action = reader.read_action().unwrap().unwrap();
|
|
|
|
assert_eq!(
|
|
|
|
action,
|
|
|
|
Action::DefineFunction {
|
2021-01-18 21:17:17 +00:00
|
|
|
name: SwfStr::from_str_with_encoding("foo", WINDOWS_1252).unwrap(),
|
2019-09-09 19:47:54 +00:00
|
|
|
params: vec![],
|
|
|
|
actions: &[0x96, 0x06, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x00, 0x26],
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
if let Action::DefineFunction { actions, .. } = action {
|
|
|
|
let mut reader = Reader::new(actions, 5);
|
|
|
|
let action = reader.read_action().unwrap().unwrap();
|
2021-01-18 21:17:17 +00:00
|
|
|
assert_eq!(
|
|
|
|
action,
|
|
|
|
Action::Push(vec![Value::Str(
|
|
|
|
SwfStr::from_str_with_encoding("test", WINDOWS_1252).unwrap()
|
|
|
|
)])
|
|
|
|
);
|
2019-09-09 19:47:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn read_push_to_end_of_action() {
|
|
|
|
// ActionPush doesn't provide an explicit # of values, but instead reads 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 mut reader = Reader::new(&action_bytes[..], 5);
|
|
|
|
let action = reader.read_action().unwrap().unwrap();
|
2020-12-17 20:47:22 +00:00
|
|
|
assert_eq!(action, Action::Push(vec![Value::Null, Value::Undefined]));
|
2019-09-09 19:47:54 +00:00
|
|
|
}
|
2017-06-24 19:56:49 +00:00
|
|
|
}
|