From dd64f1797ee2cefa59cb2c8e093fb0a02f9b3cae Mon Sep 17 00:00:00 2001 From: Charan Rathore <180254320+charan-rathore@users.noreply.github.com> Date: Sun, 18 Oct 2026 16:43:48 +0530 Subject: [PATCH] hayro-cmap patch: an unresolved usecmap with no mappings reports failure --- vendor/hayro-cmap/src/parse.rs | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/vendor/hayro-cmap/src/parse.rs b/vendor/hayro-cmap/src/parse.rs index 2a89fdbac..1137ab078 100644 --- a/vendor/hayro-cmap/src/parse.rs +++ b/vendor/hayro-cmap/src/parse.rs @@ -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()