1use std::io::{Read, Seek, SeekFrom};
2
3use bom::{BOMBlock, BOMEror, BOMResult};
4use deku::{ctx::Order, prelude::*, reader::Reader};
5
6use super::ColorSpace;
7use crate::PayloadBytes;
8
9#[derive(Debug, DekuRead)]
10#[deku(magic = b"tmfk", endian = "little")]
11pub struct KeyFmt {
12 pub version: u32,
13 pub max_count: u32,
14 #[deku(reader = "KeyFmt::read_attr_types(deku::reader, *max_count)")]
15 pub attribute_types: Vec<AttributeType>,
16}
17
18impl KeyFmt {
19 fn read_attr_types<R: Read + Seek>(
20 reader: &mut Reader<R>,
21 count: u32,
22 ) -> Result<Vec<AttributeType>, DekuError> {
23 let mut attr_types: Vec<AttributeType> = vec![];
24 for _ in 0..count {
25 attr_types.push(AttributeType::from_reader_with_ctx(
26 reader,
27 deku::ctx::Endian::Little,
28 )?);
29 reader.seek(SeekFrom::Current(2))?;
30 }
31 Ok(attr_types)
32 }
33}
34
35#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, DekuRead)]
36#[deku(endian = "little")]
37pub struct KeyToken {
38 pub x: u16,
39 pub y: u16,
40 count: u16,
41 #[deku(count = "count")]
42 pub attrs: Vec<Attribute>,
43}
44
45#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, DekuRead)]
46#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
47pub struct Attribute {
48 pub name: AttributeType,
49 pub val: u16,
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, DekuRead)]
53#[deku(id_type = "u16", endian = "little", ctx = "endian: deku::ctx::Endian")]
54pub enum AttributeType {
55 #[deku(id = 0)]
56 ThemeLook,
57 #[deku(id = 1)]
58 Element,
59 #[deku(id = 2)]
60 Part,
61 #[deku(id = 3)]
62 Size,
63 #[deku(id = 4)]
64 Direction,
65 #[deku(id = 5)]
66 Placeholder,
67 #[deku(id = 6)]
68 Value,
69 #[deku(id = 7)]
70 ThemeAppearance,
71 #[deku(id = 8)]
72 Dimension1,
73 #[deku(id = 9)]
74 Dimension2,
75 #[deku(id = 10)]
76 State,
77 #[deku(id = 11)]
78 Layer,
79 #[deku(id = 12)]
80 Scale,
81 #[deku(id = 13)]
82 Localization,
83 #[deku(id = 14)]
84 PresentationState,
85 #[deku(id = 15)]
86 Idiom,
87 #[deku(id = 16)]
88 Subtype,
89 #[deku(id = 17)]
90 Identifier,
91 #[deku(id = 18)]
92 PreviousValue,
93 #[deku(id = 19)]
94 PreviousState,
95 #[deku(id = 20)]
96 HorizontalSizeClass,
97 #[deku(id = 21)]
98 VerticalSizeClass,
99 #[deku(id = 22)]
100 MemoryLevelClass,
101 #[deku(id = 23)]
102 GraphicsFeatureSetClass,
103 #[deku(id = 24)]
104 DisplayGamut,
105 #[deku(id = 25)]
106 DeploymentTarget,
107 #[deku(id = 26)]
108 GlyphWeight,
109 #[deku(id = 27)]
110 GlyphSize,
111
112 #[deku(id_pat = "_")]
113 Unknown { tag: u16 },
114}
115
116#[derive(Debug, Clone)]
117pub enum Rendition {
118 Color(RenditionColor),
119 RawData(RenditionRawData),
120 ThemeCBCK(RenditionThemeCBCK),
121 MultisizeImageSet(RenditionMultisizeImageSet),
122 Unknown {
123 tag: [u8; 4],
124 data: RenditionUnknown,
125 },
126}
127
128#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129pub enum RenditionKind {
130 None,
131 Color,
132 RawData,
133 ThemeCBCK,
134 MultisizeImageSet,
135 Unknown,
136}
137
138#[derive(Debug, Clone, DekuRead)]
139#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
140pub struct RenditionColor {
141 pub version: u32,
142 pub color_space: ColorSpace,
143 _component_count: u32,
144 #[deku(count = "_component_count")]
145 pub components: Vec<f64>,
146}
147
148#[derive(Debug, Clone)]
149pub struct RenditionRawData {
150 pub version: u32,
151 _raw_data_length: u32,
152 pub raw_data: PayloadBytes,
153}
154
155#[derive(Debug, Clone)]
156pub struct RenditionThemeCBCK {
157 pub version: u32,
158 pub compression_type: CompressionType,
159 _raw_data_length: u32,
160 pub chunks: Vec<ThemeChunk>,
161}
162
163impl RenditionThemeCBCK {
164 pub fn raw_datas(&self) -> impl Iterator<Item = &[u8]> {
165 self.chunks.iter().map(|chunk| chunk.raw_data.as_slice())
166 }
167}
168
169#[derive(Debug, Clone, DekuRead)]
170#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
171pub struct RenditionMultisizeImageSet {
172 pub version: u32,
173 _count: u32,
174 #[deku(count = "_count")]
175 pub entries: Vec<MultisizeImageSetEntry>,
176}
177
178#[derive(Debug, Clone)]
179pub struct RenditionUnknown {
180 pub version: u32,
182 _raw_data_length: u32,
183 pub raw_data: PayloadBytes,
184}
185
186#[derive(Debug, Clone, DekuRead)]
187#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
188pub struct CBCK {
189 pub idk: u32,
190 pub tag: u32,
191 pub a: u32,
192 pub b: u32,
193}
194
195#[derive(Debug, Clone, DekuRead)]
196#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
197pub struct MultisizeImageSetEntry {
198 pub width: u32,
199 pub height: u32,
200 pub index: u16,
201 pub idiom: Idiom,
202}
203
204#[derive(Debug, Clone, DekuRead)]
205#[deku(endian = "little")]
206pub struct ThemePartHeader {
207 pub tag: [u8; 4],
208 pub arg2: u32,
209 pub arg3: u32,
210 pub height: u32,
211 pub raw_len: u32,
212}
213
214#[derive(Debug, Clone)]
215pub struct ThemeChunk {
216 pub part_header: Option<ThemePartHeader>,
217 pub raw_data: PayloadBytes,
218}
219
220pub(crate) fn parse_rendition_payload(payload: PayloadBytes) -> BOMResult<Rendition> {
221 let mut reader = Reader::new(BOMBlock::new(payload));
222 let mut tag = [0_u8; 4];
223 reader.read_bytes(4, &mut tag, Order::default())?;
224
225 match &tag {
226 b"RLOC" => {
227 let data =
228 RenditionColor::from_reader_with_ctx(&mut reader, deku::ctx::Endian::Little)?;
229 Ok(Rendition::Color(data))
230 }
231 b"DWAR" => {
232 let version = read_u32(&mut reader)?;
233 let raw_data_length = read_u32(&mut reader)?;
234 let raw_data = payload_slice(&mut reader, raw_data_length)?;
235 Ok(Rendition::RawData(RenditionRawData {
236 version,
237 _raw_data_length: raw_data_length,
238 raw_data,
239 }))
240 }
241 b"MLEC" => {
242 let version = read_u32(&mut reader)?;
243 let compression_type =
244 CompressionType::from_reader_with_ctx(&mut reader, deku::ctx::Endian::Little)?;
245 let raw_data_length = read_u32(&mut reader)?;
246 let chunks = read_theme_chunks(&mut reader, version, raw_data_length)?;
247 Ok(Rendition::ThemeCBCK(RenditionThemeCBCK {
248 version,
249 compression_type,
250 _raw_data_length: raw_data_length,
251 chunks,
252 }))
253 }
254 b"SISM" => {
255 let data = RenditionMultisizeImageSet::from_reader_with_ctx(
256 &mut reader,
257 deku::ctx::Endian::Little,
258 )?;
259 Ok(Rendition::MultisizeImageSet(data))
260 }
261 _ => {
262 let version = read_u32(&mut reader)?;
263 let raw_data_length = read_u32(&mut reader)?;
264 let raw_data = payload_slice(&mut reader, raw_data_length)?;
265 Ok(Rendition::Unknown {
266 tag,
267 data: RenditionUnknown {
268 version,
269 _raw_data_length: raw_data_length,
270 raw_data,
271 },
272 })
273 }
274 }
275}
276
277fn read_u32(reader: &mut Reader<BOMBlock>) -> Result<u32, DekuError> {
278 u32::from_reader_with_ctx(reader, deku::ctx::Endian::Little)
279}
280
281fn payload_slice(reader: &mut Reader<BOMBlock>, len: u32) -> BOMResult<PayloadBytes> {
282 let len = len as usize;
283 let slice = reader.as_mut().slice_at_current(len)?;
284 reader.bits_read = reader.bits_read.saturating_add(len.saturating_mul(8));
285 reader.leftover = None;
286 Ok(slice)
287}
288
289fn read_theme_chunks(
290 reader: &mut Reader<BOMBlock>,
291 version: u32,
292 raw_len: u32,
293) -> BOMResult<Vec<ThemeChunk>> {
294 match version {
295 0 | 2 => {
296 let raw_data = payload_slice(reader, raw_len)?;
297 Ok(vec![ThemeChunk {
298 part_header: None,
299 raw_data,
300 }])
301 }
302 1 | 3 => {
303 let mut result = vec![];
304 for _ in 0..raw_len {
305 let part_header = ThemePartHeader::from_reader_with_ctx(reader, ())?;
306 let raw_data = payload_slice(reader, part_header.raw_len)?;
307 result.push(ThemeChunk {
308 part_header: Some(part_header),
309 raw_data,
310 });
311 }
312 Ok(result)
313 }
314 _ => Err(BOMEror::ParseStruct(DekuError::Parse(
315 format!("Not support version {}", version).into(),
316 ))),
317 }
318}
319
320#[derive(Debug, Clone, Copy, PartialEq, Eq, DekuRead)]
321#[deku(id_type = "u32", endian = "little", ctx = "endian: deku::ctx::Endian")]
322pub enum CompressionType {
323 #[deku(id = 0)]
324 Uncompressed,
325 #[deku(id = 1)]
326 Rle,
327 #[deku(id = 2)]
328 Zip,
329 #[deku(id = 3)]
330 Lzvn,
331 #[deku(id = 4)]
332 Lzfse,
333 #[deku(id = 5)]
334 JpegLzfse,
335 #[deku(id = 6)]
336 Blurred,
337 #[deku(id = 7)]
338 Astc,
339 #[deku(id = 8)]
340 PaletteImg,
341 #[deku(id = 9)]
342 HEVC, #[deku(id = 10)]
344 DeepmapLzfse,
345 #[deku(id = 11)]
347 Deepmap2,
348
349 #[deku(id_pat = "_")]
350 Unknown { tag: u32 },
351}
352
353#[derive(Debug, Clone, DekuRead)]
354#[deku(id_type = "u16", endian = "little", ctx = "endian: deku::ctx::Endian")]
355pub enum Idiom {
356 #[deku(id = 0)]
357 Universal,
358 #[deku(id = 1)]
359 Phone,
360 #[deku(id = 2)]
361 Pad,
362 #[deku(id = 3)]
363 TV,
364 #[deku(id = 4)]
365 Car,
366 #[deku(id = 5)]
367 Watch,
368 #[deku(id = 6)]
369 Marketing,
370
371 #[deku(id_pat = "_")]
372 Unknown { tag: u16 },
373}
374
375#[derive(Debug, DekuRead)]
376#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
377pub struct BitmapList {
378 pub bitmap_count: u32, pub zero: u32, pub rendition_length: u32,
381}
382
383#[derive(Debug, Clone, Copy, PartialEq, Eq, DekuRead)]
384#[deku(id_type = "u32", endian = "little", ctx = "endian: deku::ctx::Endian")]
385pub enum LayoutType {
386 #[deku(id = 6)]
387 Gradient,
388 #[deku(id = 7)]
389 Effect,
390 #[deku(id = 9)]
391 Vector,
392 #[deku(id = 10)]
393 OnePartFixedSize,
394 #[deku(id = 11)]
395 OnePartTile,
396 #[deku(id = 12)]
397 OnePartScale,
398 #[deku(id = 20)]
399 ThreePartHorizontalTile,
400 #[deku(id = 21)]
401 ThreePartHorizontalScale,
402 #[deku(id = 22)]
403 ThreePartHorizontalUniform,
404 #[deku(id = 23)]
405 ThreePartVerticalTile,
406 #[deku(id = 24)]
407 ThreePartVerticalScale,
408 #[deku(id = 25)]
409 ThreePartVerticalUniform,
410 #[deku(id = 30)]
411 NinePartTile,
412 #[deku(id = 31)]
413 NinePartScale,
414 #[deku(id = 32)]
415 NinePartHorizontalUniformVerticalScale,
416 #[deku(id = 33)]
417 NinePartHorizontalScaleVerticalUniform,
418 #[deku(id = 34)]
419 NinePartEdgesOnly,
420 #[deku(id = 40)]
421 SixPart,
422 #[deku(id = 50)]
423 AnimationFilmstrip,
424
425 #[deku(id = 1000)]
426 Data,
427 #[deku(id = 1001)]
428 ExternalLink,
429 #[deku(id = 1002)]
430 LayerStack,
431 #[deku(id = 1003)]
432 InternalReference,
433 #[deku(id = 1004)]
434 PackedImage,
435 #[deku(id = 1005)]
436 NameList,
437 #[deku(id = 1006)]
438 UnknownAddObject,
439 #[deku(id = 1007)]
440 Texture,
441 #[deku(id = 1008)]
442 TextureImage,
443 #[deku(id = 1009)]
444 Color,
445 #[deku(id = 1010)]
446 MultisizeImage,
447 #[deku(id = 1012)]
448 LayerReference,
449 #[deku(id = 1013)]
450 ContentRendition,
451 #[deku(id = 1014)]
452 RecognitionObject,
453
454 #[deku(id_pat = "_")]
455 Unknown { tag: u32 },
456}
457
458#[derive(Debug, DekuRead)]
459#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
460pub struct Flags {
461 #[deku(bits = 1)]
462 pub is_header_flagged_fpo: bool,
463 #[deku(bits = 1)]
464 pub is_excluded_from_contrast_filter: bool,
465 #[deku(bits = 1)]
466 pub is_vector_based: bool,
467 #[deku(bits = 1)]
468 pub is_opaque: bool,
469 #[deku(bits = 4)]
470 pub bitmap_encoding: u8,
471 #[deku(bits = 1)]
472 pub opt_out_of_thinning: bool,
473 #[deku(bits = 1)]
474 pub is_flippable: bool,
475 #[deku(bits = 1)]
476 pub is_tintable: bool,
477 #[deku(bits = 1)]
478 pub preserved_vector_representation: bool,
479 #[deku(bits = 20)]
480 _reserved: u32,
481}
482
483#[derive(Debug, DekuRead)]
484#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
485pub struct Slice {
486 pub x: u32,
487 pub y: u32,
488 pub width: u32,
489 pub height: u32,
490}
491
492#[derive(Debug, DekuRead)]
493#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
494pub struct Metric {
495 pub width: u32,
496 pub height: u32,
497}
498
499#[derive(Debug, DekuRead)]
500#[deku(id_type = "u32", endian = "little", ctx = "endian: deku::ctx::Endian")]
501pub enum RenditionType {
502 #[deku(id = 1001)]
503 Slices(RenditionTypeSlice),
504 #[deku(id = 1003)]
505 Metrics(RenditionTypeMetric),
506 #[deku(id = 1004)]
507 BlendModeAndOpacity(RenditionTypeBlendModeAndOpacity),
508 #[deku(id = 1005)]
509 UTI(RenditionTypeUTI),
510 #[deku(id = 1006)]
511 EXIFOrientation(RenditionTypeEXIFOrientation),
512 #[deku(id = 1007)]
513 BytesPerRow { length: u32, bytes_per_row: u32 },
514 #[deku(id = 1010)]
515 Reference(RenditionTypeReference),
516 #[deku(id_pat = "_")]
517 Unknown {
518 tag: u32,
519 data: RenditionTypeUnknown,
520 },
521}
522
523#[derive(Debug, DekuRead)]
524#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
525pub struct RenditionTypeSlice {
526 _length: u32,
527 _count: u32,
528 #[deku(count = "_count")]
529 pub data: Vec<Slice>,
530}
531
532#[derive(Debug, DekuRead)]
533#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
534pub struct RenditionTypeMetric {
535 _length: u32,
536 _count: u32,
537 pub top_right_inset: Metric,
538 pub bottom_left_inset: Metric,
539 pub image_size: Metric,
540}
541
542#[derive(Debug, DekuRead)]
543#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
544pub struct RenditionTypeBlendModeAndOpacity {
545 _length: u32,
546 pub blend_mode: u32,
547 pub opacity: f32,
548}
549
550#[derive(Debug, DekuRead)]
551#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
552pub struct RenditionTypeUTI {
553 _length: u32,
554 pub string_length: u32,
555 pub padding: u32,
556 #[deku(count = "string_length")]
557 pub string: Vec<u8>,
558}
559
560#[derive(Debug, DekuRead)]
561#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
562pub struct RenditionTypeEXIFOrientation {
563 _length: u32,
564 pub orientation: EXIFOrientationValue,
565}
566
567#[derive(Debug, DekuRead)]
568#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
569pub struct RenditionTypeBytesPerRow {
570 _length: u32,
571 pub bytes_per_row: u32,
572}
573
574#[derive(Debug, DekuRead)]
575#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
576pub struct RenditionTypeReference {
577 _length: u32,
578 _magic: [u8; 4], _padding: u32, pub x: u32,
581 pub y: u32,
582 pub width: u32,
583 pub height: u32,
584 pub layout: u16, _key_length: u32,
586 #[deku(count = "_key_length")]
587 pub keys: Vec<u8>, }
589#[derive(Debug, DekuRead)]
590#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
591pub struct RenditionTypeUnknown {
592 _length: u32,
593 #[deku(count = "_length")]
594 pub data: Vec<u8>,
595}
596
597#[derive(Debug, DekuRead)]
598#[deku(id_type = "u32", endian = "little", ctx = "endian: deku::ctx::Endian")]
599pub enum EXIFOrientationValue {
600 #[deku(id = 0)]
601 None,
602 #[deku(id = 1)]
603 Normal,
604 #[deku(id = 2)]
605 Mirrored,
606 #[deku(id = 3)]
607 Rotated180,
608 #[deku(id = 4)]
609 Rotated180Mirrored,
610 #[deku(id = 5)]
611 Rotated90,
612 #[deku(id = 6)]
613 Rotated90Mirrored,
614 #[deku(id = 7)]
615 Rotated270,
616 #[deku(id = 8)]
617 Rotated270Mirrored,
618
619 #[deku(id_pat = "_")]
620 Unknown { tag: u32 },
621}