use crate::error::PdfError;
use crate::Result;
use std::collections::{HashMap, HashSet};
pub fn parse_cmap_format_12_filtered(
cmap: &[u8],
offset: usize,
used_codepoints: Option<&HashSet<u32>>,
) -> Result<HashMap<u32, u16>> {
if offset + 16 > cmap.len() {
return Err(PdfError::FontError(
"cmap Format 12 header truncated".to_string(),
));
}
let num_groups = u32::from_be_bytes([
cmap[offset + 12],
cmap[offset + 13],
cmap[offset + 14],
cmap[offset + 15],
]) as usize;
let groups_start = offset + 16;
if groups_start + num_groups * 12 > cmap.len() {
return Err(PdfError::FontError(
"cmap Format 12 groups truncated".to_string(),
));
}
let mut map = HashMap::new();
for i in 0..num_groups {
let base = groups_start + i * 12;
let start_char =
u32::from_be_bytes([cmap[base], cmap[base + 1], cmap[base + 2], cmap[base + 3]]);
let end_char = u32::from_be_bytes([
cmap[base + 4],
cmap[base + 5],
cmap[base + 6],
cmap[base + 7],
]);
let start_glyph = u32::from_be_bytes([
cmap[base + 8],
cmap[base + 9],
cmap[base + 10],
cmap[base + 11],
]);
if end_char < start_char {
continue;
}
for j in 0..=(end_char - start_char) {
let code = start_char + j;
let gid = start_glyph + j;
if gid == 0 || gid > 0xFFFF {
continue;
}
if let Some(filter) = used_codepoints {
if !filter.contains(&code) {
continue;
}
}
map.insert(code, gid as u16);
}
}
Ok(map)
}