use crate::parser::{read_u16, read_u8};
use crate::Error;
#[derive(Debug, Clone, Copy)]
pub struct Cff2Header {
pub major: u8,
pub minor: u8,
pub header_size: u8,
pub top_dict_size: u16,
}
impl Cff2Header {
pub(crate) fn parse(bytes: &[u8]) -> Result<Self, Error> {
let major = read_u8(bytes, 0)?;
let minor = read_u8(bytes, 1)?;
let header_size = read_u8(bytes, 2)?;
let top_dict_size = read_u16(bytes, 3)?;
if major != 2 {
return Err(Error::Cff("CFF2 header: major != 2"));
}
if header_size < 5 {
return Err(Error::Cff("CFF2 header: headerSize < 5"));
}
if (header_size as usize) > bytes.len() {
return Err(Error::UnexpectedEof);
}
Ok(Self {
major,
minor,
header_size,
top_dict_size,
})
}
pub fn top_dict_offset(&self) -> usize {
self.header_size as usize
}
pub fn global_subr_index_offset(&self) -> usize {
self.header_size as usize + self.top_dict_size as usize
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_minimal_header() {
let bytes = [2u8, 0, 5, 0x00, 0x0B];
let h = Cff2Header::parse(&bytes).expect("parse");
assert_eq!(h.major, 2);
assert_eq!(h.minor, 0);
assert_eq!(h.header_size, 5);
assert_eq!(h.top_dict_size, 11);
assert_eq!(h.top_dict_offset(), 5);
assert_eq!(h.global_subr_index_offset(), 16);
}
#[test]
fn rejects_cff1_major() {
let bytes = [1u8, 0, 5, 0x00, 0x0B];
assert!(matches!(
Cff2Header::parse(&bytes),
Err(Error::Cff("CFF2 header: major != 2"))
));
}
#[test]
fn rejects_header_size_below_5() {
let bytes = [2u8, 0, 4, 0x00, 0x0B];
assert!(matches!(
Cff2Header::parse(&bytes),
Err(Error::Cff("CFF2 header: headerSize < 5"))
));
}
#[test]
fn rejects_short_input() {
let bytes = [2u8, 0, 5, 0x00];
assert!(matches!(
Cff2Header::parse(&bytes),
Err(Error::UnexpectedEof)
));
}
#[test]
fn tolerates_extended_header() {
let bytes = [2u8, 0, 8, 0x00, 0x10, 0, 0, 0];
let h = Cff2Header::parse(&bytes).expect("parse");
assert_eq!(h.header_size, 8);
assert_eq!(h.top_dict_offset(), 8);
assert_eq!(h.global_subr_index_offset(), 8 + 16);
}
#[test]
fn rejects_when_declared_header_exceeds_input() {
let bytes = [2u8, 0, 10, 0x00, 0x0B];
assert!(matches!(
Cff2Header::parse(&bytes),
Err(Error::UnexpectedEof)
));
}
}