about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--gifed/src/block/extension/application.rs4
-rw-r--r--gifed/src/block/extension/graphiccontrol.rs91
-rw-r--r--gifed/src/block/mod.rs2
-rw-r--r--gifed/src/block/packed.rs127
-rw-r--r--gifprobe/src/main.rs24
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());
+					}
+				}
 			}
 		}
 	}