jxl_bitstream/container/
box_header.rs

1use crate::Error;
2
3/// Box header used in JPEG XL containers.
4#[derive(Debug, Clone)]
5pub struct ContainerBoxHeader {
6    pub(super) ty: ContainerBoxType,
7    box_size: Option<u64>,
8    is_last: bool,
9}
10
11/// Result of parsing container box header.
12pub enum HeaderParseResult {
13    /// Box header is read successfully.
14    Done {
15        header: ContainerBoxHeader,
16        header_size: usize,
17    },
18    /// Parser needs more data to read a header.
19    NeedMoreData,
20}
21
22impl ContainerBoxHeader {
23    pub(super) fn parse(buf: &[u8]) -> Result<HeaderParseResult, Error> {
24        let (tbox, box_size, header_size) = match *buf {
25            #[rustfmt::skip]
26            [0, 0, 0, 1, t0, t1, t2, t3, s0, s1, s2, s3, s4, s5, s6, s7, ..] => {
27                let xlbox = u64::from_be_bytes([s0, s1, s2, s3, s4, s5, s6, s7]);
28                let tbox = ContainerBoxType([t0, t1, t2, t3]);
29                let xlbox = xlbox.checked_sub(16).ok_or(Error::InvalidBox)?;
30                (tbox, Some(xlbox), 16)
31            }
32            [s0, s1, s2, s3, t0, t1, t2, t3, ..] => {
33                let sbox = u32::from_be_bytes([s0, s1, s2, s3]);
34                let tbox = ContainerBoxType([t0, t1, t2, t3]);
35                let sbox = if sbox == 0 {
36                    None
37                } else if let Some(sbox) = sbox.checked_sub(8) {
38                    Some(sbox as u64)
39                } else {
40                    return Err(Error::InvalidBox);
41                };
42                (tbox, sbox, 8)
43            }
44            _ => return Ok(HeaderParseResult::NeedMoreData),
45        };
46        let is_last = box_size.is_none();
47
48        let header = Self {
49            ty: tbox,
50            box_size,
51            is_last,
52        };
53        Ok(HeaderParseResult::Done {
54            header,
55            header_size,
56        })
57    }
58}
59
60impl ContainerBoxHeader {
61    #[inline]
62    pub fn box_type(&self) -> ContainerBoxType {
63        self.ty
64    }
65
66    #[inline]
67    pub fn box_size(&self) -> Option<u64> {
68        self.box_size
69    }
70
71    #[inline]
72    pub fn is_last(&self) -> bool {
73        self.is_last
74    }
75}
76
77/// Type of JPEG XL container box.
78///
79/// Known types are defined as associated consts.
80#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
81pub struct ContainerBoxType(pub [u8; 4]);
82
83impl ContainerBoxType {
84    /// JPEG XL signature box.
85    pub const JXL: Self = Self(*b"JXL ");
86
87    /// JPEG XL file type box.
88    pub const FILE_TYPE: Self = Self(*b"ftyp");
89
90    /// JPEG XL level box.
91    pub const JXL_LEVEL: Self = Self(*b"jxll");
92
93    /// JUMBF box.
94    pub const JUMBF: Self = Self(*b"jumb");
95
96    /// Exif box.
97    pub const EXIF: Self = Self(*b"Exif");
98
99    /// XML box, mainly for storing XMP metadata.
100    pub const XML: Self = Self(*b"xml ");
101
102    /// Brotli-compressed box.
103    pub const BROTLI_COMPRESSED: Self = Self(*b"brob");
104
105    /// Frame index box.
106    pub const FRAME_INDEX: Self = Self(*b"jxli");
107
108    /// JPEG XL codestream box.
109    pub const CODESTREAM: Self = Self(*b"jxlc");
110
111    /// JPEG XL partial codestream box.
112    pub const PARTIAL_CODESTREAM: Self = Self(*b"jxlp");
113
114    /// JPEG bistream reconstruction data box.
115    pub const JPEG_RECONSTRUCTION: Self = Self(*b"jbrd");
116
117    /// HDR gain map box.
118    pub const HDR_GAIN_MAP: Self = Self(*b"jhgm");
119}