From 1c2492005c30e0f6bf867211307484e9c23da7c6 Mon Sep 17 00:00:00 2001 From: Adrian Wielgosik <4729533+adrian17@users.noreply.github.com> Date: Fri, 12 Mar 2021 04:55:08 +0100 Subject: [PATCH] avm2: Fix AVM2 reader not reading variable-length numbers correctly --- swf/src/avm2/read.rs | 109 +++++++++++++++++++++++++++++++----------- swf/src/extensions.rs | 21 ++++++++ 2 files changed, 102 insertions(+), 28 deletions(-) diff --git a/swf/src/avm2/read.rs b/swf/src/avm2/read.rs index 9c0ebeb7d..e53f64cd9 100644 --- a/swf/src/avm2/read.rs +++ b/swf/src/avm2/read.rs @@ -79,17 +79,7 @@ impl<'a> Reader<'a> { } fn read_u30(&mut self) -> Result { - let mut n = 0; - let mut i = 0; - loop { - let byte: u32 = self.read_u8()?.into(); - n |= (byte & 0b0111_1111) << i; - i += 7; - if byte & 0b1000_0000 == 0 { - break; - } - } - Ok(n) + self.read_encoded_u32() } fn read_i24(&mut self) -> Result { @@ -98,23 +88,7 @@ impl<'a> Reader<'a> { | (i32::from(self.read_u8()? as i8) << 16)) } fn read_i32(&mut self) -> Result { - let mut n: i32 = 0; - let mut i = 0; - loop { - let byte: i32 = self.read_u8()?.into(); - n |= (byte & 0b0111_1111) << i; - i += 7; - - if byte & 0b1000_0000 == 0 { - if i < 32 { - n <<= 32 - i; - n >>= 32 - i; - } - - break; - } - } - Ok(n) + self.read_encoded_i32() } fn read_string(&mut self) -> Result { @@ -890,4 +864,83 @@ pub mod tests { } } } + + #[test] + fn read_u30() { + let read = |data: &[u8]| Reader::new(data).read_u30().unwrap(); + assert_eq!(read(&[0]), 0); + assert_eq!(read(&[2]), 2); + assert_eq!(read(&[0b1_0000001, 0b0_0000001]), 129); + assert_eq!( + read(&[0b1_0000001, 0b1_0000001, 0b0_1100111]), + 0b1100111_0000001_0000001 + ); + assert_eq!( + read(&[ + 0b1_0000000, + 0b1_0000000, + 0b1_0000000, + 0b1_0000000, + 0b0000_1111 + ]), + 0b1111_0000000_0000000_0000000_0000000 + ); + assert_eq!( + read(&[ + 0b1_0000000, + 0b1_0000000, + 0b1_0000000, + 0b1_0000000, + 0b1111_1111 + ]), + 0b1111_0000000_0000000_0000000_0000000 + ); + } + + #[test] + fn read_i32() { + let read = |data: &[u8]| Reader::new(data).read_i32().unwrap(); + assert_eq!(read(&[0]), 0); + assert_eq!(read(&[2]), 2); + assert_eq!(read(&[0b1_0000001, 0b0_0000001]), 129); + assert_eq!( + read(&[0b1_0000001, 0b1_0000001, 0b0_1100111]), + 0b1111_1111111_1100111_0000001_0000001_u32 as i32 + ); + assert_eq!( + read(&[0b1_0000001, 0b1_0000001, 0b1_0000001, 0b0_1100111]), + 0b1111_1100111_0000001_0000001_0000001_u32 as i32 + ); + // TODO: verify this matches Flash + assert_eq!( + read(&[ + 0b1_0000001, + 0b1_0000001, + 0b1_0000001, + 0b1_0000001, + 0b1_1000001 + ]), + 0b0001_0000001_0000001_0000001_0000001_u32 as i32 + ); + assert_eq!( + read(&[ + 0b1_0000000, + 0b1_0000000, + 0b1_0000000, + 0b1_0000000, + 0b0000_1111 + ]), + 0b1111_0000000_0000000_0000000_0000000_u32 as i32 + ); + assert_eq!( + read(&[ + 0b1_0000000, + 0b1_0000000, + 0b1_0000000, + 0b1_0000000, + 0b1111_1111 + ]), + 0b1111_0000000_0000000_0000000_0000000_u32 as i32 + ); + } } diff --git a/swf/src/extensions.rs b/swf/src/extensions.rs index 84219afa6..112a12d99 100644 --- a/swf/src/extensions.rs +++ b/swf/src/extensions.rs @@ -82,6 +82,27 @@ pub trait ReadSwfExt<'a> { Ok(val) } + #[inline] + fn read_encoded_i32(&mut self) -> Result { + let mut n: i32 = 0; + let mut i = 0; + for _ in 0..5 { + let byte: i32 = self.read_u8()?.into(); + n |= (byte & 0b0111_1111) << i; + i += 7; + + if byte & 0b1000_0000 == 0 { + if i < 32 { + n <<= 32 - i; + n >>= 32 - i; + } + + break; + } + } + Ok(n) + } + #[inline] fn read_f64_me(&mut self) -> Result { // Flash weirdly stores (some?) f64 as two LE 32-bit chunks.