use crate::parser::{read_u16, read_u8};
use crate::Error;
#[derive(Debug, Clone)]
pub(crate) enum FdSelect<'a> {
Format0 { fds: &'a [u8], num_glyphs: u32 },
Format3 {
ranges: &'a [u8],
n_ranges: u16,
sentinel: u16,
},
}
impl<'a> FdSelect<'a> {
pub(crate) fn parse(bytes: &'a [u8], off: usize, num_glyphs: u32) -> Result<Self, Error> {
let format = read_u8(bytes, off)?;
match format {
0 => {
let start = off + 1;
let end = start
.checked_add(num_glyphs as usize)
.ok_or(Error::Cff("FDSelect format 0 overflow"))?;
let fds = bytes.get(start..end).ok_or(Error::UnexpectedEof)?;
Ok(Self::Format0 { fds, num_glyphs })
}
3 => {
let n_ranges = read_u16(bytes, off + 1)?;
let ranges_at = off + 3;
let ranges_len = (n_ranges as usize) * 3;
let ranges = bytes
.get(ranges_at..ranges_at + ranges_len)
.ok_or(Error::UnexpectedEof)?;
let sentinel = read_u16(bytes, ranges_at + ranges_len)?;
Ok(Self::Format3 {
ranges,
n_ranges,
sentinel,
})
}
_ => Err(Error::Cff("unknown FDSelect format")),
}
}
pub(crate) fn fd_index(&self, gid: u16) -> Option<u8> {
match self {
Self::Format0 { fds, num_glyphs } => {
if (gid as u32) >= *num_glyphs {
return None;
}
fds.get(gid as usize).copied()
}
Self::Format3 {
ranges,
n_ranges,
sentinel,
} => {
if gid >= *sentinel {
return None;
}
let n = *n_ranges as usize;
for i in 0..n {
let rec = i * 3;
let first = u16::from_be_bytes([ranges[rec], ranges[rec + 1]]);
let fd = ranges[rec + 2];
let next_first = if i + 1 < n {
let nrec = (i + 1) * 3;
u16::from_be_bytes([ranges[nrec], ranges[nrec + 1]])
} else {
*sentinel
};
if gid >= first && gid < next_first {
return Some(fd);
}
}
None
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn format0_flat_array() {
let buf = vec![0u8, 0, 1, 1, 2, 0];
let sel = FdSelect::parse(&buf, 0, 5).expect("parse");
assert!(matches!(sel, FdSelect::Format0 { .. }));
assert_eq!(sel.fd_index(0), Some(0));
assert_eq!(sel.fd_index(1), Some(1));
assert_eq!(sel.fd_index(2), Some(1));
assert_eq!(sel.fd_index(3), Some(2));
assert_eq!(sel.fd_index(4), Some(0));
assert_eq!(sel.fd_index(5), None); }
#[test]
fn format3_ranges() {
let buf = vec![
3, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x06, ];
let sel = FdSelect::parse(&buf, 0, 6).expect("parse");
assert!(matches!(sel, FdSelect::Format3 { .. }));
for gid in 0u16..=2 {
assert_eq!(sel.fd_index(gid), Some(0), "gid {gid}");
}
for gid in 3u16..=5 {
assert_eq!(sel.fd_index(gid), Some(1), "gid {gid}");
}
assert_eq!(sel.fd_index(6), None); assert_eq!(sel.fd_index(99), None);
}
#[test]
fn format3_single_range() {
let buf = vec![
3, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, ];
let sel = FdSelect::parse(&buf, 0, 4).expect("parse");
for gid in 0u16..=3 {
assert_eq!(sel.fd_index(gid), Some(0));
}
assert_eq!(sel.fd_index(4), None);
}
#[test]
fn rejects_unknown_format() {
let buf = vec![7u8, 0, 0];
assert!(FdSelect::parse(&buf, 0, 1).is_err());
}
#[test]
fn rejects_truncated_format0() {
let buf = vec![0u8, 0, 1, 2];
assert!(FdSelect::parse(&buf, 0, 10).is_err());
}
}