Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
146 commits
Select commit Hold shift + click to select a range
cce7cc1
fix: read a stream's data each time it is asked for, and keep none of it
claude Oct 23, 2026
5dd8206
feat: bound the stream data the reader reads at once by MaxStreamLength
claude Oct 23, 2026
1b87828
fix: end a stream's data where its object ends, found by one search w…
claude Oct 23, 2026
f8f83da
fix: end an object's open containers at the next object's header
claude Oct 23, 2026
4b7c992
fix: settle a cross-reference stream's deferred length before its row…
claude Oct 23, 2026
79bc02d
fix: take a stream's /Length that a guard cut for the guard's, not th…
claude Oct 23, 2026
cd219bd
fix: end a stream's filters at a value a guard cut or left out of the…
claude Oct 23, 2026
249169e
docs: classify batch 16's bounds in ADR 34 and set them out for the r…
claude Oct 23, 2026
379b886
test: name PDFBox's zeroed object stream among the lengths qpdf takes…
claude Oct 23, 2026
759fc6a
docs: guide a caller through MaxStreamLength and a stream's data read…
claude Oct 23, 2026
9051f5d
docs: describe where a stream ends and what a guard's cut leaves in t…
claude Oct 23, 2026
f57375e
fix: read a stream's end the same however it is read again and wherev…
claude Oct 23, 2026
3f76c83
fix: name the object a guard cut at the end of a /Length's chain, and…
claude Oct 23, 2026
7bed3a2
fix: end the chain for the guard at a /Prev or /XRefStm that leads to…
claude Oct 23, 2026
b7129ee
fix: leave a header a window's edge cuts short to the edge, and name …
claude Oct 23, 2026
d3c44d1
fix: settle a cross-reference stream's deferred /Length through its r…
claude Oct 23, 2026
0c0bc40
test: open the stream length tests' corpus documents under a raised M…
claude Oct 23, 2026
9597631
fix: take a comment around a stream's end for white space only where …
claude Oct 23, 2026
f31a06d
fix: say a stream is an image only when decoding reaches its image fi…
claude Oct 23, 2026
7fd8bc4
fix: report a missing endstream when a guard left the /Length out of …
claude Oct 23, 2026
7fb39ae
fix: leave to the guard a cross-reference stream whose cut /Length ca…
claude Oct 23, 2026
080c98f
fix: report the cut MaxStreamLength makes to the diagnostics a caller…
claude Oct 23, 2026
00f2f03
docs: say a document held in memory lends its streams' raw bytes
claude Oct 23, 2026
b1a2dc8
test: hold that telling an image reaches a guard under ThrowOnLimit a…
claude Oct 23, 2026
123ddcf
docs: say what loading a value the filters read can throw from Decode…
claude Oct 23, 2026
54d963b
test: hold the paths of a stream's end that no test reached
claude Oct 23, 2026
3dd9d0a
refactor: drop a check no position can meet where a deferred length's…
claude Oct 23, 2026
cf7b1df
test: hold how a stream's end is read once the searches read as much …
claude Oct 23, 2026
c28d802
test: hold the retake of a deferred length by a row with no type field
claude Oct 23, 2026
d27cb45
test: hold that a deferred length a newer section refused takes no da…
claude Oct 23, 2026
e1452f6
refactor: keep what a guard's cut left of an object by whether it was…
claude Oct 23, 2026
18c3b3e
docs: bring the documents in line with the stream-end and guard rules…
claude Oct 23, 2026
43e3214
test: reach the two paths two coverage tests meant to and missed
claude Oct 23, 2026
7071b24
docs: say how a deferred length's chain and its endobj are read, past…
claude Oct 23, 2026
0e22445
fix: say what a /Prev or /XRefStm a guard cut leaves unchecked
claude Oct 23, 2026
0131a80
fix: name the link a cross-reference stream's /Length chain stops at
claude Oct 23, 2026
97b15cb
fix: read where a stream's data starts past a guard's window that end…
claude Oct 23, 2026
ce3decc
test: hold that a chain a guard ends leaves the rules that need it wh…
claude Oct 23, 2026
4a761b1
docs: say what a stream's raw and decoded bytes are and where their g…
claude Oct 23, 2026
4de73fc
fix: take no endobj a name or a comment holds for the one that ends a…
claude Oct 23, 2026
c4bf5b3
fix: leave rows past a spelled endstream to the guard wherever the cu…
claude Oct 23, 2026
5d31559
fix: follow a chain to the object a guard cut as far as its value is …
claude Oct 23, 2026
25bff0f
fix: ask a larger window of a stream keyword a regular byte may go on
claude Oct 23, 2026
811f3bf
fix: leave a header a window's edge cuts to the edge only where one m…
claude Oct 23, 2026
7cce393
fix: take no endobj a window's edge reaches for whole
claude Oct 23, 2026
d134848
docs: say where decoding ends at a value a guard cut, and where that …
claude Oct 23, 2026
5b30aa1
test: hold the copy of a hidden chain on relocation and the check kep…
claude Oct 23, 2026
80e8551
docs: say which code a stream taken without a search earns, and what …
claude Oct 23, 2026
640d9ff
test: reach three paths of a stream's end no test took
claude Oct 23, 2026
4927604
fix: read an object a window ends exactly with, and blame no endobj o…
claude Oct 23, 2026
dff5738
fix: read no /Prev of a hybrid file's stream, which no reader follows
claude Oct 23, 2026
11c4643
fix: ask a newer section's cut of a deferred length when the data hol…
claude Oct 23, 2026
c58bcc2
fix: check no deferred length against data a decoding guard cut
claude Oct 23, 2026
0235257
docs: say a reference's chain loads a 32nd object, whose value it drops
claude Oct 23, 2026
120779c
fix: read an object the chain reads exactly within MaxObjectLength whole
claude Oct 23, 2026
d6663f3
fix: search a stream a guard hid the length of past a header its data…
claude Oct 23, 2026
9e98575
fix: take a deferred length's data again to what a guard's cut left w…
claude Oct 23, 2026
5c50289
fix: say a hidden /XRefStm leaves its revision's stream unchecked, no…
claude Oct 23, 2026
c7c0de7
test: hold how far the chain follows a /Length or /Prev on the paths …
claude Oct 23, 2026
82f9f6e
docs: cite the tests that hold the threat model's stream and chain rows
claude Oct 23, 2026
213b613
fix: leave to the guard data a header stops where a guard hid the /Le…
claude Oct 23, 2026
d13f478
fix: read once what a guard's cut left of an object the chain asks again
claude Oct 23, 2026
95cac5e
fix: leave to the guard the rows data taken again to a cut integer st…
claude Oct 23, 2026
3db561c
fix: drop what decoding met beside a guard that kept deferred data fr…
claude Oct 23, 2026
e96f393
fix: ask the file of every endobj a window ends exactly with
claude Oct 23, 2026
6a86857
fix: blame no endobj on a reference a window's edge cuts after its ge…
claude Oct 23, 2026
898bb45
fix: judge a hybrid stream's own /Prev as written, without following it
claude Oct 23, 2026
0ecf0e4
docs: say what a hidden /XRefStm names and which parsers ask the file…
claude Oct 23, 2026
a674794
fix: read through a whole reference a guard cut the object after, as …
claude Oct 23, 2026
76d9239
fix: leave to the guard only how a deferred length's data ends, not t…
claude Oct 23, 2026
fafefd6
fix: take an R a window's edge reaches for a reference only where the…
claude Oct 23, 2026
3696774
fix: leave to the guard data an endstream it spells ends where the gu…
claude Oct 23, 2026
45f1036
fix: read no /Prev or /XRefStm of a table an /XRefStm names in a stre…
claude Oct 23, 2026
b0aaeba
fix: follow a cross-reference stream's filter values in its trailer r…
claude Oct 23, 2026
b3534fc
test: hold how a /Prev to a real is judged, and a missing endstream n…
claude Oct 23, 2026
63faa18
docs: say where a guard hides a missing endstream, and what the chain…
claude Oct 23, 2026
05ba398
fix: read an object stream member whose reference ends at MaxObjectLe…
claude Oct 23, 2026
ffa8433
fix: leave an endobj an endstream lacks the file's when the next inde…
claude Oct 23, 2026
37ff574
fix: decode data whose end a guard hides to the bytes its first decod…
claude Oct 23, 2026
9c9c137
fix: hide the end of a deferred length's data only where a guard keep…
claude Oct 23, 2026
b2cd31c
fix: reach the guard of an object the chain read through only for a v…
claude Oct 23, 2026
78386ba
fix: judge a cross-reference stream's parameters as decoding read the…
claude Oct 23, 2026
a06681e
fix: judge a cross-reference stream's /W element past the third as wr…
claude Oct 23, 2026
f3810a3
fix: find a cross-reference stream a guard cut where it was moved; ke…
claude Oct 23, 2026
0bfee24
fix: under a hidden length, end a stream at an endstream only where w…
claude Oct 24, 2026
51eac1d
fix: leave the rows a cross-reference stream lacks to the file where …
claude Oct 24, 2026
d9f42c9
docs: say what proves an endstream a stream's own, and what the chain…
claude Oct 24, 2026
cea1c7b
fix: decode data whose end a guard hides as cut data, counting a drop…
claude Oct 24, 2026
bbf30e7
fix: check a deferred length against data that holds every row whatev…
claude Oct 24, 2026
1544644
fix: prove an endstream a stream's own against each reader's index, a…
claude Oct 24, 2026
798f57e
fix: take a place a section may have moved to only where a value's gu…
claude Oct 24, 2026
2b5e0d8
fix: make room in the index by a /Size as written, reading no referen…
claude Oct 24, 2026
34cc6c8
fix: report a section found away from where it is named though a guar…
claude Oct 24, 2026
7b19e78
test: hold an object stream member whose R ends where a guard cuts th…
claude Oct 24, 2026
846df96
fix: judge by Table 8 only the parameters a cross-reference stream's …
claude Oct 24, 2026
3bdd725
test: give the proof of an endstream as why the data a spelled one en…
claude Oct 24, 2026
0733c35
test: hold what the proofs of an endstream read under a hidden length…
claude Oct 24, 2026
2524432
test: pin that the offset a section is named at keeps what it read th…
claude Oct 24, 2026
7e58b70
docs: name the spelled xref an endstream's proof accepts, and a /Size…
claude Oct 24, 2026
467e37a
test: say why a member's stream keyword at the bound is cut though th…
claude Oct 24, 2026
fea0cd6
fix: keep the decoding guard a deferred length's data reached when it…
claude Oct 24, 2026
a5d1e21
fix: check a deferred length on data MaxStreamLength cut that holds e…
claude Oct 24, 2026
9af7b1f
test: hold the ASCII85 dropped group's bound one byte short of the group
claude Oct 24, 2026
d24e6ef
fix: read once where a row that names white space before a header pla…
claude Oct 24, 2026
d6cb581
fix: leave to the guard a stream left unsearched whose length a guard…
claude Oct 24, 2026
3b68541
fix: prove an endstream by the cross-reference stream the chain read …
claude Oct 24, 2026
be4990a
fix: decode as hidden the end of data a proven endstream ends past wh…
claude Oct 24, 2026
2857673
fix: tell a section a guard cut from what only looks like one, where …
claude Oct 24, 2026
d350aec
fix: make room in the index by a newest /Size written as a real with …
claude Oct 24, 2026
283626b
fix: name the object read as a cross-reference stream in its trailer …
claude Oct 24, 2026
49e599d
docs: give the read-through and the links the reader follows where th…
claude Oct 24, 2026
087ca76
fix: decode as read whole data a proven endstream ends past white space
claude Oct 24, 2026
52f1145
fix: count a group a cut parts against what the filters before the la…
claude Oct 24, 2026
462ded1
fix: judge what a value a guard cut cannot change before charging a s…
claude Oct 24, 2026
4e074ef
fix: place a cross-reference stream's header past however much white …
claude Oct 24, 2026
86d38f5
test: hold the round's proofs, hidden ends and kept guard reports
claude Oct 24, 2026
ae25a0a
fix: read the white space an endstream's proof crosses once more at most
claude Oct 24, 2026
9369776
docs: say where a guard's cut leaves the chain going on and a hidden …
claude Oct 24, 2026
2122485
fix: leave the guard what a cut subsection element or a stream's own …
claude Oct 24, 2026
3f3459a
fix: undo as far as it goes a predicted row a hidden end leaves short
claude Oct 24, 2026
82c1f03
fix: read no more rows from data decoded again knowing its end hidden…
claude Oct 24, 2026
63e185b
fix: read on once past an endstream however many places lead to it
claude Oct 24, 2026
178e6db
docs: say what a hidden end and a value's cut leave to the file, and …
claude Oct 24, 2026
9932578
fix: leave to the guard a Flate checksum that hidden white space comp…
claude Oct 24, 2026
85d7c56
fix: find a classic table's xref keyword past however much white spac…
claude Oct 24, 2026
e4de97a
fix: read the rows a predicted row undone completes in data decoded a…
claude Oct 24, 2026
c9cf701
fix: take what follows an endstream no endobj follows from the read-o…
claude Oct 24, 2026
ade55a1
test: hold the classic table's probe to a trailer's window and to the…
claude Oct 24, 2026
9bfc102
test: hold where a subsection one of whose elements a guard cut is wr…
claude Oct 24, 2026
6ad024e
fix: charge the file with a section whose data holds too few rows wha…
claude Oct 24, 2026
17434fe
fix: leave to the guard only the white space and comments a hidden le…
claude Oct 24, 2026
0722f18
docs: say what a hidden end leaves the file and what a section's data…
claude Oct 24, 2026
a8077d8
fix: read a section whose data holds too few rows beside a cut value …
claude Oct 25, 2026
8157bff
fix: cut data a hidden length ends only where white space, or a comme…
claude Oct 25, 2026
3291bf7
fix: find a deferred length's row in the predicted row a spelled ends…
claude Oct 25, 2026
59c68ee
docs: say how a hidden end decodes and that a section lacking rows be…
claude Oct 25, 2026
42be429
fix: end the chain at a section lacking rows whose data may hold rows…
claude Oct 25, 2026
bb197f5
fix: find a deferred length's row in any predicted row a spelled ends…
claude Oct 25, 2026
ee9c26e
test: hold the bound and the empty run of data a hidden length ends
claude Oct 25, 2026
241d701
docs: say rows a section lacking rows may hold beside a cut are the g…
claude Oct 25, 2026
5e31335
test: hold where a deferred length's row is looked for again, and how…
claude Oct 25, 2026
d468352
test: store the Flate data a MaxStreamLength cut is measured against
claude Oct 25, 2026
2055eeb
test: hold the lines the batch's patch left partial, through document…
claude Oct 25, 2026
9521a47
test: say what the probe makes of a token past xref, and hold the sec…
claude Oct 25, 2026
b9df537
docs: record batch 16 in status.md
claude Oct 25, 2026
0089cbc
docs: record that batch 16 lands squashed, and remote corpus run 81
claude Oct 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

