mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-28 20:18:06 -06:00
clear_parent_tree walked /Nums with chunks_mut(2) and indexed pair[1], so a trailing key without a value that matched the page's StructParents panicked after the page content had already been replaced. Walk whole pairs only and leave an unpaired key as it is: it maps nothing, so there is nothing to clear. Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
Brandon Thomas
parent
0a054a425c
commit
e337a49631
@@ -414,12 +414,11 @@ fn clear_parent_tree(doc: &mut Document, key: i64, obj: ObjRef) -> Result<(), Al
|
||||
let Some(pt) = tree_root(doc).and_then(|r| r.get(b"ParentTree").and_then(Object::as_ref)) else { return Ok(()) };
|
||||
let Some(nums) = doc.get(pt).as_dict().and_then(|d| d.get(b"Nums").and_then(|n| n.as_array().cloned())) else { return Ok(()) };
|
||||
let mut nums = nums;
|
||||
for pair in nums.chunks_mut(2) {
|
||||
if pair[0].as_int() == Some(key) {
|
||||
match &pair[1] {
|
||||
Object::Array(a) => {
|
||||
pair[1] = Object::Array(a.iter().map(|x| if x.as_ref() == Some(obj) { Object::Null } else { x.clone() }).collect())
|
||||
}
|
||||
// Whole pairs only: a trailing key without a value maps nothing, so it is left as it is.
|
||||
for [k, v] in nums.as_chunks_mut::<2>().0 {
|
||||
if k.as_int() == Some(key) {
|
||||
match &*v {
|
||||
Object::Array(a) => *v = Object::Array(a.iter().map(|x| if x.as_ref() == Some(obj) { Object::Null } else { x.clone() }).collect()),
|
||||
Object::Ref(r) => {
|
||||
if let Some(a) = doc.get(*r).as_array().cloned() {
|
||||
let a: Vec<Object> = a.iter().map(|x| if x.as_ref() == Some(obj) { Object::Null } else { x.clone() }).collect();
|
||||
|
||||
@@ -607,6 +607,23 @@ fn marking_a_leaf_tag_as_an_artifact_preserves_appearance_and_structure_integrit
|
||||
assert_eq!(mark_tag_artifact(&mut doc, pdfcraft_cos::ObjRef::new(7, 0)), Err(ArtifactError::NotATag(7)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn marking_decorative_survives_a_parent_tree_with_an_unpaired_key() {
|
||||
// A trailing key without a value, matching the page's StructParents (#1809), and the same
|
||||
// with no valid pair at all.
|
||||
let tree = |nums: &str| pdf(&[format!("<< /Nums {nums} >>")], "").get(pdfcraft_cos::ObjRef::new(1, 0)).as_ref().clone();
|
||||
for (nums, cleared) in [("[0 [7 0 R 8 0 R] 0]", "[0 [null 8 0 R] 0]"), ("[0]", "[0]")] {
|
||||
let mut doc = figures_doc();
|
||||
let pt = pdfcraft_cos::ObjRef::new(9, 0);
|
||||
doc.set(pt, tree(nums));
|
||||
let f = figures(&doc);
|
||||
mark_decorative(&mut doc, f[0].obj).unwrap();
|
||||
assert_eq!(figures(&doc).len(), 1, "{nums}");
|
||||
// The pair is cleared and the unpaired key is kept as it was.
|
||||
assert_eq!(*doc.get(pt), tree(cleared), "{nums}");
|
||||
}
|
||||
}
|
||||
|
||||
fn ref_(n: u32) -> Option<pdfcraft_cos::ObjRef> {
|
||||
Some(pdfcraft_cos::ObjRef::new(n, 0))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user