diff --git a/swf/src/avm1/read.rs b/swf/src/avm1/read.rs index 574f276d0..d5c640f92 100644 --- a/swf/src/avm1/read.rs +++ b/swf/src/avm1/read.rs @@ -330,27 +330,27 @@ impl<'a> Reader<'a> { } fn read_try(&mut self, length: &mut usize) -> Result> { - 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 diff --git a/swf/src/avm1/types.rs b/swf/src/avm1/types.rs index ede6e1cc3..b929cba7a 100644 --- a/swf/src/avm1/types.rs +++ b/swf/src/avm1/types.rs @@ -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; + } +} diff --git a/swf/src/avm1/write.rs b/swf/src/avm1/write.rs index ce523f462..62ba64f9d 100644 --- a/swf/src/avm1/write.rs +++ b/swf/src/avm1/write.rs @@ -291,51 +291,51 @@ impl Writer { 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 { - name.len() + 1 - } else { - 1 - }; + 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 {