Fix a hole in a sparse array being skipped when serialising - #1771
Conversation
9be8003 to
292f7f1
Compare
Not sure the best behavior here:
|
|
Throw, I think - and there is a precedent in the same feature area that settles it for me: doc.file(undefined, { name: 'x.txt' }); // Error: No src specified
doc.addNamedEmbeddedFile('x', undefined); // silently accepted
Of the three, silent drop is the one I would argue against hardest. The caller asked for an attachment under a name and gets back a valid PDF with nothing attached and no signal - harder to debug than a stack trace, and there is no legitimate reason to name an attachment with no file behind it. If you want the throw I would put it in I would keep the Technically breaking, though Unreleased already carries three Happy to push that if you want it - small change on top of this. |
It should be a different PR The The PDFTree.toString change AFAIK is triggered only synthetically so i am less inclined to merge |
`PDFObject.convert` used `.map` for arrays, which does not call back for holes, so a sparse array lost the entry entirely and every later index shifted down. A destination array is `[page /XYZ left top zoom]`, so building one by index and leaving `left`/`top` unset slid `zoom` two slots and a reader followed the wrong destination. Replaced with an indexed loop rather than `Array.from`, which also visits holes but defers to a subclass's custom iterator. A hole becomes `null`, matching what foliojs#1769 already does for an explicit `undefined` entry.
292f7f1 to
4abe432
Compare
|
Done — narrowed to the On "triggered only synthetically" — fair for the tree case, and I should have led const dest = new Array(5);
dest[0] = page;
dest[1] = 'XYZ';
dest[4] = zoom; // left and top deliberately unset
Down to 3 tests, 2 red on master, 394/394. |
|
Many thanks |
Narrowed to the
convertchange, per review.lib/tree.jsis untouched — Ichecked, and tree output is byte-identical to master. The
addNamedEmbeddedFilethrow will be a separate PR.The bug
.mapdoes not call back for holes, so a sparse array lost the entry entirelyand every later index shifted down. A destination array is
[page /XYZ left top zoom], and building one by index is an ordinary thing towrite when
leftandtopare optional:const dest = [page, 'XYZ']; dest[4] = zoom;does the same thing.pdf.js reads the damage rather than rejecting it, so the reader follows a
destination the caller never asked for:
getAnnotations()[0].dest[ref, /XYZ, 72, 3]— four entries[ref, /XYZ, 72, null, 3]nullis legal in exactly those positions — Table 151 defines it as "retain thecurrent value" for
left,topandzoom, andlib/mixins/annotations.jsalready writes
[page, 'XYZ', null, null, null]forgoTo.The fix
An indexed loop rather than
Array.from, which also visits holes but defers to asubclass's custom iterator. A hole becomes
null, which is what #1769 alreadydoes for an explicit
undefinedentry — this just makes the two agree.3 tests added, 2 of which fail against master. The third covers the dictionary
guard from #1769 and is a regression guard, not evidence for this change.
Full unit suite passes, 394/394.