Skip to main content

car/model/
mod.rs

1pub mod rendition;
2
3use std::io::{Cursor, Read, Seek};
4
5use bom::{BOMBlock, BOMEror, BOMResult};
6use deku::{ctx::Order, prelude::*, reader::Reader};
7
8// 扩展源信息
9#[derive(Debug, DekuRead)]
10#[deku(endian = "big", magic = b"META")]
11pub struct ExtendedMetadata {
12    #[deku(bytes_read = "256", map = "crate::deku_read_str")]
13    pub thinning_args: String,
14    #[deku(bytes_read = "256", map = "crate::deku_read_str")]
15    pub deployment_platform_version: String,
16    #[deku(bytes_read = "256", map = "crate::deku_read_str")]
17    pub deployment_platform: String,
18    #[deku(bytes_read = "256", map = "crate::deku_read_str")]
19    pub authoring_tool: String,
20}
21
22#[derive(Debug, DekuRead)]
23#[deku(magic = b"RATC", endian = "little")]
24pub struct Header {
25    pub coreui_version: u32,
26    pub storage_version: u32,
27    pub storage_timestamp: u32,
28    pub rendition_count: u32,
29    #[deku(bytes_read = "128", map = "crate::deku_read_str")]
30    pub main_version_string: String,
31    #[deku(bytes_read = "256", map = "crate::deku_read_str")]
32    pub version_string: String,
33    pub uuid: [u8; 16],
34    pub associated_checksumag: u32,
35    pub schema_version: u32,
36    pub color_space: ColorSpace,
37    pub key_semantics: u32,
38}
39
40#[derive(Debug)]
41pub struct CSIHeader {
42    pub version: u32,
43    pub flags: rendition::Flags,
44    pub width: u32,
45    pub height: u32,
46    // 100 to @1x, 200 to @2x, 300 to @3x
47    pub scale_factor: u32,
48    pub encoding: Encoding,
49    pub color_model: ColorModel,
50    pub metadata: CSIMetadata,
51    pub tlv_length: u32,
52    pub bitmap_list: rendition::BitmapList,
53    pub tlv_data: Vec<rendition::RenditionType>,
54    pub rendition: Option<rendition::Rendition>,
55}
56
57impl CSIHeader {
58    pub(crate) fn from_bom_block(block: BOMBlock) -> BOMResult<Self> {
59        let mut reader = Reader::new(block);
60        let parts = read_csi_header_parts(&mut reader)?;
61        let tlv_data = read_tlv_data_from_bom(&mut reader, parts.tlv_length)?;
62        let rendition = if parts.bitmap_list.rendition_length > 0 {
63            let payload = payload_slice(&mut reader, parts.bitmap_list.rendition_length)?;
64            Some(rendition::parse_rendition_payload(payload)?)
65        } else {
66            None
67        };
68
69        Ok(Self::from_parts(parts, tlv_data, rendition))
70    }
71
72    fn from_parts(
73        parts: CSIHeaderParts,
74        tlv_data: Vec<rendition::RenditionType>,
75        rendition: Option<rendition::Rendition>,
76    ) -> Self {
77        Self {
78            version: parts.version,
79            flags: parts.flags,
80            width: parts.width,
81            height: parts.height,
82            scale_factor: parts.scale_factor,
83            encoding: parts.encoding,
84            color_model: parts.color_model,
85            metadata: parts.metadata,
86            tlv_length: parts.tlv_length,
87            bitmap_list: parts.bitmap_list,
88            tlv_data,
89            rendition,
90        }
91    }
92
93    pub fn size_on_disk(&self) -> usize {
94        14 * 4 + 128 + self.tlv_length as usize + self.bitmap_list.rendition_length as usize
95    }
96}
97
98impl<'a> DekuReader<'a> for CSIHeader {
99    fn from_reader_with_ctx<R: Read + Seek>(
100        reader: &mut Reader<R>,
101        _ctx: (),
102    ) -> Result<Self, DekuError>
103    where
104        Self: Sized,
105    {
106        let parts = read_csi_header_parts(reader)?;
107        let tlv_data = read_tlv_data(reader, parts.tlv_length)?;
108        let rendition = if parts.bitmap_list.rendition_length > 0 {
109            let payload = read_payload_bytes(reader, parts.bitmap_list.rendition_length)?;
110            Some(
111                rendition::parse_rendition_payload(crate::PayloadBytes::from_vec(payload))
112                    .map_err(bom_error_to_deku)?,
113            )
114        } else {
115            None
116        };
117
118        Ok(Self::from_parts(parts, tlv_data, rendition))
119    }
120}
121
122struct CSIHeaderParts {
123    version: u32,
124    flags: rendition::Flags,
125    width: u32,
126    height: u32,
127    scale_factor: u32,
128    encoding: Encoding,
129    color_model: ColorModel,
130    metadata: CSIMetadata,
131    tlv_length: u32,
132    bitmap_list: rendition::BitmapList,
133}
134
135fn read_csi_header_parts<R: Read + Seek>(
136    reader: &mut Reader<R>,
137) -> Result<CSIHeaderParts, DekuError> {
138    read_magic(reader, b"ISTC")?;
139    Ok(CSIHeaderParts {
140        version: read_u32(reader)?,
141        flags: rendition::Flags::from_reader_with_ctx(reader, deku::ctx::Endian::Little)?,
142        width: read_u32(reader)?,
143        height: read_u32(reader)?,
144        scale_factor: read_u32(reader)?,
145        encoding: Encoding::from_reader_with_ctx(reader, deku::ctx::Endian::Little)?,
146        color_model: ColorModel::from_reader_with_ctx(reader, deku::ctx::Endian::Little)?,
147        metadata: CSIMetadata::from_reader_with_ctx(reader, deku::ctx::Endian::Little)?,
148        tlv_length: read_u32(reader)?,
149        bitmap_list: rendition::BitmapList::from_reader_with_ctx(
150            reader,
151            deku::ctx::Endian::Little,
152        )?,
153    })
154}
155
156fn read_magic<R: Read + Seek>(reader: &mut Reader<R>, expected: &[u8; 4]) -> Result<(), DekuError> {
157    let mut actual = [0_u8; 4];
158    reader.read_bytes(4, &mut actual, Order::default())?;
159    if &actual != expected {
160        return Err(DekuError::Parse(
161            format!(
162                "invalid CSI header magic: expected {:?}, got {:?}",
163                expected, actual
164            )
165            .into(),
166        ));
167    }
168    Ok(())
169}
170
171fn read_u32<R: Read + Seek>(reader: &mut Reader<R>) -> Result<u32, DekuError> {
172    u32::from_reader_with_ctx(reader, deku::ctx::Endian::Little)
173}
174
175fn read_payload_bytes<R: Read + Seek>(
176    reader: &mut Reader<R>,
177    len: u32,
178) -> Result<Vec<u8>, DekuError> {
179    let len = len as usize;
180    let mut bytes = vec![0_u8; len];
181    reader.read_bytes(len, &mut bytes, Order::default())?;
182    Ok(bytes)
183}
184
185fn payload_slice(reader: &mut Reader<BOMBlock>, len: u32) -> BOMResult<crate::PayloadBytes> {
186    let len = len as usize;
187    let slice = reader.as_mut().slice_at_current(len)?;
188    reader.bits_read = reader.bits_read.saturating_add(len.saturating_mul(8));
189    reader.leftover = None;
190    Ok(slice)
191}
192
193fn read_tlv_data<R: Read + Seek>(
194    reader: &mut Reader<R>,
195    len: u32,
196) -> Result<Vec<rendition::RenditionType>, DekuError> {
197    let bytes = read_payload_bytes(reader, len)?;
198    parse_tlv_data(&bytes)
199}
200
201fn read_tlv_data_from_bom(
202    reader: &mut Reader<BOMBlock>,
203    len: u32,
204) -> BOMResult<Vec<rendition::RenditionType>> {
205    let bytes = payload_slice(reader, len)?;
206    parse_tlv_data(bytes.as_slice()).map_err(BOMEror::from)
207}
208
209fn parse_tlv_data(bytes: &[u8]) -> Result<Vec<rendition::RenditionType>, DekuError> {
210    let mut cursor = Cursor::new(bytes);
211    let mut reader = Reader::new(&mut cursor);
212    let mut result = Vec::new();
213    while (reader.as_mut().position() as usize) < bytes.len() {
214        result.push(rendition::RenditionType::from_reader_with_ctx(
215            &mut reader,
216            deku::ctx::Endian::Little,
217        )?);
218    }
219    Ok(result)
220}
221
222fn bom_error_to_deku(err: BOMEror) -> DekuError {
223    match err {
224        BOMEror::ParseStruct(err) => err,
225        err => DekuError::Parse(err.to_string().into()),
226    }
227}
228
229#[derive(Debug, DekuRead)]
230#[deku(endian = "little", ctx = "endian: deku::ctx::Endian")]
231pub struct CSIMetadata {
232    pub modification_time: u32,
233    pub layout_type: rendition::LayoutType,
234    #[deku(bytes_read = "128", map = "crate::deku_read_str")]
235    pub name: String,
236}
237
238#[derive(Debug, Clone, PartialEq, Eq, DekuRead)]
239#[deku(id_type = "u32", endian = "little", ctx = "endian: deku::ctx::Endian")]
240pub enum ColorSpace {
241    #[deku(id = 1)]
242    SRGB,
243    #[deku(id = 2)]
244    GrayGamma2_2,
245    #[deku(id = 3)]
246    DisplayP3,
247    #[deku(id = 4)]
248    ExtendedRangeSRGB,
249    #[deku(id = 5)]
250    ExtendedLinearSRGB,
251    #[deku(id = 6)]
252    ExtendedGray,
253
254    #[deku(id = 257)]
255    SystemSRGB,
256
257    #[deku(id_pat = "_")]
258    Unknown { tag: u32 },
259}
260
261#[derive(Debug, Clone, Copy, PartialEq, Eq, DekuRead)]
262#[deku(id_type = "u32", endian = "little", ctx = "endian: deku::ctx::Endian")]
263pub enum ColorModel {
264    #[deku(id = 0)]
265    None,
266    #[deku(id = 1)]
267    RGB,
268    #[deku(id = 2)]
269    Monochrome,
270    #[deku(id = 3)]
271    RGB0, // unknown
272    #[deku(id = 4)]
273    RGBP3,
274
275    #[deku(id_pat = "_")]
276    Unknown { tag: u32 },
277}
278
279#[derive(Debug, PartialEq, Eq, Clone, Copy, DekuRead)]
280#[deku(
281    id_type = "[u8; 4]",
282    endian = "little",
283    ctx = "endian: deku::ctx::Endian"
284)]
285pub enum Encoding {
286    #[deku(id = "[0, 0, 0, 0]")]
287    None,
288    #[deku(id = b"BGRA")]
289    ARGB,
290    #[deku(id = b"ATAD")]
291    Data,
292    #[deku(id = b"YARG")]
293    GRAY,
294    #[deku(id = b"GEPJ")]
295    JPEG,
296    #[deku(id = b" FDP")]
297    PDF,
298    #[deku(id = b"PBEW")]
299    WEBP,
300    #[deku(id = b"WBGR")]
301    ARGB16,
302    #[deku(id = b"61AG")]
303    GA16,
304    #[deku(id = b" 8AG")]
305    GA8,
306    #[deku(id = b"5BGR")]
307    RGB5,
308    #[deku(id = b" GVS")]
309    SVG,
310    #[deku(id = b"FIEH")]
311    HEIF,
312
313    #[deku(id_pat = "_")]
314    Unknown { tag: [u8; 4] },
315}