swf: Improve `ActionTry` read/write
* Use `TryFlags` instead of hard-coded binary literals. * Rename `try_length`, `catch_length`, `finally_length` to `try_size`, `catch_size`, `finally_size` to match SWF19 namings. * Refactor write and fix a few bugs there: * The actions length should not include the try, catch, finally bodies, only the metadata of `flags`, `try_size`, `catch_size`, `finally_size` and catch variable (either as `u8` or `SwfStr`). * A placeholder byte should be written in place of the catch variable when there is no catch clause.
This commit is contained in:
parent
d49ea10267
commit
281455be6d
|
@ -330,27 +330,27 @@ impl<'a> Reader<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_try(&mut self, length: &mut usize) -> Result<Action<'a>> {
|
fn read_try(&mut self, length: &mut usize) -> Result<Action<'a>> {
|
||||||
let flags = self.read_u8()?;
|
let flags = TryFlags::from_bits_truncate(self.read_u8()?);
|
||||||
let try_length: usize = (self.read_u16()?).into();
|
let try_size: usize = self.read_u16()?.into();
|
||||||
let catch_length: usize = (self.read_u16()?).into();
|
let catch_size: usize = self.read_u16()?.into();
|
||||||
let finally_length: usize = (self.read_u16()?).into();
|
let finally_size: usize = self.read_u16()?.into();
|
||||||
*length += try_length + catch_length + finally_length;
|
*length += try_size + catch_size + finally_size;
|
||||||
let catch_var = if flags & 0b100 == 0 {
|
let catch_var = if flags.contains(TryFlags::CATCH_IN_REGISTER) {
|
||||||
CatchVar::Var(self.read_str()?)
|
|
||||||
} else {
|
|
||||||
CatchVar::Register(self.read_u8()?)
|
CatchVar::Register(self.read_u8()?)
|
||||||
|
} else {
|
||||||
|
CatchVar::Var(self.read_str()?)
|
||||||
};
|
};
|
||||||
let try_body = self.read_slice(try_length)?;
|
let try_body = self.read_slice(try_size)?;
|
||||||
let catch_body = self.read_slice(catch_length)?;
|
let catch_body = self.read_slice(catch_size)?;
|
||||||
let finally_body = self.read_slice(finally_length)?;
|
let finally_body = self.read_slice(finally_size)?;
|
||||||
Ok(Action::Try(TryBlock {
|
Ok(Action::Try(TryBlock {
|
||||||
try_body,
|
try_body,
|
||||||
catch_body: if flags & 0b1 != 0 {
|
catch_body: if flags.contains(TryFlags::CATCH_BLOCK) {
|
||||||
Some((catch_var, catch_body))
|
Some((catch_var, catch_body))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
finally_body: if flags & 0b10 != 0 {
|
finally_body: if flags.contains(TryFlags::FINALLY_BLOCK) {
|
||||||
Some(finally_body)
|
Some(finally_body)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
@ -194,3 +194,11 @@ pub enum CatchVar<'a> {
|
||||||
Var(&'a SwfStr),
|
Var(&'a SwfStr),
|
||||||
Register(u8),
|
Register(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
pub struct TryFlags: u8 {
|
||||||
|
const CATCH_BLOCK = 1 << 0;
|
||||||
|
const FINALLY_BLOCK = 1 << 1;
|
||||||
|
const CATCH_IN_REGISTER = 1 << 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -291,51 +291,51 @@ impl<W: Write> Writer<W> {
|
||||||
Action::ToString => self.write_action_header(OpCode::ToString, 0)?,
|
Action::ToString => self.write_action_header(OpCode::ToString, 0)?,
|
||||||
Action::Trace => self.write_action_header(OpCode::Trace, 0)?,
|
Action::Trace => self.write_action_header(OpCode::Trace, 0)?,
|
||||||
Action::Try(ref try_block) => {
|
Action::Try(ref try_block) => {
|
||||||
let try_length;
|
let len = 7 + if let Some((CatchVar::Var(name), _)) = try_block.catch_body {
|
||||||
let catch_length;
|
|
||||||
let finally_length;
|
|
||||||
let mut action_buf = vec![];
|
|
||||||
{
|
|
||||||
action_buf.write_all(try_block.try_body)?;
|
|
||||||
try_length = try_block.try_body.len();
|
|
||||||
catch_length = if let Some((_, catch)) = try_block.catch_body {
|
|
||||||
action_buf.write_all(catch)?;
|
|
||||||
catch.len()
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
finally_length = if let Some(finally) = try_block.finally_body {
|
|
||||||
action_buf.write_all(finally)?;
|
|
||||||
finally.len()
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
}
|
|
||||||
let len = 7
|
|
||||||
+ action_buf.len()
|
|
||||||
+ if let Some((CatchVar::Var(name), _)) = try_block.catch_body {
|
|
||||||
name.len() + 1
|
name.len() + 1
|
||||||
} else {
|
} else {
|
||||||
1
|
1
|
||||||
};
|
};
|
||||||
self.write_action_header(OpCode::Try, len)?;
|
self.write_action_header(OpCode::Try, len)?;
|
||||||
self.write_u8(
|
|
||||||
if let Some((CatchVar::Register(_), _)) = try_block.catch_body {
|
let mut flags = TryFlags::empty();
|
||||||
0b100
|
flags.set(TryFlags::CATCH_BLOCK, try_block.catch_body.is_some());
|
||||||
} else {
|
flags.set(TryFlags::FINALLY_BLOCK, try_block.finally_body.is_some());
|
||||||
0
|
flags.set(
|
||||||
} | if try_block.finally_body.is_some() { 0b10 } else { 0 }
|
TryFlags::CATCH_IN_REGISTER,
|
||||||
| if try_block.catch_body.is_some() { 0b1 } else { 0 },
|
matches!(try_block.catch_body, Some((CatchVar::Register(_), _))),
|
||||||
)?;
|
);
|
||||||
self.write_u16(try_length as u16)?;
|
self.write_u8(flags.bits())?;
|
||||||
self.write_u16(catch_length as u16)?;
|
|
||||||
self.write_u16(finally_length as u16)?;
|
let try_size = try_block.try_body.len();
|
||||||
|
self.write_u16(try_size as u16)?;
|
||||||
|
|
||||||
|
let catch_size = try_block
|
||||||
|
.catch_body
|
||||||
|
.as_ref()
|
||||||
|
.map_or(0, |(_, catch_body)| catch_body.len());
|
||||||
|
self.write_u16(catch_size as u16)?;
|
||||||
|
|
||||||
|
let finally_size = try_block
|
||||||
|
.finally_body
|
||||||
|
.map_or(0, |finally_body| finally_body.len());
|
||||||
|
self.write_u16(finally_size as u16)?;
|
||||||
|
|
||||||
match try_block.catch_body {
|
match try_block.catch_body {
|
||||||
Some((CatchVar::Var(name), _)) => self.write_string(name)?,
|
Some((CatchVar::Var(name), _)) => self.write_string(name)?,
|
||||||
Some((CatchVar::Register(i), _)) => self.write_u8(i)?,
|
Some((CatchVar::Register(i), _)) => self.write_u8(i)?,
|
||||||
_ => (),
|
None => self.write_u8(0)?,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.output.write_all(try_block.try_body)?;
|
||||||
|
|
||||||
|
if let Some((_, catch_body)) = try_block.catch_body {
|
||||||
|
self.output.write_all(catch_body)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(finally_body) = try_block.finally_body {
|
||||||
|
self.output.write_all(finally_body)?;
|
||||||
}
|
}
|
||||||
self.output.write_all(&action_buf)?;
|
|
||||||
}
|
}
|
||||||
Action::TypeOf => self.write_action_header(OpCode::TypeOf, 0)?,
|
Action::TypeOf => self.write_action_header(OpCode::TypeOf, 0)?,
|
||||||
Action::WaitForFrame {
|
Action::WaitForFrame {
|
||||||
|
|
Loading…
Reference in New Issue