1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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<u8>,
}
pub struct XCursorEncoder {
pub images: Vec<ImageInfo>,
}
const MAGIC: [u8; 4] = [0x58, 0x63, 0x75, 0x72];
const IMAGE_HEADER: [u8; 4] = [0x02, 0x00, 0xfd, 0xff];
impl XCursorEncoder {
pub fn new(images: Vec<ImageInfo>) -> 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<u8> {
fn insert_bytes(data: &mut Vec<u8>, new_data: impl IntoIterator<Item = u8>) {
for int in new_data {
data.push(int);
}
}
fn insert_int(data: &mut Vec<u8>, 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<u8> = 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
}
}
|