From 69c87d2f3e3353a204b09f91a8fc9198c3e1fdca Mon Sep 17 00:00:00 2001 From: aiongg Date: Thu, 22 Oct 2026 01:48:30 +0000 Subject: [PATCH] Integration: #3195 keep CMap entries read before a stream ends inside a block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A begin… block cut off at the end of the stream returned None through ? and discarded the whole map; it now ends the scan like any other unparseable tail. Test: stream_cut_off_inside_a_block_keeps_the_entries_before_it. --- vendor/hayro-cmap/src/lib.rs | 7 ++++++ vendor/hayro-cmap/src/parse.rs | 41 ++++++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/vendor/hayro-cmap/src/lib.rs b/vendor/hayro-cmap/src/lib.rs index 4786e75e52..fb42ff37ec 100644 --- a/vendor/hayro-cmap/src/lib.rs +++ b/vendor/hayro-cmap/src/lib.rs @@ -1117,6 +1117,13 @@ endbfchar ); } + #[test] + fn stream_cut_off_inside_a_block_keeps_the_entries_before_it() { + let cmap = parse_with_preamble(b"1 beginbfchar <41> <0058>\n<42> <00"); + assert_eq!(cmap.lookup_bf_string(0x41), Some(BfString::Char('X'))); + assert_eq!(cmap.lookup_bf_string(0x42), None); + } + #[test] fn truncated_stream_with_no_entries_reports_failure() { // The tolerant parser keeps collected entries, but a stream that diff --git a/vendor/hayro-cmap/src/parse.rs b/vendor/hayro-cmap/src/parse.rs index 1137ab078d..a936209275 100644 --- a/vendor/hayro-cmap/src/parse.rs +++ b/vendor/hayro-cmap/src/parse.rs @@ -50,8 +50,10 @@ pub(crate) fn parse_inner<'a>( let mut last_name: Option> = None; // PdfCraft patch: track whether the scan was cut short. A CMap with an - // unparseable tail keeps the entries read so far instead of being - // discarded wholesale; one that yielded nothing still reports failure. + // unparseable tail, including one that ends inside a `begin…` block, + // keeps the entries read so far (the block parsers push into the shared + // lists as they go) 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 @@ -94,25 +96,46 @@ pub(crate) fn parse_inner<'a>( } else { match name.as_str() { Some("begincodespacerange") => { - parse_codespace_range(&mut scanner, &mut _codespace_ranges, &mut ctx)?; + if parse_codespace_range(&mut scanner, &mut _codespace_ranges, &mut ctx).is_none() { + truncated = true; + break; + } } Some("begincidrange") => { - parse_range(&mut scanner, &mut ranges, &mut ctx, "endcidrange")?; + if parse_range(&mut scanner, &mut ranges, &mut ctx, "endcidrange").is_none() { + truncated = true; + break; + } } Some("begincidchar") => { - parse_char(&mut scanner, &mut ranges, &mut ctx, "endcidchar")?; + if parse_char(&mut scanner, &mut ranges, &mut ctx, "endcidchar").is_none() { + truncated = true; + break; + } } Some("beginnotdefrange") => { - parse_range(&mut scanner, &mut notdef_ranges, &mut ctx, "endnotdefrange")?; + if parse_range(&mut scanner, &mut notdef_ranges, &mut ctx, "endnotdefrange").is_none() { + truncated = true; + break; + } } Some("beginnotdefchar") => { - parse_char(&mut scanner, &mut notdef_ranges, &mut ctx, "endnotdefchar")?; + if parse_char(&mut scanner, &mut notdef_ranges, &mut ctx, "endnotdefchar").is_none() { + truncated = true; + break; + } } Some("beginbfchar") => { - parse_bf_char(&mut scanner, &mut bf_entries, &mut ctx)?; + if parse_bf_char(&mut scanner, &mut bf_entries, &mut ctx).is_none() { + truncated = true; + break; + } } Some("beginbfrange") => { - parse_bf_range(&mut scanner, &mut bf_entries, &mut ctx)?; + if parse_bf_range(&mut scanner, &mut bf_entries, &mut ctx).is_none() { + truncated = true; + break; + } } Some("usecmap") => { // PdfCraft patch: an unresolvable or unparseable `usecmap`