Skip to main content

stegano_f5_jpeg_decoder/
parser.rs

1use crate::error::{Error, Result, UnsupportedFeature};
2use crate::huffman::{HuffmanTable, HuffmanTableClass};
3use crate::marker::Marker;
4use crate::marker::Marker::*;
5use crate::{read_u8, read_u16_from_be};
6use alloc::borrow::ToOwned;
7use alloc::vec::Vec;
8use alloc::{format, vec};
9use core::ops::{self, Range};
10use std::io::{self, Read};
11
12#[derive(Clone, Copy, Debug, PartialEq)]
13pub struct Dimensions {
14    pub width: u16,
15    pub height: u16,
16}
17
18/// The entropy coding method used in the JPEG image.
19#[derive(Clone, Copy, Debug, PartialEq)]
20pub enum EntropyCoding {
21    /// Huffman coding (most common)
22    Huffman,
23    /// Arithmetic coding
24    Arithmetic,
25}
26
27/// Represents the coding process of an image.
28#[derive(Clone, Copy, Debug, PartialEq)]
29pub enum CodingProcess {
30    /// Sequential Discrete Cosine Transform
31    DctSequential,
32    /// Progressive Discrete Cosine Transform
33    DctProgressive,
34    /// Lossless
35    Lossless,
36}
37
38// Table H.1
39#[derive(Clone, Copy, Debug, PartialEq)]
40pub enum Predictor {
41    NoPrediction,
42    Ra,
43    Rb,
44    Rc,
45    RaRbRc1, // Ra + Rb - Rc
46    RaRbRc2, // Ra + ((Rb - Rc) >> 1)
47    RaRbRc3, // Rb + ((Ra - Rb) >> 1)
48    RaRb,    // (Ra + Rb)/2
49}
50
51/// Information from the JPEG frame header (SOF marker).
52#[derive(Clone)]
53pub struct FrameInfo {
54    /// Whether this is a baseline DCT frame (SOF0).
55    pub is_baseline: bool,
56    /// Whether this is a differential frame.
57    pub is_differential: bool,
58    /// The coding process (sequential, progressive, or lossless).
59    pub coding_process: CodingProcess,
60    /// The entropy coding method (Huffman or arithmetic).
61    pub entropy_coding: EntropyCoding,
62    /// Sample precision in bits (typically 8 or 12).
63    pub precision: u8,
64    /// The original image dimensions.
65    pub image_size: Dimensions,
66    /// The output dimensions (may differ due to scaling).
67    pub output_size: Dimensions,
68    /// The MCU (Minimum Coded Unit) grid dimensions.
69    pub mcu_size: Dimensions,
70    /// The image components (Y, Cb, Cr, etc.).
71    pub components: Vec<Component>,
72}
73
74#[derive(Debug)]
75pub struct ScanInfo {
76    pub component_indices: Vec<usize>,
77    pub dc_table_indices: Vec<usize>,
78    pub ac_table_indices: Vec<usize>,
79
80    pub spectral_selection: Range<u8>,
81    pub predictor_selection: Predictor, // for lossless
82    pub successive_approximation_high: u8,
83    pub successive_approximation_low: u8,
84    pub point_transform: u8, // for lossless
85}
86
87/// A JPEG image component (e.g., Y, Cb, Cr).
88#[derive(Clone, Debug)]
89pub struct Component {
90    /// Component identifier (1=Y, 2=Cb, 3=Cr in JFIF).
91    pub identifier: u8,
92    /// Horizontal sampling factor (1-4).
93    pub horizontal_sampling_factor: u8,
94    /// Vertical sampling factor (1-4).
95    pub vertical_sampling_factor: u8,
96    /// Index of the quantization table used by this component.
97    pub quantization_table_index: usize,
98    /// DCT scaling factor.
99    pub dct_scale: usize,
100    /// Component dimensions in pixels.
101    pub size: Dimensions,
102    /// Component dimensions in 8x8 blocks.
103    pub block_size: Dimensions,
104}
105
106#[derive(Debug)]
107pub enum AppData {
108    Adobe(AdobeColorTransform),
109    Jfif,
110    Avi1,
111    Icc(IccChunk),
112    Exif(Vec<u8>),
113    Xmp(Vec<u8>),
114    Psir(Vec<u8>),
115}
116
117// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe
118#[allow(clippy::upper_case_acronyms)]
119#[derive(Clone, Copy, Debug, PartialEq)]
120pub enum AdobeColorTransform {
121    // RGB or CMYK
122    Unknown,
123    YCbCr,
124    // YCbCrK
125    YCCK,
126}
127#[derive(Debug)]
128pub struct IccChunk {
129    pub num_markers: u8,
130    pub seq_no: u8,
131    pub data: Vec<u8>,
132}
133
134impl FrameInfo {
135    pub(crate) fn update_idct_size(&mut self, idct_size: usize) -> Result<()> {
136        for component in &mut self.components {
137            component.dct_scale = idct_size;
138        }
139
140        update_component_sizes(self.image_size, &mut self.components)?;
141
142        self.output_size = Dimensions {
143            width: (self.image_size.width as f32 * idct_size as f32 / 8.0).ceil() as u16,
144            height: (self.image_size.height as f32 * idct_size as f32 / 8.0).ceil() as u16,
145        };
146
147        Ok(())
148    }
149}
150
151fn read_length<R: Read>(reader: &mut R, marker: Marker) -> Result<usize> {
152    assert!(marker.has_length());
153
154    // length is including itself.
155    let length = usize::from(read_u16_from_be(reader)?);
156
157    if length < 2 {
158        return Err(Error::Format(format!(
159            "encountered {:?} with invalid length {}",
160            marker, length
161        )));
162    }
163
164    Ok(length - 2)
165}
166
167fn skip_bytes<R: Read>(reader: &mut R, length: usize) -> Result<()> {
168    let length = length as u64;
169    let to_skip = &mut reader.by_ref().take(length);
170    let copied = io::copy(to_skip, &mut io::sink())?;
171    if copied < length {
172        Err(Error::Io(io::ErrorKind::UnexpectedEof.into()))
173    } else {
174        Ok(())
175    }
176}
177
178// Section B.2.2
179pub fn parse_sof<R: Read>(reader: &mut R, marker: Marker) -> Result<FrameInfo> {
180    let length = read_length(reader, marker)?;
181
182    if length <= 6 {
183        return Err(Error::Format("invalid length in SOF".to_owned()));
184    }
185
186    let is_baseline = marker == SOF(0);
187    let is_differential = match marker {
188        SOF(0..=3) | SOF(9..=11) => false,
189        SOF(5..=7) | SOF(13..=15) => true,
190        _ => panic!(),
191    };
192    let coding_process = match marker {
193        SOF(0) | SOF(1) | SOF(5) | SOF(9) | SOF(13) => CodingProcess::DctSequential,
194        SOF(2) | SOF(6) | SOF(10) | SOF(14) => CodingProcess::DctProgressive,
195        SOF(3) | SOF(7) | SOF(11) | SOF(15) => CodingProcess::Lossless,
196        _ => panic!(),
197    };
198    let entropy_coding = match marker {
199        SOF(0..=3) | SOF(5..=7) => EntropyCoding::Huffman,
200        SOF(9..=11) | SOF(13..=15) => EntropyCoding::Arithmetic,
201        _ => panic!(),
202    };
203
204    let precision = read_u8(reader)?;
205
206    match precision {
207        8 => {}
208        12 => {
209            if is_baseline {
210                return Err(Error::Format(
211                    "12 bit sample precision is not allowed in baseline".to_owned(),
212                ));
213            }
214        }
215        _ => {
216            if coding_process != CodingProcess::Lossless || precision > 16 {
217                return Err(Error::Format(format!(
218                    "invalid precision {} in frame header",
219                    precision
220                )));
221            }
222        }
223    }
224
225    let height = read_u16_from_be(reader)?;
226    let width = read_u16_from_be(reader)?;
227
228    // height:
229    // "Value 0 indicates that the number of lines shall be defined by the DNL marker and
230    //     parameters at the end of the first scan (see B.2.5)."
231    if height == 0 {
232        return Err(Error::Unsupported(UnsupportedFeature::DNL));
233    }
234
235    if width == 0 {
236        return Err(Error::Format("zero width in frame header".to_owned()));
237    }
238
239    let component_count = read_u8(reader)?;
240
241    if component_count == 0 {
242        return Err(Error::Format(
243            "zero component count in frame header".to_owned(),
244        ));
245    }
246    if coding_process == CodingProcess::DctProgressive && component_count > 4 {
247        return Err(Error::Format(
248            "progressive frame with more than 4 components".to_owned(),
249        ));
250    }
251
252    if length != 6 + 3 * component_count as usize {
253        return Err(Error::Format("invalid length in SOF".to_owned()));
254    }
255
256    let mut components: Vec<Component> = Vec::with_capacity(component_count as usize);
257
258    for _ in 0..component_count {
259        let identifier = read_u8(reader)?;
260
261        // Each component's identifier must be unique.
262        if components.iter().any(|c| c.identifier == identifier) {
263            return Err(Error::Format(format!(
264                "duplicate frame component identifier {}",
265                identifier
266            )));
267        }
268
269        let byte = read_u8(reader)?;
270        let horizontal_sampling_factor = byte >> 4;
271        let vertical_sampling_factor = byte & 0x0f;
272
273        if horizontal_sampling_factor == 0 || horizontal_sampling_factor > 4 {
274            return Err(Error::Format(format!(
275                "invalid horizontal sampling factor {}",
276                horizontal_sampling_factor
277            )));
278        }
279        if vertical_sampling_factor == 0 || vertical_sampling_factor > 4 {
280            return Err(Error::Format(format!(
281                "invalid vertical sampling factor {}",
282                vertical_sampling_factor
283            )));
284        }
285
286        let quantization_table_index = read_u8(reader)?;
287
288        if quantization_table_index > 3
289            || (coding_process == CodingProcess::Lossless && quantization_table_index != 0)
290        {
291            return Err(Error::Format(format!(
292                "invalid quantization table index {}",
293                quantization_table_index
294            )));
295        }
296
297        components.push(Component {
298            identifier,
299            horizontal_sampling_factor,
300            vertical_sampling_factor,
301            quantization_table_index: quantization_table_index as usize,
302            dct_scale: 8,
303            size: Dimensions {
304                width: 0,
305                height: 0,
306            },
307            block_size: Dimensions {
308                width: 0,
309                height: 0,
310            },
311        });
312    }
313
314    let mcu_size = update_component_sizes(Dimensions { width, height }, &mut components)?;
315
316    Ok(FrameInfo {
317        is_baseline,
318        is_differential,
319        coding_process,
320        entropy_coding,
321        precision,
322        image_size: Dimensions { width, height },
323        output_size: Dimensions { width, height },
324        mcu_size,
325        components,
326    })
327}
328
329/// Returns ceil(x/y), requires x>0
330fn ceil_div(x: u32, y: u32) -> Result<u16> {
331    if x == 0 || y == 0 {
332        // TODO Determine how this error is reached. Can we validate input
333        // earlier and error out then?
334        return Err(Error::Format("invalid dimensions".to_owned()));
335    }
336    Ok((1 + ((x - 1) / y)) as u16)
337}
338
339fn update_component_sizes(size: Dimensions, components: &mut [Component]) -> Result<Dimensions> {
340    let h_max = components
341        .iter()
342        .map(|c| c.horizontal_sampling_factor)
343        .max()
344        .unwrap() as u32;
345    let v_max = components
346        .iter()
347        .map(|c| c.vertical_sampling_factor)
348        .max()
349        .unwrap() as u32;
350
351    let mcu_size = Dimensions {
352        width: ceil_div(size.width as u32, h_max * 8)?,
353        height: ceil_div(size.height as u32, v_max * 8)?,
354    };
355
356    for component in components {
357        component.size.width = ceil_div(
358            size.width as u32
359                * component.horizontal_sampling_factor as u32
360                * component.dct_scale as u32,
361            h_max * 8,
362        )?;
363        component.size.height = ceil_div(
364            size.height as u32
365                * component.vertical_sampling_factor as u32
366                * component.dct_scale as u32,
367            v_max * 8,
368        )?;
369
370        component.block_size.width = mcu_size.width * component.horizontal_sampling_factor as u16;
371        component.block_size.height = mcu_size.height * component.vertical_sampling_factor as u16;
372    }
373
374    Ok(mcu_size)
375}
376
377#[test]
378fn test_update_component_sizes() {
379    let mut components = [Component {
380        identifier: 1,
381        horizontal_sampling_factor: 2,
382        vertical_sampling_factor: 2,
383        quantization_table_index: 0,
384        dct_scale: 8,
385        size: Dimensions {
386            width: 0,
387            height: 0,
388        },
389        block_size: Dimensions {
390            width: 0,
391            height: 0,
392        },
393    }];
394    let mcu = update_component_sizes(
395        Dimensions {
396            width: 800,
397            height: 280,
398        },
399        &mut components,
400    )
401    .unwrap();
402    assert_eq!(
403        mcu,
404        Dimensions {
405            width: 50,
406            height: 18
407        }
408    );
409    assert_eq!(
410        components[0].block_size,
411        Dimensions {
412            width: 100,
413            height: 36
414        }
415    );
416    assert_eq!(
417        components[0].size,
418        Dimensions {
419            width: 800,
420            height: 280
421        }
422    );
423}
424
425// Section B.2.3
426pub fn parse_sos<R: Read>(reader: &mut R, frame: &FrameInfo) -> Result<ScanInfo> {
427    let length = read_length(reader, SOS)?;
428    if 0 == length {
429        return Err(Error::Format("zero length in SOS".to_owned()));
430    }
431
432    let component_count = read_u8(reader)?;
433
434    if component_count == 0 || component_count > 4 {
435        return Err(Error::Format(format!(
436            "invalid component count {} in scan header",
437            component_count
438        )));
439    }
440
441    if length != 4 + 2 * component_count as usize {
442        return Err(Error::Format("invalid length in SOS".to_owned()));
443    }
444
445    let mut component_indices = Vec::with_capacity(component_count as usize);
446    let mut dc_table_indices = Vec::with_capacity(component_count as usize);
447    let mut ac_table_indices = Vec::with_capacity(component_count as usize);
448
449    for _ in 0..component_count {
450        let identifier = read_u8(reader)?;
451
452        let component_index = match frame
453            .components
454            .iter()
455            .position(|c| c.identifier == identifier)
456        {
457            Some(value) => value,
458            None => {
459                return Err(Error::Format(format!(
460                    "scan component identifier {} does not match any of the component identifiers defined in the frame",
461                    identifier
462                )));
463            }
464        };
465
466        // Each of the scan's components must be unique.
467        if component_indices.contains(&component_index) {
468            return Err(Error::Format(format!(
469                "duplicate scan component identifier {}",
470                identifier
471            )));
472        }
473
474        // "... the ordering in the scan header shall follow the ordering in the frame header."
475        if component_index < *component_indices.iter().max().unwrap_or(&0) {
476            return Err(Error::Format(
477                "the scan component order does not follow the order in the frame header".to_owned(),
478            ));
479        }
480
481        let byte = read_u8(reader)?;
482        let dc_table_index = byte >> 4;
483        let ac_table_index = byte & 0x0f;
484
485        if dc_table_index > 3 || (frame.is_baseline && dc_table_index > 1) {
486            return Err(Error::Format(format!(
487                "invalid dc table index {}",
488                dc_table_index
489            )));
490        }
491        if ac_table_index > 3 || (frame.is_baseline && ac_table_index > 1) {
492            return Err(Error::Format(format!(
493                "invalid ac table index {}",
494                ac_table_index
495            )));
496        }
497
498        component_indices.push(component_index);
499        dc_table_indices.push(dc_table_index as usize);
500        ac_table_indices.push(ac_table_index as usize);
501    }
502
503    let blocks_per_mcu = component_indices
504        .iter()
505        .map(|&i| {
506            frame.components[i].horizontal_sampling_factor as u32
507                * frame.components[i].vertical_sampling_factor as u32
508        })
509        .fold(0, ops::Add::add);
510
511    if component_count > 1 && blocks_per_mcu > 10 {
512        return Err(Error::Format(
513            "scan with more than one component and more than 10 blocks per MCU".to_owned(),
514        ));
515    }
516
517    // Also utilized as 'Predictor' in lossless coding, as MEAN in JPEG-LS etc.
518    let spectral_selection_start = read_u8(reader)?;
519    // Also utilized as ILV parameter in JPEG-LS.
520    let mut spectral_selection_end = read_u8(reader)?;
521
522    let byte = read_u8(reader)?;
523    let successive_approximation_high = byte >> 4;
524    let successive_approximation_low = byte & 0x0f;
525
526    // The Differential Pulse-Mode prediction used (similar to png). Only utilized in Lossless
527    // coding. Don't confuse with the JPEG-LS parameter coded using the same scan info portion.
528    let predictor_selection;
529    let point_transform = successive_approximation_low;
530
531    if point_transform >= frame.precision {
532        return Err(Error::Format(
533            "invalid point transform, must be less than the frame precision".to_owned(),
534        ));
535    }
536
537    if frame.coding_process == CodingProcess::DctProgressive {
538        predictor_selection = Predictor::NoPrediction;
539        if spectral_selection_end > 63
540            || spectral_selection_start > spectral_selection_end
541            || (spectral_selection_start == 0 && spectral_selection_end != 0)
542        {
543            return Err(Error::Format(format!(
544                "invalid spectral selection parameters: ss={}, se={}",
545                spectral_selection_start, spectral_selection_end
546            )));
547        }
548        if spectral_selection_start != 0 && component_count != 1 {
549            return Err(Error::Format(
550                "spectral selection scan with AC coefficients can't have more than one component"
551                    .to_owned(),
552            ));
553        }
554
555        if successive_approximation_high > 13 || successive_approximation_low > 13 {
556            return Err(Error::Format(format!(
557                "invalid successive approximation parameters: ah={}, al={}",
558                successive_approximation_high, successive_approximation_low
559            )));
560        }
561
562        // Section G.1.1.1.2
563        // "Each scan which follows the first scan for a given band progressively improves
564        //     the precision of the coefficients by one bit, until full precision is reached."
565        if successive_approximation_high != 0
566            && successive_approximation_high != successive_approximation_low + 1
567        {
568            return Err(Error::Format(
569                "successive approximation scan with more than one bit of improvement".to_owned(),
570            ));
571        }
572    } else if frame.coding_process == CodingProcess::Lossless {
573        if spectral_selection_end != 0 {
574            return Err(Error::Format(
575                "spectral selection end shall be zero in lossless scan".to_owned(),
576            ));
577        }
578        if successive_approximation_high != 0 {
579            return Err(Error::Format(
580                "successive approximation high shall be zero in lossless scan".to_owned(),
581            ));
582        }
583        predictor_selection = match spectral_selection_start {
584            0 => Predictor::NoPrediction,
585            1 => Predictor::Ra,
586            2 => Predictor::Rb,
587            3 => Predictor::Rc,
588            4 => Predictor::RaRbRc1,
589            5 => Predictor::RaRbRc2,
590            6 => Predictor::RaRbRc3,
591            7 => Predictor::RaRb,
592            _ => {
593                return Err(Error::Format(format!(
594                    "invalid predictor selection value: {}",
595                    spectral_selection_start
596                )));
597            }
598        };
599    } else {
600        predictor_selection = Predictor::NoPrediction;
601        if spectral_selection_end == 0 {
602            spectral_selection_end = 63;
603        }
604        if spectral_selection_start != 0 || spectral_selection_end != 63 {
605            return Err(Error::Format(
606                "spectral selection is not allowed in non-progressive scan".to_owned(),
607            ));
608        }
609        if successive_approximation_high != 0 || successive_approximation_low != 0 {
610            return Err(Error::Format(
611                "successive approximation is not allowed in non-progressive scan".to_owned(),
612            ));
613        }
614    }
615
616    Ok(ScanInfo {
617        component_indices,
618        dc_table_indices,
619        ac_table_indices,
620        spectral_selection: Range {
621            start: spectral_selection_start,
622            end: spectral_selection_end + 1,
623        },
624        predictor_selection,
625        successive_approximation_high,
626        successive_approximation_low,
627        point_transform,
628    })
629}
630
631// Section B.2.4.1
632pub fn parse_dqt<R: Read>(reader: &mut R) -> Result<[Option<[u16; 64]>; 4]> {
633    let mut length = read_length(reader, DQT)?;
634    let mut tables = [None; 4];
635
636    // Each DQT segment may contain multiple quantization tables.
637    while length > 0 {
638        let byte = read_u8(reader)?;
639        let precision = (byte >> 4) as usize;
640        let index = (byte & 0x0f) as usize;
641
642        // The combination of 8-bit sample precision and 16-bit quantization tables is explicitly
643        // disallowed by the JPEG spec:
644        //     "An 8-bit DCT-based process shall not use a 16-bit precision quantization table."
645        //     "Pq: Quantization table element precision – Specifies the precision of the Qk
646        //      values. Value 0 indicates 8-bit Qk values; value 1 indicates 16-bit Qk values. Pq
647        //      shall be zero for 8 bit sample precision P (see B.2.2)."
648        // libjpeg allows this behavior though, and there are images in the wild using it. So to
649        // match libjpeg's behavior we are deviating from the JPEG spec here.
650        if precision > 1 {
651            return Err(Error::Format(format!(
652                "invalid precision {} in DQT",
653                precision
654            )));
655        }
656        if index > 3 {
657            return Err(Error::Format(format!(
658                "invalid destination identifier {} in DQT",
659                index
660            )));
661        }
662        if length < 65 + 64 * precision {
663            return Err(Error::Format("invalid length in DQT".to_owned()));
664        }
665
666        let mut table = [0u16; 64];
667
668        for item in table.iter_mut() {
669            *item = match precision {
670                0 => u16::from(read_u8(reader)?),
671                1 => read_u16_from_be(reader)?,
672                _ => unreachable!(),
673            };
674        }
675
676        if table.contains(&0) {
677            return Err(Error::Format(
678                "quantization table contains element with a zero value".to_owned(),
679            ));
680        }
681
682        tables[index] = Some(table);
683        length -= 65 + 64 * precision;
684    }
685
686    Ok(tables)
687}
688
689// Section B.2.4.2
690#[allow(clippy::type_complexity)]
691pub fn parse_dht<R: Read>(
692    reader: &mut R,
693    is_baseline: Option<bool>,
694) -> Result<(Vec<Option<HuffmanTable>>, Vec<Option<HuffmanTable>>)> {
695    let mut length = read_length(reader, DHT)?;
696    let mut dc_tables = vec![None, None, None, None];
697    let mut ac_tables = vec![None, None, None, None];
698
699    // Each DHT segment may contain multiple huffman tables.
700    while length > 17 {
701        let byte = read_u8(reader)?;
702        let class = byte >> 4;
703        let index = (byte & 0x0f) as usize;
704
705        if class != 0 && class != 1 {
706            return Err(Error::Format(format!("invalid class {} in DHT", class)));
707        }
708        if is_baseline == Some(true) && index > 1 {
709            return Err(Error::Format(
710                "a maximum of two huffman tables per class are allowed in baseline".to_owned(),
711            ));
712        }
713        if index > 3 {
714            return Err(Error::Format(format!(
715                "invalid destination identifier {} in DHT",
716                index
717            )));
718        }
719
720        let mut counts = [0u8; 16];
721        reader.read_exact(&mut counts)?;
722
723        let size = counts
724            .iter()
725            .map(|&val| val as usize)
726            .fold(0, ops::Add::add);
727
728        if size == 0 {
729            return Err(Error::Format(
730                "encountered table with zero length in DHT".to_owned(),
731            ));
732        } else if size > 256 {
733            return Err(Error::Format(
734                "encountered table with excessive length in DHT".to_owned(),
735            ));
736        } else if size > length - 17 {
737            return Err(Error::Format("invalid length in DHT".to_owned()));
738        }
739
740        let mut values = vec![0u8; size];
741        reader.read_exact(&mut values)?;
742
743        match class {
744            0 => {
745                dc_tables[index] = Some(HuffmanTable::new(&counts, &values, HuffmanTableClass::DC)?)
746            }
747            1 => {
748                ac_tables[index] = Some(HuffmanTable::new(&counts, &values, HuffmanTableClass::AC)?)
749            }
750            _ => unreachable!(),
751        }
752
753        length -= 17 + size;
754    }
755
756    if length != 0 {
757        return Err(Error::Format("invalid length in DHT".to_owned()));
758    }
759
760    Ok((dc_tables, ac_tables))
761}
762
763// Section B.2.4.4
764pub fn parse_dri<R: Read>(reader: &mut R) -> Result<u16> {
765    let length = read_length(reader, DRI)?;
766
767    if length != 2 {
768        return Err(Error::Format("DRI with invalid length".to_owned()));
769    }
770
771    Ok(read_u16_from_be(reader)?)
772}
773
774// Section B.2.4.5
775pub fn parse_com<R: Read>(reader: &mut R) -> Result<Vec<u8>> {
776    let length = read_length(reader, COM)?;
777    let mut buffer = vec![0u8; length];
778
779    reader.read_exact(&mut buffer)?;
780
781    Ok(buffer)
782}
783
784// Section B.2.4.6
785pub fn parse_app<R: Read>(reader: &mut R, marker: Marker) -> Result<Option<AppData>> {
786    let length = read_length(reader, marker)?;
787    let mut bytes_read = 0;
788    let mut result = None;
789
790    match marker {
791        APP(0) => {
792            if length >= 5 {
793                let mut buffer = [0u8; 5];
794                reader.read_exact(&mut buffer)?;
795                bytes_read = buffer.len();
796
797                // http://www.w3.org/Graphics/JPEG/jfif3.pdf
798                if buffer[0..5] == *b"JFIF\0" {
799                    result = Some(AppData::Jfif);
800                // https://sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#AVI1
801                } else if buffer[0..5] == *b"AVI1\0" {
802                    result = Some(AppData::Avi1);
803                }
804            }
805        }
806        APP(1) => {
807            let mut buffer = vec![0u8; length];
808            reader.read_exact(&mut buffer)?;
809            bytes_read = buffer.len();
810
811            // https://web.archive.org/web/20190624045241if_/http://www.cipa.jp:80/std/documents/e/DC-008-Translation-2019-E.pdf
812            // 4.5.4 Basic Structure of JPEG Compressed Data
813            if length >= 6 && buffer[0..6] == *b"Exif\x00\x00" {
814                result = Some(AppData::Exif(buffer[6..].to_vec()));
815            }
816            // XMP packet
817            // https://github.com/adobe/XMP-Toolkit-SDK/blob/main/docs/XMPSpecificationPart3.pdf
818            else if length >= 29 && buffer[0..29] == *b"http://ns.adobe.com/xap/1.0/\0" {
819                result = Some(AppData::Xmp(buffer[29..].to_vec()));
820            }
821        }
822        APP(2) => {
823            if length > 14 {
824                let mut buffer = [0u8; 14];
825                reader.read_exact(&mut buffer)?;
826                bytes_read = buffer.len();
827
828                // http://www.color.org/ICC_Minor_Revision_for_Web.pdf
829                // B.4 Embedding ICC profiles in JFIF files
830                if buffer[0..12] == *b"ICC_PROFILE\0" {
831                    let mut data = vec![0; length - bytes_read];
832                    reader.read_exact(&mut data)?;
833                    bytes_read += data.len();
834                    result = Some(AppData::Icc(IccChunk {
835                        seq_no: buffer[12],
836                        num_markers: buffer[13],
837                        data,
838                    }));
839                }
840            }
841        }
842        APP(13) => {
843            if length >= 14 {
844                let mut buffer = [0u8; 14];
845                reader.read_exact(&mut buffer)?;
846                bytes_read = buffer.len();
847
848                // PSIR (Photoshop)
849                // https://github.com/adobe/XMP-Toolkit-SDK/blob/main/docs/XMPSpecificationPart3.pdf
850                if buffer[0..14] == *b"Photoshop 3.0\0" {
851                    let mut data = vec![0; length - bytes_read];
852                    reader.read_exact(&mut data)?;
853                    bytes_read += data.len();
854                    result = Some(AppData::Psir(data));
855                }
856            }
857        }
858        APP(14) => {
859            if length >= 12 {
860                let mut buffer = [0u8; 12];
861                reader.read_exact(&mut buffer)?;
862                bytes_read = buffer.len();
863
864                // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe
865                if buffer[0..6] == *b"Adobe\0" {
866                    let color_transform = match buffer[11] {
867                        0 => AdobeColorTransform::Unknown,
868                        1 => AdobeColorTransform::YCbCr,
869                        2 => AdobeColorTransform::YCCK,
870                        _ => {
871                            return Err(Error::Format(
872                                "invalid color transform in adobe app segment".to_owned(),
873                            ));
874                        }
875                    };
876
877                    result = Some(AppData::Adobe(color_transform));
878                }
879            }
880        }
881        _ => {}
882    }
883
884    skip_bytes(reader, length - bytes_read)?;
885    Ok(result)
886}