94 changes: 72 additions & 22 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,27 +94,71 @@ separate types, separate severity scales, and vocabularies that never share a co
gave is copied before a relocation or a rebuild changes it, so that validation still sees the file's own.
3. **Lazy resolution** — `PdfReference.Resolve()` reads and parses the object on demand. A bounded cache
avoids reparsing hot objects (the page tree, shared resources) without ever retaining the whole document.
4. **Streams** — stream data is neither read nor decoded until the caller asks, and then decodes under the
limits of the document it came from; a stream built in memory decodes under the defaults. A stream copied
from one document to another travels **encoded**, with no decompress/recompress cycle. Its declared
length is checked when it is parsed, against the `endstream` that must follow it: in the window the object
is parsed through, or by asking the file for the few bytes after it when the data runs past the window.
A length nothing confirms gives way to the first `endstream` after the data's start: found in the window,
grown up to the object's limit, when the declared length ends inside it or the `/Length` gives none;
searched in the file when a declared length runs past the window — once per stream, no further than the
nearer of the next object the file's index places, as the file wrote it (as the reader rebuilt it when the
document opened, when the file wrote none), and the first object header the file's bytes hold, or the end
of the file, the declared length kept when none lies before them, and the searches of a document reading
a few times the file at most. Neither bound changes as objects are read: what a search keeps depends on
the file's bytes and its index as written, and in the 401 corpus documents measured each stream — each
copy of an object at its offset — takes the same length whatever was read before it. A crafted file can
still make it depend on the number a stream is first read under, on the rebuild's scan for trailers, or,
once the searches of a document have read four times the file, on which streams were searched first
([#138], M23). A stream the file ends inside runs to the end of the file. Each is a diagnostic.
5. **Guards** — every read sized by the file is bounded. A bound a valid file can exceed — a stream's
decoded length, an object's length, a cross-reference section's length and their number, a trailer's
length — is a `PdfReaderLimits` option, on by default and reported under its own `limit.*` code when
reached; a bound only an invalid file reaches is an internal constant (ADR 34).
4. **Streams** — stream data is neither read nor decoded until the caller asks, nor kept once read
(section 5), and decodes under the limits of the document it came from; a stream built in memory decodes
under the defaults. A stream copied from one document to another travels **encoded**, with no
decompress/recompress cycle. Its declared length is checked when it is parsed, against the `endstream` that
must follow it after white space and comments, however many — in the window the object is parsed through, or
in the file past it, read on as far as they run —, a comment counting only once white space comes before it: a
`%` right where the length ends is the data's, and leaves the length unconfirmed. A length nothing confirms, or
a `/Length` that gives none, goes to one search for the first `endstream` after the data's start ([#174]): in
the bytes the parser holds, then forward in the file — once per stream, no further than the nearer of the next
object the file's index places, as the file wrote it (as the reader rebuilt it when the document opened, when
the file wrote none), and the first object header the file's bytes hold, or the end of the file, and the
searches of a document reading a few times the file at most. A stream's data never counts toward its
object's length: no window grows to find its `endstream`. Neither bound changes as objects are read: what a
search keeps depends on the file's bytes and its index as written, and in the 401 corpus documents measured
each stream — each copy of an object at its offset — takes the same length whatever was read before it. A
crafted file can still make it depend on the number a stream is first read under, on the rebuild's scan for
trailers, or, once the searches of a document have read four times the file, on which streams were searched
first ([#138], M23). A stream whose `/Length` a guard cut or left out of the index may be valid, its length only
hidden: when a header its data spells — an embedded file's does — stops its search, no `endobj` of its own before
it, or an `endstream` it spells ends it, the data up to there is the guard's, cut by it, and nothing is said of the
file. An `endstream` is the stream's own, and its end the file's, only where what follows the object's end — its
`endobj`, or the `endstream` where none follows — is the next object the index places, a cross-reference stream
the chain read, the end of the file, or `xref` or `startxref`, read once for each place ([#224]); white space
before the keyword, which only the hidden length says is the data's or not, leaves the data's end to the guard as it
decodes (`PdfStreamData.EndHidden`). With no
`endstream` before the stop, the object's `endobj` ends the data where it
follows the declared length as an `endstream` would, or where it is the last one, a whole keyword — no regular
character, solidus or percent sign right before it, which would make it part of a token, a name or a comment that
starts there: the data before it, which no lexing reads, says nothing of one further back —, and only
white space and comments run from it to the stop. That last `endobj` is followed forward through the search's
own reads, which read every byte up to the stop already: no byte before the stop is read a second time,
backward, and a comment, which can be told only from the start of its line, is read as one. Without either,
a declared length that ends before the stop is kept, and the data otherwise runs to the stop — to the end of
the file, for a stream the file ends inside. Each is a diagnostic. What the search found is kept for the
stream; whether `endobj` follows the declared length is read again only when a rebuild changes that length.
5. **Guards** — every read sized by the file is bounded. A bound a valid file can exceed — a stream's data
read at once and its decoded length, the filters it passes through, an object's length, a cross-reference
section's length and their number, a trailer's length, the entries of the index — is a `PdfReaderLimits`
option, on by default and reported under its own `limit.*` code when reached; a bound only an invalid file
reaches is an internal constant (ADR 34). What a guard cut is the guard's, never the file's fault: a value
that leads to an object a guard cut or left out of the index — a stream's `/Length`, `/Filter` or
`/DecodeParms`, a cross-reference stream's `/W`, a trailer's `/Prev` or `/XRefStm` the reader follows — is not
judged as one the file gave. The stream's data is found by its `endstream`, an integer the cut left only a place to look for
one at, and a missing `endstream` is still the file's fault but where the search stops at a header the data
spells or an `endstream` nothing after it proves the stream's own (item 4); a reference the cut left whole is read
through, as a load reads it; its chain of filters ends there, with the data
left encoded; and the chain of cross-reference sections ends at that section, with nothing rebuilt and the
older sections and their trailers the guard's to hide, wherever near its named offset the section is found —
unless what the values read say makes it unreadable whatever the cut hides, or data whose length the file
gives, its filters written direct, lacks the rows they declare whatever it hides — the file's fault, such a section
read as read whole, lacking rows, its trailer merged and the chain going on where the data holds no row at the
fewest bytes a row may take: rows it may hold, read with the cut value, are the guard's, the chain ending there. An
object `MaxObjectLength` cut there is loaded once the chain is read, which reaches the guard — thrown at opening
under `ThrowOnLimit` —, for a value the chain keeps: not for a place it dropped as no section. A cross-reference
stream's `/Length` the chain could not read, which leads to such an object, ends the chain so wherever only it
could say how far the data runs: with no `endstream` before the next object or the end of the file, the
section is the guard's, not malformed; where the rows spell one and no `endstream` confirms what the cut left
of the length, the rows past it are the guard's — unless what follows the `endstream` the data was taken to
proves it the stream's own, as in item 4, which leaves the rows the data lacks to the file. Such data, whose end
a guard hides, is decoded again as data a guard cut, a group its end parts dropped and what a filter says of the
end silenced; a decoding guard the first decoding reached stands, and no more rows are held than it read.
Data an `endstream` proven its own ends past white space or comments (item 4) decodes up to where that run
starts — a comment past white space within the data, but in ASCII85 data, where a `%` is a digit —, the first
filter's running out there silenced, and where its output may lack what the run holds, its end the guard's, as cut;
Flate data whose deflate body ends in the data as taken is whole, its checksum alone reaching into the run.

### 3.2 The write path

Expand Down Expand Up @@ -163,7 +207,10 @@ goes wrong. No intermediate layer may drop it.
## 5. Memory and CPU strategy

- **Memory budget**: consumption follows the complexity of the **page** being processed, never the size of
the document. A ten-thousand-page report must generate in the footprint of a ten-page one. One decoded
the document. A ten-thousand-page report must generate in the footprint of a ten-page one. A stream's
encoded data is kept by nothing: it is read each time it is asked for — lent where it lies by a source held
in memory, read into an array of its length from any other —, at most `PdfReaderLimits.MaxStreamLength` of it
at once, so that streams whose data share a stretch of the file hold no copy of it each ([#170]). One decoded
stream is still held whole, up to `PdfReaderLimits.MaxDecodedStreamLength` and at most `Array.MaxLength`,
until M23 decodes a piece at a time ([#48]), in native memory if a measurement asks for it (ADR 35). Of a chain
of filters, the filters before the last share that bound for what they pass along together, so that decoding a
Expand Down Expand Up @@ -240,3 +287,6 @@ publication.
[#34]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/34
[#48]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/48
[#138]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/138
[#170]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/170
[#174]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/174
[#224]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/224
37 changes: 35 additions & 2 deletions docs/milestones/M02.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,33 @@ and none lost is no finding ([#275]); and an object an object stream writes as a
stream, and the definition of it, that the chain's index places: an object a rebuild serves from another, which does not
list it or writes it as a stream, reads as null with no finding yet ([#276]).

Where a stream's data ends is settled once for each stream, by the same rules wherever the parser's window ends: a
declared length that an `endstream` follows, past white space and comments however many, a comment only after white
space, is the stream's; any other, or none, goes to one search for the first `endstream`, up to the nearer of the first
object header and the next object the index as written places, the object's `endobj` standing in for it when none lies
before; and a stream's data never counts toward `MaxObjectLength` ([#174]). A cross-reference stream whose `/Length` the
chain cannot read is searched alike past the window, with no header stopping it; where the row the section's reading
keeps for that `/Length` lies among rows that spell `endstream`, the data is taken again to the length it gives, and
data no `endstream` ends before the next object the sections read so far place makes the section malformed, the file's
fault and no guard's, unless that `/Length` leads to an object a guard cut ([#220]). The next object's header ends every
array and dictionary an object, or a trailer, left open, and the object lacks its `endobj` ([#230]).
A stream's `/Length`, `/Filter` or `/DecodeParms`, or a filter's parameter, that leads to an object a guard cut or left
out of the index is the guard's, never judged as a value the file gave: the length is not judged, the data is found by
its `endstream`, and one missing is still the file's fault, unless a header the data spells, or an `endstream` nothing
after it proves the stream's own — the next object the index places, a cross-reference stream the chain read, the end
of the file, `xref` or `startxref`, after the object's `endobj` or in its place —, stops the search, the data up to it then the guard's; the filters end there,
the rest of them left undone,
`HasImageFilter` seeing no image past it, and an object stream so left is hidden as one a guard cut,
`xref.checked-in-part`'s rather than `xref.object-stream-broken`'s. A cross-reference stream whose `/W`, `/Index`,
`/Filter` or `/DecodeParms`, or `/Size` with no `/Index` — or whose `/Length`, when no `endstream` ends its data —
leads to an object `MaxObjectLength` cuts while the chain is read ends the chain as a section a guard cut, found where
it is named or near there, as a `/Prev` or `/XRefStm` the reader follows that leads to one does, and nothing is rebuilt;
the rows its data lacks past the `endstream` such a `/Length` left it at are the guard's, unless that `endstream` is
proven the stream's own ([#224], [#263]). A stream's data is read each time it is asked for and kept
by nothing — validating object streams whose data share a stretch of the file holds no copy of it for each —, and no
more than `MaxStreamLength` of it is read at once, a guard reported once in the document's diagnostics and with each
decoding into diagnostics a caller passes ([#170]).

## Slices

1. Findings, report, rule engine, profile plumbing, and a single trivial rule end to end. **Done on
Expand Down Expand Up @@ -227,8 +254,8 @@ dictionary listed as a kid is read as a page without `/Parent`, `/MediaBox` or `
`/Contents` naming an object the file lacks (`t02-01-004`, `t02-02-001`, `t02-03-011`) is `object.reference-missing`, a
warning, and `t02-01-004`'s page, which no tree lists, `page-tree.page-orphaned`. Two content-stream cases whose
`stream` keyword is missing, or that have bytes between `endstream` and `endobj` (`t02-05-01-013`, `-017`), earn
`object.endobj-missing` for what follows their value; one without `endstream` (`-014`) leaves where its object ends
unknown, and its stream is the stream rules' to judge.
`object.endobj-missing` for what follows their value; one without `endstream` (`-014`) keeps the 68 bytes its `/Length`
declares, which its object's `endobj` follows ([#174]), and its stream is the stream rules' to judge.

The object-shape rules answered for the rest of the catalog, page tree and page object cases. A root typed `/Pagez`
(`t02-02-009`), a page typed `/Font` (`t02-03-002`) and a catalog of the wrong `/Type` (`t02-01-006`) earn
Expand Down Expand Up @@ -406,12 +433,18 @@ By Diátaxis section, since [ADR 47](../adr/0047-the-user-documentation-follows-
[#154]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/154
[#160]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/160
[#161]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/161
[#170]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/170
[#174]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/174
[#175]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/175
[#181]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/181
[#183]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/183
[#200]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/200
[#202]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/202
[#220]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/220
[#224]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/224
[#230]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/230
[#237]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/237
[#263]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/263
[#274]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/274
[#275]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/275
[#276]: https://github.com/AdCodicem/AdCodicem.Pdf/issues/276
Loading
Loading