Refuse encoding unverified glyphs after a font decode allowance refusal

This commit is contained in:
FredApps committed 2026-11-08 14:39:32 +01:00
1 parent ef7f2f3116
commit 6f5f361368
2 files changed
+30 -1

No files matched your search

+7 -1
View File
@@ -979,8 +979,14 @@ impl Metrics {
}
/// The bytes that show `text` in this font, or `None` if some character has no code or
/// no glyph in it (the caller then substitutes another font).
/// no glyph in it, or the metrics were read past their allowance (the caller then substitutes
/// another font). Empty text needs no verified glyph and always encodes.
pub fn encode(&self, text: &str) -> Option<Vec<u8>> {
// A refused read cannot establish the mappings or glyphs needed to write new text.
// Empty text needs neither and remains usable for erasing existing text.
if self.past_allowance && !text.is_empty() {
return None;
}
// The lowest code showing each wanted character. Explicit entries and the encoding are
// checked one by one; each range is asked for the wanted characters it can show.
let wanted: HashSet<char> = text.chars().collect();
+23
View File
@@ -1173,3 +1173,26 @@ fn low_codes_resolve_to_the_covering_range() {
assert_eq!(covered, [5, 6, 7, 100, 101]);
assert_eq!((u.covering(0xFFFF).is_some(), u.covering(0x1_0001).is_some(), u.covering(0x1_0002).is_none()), (true, true, true));
}
#[test]
fn refused_subset_reads_do_not_encode_unverified_glyphs() {
let mut doc = Document::new_empty();
let (mut f, sizes) = subset_type0(&mut doc, b"");
f.set(b"Encoding".to_vec(), Object::name("Identity-H"));
f.set(b"ToUnicode".to_vec(), Object::name("Identity-H"));
if let Some(Object::Array(descendants)) = f.get_mut(b"DescendantFonts")
&& let Some(Object::Dict(descendant)) = descendants.first_mut()
{
descendant.set(b"DW".to_vec(), Object::Int(1000));
}
let whole = Metrics::from_dict(&doc, &f);
assert!(!whole.past_allowance && !whole.outlined_cids.is_empty());
assert!(whole.encode("\u{ffff}").is_none());
// Refuse the program, then the CID map after reading the complete program.
for allowance in [0, sizes[1]] {
let partial = Metrics::from_dict_within(&doc, &f, &mut DecodeBudget::new(allowance, 0));
assert!(partial.past_allowance);
assert_eq!(partial.encode(""), Some(Vec::new()));
assert!(partial.encode("\u{ffff}").is_none(), "allowance {allowance} must not turn /DW into proof of a glyph");
}
}