From bf94f5dbaaa186612216f821c4cbdf586678031f Mon Sep 17 00:00:00 2001 From: Mike Welsh Date: Sun, 17 Jan 2021 15:24:20 -0800 Subject: [PATCH] swf: Split out bit i/o into SwfBitsReader/Writer types --- swf/src/read.rs | 601 +++++++++++++++++++++++++------------------ swf/src/types.rs | 8 + swf/src/write.rs | 654 +++++++++++++++++++++++++---------------------- 3 files changed, 709 insertions(+), 554 deletions(-) diff --git a/swf/src/read.rs b/swf/src/read.rs index 15ddd348f..791709fe0 100644 --- a/swf/src/read.rs +++ b/swf/src/read.rs @@ -271,17 +271,78 @@ pub trait SwfRead { // TODO: Verify ANSI for SWF 5 and earlier. String::from_utf8(bytes).map_err(|_| Error::invalid_data("Invalid string data")) } + + fn bits(&mut self) -> BitReader<&mut R> { + BitReader { + input: self.get_inner(), + byte: 0, + bit_index: 0, + } + } +} + +pub struct BitReader { + input: R, + byte: u8, + bit_index: u8, +} + +impl BitReader { + #[inline] + fn byte_align(&mut self) { + self.bit_index = 0; + } + + #[inline] + fn read_bit(&mut self) -> io::Result { + if self.bit_index == 0 { + self.byte = self.input.read_u8()?; + self.bit_index = 8; + } + self.bit_index -= 1; + let val = self.byte & (1 << self.bit_index) != 0; + Ok(val) + } + + #[inline] + fn read_ubits(&mut self, num_bits: u32) -> io::Result { + let mut val = 0u32; + for _ in 0..num_bits { + val <<= 1; + val |= if self.read_bit()? { 1 } else { 0 }; + } + Ok(val) + } + + #[inline] + fn read_sbits(&mut self, num_bits: u32) -> io::Result { + if num_bits > 0 { + self.read_ubits(num_bits) + .map(|n| (n as i32) << (32 - num_bits) >> (32 - num_bits)) + } else { + Ok(0) + } + } + + #[inline] + fn read_sbits_twips(&mut self, num_bits: u32) -> io::Result { + self.read_sbits(num_bits).map(Twips::new) + } + + #[inline] + fn read_fbits(&mut self, num_bits: u32) -> io::Result { + self.read_sbits(num_bits).map(|n| (n as f32) / 65536f32) + } + + #[inline] + fn reader(&mut self) -> &mut R { + &mut self.input + } } pub struct Reader { input: R, version: u8, - - byte: u8, - bit_index: u8, - - num_fill_bits: u8, - num_line_bits: u8, } impl SwfRead for Reader { @@ -290,56 +351,41 @@ impl SwfRead for Reader { } fn read_u8(&mut self) -> io::Result { - self.byte_align(); self.input.read_u8() } fn read_u16(&mut self) -> io::Result { - self.byte_align(); self.input.read_u16::() } fn read_u32(&mut self) -> io::Result { - self.byte_align(); self.input.read_u32::() } fn read_i8(&mut self) -> io::Result { - self.byte_align(); self.input.read_i8() } fn read_i16(&mut self) -> io::Result { - self.byte_align(); self.input.read_i16::() } fn read_i32(&mut self) -> io::Result { - self.byte_align(); self.input.read_i32::() } fn read_f32(&mut self) -> io::Result { - self.byte_align(); self.input.read_f32::() } fn read_f64(&mut self) -> io::Result { - self.byte_align(); self.input.read_f64::() } } impl Reader { pub fn new(input: R, version: u8) -> Reader { - Reader { - input, - version, - byte: 0, - bit_index: 0, - num_fill_bits: 0, - num_line_bits: 0, - } + Reader { input, version } } pub fn version(&self) -> u8 { @@ -686,56 +732,16 @@ impl Reader { } pub fn read_rectangle(&mut self) -> Result { - self.byte_align(); - let num_bits = self.read_ubits(5)? as usize; + let mut bits = self.bits(); + let num_bits: u32 = bits.read_ubits(5)?; Ok(Rectangle { - x_min: self.read_sbits_twips(num_bits)?, - x_max: self.read_sbits_twips(num_bits)?, - y_min: self.read_sbits_twips(num_bits)?, - y_max: self.read_sbits_twips(num_bits)?, + x_min: bits.read_sbits_twips(num_bits)?, + x_max: bits.read_sbits_twips(num_bits)?, + y_min: bits.read_sbits_twips(num_bits)?, + y_max: bits.read_sbits_twips(num_bits)?, }) } - pub fn read_bit(&mut self) -> Result { - if self.bit_index == 0 { - self.byte = self.input.read_u8()?; - self.bit_index = 8; - } - self.bit_index -= 1; - let val = self.byte & (1 << self.bit_index) != 0; - Ok(val) - } - - pub fn byte_align(&mut self) { - self.bit_index = 0; - } - - pub fn read_ubits(&mut self, num_bits: usize) -> Result { - let mut val = 0u32; - for _ in 0..num_bits { - val <<= 1; - val |= if self.read_bit()? { 1 } else { 0 }; - } - Ok(val) - } - - pub fn read_sbits(&mut self, num_bits: usize) -> Result { - if num_bits > 0 { - self.read_ubits(num_bits) - .map(|n| (n as i32) << (32 - num_bits) >> (32 - num_bits)) - } else { - Ok(0) - } - } - - pub fn read_sbits_twips(&mut self, num_bits: usize) -> Result { - self.read_sbits(num_bits).map(Twips::new) - } - - pub fn read_fbits(&mut self, num_bits: usize) -> Result { - self.read_sbits(num_bits).map(|n| (n as f32) / 65536f32) - } - pub fn read_encoded_u32(&mut self) -> Result { let mut val = 0u32; for i in 0..5 { @@ -769,10 +775,10 @@ impl Reader { } pub fn read_color_transform_no_alpha(&mut self) -> Result { - self.byte_align(); - let has_add = self.read_bit()?; - let has_mult = self.read_bit()?; - let num_bits = self.read_ubits(4)? as usize; + let mut bits = self.bits(); + let has_add = bits.read_bit()?; + let has_mult = bits.read_bit()?; + let num_bits = bits.read_ubits(4)?; let mut color_transform = ColorTransform { r_multiply: 1f32, g_multiply: 1f32, @@ -784,23 +790,23 @@ impl Reader { a_add: 0i16, }; if has_mult { - color_transform.r_multiply = self.read_sbits(num_bits)? as f32 / 256f32; - color_transform.g_multiply = self.read_sbits(num_bits)? as f32 / 256f32; - color_transform.b_multiply = self.read_sbits(num_bits)? as f32 / 256f32; + color_transform.r_multiply = bits.read_sbits(num_bits)? as f32 / 256f32; + color_transform.g_multiply = bits.read_sbits(num_bits)? as f32 / 256f32; + color_transform.b_multiply = bits.read_sbits(num_bits)? as f32 / 256f32; } if has_add { - color_transform.r_add = self.read_sbits(num_bits)? as i16; - color_transform.g_add = self.read_sbits(num_bits)? as i16; - color_transform.b_add = self.read_sbits(num_bits)? as i16; + color_transform.r_add = bits.read_sbits(num_bits)? as i16; + color_transform.g_add = bits.read_sbits(num_bits)? as i16; + color_transform.b_add = bits.read_sbits(num_bits)? as i16; } Ok(color_transform) } fn read_color_transform(&mut self) -> Result { - self.byte_align(); - let has_add = self.read_bit()?; - let has_mult = self.read_bit()?; - let num_bits = self.read_ubits(4)? as usize; + let mut bits = self.bits(); + let has_add = bits.read_bit()?; + let has_mult = bits.read_bit()?; + let num_bits = bits.read_ubits(4)?; let mut color_transform = ColorTransform { r_multiply: 1f32, g_multiply: 1f32, @@ -812,40 +818,39 @@ impl Reader { a_add: 0i16, }; if has_mult { - color_transform.r_multiply = self.read_sbits(num_bits)? as f32 / 256f32; - color_transform.g_multiply = self.read_sbits(num_bits)? as f32 / 256f32; - color_transform.b_multiply = self.read_sbits(num_bits)? as f32 / 256f32; - color_transform.a_multiply = self.read_sbits(num_bits)? as f32 / 256f32; + color_transform.r_multiply = bits.read_sbits(num_bits)? as f32 / 256f32; + color_transform.g_multiply = bits.read_sbits(num_bits)? as f32 / 256f32; + color_transform.b_multiply = bits.read_sbits(num_bits)? as f32 / 256f32; + color_transform.a_multiply = bits.read_sbits(num_bits)? as f32 / 256f32; } if has_add { - color_transform.r_add = self.read_sbits(num_bits)? as i16; - color_transform.g_add = self.read_sbits(num_bits)? as i16; - color_transform.b_add = self.read_sbits(num_bits)? as i16; - color_transform.a_add = self.read_sbits(num_bits)? as i16; + color_transform.r_add = bits.read_sbits(num_bits)? as i16; + color_transform.g_add = bits.read_sbits(num_bits)? as i16; + color_transform.b_add = bits.read_sbits(num_bits)? as i16; + color_transform.a_add = bits.read_sbits(num_bits)? as i16; } Ok(color_transform) } fn read_matrix(&mut self) -> Result { - self.byte_align(); + let mut bits = self.bits(); let mut m = Matrix::identity(); // Scale - if self.read_bit()? { - let num_bits = self.read_ubits(5)? as usize; - m.a = self.read_fbits(num_bits)?; - m.d = self.read_fbits(num_bits)?; + if bits.read_bit()? { + let num_bits = bits.read_ubits(5)?; + m.a = bits.read_fbits(num_bits)?; + m.d = bits.read_fbits(num_bits)?; } // Rotate/Skew - if self.read_bit()? { - let num_bits = self.read_ubits(5)? as usize; - m.b = self.read_fbits(num_bits)?; - m.c = self.read_fbits(num_bits)?; + if bits.read_bit()? { + let num_bits = bits.read_ubits(5)?; + m.b = bits.read_fbits(num_bits)?; + m.c = bits.read_fbits(num_bits)?; } // Translate (always present) - let num_bits = self.read_ubits(5)? as usize; - m.tx = self.read_sbits_twips(num_bits)?; - m.ty = self.read_sbits_twips(num_bits)?; - self.byte_align(); + let num_bits = bits.read_ubits(5)?; + m.tx = bits.read_sbits_twips(num_bits)?; + m.ty = bits.read_sbits_twips(num_bits)?; Ok(m) } @@ -1168,15 +1173,21 @@ impl Reader { self.read_u16()?; } + let swf_version = self.version; for _ in 0..num_glyphs { let mut glyph = vec![]; - self.num_fill_bits = self.read_ubits(4)? as u8; - self.num_line_bits = self.read_ubits(4)? as u8; - while let Some(record) = self.read_shape_record(1)? { + let num_bits = self.read_u8()?; + let mut shape_context = ShapeContext { + swf_version, + shape_version: 1, + num_fill_bits: num_bits >> 4, + num_line_bits: num_bits & 0b1111, + }; + let mut bits = self.bits(); + while let Some(record) = Self::read_shape_record(&mut bits, &mut shape_context)? { glyph.push(record); } glyphs.push(glyph); - self.byte_align(); } } @@ -1249,13 +1260,19 @@ impl Reader { } // ShapeTable + let swf_version = self.version; for glyph in &mut glyphs { - self.num_fill_bits = self.read_ubits(4)? as u8; - self.num_line_bits = self.read_ubits(4)? as u8; - while let Some(record) = self.read_shape_record(1)? { + let num_bits = self.read_u8()?; + let mut shape_context = ShapeContext { + swf_version, + shape_version: 1, + num_fill_bits: num_bits >> 4, + num_line_bits: num_bits & 0b1111, + }; + let mut bits = self.bits(); + while let Some(record) = Self::read_shape_record(&mut bits, &mut shape_context)? { glyph.shape_records.push(record); } - self.byte_align(); } // CodeTable @@ -1485,17 +1502,30 @@ impl Reader { } // TODO(Herschel): Add read_shape - self.num_fill_bits = self.read_ubits(4)? as u8; - self.num_line_bits = self.read_ubits(4)? as u8; + let swf_version = self.version; + let mut bits = self.bits(); + let mut shape_context = ShapeContext { + swf_version, + shape_version, + num_fill_bits: bits.read_ubits(4)? as u8, + num_line_bits: bits.read_ubits(4)? as u8, + }; let mut start_shape = Vec::new(); - while let Some(record) = self.read_shape_record(1)? { + while let Some(record) = Self::read_shape_record(&mut bits, &mut shape_context)? { start_shape.push(record); } + drop(bits); - self.byte_align(); let mut end_shape = Vec::new(); self.read_u8()?; // NumFillBits and NumLineBits are written as 0 for the end shape. - while let Some(record) = self.read_shape_record(1)? { + let mut shape_context = ShapeContext { + swf_version: self.version, + shape_version, + num_fill_bits: 0, + num_line_bits: 0, + }; + let mut bits = self.bits(); + while let Some(record) = Self::read_shape_record(&mut bits, &mut shape_context)? { end_shape.push(record); } Ok(DefineMorphShape { @@ -1535,20 +1565,21 @@ impl Reader { // MorphLineStyle2 in DefineMorphShape2. let start_width = Twips::new(self.read_u16()?); let end_width = Twips::new(self.read_u16()?); - let start_cap = match self.read_ubits(2)? { + let flags0 = self.read_u8()?; + let flags1 = self.read_u8()?; + let start_cap = match flags0 >> 6 { 0 => LineCapStyle::Round, 1 => LineCapStyle::None, 2 => LineCapStyle::Square, _ => return Err(Error::invalid_data("Invalid line cap type.")), }; - let join_style_id = self.read_ubits(2)?; - let has_fill = self.read_bit()?; - let allow_scale_x = !self.read_bit()?; - let allow_scale_y = !self.read_bit()?; - let is_pixel_hinted = self.read_bit()?; - self.read_ubits(5)?; - let allow_close = !self.read_bit()?; - let end_cap = match self.read_ubits(2)? { + let join_style_id = (flags0 >> 4) & 0b11; + let has_fill = (flags0 & 0b1000) != 0; + let allow_scale_x = (flags0 & 0b100) == 0; + let allow_scale_y = (flags0 & 0b10) == 0; + let is_pixel_hinted = (flags0 & 0b1) != 0; + let allow_close = (flags1 & 0b100) == 0; + let end_cap = match flags1 & 0b11 { 0 => LineCapStyle::Round, 1 => LineCapStyle::None, 2 => LineCapStyle::Square, @@ -1732,9 +1763,16 @@ impl Reader { } else { (shape_bounds.clone(), false, true, false) }; - let styles = self.read_shape_styles(version)?; + let (styles, num_fill_bits, num_line_bits) = self.read_shape_styles(version)?; let mut records = Vec::new(); - while let Some(record) = self.read_shape_record(version)? { + let mut shape_context = ShapeContext { + swf_version: self.version, + shape_version: version, + num_fill_bits, + num_line_bits, + }; + let mut bits = self.bits(); + while let Some(record) = Self::read_shape_record(&mut bits, &mut shape_context)? { records.push(record); } Ok(Shape { @@ -1786,7 +1824,7 @@ impl Reader { }) } - fn read_shape_styles(&mut self, shape_version: u8) -> Result { + fn read_shape_styles(&mut self, shape_version: u8) -> Result<(ShapeStyles, u8, u8)> { let num_fill_styles = match self.read_u8()? { 0xff if shape_version >= 2 => self.read_u16()? as usize, n => n as usize, @@ -1806,12 +1844,15 @@ impl Reader { line_styles.push(self.read_line_style(shape_version)?); } - self.num_fill_bits = self.read_ubits(4)? as u8; - self.num_line_bits = self.read_ubits(4)? as u8; - Ok(ShapeStyles { - fill_styles, - line_styles, - }) + let num_bits = self.read_u8()?; + Ok(( + ShapeStyles { + fill_styles, + line_styles, + }, + num_bits >> 4, + num_bits & 0b1111, + )) } fn read_fill_style(&mut self, shape_version: u8) -> Result { @@ -1870,20 +1911,21 @@ impl Reader { } else { // LineStyle2 in DefineShape4 let width = Twips::new(self.read_u16()?); - let start_cap = match self.read_ubits(2)? { + let flags0 = self.read_u8()?; + let flags1 = self.read_u8()?; + let start_cap = match flags0 >> 6 { 0 => LineCapStyle::Round, 1 => LineCapStyle::None, 2 => LineCapStyle::Square, _ => return Err(Error::invalid_data("Invalid line cap type.")), }; - let join_style_id = self.read_ubits(2)?; - let has_fill = self.read_bit()?; - let allow_scale_x = !self.read_bit()?; - let allow_scale_y = !self.read_bit()?; - let is_pixel_hinted = self.read_bit()?; - self.read_ubits(5)?; - let allow_close = !self.read_bit()?; - let end_cap = match self.read_ubits(2)? { + let join_style_id = (flags0 >> 4) & 0b11; + let has_fill = (flags0 & 0b1000) != 0; + let allow_scale_x = (flags0 & 0b100) == 0; + let allow_scale_y = (flags0 & 0b10) == 0; + let is_pixel_hinted = (flags0 & 0b1) != 0; + let allow_close = (flags1 & 0b100) == 0; + let end_cap = match flags1 & 0b11 { 0 => LineCapStyle::Round, 1 => LineCapStyle::None, 2 => LineCapStyle::Square, @@ -1927,7 +1969,6 @@ impl Reader { fn read_gradient(&mut self, shape_version: u8) -> Result { let matrix = self.read_matrix()?; - self.byte_align(); let (num_records, spread, interpolation) = self.read_gradient_flags()?; let mut records = Vec::with_capacity(num_records); for _ in 0..num_records { @@ -1965,42 +2006,45 @@ impl Reader { Ok((num_records, spread, interpolation)) } - fn read_shape_record(&mut self, shape_version: u8) -> Result> { - let is_edge_record = self.read_bit()?; + fn read_shape_record( + bits: &mut BitReader<&mut R>, + context: &mut ShapeContext, + ) -> Result> { + let is_edge_record = bits.read_bit()?; let shape_record = if is_edge_record { - let is_straight_edge = self.read_bit()?; + let is_straight_edge = bits.read_bit()?; if is_straight_edge { // StraightEdge - let num_bits = self.read_ubits(4)? as usize + 2; - let is_axis_aligned = !self.read_bit()?; - let is_vertical = is_axis_aligned && self.read_bit()?; + let num_bits = bits.read_ubits(4)? + 2; + let is_axis_aligned = !bits.read_bit()?; + let is_vertical = is_axis_aligned && bits.read_bit()?; let delta_x = if !is_axis_aligned || !is_vertical { - self.read_sbits_twips(num_bits)? + bits.read_sbits_twips(num_bits)? } else { Default::default() }; let delta_y = if !is_axis_aligned || is_vertical { - self.read_sbits_twips(num_bits)? + bits.read_sbits_twips(num_bits)? } else { Default::default() }; Some(ShapeRecord::StraightEdge { delta_x, delta_y }) } else { // CurvedEdge - let num_bits = self.read_ubits(4)? as usize + 2; + let num_bits = bits.read_ubits(4)? + 2; Some(ShapeRecord::CurvedEdge { - control_delta_x: self.read_sbits_twips(num_bits)?, - control_delta_y: self.read_sbits_twips(num_bits)?, - anchor_delta_x: self.read_sbits_twips(num_bits)?, - anchor_delta_y: self.read_sbits_twips(num_bits)?, + control_delta_x: bits.read_sbits_twips(num_bits)?, + control_delta_y: bits.read_sbits_twips(num_bits)?, + anchor_delta_x: bits.read_sbits_twips(num_bits)?, + anchor_delta_y: bits.read_sbits_twips(num_bits)?, }) } } else { - let flags = self.read_ubits(5)?; + let flags = bits.read_ubits(5)?; if flags != 0 { // StyleChange - let num_fill_bits = self.num_fill_bits as usize; - let num_line_bits = self.num_line_bits as usize; + let num_fill_bits = context.num_fill_bits as u32; + let num_line_bits = context.num_line_bits as u32; let mut new_style = StyleChangeData { move_to: None, fill_style_0: None, @@ -2010,26 +2054,31 @@ impl Reader { }; if (flags & 0b1) != 0 { // move - let num_bits = self.read_ubits(5)? as usize; + let num_bits = bits.read_ubits(5)?; new_style.move_to = Some(( - self.read_sbits_twips(num_bits)?, - self.read_sbits_twips(num_bits)?, + bits.read_sbits_twips(num_bits)?, + bits.read_sbits_twips(num_bits)?, )); } if (flags & 0b10) != 0 { - new_style.fill_style_0 = Some(self.read_ubits(num_fill_bits)?); + new_style.fill_style_0 = Some(bits.read_ubits(num_fill_bits)?); } if (flags & 0b100) != 0 { - new_style.fill_style_1 = Some(self.read_ubits(num_fill_bits)?); + new_style.fill_style_1 = Some(bits.read_ubits(num_fill_bits)?); } if (flags & 0b1000) != 0 { - new_style.line_style = Some(self.read_ubits(num_line_bits)?); + new_style.line_style = Some(bits.read_ubits(num_line_bits)?); } // The spec says that StyleChangeRecord can only occur in DefineShape2+, // but SWFs in the wild exist with them in DefineShape1 (generated by third party tools), // and these run correctly in the Flash Player. if (flags & 0b10000) != 0 { - let new_styles = self.read_shape_styles(shape_version)?; + bits.byte_align(); + let mut reader = Reader::new(bits.reader(), context.swf_version); + let (new_styles, num_fill_bits, num_line_bits) = + reader.read_shape_styles(context.shape_version)?; + context.num_fill_bits = num_fill_bits; + context.num_line_bits = num_line_bits; new_style.new_styles = Some(new_styles); } Some(ShapeRecord::StyleChange(new_style)) @@ -2295,28 +2344,29 @@ impl Reader { fn read_clip_event_flags(&mut self) -> Result> { // TODO: Switch to a bitset. let mut event_list = EnumSet::new(); - if self.read_bit()? { + let flags = self.read_u8()?; + if flags & 0b1000_0000 != 0 { event_list.insert(ClipEventFlag::KeyUp); } - if self.read_bit()? { + if flags & 0b0100_0000 != 0 { event_list.insert(ClipEventFlag::KeyDown); } - if self.read_bit()? { + if flags & 0b0010_0000 != 0 { event_list.insert(ClipEventFlag::MouseUp); } - if self.read_bit()? { + if flags & 0b0001_0000 != 0 { event_list.insert(ClipEventFlag::MouseDown); } - if self.read_bit()? { + if flags & 0b0000_1000 != 0 { event_list.insert(ClipEventFlag::MouseMove); } - if self.read_bit()? { + if flags & 0b0000_0100 != 0 { event_list.insert(ClipEventFlag::Unload); } - if self.read_bit()? { + if flags & 0b0000_0010 != 0 { event_list.insert(ClipEventFlag::EnterFrame); } - if self.read_bit()? { + if flags & 0b0000_0001 != 0 { event_list.insert(ClipEventFlag::Load); } if self.version < 6 { @@ -2325,43 +2375,44 @@ impl Reader { // This was expanded to 4 bytes in SWFv6. self.read_u8()?; } else { - if self.read_bit()? { + let flags = self.read_u8()?; + if flags & 0b1000_0000 != 0 { event_list.insert(ClipEventFlag::DragOver); } - if self.read_bit()? { + if flags & 0b0100_0000 != 0 { event_list.insert(ClipEventFlag::RollOut); } - if self.read_bit()? { + if flags & 0b0010_0000 != 0 { event_list.insert(ClipEventFlag::RollOver); } - if self.read_bit()? { + if flags & 0b0001_0000 != 0 { event_list.insert(ClipEventFlag::ReleaseOutside); } - if self.read_bit()? { + if flags & 0b0000_1000 != 0 { event_list.insert(ClipEventFlag::Release); } - if self.read_bit()? { + if flags & 0b0000_0100 != 0 { event_list.insert(ClipEventFlag::Press); } - if self.read_bit()? { + if flags & 0b0000_0010 != 0 { event_list.insert(ClipEventFlag::Initialize); } - if self.read_bit()? { + if flags & 0b0000_0001 != 0 { event_list.insert(ClipEventFlag::Data); } if self.version < 6 { self.read_u16()?; } else { - self.read_ubits(5)?; - if self.read_bit()? { + let flags = self.read_u8()?; + if flags & 0b0000_0100 != 0 { // Construct was only added in SWF7, but it's not version-gated; // Construct events will still fire in SWF6 in a v7+ player. (#1424) event_list.insert(ClipEventFlag::Construct); } - if self.read_bit()? { + if flags & 0b0000_0010 != 0 { event_list.insert(ClipEventFlag::KeyPress); } - if self.read_bit()? { + if flags & 0b0000_0001 != 0 { event_list.insert(ClipEventFlag::DragOut); } self.read_u8()?; @@ -2371,46 +2422,71 @@ impl Reader { } pub fn read_filter(&mut self) -> Result { - self.byte_align(); let filter = match self.read_u8()? { - 0 => Filter::DropShadowFilter(Box::new(DropShadowFilter { - color: self.read_rgba()?, - blur_x: self.read_fixed16()?, - blur_y: self.read_fixed16()?, - angle: self.read_fixed16()?, - distance: self.read_fixed16()?, - strength: self.read_fixed8()?, - is_inner: self.read_bit()?, - is_knockout: self.read_bit()?, - num_passes: self.read_ubits(6)? as u8 & 0b011111, - })), + 0 => { + let color = self.read_rgba()?; + let blur_x = self.read_fixed16()?; + let blur_y = self.read_fixed16()?; + let angle = self.read_fixed16()?; + let distance = self.read_fixed16()?; + let strength = self.read_fixed8()?; + let flags = self.read_u8()?; + Filter::DropShadowFilter(Box::new(DropShadowFilter { + color, + blur_x, + blur_y, + angle, + distance, + strength, + is_inner: flags & 0b1000_0000 != 0, + is_knockout: flags & 0b0100_0000 != 0, + num_passes: flags & 0b0001_1111, + })) + } 1 => Filter::BlurFilter(Box::new(BlurFilter { blur_x: self.read_fixed16()?, blur_y: self.read_fixed16()?, - num_passes: self.read_ubits(5)? as u8, - })), - 2 => Filter::GlowFilter(Box::new(GlowFilter { - color: self.read_rgba()?, - blur_x: self.read_fixed16()?, - blur_y: self.read_fixed16()?, - strength: self.read_fixed8()?, - is_inner: self.read_bit()?, - is_knockout: self.read_bit()?, - num_passes: self.read_ubits(6)? as u8 & 0b011111, - })), - 3 => Filter::BevelFilter(Box::new(BevelFilter { - shadow_color: self.read_rgba()?, - highlight_color: self.read_rgba()?, - blur_x: self.read_fixed16()?, - blur_y: self.read_fixed16()?, - angle: self.read_fixed16()?, - distance: self.read_fixed16()?, - strength: self.read_fixed8()?, - is_inner: self.read_bit()?, - is_knockout: self.read_bit()?, - is_on_top: (self.read_ubits(2)? & 0b1) != 0, - num_passes: self.read_ubits(4)? as u8 & 0b011111, + num_passes: (self.read_u8()? & 0b1111_1000) >> 3, })), + 2 => { + let color = self.read_rgba()?; + let blur_x = self.read_fixed16()?; + let blur_y = self.read_fixed16()?; + let strength = self.read_fixed8()?; + let flags = self.read_u8()?; + Filter::GlowFilter(Box::new(GlowFilter { + color, + blur_x, + blur_y, + strength, + is_inner: flags & 0b1000_0000 != 0, + is_knockout: flags & 0b0100_0000 != 0, + num_passes: flags & 0b0001_1111, + })) + } + 3 => { + let shadow_color = self.read_rgba()?; + let highlight_color = self.read_rgba()?; + let blur_x = self.read_fixed16()?; + let blur_y = self.read_fixed16()?; + let angle = self.read_fixed16()?; + let distance = self.read_fixed16()?; + let strength = self.read_fixed8()?; + let flags = self.read_u8()?; + Filter::BevelFilter(Box::new(BevelFilter { + shadow_color, + highlight_color, + blur_x, + blur_y, + angle, + distance, + strength, + is_inner: flags & 0b1000_0000 != 0, + is_knockout: flags & 0b0100_0000 != 0, + is_on_top: flags & 0b0001_0000 != 0, + num_passes: flags & 0b0000_1111, + })) + } 4 => { let num_colors = self.read_u8()?; let mut colors = Vec::with_capacity(num_colors as usize); @@ -2424,17 +2500,23 @@ impl Reader { ratio: self.read_u8()?, }); } + let blur_x = self.read_fixed16()?; + let blur_y = self.read_fixed16()?; + let angle = self.read_fixed16()?; + let distance = self.read_fixed16()?; + let strength = self.read_fixed8()?; + let flags = self.read_u8()?; Filter::GradientGlowFilter(Box::new(GradientGlowFilter { colors: gradient_records, - blur_x: self.read_fixed16()?, - blur_y: self.read_fixed16()?, - angle: self.read_fixed16()?, - distance: self.read_fixed16()?, - strength: self.read_fixed8()?, - is_inner: self.read_bit()?, - is_knockout: self.read_bit()?, - is_on_top: (self.read_ubits(2)? & 0b1) != 0, - num_passes: self.read_ubits(4)? as u8, + blur_x, + blur_y, + angle, + distance, + strength, + is_inner: flags & 0b1000_0000 != 0, + is_knockout: flags & 0b0100_0000 != 0, + is_on_top: flags & 0b0001_0000 != 0, + num_passes: flags & 0b0000_1111, })) } 5 => { @@ -2480,22 +2562,27 @@ impl Reader { ratio: self.read_u8()?, }); } + let blur_x = self.read_fixed16()?; + let blur_y = self.read_fixed16()?; + let angle = self.read_fixed16()?; + let distance = self.read_fixed16()?; + let strength = self.read_fixed8()?; + let flags = self.read_u8()?; Filter::GradientBevelFilter(Box::new(GradientBevelFilter { colors: gradient_records, - blur_x: self.read_fixed16()?, - blur_y: self.read_fixed16()?, - angle: self.read_fixed16()?, - distance: self.read_fixed16()?, - strength: self.read_fixed8()?, - is_inner: self.read_bit()?, - is_knockout: self.read_bit()?, - is_on_top: (self.read_ubits(2)? & 0b1) != 0, - num_passes: self.read_ubits(4)? as u8 & 0b011111, + blur_x, + blur_y, + angle, + distance, + strength, + is_inner: flags & 0b1000_0000 != 0, + is_knockout: flags & 0b0100_0000 != 0, + is_on_top: flags & 0b0001_0000 != 0, + num_passes: flags & 0b0000_1111, })) } _ => return Err(Error::invalid_data("Invalid filter type")), }; - self.byte_align(); Ok(filter) } @@ -2647,10 +2734,11 @@ impl Reader { // TODO(Herschel): font_id and height are tied together. Merge them into a struct? let num_glyphs = self.read_u8()?; let mut glyphs = Vec::with_capacity(num_glyphs as usize); + let mut bits = self.bits(); for _ in 0..num_glyphs { glyphs.push(GlyphEntry { - index: self.read_ubits(num_glyph_bits as usize)?, - advance: self.read_sbits(num_advance_bits as usize)?, + index: bits.read_ubits(num_glyph_bits.into())?, + advance: bits.read_sbits(num_advance_bits.into())?, }); } @@ -2988,9 +3076,10 @@ pub mod tests { fn read_bit() { let mut buf: &[u8] = &[0b01010101, 0b00100101]; let mut reader = Reader::new(&mut buf, 1); + let mut bits = reader.bits(); assert_eq!( (0..16) - .map(|_| reader.read_bit().unwrap()) + .map(|_| bits.read_bit().unwrap()) .collect::>(), [ false, true, false, true, false, true, false, true, false, false, true, false, @@ -3003,9 +3092,10 @@ pub mod tests { fn read_ubits() { let mut buf: &[u8] = &[0b01010101, 0b00100101]; let mut reader = Reader::new(&mut buf, 1); + let mut bits = reader.bits(); assert_eq!( (0..8) - .map(|_| reader.read_ubits(2).unwrap()) + .map(|_| bits.read_ubits(2).unwrap()) .collect::>(), [1, 1, 1, 1, 0, 2, 1, 1] ); @@ -3015,9 +3105,10 @@ pub mod tests { fn read_sbits() { let mut buf: &[u8] = &[0b01010101, 0b00100101]; let mut reader = Reader::new(&mut buf, 1); + let mut bits = reader.bits(); assert_eq!( (0..8) - .map(|_| reader.read_sbits(2).unwrap()) + .map(|_| bits.read_sbits(2).unwrap()) .collect::>(), [1, 1, 1, 1, 0, -2, 1, 1] ); @@ -3025,15 +3116,17 @@ pub mod tests { #[test] fn read_fbits() { - assert_eq!(Reader::new(&[0][..], 1).read_fbits(5).unwrap(), 0f32); + assert_eq!(Reader::new(&[0][..], 1).bits().read_fbits(5).unwrap(), 0f32); assert_eq!( Reader::new(&[0b01000000, 0b00000000, 0b0_0000000][..], 1) + .bits() .read_fbits(17) .unwrap(), 0.5f32 ); assert_eq!( Reader::new(&[0b10000000, 0b00000000][..], 1) + .bits() .read_fbits(16) .unwrap(), -0.5f32 @@ -3253,7 +3346,19 @@ pub mod tests { #[test] fn read_shape_record() { - let read = |buf: &[u8]| reader(buf).read_shape_record(2).unwrap().unwrap(); + let read = |buf: &[u8]| { + let mut reader = reader(buf); + let mut context = ShapeContext { + swf_version: reader.version, + shape_version: 2, + num_fill_bits: 1, + num_line_bits: 1, + }; + let mut bits = reader.bits(); + Reader::read_shape_record(&mut bits, &mut context) + .unwrap() + .unwrap() + }; let shape_record = ShapeRecord::StraightEdge { delta_x: Twips::from_pixels(1.0), diff --git a/swf/src/types.rs b/swf/src/types.rs index 3f36722e1..60041c0f4 100644 --- a/swf/src/types.rs +++ b/swf/src/types.rs @@ -583,6 +583,14 @@ pub struct SymbolClassLink { pub class_name: String, } +#[derive(Debug, PartialEq, Clone)] +pub struct ShapeContext { + pub swf_version: u8, + pub shape_version: u8, + pub num_fill_bits: u8, + pub num_line_bits: u8, +} + #[derive(Debug, PartialEq, Clone)] pub struct Shape { pub version: u8, diff --git a/swf/src/write.rs b/swf/src/write.rs index ab73c7272..4a6489122 100644 --- a/swf/src/write.rs +++ b/swf/src/write.rs @@ -189,98 +189,60 @@ pub trait SwfWrite { self.get_inner().write_all(s.as_bytes())?; self.write_u8(0) } -} -struct Writer { - pub output: W, - pub version: u8, - pub byte: u8, - pub bit_index: u8, - pub num_fill_bits: u8, - pub num_line_bits: u8, -} - -impl SwfWrite for Writer { - fn get_inner(&mut self) -> &mut W { - &mut self.output - } - - fn write_u8(&mut self, n: u8) -> io::Result<()> { - self.flush_bits()?; - self.output.write_u8(n) - } - - fn write_u16(&mut self, n: u16) -> io::Result<()> { - self.flush_bits()?; - self.output.write_u16::(n) - } - - fn write_u32(&mut self, n: u32) -> io::Result<()> { - self.flush_bits()?; - self.output.write_u32::(n) - } - - fn write_i8(&mut self, n: i8) -> io::Result<()> { - self.flush_bits()?; - self.output.write_i8(n) - } - - fn write_i16(&mut self, n: i16) -> io::Result<()> { - self.flush_bits()?; - self.output.write_i16::(n) - } - - fn write_i32(&mut self, n: i32) -> io::Result<()> { - self.flush_bits()?; - self.output.write_i32::(n) - } - - fn write_f32(&mut self, n: f32) -> io::Result<()> { - self.flush_bits()?; - self.output.write_f32::(n) - } - - fn write_f64(&mut self, n: f64) -> io::Result<()> { - self.flush_bits()?; - self.output.write_f64::(n) - } - - fn write_c_string(&mut self, s: &str) -> io::Result<()> { - self.flush_bits()?; - self.get_inner().write_all(s.as_bytes())?; - self.write_u8(0) - } -} - -impl Writer { - fn new(output: W, version: u8) -> Writer { - Writer { - output, - version, + fn bits(&mut self) -> BitWriter<&mut W> { + BitWriter { + output: self.get_inner(), byte: 0, bit_index: 8, - num_fill_bits: 0, - num_line_bits: 0, } } +} - #[allow(dead_code)] - fn into_inner(self) -> W { - self.output - } +pub struct BitWriter { + output: W, + pub byte: u8, + pub bit_index: u8, +} - fn write_bit(&mut self, set: bool) -> Result<()> { +impl BitWriter { + #[inline] + fn write_bit(&mut self, bit: bool) -> io::Result<()> { self.bit_index -= 1; - if set { + if bit { self.byte |= 1 << self.bit_index; } if self.bit_index == 0 { - self.flush_bits()?; + self.flush()?; } Ok(()) } - fn flush_bits(&mut self) -> io::Result<()> { + #[inline] + fn write_ubits(&mut self, num_bits: u32, n: u32) -> io::Result<()> { + for i in 0..num_bits { + self.write_bit(n & (1 << u32::from(num_bits - i - 1)) != 0)?; + } + Ok(()) + } + + #[inline] + fn write_sbits(&mut self, num_bits: u32, n: i32) -> io::Result<()> { + self.write_ubits(num_bits, n as u32) + } + + #[inline] + fn write_sbits_twips(&mut self, num_bits: u32, twips: Twips) -> io::Result<()> { + self.write_sbits(num_bits, twips.get()) + } + + #[inline] + fn write_fbits(&mut self, num_bits: u32, n: f32) -> io::Result<()> { + self.write_sbits(num_bits, (n * 65536f32) as i32) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { if self.bit_index != 8 { self.output.write_u8(self.byte)?; self.bit_index = 8; @@ -289,23 +251,75 @@ impl Writer { Ok(()) } - fn write_ubits(&mut self, num_bits: u8, n: u32) -> Result<()> { - for i in 0..num_bits { - self.write_bit(n & (1 << u32::from(num_bits - i - 1)) != 0)?; - } - Ok(()) + #[inline] + fn writer(&mut self) -> &mut W { + &mut self.output + } +} + +impl Drop for BitWriter { + #[inline] + fn drop(&mut self) { + let _ = self.flush(); + } +} + +struct Writer { + pub output: W, + pub version: u8, +} + +impl SwfWrite for Writer { + fn get_inner(&mut self) -> &mut W { + &mut self.output } - fn write_sbits(&mut self, num_bits: u8, n: i32) -> Result<()> { - self.write_ubits(num_bits, n as u32) + fn write_u8(&mut self, n: u8) -> io::Result<()> { + self.output.write_u8(n) } - fn write_sbits_twips(&mut self, num_bits: u8, twips: Twips) -> Result<()> { - self.write_sbits(num_bits, twips.get()) + fn write_u16(&mut self, n: u16) -> io::Result<()> { + self.output.write_u16::(n) } - fn write_fbits(&mut self, num_bits: u8, n: f32) -> Result<()> { - self.write_sbits(num_bits, (n * 65536f32) as i32) + fn write_u32(&mut self, n: u32) -> io::Result<()> { + self.output.write_u32::(n) + } + + fn write_i8(&mut self, n: i8) -> io::Result<()> { + self.output.write_i8(n) + } + + fn write_i16(&mut self, n: i16) -> io::Result<()> { + self.output.write_i16::(n) + } + + fn write_i32(&mut self, n: i32) -> io::Result<()> { + self.output.write_i32::(n) + } + + fn write_f32(&mut self, n: f32) -> io::Result<()> { + self.output.write_f32::(n) + } + + fn write_f64(&mut self, n: f64) -> io::Result<()> { + self.output.write_f64::(n) + } + + fn write_c_string(&mut self, s: &str) -> io::Result<()> { + self.get_inner().write_all(s.as_bytes())?; + self.write_u8(0) + } +} + +impl Writer { + fn new(output: W, version: u8) -> Writer { + Writer { output, version } + } + + #[allow(dead_code)] + fn into_inner(self) -> W { + self.output } fn write_encoded_u32(&mut self, mut n: u32) -> Result<()> { @@ -324,8 +338,7 @@ impl Writer { } fn write_rectangle(&mut self, rectangle: &Rectangle) -> Result<()> { - self.flush_bits()?; - let num_bits: u8 = [ + let num_bits = [ rectangle.x_min, rectangle.x_max, rectangle.y_min, @@ -335,11 +348,12 @@ impl Writer { .map(|x| count_sbits_twips(*x)) .max() .unwrap(); - self.write_ubits(5, num_bits.into())?; - self.write_sbits_twips(num_bits, rectangle.x_min)?; - self.write_sbits_twips(num_bits, rectangle.x_max)?; - self.write_sbits_twips(num_bits, rectangle.y_min)?; - self.write_sbits_twips(num_bits, rectangle.y_max)?; + let mut bits = self.bits(); + bits.write_ubits(5, num_bits.into())?; + bits.write_sbits_twips(num_bits, rectangle.x_min)?; + bits.write_sbits_twips(num_bits, rectangle.x_max)?; + bits.write_sbits_twips(num_bits, rectangle.y_min)?; + bits.write_sbits_twips(num_bits, rectangle.y_max)?; Ok(()) } @@ -365,7 +379,6 @@ impl Writer { fn write_color_transform_no_alpha(&mut self, color_transform: &ColorTransform) -> Result<()> { // TODO: Assert that alpha is 1.0? - self.flush_bits()?; let has_mult = color_transform.r_multiply != 1f32 || color_transform.g_multiply != 1f32 || color_transform.b_multiply != 1f32; @@ -382,8 +395,9 @@ impl Writer { color_transform.b_add, color_transform.a_add, ]; - self.write_bit(has_mult)?; - self.write_bit(has_add)?; + let mut bits = self.bits(); + bits.write_bit(has_mult)?; + bits.write_bit(has_add)?; let mut num_bits = if has_mult { multiply .iter() @@ -391,7 +405,7 @@ impl Writer { .max() .unwrap() } else { - 0u8 + 0 }; if has_add { num_bits = max( @@ -402,22 +416,21 @@ impl Writer { .unwrap(), ); } - self.write_ubits(4, num_bits.into())?; + bits.write_ubits(4, num_bits.into())?; if has_mult { - self.write_sbits(num_bits, (color_transform.r_multiply * 256f32) as i32)?; - self.write_sbits(num_bits, (color_transform.g_multiply * 256f32) as i32)?; - self.write_sbits(num_bits, (color_transform.b_multiply * 256f32) as i32)?; + bits.write_sbits(num_bits, (color_transform.r_multiply * 256f32) as i32)?; + bits.write_sbits(num_bits, (color_transform.g_multiply * 256f32) as i32)?; + bits.write_sbits(num_bits, (color_transform.b_multiply * 256f32) as i32)?; } if has_add { - self.write_sbits(num_bits, color_transform.r_add.into())?; - self.write_sbits(num_bits, color_transform.g_add.into())?; - self.write_sbits(num_bits, color_transform.b_add.into())?; + bits.write_sbits(num_bits, color_transform.r_add.into())?; + bits.write_sbits(num_bits, color_transform.g_add.into())?; + bits.write_sbits(num_bits, color_transform.b_add.into())?; } Ok(()) } fn write_color_transform(&mut self, color_transform: &ColorTransform) -> Result<()> { - self.flush_bits()?; let has_mult = color_transform.r_multiply != 1f32 || color_transform.g_multiply != 1f32 || color_transform.b_multiply != 1f32 @@ -438,8 +451,9 @@ impl Writer { color_transform.b_add, color_transform.a_add, ]; - self.write_bit(has_add)?; - self.write_bit(has_mult)?; + let mut bits = self.bits(); + bits.write_bit(has_add)?; + bits.write_bit(has_mult)?; let mut num_bits = if has_mult { multiply .iter() @@ -447,7 +461,7 @@ impl Writer { .max() .unwrap() } else { - 0u8 + 0 }; if has_add { num_bits = max( @@ -458,48 +472,47 @@ impl Writer { .unwrap(), ); } - self.write_ubits(4, num_bits.into())?; + bits.write_ubits(4, num_bits.into())?; if has_mult { - self.write_sbits(num_bits, (color_transform.r_multiply * 256f32) as i32)?; - self.write_sbits(num_bits, (color_transform.g_multiply * 256f32) as i32)?; - self.write_sbits(num_bits, (color_transform.b_multiply * 256f32) as i32)?; - self.write_sbits(num_bits, (color_transform.a_multiply * 256f32) as i32)?; + bits.write_sbits(num_bits, (color_transform.r_multiply * 256f32) as i32)?; + bits.write_sbits(num_bits, (color_transform.g_multiply * 256f32) as i32)?; + bits.write_sbits(num_bits, (color_transform.b_multiply * 256f32) as i32)?; + bits.write_sbits(num_bits, (color_transform.a_multiply * 256f32) as i32)?; } if has_add { - self.write_sbits(num_bits, color_transform.r_add.into())?; - self.write_sbits(num_bits, color_transform.g_add.into())?; - self.write_sbits(num_bits, color_transform.b_add.into())?; - self.write_sbits(num_bits, color_transform.a_add.into())?; + bits.write_sbits(num_bits, color_transform.r_add.into())?; + bits.write_sbits(num_bits, color_transform.g_add.into())?; + bits.write_sbits(num_bits, color_transform.b_add.into())?; + bits.write_sbits(num_bits, color_transform.a_add.into())?; } Ok(()) } fn write_matrix(&mut self, m: &Matrix) -> Result<()> { - self.flush_bits()?; + let mut bits = self.bits(); // Scale let has_scale = m.a != 1f32 || m.d != 1f32; - self.write_bit(has_scale)?; + bits.write_bit(has_scale)?; if has_scale { let num_bits = max(count_fbits(m.a), count_fbits(m.d)); - self.write_ubits(5, num_bits.into())?; - self.write_fbits(num_bits, m.a)?; - self.write_fbits(num_bits, m.d)?; + bits.write_ubits(5, num_bits.into())?; + bits.write_fbits(num_bits, m.a)?; + bits.write_fbits(num_bits, m.d)?; } // Rotate/Skew let has_rotate_skew = m.b != 0f32 || m.c != 0f32; - self.write_bit(has_rotate_skew)?; + bits.write_bit(has_rotate_skew)?; if has_rotate_skew { let num_bits = max(count_fbits(m.b), count_fbits(m.c)); - self.write_ubits(5, num_bits.into())?; - self.write_fbits(num_bits, m.b)?; - self.write_fbits(num_bits, m.c)?; + bits.write_ubits(5, num_bits.into())?; + bits.write_fbits(num_bits, m.b)?; + bits.write_fbits(num_bits, m.c)?; } // Translate (always written) let num_bits = max(count_sbits_twips(m.tx), count_sbits_twips(m.ty)); - self.write_ubits(5, num_bits.into())?; - self.write_sbits_twips(num_bits, m.tx)?; - self.write_sbits_twips(num_bits, m.ty)?; - self.flush_bits()?; + bits.write_ubits(5, num_bits.into())?; + bits.write_sbits_twips(num_bits, m.tx)?; + bits.write_sbits_twips(num_bits, m.ty)?; Ok(()) } @@ -622,7 +635,6 @@ impl Writer { writer.write_character_id(button_color.id)?; for color_transform in &button_color.color_transforms { writer.write_color_transform_no_alpha(color_transform)?; - writer.flush_bits()?; } } self.write_tag_header(TagCode::DefineButtonCxform, buf.len() as u32)?; @@ -677,17 +689,20 @@ impl Writer { // Bit length for fill and line indices. // TODO: This theoretically could be >1? - writer.num_fill_bits = 1; - writer.num_line_bits = 0; - writer.write_ubits(4, 1)?; - writer.write_ubits(4, 0)?; + let mut shape_context = ShapeContext { + swf_version: self.version, + shape_version: 1, + num_fill_bits: 1, + num_line_bits: 0, + }; + writer.write_u8(0b0001_0000)?; + let mut bits = writer.bits(); for shape_record in glyph { - writer.write_shape_record(shape_record, 1)?; + Self::write_shape_record(shape_record, &mut bits, &mut shape_context)?; } // End shape record. - writer.write_ubits(6, 0)?; - writer.flush_bits()?; + bits.write_ubits(6, 0)?; } } @@ -790,7 +805,6 @@ impl Writer { let mut writer = Writer::new(&mut buf, self.version); writer.write_u16(id)?; writer.write_rectangle(splitter_rect)?; - writer.flush_bits()?; } self.write_tag_header(TagCode::DefineScalingGrid, buf.len() as u32)?; self.output.write_all(&buf)?; @@ -1183,8 +1197,8 @@ impl Writer { let num_fill_styles = data.start.fill_styles.len(); let num_line_styles = data.start.line_styles.len(); - let num_fill_bits = count_ubits(num_fill_styles as u32); - let num_line_bits = count_ubits(num_line_styles as u32); + let num_fill_bits = count_ubits(num_fill_styles as u32) as u8; + let num_line_bits = count_ubits(num_line_styles as u32) as u8; // Need to write styles first, to calculate offset to EndEdges. let mut start_buf = Vec::new(); @@ -1224,16 +1238,20 @@ impl Writer { } // TODO(Herschel): Make fn write_shape. - writer.write_ubits(4, num_fill_bits.into())?; - writer.write_ubits(4, num_line_bits.into())?; - writer.num_fill_bits = num_fill_bits; - writer.num_line_bits = num_line_bits; + writer.write_u8((num_fill_bits << 4) | (num_line_bits & 0b1111))?; + + let mut shape_context = ShapeContext { + swf_version: self.version, + shape_version: 1, + num_fill_bits, + num_line_bits, + }; + let mut bits = writer.bits(); for shape_record in &data.start.shape { - writer.write_shape_record(shape_record, 1)?; + Self::write_shape_record(shape_record, &mut bits, &mut shape_context)?; } // End shape record. - writer.write_ubits(6, 0)?; - writer.flush_bits()?; + bits.write_ubits(6, 0)?; } let mut buf = Vec::new(); @@ -1261,14 +1279,18 @@ impl Writer { // EndEdges. writer.write_u8(0)?; // NumFillBits and NumLineBits are written as 0 for the end shape. - writer.num_fill_bits = num_fill_bits; - writer.num_line_bits = num_line_bits; + let mut shape_context = ShapeContext { + swf_version: self.version, + shape_version: 1, + num_fill_bits, + num_line_bits, + }; + let mut bits = writer.bits(); for shape_record in &data.end.shape { - writer.write_shape_record(shape_record, 1)?; + Self::write_shape_record(shape_record, &mut bits, &mut shape_context)?; } // End shape record. - writer.write_ubits(6, 0)?; - writer.flush_bits()?; + bits.write_ubits(6, 0)?; } let tag_code = if data.version == 1 { @@ -1419,7 +1441,8 @@ impl Writer { self.write_u16(end.width.get() as u16)?; // MorphLineStyle2 - self.write_ubits( + let mut bits = self.bits(); + bits.write_ubits( 2, match start.start_cap { LineCapStyle::Round => 0, @@ -1427,7 +1450,7 @@ impl Writer { LineCapStyle::Square => 2, }, )?; - self.write_ubits( + bits.write_ubits( 2, match start.join_style { LineJoinStyle::Round => 0, @@ -1435,13 +1458,13 @@ impl Writer { LineJoinStyle::Miter(_) => 2, }, )?; - self.write_bit(start.fill_style.is_some())?; - self.write_bit(!start.allow_scale_x)?; - self.write_bit(!start.allow_scale_y)?; - self.write_bit(start.is_pixel_hinted)?; - self.write_ubits(5, 0)?; - self.write_bit(!start.allow_close)?; - self.write_ubits( + bits.write_bit(start.fill_style.is_some())?; + bits.write_bit(!start.allow_scale_x)?; + bits.write_bit(!start.allow_scale_y)?; + bits.write_bit(start.is_pixel_hinted)?; + bits.write_ubits(5, 0)?; + bits.write_bit(!start.allow_close)?; + bits.write_ubits( 2, match start.end_cap { LineCapStyle::Round => 0, @@ -1449,6 +1472,7 @@ impl Writer { LineCapStyle::Square => 2, }, )?; + drop(bits); if let LineJoinStyle::Miter(miter_factor) = start.join_style { self.write_fixed8(miter_factor)?; } @@ -1503,7 +1527,6 @@ impl Writer { writer.write_rectangle(&shape.shape_bounds)?; if shape.version >= 4 { writer.write_rectangle(&shape.edge_bounds)?; - writer.flush_bits()?; writer.write_u8( if shape.has_fill_winding_rule { 0b100 @@ -1517,14 +1540,20 @@ impl Writer { )?; } - writer.write_shape_styles(&shape.styles, shape.version)?; - + let (num_fill_bits, num_line_bits) = + writer.write_shape_styles(&shape.styles, shape.version)?; + let mut shape_context = ShapeContext { + swf_version: self.version, + shape_version: shape.version, + num_fill_bits, + num_line_bits, + }; + let mut bits = writer.bits(); for shape_record in &shape.shape { - writer.write_shape_record(shape_record, shape.version)?; + Self::write_shape_record(shape_record, &mut bits, &mut shape_context)?; } // End shape record. - writer.write_ubits(6, 0)?; - writer.flush_bits()?; + bits.write_ubits(6, 0)?; } let tag_code = match shape.version { @@ -1640,7 +1669,7 @@ impl Writer { Ok(()) } - fn write_shape_styles(&mut self, styles: &ShapeStyles, shape_version: u8) -> Result<()> { + fn write_shape_styles(&mut self, styles: &ShapeStyles, shape_version: u8) -> Result<(u8, u8)> { // TODO: Check shape_version. if styles.fill_styles.len() >= 0xff { self.write_u8(0xff)?; @@ -1662,33 +1691,35 @@ impl Writer { self.write_line_style(line_style, shape_version)?; } - let num_fill_bits = count_ubits(styles.fill_styles.len() as u32); - let num_line_bits = count_ubits(styles.line_styles.len() as u32); - self.write_ubits(4, num_fill_bits.into())?; - self.write_ubits(4, num_line_bits.into())?; - self.num_fill_bits = num_fill_bits; - self.num_line_bits = num_line_bits; - Ok(()) + let num_fill_bits = count_ubits(styles.fill_styles.len() as u32) as u8; + let num_line_bits = count_ubits(styles.line_styles.len() as u32) as u8; + self.write_u8((num_fill_bits << 4) | (num_line_bits & 0b1111))?; + + Ok((num_fill_bits, num_line_bits)) } - fn write_shape_record(&mut self, record: &ShapeRecord, shape_version: u8) -> Result<()> { + fn write_shape_record( + record: &ShapeRecord, + bits: &mut BitWriter, + context: &mut ShapeContext, + ) -> Result<()> { match *record { ShapeRecord::StraightEdge { delta_x, delta_y } => { - self.write_ubits(2, 0b11)?; // Straight edge + bits.write_ubits(2, 0b11)?; // Straight edge // TODO: Check underflow? let mut num_bits = max(count_sbits_twips(delta_x), count_sbits_twips(delta_y)); num_bits = max(2, num_bits); let is_axis_aligned = delta_x.get() == 0 || delta_y.get() == 0; - self.write_ubits(4, u32::from(num_bits) - 2)?; - self.write_bit(!is_axis_aligned)?; + bits.write_ubits(4, u32::from(num_bits) - 2)?; + bits.write_bit(!is_axis_aligned)?; if is_axis_aligned { - self.write_bit(delta_x.get() == 0)?; + bits.write_bit(delta_x.get() == 0)?; } if delta_x.get() != 0 { - self.write_sbits_twips(num_bits, delta_x)?; + bits.write_sbits_twips(num_bits, delta_x)?; } if delta_y.get() != 0 { - self.write_sbits_twips(num_bits, delta_y)?; + bits.write_sbits_twips(num_bits, delta_y)?; } } ShapeRecord::CurvedEdge { @@ -1697,7 +1728,7 @@ impl Writer { anchor_delta_x, anchor_delta_y, } => { - self.write_ubits(2, 0b10)?; // Curved edge + bits.write_ubits(2, 0b10)?; // Curved edge let num_bits = [ control_delta_x, control_delta_y, @@ -1708,43 +1739,48 @@ impl Writer { .map(|x| count_sbits_twips(*x)) .max() .unwrap(); - self.write_ubits(4, u32::from(num_bits) - 2)?; - self.write_sbits_twips(num_bits, control_delta_x)?; - self.write_sbits_twips(num_bits, control_delta_y)?; - self.write_sbits_twips(num_bits, anchor_delta_x)?; - self.write_sbits_twips(num_bits, anchor_delta_y)?; + bits.write_ubits(4, u32::from(num_bits) - 2)?; + bits.write_sbits_twips(num_bits, control_delta_x)?; + bits.write_sbits_twips(num_bits, control_delta_y)?; + bits.write_sbits_twips(num_bits, anchor_delta_x)?; + bits.write_sbits_twips(num_bits, anchor_delta_y)?; } ShapeRecord::StyleChange(ref style_change) => { - self.write_bit(false)?; // Style change - let num_fill_bits = self.num_fill_bits; - let num_line_bits = self.num_line_bits; - self.write_bit(style_change.new_styles.is_some())?; - self.write_bit(style_change.line_style.is_some())?; - self.write_bit(style_change.fill_style_1.is_some())?; - self.write_bit(style_change.fill_style_0.is_some())?; - self.write_bit(style_change.move_to.is_some())?; + bits.write_bit(false)?; // Style change + let num_fill_bits = context.num_fill_bits.into(); + let num_line_bits = context.num_line_bits.into(); + bits.write_bit(style_change.new_styles.is_some())?; + bits.write_bit(style_change.line_style.is_some())?; + bits.write_bit(style_change.fill_style_1.is_some())?; + bits.write_bit(style_change.fill_style_0.is_some())?; + bits.write_bit(style_change.move_to.is_some())?; if let Some((move_x, move_y)) = style_change.move_to { let num_bits = max(count_sbits_twips(move_x), count_sbits_twips(move_y)); - self.write_ubits(5, num_bits.into())?; - self.write_sbits_twips(num_bits, move_x)?; - self.write_sbits_twips(num_bits, move_y)?; + bits.write_ubits(5, num_bits.into())?; + bits.write_sbits_twips(num_bits, move_x)?; + bits.write_sbits_twips(num_bits, move_y)?; } if let Some(fill_style_index) = style_change.fill_style_0 { - self.write_ubits(num_fill_bits, fill_style_index)?; + bits.write_ubits(num_fill_bits, fill_style_index)?; } if let Some(fill_style_index) = style_change.fill_style_1 { - self.write_ubits(num_fill_bits, fill_style_index)?; + bits.write_ubits(num_fill_bits, fill_style_index)?; } if let Some(line_style_index) = style_change.line_style { - self.write_ubits(num_line_bits, line_style_index)?; + bits.write_ubits(num_line_bits, line_style_index)?; } if let Some(ref new_styles) = style_change.new_styles { - if shape_version < 2 { + if context.shape_version < 2 { return Err(Error::invalid_data( "Only DefineShape2 and higher may change styles.", )); } - self.write_shape_styles(new_styles, shape_version)?; + bits.flush()?; + let mut writer = Writer::new(bits.writer(), context.swf_version); + let (num_fill_bits, num_line_bits) = + writer.write_shape_styles(new_styles, context.shape_version)?; + context.num_fill_bits = num_fill_bits; + context.num_line_bits = num_line_bits; } } } @@ -1814,8 +1850,9 @@ impl Writer { // TODO(Herschel): Handle overflow. self.write_u16(line_style.width.get() as u16)?; if shape_version >= 4 { + let mut bits = self.bits(); // LineStyle2 - self.write_ubits( + bits.write_ubits( 2, match line_style.start_cap { LineCapStyle::Round => 0, @@ -1823,7 +1860,7 @@ impl Writer { LineCapStyle::Square => 2, }, )?; - self.write_ubits( + bits.write_ubits( 2, match line_style.join_style { LineJoinStyle::Round => 0, @@ -1831,13 +1868,13 @@ impl Writer { LineJoinStyle::Miter(_) => 2, }, )?; - self.write_bit(line_style.fill_style.is_some())?; - self.write_bit(!line_style.allow_scale_x)?; - self.write_bit(!line_style.allow_scale_y)?; - self.write_bit(line_style.is_pixel_hinted)?; - self.write_ubits(5, 0)?; - self.write_bit(!line_style.allow_close)?; - self.write_ubits( + bits.write_bit(line_style.fill_style.is_some())?; + bits.write_bit(!line_style.allow_scale_x)?; + bits.write_bit(!line_style.allow_scale_y)?; + bits.write_bit(line_style.is_pixel_hinted)?; + bits.write_ubits(5, 0)?; + bits.write_bit(!line_style.allow_close)?; + bits.write_ubits( 2, match line_style.end_cap { LineCapStyle::Round => 0, @@ -1845,6 +1882,7 @@ impl Writer { LineCapStyle::Square => 2, }, )?; + drop(bits); if let LineJoinStyle::Miter(miter_factor) = line_style.join_style { self.write_fixed8(miter_factor)?; } @@ -1864,7 +1902,6 @@ impl Writer { fn write_gradient(&mut self, gradient: &Gradient, shape_version: u8) -> Result<()> { self.write_matrix(&gradient.matrix)?; - self.flush_bits()?; self.write_gradient_flags(gradient)?; for record in &gradient.records { self.write_u8(record.ratio)?; @@ -2052,7 +2089,6 @@ impl Writer { if let Some(clip_actions) = &place_object.clip_actions { writer.write_clip_actions(clip_actions)?; } - writer.flush_bits()?; // PlaceObject4 adds some embedded AMF data per instance. if place_object_version >= 4 { @@ -2082,10 +2118,11 @@ impl Writer { self.write_fixed16(drop_shadow.angle)?; self.write_fixed16(drop_shadow.distance)?; self.write_fixed8(drop_shadow.strength)?; - self.write_bit(drop_shadow.is_inner)?; - self.write_bit(drop_shadow.is_knockout)?; - self.write_bit(true)?; - self.write_ubits(5, drop_shadow.num_passes.into())?; + let mut bits = self.bits(); + bits.write_bit(drop_shadow.is_inner)?; + bits.write_bit(drop_shadow.is_knockout)?; + bits.write_bit(true)?; + bits.write_ubits(5, drop_shadow.num_passes.into())?; } Filter::BlurFilter(ref blur) => { @@ -2101,10 +2138,11 @@ impl Writer { self.write_fixed16(glow.blur_x)?; self.write_fixed16(glow.blur_y)?; self.write_fixed8(glow.strength)?; - self.write_bit(glow.is_inner)?; - self.write_bit(glow.is_knockout)?; - self.write_bit(true)?; - self.write_ubits(5, glow.num_passes.into())?; + let mut bits = self.bits(); + bits.write_bit(glow.is_inner)?; + bits.write_bit(glow.is_knockout)?; + bits.write_bit(true)?; + bits.write_ubits(5, glow.num_passes.into())?; } Filter::BevelFilter(ref bevel) => { @@ -2116,11 +2154,12 @@ impl Writer { self.write_fixed16(bevel.angle)?; self.write_fixed16(bevel.distance)?; self.write_fixed8(bevel.strength)?; - self.write_bit(bevel.is_inner)?; - self.write_bit(bevel.is_knockout)?; - self.write_bit(true)?; - self.write_bit(bevel.is_on_top)?; - self.write_ubits(4, bevel.num_passes.into())?; + let mut bits = self.bits(); + bits.write_bit(bevel.is_inner)?; + bits.write_bit(bevel.is_knockout)?; + bits.write_bit(true)?; + bits.write_bit(bevel.is_on_top)?; + bits.write_ubits(4, bevel.num_passes.into())?; } Filter::GradientGlowFilter(ref glow) => { @@ -2137,11 +2176,12 @@ impl Writer { self.write_fixed16(glow.angle)?; self.write_fixed16(glow.distance)?; self.write_fixed8(glow.strength)?; - self.write_bit(glow.is_inner)?; - self.write_bit(glow.is_knockout)?; - self.write_bit(true)?; - self.write_bit(glow.is_on_top)?; - self.write_ubits(4, glow.num_passes.into())?; + let mut bits = self.bits(); + bits.write_bit(glow.is_inner)?; + bits.write_bit(glow.is_knockout)?; + bits.write_bit(true)?; + bits.write_bit(glow.is_on_top)?; + bits.write_ubits(4, glow.num_passes.into())?; } Filter::ConvolutionFilter(ref convolve) => { @@ -2181,14 +2221,14 @@ impl Writer { self.write_fixed16(bevel.angle)?; self.write_fixed16(bevel.distance)?; self.write_fixed8(bevel.strength)?; - self.write_bit(bevel.is_inner)?; - self.write_bit(bevel.is_knockout)?; - self.write_bit(true)?; - self.write_bit(bevel.is_on_top)?; - self.write_ubits(4, bevel.num_passes.into())?; + let mut bits = self.bits(); + bits.write_bit(bevel.is_inner)?; + bits.write_bit(bevel.is_knockout)?; + bits.write_bit(true)?; + bits.write_bit(bevel.is_on_top)?; + bits.write_ubits(4, bevel.num_passes.into())?; } } - self.flush_bits()?; Ok(()) } @@ -2221,30 +2261,31 @@ impl Writer { fn write_clip_event_flags(&mut self, clip_events: EnumSet) -> Result<()> { // TODO: Assert proper version. - self.write_bit(clip_events.contains(ClipEventFlag::KeyUp))?; - self.write_bit(clip_events.contains(ClipEventFlag::KeyDown))?; - self.write_bit(clip_events.contains(ClipEventFlag::MouseUp))?; - self.write_bit(clip_events.contains(ClipEventFlag::MouseDown))?; - self.write_bit(clip_events.contains(ClipEventFlag::MouseMove))?; - self.write_bit(clip_events.contains(ClipEventFlag::Unload))?; - self.write_bit(clip_events.contains(ClipEventFlag::EnterFrame))?; - self.write_bit(clip_events.contains(ClipEventFlag::Load))?; - self.write_bit(clip_events.contains(ClipEventFlag::DragOver))?; - self.write_bit(clip_events.contains(ClipEventFlag::RollOut))?; - self.write_bit(clip_events.contains(ClipEventFlag::RollOver))?; - self.write_bit(clip_events.contains(ClipEventFlag::ReleaseOutside))?; - self.write_bit(clip_events.contains(ClipEventFlag::Release))?; - self.write_bit(clip_events.contains(ClipEventFlag::Press))?; - self.write_bit(clip_events.contains(ClipEventFlag::Initialize))?; - self.write_bit(clip_events.contains(ClipEventFlag::Data))?; - if self.version >= 6 { - self.write_ubits(5, 0)?; - self.write_bit(clip_events.contains(ClipEventFlag::Construct))?; - self.write_bit(clip_events.contains(ClipEventFlag::KeyPress))?; - self.write_bit(clip_events.contains(ClipEventFlag::DragOut))?; - self.write_u8(0)?; + let version = self.version; + let mut bits = self.bits(); + bits.write_bit(clip_events.contains(ClipEventFlag::KeyUp))?; + bits.write_bit(clip_events.contains(ClipEventFlag::KeyDown))?; + bits.write_bit(clip_events.contains(ClipEventFlag::MouseUp))?; + bits.write_bit(clip_events.contains(ClipEventFlag::MouseDown))?; + bits.write_bit(clip_events.contains(ClipEventFlag::MouseMove))?; + bits.write_bit(clip_events.contains(ClipEventFlag::Unload))?; + bits.write_bit(clip_events.contains(ClipEventFlag::EnterFrame))?; + bits.write_bit(clip_events.contains(ClipEventFlag::Load))?; + bits.write_bit(clip_events.contains(ClipEventFlag::DragOver))?; + bits.write_bit(clip_events.contains(ClipEventFlag::RollOut))?; + bits.write_bit(clip_events.contains(ClipEventFlag::RollOver))?; + bits.write_bit(clip_events.contains(ClipEventFlag::ReleaseOutside))?; + bits.write_bit(clip_events.contains(ClipEventFlag::Release))?; + bits.write_bit(clip_events.contains(ClipEventFlag::Press))?; + bits.write_bit(clip_events.contains(ClipEventFlag::Initialize))?; + bits.write_bit(clip_events.contains(ClipEventFlag::Data))?; + if version >= 6 { + bits.write_ubits(5, 0)?; + bits.write_bit(clip_events.contains(ClipEventFlag::Construct))?; + bits.write_bit(clip_events.contains(ClipEventFlag::KeyPress))?; + bits.write_bit(clip_events.contains(ClipEventFlag::DragOut))?; + bits.write_ubits(8, 0)?; } - self.flush_bits()?; Ok(()) } @@ -2275,7 +2316,8 @@ impl Writer { } fn write_sound_format(&mut self, sound_format: &SoundFormat) -> Result<()> { - self.write_ubits( + let mut bits = self.bits(); + bits.write_ubits( 4, match sound_format.compression { AudioCompression::UncompressedUnknownEndian => 0, @@ -2288,7 +2330,7 @@ impl Writer { AudioCompression::Speex => 11, }, )?; - self.write_ubits( + bits.write_ubits( 2, match sound_format.sample_rate { 5512 => 0, @@ -2298,9 +2340,8 @@ impl Writer { _ => return Err(Error::invalid_data("Invalid sample rate.")), }, )?; - self.write_bit(sound_format.is_16_bit)?; - self.write_bit(sound_format.is_stereo)?; - self.flush_bits()?; + bits.write_bit(sound_format.is_16_bit)?; + bits.write_bit(sound_format.is_stereo)?; Ok(()) } @@ -2359,8 +2400,12 @@ impl Writer { let mut shape_writer = Writer::new(&mut shape_buf, self.version); // ShapeTable - shape_writer.num_fill_bits = 1; - shape_writer.num_line_bits = 0; + let mut shape_context = ShapeContext { + swf_version: self.version, + shape_version: 1, + num_fill_bits: 1, + num_line_bits: 0, + }; for glyph in &font.glyphs { // Store offset for later. let offset = num_glyphs * 4 + shape_writer.output.len(); @@ -2369,15 +2414,13 @@ impl Writer { has_wide_offsets = true; } - shape_writer.write_ubits(4, 1)?; - shape_writer.write_ubits(4, 0)?; - + shape_writer.write_u8(0b0001_0000)?; + let mut bits = shape_writer.bits(); for shape_record in &glyph.shape_records { - shape_writer.write_shape_record(shape_record, 1)?; + Self::write_shape_record(shape_record, &mut bits, &mut shape_context)?; } // End shape record. - shape_writer.write_ubits(6, 0)?; - shape_writer.flush_bits()?; + bits.write_ubits(6, 0)?; } } @@ -2520,8 +2563,8 @@ impl Writer { .flat_map(|r| r.glyphs.iter().map(|g| count_sbits(g.advance))) .max() .unwrap_or(0); - writer.write_u8(num_glyph_bits)?; - writer.write_u8(num_advance_bits)?; + writer.write_u8(num_glyph_bits as u8)?; + writer.write_u8(num_advance_bits as u8)?; for record in &text.records { let flags = 0b10000000 @@ -2546,9 +2589,10 @@ impl Writer { writer.write_u16(height.get() as u16)?; } writer.write_u8(record.glyphs.len() as u8)?; + let mut bits = writer.bits(); for glyph in &record.glyphs { - writer.write_ubits(num_glyph_bits, glyph.index)?; - writer.write_sbits(num_advance_bits, glyph.advance)?; + bits.write_ubits(num_glyph_bits, glyph.index)?; + bits.write_sbits(num_advance_bits, glyph.advance)?; } } writer.write_u8(0)?; // End of text records. @@ -2714,7 +2758,7 @@ impl Writer { } } -fn count_ubits(mut n: u32) -> u8 { +fn count_ubits(mut n: u32) -> u32 { let mut num_bits = 0; while n > 0 { n >>= 1; @@ -2723,7 +2767,7 @@ fn count_ubits(mut n: u32) -> u8 { num_bits } -fn count_sbits(n: i32) -> u8 { +fn count_sbits(n: i32) -> u32 { if n == 0 { 0 } else if n == -1 { @@ -2735,7 +2779,7 @@ fn count_sbits(n: i32) -> u8 { } } -fn count_sbits_twips(n: Twips) -> u8 { +fn count_sbits_twips(n: Twips) -> u32 { let n = n.get(); if n == 0 { 0 @@ -2748,7 +2792,7 @@ fn count_sbits_twips(n: Twips) -> u8 { } } -fn count_fbits(n: f32) -> u8 { +fn count_fbits(n: f32) -> u32 { count_sbits((n * 65536f32) as i32) } @@ -2853,15 +2897,16 @@ mod tests { #[test] fn write_bit() { - let bits = [ + let out_bits = [ false, true, false, true, false, true, false, true, false, false, true, false, false, true, false, true, ]; let mut buf = Vec::new(); { let mut writer = Writer::new(&mut buf, 1); - for b in &bits { - writer.write_bit(*b).unwrap(); + let mut bits = writer.bits(); + for b in &out_bits { + bits.write_bit(*b).unwrap(); } } assert_eq!(buf, [0b01010101, 0b00100101]); @@ -2874,10 +2919,10 @@ mod tests { let mut buf = Vec::new(); { let mut writer = Writer::new(&mut buf, 1); + let mut bits = writer.bits(); for n in &nums { - writer.write_ubits(num_bits, *n).unwrap(); + bits.write_ubits(num_bits, *n).unwrap(); } - writer.flush_bits().unwrap(); } assert_eq!(buf, [0b01010101, 0b00100101]); } @@ -2889,10 +2934,10 @@ mod tests { let mut buf = Vec::new(); { let mut writer = Writer::new(&mut buf, 1); + let mut bits = writer.bits(); for n in &nums { - writer.write_sbits(num_bits, *n).unwrap(); + bits.write_sbits(num_bits, *n).unwrap(); } - writer.flush_bits().unwrap(); } assert_eq!(buf, [0b01010101, 0b00100101]); } @@ -2904,10 +2949,10 @@ mod tests { let mut buf = Vec::new(); { let mut writer = Writer::new(&mut buf, 1); + let mut bits = writer.bits(); for n in &nums { - writer.write_fbits(num_bits, *n).unwrap(); + bits.write_fbits(num_bits, *n).unwrap(); } - writer.flush_bits().unwrap(); } assert_eq!( buf, @@ -2923,7 +2968,7 @@ mod tests { #[test] fn count_ubits() { - assert_eq!(super::count_ubits(0), 0u8); + assert_eq!(super::count_ubits(0), 0); assert_eq!(super::count_ubits(1u32), 1); assert_eq!(super::count_ubits(2u32), 2); assert_eq!(super::count_ubits(0b_00111101_00000000u32), 14); @@ -2931,14 +2976,14 @@ mod tests { #[test] fn count_sbits() { - assert_eq!(super::count_sbits(0), 0u8); - assert_eq!(super::count_sbits(1), 2u8); - assert_eq!(super::count_sbits(2), 3u8); - assert_eq!(super::count_sbits(0b_00111101_00000000), 15u8); + assert_eq!(super::count_sbits(0), 0); + assert_eq!(super::count_sbits(1), 2); + assert_eq!(super::count_sbits(2), 3); + assert_eq!(super::count_sbits(0b_00111101_00000000), 15); - assert_eq!(super::count_sbits(-1), 1u8); - assert_eq!(super::count_sbits(-2), 2u8); - assert_eq!(super::count_sbits(-0b_00110101_01010101), 15u8); + assert_eq!(super::count_sbits(-1), 1); + assert_eq!(super::count_sbits(-2), 2); + assert_eq!(super::count_sbits(-0b_00110101_01010101), 15); } #[test] @@ -2971,7 +3016,6 @@ mod tests { { let mut writer = Writer::new(&mut buf, 1); writer.write_rectangle(&rect).unwrap(); - writer.flush_bits().unwrap(); } assert_eq!(buf, [0]); } @@ -2988,7 +3032,6 @@ mod tests { { let mut writer = Writer::new(&mut buf, 1); writer.write_rectangle(&rect).unwrap(); - writer.flush_bits().unwrap(); } assert_eq!(buf, [0b_00110_101, 0b100_01010, 0b0_101100_0, 0b_10100_000]); } @@ -3032,7 +3075,6 @@ mod tests { { let mut writer = Writer::new(&mut buf, 1); writer.write_matrix(m).unwrap(); - writer.flush_bits().unwrap(); } buf }