From 6e3b3c8013e6d8814dbf70c854e55d062bedbdf4 Mon Sep 17 00:00:00 2001 From: memdmp Date: Mon, 13 Jan 2025 16:54:34 +0100 Subject: chore: initial commit --- src/xcursor.rs | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 src/xcursor.rs (limited to 'src/xcursor.rs') diff --git a/src/xcursor.rs b/src/xcursor.rs new file mode 100644 index 0000000..ff6c3d6 --- /dev/null +++ b/src/xcursor.rs @@ -0,0 +1,101 @@ +#[derive(Debug, Clone)] +pub struct ImageInfo { + pub r#type: u32, + pub subtype: u32, + pub width: u32, + pub height: u32, + pub xhot: u32, + pub yhot: u32, + pub delay: u32, + pub data: Vec, +} + +pub struct XCursorEncoder { + pub images: Vec, +} + +const MAGIC: [u8; 4] = [0x58, 0x63, 0x75, 0x72]; +const IMAGE_HEADER: [u8; 4] = [0x02, 0x00, 0xfd, 0xff]; + +impl XCursorEncoder { + pub fn new(images: Vec) -> Self { + XCursorEncoder { images } + } + + fn image_pos(&self, position: usize) -> usize { + let mut val = 12 * self.images.len() + 16; + for n in 0..position { + val += 36 + ((self.images[n].width as usize) * (self.images[n].height as usize) * 4) + } + val + } + + pub fn pack(&mut self) -> Vec { + fn insert_bytes(data: &mut Vec, new_data: impl IntoIterator) { + for int in new_data { + data.push(int); + } + } + fn insert_int(data: &mut Vec, int: u32) { + data.push((int & 0xff) as u8); + data.push(((int >> 8) & 0xff) as u8); + data.push(((int >> 16) & 0xff) as u8); + data.push(((int >> 24) & 0xff) as u8); + } + + let mut data: Vec = Vec::new(); + + // File Header + { + // MAGIC string ("Xcur") + insert_bytes(&mut data, MAGIC); + // CARD32 bytes in this header + insert_int(&mut data, 16); + // CARD32 file version + insert_int(&mut data, 1); + // CARD32 number of toc entries + insert_int(&mut data, self.images.len().try_into().unwrap()); + } + + // ntoc entries + { + let mut img_idx: usize = 0; + for img in self.images.clone().into_iter() { + // Some header + insert_bytes(&mut data, IMAGE_HEADER); + // CARD32 type-specific label - size for images + insert_int(&mut data, img.r#type); + // CARD32 absolute byte position of table in file + insert_int(&mut data, self.image_pos(img_idx).try_into().unwrap()); + + img_idx += 1; + } + } + + // images + { + for img in self.images.clone().into_iter() { + // Header Size (36) + insert_int(&mut data, 36); + // Image Type + insert_bytes(&mut data, IMAGE_HEADER); + // Subtype, for nominal size + insert_int(&mut data, img.subtype); + // Version + insert_int(&mut data, 1); + // Image dimensions + insert_int(&mut data, img.width); + insert_int(&mut data, img.height); + // Cursor positioning + insert_int(&mut data, img.xhot); + insert_int(&mut data, img.yhot); + // Milliseconds till next frame + insert_int(&mut data, img.delay); + // Raw image data + insert_bytes(&mut data, img.data); + } + } + + data + } +} -- cgit v1.2.3