#![allow(clippy::type_complexity)]
pub mod charset;
pub mod charstring;
pub mod encodings;
use tarrasque::{Extract, ExtractError, ExtractResult, Stream, View, extract};
use crate::dict::{Private, Top};
use crate::error::{CffError, UNSUPPORTED};
use crate::index::{Index};
use self::charset::{Charset};
use self::charstring::{Charstring};
use self::encodings::{Encodings};
#[inline]
fn parse_private<'s>(
bytes: &'s [u8], top: &Top<'s>
) -> Result<(Private<'s>, Option<Index<'s, &'s [u8]>>), CffError<'s>> {
if let Some((size, offset)) = top.private {
let stream = Stream(bytes);
let start = offset as usize;
let end = start + size as usize;
let private: Private<'s> = stream.substream(start..end)?.extract(())?;
let subroutines = if let Some(subroutines) = private.subroutines {
Some(stream.substream(start + subroutines as usize..)?.extract(())?)
} else {
None
};
Ok((private, subroutines))
} else {
Ok((Stream(&[]).extract(())?, None))
}
}
extract! {
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Format0<'s>(num_glyphs: usize) {
pub indices: &'s [u8] = [num_glyphs as usize],
}
}
impl<'s> Format0<'s> {
#[inline]
pub fn find_index(&self, index: usize) -> Option<usize> {
self.indices.get(index).cloned().map(usize::from)
}
}
extract! {
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Range[3] {
pub first: u16 = [],
pub index: u8 = [],
}
}
extract! {
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Format3<'s> {
pub num_ranges: u16 = [],
pub ranges: View<'s, Range, ()> = [(num_ranges as usize, ())],
pub sentinel: u16 = [],
}
}
impl<'s> Format3<'s> {
#[inline]
pub fn find_index(&self, index: usize) -> Option<usize> {
let mut ranges = self.ranges.iter().peekable();
while let (Some(current), next) = (ranges.next(), ranges.peek()) {
if index < next.map_or(self.sentinel as usize, |r| r.first as usize) {
return Some(current.index as usize);
}
}
None
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Select<'s> {
Format0(Format0<'s>),
Format3(Format3<'s>),
}
impl<'s> Select<'s> {
#[inline]
pub fn find_index(&self, index: usize) -> Option<usize> {
match self {
Select::Format0(select) => select.find_index(index),
Select::Format3(select) => select.find_index(index),
}
}
}
impl<'s> Extract<'s, usize> for Select<'s> {
#[inline]
fn extract(
stream: &mut Stream<'s>, num_glyphs: usize
) -> ExtractResult<'s, Self> {
match stream.extract::<u8, _>(())? {
0 => Ok(Select::Format0(stream.extract(num_glyphs)?)),
3 => Ok(Select::Format3(stream.extract(())?)),
_ => Err(ExtractError::Code(UNSUPPORTED)),
}
}
}
pub type Group<'s> = (Top<'s>, Private<'s>, Option<Index<'s, &'s [u8]>>);
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Glyphs<'s> {
pub bytes: &'s [u8],
pub top: Top<'s>,
pub private: Private<'s>,
pub subroutines: (Index<'s, &'s [u8]>, Option<Index<'s, &'s [u8]>>),
pub encodings: Encodings<'s>,
pub charset: Charset<'s>,
pub charstrings: Index<'s, &'s [u8]>,
pub groups: Option<(Select<'s>, Index<'s, Top<'s>>)>,
}
impl<'s> Glyphs<'s> {
#[inline]
pub fn parse(
bytes: &'s [u8], top: Top<'s>, global: Index<'s, &'s [u8]>
) -> Result<Self, CffError<'s>> {
let stream = Stream(bytes);
let charstrings = if let Some(charstrings) = top.charstrings {
let mut substream = stream.substream(charstrings as usize..)?;
substream.extract::<Index<'s, &'s [u8]>, _>(())?
} else {
return Err(CffError::Missing);
};
let groups = if let Some(cid) = top.cid {
let mut substream = stream.substream(cid.fd_select as usize..)?;
let select: Select<'s> = substream.extract(charstrings.len())?;
let mut substream = stream.substream(cid.fd_array as usize..)?;
let tops: Index<'s, Top<'s>> = substream.extract(())?;
Some((select, tops))
} else {
None
};
let (private, local) = parse_private(bytes, &top)?;
let mut substream = stream.substream(top.encoding as usize..)?;
let encodings = substream.extract(top.encoding)?;
let mut substream = stream.substream(top.charset as usize..)?;
let charset = substream.extract((top.charset, charstrings.len()))?;
Ok(Glyphs {
bytes,
top,
private,
subroutines: (global, local),
encodings,
charset,
charstrings,
groups,
})
}
#[inline]
fn parse_group(
&self, index: usize
) -> Result<Option<Group<'s>>, CffError<'s>> {
if let Some((select, tops)) = self.groups {
let index = select.find_index(index).ok_or(CffError::Missing)?;
let top = tops.parse_object(index).ok_or(CffError::Missing)??;
let (private, subroutines) = parse_private(self.bytes, &top)?;
Ok(Some((top, private, subroutines)))
} else {
Ok(Some((self.top, self.private, self.subroutines.1)))
}
}
#[inline]
pub fn parse_charstring(
&self, index: usize
) -> Option<Result<(Charstring<'s>, Group<'s>), CffError<'s>>> {
let group = match self.parse_group(index) {
Ok(Some(group)) => group,
Ok(None) => return None,
Err(error) => return Some(Err(error)),
};
self.charstrings.get(index).map(|b| {
Ok((Charstring::new(self.subroutines.0, group.2, b), group))
})
}
}