Implement remaining AVM1 tags; Use Rust 1.13 ? operator
This commit is contained in:
parent
94bed0cfd0
commit
461ab7ad15
|
@ -81,8 +81,6 @@ pub enum OpCode {
|
|||
InstanceOf = 0x54,
|
||||
Enumerate2 = 0x55,
|
||||
|
||||
DoInitAction = 0x59,
|
||||
|
||||
BitAnd = 0x60,
|
||||
BitOr = 0x61,
|
||||
BitXor = 0x62,
|
||||
|
|
158
src/avm1/read.rs
158
src/avm1/read.rs
|
@ -1,4 +1,4 @@
|
|||
use avm1::types::{Action, SendVarsMethod, Value};
|
||||
use avm1::types::*;
|
||||
use avm1::opcode::OpCode;
|
||||
use read::SwfRead;
|
||||
use std::io::{Error, ErrorKind, Read, Result};
|
||||
|
@ -38,14 +38,43 @@ impl<R: Read> Reader<R> {
|
|||
OpCode::End => return Ok(None),
|
||||
|
||||
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,
|
||||
OpCode::ConstantPool => {
|
||||
let mut constants = vec![];
|
||||
for _ in 0..action_reader.read_u16()? {
|
||||
constants.push(action_reader.read_c_string()?);
|
||||
}
|
||||
Action::ConstantPool(constants)
|
||||
},
|
||||
OpCode::Decrement => Action::Decrement,
|
||||
OpCode::DefineFunction => action_reader.read_define_function()?,
|
||||
OpCode::DefineFunction2 => action_reader.read_define_function_2()?,
|
||||
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,
|
||||
OpCode::GetUrl => Action::GetUrl {
|
||||
|
@ -80,14 +109,24 @@ impl<R: Read> Reader<R> {
|
|||
}
|
||||
},
|
||||
OpCode::GotoLabel => Action::GotoLabel(try!(action_reader.read_c_string())),
|
||||
OpCode::Greater => Action::Greater,
|
||||
OpCode::If => Action::If { offset: try!(action_reader.read_i16()) },
|
||||
OpCode::ImplementsOp => Action::ImplementsOp,
|
||||
OpCode::Increment => Action::Increment,
|
||||
OpCode::InitArray => Action::InitArray,
|
||||
OpCode::InitObject => Action::InitObject,
|
||||
OpCode::InstanceOf => Action::InstanceOf,
|
||||
OpCode::Jump => Action::Jump { offset: try!(action_reader.read_i16()) },
|
||||
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,
|
||||
|
@ -102,32 +141,52 @@ impl<R: Read> Reader<R> {
|
|||
};
|
||||
Action::Push(values)
|
||||
},
|
||||
OpCode::PushDuplicate => Action::PushDuplicate,
|
||||
OpCode::RandomNumber => Action::RandomNumber,
|
||||
OpCode::RemoveSprite => Action::RemoveSprite,
|
||||
OpCode::Return => Action::Return,
|
||||
OpCode::SetMember => Action::SetMember,
|
||||
OpCode::SetProperty => Action::SetProperty,
|
||||
OpCode::SetTarget => Action::SetTarget(try!(action_reader.read_c_string())),
|
||||
OpCode::SetTarget => Action::SetTarget(action_reader.read_c_string()?),
|
||||
OpCode::SetTarget2 => Action::SetTarget2,
|
||||
OpCode::SetVariable => Action::SetVariable,
|
||||
OpCode::StackSwap => Action::StackSwap,
|
||||
OpCode::StartDrag => Action::StartDrag,
|
||||
OpCode::Stop => Action::Stop,
|
||||
OpCode::StopSounds => Action::StopSounds,
|
||||
OpCode::StoreRegister => Action::StoreRegister(action_reader.read_u8()?),
|
||||
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::ToInteger => Action::ToInteger,
|
||||
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,
|
||||
OpCode::Try => action_reader.read_try()?,
|
||||
OpCode::TypeOf => Action::TypeOf,
|
||||
OpCode::WaitForFrame => Action::WaitForFrame {
|
||||
frame: try!(action_reader.read_u16()),
|
||||
num_actions_to_skip: try!(action_reader.read_u8()),
|
||||
},
|
||||
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 as u64),
|
||||
self.version
|
||||
);
|
||||
Action::With { actions: with_reader.read_action_list()? }
|
||||
},
|
||||
OpCode::WaitForFrame2 => Action::WaitForFrame2 {
|
||||
num_actions_to_skip: try!(action_reader.read_u8()),
|
||||
},
|
||||
_ => action_reader.read_unknown_action(opcode, length)?
|
||||
}
|
||||
} else {
|
||||
action_reader.read_unknown_action(opcode, length)?
|
||||
|
@ -166,6 +225,97 @@ impl<R: Read> Reader<R> {
|
|||
};
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn read_define_function(&mut self) -> Result<Action> {
|
||||
let name = self.read_c_string()?;
|
||||
let num_params = self.read_u16()?;
|
||||
let mut params = Vec::with_capacity(num_params as usize);
|
||||
for _ in 0..num_params {
|
||||
params.push(self.read_c_string()?);
|
||||
}
|
||||
let code_length = self.read_u16()?;
|
||||
let mut fn_reader = Reader::new(
|
||||
(&mut self.inner as &mut Read).take(code_length as u64),
|
||||
self.version
|
||||
);
|
||||
Ok(Action::DefineFunction {
|
||||
name: name,
|
||||
params: params,
|
||||
actions: fn_reader.read_action_list()?,
|
||||
})
|
||||
}
|
||||
|
||||
fn read_define_function_2(&mut self) -> Result<Action> {
|
||||
let name = self.read_c_string()?;
|
||||
let num_params = self.read_u16()?;
|
||||
let num_registers = self.read_u8()?; // Number of registers
|
||||
let flags = self.read_u16()?;
|
||||
let mut params = Vec::with_capacity(num_params as usize + num_registers as usize);
|
||||
for _ in 0..num_params {
|
||||
let register = self.read_u8()?;
|
||||
params.push(FunctionParam {
|
||||
name: self.read_c_string()?,
|
||||
register_index: if register == 0 { None } else { Some(register) },
|
||||
});
|
||||
}
|
||||
let code_length = self.read_u16()?;
|
||||
let mut fn_reader = Reader::new(
|
||||
(&mut self.inner as &mut Read).take(code_length as u64),
|
||||
self.version
|
||||
);
|
||||
Ok(Action::DefineFunction2(Function {
|
||||
name: name,
|
||||
params: params,
|
||||
preload_global: flags & 0b1_00000000 != 0,
|
||||
preload_parent: flags & 0b10000000 != 0,
|
||||
preload_root: flags & 0b1000000 != 0,
|
||||
suppress_super: flags & 0b100000 != 0,
|
||||
preload_super: flags & 0b10000 != 0,
|
||||
suppress_arguments: flags & 0b1000 != 0,
|
||||
preload_arguments: flags & 0b100 != 0,
|
||||
suppress_this: flags & 0b10 != 0,
|
||||
preload_this: flags & 0b1 != 0,
|
||||
actions: fn_reader.read_action_list()?,
|
||||
}))
|
||||
}
|
||||
|
||||
fn read_try(&mut self) -> Result<Action> {
|
||||
let flags = self.read_u8()?;
|
||||
let try_length = self.read_u16()?;
|
||||
let catch_length = self.read_u16()?;
|
||||
let finally_length = self.read_u16()?;
|
||||
let catch_var = if flags & 0b100 != 0 {
|
||||
CatchVar::Var(self.read_c_string()?)
|
||||
} else {
|
||||
CatchVar::Register(self.read_u8()?)
|
||||
};
|
||||
let try_actions = {
|
||||
let mut fn_reader = Reader::new(
|
||||
(&mut self.inner as &mut Read).take(try_length as u64),
|
||||
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 as u64),
|
||||
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 as u64),
|
||||
self.version
|
||||
);
|
||||
fn_reader.read_action_list()?
|
||||
};
|
||||
Ok(Action::Try(TryBlock {
|
||||
try: try_actions,
|
||||
catch: if flags & 0b1 != 0 { Some((catch_var, catch_actions)) } else { None },
|
||||
finally: if flags & 0b10 != 0 { Some(finally_actions) } else { None },
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1,14 +1,37 @@
|
|||
#[derive(Debug,PartialEq)]
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub enum Action {
|
||||
Add,
|
||||
Add2,
|
||||
And,
|
||||
AsciiToChar,
|
||||
BitAnd,
|
||||
BitLShift,
|
||||
BitOr,
|
||||
BitRShift,
|
||||
BitURShift,
|
||||
BitXor,
|
||||
Call,
|
||||
CallFunction,
|
||||
CallMethod,
|
||||
CastOp,
|
||||
CharToAscii,
|
||||
CloneSprite,
|
||||
ConstantPool(Vec<String>),
|
||||
Decrement,
|
||||
DefineFunction { name: String, params: Vec<String>, actions: Vec<Action> },
|
||||
DefineFunction2(Function),
|
||||
DefineLocal,
|
||||
DefineLocal2,
|
||||
Delete,
|
||||
Delete2,
|
||||
Divide,
|
||||
EndDrag,
|
||||
Enumerate,
|
||||
Enumerate2,
|
||||
Equals,
|
||||
Equals2,
|
||||
Extends,
|
||||
GetMember,
|
||||
GetProperty,
|
||||
GetTime,
|
||||
GetUrl { url: String, target: String },
|
||||
|
@ -17,14 +40,24 @@ pub enum Action {
|
|||
GotoFrame(u16),
|
||||
GotoFrame2 { set_playing: bool, scene_offset: u16 },
|
||||
GotoLabel(String),
|
||||
Greater,
|
||||
If { offset: i16 },
|
||||
ImplementsOp,
|
||||
Increment,
|
||||
InitArray,
|
||||
InitObject,
|
||||
InstanceOf,
|
||||
Jump { offset: i16 },
|
||||
Less,
|
||||
Less2,
|
||||
MBAsciiToChar,
|
||||
MBCharToAscii,
|
||||
MBStringExtract,
|
||||
MBStringLength,
|
||||
Modulo,
|
||||
Multiply,
|
||||
NewMethod,
|
||||
NewObject,
|
||||
NextFrame,
|
||||
Not,
|
||||
Or,
|
||||
|
@ -32,30 +65,44 @@ pub enum Action {
|
|||
Pop,
|
||||
PreviousFrame,
|
||||
Push(Vec<Value>),
|
||||
PushDuplicate,
|
||||
RandomNumber,
|
||||
RemoveSprite,
|
||||
Return,
|
||||
SetMember,
|
||||
SetProperty,
|
||||
SetTarget(String),
|
||||
SetTarget2,
|
||||
SetVariable,
|
||||
StackSwap,
|
||||
StartDrag,
|
||||
Stop,
|
||||
StopSounds,
|
||||
StoreRegister(u8),
|
||||
StrictEquals,
|
||||
StringAdd,
|
||||
StringEquals,
|
||||
StringExtract,
|
||||
StringGreater,
|
||||
StringLength,
|
||||
StringLess,
|
||||
Subtract,
|
||||
TargetPath,
|
||||
Throw,
|
||||
ToInteger,
|
||||
ToNumber,
|
||||
ToString,
|
||||
ToggleQuality,
|
||||
Trace,
|
||||
Try(TryBlock),
|
||||
TypeOf,
|
||||
WaitForFrame { frame: u16, num_actions_to_skip: u8 },
|
||||
WaitForFrame2 { num_actions_to_skip: u8 },
|
||||
With { actions: Vec<Action> },
|
||||
Unknown { opcode: u8, data: Vec<u8> },
|
||||
}
|
||||
|
||||
#[derive(Debug,PartialEq)]
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub enum Value {
|
||||
Undefined,
|
||||
Null,
|
||||
|
@ -73,4 +120,39 @@ pub enum SendVarsMethod {
|
|||
None,
|
||||
Get,
|
||||
Post,
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct Function {
|
||||
pub name: String,
|
||||
pub params: Vec<FunctionParam>,
|
||||
pub preload_parent: bool,
|
||||
pub preload_root: bool,
|
||||
pub suppress_super: bool,
|
||||
pub preload_super: bool,
|
||||
pub suppress_arguments: bool,
|
||||
pub preload_arguments: bool,
|
||||
pub suppress_this: bool,
|
||||
pub preload_this: bool,
|
||||
pub preload_global: bool,
|
||||
pub actions: Vec<Action>,
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug,PartialEq,Eq)]
|
||||
pub struct FunctionParam {
|
||||
pub name: String,
|
||||
pub register_index: Option<u8>,
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct TryBlock {
|
||||
pub try: Vec<Action>,
|
||||
pub catch: Option<(CatchVar, Vec<Action>)>,
|
||||
pub finally: Option<Vec<Action>>,
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug,PartialEq,Eq)]
|
||||
pub enum CatchVar {
|
||||
Var(String),
|
||||
Register(u8),
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use avm1::types::{Action, SendVarsMethod, Value};
|
||||
use avm1::types::*;
|
||||
use avm1::opcode::OpCode;
|
||||
use write::SwfWrite;
|
||||
use std::io::{Result, Write};
|
||||
|
@ -29,24 +29,105 @@ impl<W: Write> Writer<W> {
|
|||
|
||||
pub fn write_action(&mut self, action: &Action) -> Result<()> {
|
||||
match action {
|
||||
&Action::Add => try!(self.write_action_header(OpCode::Add, 0)),
|
||||
&Action::And => try!(self.write_action_header(OpCode::And, 0)),
|
||||
&Action::AsciiToChar => try!(self.write_action_header(OpCode::AsciiToChar, 0)),
|
||||
&Action::Call => try!(self.write_action_header(OpCode::Call, 0)),
|
||||
&Action::CharToAscii => try!(self.write_action_header(OpCode::CharToAscii, 0)),
|
||||
&Action::CloneSprite => try!(self.write_action_header(OpCode::CloneSprite, 0)),
|
||||
&Action::Divide => try!(self.write_action_header(OpCode::Divide, 0)),
|
||||
&Action::EndDrag => try!(self.write_action_header(OpCode::EndDrag, 0)),
|
||||
&Action::Equals => try!(self.write_action_header(OpCode::Equals, 0)),
|
||||
&Action::GetProperty => try!(self.write_action_header(OpCode::GetProperty, 0)),
|
||||
&Action::GetTime => try!(self.write_action_header(OpCode::GetTime, 0)),
|
||||
&Action::Add => self.write_action_header(OpCode::Add, 0)?,
|
||||
&Action::Add2 => self.write_action_header(OpCode::Add2, 0)?,
|
||||
&Action::And => self.write_action_header(OpCode::And, 0)?,
|
||||
&Action::AsciiToChar => self.write_action_header(OpCode::AsciiToChar, 0)?,
|
||||
&Action::BitAnd => self.write_action_header(OpCode::BitAnd, 0)?,
|
||||
&Action::BitLShift => self.write_action_header(OpCode::BitLShift, 0)?,
|
||||
&Action::BitOr => self.write_action_header(OpCode::BitOr, 0)?,
|
||||
&Action::BitRShift => self.write_action_header(OpCode::BitRShift, 0)?,
|
||||
&Action::BitURShift => self.write_action_header(OpCode::BitURShift, 0)?,
|
||||
&Action::BitXor => self.write_action_header(OpCode::BitXor, 0)?,
|
||||
&Action::Call => self.write_action_header(OpCode::Call, 0)?,
|
||||
&Action::CallFunction => self.write_action_header(OpCode::CallFunction, 0)?,
|
||||
&Action::CallMethod => self.write_action_header(OpCode::CallMethod, 0)?,
|
||||
&Action::CastOp => self.write_action_header(OpCode::CastOp, 0)?,
|
||||
&Action::CharToAscii => self.write_action_header(OpCode::CharToAscii, 0)?,
|
||||
&Action::CloneSprite => self.write_action_header(OpCode::CloneSprite, 0)?,
|
||||
&Action::ConstantPool(ref constants) => {
|
||||
let len = 2 + constants.iter().map(|c| c.len() + 1).sum::<usize>();
|
||||
self.write_action_header(OpCode::ConstantPool, len)?;
|
||||
self.write_u16(constants.len() as u16)?;
|
||||
for constant in constants {
|
||||
self.write_c_string(constant)?;
|
||||
}
|
||||
},
|
||||
&Action::Decrement => self.write_action_header(OpCode::Decrement, 0)?,
|
||||
&Action::DefineFunction { ref name, ref params, ref actions } => {
|
||||
let mut action_buf = vec![];
|
||||
{
|
||||
let mut fn_writer = Writer::new(&mut action_buf, self.version);
|
||||
fn_writer.write_action_list(actions)?;
|
||||
}
|
||||
let len = name.len() + 1
|
||||
+ 2 + params.iter().map(|p| p.len() + 1).sum::<usize>()
|
||||
+ 2 + action_buf.len();
|
||||
self.write_action_header(OpCode::DefineFunction, len)?;
|
||||
self.write_c_string(name)?;
|
||||
self.write_u16(params.len() as u16)?;
|
||||
for param in params {
|
||||
self.write_c_string(param)?;
|
||||
}
|
||||
self.write_u16(action_buf.len() as u16)?;
|
||||
self.inner.write_all(&action_buf)?;
|
||||
},
|
||||
&Action::DefineFunction2(ref function) => {
|
||||
let mut action_buf = vec![];
|
||||
{
|
||||
let mut fn_writer = Writer::new(&mut action_buf, self.version);
|
||||
fn_writer.write_action_list(&function.actions)?;
|
||||
}
|
||||
let len = function.name.len() + 1
|
||||
+ 3 + function.params.iter().map(|p| p.name.len() + 2).sum::<usize>()
|
||||
+ 4 + action_buf.len();
|
||||
let num_registers = function.params.iter().map(
|
||||
|p| if p.register_index.is_none() { 1 } else { 0 }).sum();
|
||||
self.write_action_header(OpCode::DefineFunction2, len)?;
|
||||
self.write_c_string(&function.name)?;
|
||||
self.write_u16(function.params.len() as u16)?;
|
||||
self.write_u8(num_registers)?;
|
||||
let flags =
|
||||
if function.preload_global { 0b1_00000000 } else { 0 } |
|
||||
if function.preload_parent { 0b10000000 } else { 0 } |
|
||||
if function.preload_root { 0b1000000 } else { 0 } |
|
||||
if function.suppress_super { 0b100000 } else { 0 } |
|
||||
if function.preload_super { 0b10000 } else { 0 } |
|
||||
if function.suppress_arguments { 0b1000 } else { 0 } |
|
||||
if function.preload_arguments { 0b100 } else { 0 } |
|
||||
if function.suppress_this { 0b10 } else { 0 } |
|
||||
if function.preload_this { 0b1 } else { 0 };
|
||||
self.write_u16(flags)?;
|
||||
for param in &function.params {
|
||||
self.write_u8(
|
||||
if let Some(n) = param.register_index { n } else { 0 }
|
||||
)?;
|
||||
self.write_c_string(¶m.name)?;
|
||||
}
|
||||
self.write_u16(action_buf.len() as u16)?;
|
||||
self.inner.write_all(&action_buf)?;
|
||||
},
|
||||
&Action::DefineLocal => self.write_action_header(OpCode::DefineLocal, 0)?,
|
||||
&Action::DefineLocal2 => self.write_action_header(OpCode::DefineLocal2, 0)?,
|
||||
&Action::Divide => self.write_action_header(OpCode::Divide, 0)?,
|
||||
&Action::Delete => self.write_action_header(OpCode::Delete, 0)?,
|
||||
&Action::Delete2 => self.write_action_header(OpCode::Delete2, 0)?,
|
||||
&Action::EndDrag => self.write_action_header(OpCode::EndDrag, 0)?,
|
||||
&Action::Enumerate => self.write_action_header(OpCode::Enumerate, 0)?,
|
||||
&Action::Enumerate2 => self.write_action_header(OpCode::Enumerate2, 0)?,
|
||||
&Action::Equals => self.write_action_header(OpCode::Equals, 0)?,
|
||||
&Action::Equals2 => self.write_action_header(OpCode::Equals2, 0)?,
|
||||
&Action::Extends => self.write_action_header(OpCode::Extends, 0)?,
|
||||
&Action::GetMember => self.write_action_header(OpCode::GetMember, 0)?,
|
||||
&Action::GetProperty => self.write_action_header(OpCode::GetProperty, 0)?,
|
||||
&Action::GetTime => self.write_action_header(OpCode::GetTime, 0)?,
|
||||
&Action::GetUrl { ref url, ref target } => {
|
||||
try!(self.write_action_header(OpCode::GetUrl, url.len() + target.len() + 2));
|
||||
try!(self.write_c_string(url));
|
||||
try!(self.write_c_string(target));
|
||||
self.write_action_header(OpCode::GetUrl, url.len() + target.len() + 2)?;
|
||||
self.write_c_string(url)?;
|
||||
self.write_c_string(target)?;
|
||||
},
|
||||
&Action::GetUrl2 { send_vars_method, is_target_sprite, is_load_vars } => {
|
||||
try!(self.write_action_header(OpCode::GetUrl2, 1));
|
||||
self.write_action_header(OpCode::GetUrl2, 1)?;
|
||||
let flags =
|
||||
(match send_vars_method {
|
||||
SendVarsMethod::None => 0,
|
||||
|
@ -55,47 +136,57 @@ impl<W: Write> Writer<W> {
|
|||
} << 6) |
|
||||
if is_target_sprite { 0b10 } else { 0 } |
|
||||
if is_load_vars { 0b1 } else { 0 };
|
||||
try!(self.write_u8(flags));
|
||||
self.write_u8(flags)?;
|
||||
},
|
||||
&Action::GetVariable => try!(self.write_action_header(OpCode::GetVariable, 0)),
|
||||
&Action::GetVariable => self.write_action_header(OpCode::GetVariable, 0)?,
|
||||
&Action::GotoFrame(frame) => {
|
||||
try!(self.write_action_header(OpCode::GotoFrame, 2));
|
||||
try!(self.write_u16(frame));
|
||||
self.write_action_header(OpCode::GotoFrame, 2)?;
|
||||
self.write_u16(frame)?;
|
||||
},
|
||||
&Action::GotoFrame2 { set_playing, scene_offset } => {
|
||||
if scene_offset != 0 {
|
||||
try!(self.write_action_header(OpCode::GotoFrame2, 3));
|
||||
try!(self.write_u8(if set_playing { 0b11 } else { 0b01 }));
|
||||
try!(self.write_u16(scene_offset));
|
||||
self.write_action_header(OpCode::GotoFrame2, 3)?;
|
||||
self.write_u8(if set_playing { 0b11 } else { 0b01 })?;
|
||||
self.write_u16(scene_offset)?;
|
||||
} else {
|
||||
try!(self.write_action_header(OpCode::GotoFrame2, 1));
|
||||
try!(self.write_u8(if set_playing { 0b10 } else { 0b00 }));
|
||||
self.write_action_header(OpCode::GotoFrame2, 1)?;
|
||||
self.write_u8(if set_playing { 0b10 } else { 0b00 })?;
|
||||
}
|
||||
},
|
||||
&Action::GotoLabel(ref label) => {
|
||||
try!(self.write_action_header(OpCode::GotoLabel, label.len() + 1));
|
||||
try!(self.write_c_string(label));
|
||||
self.write_action_header(OpCode::GotoLabel, label.len() + 1)?;
|
||||
self.write_c_string(label)?;
|
||||
},
|
||||
&Action::Greater => self.write_action_header(OpCode::Greater, 0)?,
|
||||
&Action::If { offset } => {
|
||||
try!(self.write_action_header(OpCode::If, 2));
|
||||
try!(self.write_i16(offset));
|
||||
self.write_action_header(OpCode::If, 2)?;
|
||||
self.write_i16(offset)?;
|
||||
},
|
||||
&Action::ImplementsOp => self.write_action_header(OpCode::ImplementsOp, 0)?,
|
||||
&Action::Increment => self.write_action_header(OpCode::Increment, 0)?,
|
||||
&Action::InitArray => self.write_action_header(OpCode::InitArray, 0)?,
|
||||
&Action::InitObject => self.write_action_header(OpCode::InitObject, 0)?,
|
||||
&Action::InstanceOf => self.write_action_header(OpCode::InstanceOf, 0)?,
|
||||
&Action::Jump { offset } => {
|
||||
try!(self.write_action_header(OpCode::Jump, 2));
|
||||
try!(self.write_i16(offset));
|
||||
self.write_action_header(OpCode::Jump, 2)?;
|
||||
self.write_i16(offset)?;
|
||||
},
|
||||
&Action::Less => try!(self.write_action_header(OpCode::Less, 0)),
|
||||
&Action::MBAsciiToChar => try!(self.write_action_header(OpCode::MBAsciiToChar, 0)),
|
||||
&Action::MBCharToAscii => try!(self.write_action_header(OpCode::MBCharToAscii, 0)),
|
||||
&Action::MBStringExtract => try!(self.write_action_header(OpCode::MBStringExtract, 0)),
|
||||
&Action::MBStringLength => try!(self.write_action_header(OpCode::MBStringLength, 0)),
|
||||
&Action::Multiply => try!(self.write_action_header(OpCode::Multiply, 0)),
|
||||
&Action::NextFrame => try!(self.write_action_header(OpCode::NextFrame, 0)),
|
||||
&Action::Not => try!(self.write_action_header(OpCode::Not, 0)),
|
||||
&Action::Or => try!(self.write_action_header(OpCode::Or, 0)),
|
||||
&Action::Play => try!(self.write_action_header(OpCode::Play, 0)),
|
||||
&Action::Pop => try!(self.write_action_header(OpCode::Pop, 0)),
|
||||
&Action::PreviousFrame => try!(self.write_action_header(OpCode::PreviousFrame, 0)),
|
||||
&Action::Less => self.write_action_header(OpCode::Less, 0)?,
|
||||
&Action::Less2 => self.write_action_header(OpCode::Less2, 0)?,
|
||||
&Action::MBAsciiToChar => self.write_action_header(OpCode::MBAsciiToChar, 0)?,
|
||||
&Action::MBCharToAscii => self.write_action_header(OpCode::MBCharToAscii, 0)?,
|
||||
&Action::MBStringExtract => self.write_action_header(OpCode::MBStringExtract, 0)?,
|
||||
&Action::MBStringLength => self.write_action_header(OpCode::MBStringLength, 0)?,
|
||||
&Action::Modulo => self.write_action_header(OpCode::Modulo, 0)?,
|
||||
&Action::Multiply => self.write_action_header(OpCode::Multiply, 0)?,
|
||||
&Action::NewMethod => self.write_action_header(OpCode::NewMethod, 0)?,
|
||||
&Action::NewObject => self.write_action_header(OpCode::NewObject, 0)?,
|
||||
&Action::NextFrame => self.write_action_header(OpCode::NextFrame, 0)?,
|
||||
&Action::Not => self.write_action_header(OpCode::Not, 0)?,
|
||||
&Action::Or => self.write_action_header(OpCode::Or, 0)?,
|
||||
&Action::Play => self.write_action_header(OpCode::Play, 0)?,
|
||||
&Action::Pop => self.write_action_header(OpCode::Pop, 0)?,
|
||||
&Action::PreviousFrame => self.write_action_header(OpCode::PreviousFrame, 0)?,
|
||||
&Action::Push(ref values) => {
|
||||
let len = values.iter().map(|v| {
|
||||
match v {
|
||||
|
@ -110,44 +201,104 @@ impl<W: Write> Writer<W> {
|
|||
&Value::ConstantPool(v) => if v < 256 { 2 } else { 3 },
|
||||
}
|
||||
}).sum();
|
||||
try!(self.write_action_header(OpCode::Push, len));
|
||||
self.write_action_header(OpCode::Push, len)?;
|
||||
for value in values {
|
||||
try!(self.write_push_value(value));
|
||||
self.write_push_value(value)?;
|
||||
}
|
||||
},
|
||||
&Action::RandomNumber => try!(self.write_action_header(OpCode::RandomNumber, 0)),
|
||||
&Action::RemoveSprite => try!(self.write_action_header(OpCode::RemoveSprite, 0)),
|
||||
&Action::SetProperty => try!(self.write_action_header(OpCode::SetProperty, 0)),
|
||||
&Action::PushDuplicate => self.write_action_header(OpCode::PushDuplicate, 0)?,
|
||||
&Action::RandomNumber => self.write_action_header(OpCode::RandomNumber, 0)?,
|
||||
&Action::RemoveSprite => self.write_action_header(OpCode::RemoveSprite, 0)?,
|
||||
&Action::Return => self.write_action_header(OpCode::Return, 0)?,
|
||||
&Action::SetMember => self.write_action_header(OpCode::SetMember, 0)?,
|
||||
&Action::SetProperty => self.write_action_header(OpCode::SetProperty, 0)?,
|
||||
&Action::SetTarget(ref target) => {
|
||||
try!(self.write_action_header(OpCode::SetTarget, target.len() + 1));
|
||||
try!(self.write_c_string(target));
|
||||
self.write_action_header(OpCode::SetTarget, target.len() + 1)?;
|
||||
self.write_c_string(target)?;
|
||||
},
|
||||
&Action::SetTarget2 => try!(self.write_action_header(OpCode::SetTarget2, 0)),
|
||||
&Action::SetVariable => try!(self.write_action_header(OpCode::SetVariable, 0)),
|
||||
&Action::StartDrag => try!(self.write_action_header(OpCode::StartDrag, 0)),
|
||||
&Action::Stop => try!(self.write_action_header(OpCode::Stop, 0)),
|
||||
&Action::StopSounds => try!(self.write_action_header(OpCode::StopSounds, 0)),
|
||||
&Action::StringAdd => try!(self.write_action_header(OpCode::StringAdd, 0)),
|
||||
&Action::StringEquals => try!(self.write_action_header(OpCode::StringEquals, 0)),
|
||||
&Action::StringExtract => try!(self.write_action_header(OpCode::StringExtract, 0)),
|
||||
&Action::StringLength => try!(self.write_action_header(OpCode::StringLength, 0)),
|
||||
&Action::StringLess => try!(self.write_action_header(OpCode::StringLess, 0)),
|
||||
&Action::Subtract => try!(self.write_action_header(OpCode::Subtract, 0)),
|
||||
&Action::ToInteger => try!(self.write_action_header(OpCode::ToInteger, 0)),
|
||||
&Action::ToggleQuality => try!(self.write_action_header(OpCode::ToggleQuality, 0)),
|
||||
&Action::Trace => try!(self.write_action_header(OpCode::Trace, 0)),
|
||||
&Action::SetTarget2 => self.write_action_header(OpCode::SetTarget2, 0)?,
|
||||
&Action::SetVariable => self.write_action_header(OpCode::SetVariable, 0)?,
|
||||
&Action::StackSwap => self.write_action_header(OpCode::StackSwap, 0)?,
|
||||
&Action::StartDrag => self.write_action_header(OpCode::StartDrag, 0)?,
|
||||
&Action::Stop => self.write_action_header(OpCode::Stop, 0)?,
|
||||
&Action::StopSounds => self.write_action_header(OpCode::StopSounds, 0)?,
|
||||
&Action::StoreRegister(register) => {
|
||||
self.write_action_header(OpCode::StoreRegister, 1)?;
|
||||
self.write_u8(register)?;
|
||||
},
|
||||
&Action::StrictEquals => self.write_action_header(OpCode::StrictEquals, 0)?,
|
||||
&Action::StringAdd => self.write_action_header(OpCode::StringAdd, 0)?,
|
||||
&Action::StringEquals => self.write_action_header(OpCode::StringEquals, 0)?,
|
||||
&Action::StringExtract => self.write_action_header(OpCode::StringExtract, 0)?,
|
||||
&Action::StringGreater => self.write_action_header(OpCode::StringGreater, 0)?,
|
||||
&Action::StringLength => self.write_action_header(OpCode::StringLength, 0)?,
|
||||
&Action::StringLess => self.write_action_header(OpCode::StringLess, 0)?,
|
||||
&Action::Subtract => self.write_action_header(OpCode::Subtract, 0)?,
|
||||
&Action::TargetPath => self.write_action_header(OpCode::TargetPath, 0)?,
|
||||
&Action::Throw => self.write_action_header(OpCode::Throw, 0)?,
|
||||
&Action::ToggleQuality => self.write_action_header(OpCode::ToggleQuality, 0)?,
|
||||
&Action::ToInteger => self.write_action_header(OpCode::ToInteger, 0)?,
|
||||
&Action::ToNumber => self.write_action_header(OpCode::ToNumber, 0)?,
|
||||
&Action::ToString => self.write_action_header(OpCode::ToString, 0)?,
|
||||
&Action::Trace => self.write_action_header(OpCode::Trace, 0)?,
|
||||
&Action::Try(ref try_block) => {
|
||||
let try_length;
|
||||
let catch_length;
|
||||
let finally_length;
|
||||
let mut action_buf = vec![];
|
||||
{
|
||||
let mut fn_writer = Writer::new(&mut action_buf, self.version);
|
||||
fn_writer.write_action_list(&try_block.try)?;
|
||||
try_length = fn_writer.inner.len();
|
||||
if let Some((_, ref catch)) = try_block.catch {
|
||||
fn_writer.write_action_list(catch)?;
|
||||
}
|
||||
catch_length = fn_writer.inner.len() - try_length;
|
||||
if let Some(ref finally) = try_block.finally {
|
||||
fn_writer.write_action_list(finally)?;
|
||||
}
|
||||
finally_length = fn_writer.inner.len() - (try_length + catch_length);
|
||||
}
|
||||
let len = 7 + action_buf.len() +
|
||||
if let Some((CatchVar::Var(ref name), _)) = try_block.catch { name.len() + 1 } else { 1 };
|
||||
self.write_action_header(OpCode::Try, len)?;
|
||||
self.write_u8(
|
||||
if let Some((CatchVar::Register(_), _)) = try_block.catch { 0b100 } else { 0 } |
|
||||
if try_block.finally.is_some() { 0b10 } else { 0 } |
|
||||
if try_block.catch.is_some() { 0b1 } else { 0 }
|
||||
)?;
|
||||
self.write_u16(try_length as u16)?;
|
||||
self.write_u16(catch_length as u16)?;
|
||||
self.write_u16(finally_length as u16)?;
|
||||
match try_block.catch {
|
||||
Some((CatchVar::Var(ref name), _)) => self.write_c_string(name)?,
|
||||
Some((CatchVar::Register(i), _)) => self.write_u8(i)?,
|
||||
_ => (),
|
||||
}
|
||||
self.inner.write_all(&action_buf)?;
|
||||
},
|
||||
&Action::TypeOf => self.write_action_header(OpCode::TypeOf, 0)?,
|
||||
&Action::WaitForFrame { frame, num_actions_to_skip } => {
|
||||
try!(self.write_action_header(OpCode::WaitForFrame, 3));
|
||||
try!(self.write_u16(frame));
|
||||
try!(self.write_u8(num_actions_to_skip));
|
||||
self.write_action_header(OpCode::WaitForFrame, 3)?;
|
||||
self.write_u16(frame)?;
|
||||
self.write_u8(num_actions_to_skip)?;
|
||||
},
|
||||
&Action::WaitForFrame2 { num_actions_to_skip } => {
|
||||
try!(self.write_action_header(OpCode::WaitForFrame2, 1));
|
||||
try!(self.write_u8(num_actions_to_skip));
|
||||
self.write_action_header(OpCode::WaitForFrame2, 1)?;
|
||||
self.write_u8(num_actions_to_skip)?;
|
||||
},
|
||||
&Action::With { ref actions } => {
|
||||
let mut action_buf = vec![];
|
||||
{
|
||||
let mut fn_writer = Writer::new(&mut action_buf, self.version);
|
||||
fn_writer.write_action_list(actions)?;
|
||||
}
|
||||
self.write_action_header(OpCode::With, action_buf.len())?;
|
||||
self.inner.write_all(&action_buf)?;
|
||||
},
|
||||
&Action::Unknown { opcode, ref data } => {
|
||||
try!(self.write_opcode_and_length(opcode, data.len()));
|
||||
try!(self.inner.write_all(&data));
|
||||
self.write_opcode_and_length(opcode, data.len())?;
|
||||
self.inner.write_all(&data)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue