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>> {
|
||||
let flags = self.read_u8()?;
|
||||
let try_length: usize = (self.read_u16()?).into();
|
||||
let catch_length: usize = (self.read_u16()?).into();
|
||||
let finally_length: usize = (self.read_u16()?).into();
|
||||
*length += try_length + catch_length + finally_length;
|
||||
let catch_var = if flags & 0b100 == 0 {
|
||||
CatchVar::Var(self.read_str()?)
|
||||
} else {
|
||||
let flags = TryFlags::from_bits_truncate(self.read_u8()?);
|
||||
let try_size: usize = self.read_u16()?.into();
|
||||
let catch_size: usize = self.read_u16()?.into();
|
||||
let finally_size: usize = self.read_u16()?.into();
|
||||
*length += try_size + catch_size + finally_size;
|
||||
let catch_var = if flags.contains(TryFlags::CATCH_IN_REGISTER) {
|
||||
CatchVar::Register(self.read_u8()?)
|
||||
} else {
|
||||
CatchVar::Var(self.read_str()?)
|
||||
};
|
||||
let try_body = self.read_slice(try_length)?;
|
||||
let catch_body = self.read_slice(catch_length)?;
|
||||
let finally_body = self.read_slice(finally_length)?;
|
||||
let try_body = self.read_slice(try_size)?;
|
||||
let catch_body = self.read_slice(catch_size)?;
|
||||
let finally_body = self.read_slice(finally_size)?;
|
||||
Ok(Action::Try(TryBlock {
|
||||
try_body,
|
||||
catch_body: if flags & 0b1 != 0 {
|
||||
catch_body: if flags.contains(TryFlags::CATCH_BLOCK) {
|
||||
Some((catch_var, catch_body))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
finally_body: if flags & 0b10 != 0 {
|
||||
finally_body: if flags.contains(TryFlags::FINALLY_BLOCK) {
|
||||
Some(finally_body)
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -194,3 +194,11 @@ pub enum CatchVar<'a> {
|
|||
Var(&'a SwfStr),
|
||||
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::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![];
|
||||
{
|
||||
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 {
|
||||
let len = 7 + if let Some((CatchVar::Var(name), _)) = try_block.catch_body {
|
||||
name.len() + 1
|
||||
} else {
|
||||
1
|
||||
};
|
||||
self.write_action_header(OpCode::Try, len)?;
|
||||
self.write_u8(
|
||||
if let Some((CatchVar::Register(_), _)) = try_block.catch_body {
|
||||
0b100
|
||||
} else {
|
||||
0
|
||||
} | if try_block.finally_body.is_some() { 0b10 } else { 0 }
|
||||
| if try_block.catch_body.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)?;
|
||||
|
||||
let mut flags = TryFlags::empty();
|
||||
flags.set(TryFlags::CATCH_BLOCK, try_block.catch_body.is_some());
|
||||
flags.set(TryFlags::FINALLY_BLOCK, try_block.finally_body.is_some());
|
||||
flags.set(
|
||||
TryFlags::CATCH_IN_REGISTER,
|
||||
matches!(try_block.catch_body, Some((CatchVar::Register(_), _))),
|
||||
);
|
||||
self.write_u8(flags.bits())?;
|
||||
|
||||
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 {
|
||||
Some((CatchVar::Var(name), _)) => self.write_string(name)?,
|
||||
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::WaitForFrame {
|
||||
|
|
Loading…
Reference in New Issue