icon_cache/
raw.rs

1//! FFI-compatible 'raw' structs matching the exact layout of the icon cache file.
2
3use std::ffi::{CStr, FromBytesUntilNulError};
4use std::marker::PhantomData;
5use std::path::Path;
6use zerocopy::{
7    byteorder::network_endian::{U16, U32},
8    *,
9};
10
11#[repr(C)]
12#[derive(derive_more::Debug, FromBytes, KnownLayout, Immutable, Eq, PartialEq)]
13pub struct Offset<V, T: ?Sized> {
14    pub offset: V,
15    #[debug(skip)]
16    marker: PhantomData<T>,
17}
18
19impl<V, T> Offset<V, T>
20where
21    V: Into<u32> + Copy,
22    T: TryFromBytes + KnownLayout + Immutable + ?Sized,
23{
24    pub fn at<'a>(&self, bytes: &'a [u8]) -> Result<&'a T, TryCastError<&'a [u8], T>> {
25        let offset = self.offset.into() as usize;
26        T::try_ref_from_prefix(&bytes[offset..]).map(|(t, _)| t)
27    }
28}
29
30impl<V> Offset<V, CStr>
31where
32    V: Into<u32> + Copy,
33{
34    pub fn str_at<'a>(&self, bytes: &'a [u8]) -> Result<&'a CStr, FromBytesUntilNulError> {
35        let offset = self.offset.into() as usize;
36        CStr::from_bytes_until_nul(&bytes[offset..])
37    }
38}
39
40impl<V> Offset<V, Path>
41where
42    V: Into<u32> + Copy,
43{
44    pub fn path_at<'a>(&self, bytes: &'a [u8]) -> Option<&'a Path> {
45        let offset = self.offset.into() as usize;
46        let cstr = CStr::from_bytes_until_nul(&bytes[offset..]).ok()?;
47        let str = cstr.to_str().ok()?;
48        Some(Path::new(str))
49    }
50}
51
52impl<V, T: ?Sized> Clone for Offset<V, T>
53where
54    V: Clone,
55{
56    fn clone(&self) -> Self {
57        Self {
58            offset: self.offset.clone(),
59            marker: Default::default(),
60        }
61    }
62}
63
64impl<V, T: ?Sized> Copy for Offset<V, T> where V: Copy {}
65
66impl<V, T> Offset<V, T>
67where
68    T: ?Sized,
69{
70    pub fn new(offset: impl Into<V>) -> Self {
71        Self {
72            offset: offset.into(),
73            marker: Default::default(),
74        }
75    }
76}
77
78impl<T> Offset<U32, T>
79where
80    T: ?Sized,
81{
82    #[inline(always)]
83    pub fn is_null(&self) -> bool {
84        self.offset == 0 || self.offset == 0xFFFFFFFF
85    }
86}
87
88#[repr(C)]
89#[derive(Debug, FromBytes, KnownLayout, Immutable, Eq, PartialEq)]
90pub struct Header {
91    pub major_version: U16,
92    pub minor_version: U16,
93    pub hash: Offset<U32, Hash>,
94    pub directory_list: Offset<U32, DirectoryList>,
95}
96
97#[repr(C)]
98#[derive(Debug, FromBytes, KnownLayout, Immutable, Eq, PartialEq)]
99pub struct DirectoryList {
100    pub n_directories: U32,
101    pub directory: [Offset<U32, Path>],
102}
103
104#[repr(C)]
105#[derive(Debug, FromBytes, KnownLayout, Immutable, Eq, PartialEq)]
106pub struct Hash {
107    pub n_buckets: U32,
108    pub icon: [Offset<U32, Icon>],
109}
110
111#[repr(C)]
112#[derive(Debug, FromBytes, KnownLayout, Immutable, Eq, PartialEq)]
113pub struct Icon {
114    pub chain: Offset<U32, Icon>,
115    pub name: Offset<U32, CStr>,
116    pub image_list: Offset<U32, ImageList>,
117}
118
119impl Icon {
120    pub(crate) fn iter<'a>(&'a self, bytes: &'a [u8]) -> impl Iterator<Item = &'a Icon> {
121        let mut icon = Some(self);
122
123        std::iter::from_fn(move || {
124            let result = icon;
125
126            if let Some(result) = result {
127                if result.chain.is_null() {
128                    icon = None; // Next `result` will be None
129                    return Some(result);
130                }
131
132                icon = result.chain.at(bytes).ok()
133            }
134
135            result
136        })
137    }
138}
139
140#[repr(C)]
141#[derive(Debug, FromBytes, KnownLayout, Immutable, Eq, PartialEq)]
142pub struct ImageList {
143    pub n_images: U32,
144    pub images: [Image],
145}
146
147#[repr(C)]
148#[derive(Debug, Copy, Clone, FromBytes, KnownLayout, Immutable, Eq, PartialEq)]
149pub struct Image {
150    pub directory_index: U16,
151    pub icon_flags: Flags,
152    pub image_data: Offset<U32, ImageData>,
153}
154
155#[repr(C)]
156#[derive(Debug, Copy, Clone, Default, FromBytes, Immutable, Eq, PartialEq)]
157pub struct Flags {
158    value: U16,
159}
160
161impl Flags {
162    pub const HAS_SUFFIX_XPM: U16 = U16::new(1);
163    pub const HAS_SUFFIX_SVG: U16 = U16::new(2);
164    pub const HAS_SUFFIX_PNG: U16 = U16::new(4);
165    pub const HAS_ICON_FILE: U16 = U16::new(8);
166
167    pub fn new(value: U16) -> Self {
168        Flags { value }
169    }
170
171    pub fn bits(&self) -> U16 {
172        self.value
173    }
174
175    pub fn has_suffix_xpm(&self) -> bool {
176        (self.value & Self::HAS_SUFFIX_XPM) != 0
177    }
178
179    pub fn has_suffix_svg(&self) -> bool {
180        (self.value & Self::HAS_SUFFIX_SVG) != 0
181    }
182
183    pub fn has_suffix_png(&self) -> bool {
184        (self.value & Self::HAS_SUFFIX_PNG) != 0
185    }
186}
187
188#[repr(C)]
189#[derive(Debug, Copy, Clone, FromBytes, KnownLayout, Immutable, Eq, PartialEq)]
190pub struct ImageData {
191    pub image_pixel_data: Offset<U32, ()>,
192    pub image_meta_data: Offset<U32, MetaData>,
193    pub image_pixel_data_type: Offset<U32, ()>,
194    pub image_pixel_data_length: Offset<U32, ()>,
195    // pixel_data
196}
197
198#[repr(C)]
199#[derive(Debug, Copy, Clone, FromBytes, KnownLayout, Immutable, Eq, PartialEq)]
200pub struct MetaData {
201    pub embedded_rect: Offset<U32, EmbeddedRect>,
202    pub attach_point_list: Offset<U32, AttachPointList>,
203    pub display_name_list: Offset<U32, DisplayNameList>,
204}
205
206#[repr(C)]
207#[derive(Debug, Copy, Clone, Default, FromBytes, Immutable, Eq, PartialEq)]
208pub struct EmbeddedRect {
209    pub x0: U16,
210    pub y0: U16,
211    pub x1: U16,
212    pub y1: U16,
213}
214
215#[repr(C)]
216#[derive(Debug, FromBytes, KnownLayout, Immutable, Eq, PartialEq)]
217pub struct AttachPointList {
218    pub n_attach_points: U32,
219    pub attach_points: [AttachPoint],
220}
221
222#[repr(C)]
223#[derive(Debug, Copy, Clone, Default, FromBytes, Immutable, Eq, PartialEq)]
224pub struct AttachPoint {
225    pub x: U16,
226    pub y: U16,
227}
228
229#[repr(C)]
230#[derive(Debug, FromBytes, KnownLayout, Immutable, Eq, PartialEq)]
231pub struct DisplayNameList {
232    pub n_display_names: U32,
233    pub display_name: [DisplayName],
234}
235
236#[repr(C)]
237#[derive(Debug, Copy, Clone, FromBytes, Immutable, Eq, PartialEq)]
238pub struct DisplayName {
239    pub display_lang: Offset<U32, CStr>,
240    pub display_name: Offset<U32, CStr>,
241}