1use std::io::Write;
2
3use brotli_decompressor::DecompressorWriter;
4use jxl_bitstream::container::box_header::ContainerBoxType;
5use jxl_bitstream::ParseEvent;
6
7use crate::Result;
8
9mod exif;
10mod jbrd;
11
12pub use exif::*;
13pub use jbrd::*;
14
15#[derive(Debug, Default)]
16pub struct AuxBoxReader {
17 data: DataKind,
18 done: bool,
19}
20
21#[derive(Default)]
22enum DataKind {
23 #[default]
24 Init,
25 NoData,
26 Raw(Vec<u8>),
27 Brotli(Box<DecompressorWriter<Vec<u8>>>),
28}
29
30impl std::fmt::Debug for DataKind {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 match self {
33 Self::Init => write!(f, "Init"),
34 Self::NoData => write!(f, "NoData"),
35 Self::Raw(buf) => f
36 .debug_tuple("Raw")
37 .field(&format_args!("{} byte(s)", buf.len()))
38 .finish(),
39 Self::Brotli(_) => f.debug_tuple("Brotli").finish(),
40 }
41 }
42}
43
44impl AuxBoxReader {
45 pub(super) fn new() -> Self {
46 Self::default()
47 }
48
49 pub(super) fn ensure_raw(&mut self) {
50 if self.done {
51 return;
52 }
53
54 match self.data {
55 DataKind::Init => {
56 self.data = DataKind::Raw(Vec::new());
57 }
58 DataKind::NoData | DataKind::Brotli(_) => {
59 panic!();
60 }
61 DataKind::Raw(_) => {}
62 }
63 }
64
65 pub(super) fn ensure_brotli(&mut self) -> Result<()> {
66 if self.done {
67 return Ok(());
68 }
69
70 match self.data {
71 DataKind::Init => {
72 let writer = DecompressorWriter::new(Vec::<u8>::new(), 4096);
73 self.data = DataKind::Brotli(Box::new(writer));
74 }
75 DataKind::NoData | DataKind::Raw(_) => {
76 panic!();
77 }
78 DataKind::Brotli(_) => {}
79 }
80 Ok(())
81 }
82}
83
84impl AuxBoxReader {
85 pub fn feed_data(&mut self, data: &[u8]) -> Result<()> {
86 if self.done {
87 return Err(std::io::Error::new(
88 std::io::ErrorKind::InvalidData,
89 "cannot feed into finalized box",
90 )
91 .into());
92 }
93
94 match self.data {
95 DataKind::Init => {
96 self.data = DataKind::Raw(data.to_vec());
97 }
98 DataKind::NoData => {
99 unreachable!();
100 }
101 DataKind::Raw(ref mut buf) => {
102 buf.extend_from_slice(data);
103 }
104 DataKind::Brotli(ref mut writer) => {
105 writer.write_all(data)?;
106 }
107 }
108 Ok(())
109 }
110
111 pub fn finalize(&mut self) -> Result<()> {
112 if self.done {
113 return Ok(());
114 }
115
116 if let DataKind::Brotli(ref mut writer) = self.data {
117 writer.flush()?;
118 writer.close()?;
119 }
120
121 match std::mem::replace(&mut self.data, DataKind::NoData) {
122 DataKind::Init | DataKind::NoData => {}
123 DataKind::Raw(buf) => self.data = DataKind::Raw(buf),
124 DataKind::Brotli(writer) => {
125 let inner = writer.into_inner().inspect_err(|_| {
126 tracing::warn!("Brotli decompressor reported an error");
127 });
128 let buf = inner.unwrap_or_else(|buf| buf);
129 self.data = DataKind::Raw(buf);
130 }
131 }
132
133 self.done = true;
134 Ok(())
135 }
136}
137
138impl AuxBoxReader {
139 pub fn is_done(&self) -> bool {
140 self.done
141 }
142
143 pub fn data(&self) -> AuxBoxData<&[u8]> {
144 if !self.is_done() {
145 return AuxBoxData::Decoding;
146 }
147
148 match &self.data {
149 DataKind::Init | DataKind::Brotli(_) => AuxBoxData::Decoding,
150 DataKind::NoData => AuxBoxData::NotFound,
151 DataKind::Raw(buf) => AuxBoxData::Data(buf),
152 }
153 }
154}
155
156pub enum AuxBoxData<T> {
158 Data(T),
160 Decoding,
162 NotFound,
164}
165
166impl<T> std::fmt::Debug for AuxBoxData<T> {
167 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168 match self {
169 Self::Data(_) => write!(f, "Data(_)"),
170 Self::Decoding => write!(f, "Decoding"),
171 Self::NotFound => write!(f, "NotFound"),
172 }
173 }
174}
175
176impl<T> AuxBoxData<T> {
177 pub fn has_data(&self) -> bool {
178 matches!(self, Self::Data(_))
179 }
180
181 pub fn is_decoding(&self) -> bool {
182 matches!(self, Self::Decoding)
183 }
184
185 pub fn is_not_found(&self) -> bool {
186 matches!(self, Self::NotFound)
187 }
188
189 pub fn unwrap(self) -> T {
190 let Self::Data(x) = self else {
191 panic!("cannot unwrap `AuxBoxData` which doesn't have any data");
192 };
193 x
194 }
195
196 pub fn unwrap_or(self, or: T) -> T {
197 match self {
198 Self::Data(x) => x,
199 _ => or,
200 }
201 }
202
203 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> AuxBoxData<U> {
204 match self {
205 Self::Data(x) => AuxBoxData::Data(f(x)),
206 Self::Decoding => AuxBoxData::Decoding,
207 Self::NotFound => AuxBoxData::NotFound,
208 }
209 }
210
211 pub fn as_ref(&self) -> AuxBoxData<&T> {
212 match self {
213 Self::Data(x) => AuxBoxData::Data(x),
214 Self::Decoding => AuxBoxData::Decoding,
215 Self::NotFound => AuxBoxData::NotFound,
216 }
217 }
218}
219
220impl<T, E> AuxBoxData<std::result::Result<T, E>> {
221 pub fn transpose(self) -> std::result::Result<AuxBoxData<T>, E> {
222 match self {
223 Self::Data(Ok(x)) => Ok(AuxBoxData::Data(x)),
224 Self::Data(Err(e)) => Err(e),
225 Self::Decoding => Ok(AuxBoxData::Decoding),
226 Self::NotFound => Ok(AuxBoxData::NotFound),
227 }
228 }
229}
230
231#[derive(Debug)]
233pub struct AuxBoxList {
234 boxes: Vec<(ContainerBoxType, AuxBoxReader)>,
235 jbrd: Jbrd,
236 current_box_ty: Option<ContainerBoxType>,
237 current_box: AuxBoxReader,
238 last_box: bool,
239}
240
241impl AuxBoxList {
242 pub(super) fn new() -> Self {
243 Self {
244 boxes: Vec::new(),
245 jbrd: Jbrd::new(),
246 current_box_ty: None,
247 current_box: AuxBoxReader::new(),
248 last_box: false,
249 }
250 }
251
252 pub(super) fn handle_event(&mut self, event: ParseEvent) -> Result<()> {
253 match event {
254 ParseEvent::BitstreamKind(_) => {}
255 ParseEvent::Codestream(_) => {}
256 ParseEvent::NoMoreAuxBox => {
257 self.current_box_ty = None;
258 self.last_box = true;
259 }
260 ParseEvent::AuxBoxStart {
261 ty,
262 brotli_compressed,
263 last_box,
264 } => {
265 self.current_box_ty = Some(ty);
266 if ty != ContainerBoxType::JPEG_RECONSTRUCTION {
267 if brotli_compressed {
268 self.current_box.ensure_brotli()?;
269 } else {
270 self.current_box.ensure_raw();
271 }
272 }
273 self.last_box = last_box;
274 }
275 ParseEvent::AuxBoxData(ty, buf) => {
276 self.current_box_ty = Some(ty);
277 if ty == ContainerBoxType::JPEG_RECONSTRUCTION {
278 self.jbrd.feed_bytes(buf)?;
279 } else {
280 self.current_box.feed_data(buf)?;
281 }
282 }
283 ParseEvent::AuxBoxEnd(ty) => {
284 self.current_box_ty = Some(ty);
285 self.finalize()?;
286 }
287 }
288 Ok(())
289 }
290
291 fn finalize(&mut self) -> Result<()> {
292 match self.current_box_ty {
293 Some(ContainerBoxType::JPEG_RECONSTRUCTION) => {
294 self.jbrd.finalize()?;
295 }
296 Some(ty) => {
297 self.current_box.finalize()?;
298 let finished_box = std::mem::replace(&mut self.current_box, AuxBoxReader::new());
299 self.boxes.push((ty, finished_box));
300 }
301 None => {
302 return Ok(());
303 }
304 }
305
306 self.current_box_ty = None;
307 Ok(())
308 }
309
310 pub(super) fn eof(&mut self) -> Result<()> {
311 self.finalize()?;
312 self.last_box = true;
313 Ok(())
314 }
315}
316
317impl AuxBoxList {
318 pub(crate) fn jbrd(&self) -> AuxBoxData<&jxl_jbr::JpegBitstreamData> {
319 if let Some(data) = self.jbrd.data() {
320 AuxBoxData::Data(data)
321 } else if self.last_box
322 && self.current_box_ty != Some(ContainerBoxType::JPEG_RECONSTRUCTION)
323 {
324 AuxBoxData::NotFound
325 } else {
326 AuxBoxData::Decoding
327 }
328 }
329
330 fn first_of_type(&self, ty: ContainerBoxType) -> AuxBoxData<&[u8]> {
331 let maybe = self.boxes.iter().find(|&&(ty_to_test, _)| ty_to_test == ty);
332 let data = maybe.map(|(_, b)| b.data());
333
334 if let Some(data) = data {
335 data
336 } else if self.last_box && self.current_box_ty != Some(ty) {
337 AuxBoxData::NotFound
338 } else {
339 AuxBoxData::Decoding
340 }
341 }
342
343 pub fn first_exif(&self) -> Result<AuxBoxData<RawExif>> {
345 let exif = self.first_of_type(ContainerBoxType::EXIF);
346 exif.map(RawExif::new).transpose()
347 }
348
349 pub fn first_xml(&self) -> AuxBoxData<&[u8]> {
351 self.first_of_type(ContainerBoxType::XML)
352 }
353}