Repository navigation
An Operation says which bytes of the stream it is - #33
Merged
Merged
Conversation
Operation gains Start and End: the byte range of the operation in the stream it was scanned from, Start at its first operand (or at the operator when it has none) and End just past the operator. ⛔ THEY ARE HERE SO THAT A CONTENT STREAM CAN BE EDITED IN PLACE. A tool that wants to put something before every BT has two honest ways to find one: re-serialise the whole stream, which risks changing what an inline image's bytes mean, or know where the operator was — and this scanner is the only thing that does know. "BT" appears inside strings, inside names and inside an inline image's data, and a byte search cannot tell those from an operator. The test pins the discriminator: in `(BT in a string) Tj BT /F1 12 Tf ET` a byte search finds index 1, inside somebody's text, and the scan reports index 20. End is the LEXER's position rather than the operator's start plus its length, because an inline image's operator token is "BI" and its operation runs to the EI three keywords later — measuring from the operator would put the end in the middle of the image's data, where a splice corrupts the image instead of the stream around it. Start is the first OPERAND's position, so that splicing before an operation does not land between its operands and its operator. The ranges of a stream are asserted ordered and disjoint, which is what lets a caller splice at several of them in one pass, and a stream with rubbish in it keeps honest ranges around what the scan stepped over. 100% statement coverage, go vet and gofmt clean. Two mutations caught: the range reduced to the operator alone, and the first-operand mark overwritten by each later operand. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
OperationgainsStartandEnd: the byte range of the operation in thestream it was scanned from —
Startat its first operand (or at the operatorwhen it has none),
Endjust past the operator.⛔ They are here so a content stream can be edited in place
A tool that wants to put something before every
BThas two honest ways tofind one:
image's bytes mean;
does.
BTappears inside strings, inside names, and inside an inline image's data,and a byte search cannot tell those from an operator. The test pins the
discriminator:
A tool splicing at index 1 corrupts the string.
Two details that are easy to get wrong
Endis the lexer's position, not the operator's start plus its length.An inline image's operator token is
BIand its operation runs to theEIthree keywords later, so measuring from the operator would put the end in
the middle of the image's data — where a splice corrupts the image instead
of the stream around it. Asserted;
Startis the first operand's position, so splicing before an operationdoes not land between its operands and its operator.
1 0 0 RGstarts atthe
1, not at theRG.The ranges of a stream are asserted ordered and disjoint, which is what
lets a caller splice at several of them in one pass, and a stream with rubbish
in it keeps honest ranges around what the scan stepped over.
Why in
readerrather than in the callerThree packages already scan content streams through this one scanner —
extract,renderandlatex— so the primitive is shared already; what wasmissing was the one fact only the scan has. The first consumer is
go-pdfkit/ops, for a verb that recolours text without touching anything else.Checks
100 % statement coverage,
go vetandgofmtclean. Two mutations caught: therange reduced to the operator alone, and the first-operand mark overwritten by
each later operand.
🤖 Generated with Claude Code