diff options
-rw-r--r-- | gifed/src/block/extension/application.rs | 4 | ||||
-rw-r--r-- | gifed/src/block/extension/graphiccontrol.rs | 91 | ||||
-rw-r--r-- | gifed/src/block/mod.rs | 2 | ||||
-rw-r--r-- | gifed/src/block/packed.rs | 127 | ||||
-rw-r--r-- | gifprobe/src/main.rs | 24 |
5 files changed, 126 insertions, 122 deletions
diff --git a/gifed/src/block/extension/application.rs b/gifed/src/block/extension/application.rs index 3d46277..2244c35 100644 --- a/gifed/src/block/extension/application.rs +++ b/gifed/src/block/extension/application.rs @@ -12,4 +12,8 @@ impl Application { pub fn authentication_code(&self) -> &[u8] { &self.authentication_code } + + pub fn data(&self) -> &[u8] { + &self.data + } } diff --git a/gifed/src/block/extension/graphiccontrol.rs b/gifed/src/block/extension/graphiccontrol.rs index a6abbdc..e9662b6 100644 --- a/gifed/src/block/extension/graphiccontrol.rs +++ b/gifed/src/block/extension/graphiccontrol.rs @@ -1,14 +1,16 @@ use std::{convert::TryInto, fmt, time::Duration}; +use crate::block::packed::GraphicPacked; + #[derive(Clone, Debug)] pub struct GraphicControl { - pub(crate) packed: u8, + pub(crate) packed: GraphicPacked, pub(crate) delay: u16, pub(crate) transparency_index: u8, } impl GraphicControl { - pub fn new( + pub(crate) fn new( disposal_method: DisposalMethod, user_input_flag: bool, transparency_flag: bool, @@ -16,47 +18,50 @@ impl GraphicControl { transparency_index: u8, ) -> Self { let mut ret = Self { - packed: 0, + packed: GraphicPacked { raw: 0 }, delay, transparency_index, }; ret.set_disposal_method(disposal_method); - ret.set_user_input(user_input_flag); - ret.set_transparent(transparency_flag); + ret.packed.set_user_input(user_input_flag); + ret.packed.set_transparent_color(transparency_flag); ret } + pub fn packed(&self) -> &GraphicPacked { + &self.packed + } + /// Get the disposal method that should be used for the associated image. /// /// # Returns /// This method will return `Some([DisposalMethod])` if the disposal method /// is recognized, or None if it was set to a reserved value. pub fn disposal_method(&self) -> Option<DisposalMethod> { - match self.packed & 0b000_111_00 { - 0b000_000_00 => Some(DisposalMethod::NoAction), - 0b000_100_00 => Some(DisposalMethod::DoNotDispose), - 0b000_010_00 => Some(DisposalMethod::RestoreBackground), - 0b000_110_00 => Some(DisposalMethod::RestorePrevious), + match self.packed.disposal_method() { + 0 => Some(DisposalMethod::NoAction), + 1 => Some(DisposalMethod::DoNotDispose), + 2 => Some(DisposalMethod::RestoreBackground), + 3 => Some(DisposalMethod::RestorePrevious), _ => None, } } - /// Set the disposal method that shoudl be used for the associated image. - pub fn set_disposal_method(&mut self, method: DisposalMethod) { - match method { - DisposalMethod::NoAction => self.packed &= 0b111_000_1_1, - DisposalMethod::DoNotDispose => self.packed |= 0b000_100_0_0, - DisposalMethod::RestoreBackground => self.packed |= 0b000_010_0_0, - DisposalMethod::RestorePrevious => self.packed |= 0b000_110_0_0, - }; + pub fn set_disposal_method(&mut self, dispose: DisposalMethod) { + match dispose { + DisposalMethod::NoAction => self.packed.set_disposal_method(0), + DisposalMethod::DoNotDispose => self.packed.set_disposal_method(1), + DisposalMethod::RestoreBackground => self.packed.set_disposal_method(2), + DisposalMethod::RestorePrevious => self.packed.set_disposal_method(4), + } } /// Returns the index that should be replaced by a fully transparent pixel /// if the transparency flag is set, or None if it's not set. pub fn transparent_index(&self) -> Option<u8> { - if self.transparent() { + if self.packed.transparent_color() { Some(self.transparency_index) } else { None @@ -64,68 +69,32 @@ impl GraphicControl { } /// Returns the transparency index regardless if the transparency flag is set. - /// You probably want [GraphicControl::transparency_index] instead.s + /// You probably want [GraphicControl::transparency_index] instead. pub fn transparent_index_unchecked(&self) -> u8 { self.transparency_index } - /// Sets the transparent index flag to the value provided. This will change - /// the index value in any way and should be used with caution. You probably - /// want [GraphicControl::set_transparent_index] instead. - pub fn set_transparent(&mut self, flag: bool) { - if flag { - self.packed |= 0b000_000_0_1; - } else { - self.packed &= 0b111_111_1_0; - } - } - /// Sets the transparent index and flips the flag to indicate a transparent - /// index is present. + /// index is present if `index` is `Some`. pub fn set_transparent_index(&mut self, index: Option<u8>) { - self.set_transparent(index.is_some()); + self.packed.set_transparent_color(index.is_some()); if let Some(index) = index { self.transparency_index = index; } } - /// Get the value of the transparency flag - pub fn transparent(&self) -> bool { - self.packed & 0b000_000_0_1 > 0 - } - - pub fn user_input(&self) -> bool { - self.packed & 0b000_000_1_0 > 0 - } - - pub fn set_user_input(&mut self, flag: bool) { - if flag { - self.packed |= 0b000_000_1_0; - } else { - self.packed &= 0b111_111_0_1; - } + pub fn delay_duration(&self) -> Duration { + Duration::from_millis(self.delay as u64 * 10) } pub fn delay(&self) -> u16 { self.delay } - pub fn delay_duration(&self) -> Duration { - Duration::from_millis(self.delay as u64 * 10) - } - pub fn delay_mut(&mut self) -> &mut u16 { &mut self.delay } - - pub fn packed(&self) -> u8 { - self.packed - } - - pub fn packed_mut(&mut self) -> &mut u8 { - &mut self.packed - } } impl From<[u8; 4]> for GraphicControl { @@ -135,7 +104,7 @@ impl From<[u8; 4]> for GraphicControl { let transparency_index = arr[3]; Self { - packed, + packed: GraphicPacked { raw: packed }, delay, transparency_index, } diff --git a/gifed/src/block/mod.rs b/gifed/src/block/mod.rs index 623b346..31e78b1 100644 --- a/gifed/src/block/mod.rs +++ b/gifed/src/block/mod.rs @@ -57,7 +57,7 @@ fn encode_extension(block: &Block) -> Box<[u8]> { Block::GraphicControlExtension(gce) => { vec.push(0xF9); // Graphic control label vec.push(0x04); // Block size for this extension is always 4 - vec.push(gce.packed); + vec.push(gce.packed.raw); vec.extend_from_slice(&gce.delay.to_le_bytes()); vec.push(gce.transparency_index); } diff --git a/gifed/src/block/packed.rs b/gifed/src/block/packed.rs index 4eaa5b8..1557fae 100644 --- a/gifed/src/block/packed.rs +++ b/gifed/src/block/packed.rs @@ -1,83 +1,94 @@ -struct InnerPacked<T> { - raw: T, +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct GraphicPacked { + pub raw: u8, } -impl InnerPacked<&u8> { - #[inline] - fn color_table(&self) -> bool { - self.raw & 0b1000_0000 > 0 +impl GraphicPacked { + pub(crate) fn new(packed: u8) -> Self { + Self { raw: packed } } - #[inline] - fn color_resolution(&self) -> u8 { - (self.raw & 0b0111_0000) >> 4 + pub fn reserved(&self) -> u8 { + graphic_reserved(self.raw) } - #[inline] - fn logical_sort(&self) -> bool { - self.raw & 0b0000_1000 > 0 + pub fn set_reserved(&mut self, reserved: u8) { + set_graphic_reserved(&mut self.raw, reserved) } - #[inline] - fn image_sort(&self) -> bool { - self.raw & 0b0010_0000 > 0 + pub fn disposal_method(&self) -> u8 { + disposal_method(self.raw) } - #[inline] - fn color_table_size(&self) -> u8 { - self.raw & 0b0000_0111 + pub fn set_disposal_method(&mut self, disposal: u8) { + set_disposal_method(&mut self.raw, disposal) } - #[inline] - fn interlace(&self) -> bool { - self.raw & 0b0100_0000 > 0 + pub fn user_input(&self) -> bool { + user_input(self.raw) } -} -impl InnerPacked<&mut u8> { - #[inline] - fn set_color_table(&mut self, flag: bool) { - if flag { - *self.raw |= 0b1000_0000; - } else { - *self.raw &= 0b0111_1111; - } + pub fn set_user_input(&mut self, flag: bool) { + set_user_input(&mut self.raw, flag) } - #[inline] - fn set_color_resolution(&mut self, resolution: u8) { - *self.raw |= (resolution & 0b0111_0000) << 4; + pub fn transparent_color(&self) -> bool { + transparent_color(self.raw) } - #[inline] - fn set_logical_sort(&mut self, flag: bool) { - if flag { - *self.raw |= 0b0000_1000; - } else { - *self.raw &= 0b1111_0111; - } + pub fn set_transparent_color(&mut self, flag: bool) { + set_transparent_flag(&mut self.raw, flag) } +} - #[inline] - fn set_image_sort(&mut self, flag: bool) { - if flag { - *self.raw |= 0b0010_0000; - } else { - *self.raw &= 0b1101_1111; - } - } +#[inline] +fn graphic_reserved(packed: u8) -> u8 { + packed & 0b111_000_0_0 >> 5 +} + +#[inline] +fn disposal_method(packed: u8) -> u8 { + packed & 0b000_111_0_0 >> 2 +} + +#[inline] +fn user_input(packed: u8) -> bool { + packed & 0b000_000_1_0 > 0 +} - #[inline] - fn set_color_table_size(&mut self, size: u8) { - *self.raw |= size & 0b0000_0111; +#[inline] +fn transparent_color(packed: u8) -> bool { + packed & 0b000_000_0_1 > 0 +} + +#[inline] +fn set_graphic_reserved(packed: &mut u8, reserved: u8) { + // We care about the three least significant bits and we want to shift + // them so they're at the top, five away. From 000_001_1_1 to 111_000_0_0 + *packed = (reserved & 0b0000_0111) << 5; +} + +#[inline] +fn set_disposal_method(packed: &mut u8, disposal: u8) { + // Care about 3 least significant bits and we want them three from the top + // from 000_001_1_1 into 000_111_0_0 + *packed = (disposal & 0b0000_0111) << 2; +} + +#[inline] +fn set_user_input(packed: &mut u8, flag: bool) { + if flag { + *packed |= 0b000_000_1_0; + } else { + *packed &= 0b111_111_0_1; } +} - #[inline] - fn set_interlace(&mut self, flag: bool) { - if flag { - *self.raw |= 0b0100_0000; - } else { - *self.raw &= 0b1011_1111; - } +#[inline] +fn set_transparent_flag(packed: &mut u8, flag: bool) { + if flag { + *packed |= 0b000_000_0_1; + } else { + *packed &= 0b111_111_1_0; } } diff --git a/gifprobe/src/main.rs b/gifprobe/src/main.rs index a8e3cfd..128aae1 100644 --- a/gifprobe/src/main.rs +++ b/gifprobe/src/main.rs @@ -51,10 +51,17 @@ fn main() { Block::GraphicControlExtension(gce) => { hundreths += gce.delay() as usize; + let dispose_string = if let Some(dispose) = gce.disposal_method() { + dispose.to_string() + } else { + String::from("Reserved Value!"); + format!("Reserved: {:b}", gce.packed().disposal_method()) + }; + println!( "Graphic Control Extension\n\tDelay Time {}\n\tDispose {}", format!("{}s", gce.delay() as f32 / 100.0).yellow(), - gce.disposal_method().unwrap().yellow() + dispose_string.yellow() ) } Block::LoopingExtension(_) => todo!(), @@ -63,13 +70,26 @@ fn main() { } Block::ApplicationExtension(app) => { let auth = app.authentication_code(); + let app_ident = String::from_utf8_lossy(app.identifier()); + println!( "Application Extension\n\tIdentifier {}\n\tAuthentication {:02X} {:02X} {:02X}", - String::from_utf8_lossy(app.identifier()).yellow(), + app_ident.yellow(), auth[0].yellow(), auth[1].yellow(), auth[2].yellow() ); + + if app_ident == "NETSCAPE" { + let data = app.data(); + let looping = u16::from_le_bytes([data[0], data[1]]); + + if looping == 0 { + println!("\tLoop {}", "forever".yellow()) + } else { + println!("\tLoop {}", looping.yellow()); + } + } } } } |