Skip to content

Stop throwing away the files a document carries - #20

Merged
tannevaled merged 1 commit into
mainfrom
carry-the-files
Aug 30, 2026
Merged

Stop throwing away the files a document carries#20
tannevaled merged 1 commit into
mainfrom
carry-the-files

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

A PDF can hold whole files inside it — the spreadsheet a report was drawn from, the XML a form was filled from, the source of a figure. Every verb here dropped them.

Not out of carelessness: the catalogue's /Names was dropped whole, on the ground that a name tree points into the document rather than describing it. That is true of /Dests, whose names point at pages this reorders and removes, and of /JavaScript, which is code. It is not true of /EmbeddedFiles: a file inside a document belongs to no page, so nothing here can invalidate it — and nothing on the page says it is there, so nobody notices it went until the file is wanted.

45 of the 3 215 documents in the forms and scans corpora carry one, 50 files between them.

So they are carried, and three verbs follow from having to read them anyway: Attachments lists what a document holds, Attach puts one in, Detach takes one out. Two files under one name is a document that has lost one of them, so a name already used is refused rather than quietly replacing what is there. A sanitised file still carries nothing inside it — that is what sanitising is for.

What the tests found

Files from several documents are all kept, unlike everything else in the catalogue: two forms cannot be merged and two catalogues cannot be chosen between, but two sets of files can simply both be carried. Writing that test is what found the bug — Attachments read the single source, and a merged document has none.

Two things a specification can point at are not files, and both are left out rather than handed over empty: one that names no stream, and one whose stream is still in a filter nothing here unpacks. DecodeStream hands those back as they were stored and names what they are in, so passing them on gives somebody a spreadsheet that is not one.

Judged by poppler rather than by ourselves

pdfdetach -list says 1 file before and 2 after a rotation and an addition, and -saveall writes both with the right bytes.

Parity: BentoPDF's Add Attachments, Extract Attachments and Edit Attachments.

100% statement coverage, go vet and -race clean, nine cross-compile targets.

A PDF can hold whole files inside it — the spreadsheet a report was drawn from,
the XML a form was filled from, the source of a figure. Every verb here dropped
them.

Not out of carelessness: the catalogue's /Names was dropped whole, on the
ground that a name tree points INTO the document rather than describing it.
That is true of /Dests, whose names point at pages this reorders and removes,
and of /JavaScript, which is code. It is not true of /EmbeddedFiles. A file
inside a document belongs to no page, so nothing here can invalidate it — and
nothing on the page says it is there, so nobody notices it went until the file
is wanted.

45 of the 3 215 documents in the forms and scans corpora carry one, 50 files
between them.

So they are carried, and three verbs follow from having to read them anyway:
Attachments lists what a document holds, Attach puts one in, Detach takes one
out. Two files under one name is a document that has lost one of them, so a
name already used is refused rather than quietly replacing what is there.

A sanitised file still carries nothing inside it. That is what sanitising is
for.

Files from SEVERAL documents are all kept, unlike everything else in the
catalogue. Two forms cannot be merged and two catalogues cannot be chosen
between; two sets of files can simply both be carried, because a file belongs
to no page and so cannot be in conflict. The test for that is what found the
bug: Attachments read the single source and a merged document has none.

Two things a specification can point at are not files, and both are left out
rather than handed over empty. One that names no stream at all. And one whose
stream is still in a filter nothing here unpacks — DecodeStream hands those
back as they were STORED and names what they are in, so passing them on gives
somebody a spreadsheet that is not one.

Judged by poppler rather than by ourselves: pdfdetach lists one file before and
two after a rotation and an addition, and saves both with the right bytes.

100% statement coverage, go vet and -race clean, nine cross-compile targets.
@tannevaled
tannevaled merged commit 89847c4 into main Aug 30, 2026
1 check passed
@tannevaled
tannevaled deleted the carry-the-files branch August 30, 2026 13:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant