xcursor_writer/
lib.rs

1mod comment;
2mod image;
3use std::io;
4const XCURSOR_MAGIC: &[u8] = b"Xcur";
5const XCURSOR_FILE_MAJOR: u32 = 1;
6const XCURSOR_FILE_MINOR: u32 = 0;
7const XCURSOR_FILE_VERSION: u32 = (XCURSOR_FILE_MAJOR << 16) | (XCURSOR_FILE_MINOR);
8const XCURSOR_FILE_HEADER_LEN: u32 = 4 * 4;
9const XCURSOR_FILE_TOC_LEN: u32 = 3 * 4;
10const XCURSOR_IMAGE_MAX_DIM: u32 = 32767;
11const XCURSOR_CHUNK_HEADER_LEN: u32 = 4 * 4;
12
13pub use comment::Comment;
14pub use image::Image;
15
16pub fn write_to_vec(images: &[Image], comments: &[Comment]) -> io::Result<Vec<u8>> {
17    let mut cursor = std::io::Cursor::new(Vec::<u8>::new());
18    write(&mut cursor, images, comments)?;
19    Ok(cursor.into_inner())
20}
21
22pub fn write(o: &mut impl io::Write, images: &[Image], comments: &[Comment]) -> io::Result<()> {
23    for image in images {
24        if image.width > XCURSOR_IMAGE_MAX_DIM || image.height > XCURSOR_IMAGE_MAX_DIM {
25            return Err(io::Error::new(
26                io::ErrorKind::Other,
27                "The cursor dimension is larger than 32767px",
28            ));
29        }
30    }
31
32    o.write(XCURSOR_MAGIC)?;
33    o.write(&XCURSOR_FILE_HEADER_LEN.to_le_bytes())?;
34    o.write(&XCURSOR_FILE_VERSION.to_le_bytes())?;
35
36    let num_toc = (images.len() + comments.len()) as u32;
37    o.write(&num_toc.to_le_bytes())?;
38
39    let mut position = XCURSOR_FILE_HEADER_LEN + num_toc * XCURSOR_FILE_TOC_LEN;
40    for image in images {
41        image::write_image_toc(o, image.size, position)?;
42        position += image::len_image_chunk(image.width * image.height * 4);
43    }
44
45    for comment in comments {
46        comment::write_comment_toc(o, comment, position)?;
47        position += comment::len_comment_chunk(comment);
48    }
49
50    for image in images {
51        image::write_image_chunk(o, image)?;
52    }
53
54    for comment in comments {
55        comment::write_comment_chunk(o, comment)?;
56    }
57
58    Ok(())
59}