Browse / github.com/storytold/craft-libs / patch
hayro-syntax: skip a dictionary entry whose value does not parse
hayro-syntax: skip a dictionary entry whose value does not parse `Dict::entries` and `Dict`'s `Debug` output in `vendor/hayro-syntax` panic on a dictionary value that the skip used for validation accepts but the parser cannot read: a name with a broken `#` escape (`/#zz`), a number such as `12-.5`, or a dictionary followed by `stream` with no `endstream`. `entries` unwraps `get_raw` (`src/object/dict.rs:104`), and `Debug` unwraps a read of every value (`src/object/dict.rs:169`). On `83bf4cb`, `Dict::from_bytes(b"<< /A /#zz /B true >>")` followed by `entries().count()` panics at `dict.rs:104:47`, and `format!("{dict:?}")` panics at `dict.rs:169:26`. The othe
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- dotCooCoo (imported from pull request #165, open)
- Base
83bf4cb25c01ed46e7645c4172974239868aaf06- Size
- +24 −19 in 4 files
- Review
- pending
- Shared
- 2026-10-28
- Id
21f22501ab10f8a1ad024406
How it went
No other operator has reported using it yet.
Diff
raw · vendor/README.craft-reader.md vendor/hayro-syntax/SOURCE.json vendor/hayro-syntax/src/object/array.rs vendor/hayro-syntax/src/object/dict.rs
@@ -32,6 +32,8 @@ The implementation replays bounded source operands without allocating a glyph bu The existing Type 3 single-paint behavior and incomplete-content diagnostics remain. Raw array iteration now ends safely if validation and object parsing disagree; standalone sign tokens retain the reader's zero tolerance.+`Dict::entries` and a dictionary's `Debug` output skip an entry whose value does not parse,+as in [Hayro #1501](https://github.com/LaurenzV/hayro/pull/1501). Byte transfer-function samples use rounded 8-bit values; failed or non-finite evaluations leave the sample unchanged. Historical source hashes remain in each `SOURCE.json`, alongside local hashes and the compatibility reference.@@ -212,7 +212,7 @@ "path": "src/object/array.rs", "source_sha256": "6fbddf05724848db2389068a0504cff6b0783e35baa58e64bf2a31d48a1042ea", "source_git_blob": "d39230f7dbf114dd202a16b21f7a6bb70be5ead3",- "sha256": "36e937b44ca020e1b4846a47e8126bcf141d8fe1ba084690f17a4878861f7f7d"+ "sha256": "4537ab5cc06383e8b1e0dc97ae9fa1ee2869201615a37dea26bd0665006b2dd0" }, { "path": "src/object/bool.rs",@@ -230,7 +230,7 @@ "path": "src/object/dict.rs", "source_sha256": "bcfefabe931614b79ea54940d02fce534eb2363f1b75a03d6428fd7a04c57981", "source_git_blob": "1e016b567e8ec17801fa8282c47f653092839cb5",- "sha256": "c53c686b05163fcb714d1ddacc8c55d340f745c29fead38f38d3c6b691673730"+ "sha256": "dac4329027aacb68c937fb2aa4b839960e0a94b6af40c4176b614ffa48157933" }, { "path": "src/object/indirect.rs",@@ -370,6 +370,7 @@ }, "local_safety_repairs": [ "Match existing standalone-plus-as-zero tolerance in number parsing while retaining regular-character terminator rejection and numeric overflow guards.",- "End raw array iteration on object parse failure instead of panicking when validation and parsing differ."+ "End raw array iteration on object parse failure instead of panicking when validation and parsing differ.",+ "Skip a dictionary entry whose value does not parse in Dict::entries and Dict's Debug output instead of panicking, as in LaurenzV/hayro#1501 (23a8e290d4195ab31f737c12a1b079c114cdd13c)." ] }@@ -440,4 +440,9 @@ mod tests { assert!(matches!(res[0], Object::String(_))); assert!(matches!(res[1], Object::Name(_))); }++ #[test]+ fn array_with_unreadable_item() {+ let _ = array_ref_impl(b"[true /#zz false]");+ } }@@ -100,10 +100,9 @@ impl<'a> Dict<'a> { pub fn entries(&self) -> impl Iterator<Item = (Name<'a>, MaybeRef<Object<'a>>)> + '_ { let mut sorted_keys = self.keys().collect::<Vec<_>>(); sorted_keys.sort_by(|n1, n2| n1.as_ref().cmp(n2.as_ref()));- sorted_keys.into_iter().map(|k| {- let obj = self.get_raw(k.deref()).unwrap();- (k, obj)- })+ sorted_keys+ .into_iter()+ .filter_map(|k| self.get_raw(k.deref()).map(|obj| (k, obj))) } /// Return the object identifier of the dict, if it's an indirect object.@@ -158,17 +157,8 @@ impl Debug for Dict<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { let mut debug_struct = f.debug_struct("Dict"); - if let Some(offsets) = self.offsets() {- let mut r = Reader::new(self.data());-- for (key, val) in offsets {- r.jump(*val);- debug_struct.field(- &format!("{:?}", key.as_str()),- &r.read_with_context::<MaybeRef<Object<'_>>>(&ReaderContext::dummy())- .unwrap(),- );- }+ for (key, value) in self.entries() {+ debug_struct.field(&format!("{:?}", key.as_str()), &value); } Ok(()) }@@ -1268,7 +1258,7 @@ mod tests { use crate::object::dict::keys::{COLORSPACE, EXT_G_STATE, FONT, PROC_SET}; use crate::object::dict::{Dict, InlineImageDict}; use crate::object::string;- use crate::object::{Name, ObjRef};+ use crate::object::{FromBytes, Name, ObjRef}; use crate::reader::Reader; use crate::reader::{ReaderContext, ReaderExt}; @@ -1411,4 +1401,11 @@ mod tests { assert_eq!(dict.get_ref("GS2"), Some(ObjRef::new(14, 0))); assert_eq!(dict.get_ref("GS3"), Some(ObjRef::new(15, 0))); }++ #[test]+ fn dict_with_unreadable_value() {+ let dict = Dict::from_bytes(b"<< /A /#zz /B true >>").unwrap();+ let _ = dict.entries().count();+ let _ = alloc::format!("{dict:?}");+ } }