Repository navigation
TextString: what the document says in a human language - #34
Merged
Merged
Conversation
`pdfops info` printed a document's creator as creator \xfe\xffL\x00a\x00T\x00e\x00X\x00 \x00v\x00i\x00a... and had done for as long as the verb existed. ToString hands back the BYTES, and the bytes of a text string are not text: a title, an author, a bookmark's label and a form field's value are PDFDocEncoding, or UTF-16BE behind FE FF, or -- since PDF 2.0 -- UTF-8 behind EF BB BF. Only those two marks, and no guessing beyond them. A string that merely looks like UTF-16LE is PDFDocEncoding that happens to contain a zero byte, and decoding it as UTF-16 turns a readable title into mojibake: the opposite failure, and just as silent. PDFDocEncoding is NOT Latin 1, which is the other half of the defect. The spacing accents sit at 0x18..0x1F where Latin 1 has control characters, the typographic marks at 0x80..0x9E where Latin 1 has nothing, the Euro at 0xA0 where Latin 1 has a non-breaking space, and 0x7F, 0x9F and 0xAD are undefined -- said to mean nothing rather than quietly becoming a soft hyphen. The table was checked against Annex D.2 entry by entry rather than remembered. 100% of statements, no uncovered blocks, 12 mutations caught. One of them needed the test to assert the WHOLE string: accepting FF FE as a mark and then decoding big-endian anyway gives mojibake too, so "it does not say La" could not tell the two apart. 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.
pdfops infoprinted a document's creator asand had done for as long as the verb existed.
ToStringhands back thebytes, and the bytes of a text string are not text: a title, an author, a
bookmark's label and a form field's value are PDFDocEncoding, or UTF-16BE
behind
FE FF, or — since PDF 2.0 — UTF-8 behindEF BB BF.⛔ Only those two marks, and no guessing beyond them
A string that merely looks like UTF-16LE is PDFDocEncoding that happens to
contain a zero byte, and decoding it as UTF-16 turns a readable title into
mojibake. That is the opposite failure to the one above, and just as silent.
⛔ PDFDocEncoding is not Latin 1
Which is the other half of the defect, and the half that a decoder written from
memory gets wrong:
0x18–0x1F˘ˇˆ˙˝˛˚˜, where Latin 1 has control characters0x80–0x9E0xA00x7F,0x9F,0xADThe table was checked against Annex D.2 of ISO 32000-1 entry by entry rather
than remembered.
How it is checked
100% of statements, no uncovered blocks, 12 mutations caught. One of them
needed the test to assert the whole string: accepting
FF FEas a mark andthen decoding big-endian anyway gives mojibake too, so "it does not say
La"could not tell the two apart.
Surrogate pairs, an odd trailing byte (half a code unit is not a character, and
a truncated string should look truncated), a bare BOM, and invalid UTF-8 behind
a UTF-8 mark all have tests of their own.
🤖 Generated with Claude Code