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