use core::fmt::{self, Debug};
const SFNT_TT: u32 = 0x0001_0000;
const SFNT_TRUE: u32 = 0x74727565; const SFNT_OTTO: u32 = 0x4F54_544F;
pub fn find_table<'a>(bytes: &'a [u8], tag: &[u8; 4], header_offset: usize) -> Option<&'a [u8]> {
if bytes.len() < header_offset + 12 {
return None;
}
let h = &bytes[header_offset..];
let magic = u32::from_be_bytes([h[0], h[1], h[2], h[3]]);
if magic != SFNT_TT && magic != SFNT_TRUE && magic != SFNT_OTTO {
return None;
}
let n = u16::from_be_bytes([h[4], h[5]]) as usize;
if h.len() < 12 + n * 16 {
return None;
}
for i in 0..n {
let rec = &h[12 + i * 16..12 + (i + 1) * 16];
if &rec[0..4] == tag {
let off = u32::from_be_bytes([rec[8], rec[9], rec[10], rec[11]]) as usize;
let len = u32::from_be_bytes([rec[12], rec[13], rec[14], rec[15]]) as usize;
if off.saturating_add(len) > bytes.len() {
return None;
}
return Some(&bytes[off..off + len]);
}
}
None
}
#[inline]
fn u16_be(b: &[u8], o: usize) -> Option<u16> {
Some(u16::from_be_bytes([*b.get(o)?, *b.get(o + 1)?]))
}
#[inline]
fn i16_be(b: &[u8], o: usize) -> Option<i16> {
Some(i16::from_be_bytes([*b.get(o)?, *b.get(o + 1)?]))
}
#[inline]
fn u32_be(b: &[u8], o: usize) -> Option<u32> {
Some(u32::from_be_bytes([
*b.get(o)?,
*b.get(o + 1)?,
*b.get(o + 2)?,
*b.get(o + 3)?,
]))
}
#[inline]
fn i32_be(b: &[u8], o: usize) -> Option<i32> {
Some(i32::from_be_bytes([
*b.get(o)?,
*b.get(o + 1)?,
*b.get(o + 2)?,
*b.get(o + 3)?,
]))
}
#[inline]
fn f2dot14(raw: i16) -> f32 {
raw as f32 / 16384.0
}
#[derive(Debug, Clone)]
struct Region {
axes: Vec<(f32, f32, f32)>,
}
impl Region {
fn scalar(&self, coords: &[f32]) -> f32 {
let mut s = 1.0f32;
for (ai, &(start, peak, end)) in self.axes.iter().enumerate() {
let c = coords.get(ai).copied().unwrap_or(0.0);
if peak == 0.0 {
continue;
}
if c == 0.0 || (c < 0.0) != (peak < 0.0) {
return 0.0;
}
if c == peak {
continue;
}
if c < start || c > end {
return 0.0;
}
if c < peak {
if (peak - start).abs() < f32::EPSILON {
return 0.0;
}
s *= (c - start) / (peak - start);
} else {
if (end - peak).abs() < f32::EPSILON {
return 0.0;
}
s *= (end - c) / (end - peak);
}
}
s
}
}
#[derive(Debug, Clone)]
struct ItemVariationData {
region_indexes: Vec<u16>,
delta_sets: Vec<Vec<i32>>,
}
#[derive(Debug, Clone, Default)]
pub struct ItemVariationStore {
axis_count: u16,
regions: Vec<Region>,
subtables: Vec<ItemVariationData>,
}
impl ItemVariationStore {
pub fn parse(bytes: &[u8], offset: usize) -> Option<Self> {
let b = bytes.get(offset..)?;
let format = u16_be(b, 0)?;
if format != 1 {
return None;
}
let region_list_offset = u32_be(b, 2)? as usize;
let item_var_data_count = u16_be(b, 6)? as usize;
let r = b.get(region_list_offset..)?;
let axis_count = u16_be(r, 0)?;
let region_count = u16_be(r, 2)? as usize;
let mut regions = Vec::with_capacity(region_count);
let region_size = axis_count as usize * 6; for ri in 0..region_count {
let off = 4 + ri * region_size;
let rb = r.get(off..off + region_size)?;
let mut axes = Vec::with_capacity(axis_count as usize);
for ai in 0..axis_count as usize {
let start = f2dot14(i16_be(rb, ai * 6)?);
let peak = f2dot14(i16_be(rb, ai * 6 + 2)?);
let end = f2dot14(i16_be(rb, ai * 6 + 4)?);
axes.push((start, peak, end));
}
regions.push(Region { axes });
}
let mut subtables = Vec::with_capacity(item_var_data_count);
for ii in 0..item_var_data_count {
let sub_off_off = 8 + ii * 4;
let sub_off = u32_be(b, sub_off_off)? as usize;
let sb = b.get(sub_off..)?;
let item_count = u16_be(sb, 0)? as usize;
let raw_word_delta_count = u16_be(sb, 2)?;
let long_mode = (raw_word_delta_count & 0x8000) != 0;
let word_delta_count = (raw_word_delta_count & 0x7FFF) as usize;
let region_index_count = u16_be(sb, 4)? as usize;
let mut region_indexes = Vec::with_capacity(region_index_count);
for k in 0..region_index_count {
region_indexes.push(u16_be(sb, 6 + k * 2)?);
}
if word_delta_count > region_index_count {
return None;
}
let row_size = if long_mode {
word_delta_count * 4 + (region_index_count - word_delta_count) * 2
} else {
word_delta_count * 2 + (region_index_count - word_delta_count)
};
let row_base = 6 + region_index_count * 2;
let mut delta_sets = Vec::with_capacity(item_count);
for it in 0..item_count {
let off = row_base + it * row_size;
let rs = sb.get(off..off + row_size)?;
let mut deltas = Vec::with_capacity(region_index_count);
let mut rp = 0usize;
for k in 0..region_index_count {
if k < word_delta_count {
if long_mode {
deltas.push(i32_be(rs, rp)?);
rp += 4;
} else {
deltas.push(i16_be(rs, rp)? as i32);
rp += 2;
}
} else if long_mode {
deltas.push(i16_be(rs, rp)? as i32);
rp += 2;
} else {
deltas.push((rs[rp] as i8) as i32);
rp += 1;
}
}
delta_sets.push(deltas);
}
subtables.push(ItemVariationData {
region_indexes,
delta_sets,
});
}
Some(Self {
axis_count,
regions,
subtables,
})
}
pub fn axis_count(&self) -> u16 {
self.axis_count
}
pub fn resolve_delta(&self, outer: u16, inner: u16, coords: &[f32]) -> f32 {
let st = match self.subtables.get(outer as usize) {
Some(s) => s,
None => return 0.0,
};
let row = match st.delta_sets.get(inner as usize) {
Some(r) => r,
None => return 0.0,
};
let mut sum = 0.0f32;
for (k, &d) in row.iter().enumerate() {
let region_index = match st.region_indexes.get(k) {
Some(&i) => i as usize,
None => continue,
};
let region = match self.regions.get(region_index) {
Some(r) => r,
None => continue,
};
let s = region.scalar(coords);
if s != 0.0 {
sum += s * d as f32;
}
}
sum
}
}
#[derive(Debug, Clone)]
pub struct DeltaSetIndexMap {
inner_bits: u32,
map_count: u32,
entries: Vec<(u16, u16)>,
}
impl DeltaSetIndexMap {
pub fn parse(bytes: &[u8], offset: usize) -> Option<Self> {
let b = bytes.get(offset..)?;
if b.len() < 4 {
return None;
}
let format = b[0];
let entry_format = b[1];
let (map_count, header_size) = match format {
0 => (u16_be(b, 2)? as u32, 4usize),
1 => (u32_be(b, 2)?, 6usize),
_ => return None,
};
let entry_size = (((entry_format >> 4) & 0x03) + 1) as usize;
let inner_bits = ((entry_format & 0x0F) + 1) as u32;
let inner_mask = (1u32 << inner_bits) - 1;
let need = header_size + entry_size * map_count as usize;
if b.len() < need {
return None;
}
let mut entries = Vec::with_capacity(map_count as usize);
for i in 0..map_count as usize {
let p = header_size + i * entry_size;
let mut v = 0u32;
for k in 0..entry_size {
v = (v << 8) | b[p + k] as u32;
}
let inner = (v & inner_mask) as u16;
let outer = ((v >> inner_bits) & 0xFFFF) as u16;
entries.push((outer, inner));
}
Some(Self {
inner_bits,
map_count,
entries,
})
}
pub fn resolve(&self, key: u32) -> (u16, u16) {
if self.entries.is_empty() {
return (0, 0);
}
let idx = if key >= self.map_count {
self.entries.len() - 1
} else {
key as usize
};
self.entries[idx]
}
pub fn map_count(&self) -> u32 {
self.map_count
}
pub fn inner_bits(&self) -> u32 {
self.inner_bits
}
}
#[derive(Debug, Clone)]
pub struct MvarValue {
pub tag: [u8; 4],
pub outer: u16,
pub inner: u16,
}
#[derive(Debug, Clone)]
pub struct MvarTable {
values: Vec<MvarValue>,
ivs: Option<ItemVariationStore>,
}
impl MvarTable {
pub fn parse(bytes: &[u8]) -> Option<Self> {
if bytes.len() < 12 {
return None;
}
let major = u16_be(bytes, 0)?;
if major != 1 {
return None;
}
let value_record_size = u16_be(bytes, 6)? as usize;
let value_record_count = u16_be(bytes, 8)? as usize;
let ivs_offset = u16_be(bytes, 10)? as usize;
let header_size = 12usize;
let need = header_size + value_record_count * value_record_size;
if bytes.len() < need {
return None;
}
if value_record_size < 8 {
return None;
}
let mut values = Vec::with_capacity(value_record_count);
for i in 0..value_record_count {
let off = header_size + i * value_record_size;
let mut tag = [0u8; 4];
tag.copy_from_slice(&bytes[off..off + 4]);
let outer = u16_be(bytes, off + 4)?;
let inner = u16_be(bytes, off + 6)?;
values.push(MvarValue { tag, outer, inner });
}
let ivs = if ivs_offset != 0 {
ItemVariationStore::parse(bytes, ivs_offset)
} else {
None
};
Some(Self { values, ivs })
}
pub fn values(&self) -> &[MvarValue] {
&self.values
}
pub fn delta(&self, tag: &[u8; 4], coords: &[f32]) -> f32 {
let v = self.values.iter().find(|v| &v.tag == tag);
let v = match v {
Some(v) => v,
None => return 0.0,
};
match self.ivs.as_ref() {
Some(s) => s.resolve_delta(v.outer, v.inner, coords),
None => 0.0,
}
}
}
#[derive(Debug, Clone)]
pub struct AdvanceVariationTable {
ivs: ItemVariationStore,
advance_map: Option<DeltaSetIndexMap>,
lsb_map: Option<DeltaSetIndexMap>,
rsb_map: Option<DeltaSetIndexMap>,
}
impl AdvanceVariationTable {
pub fn parse(bytes: &[u8]) -> Option<Self> {
if bytes.len() < 20 {
return None;
}
let major = u16_be(bytes, 0)?;
if major != 1 {
return None;
}
let ivs_off = u32_be(bytes, 4)? as usize;
let advance_map_off = u32_be(bytes, 8)? as usize;
let lsb_map_off = u32_be(bytes, 12)? as usize;
let rsb_map_off = u32_be(bytes, 16)? as usize;
let ivs = ItemVariationStore::parse(bytes, ivs_off)?;
let advance_map = if advance_map_off != 0 {
DeltaSetIndexMap::parse(bytes, advance_map_off)
} else {
None
};
let lsb_map = if lsb_map_off != 0 {
DeltaSetIndexMap::parse(bytes, lsb_map_off)
} else {
None
};
let rsb_map = if rsb_map_off != 0 {
DeltaSetIndexMap::parse(bytes, rsb_map_off)
} else {
None
};
Some(Self {
ivs,
advance_map,
lsb_map,
rsb_map,
})
}
pub fn advance_delta(&self, gid: u16, coords: &[f32]) -> f32 {
let (outer, inner) = match self.advance_map.as_ref() {
Some(m) => m.resolve(gid as u32),
None => (0, gid),
};
self.ivs.resolve_delta(outer, inner, coords)
}
pub fn lsb_delta(&self, gid: u16, coords: &[f32]) -> f32 {
match self.lsb_map.as_ref() {
Some(m) => {
let (outer, inner) = m.resolve(gid as u32);
self.ivs.resolve_delta(outer, inner, coords)
}
None => 0.0,
}
}
pub fn rsb_delta(&self, gid: u16, coords: &[f32]) -> f32 {
match self.rsb_map.as_ref() {
Some(m) => {
let (outer, inner) = m.resolve(gid as u32);
self.ivs.resolve_delta(outer, inner, coords)
}
None => 0.0,
}
}
pub fn has_advance_axis(&self) -> bool {
self.advance_map.is_some() || !self.ivs.subtables.is_empty()
}
}
#[derive(Debug, Clone)]
pub struct StatAxis {
pub tag: [u8; 4],
pub axis_name_id: u16,
pub axis_ordering: u16,
}
#[derive(Debug, Clone)]
pub enum StatAxisValue {
Single {
axis_index: u16,
flags: u16,
value_name_id: u16,
value: f32,
},
Range {
axis_index: u16,
flags: u16,
value_name_id: u16,
nominal_value: f32,
range_min: f32,
range_max: f32,
},
Linked {
axis_index: u16,
flags: u16,
value_name_id: u16,
value: f32,
linked_value: f32,
},
Combined {
flags: u16,
value_name_id: u16,
per_axis: Vec<(u16, f32)>,
},
}
impl StatAxisValue {
pub fn value_name_id(&self) -> u16 {
match self {
Self::Single { value_name_id, .. }
| Self::Range { value_name_id, .. }
| Self::Linked { value_name_id, .. }
| Self::Combined { value_name_id, .. } => *value_name_id,
}
}
}
#[derive(Debug, Clone)]
pub struct StatTable {
axes: Vec<StatAxis>,
axis_values: Vec<StatAxisValue>,
elided_fallback_name_id: u16,
}
impl StatTable {
pub fn parse(bytes: &[u8]) -> Option<Self> {
if bytes.len() < 18 {
return None;
}
let major = u16_be(bytes, 0)?;
if major != 1 {
return None;
}
let minor = u16_be(bytes, 2)?;
let design_axis_size = u16_be(bytes, 4)? as usize;
let design_axis_count = u16_be(bytes, 6)? as usize;
let design_axes_offset = u32_be(bytes, 8)? as usize;
let axis_value_count = u16_be(bytes, 12)? as usize;
let axis_values_offset = u32_be(bytes, 14)? as usize;
let elided_fallback_name_id = if minor >= 1 && bytes.len() >= 20 {
u16_be(bytes, 18)?
} else {
2
};
if design_axis_size < 8 {
return None;
}
let need = design_axes_offset + design_axis_count * design_axis_size;
if bytes.len() < need {
return None;
}
let mut axes = Vec::with_capacity(design_axis_count);
for i in 0..design_axis_count {
let off = design_axes_offset + i * design_axis_size;
let mut tag = [0u8; 4];
tag.copy_from_slice(&bytes[off..off + 4]);
let axis_name_id = u16_be(bytes, off + 4)?;
let axis_ordering = u16_be(bytes, off + 6)?;
axes.push(StatAxis {
tag,
axis_name_id,
axis_ordering,
});
}
let mut axis_values = Vec::with_capacity(axis_value_count);
if axis_values_offset != 0 && axis_value_count > 0 {
let off_table_end = axis_values_offset + axis_value_count * 2;
if bytes.len() < off_table_end {
return None;
}
for i in 0..axis_value_count {
let off_off = axis_values_offset + i * 2;
let rec_off = axis_values_offset + u16_be(bytes, off_off)? as usize;
if rec_off + 8 > bytes.len() {
return None;
}
let format = u16_be(bytes, rec_off)?;
match format {
1 => {
if rec_off + 12 > bytes.len() {
return None;
}
let axis_index = u16_be(bytes, rec_off + 2)?;
let flags = u16_be(bytes, rec_off + 4)?;
let value_name_id = u16_be(bytes, rec_off + 6)?;
let value = fixed_to_f32(i32_be(bytes, rec_off + 8)?);
axis_values.push(StatAxisValue::Single {
axis_index,
flags,
value_name_id,
value,
});
}
2 => {
if rec_off + 20 > bytes.len() {
return None;
}
let axis_index = u16_be(bytes, rec_off + 2)?;
let flags = u16_be(bytes, rec_off + 4)?;
let value_name_id = u16_be(bytes, rec_off + 6)?;
let nominal_value = fixed_to_f32(i32_be(bytes, rec_off + 8)?);
let range_min = fixed_to_f32(i32_be(bytes, rec_off + 12)?);
let range_max = fixed_to_f32(i32_be(bytes, rec_off + 16)?);
axis_values.push(StatAxisValue::Range {
axis_index,
flags,
value_name_id,
nominal_value,
range_min,
range_max,
});
}
3 => {
if rec_off + 16 > bytes.len() {
return None;
}
let axis_index = u16_be(bytes, rec_off + 2)?;
let flags = u16_be(bytes, rec_off + 4)?;
let value_name_id = u16_be(bytes, rec_off + 6)?;
let value = fixed_to_f32(i32_be(bytes, rec_off + 8)?);
let linked_value = fixed_to_f32(i32_be(bytes, rec_off + 12)?);
axis_values.push(StatAxisValue::Linked {
axis_index,
flags,
value_name_id,
value,
linked_value,
});
}
4 => {
let axis_count = u16_be(bytes, rec_off + 2)? as usize;
let flags = u16_be(bytes, rec_off + 4)?;
let value_name_id = u16_be(bytes, rec_off + 6)?;
let per_axis_off = rec_off + 8;
let need = per_axis_off + axis_count * 6;
if need > bytes.len() {
return None;
}
let mut per_axis = Vec::with_capacity(axis_count);
for k in 0..axis_count {
let p = per_axis_off + k * 6;
let ai = u16_be(bytes, p)?;
let v = fixed_to_f32(i32_be(bytes, p + 2)?);
per_axis.push((ai, v));
}
axis_values.push(StatAxisValue::Combined {
flags,
value_name_id,
per_axis,
});
}
_ => {
}
}
}
}
Some(Self {
axes,
axis_values,
elided_fallback_name_id,
})
}
pub fn axes(&self) -> &[StatAxis] {
&self.axes
}
pub fn axis_values(&self) -> &[StatAxisValue] {
&self.axis_values
}
pub fn elided_fallback_name_id(&self) -> u16 {
self.elided_fallback_name_id
}
}
#[inline]
fn fixed_to_f32(raw: i32) -> f32 {
raw as f32 / 65536.0
}
#[derive(Clone)]
pub struct NameTableSnapshot {
records: Vec<(i32, u16, String)>,
}
impl Debug for NameTableSnapshot {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("NameTableSnapshot")
.field("records", &self.records.len())
.finish()
}
}
impl NameTableSnapshot {
pub fn parse(bytes: &[u8]) -> Option<Self> {
if bytes.len() < 6 {
return None;
}
let format = u16_be(bytes, 0)?;
if format > 1 {
return None;
}
let count = u16_be(bytes, 2)? as usize;
let string_offset = u16_be(bytes, 4)? as usize;
let need = 6 + count * 12;
if bytes.len() < need || string_offset > bytes.len() {
return None;
}
let mut records = Vec::with_capacity(count);
for i in 0..count {
let off = 6 + i * 12;
let platform = u16_be(bytes, off)?;
let encoding = u16_be(bytes, off + 2)?;
let language = u16_be(bytes, off + 4)?;
let name_id = u16_be(bytes, off + 6)?;
let length = u16_be(bytes, off + 8)? as usize;
let str_off = u16_be(bytes, off + 10)? as usize;
let start = string_offset + str_off;
let end = match start.checked_add(length) {
Some(e) if e <= bytes.len() => e,
_ => continue,
};
let raw = &bytes[start..end];
let rank = rank_record(platform, encoding, language);
let decoded = match decode_name(platform, encoding, raw) {
Some(s) => s,
None => continue,
};
records.push((rank, name_id, decoded));
}
Some(Self { records })
}
pub fn find(&self, name_id: u16) -> Option<&str> {
let mut best: Option<(i32, &str)> = None;
for (rank, nid, s) in &self.records {
if *nid != name_id {
continue;
}
match best {
Some((br, _)) if br >= *rank => {}
_ => best = Some((*rank, s.as_str())),
}
}
best.map(|(_, s)| s)
}
}
fn rank_record(platform: u16, encoding: u16, language: u16) -> i32 {
match (platform, encoding, language) {
(3, 1, 0x0409) => 100, (3, 1, l) if l & 0xFF == 9 => 90,
(3, 1, _) => 80,
(3, 10, _) => 75, (1, 0, 0) => 70,
(0, _, _) => 60,
_ => 10,
}
}
fn decode_name(platform: u16, encoding: u16, raw: &[u8]) -> Option<String> {
match (platform, encoding) {
(0, _) | (3, 1) | (3, 10) => {
if raw.len() % 2 != 0 {
return None;
}
let mut s = String::with_capacity(raw.len() / 2);
let mut i = 0;
while i + 1 < raw.len() {
let u = u16::from_be_bytes([raw[i], raw[i + 1]]);
i += 2;
if (0xD800..=0xDBFF).contains(&u) {
if i + 1 >= raw.len() {
return None;
}
let lo = u16::from_be_bytes([raw[i], raw[i + 1]]);
if !(0xDC00..=0xDFFF).contains(&lo) {
return None;
}
i += 2;
let cp = 0x10000 + (((u - 0xD800) as u32) << 10) + (lo - 0xDC00) as u32;
s.push(char::from_u32(cp)?);
} else {
s.push(char::from_u32(u as u32)?);
}
}
Some(s)
}
(1, 0) => Some(
raw.iter()
.map(|&b| if b < 0x80 { b as char } else { '?' })
.collect(),
),
_ => None,
}
}
#[derive(Debug, Clone)]
pub struct Cff2Table {
pub glyph_count: u32,
pub axis_count: u16,
pub has_charstrings: bool,
}
impl Cff2Table {
pub fn parse(bytes: &[u8]) -> Option<Self> {
if bytes.len() < 5 {
return None;
}
let major = bytes[0];
let _minor = bytes[1];
let header_size = bytes[2] as usize;
let top_dict_length = u16_be(bytes, 3)? as usize;
if major != 2 {
return None;
}
if header_size < 5 || header_size + top_dict_length > bytes.len() {
return None;
}
let top_dict = &bytes[header_size..header_size + top_dict_length];
let cursor = header_size + top_dict_length;
let _global_subrs_end = cff2_index_end(bytes, cursor)?;
let (charstrings_off, vstore_off) = parse_cff2_top_dict(top_dict)?;
let glyph_count = if let Some(cs_off) = charstrings_off {
cff2_index_count(bytes, cs_off as usize).unwrap_or(0)
} else {
0
};
let axis_count = match vstore_off {
Some(v) => {
let v = v as usize;
if v + 2 > bytes.len() {
0
} else {
let _len = u16_be(bytes, v)?;
let store = ItemVariationStore::parse(bytes, v + 2)?;
store.axis_count()
}
}
None => 0,
};
Some(Self {
glyph_count,
axis_count,
has_charstrings: glyph_count > 0,
})
}
}
fn cff2_index_end(bytes: &[u8], offset: usize) -> Option<usize> {
if offset + 4 > bytes.len() {
return None;
}
let count = u32_be(bytes, offset)?;
if count == 0 {
return Some(offset + 4);
}
if offset + 5 > bytes.len() {
return None;
}
let off_size = bytes[offset + 4] as usize;
if !(1..=4).contains(&off_size) {
return None;
}
let off_array_off = offset + 5;
let off_array_end = off_array_off + off_size * (count as usize + 1);
if off_array_end > bytes.len() {
return None;
}
let last_off_off = off_array_off + off_size * count as usize;
let mut last = 0u32;
for i in 0..off_size {
last = (last << 8) | bytes[last_off_off + i] as u32;
}
let data_area_end = off_array_end + (last as usize).saturating_sub(1);
if data_area_end > bytes.len() {
return None;
}
Some(data_area_end)
}
fn cff2_index_count(bytes: &[u8], offset: usize) -> Option<u32> {
if offset + 4 > bytes.len() {
return None;
}
u32_be(bytes, offset)
}
fn parse_cff2_top_dict(dict: &[u8]) -> Option<(Option<u32>, Option<u32>)> {
let mut cursor = 0usize;
let mut operands: Vec<i32> = Vec::with_capacity(8);
let mut charstrings: Option<u32> = None;
let mut vstore: Option<u32> = None;
while cursor < dict.len() {
let b0 = dict[cursor];
cursor += 1;
if b0 <= 21 {
let op = if b0 == 12 {
if cursor >= dict.len() {
return None;
}
let b1 = dict[cursor];
cursor += 1;
0x0C00 | b1 as u16
} else {
b0 as u16
};
let last = operands.last().copied();
match op {
17 => {
if let Some(v) = last {
if v >= 0 {
charstrings = Some(v as u32);
}
}
}
24 => {
if let Some(v) = last {
if v >= 0 {
vstore = Some(v as u32);
}
}
}
_ => {}
}
operands.clear();
} else {
let v = match b0 {
28 => {
if cursor + 2 > dict.len() {
return None;
}
let v = i16::from_be_bytes([dict[cursor], dict[cursor + 1]]) as i32;
cursor += 2;
v
}
29 => {
if cursor + 4 > dict.len() {
return None;
}
let v = i32::from_be_bytes([
dict[cursor],
dict[cursor + 1],
dict[cursor + 2],
dict[cursor + 3],
]);
cursor += 4;
v
}
30 => {
let mut done = false;
while !done {
if cursor >= dict.len() {
return None;
}
let b = dict[cursor];
cursor += 1;
if (b & 0x0F) == 0x0F || (b & 0xF0) == 0xF0 {
done = true;
}
}
0
}
32..=246 => b0 as i32 - 139,
247..=250 => {
if cursor >= dict.len() {
return None;
}
let b1 = dict[cursor] as i32;
cursor += 1;
(b0 as i32 - 247) * 256 + b1 + 108
}
251..=254 => {
if cursor >= dict.len() {
return None;
}
let b1 = dict[cursor] as i32;
cursor += 1;
-((b0 as i32 - 251) * 256) - b1 - 108
}
_ => return None,
};
operands.push(v);
}
}
Some((charstrings, vstore))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn name_snapshot_decodes_utf16_be() {
let s = "Inter";
let utf16: Vec<u8> = s.encode_utf16().flat_map(|u| u.to_be_bytes()).collect();
let length = utf16.len() as u16;
let header_size = 6 + 12;
let mut out = vec![0u8; header_size];
out[2..4].copy_from_slice(&1u16.to_be_bytes()); out[4..6].copy_from_slice(&(header_size as u16).to_be_bytes()); out[6..8].copy_from_slice(&3u16.to_be_bytes()); out[8..10].copy_from_slice(&1u16.to_be_bytes()); out[10..12].copy_from_slice(&0x0409u16.to_be_bytes()); out[12..14].copy_from_slice(&256u16.to_be_bytes()); out[14..16].copy_from_slice(&length.to_be_bytes()); out[16..18].copy_from_slice(&0u16.to_be_bytes()); out.extend_from_slice(&utf16);
let n = NameTableSnapshot::parse(&out).expect("parse");
assert_eq!(n.find(256), Some("Inter"));
assert_eq!(n.find(257), None);
}
#[test]
fn item_variation_store_resolves_zero_for_default_coords() {
let region_list_off = 12u32;
let ivd_off = 22u32;
let mut b = Vec::new();
b.extend_from_slice(&1u16.to_be_bytes()); b.extend_from_slice(®ion_list_off.to_be_bytes());
b.extend_from_slice(&1u16.to_be_bytes()); b.extend_from_slice(&ivd_off.to_be_bytes());
debug_assert_eq!(b.len() as u32, region_list_off);
b.extend_from_slice(&1u16.to_be_bytes()); b.extend_from_slice(&1u16.to_be_bytes()); b.extend_from_slice(&(-16384i16).to_be_bytes());
b.extend_from_slice(&(16384i16).to_be_bytes());
b.extend_from_slice(&(16384i16).to_be_bytes());
debug_assert_eq!(b.len() as u32, ivd_off);
b.extend_from_slice(&1u16.to_be_bytes()); b.extend_from_slice(&0u16.to_be_bytes()); b.extend_from_slice(&1u16.to_be_bytes()); b.extend_from_slice(&0u16.to_be_bytes()); b.push(10u8); let s = ItemVariationStore::parse(&b, 0).expect("parse");
assert!((s.resolve_delta(0, 0, &[0.0]) - 0.0).abs() < 1e-6);
assert!((s.resolve_delta(0, 0, &[1.0]) - 10.0).abs() < 1e-6);
assert!((s.resolve_delta(0, 0, &[0.5]) - 7.5).abs() < 1e-6);
}
#[test]
fn delta_set_index_map_resolves_short_form() {
let raw = [
0u8, 0x30, ];
let mut b = vec![
0u8, 0x03, 0u8, 3, 0x10, 0x21, 0x32,
];
let _ = raw;
let m = DeltaSetIndexMap::parse(&b, 0).expect("parse");
assert_eq!(m.resolve(0), (1, 0));
assert_eq!(m.resolve(1), (2, 1));
assert_eq!(m.resolve(2), (3, 2));
assert_eq!(m.resolve(99), (3, 2));
b = vec![
0u8, 0x13, 0u8, 1, 0x00, 0x42, ];
let m2 = DeltaSetIndexMap::parse(&b, 0).expect("parse");
assert_eq!(m2.resolve(0), (4, 2));
}
#[test]
fn cff2_index_walker_handles_empty_and_nonempty() {
let empty = [0u8; 4];
assert_eq!(cff2_index_end(&empty, 0), Some(4));
let mut b = Vec::new();
b.extend_from_slice(&1u32.to_be_bytes()); b.push(1u8); b.push(1u8); b.push(4u8); b.extend_from_slice(&[0xAA, 0xBB, 0xCC]);
assert_eq!(cff2_index_end(&b, 0), Some(b.len()));
}
#[test]
fn stat_axis_value_format1_round_trip() {
let header_size = 20usize;
let design_axes_offset = header_size;
let design_axis_size = 8usize;
let axis_value_offset_table = design_axes_offset + design_axis_size;
let av_record_offset = axis_value_offset_table + 2;
let mut b = vec![0u8; av_record_offset + 12];
b[0..2].copy_from_slice(&1u16.to_be_bytes()); b[2..4].copy_from_slice(&1u16.to_be_bytes()); b[4..6].copy_from_slice(&8u16.to_be_bytes()); b[6..8].copy_from_slice(&1u16.to_be_bytes()); b[8..12].copy_from_slice(&(design_axes_offset as u32).to_be_bytes());
b[12..14].copy_from_slice(&1u16.to_be_bytes()); b[14..18].copy_from_slice(&(axis_value_offset_table as u32).to_be_bytes());
b[18..20].copy_from_slice(&2u16.to_be_bytes()); b[design_axes_offset..design_axes_offset + 4].copy_from_slice(b"wght");
b[design_axes_offset + 4..design_axes_offset + 6].copy_from_slice(&256u16.to_be_bytes()); let av_rel = (av_record_offset - axis_value_offset_table) as u16;
b[axis_value_offset_table..axis_value_offset_table + 2]
.copy_from_slice(&av_rel.to_be_bytes());
let r = av_record_offset;
b[r..r + 2].copy_from_slice(&1u16.to_be_bytes());
b[r + 2..r + 4].copy_from_slice(&0u16.to_be_bytes());
b[r + 4..r + 6].copy_from_slice(&0u16.to_be_bytes());
b[r + 6..r + 8].copy_from_slice(&257u16.to_be_bytes());
b[r + 8..r + 12].copy_from_slice(&((400i32) << 16).to_be_bytes());
let _ = av_rel;
let _ = av_record_offset;
let s = StatTable::parse(&b).expect("parse");
assert_eq!(s.axes().len(), 1);
assert_eq!(&s.axes()[0].tag, b"wght");
assert_eq!(s.axes()[0].axis_name_id, 256);
assert_eq!(s.elided_fallback_name_id(), 2);
match &s.axis_values()[0] {
StatAxisValue::Single {
axis_index,
value_name_id,
value,
..
} => {
assert_eq!(*axis_index, 0);
assert_eq!(*value_name_id, 257);
assert!((value - 400.0).abs() < 1e-3);
}
other => panic!("wrong format: {other:?}"),
}
}
}