exifsd/
scan_segment.rs

1use crate::*;
2use byteorder::{BigEndian, WriteBytesExt};
3use combine::{parser::*, *};
4use std::io;
5
6/// A Scan Segment is contains a segment of the JPEG data.
7#[derive(Copy, Clone, Debug, PartialEq, Eq)]
8pub struct ScanSegment<'a> {
9    /// Specifies which segment is encoded following this specifier.
10    pub specifier: &'a [u8],
11    /// The actual entropy-encoded data that makes up the image segment.
12    pub data: &'a [u8],
13}
14
15impl<'a> ScanSegment<'a> {
16    /// Parses out a Scan Segment, including the entropy-encoded data.
17    ///
18    /// ```
19    /// use exifsd::*;
20    /// use combine::*;
21    ///
22    /// let input = &[0xFF, 0xDA, 0x00, 0x02, 0x01, 0xFF, 0x00, 0x02, 0xFF, 0xFF, 0xD9][..];
23    /// let result = ScanSegment::parser().parse(input);
24    /// let expected = ScanSegment { specifier: &[], data: &[0x01, 0xFF, 0x00, 0x02, 0xFF] };
25    ///
26    /// // Note that the marker `[0xFF, 0xD9]` is not consumed.
27    /// assert_eq!(result, Ok((expected, &[0xFF, 0xD9][..])));
28    /// ```
29    pub fn parser<I: 'a>() -> impl Parser<Input = I, Output = ScanSegment<'a>> + 'a
30    where
31        I: RangeStream<Item = u8, Range = &'a [u8]>,
32        I::Error: ParseError<I::Item, I::Range, I::Position>,
33    {
34        MarkedData::parser(token(0xDA).expected("Start of Scan marker")).then(|md| {
35            segment_data().map(move |data| ScanSegment {
36                specifier: md.data,
37                data,
38            })
39        })
40    }
41
42    /// Writes the binary representation of the `ScanSegment` out to a file.
43    ///
44    /// ```
45    /// use exifsd::*;
46    /// use combine::*;
47    ///
48    /// let input = &[0xFF, 0xDA, 0x00, 0x02, 0x01, 0xFF, 0x00, 0x02][..];
49    /// let scan_segment = ScanSegment::parser().parse(input).unwrap().0;
50    /// let mut written = vec![];
51    /// scan_segment.write(&mut written).unwrap();
52    /// assert_eq!(input, &written[..]);
53    /// ```
54    pub fn write<W: WriteBytesExt>(&self, writer: &mut W) -> io::Result<()> {
55        // Start of Segment marker.
56        writer.write_u16::<BigEndian>(0xFFDA)?;
57        // Include the size of the data field in its own size.
58        writer.write_u16::<BigEndian>((self.specifier.len() + 2) as u16)?;
59        writer.write_all(self.specifier)?;
60        writer.write_all(self.data)
61    }
62}
63
64/// Parses out an entropy-encoded data section, including `0xFF` padding.
65///
66/// ```
67/// use exifsd::*;
68/// use combine::*;
69///
70/// let result = segment_data().parse(&[0x01, 0xFF, 0x00, 0x02, 0xFF, 0xFF, 0xD9][..]);
71///
72/// // Note that the marker `[0xFF, 0xD9]` is not consumed.
73/// assert_eq!(result, Ok(((&[0x01, 0xFF, 0x00, 0x02, 0xFF][..]), &[0xFF, 0xD9][..])));
74///
75/// let result = segment_data().parse(&[0x01, 0xFF, 0x00, 0x02, 0xFF, 0xFF, 0x00][..]);
76///
77/// // Note that the marker `[0xFF, 0x00]` is not consumed because it follows the padding.
78/// assert_eq!(result, Ok(((&[0x01, 0xFF, 0x00, 0x02, 0xFF][..]), &[0xFF, 0x00][..])));
79/// ```
80pub fn segment_data<'a, I: 'a>() -> impl Parser<Input = I, Output = &'a [u8]> + 'a
81where
82    I: RangeStream<Item = u8, Range = &'a [u8]>,
83    I::Error: ParseError<I::Item, I::Range, I::Position>,
84{
85    let marker = |m| range::recognize(token(0xFF)).skip(look_ahead(m));
86    let escape = marker(token(0x00));
87    let padding = marker(token(0xFF));
88    let unescaped_data = range::recognize(none_of(std::iter::once(0xFF)));
89    range::recognize(
90        skip_many(choice((
91            attempt(unescaped_data),
92            attempt(escape),
93            attempt(rst()),
94        )))
95        .skip(skip_many(attempt(padding))),
96    )
97}