1use super::name::NameId;
4use super::parse_prelude::*;
5
6pub const CPAL: Tag = Tag::new(b"CPAL");
8
9#[derive(Copy, Clone)]
13pub struct Cpal<'a> {
14 data: Buffer<'a>,
15 version: u16,
16 len: u16,
17 offset: u32,
18}
19
20impl<'a> Cpal<'a> {
21 pub fn new(data: &'a [u8]) -> Self {
24 let data = Buffer::new(data);
25 let version = data.read_or_default(0);
26 let len = data.read_or_default(4);
27 let offset = data.read_or_default(8);
28 Self {
29 data,
30 version,
31 len,
32 offset,
33 }
34 }
35
36 pub fn version(&self) -> u16 {
38 self.version
39 }
40
41 pub fn len(&self) -> u16 {
43 self.len
44 }
45
46 pub fn is_empty(&self) -> bool {
48 self.len == 0
49 }
50
51 pub fn get(&self, index: u16) -> Option<Palette<'a>> {
53 if index >= self.len {
54 return None;
55 }
56 let d = &self.data;
57 let name_id = (|| {
58 if self.version == 0 {
59 return None;
60 }
61 let base = 16 + self.len as usize * 2;
62 let labels_offset = d.read_u32(base)? as usize;
63 if labels_offset == 0 {
64 return None;
65 }
66 d.read_u16(labels_offset + index as usize * 2)
67 })();
68 let flags = (|| {
69 if self.version == 0 {
70 return None;
71 }
72 let base = 12 + self.len as usize * 2;
73 let types_offset = d.read_u32(base)? as usize;
74 if types_offset == 0 {
75 return None;
76 }
77 d.read_u32(types_offset + index as usize * 4)
78 })()
79 .unwrap_or(0);
80 let theme = match flags & 0b11 {
81 0b01 => Theme::Light,
82 0b10 => Theme::Dark,
83 _ => Theme::Any,
84 };
85 let len = d.read::<u16>(2)? as usize;
86 let first = d.read_u32(12 + index as usize * 2)? as usize;
87 let offset = self.offset as usize + first;
88 let colors = d.read_slice(offset, len)?;
89 Some(Palette {
90 index,
91 name_id,
92 theme,
93 colors,
94 })
95 }
96
97 pub fn palettes(&self) -> impl Iterator<Item = Palette<'a>> + 'a + Clone {
99 let copy = *self;
100 (0..self.len).filter_map(move |i| copy.get(i))
101 }
102}
103
104#[derive(Copy, Clone)]
106pub struct Palette<'a> {
107 pub index: u16,
109 pub name_id: Option<NameId>,
111 pub theme: Theme,
113 pub colors: Slice<'a, Color>,
115}
116
117#[derive(Copy, Clone, PartialEq, Eq, Debug)]
119pub enum Theme {
120 Any,
122 Light,
124 Dark,
126}
127
128#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
130pub struct Color {
131 pub r: u8,
133 pub g: u8,
135 pub b: u8,
137 pub a: u8,
139}
140
141impl ReadData for Color {
142 unsafe fn read_data_unchecked(buf: &[u8], offset: usize) -> Self {
143 Self {
144 r: *buf.get_unchecked(offset + 2),
145 g: *buf.get_unchecked(offset + 1),
146 b: *buf.get_unchecked(offset),
147 a: *buf.get_unchecked(offset + 3),
148 }
149 }
150}