use crate::cff::dict::{Dict, Operator};
use crate::cff::index::Index;
use crate::Error;
#[derive(Debug, Clone)]
pub(crate) struct PrivateDict<'a> {
pub(crate) default_width_x: f32,
pub(crate) nominal_width_x: f32,
pub(crate) local_subrs: Option<Index<'a>>,
}
impl<'a> PrivateDict<'a> {
pub(crate) fn parse(bytes: &'a [u8], private_off: usize, size: usize) -> Result<Self, Error> {
let end = private_off
.checked_add(size)
.ok_or(Error::Cff("Private DICT size overflow"))?;
if end > bytes.len() {
return Err(Error::UnexpectedEof);
}
let dict = Dict::parse(&bytes[private_off..end])?;
let default_width_x = dict
.get_array(Operator::DefaultWidthX)
.and_then(|v| v.last().copied())
.map(|o| o.as_f64() as f32)
.unwrap_or(0.0);
let nominal_width_x = dict
.get_array(Operator::NominalWidthX)
.and_then(|v| v.last().copied())
.map(|o| o.as_f64() as f32)
.unwrap_or(0.0);
let local_subrs = if let Some(off) = dict.get_int(Operator::Subrs) {
if off < 0 {
return Err(Error::Cff("negative local subrs offset"));
}
let abs = private_off
.checked_add(off as usize)
.ok_or(Error::Cff("local subrs overflow"))?;
Some(Index::parse(bytes, abs)?)
} else {
None
};
Ok(Self {
default_width_x,
nominal_width_x,
local_subrs,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn defaults_when_absent() {
let bytes = vec![];
let p = PrivateDict::parse(&bytes, 0, 0).unwrap();
assert_eq!(p.default_width_x, 0.0);
assert_eq!(p.nominal_width_x, 0.0);
assert!(p.local_subrs.is_none());
}
#[test]
fn picks_up_widths() {
let dict_bytes = vec![248, 136, 20, 248, 36, 21];
let mut whole = vec![0u8, 0, 0, 0];
whole.extend_from_slice(&dict_bytes);
let p = PrivateDict::parse(&whole, 4, dict_bytes.len()).unwrap();
assert_eq!(p.default_width_x, 500.0);
assert_eq!(p.nominal_width_x, 400.0);
}
}