use crate::*;
use byteorder::{BigEndian, WriteBytesExt};
use combine::{parser::*, *};
use std::io;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ScanSegment<'a> {
pub specifier: &'a [u8],
pub data: &'a [u8],
}
impl<'a> ScanSegment<'a> {
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,
})
})
}
pub fn write<W: WriteBytesExt>(&self, writer: &mut W) -> io::Result<()> {
writer.write_u16::<BigEndian>(0xFFDA)?;
writer.write_u16::<BigEndian>((self.specifier.len() + 2) as u16)?;
writer.write_all(self.specifier)?;
writer.write_all(self.data)
}
}
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))),
)
}