use crate::{
AnyWhatever,
ascii85::{self, Ascii85Error},
machine::{Token, TokenArray, Value},
name,
type1::Header,
};
use either::Either;
use snafu::FromString as _;
use std::{
cell::RefCell,
iter::once,
num::{ParseFloatError, ParseIntError},
rc::Rc,
str::{Utf8Error, from_utf8},
string::FromUtf8Error,
};
use winnow::{
ModalResult, Parser,
ascii::hex_digit1,
combinator::{alt, delimited, dispatch, fail, opt, preceded, repeat, terminated},
error::{ErrMode, FromExternalError, ParseError, ParserError},
stream::{AsChar, Stream},
token::{any, literal, one_of, take_till, take_while},
};
#[derive(snafu::Snafu, Debug)]
pub enum PossibleError {
#[snafu(transparent)]
Utf8 { source: Utf8Error },
#[snafu(transparent)]
Utf8Str { source: FromUtf8Error },
#[snafu(transparent)]
Int { source: ParseIntError },
#[snafu(transparent)]
Ascii85 { source: Ascii85Error },
}
pub(crate) fn parse_error_to_whatever<I, E: std::error::Error + Send + Sync + 'static>(
err: ParseError<I, E>,
msg: impl Into<String>,
) -> AnyWhatever {
let e = err.into_inner();
AnyWhatever::with_source(Box::new(e), msg.into())
}
pub fn header<'a, E>(input: &mut &'a [u8]) -> ModalResult<Header, E>
where
E: ParserError<&'a [u8]> + FromExternalError<&'a [u8], FromUtf8Error>,
{
preceded(
literal(b"%!"),
alt((b"PS-AdobeFont", b"AdobeFont", b"FontType1")),
)
.parse_next(input)?;
let spec_ver = delimited('-', take_till(1.., ':'), b": ").parse_next(input)?;
let font_name = take_till(1.., ' ').parse_next(input)?;
let font_ver = delimited(
' ',
take_while(1.., (('0'..='9'), '.', ('a'..='z'))),
loose_line_ending,
)
.parse_next(input)?;
Ok(Header {
spec_ver: String::from_utf8(spec_ver.to_owned())
.map_err(|e| ErrMode::from_external_error(input, e))?,
font_name: String::from_utf8(font_name.to_owned())
.map_err(|e| ErrMode::from_external_error(input, e))?,
font_ver: String::from_utf8(font_ver.to_owned())
.map_err(|e| ErrMode::from_external_error(input, e))?,
})
}
fn comment<'a, E: ParserError<&'a [u8]>>(input: &mut &'a [u8]) -> ModalResult<(), E> {
preceded(
literal(b"%"),
take_till(0.., |c| c == b'\n' || c == b'\r' || c == b'\x0c'),
)
.parse_next(input)?;
Ok(())
}
fn is_white_space(b: u8) -> bool {
b == b' ' || b == b'\t' || b == b'\n' || b == b'\x0C' || b == b'\r' || b == b'\0'
}
fn is_delimiter(b: u8) -> bool {
b == b'('
|| b == b')'
|| b == b'<'
|| b == b'>'
|| b == b'['
|| b == b']'
|| b == b'{'
|| b == b'}'
|| b == b'/'
|| b == b'%'
}
fn is_regular_char(b: u8) -> bool {
!is_white_space(b) && !is_delimiter(b)
}
pub fn white_space<'a, E>(input: &mut &'a [u8]) -> ModalResult<&'a [u8], E>
where
E: ParserError<&'a [u8]>,
{
take_while(1.., is_white_space).parse_next(input)
}
pub fn white_space_or_comment<'a, E>(input: &mut &'a [u8]) -> ModalResult<(), E>
where
E: ParserError<&'a [u8]>,
{
alt((white_space.value(()), comment)).parse_next(input)
}
pub fn ws_prefixed<'a, P, O, E>(p: P) -> impl Parser<&'a [u8], O, ErrMode<E>>
where
P: Parser<&'a [u8], O, ErrMode<E>>,
E: ParserError<&'a [u8]>,
{
preceded(repeat::<_, _, (), _, _>(.., white_space_or_comment), p)
}
fn loose_line_ending<'a, E>(input: &mut &'a [u8]) -> ModalResult<(), E>
where
E: ParserError<&'a [u8]>,
{
match input.first() {
Some(b'\n') => {
input.next_token();
Ok(())
}
Some(b'\r') => {
input.next_token();
if input.first() == Some(&b'\n') {
input.next_token();
}
Ok(())
}
_ => fail.parse_next(input),
}
}
fn int_or_float<'a, E>(input: &mut &'a [u8]) -> ModalResult<Either<i32, f32>, E>
where
E: ParserError<&'a [u8]>
+ FromExternalError<&'a [u8], Utf8Error>
+ FromExternalError<&'a [u8], ParseIntError>
+ FromExternalError<&'a [u8], ParseFloatError>,
{
let buf = (
one_of(('0'..='9', '+', '-', '.')),
take_while(0.., ('0'..='9', 'a'..='z', 'A'..='Z', '.', '-', '+', '#')),
)
.take()
.parse_next(input)?;
if let Some(pos) = memchr::memchr(b'#', buf) {
let (radix, num) = buf.split_at(pos);
let radix = from_utf8(radix)
.map_err(|e| ErrMode::from_external_error(input, e))?
.parse::<u32>()
.map_err(|_| ErrMode::from_input(input))?;
let num = i32::from_str_radix(
from_utf8(&num[1..]).map_err(|e| ErrMode::from_external_error(input, e))?,
radix,
)
.map_err(|e| ErrMode::from_external_error(input, e))?;
return Ok(Either::Left(num));
}
if memchr::memchr3(b'.', b'e', b'E', buf).is_some() {
Ok(Either::Right(
from_utf8(buf)
.map_err(|e| ErrMode::from_external_error(input, e))?
.parse::<f32>()
.map_err(|e| ErrMode::from_external_error(input, e))?,
))
} else {
Ok(
match from_utf8(buf)
.map_err(|e| ErrMode::from_external_error(input, e))?
.parse::<i32>()
{
Ok(v) => Either::Left(v),
Err(_) => Either::Right(
from_utf8(buf)
.map_err(|e| ErrMode::from_external_error(input, e))?
.parse::<f32>()
.map_err(|e| ErrMode::from_external_error(input, e))?,
),
},
)
}
}
fn string<'a, E>(input: &mut &'a [u8]) -> ModalResult<Box<[u8]>, E>
where
E: ParserError<&'a [u8]> + FromExternalError<&'a [u8], PossibleError>,
{
enum StringFragment<'a> {
Literal(&'a [u8]),
EscapedChar(u8),
EscapedNewLine,
Nested(Box<[u8]>),
}
fn literal_fragment<'a, E: ParserError<&'a [u8]>>(
input: &mut &'a [u8],
) -> ModalResult<StringFragment<'a>, E> {
let buf = take_till(1.., (b'(', b')', b'\\')).parse_next(input)?;
Ok(StringFragment::Literal(buf))
}
fn escaped_char<'a, E>(input: &mut &'a [u8]) -> ModalResult<StringFragment<'a>, E>
where
E: ParserError<&'a [u8]> + FromExternalError<&'a [u8], PossibleError>,
{
let parse_oct_byte = take_while(1..=3, |c: u8| c.is_oct_digit()).try_map(|buf| {
Ok::<_, PossibleError>((u16::from_str_radix(from_utf8(buf)?, 8)? & 0xff) as u8)
});
let c = preceded(
literal(b"\\"),
alt((
b'n'.value(b'\n'),
b'r'.value(b'\r'),
b't'.value(b'\t'),
b'b'.value(b'\x08'),
b'f'.value(b'\x0C'),
b'('.value(b'('),
b')'.value(b')'),
parse_oct_byte,
)),
)
.parse_next(input)?;
Ok(StringFragment::EscapedChar(c))
}
fn escaped_newline<'a, E: ParserError<&'a [u8]>>(
input: &mut &'a [u8],
) -> ModalResult<StringFragment<'a>, E> {
preceded(literal(b"\\"), loose_line_ending).parse_next(input)?;
Ok(StringFragment::EscapedNewLine)
}
fn build_string<'a, E>(input: &mut &'a [u8]) -> ModalResult<Box<[u8]>, E>
where
E: ParserError<&'a [u8]> + FromExternalError<&'a [u8], PossibleError>,
{
repeat(0.., fragment)
.fold(Vec::new, |mut r, frag| {
match frag {
StringFragment::Literal(s) => r.extend_from_slice(s),
StringFragment::EscapedChar(c) => r.push(c),
StringFragment::EscapedNewLine => (),
StringFragment::Nested(s) => {
r.extend(once(b'(').chain(s.iter().copied()).chain(once(b')')));
}
}
r
})
.parse_next(input)
.map(Into::into)
}
fn nested<'a, E>(input: &mut &'a [u8]) -> ModalResult<StringFragment<'a>, E>
where
E: ParserError<&'a [u8]> + FromExternalError<&'a [u8], PossibleError>,
{
let frag = delimited(b'(', opt(build_string), b')').parse_next(input)?;
Ok(StringFragment::Nested(match frag {
Some(s) => s,
None => (*b"").into(),
}))
}
fn fragment<'a, E>(input: &mut &'a [u8]) -> ModalResult<StringFragment<'a>, E>
where
E: ParserError<&'a [u8]> + FromExternalError<&'a [u8], PossibleError>,
{
alt((literal_fragment, escaped_char, escaped_newline, nested)).parse_next(input)
}
fn literal_string<'a, E>(input: &mut &'a [u8]) -> ModalResult<Box<[u8]>, E>
where
E: ParserError<&'a [u8]> + FromExternalError<&'a [u8], PossibleError>,
{
terminated(build_string, b')').parse_next(input)
}
fn hex_string<'a, E>(input: &mut &'a [u8]) -> ModalResult<Box<[u8]>, E>
where
E: ParserError<&'a [u8]> + FromExternalError<&'a [u8], PossibleError>,
{
let bytes = repeat(0.., alt((hex_digit1, white_space)))
.fold(Vec::new, |mut bytes, frag| {
if !is_white_space(frag[0]) {
bytes.extend(frag);
}
bytes
})
.try_map(|mut s| {
if s.len() % 2 != 0 {
s.push(b'0');
}
let mut bytes = Vec::with_capacity(s.len() / 2);
for i in (0..s.len()).step_by(2) {
bytes.push(u8::from_str_radix(from_utf8(&s[i..i + 2])?, 16)?);
}
Ok::<_, PossibleError>(Box::<[u8]>::from(bytes))
});
terminated(bytes, b'>').parse_next(input)
}
fn ascii85<'a, E>(input: &mut &'a [u8]) -> ModalResult<Box<[u8]>, E>
where
E: ParserError<&'a [u8]> + FromExternalError<&'a [u8], PossibleError>,
{
delimited(
b'~',
take_while(0.., |c| c != b'~')
.try_map(|v: &[u8]| Ok::<_, PossibleError>(ascii85::decode(v)?.into())),
b"~>",
)
.parse_next(input)
}
fn hex_or_85<'a, E>(input: &mut &'a [u8]) -> ModalResult<Box<[u8]>, E>
where
E: ParserError<&'a [u8]> + FromExternalError<&'a [u8], PossibleError>,
{
alt((hex_string, ascii85)).parse_next(input)
}
dispatch!(any;
b'(' => literal_string,
b'<' => hex_or_85,
_ => fail,
)
.parse_next(input)
}
fn executable_name<'a, E>(input: &mut &'a [u8]) -> ModalResult<&'a str, E>
where
E: ParserError<&'a [u8]> + FromExternalError<&'a [u8], Utf8Error>,
{
take_while(1.., is_regular_char)
.try_map(from_utf8)
.parse_next(input)
}
fn literal_name<'a, E>(input: &mut &'a [u8]) -> ModalResult<&'a str, E>
where
E: ParserError<&'a [u8]> + FromExternalError<&'a [u8], Utf8Error>,
{
preceded('/', take_while(0.., is_regular_char).try_map(from_utf8)).parse_next(input)
}
fn procedure<'a, E>(input: &mut &'a [u8]) -> ModalResult<TokenArray, E>
where
E: ParserError<&'a [u8]>
+ FromExternalError<&'a [u8], Utf8Error>
+ FromExternalError<&'a [u8], ParseIntError>
+ FromExternalError<&'a [u8], ParseFloatError>
+ FromExternalError<&'a [u8], PossibleError>,
{
delimited(b'{', repeat(0.., ws_prefixed(token)), ws_prefixed(b'}')).parse_next(input)
}
fn special_name<'a, E>(input: &mut &'a [u8]) -> ModalResult<&'a str, E>
where
E: ParserError<&'a [u8]> + FromExternalError<&'a [u8], Utf8Error>,
{
let buf = take_while(1..=2, (b'[', ']', b"<<", b">>")).parse_next(input)?;
from_utf8(buf).map_err(|e| ErrMode::from_external_error(input, e))
}
pub fn token<'a, E>(input: &mut &'a [u8]) -> ModalResult<Token, E>
where
E: ParserError<&'a [u8]>
+ FromExternalError<&'a [u8], Utf8Error>
+ FromExternalError<&'a [u8], ParseIntError>
+ FromExternalError<&'a [u8], ParseFloatError>
+ FromExternalError<&'a [u8], PossibleError>,
{
alt((
int_or_float.map(|v| Token::Literal(v.either(Value::Integer, Value::Real))),
string.map(|s| Token::Literal(Vec::from(s).into())),
literal_name.map(|s| Token::Literal(Value::Name(name(s)))),
special_name.map(|s| Token::Name(name(s))),
procedure.map(|a| Token::Literal(Value::Procedure(Rc::new(RefCell::new(a))))),
executable_name.map(|s| Token::Name(name(s))),
))
.parse_next(input)
}
#[cfg(test)]
mod tests;