hayro-cmap patch: an unresolved usecmap with no mappings reports failure

This commit is contained in:
Charan Rathore
2026-10-18 16:43:48 +05:30
committed by GitHub
parent fb1f72e9ed
commit dd64f1797e
+24 -7
View File
@@ -53,6 +53,12 @@ pub(crate) fn parse_inner<'a>(
// unparseable tail keeps the entries read so far instead of being
// discarded wholesale; one that yielded nothing still reports failure.
let mut truncated = false;
// PdfCraft patch: track a `usecmap` reference that could not be resolved
// or parsed. When the stream yields no mappings of its own, the caller
// must see failure rather than an empty map, so its encoding fallback
// paths run exactly as they did before the tolerant-usecmap change.
let mut usecmap_failed = false;
while !scanner.at_end() {
let Ok(obj) = scanner.parse_object() else {
truncated = true;
@@ -110,11 +116,20 @@ pub(crate) fn parse_inner<'a>(
}
Some("usecmap") => {
// PdfCraft patch: an unresolvable or unparseable `usecmap`
// reference drops only the base, not the whole CMap.
if let Some(name) = last_name.as_deref() {
if let Some(nested_data) = (ctx.get_cmap)(CMapName::from_bytes(name)) {
base = parse_inner(nested_data, ctx.get_cmap.clone(), depth + 1).map(Box::new);
// reference drops only the base, not the whole CMap, but
// is remembered so a stream that then yields no mappings
// at all still reports failure.
let resolved = last_name.as_deref().and_then(|name| {
(ctx.get_cmap)(CMapName::from_bytes(name))
});
match resolved {
Some(nested_data) => {
match parse_inner(nested_data, ctx.get_cmap.clone(), depth + 1) {
Some(nested) => base = Some(Box::new(nested)),
None => usecmap_failed = true,
}
}
None => usecmap_failed = true,
}
}
_ => {}
@@ -147,9 +162,11 @@ pub(crate) fn parse_inner<'a>(
writing_mode,
};
// PdfCraft patch: a truncated CMap that yielded nothing still reports failure,
// so callers fall back to the font's own encoding exactly as before.
if truncated
// PdfCraft patch: a CMap that was cut short or whose `usecmap` base could
// not be resolved, and that yielded no mappings of its own, still reports
// failure, so callers fall back to the font's own encoding exactly as
// before.
if (truncated || usecmap_failed)
&& ranges.is_empty()
&& notdef_ranges.is_empty()
&& bf_entries.is_empty()