Documentation
¶
Overview ¶
Package pdf0 is a PDF 2.0 parser, serializer, and PDF/A validator. Its only dependencies are the author's own pure-Go modules (formalis for EN 16931 invoice rules, golittlecms for ICC profiles, gopenjpeg for JPEG 2000).
The core is four entry points:
- Read parses PDF bytes into a typed object model (see Document), recovering from common malformations rather than crashing on hostile input.
- Document.Write serializes the object model back to conformant PDF bytes.
- ValidatePDFA and ValidatePDFABytes check a document against PDF/A conformance levels: PDF/A-1a, -1b, -2a, -2b, -3a, -3b, and -4. The Level A levels are Level B plus the accessibility requirements.
- NewPDFADocument (and NewPDFADocumentWithInfo) build a minimal PDF/A document.
Built on those: encryption (ReadWithPassword, Document.SetEncryption, Document.RemoveEncryption), digital signatures (Document.WriteSigned, Document.VerifySignatures, Document.ValidatePAdES), extraction (Document.ExtractText, Document.ExtractImages, Document.Images), page operations (Document.ExtractPages, Document.AppendPages), conformance repair (Document.Repair), incremental writing (Document.WriteIncremental), and nine conformance validators besides PDF/A.
Reading and writing ¶
doc, err := pdf0.Read(bytes.NewReader(data), int64(len(data)))
if err != nil { /* malformed beyond recovery */ }
var out bytes.Buffer
err = doc.Write(&out)
Resource limits ¶
pdf0 parses untrusted input, so every unbounded loop and every allocation sized by a number the file supplies is capped. The defaults are safe for hostile input and no real file measured across the veraPDF corpus or a 978-file Common Crawl sample comes within 2x of any of them, so a caller who configures nothing needs to do nothing.
Eleven of those caps are settable per document, as variadic Option values on Read, ReadWithPassword, their Context variants and ParseXRefStream (see WithMaxDecodedStreamBytes and the other With* functions). They resolve once and are stored on the Document, so validation and extraction inherit whatever Read was given, and two documents read with different limits never interfere:
doc, err := pdf0.Read(r, size, pdf0.WithMaxDecodedStreamBytes(8<<20), pdf0.WithMaxDecodedContentBytes(64<<20), )
When a cap does stop a check, the validators say so rather than guess: the trip is reported as a finding under the rule identifier "limit", which IsCheckerFinding separates from a real non-conformance. A caller asking "is this file conformant?" should read such a finding as "unknown", never as a failure.
Cancellation ¶
The work a document can cost is set by the document, not by the caller: a 71 MB, 1256-page file takes about ten seconds to validate. The long-running entry points therefore have Context variants — ReadContext, ReadWithPasswordContext, Document.WriteContext, ValidatePDFAContext, ValidatePDFABytesContext, ValidatePDFUAContext, ValidatePDFUA2Context, ValidatePDFXContext, ValidatePDFVTContext, ValidatePDFVT2Context, ValidatePDFRContext, ValidateDPartsContext, ValidateFacturXContext, ValidateOrderXContext, Document.ExtractTextContext and Document.ExtractImagesContext:
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
defer cancel()
for _, e := range pdf0.ValidatePDFAContext(ctx, doc, pdf0.PDFA4) { ... }
A context is a first parameter rather than a With* Option deliberately. An Option is stored on the Document and inherited by every later call, which is the wrong lifetime for a context and would make cancellation invisible at the call site; limits describe what a document may cost, contexts describe how long an operation may take. Every original signature is unchanged, and an entry point whose cost is bounded rather than document-scale — ExtractPageText (one page), Images (an iterator the caller can break out of), Document.VerifySignatures — deliberately has no variant. ValidateFacturX and ValidateOrderX had none until formalis v0.2.0, for reasons that have both lapsed: their findings were formalis.Violation values, which IsCheckerFinding could not classify, and the invoice half of the work was a rule engine that took no context. The findings are now this package's own types and the engine takes a context, so both halves of a Factur-X validation are cancellable and a cancelled run reports the reserved "limit" rule like every other. See docs/architecture.md#cancellation for the full table.
A cancelled validation returns the findings it had gathered plus one under the rule "limit", the same channel a tripped resource cap uses, so a cancelled run can never be mistaken for a clean bill of health. Read, Write and the extractors have no finding channel, so they return an error wrapping ctx.Err() instead. Cancellation is checked at coarse boundaries — per check, per page, per content stream, per megabyte scanned or decompressed — which on that 71 MB file takes effect within about 60 ms.
Encrypted files using the standard security handler are decrypted on Read when the (empty or supplied) user or owner password is correct: RC4 and AES-128 at revisions 2-4, and AES-256 at revision 6. Revision 5 is a deprecated draft and is rejected. Document.Encrypted reports the presence of an /Encrypt dictionary; a decrypted document retains its file key and re-encrypts on Write, so the object model round-trips — though the bytes do not, because AES draws a fresh random initialisation vector per object on every write. Document.RemoveEncryption drops the encryption so Write emits plaintext. A document whose scheme or password could not be handled stays encrypted (Document.Locked reports this) and is written back unchanged as a lossless passthrough. Write regenerates the on-disk layout, emitting a cross-reference stream when the source used one and a traditional cross-reference table otherwise.
Validating ¶
for _, e := range pdf0.ValidatePDFA(doc, pdf0.PDFA4) {
fmt.Println(e) // e.g. [PDF/A-4 6.2.10] object 12: font ... must be embedded
}
An empty result means no implemented check fired, not a guarantee of full conformance: the validator covers a subset of ISO 19005. Validation does not mutate its Document and is safe to run concurrently on the same Document. Use ValidatePDFABytes when you have the raw file bytes and want the byte-level file-structure checks (e.g. no data after %%EOF) as well.
The other PDF standards follow the same shape: each validator is a free function taking the *Document as its first parameter (ValidatePDFUA, ValidatePDFUA2, ValidatePDFX, ValidatePDFVT, ValidatePDFVT2, ValidatePDFR, ValidateDParts), and every finding type satisfies the Violation interface, so findings from different validators can be collected together. ValidateFacturX and ValidateOrderX differ only in shape: they return a result struct, because they also carry the extracted invoice XML, the conformance level and what the invoice rule engine did not evaluate, but the findings inside it are FacturXViolation and OrderXViolation values and satisfy Violation like the rest. See the Violation documentation.
Every validator returns its findings in a deterministic order (by rule, then object, then message) and runs its checks under a recover boundary: a check that panics on hostile input is reported as a finding whose rule is "internal" rather than crashing the caller. A stack overflow from unbounded recursion is fatal and is not recoverable; those are prevented at the source.
Signatures ¶
Document.VerifySignatures reports one SignatureResult per signature. Read the verdict with SignatureResult.DocumentUnmodified, which is Valid AND CoversWholeDocument: Valid alone accepts a document whose content was changed by a post-signing incremental update. VerifySignatures performs no trust-chain check at all — use Document.VerifySignaturesWithRoots to populate TrustedChain.
See docs/architecture.md for how bytes flow through Read and Write, docs/validators.md for the validator family, and docs/signing.md for signing and verification.
Index ¶
- func DefaultSRGBProfile() []byte
- func DocumentEqual(a, b *Document) bool
- func EmbedFacturX(doc *Document, invoiceXML []byte, profile formalis.Profile, title string) error
- func Equal(a, b Object) bool
- func GenerateXMPMetadata(level PDFALevel, title, author string) []byte
- func IsCheckerFinding(v Violation) bool
- type Array
- type Boolean
- type DPartViolation
- type Dictionary
- type Document
- func NewPDFADocument(level PDFALevel) *Document
- func NewPDFADocumentWithInfo(level PDFALevel, title, author string) *Document
- func Read(r io.ReaderAt, size int64, opts ...Option) (*Document, error)
- func ReadContext(ctx context.Context, r io.ReaderAt, size int64, opts ...Option) (*Document, error)
- func ReadWithPassword(r io.ReaderAt, size int64, password string, opts ...Option) (*Document, error)
- func ReadWithPasswordContext(ctx context.Context, r io.ReaderAt, size int64, password string, ...) (*Document, error)
- func (d *Document) AppendPages(other *Document)
- func (d *Document) DSSCerts() []*x509.Certificate
- func (d *Document) DSSRevocationMaterial() (crls, ocsps [][]byte)
- func (d *Document) ExtractImages() []ExtractedImage
- func (d *Document) ExtractImagesContext(ctx context.Context) ([]ExtractedImage, error)
- func (d *Document) ExtractPageText(page *Dictionary) string
- func (d *Document) ExtractPages(indices []int) (*Document, error)
- func (d *Document) ExtractText() string
- func (d *Document) ExtractTextContext(ctx context.Context) (string, error)
- func (d *Document) Images() iter.Seq[ExtractedImage]
- func (d *Document) Locked() bool
- func (d *Document) PageCount() int
- func (d *Document) PageList() []*Dictionary
- func (d *Document) RemoveEncryption()
- func (d *Document) Repair(level PDFALevel) []RepairAction
- func (d *Document) Resolve(obj Object) Object
- func (d *Document) ResolveDict(obj Object) *Dictionary
- func (d *Document) SetEncryption(userPassword, ownerPassword string) error
- func (d *Document) ValidatePAdES(raw []byte) []PAdESResult
- func (d *Document) VerifySignatures(raw []byte) []SignatureResult
- func (d *Document) VerifySignaturesWithRoots(raw []byte, roots *x509.CertPool) []SignatureResult
- func (d *Document) Write(w io.Writer) error
- func (d *Document) WriteArchivalTimestamp(w io.Writer, original []byte, certs []*x509.Certificate, ...) error
- func (d *Document) WriteContext(ctx context.Context, w io.Writer) error
- func (d *Document) WriteIncremental(w io.Writer, original []byte, changed []int) error
- func (d *Document) WriteSigned(w io.Writer, cert *x509.Certificate, key crypto.Signer) error
- func (d *Document) WriteSignedIncremental(w io.Writer, original []byte, cert *x509.Certificate, key crypto.Signer) error
- func (d *Document) WriteSignedTimestamped(w io.Writer, cert *x509.Certificate, key crypto.Signer, ...) error
- type ExtractedImage
- type FacturXResult
- type FacturXViolation
- type IndirectObject
- type IndirectRef
- type Integer
- type Lexer
- type Name
- type Null
- type Object
- type Option
- func WithMaxCIDRangeSpan(n int) Option
- func WithMaxCmapWork(n int) Option
- func WithMaxContentStreamBytes(n int) Option
- func WithMaxDecodedContentBytes(n int64) Option
- func WithMaxDecodedStreamBytes(n int) Option
- func WithMaxICCProfileBytes(n int) Option
- func WithMaxObjectStreamBytes(n int64) Option
- func WithMaxPostScriptSteps(n int) Option
- func WithMaxRoleMapSteps(n int) Option
- func WithMaxTableGridFills(n int64) Option
- func WithMaxXMPPacketBytes(n int) Option
- type OrderXProfile
- type OrderXResult
- type OrderXViolation
- type PAdESLevel
- type PAdESResult
- type PDFALevel
- type PDFRViolation
- type PDFVTViolation
- type PDFXLevel
- type PDFXViolation
- type Parser
- type Real
- type RepairAction
- type RevocationInfo
- type RevocationStatus
- type Serializer
- type SignatureResult
- type Stream
- type String
- type Token
- type TokenType
- type UAViolation
- type ValidationError
- func ValidatePDFA(doc *Document, level PDFALevel) []ValidationError
- func ValidatePDFABytes(doc *Document, level PDFALevel, rawData []byte) []ValidationError
- func ValidatePDFABytesContext(ctx context.Context, doc *Document, level PDFALevel, rawData []byte) []ValidationError
- func ValidatePDFAContext(ctx context.Context, doc *Document, level PDFALevel) []ValidationError
- type Violation
- type XRefEntry
- type XRefTable
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DefaultSRGBProfile ¶
func DefaultSRGBProfile() []byte
DefaultSRGBProfile returns a real sRGB ICC profile (ICC v2.1, valid at every PDF/A level) generated by golittlecms, a pure-Go Little CMS port. It is exported for callers that assemble their own OutputIntent; NewPDFADocument uses sRGBProfile to select a level-appropriate profile version.
func DocumentEqual ¶
DocumentEqual compares two Documents for semantic equality.
func EmbedFacturX ¶
EmbedFacturX embeds the CII invoice XML into doc as the associated file factur-x.xml and writes the Factur-X metadata for the given profile. doc must be a valid PDF/A-3 document (for example from NewPDFADocument(PDFA3b)); the result is a Factur-X container that ValidateFacturX accepts after a round trip. title, when non-empty, is recorded as the document title in the XMP.
func Equal ¶
Equal reports whether two PDF objects are semantically equal. It compares values deeply. IndirectRef values are compared by their object/generation numbers only; Equal does not resolve references (it has no document to resolve against), so an IndirectRef is never equal to the object it points to.
func GenerateXMPMetadata ¶
GenerateXMPMetadata creates XMP metadata bytes for the given PDF/A level.
func IsCheckerFinding ¶
IsCheckerFinding reports whether a finding describes a problem in the checker rather than a non-conformance of the document. Two rule identifiers are reserved for this: "internal" (a check panicked and was recovered) and "limit" (a resource guard tripped, so a check could not be completed). A caller that wants "is this file conformant?" should treat a checker finding as "unknown", not as a failure:
var real []pdf0.Violation
for _, e := range pdf0.ValidatePDFA(doc, pdf0.PDFA2b) {
if !pdf0.IsCheckerFinding(e) {
real = append(real, e)
}
}
Neither kind fires on any file in the veraPDF corpus; both mean the input is adversarial or the checker has a bug.
Types ¶
type DPartViolation ¶
type DPartViolation struct {
Rule string // ISO 32000-2 subclause, e.g. "14.12.2"
Message string
Object int // object number the violation is anchored to, 0 if N/A
}
DPartViolation reports a way in which a document's DPart hierarchy departs from ISO 32000-2 clause 14.12.
func ValidateDParts ¶
func ValidateDParts(doc *Document) []DPartViolation
ValidateDParts checks a document's DPart hierarchy against ISO 32000-2 clause 14.12. A document without a /DPartRoot in its catalog has no hierarchy and is reported as valid (nil), since the structure is optional. The checks cover: the DPartRoot and DPartRootNode wiring (Table 408), each node's /Type, required /Parent up-link and its target (14.12.2), the exclusive /DParts vs /Start+/End roles (Table 409), the leaf page ranges partitioning every page exactly once in page-tree order (14.12.2/14.12.3), page /DPart back-references (14.12.3), /NodeNameList depth (Table 408), and DPM key/value constraints (14.12.4.2).
func ValidateDPartsContext ¶
func ValidateDPartsContext(ctx context.Context, doc *Document) []DPartViolation
ValidateDPartsContext is ValidateDParts with cancellation; a cancelled run reports itself under the rule "limit" (see cancel.go).
func (DPartViolation) Error ¶
func (v DPartViolation) Error() string
func (DPartViolation) ObjectNum ¶
func (v DPartViolation) ObjectNum() int
ObjectNum returns the anchoring object number, 0 if N/A.
func (DPartViolation) RuleID ¶
func (v DPartViolation) RuleID() string
RuleID returns the ISO 32000-2 DPart subclause.
type Dictionary ¶
Dictionary represents a PDF dictionary object. Uses parallel slices to preserve key insertion order for round-tripping.
func (*Dictionary) Clone ¶
func (d *Dictionary) Clone() *Dictionary
Clone returns a copy of the dictionary whose Keys and Values live in fresh backing arrays, so that Set/Delete on the copy do not mutate the original. Value objects are shared, not deep-copied.
func (*Dictionary) Delete ¶
func (d *Dictionary) Delete(key Name) bool
Delete removes the key-value pair for the given key. Returns true if the key was found and removed.
func (*Dictionary) Get ¶
func (d *Dictionary) Get(key Name) Object
Get returns the value associated with the given key, or nil if not found.
func (*Dictionary) Set ¶
func (d *Dictionary) Set(key Name, value Object)
Set sets the value for the given key. If the key already exists, it updates the value in place (its slot is unchanged, so the lookup index stays valid). Otherwise it appends a new key-value pair and drops the index, which the next lookup rebuilds lazily.
Set deliberately scans linearly rather than consulting the index: building the index here would make append-heavy construction O(n^2) (each Set would rebuild an O(n) map). The index accelerates the read-heavy Get path, which is where the super-linear validator traversals live; the parser, the one producer of very large dictionaries, populates Keys/Values directly and never routes through Set.
type Document ¶
type Document struct {
Version string // e.g., "2.0"
Objects map[int]*IndirectObject // object number → object
Trailer Dictionary
// Encrypted reports whether the file carried an /Encrypt dictionary.
// Standard-security-handler files with the empty user password are decrypted
// on Read (RC4, AES-128, and AES-256); their strings and streams are then in
// the clear but this flag stays set. Schemes decryption does not handle
// (non-empty passwords) keep their contents encrypted. Write re-encrypts a
// decrypted document (reproducing the original /Encrypt) but refuses one whose
// content is still encrypted.
Encrypted bool
// Offsets records the absolute byte offset of each uncompressed indirect
// object, for the byte-level file-structure checks. Objects materialised
// from object streams are absent.
Offsets map[int]int64
// contains filtered or unexported fields
}
Document represents a parsed PDF file.
func NewPDFADocument ¶
NewPDFADocument creates a minimal valid PDF/A document for the given level. The document has an empty page tree and passes ValidatePDFA.
func NewPDFADocumentWithInfo ¶
NewPDFADocumentWithInfo is NewPDFADocument with the document title and author embedded in the generated XMP metadata.
func Read ¶
Read parses a PDF document from the given data.
A malformed or adversarial file always yields an error, never a panic: any panic escaping the parse is recovered and returned as an error.
Encrypted files (standard security handler) are decrypted with the empty password; use ReadWithPassword to supply a user or owner password. A file that cannot be decrypted is still parsed structurally, with its strings and streams left encrypted (see Document.Encrypted). Resource limits default to values safe for untrusted input; pass With* options to change them. The resolved limits are stored on the returned Document, so every validator and extractor that runs on it inherits the same configuration.
func ReadContext ¶
ReadContext is Read with cancellation. Parsing is not usually the expensive half — a 71 MB file parses in about 100 ms — but its cost is set by the file: a small file can carry half a gigabyte of object streams to decompress, and a cross-reference section too broken to use is rebuilt by scanning the whole file. Those are the cases a caller with a deadline needs to be able to stop.
A cancelled read returns a nil Document and an error wrapping ctx.Err(), so errors.Is(err, context.Canceled) and errors.Is(err, context.DeadlineExceeded) both work. It never returns a partial Document: a document missing an arbitrary subset of its objects is indistinguishable from one whose file genuinely lacks them, and every validator would then report the absence as a conformance failure. See cancel.go.
func ReadWithPassword ¶
func ReadWithPassword(r io.ReaderAt, size int64, password string, opts ...Option) (*Document, error)
ReadWithPassword is Read with a user or owner password for an encrypted file.
func ReadWithPasswordContext ¶
func ReadWithPasswordContext(ctx context.Context, r io.ReaderAt, size int64, password string, opts ...Option) (*Document, error)
ReadWithPasswordContext is ReadWithPassword with cancellation; see ReadContext.
func (*Document) AppendPages ¶
AppendPages copies every page of other onto the end of this document.
func (*Document) DSSCerts ¶
func (d *Document) DSSCerts() []*x509.Certificate
DSSCerts returns the certificates stored in the document's DSS /Certs (the chain material a long-term signature carries).
func (*Document) DSSRevocationMaterial ¶
DSSRevocationMaterial returns the CRLs and OCSP responses (DER) stored in the document's DSS (Document Security Store), decoded through their stream filters.
func (*Document) ExtractImages ¶
func (d *Document) ExtractImages() []ExtractedImage
ExtractImages returns every image XObject drawn from the document's pages, each decoded when the codec is one this package handles. Form XObjects are followed into their own resources, so images nested inside forms are found too.
Every decoded image is held in the returned slice at once; on a large scan document that is unbounded memory. Use Images to iterate lazily with at most one decoded image live at a time.
func (*Document) ExtractImagesContext ¶
func (d *Document) ExtractImagesContext(ctx context.Context) ([]ExtractedImage, error)
ExtractImagesContext is ExtractImages with cancellation.
It returns the images extracted before the cancellation and an error wrapping ctx.Err(), for the reason ExtractTextContext does: extraction has no finding channel, so a short slice returned bare would be indistinguishable from a document with fewer images. The error is nil exactly when every image was reached.
Cancellation is checked between images, so it takes effect after at most one image decode. A single very large image is therefore not interruptible; that residual is bounded by the codec budgets rather than by the context. See cancel.go.
There is deliberately no context variant of Images: an iterator is already cancellable by breaking out of the range loop, and because each image is decoded only as it is yielded, breaking after image N skips exactly the work a context checked between images would have skipped.
func (*Document) ExtractPageText ¶
func (d *Document) ExtractPageText(page *Dictionary) string
ExtractPageText returns the visible text of a single page dictionary. It resolves the page's /Resources through the page-tree inheritance chain and recurses into invoked form XObjects, so text drawn via inherited fonts or inside a form is not dropped.
There is deliberately no ExtractPageTextContext: one page is the unit of work, and a caller extracting several pages already has a loop of its own to check a context in. Adding a variant here would move that check inside a call that does one page's work either way.
func (*Document) ExtractPages ¶
ExtractPages returns a new document containing only the given pages (0-based, in the order given). The source is not modified.
func (*Document) ExtractText ¶
ExtractText returns the visible text of every page in reading order, pages separated by a form feed. Text is decoded through each font's ToUnicode CMap; glyphs without a ToUnicode mapping are dropped. Layout is approximate: line breaks follow the text-positioning operators and wide inter-glyph gaps become spaces.
func (*Document) ExtractTextContext ¶
ExtractTextContext is ExtractText with cancellation.
It returns the text extracted before the cancellation *and* an error wrapping ctx.Err(). Both, because either alone would be a lie: discarding the text throws away work the caller paid for, and returning it bare would present a truncated document as a whole one. Extraction has no finding channel — the mechanism the validators use to say "this result is incomplete" (see cancel.go and docs/limits.md) — so the error is the only place that fact can live, and a caller who ignores it gets a silently short document.
The error is nil exactly when the extraction ran to completion.
func (*Document) Images ¶
func (d *Document) Images() iter.Seq[ExtractedImage]
Images returns an iterator over the image XObjects drawn from the document's pages, in the same order ExtractImages reports them. Each image is decoded only as it is yielded, so — unlike ExtractImages, which materializes every decoded image at once — iteration keeps at most one decoded image live at a time (unless the caller retains them), and breaking out of the loop skips the remaining decode work entirely.
func (*Document) Locked ¶
Locked reports whether the document carried encryption that could not be removed: it has an /Encrypt dictionary but no usable security handler, because the supplied password was wrong or the scheme is unsupported. Its strings and streams are still ciphertext.
Encrypted alone does not distinguish this from a successfully decrypted file (both keep Encrypted true). Callers that intend to read content, validate, extract, or re-encrypt should check Locked first: on a locked document RemoveEncryption is a no-op, ExtractText and the validators see ciphertext, and SetEncryption/Write refuse.
func (*Document) PageList ¶
func (d *Document) PageList() []*Dictionary
PageList returns the document's page dictionaries in reading order.
func (*Document) RemoveEncryption ¶
func (d *Document) RemoveEncryption()
RemoveEncryption drops encryption from a document that was decrypted on Read, so a subsequent Write emits it in the clear. It clears the security handler and removes /Encrypt from the trailer (and the object graph). It has no effect on a document whose content could not be decrypted (see Locked).
func (*Document) Repair ¶
func (d *Document) Repair(level PDFALevel) []RepairAction
Repair applies a set of safe, well-defined fixes that remove common PDF/A conformance failures, and reports what it changed. It mutates the document in place; a subsequent Write emits the repaired file. Repair never touches page content or fonts — it only removes forbidden document-level constructs — so it cannot make a conformant document non-conformant.
It is not a substitute for validation: run ValidatePDFA afterwards to see what remains (missing embedded fonts, device colour without an output intent, and the like need information Repair does not have).
func (*Document) Resolve ¶
Resolve follows an IndirectRef to its value, iterating through chains of references (a legal indirect object whose value is itself a reference). Returns the object unchanged if it is not an IndirectRef, and nil if any target in the chain does not exist or the chain cycles.
func (*Document) ResolveDict ¶
func (d *Document) ResolveDict(obj Object) *Dictionary
ResolveDict resolves obj and type-asserts to *Dictionary.
func (*Document) SetEncryption ¶
SetEncryption configures the document to be encrypted on the next Write using the standard security handler with AES-256 (V5/R6, ISO 32000-2 §7.6.4). The user password opens the file for reading; the owner password additionally carries full permissions. Either may be empty.
It installs a fresh /Encrypt dictionary and a random file key, replacing any existing encryption. Write then enciphers every string and stream; the in-memory document stays in the clear, so it remains usable afterwards.
func (*Document) ValidatePAdES ¶
func (d *Document) ValidatePAdES(raw []byte) []PAdESResult
ValidatePAdES assesses every signature in the document for PAdES conformance against the original file bytes. Results are ordered by the object number of the signature dictionary, the same deterministic order VerifySignatures uses.
func (*Document) VerifySignatures ¶
func (d *Document) VerifySignatures(raw []byte) []SignatureResult
VerifySignatures verifies every signature in the document against the original file bytes. For each it recomputes the digest over the signed /ByteRange, checks it against the signature's messageDigest attribute, and verifies the signature over the signed attributes with the embedded certificate. It does not build a trust chain (no root store): a Valid result means the bytes inside the signed /ByteRange are intact and were signed by the holder of the embedded certificate's private key. It does NOT by itself mean the document was not modified after signing — an incremental update can change the rendered content while leaving the signed range intact. Combine Valid with CoversWholeDocument (see SignatureResult.DocumentUnmodified).
func (*Document) VerifySignaturesWithRoots ¶
func (d *Document) VerifySignaturesWithRoots(raw []byte, roots *x509.CertPool) []SignatureResult
VerifySignaturesWithRoots verifies every signature as VerifySignatures does and, when roots is non-nil, additionally builds the signer's certificate chain to one of those trust anchors (using the certificates embedded in the CMS as intermediates), validating at the current time. The chain outcome is reported in TrustedChain / ChainErr and does not affect Valid, which remains a statement about the cryptographic integrity of the signed content.
Results are ordered by the object number of the signature dictionary, which is stable across runs (the objects are held in a map, whose iteration order is not) and meaningful: in a document signed by successive incremental updates the later signature is the later object.
func (*Document) Write ¶
Write serializes the document to the writer in PDF format.
A document decrypted on Read is re-encrypted with its retained key so it round-trips. A document that could not be decrypted (Document.Locked) is written back verbatim as a lossless passthrough under its preserved /Encrypt. Write regenerates the cross-reference section, emitting a cross-reference stream when the source used one and a traditional table otherwise.
func (*Document) WriteArchivalTimestamp ¶
func (d *Document) WriteArchivalTimestamp(w io.Writer, original []byte, certs []*x509.Certificate, tsaCert *x509.Certificate, tsaKey crypto.Signer) error
WriteArchivalTimestamp adds a DSS (holding certs as validation material) and a document time-stamp over the whole file, as an incremental update. original must be the bytes the document was read from. The document should already carry a B-T signature for the result to reach B-LTA.
func (*Document) WriteContext ¶
WriteContext is Write with cancellation.
Writing is usually fast, but its cost is the document's, not the caller's: a malformed cross-reference table can make one large stream reachable from thousands of object numbers, and the resulting output is legitimately enormous. cmd/corpusprobe streams exactly that case to io.Discard.
A cancelled write returns an error wrapping ctx.Err(). Whatever had already been written stays written — an io.Writer cannot be rewound — so the output is a truncated file, and the returned error is the only thing that says so. A caller that must not leave a partial file behind should write to a temporary and rename on success. See cancel.go.
func (*Document) WriteIncremental ¶
WriteIncremental writes an incremental update: the original file bytes verbatim followed by only the objects listed in changed, a new cross-reference section whose /Prev chains back to the original, and a new trailer. The original bytes are preserved exactly, so any signature over them stays valid and the update can be undone by truncation.
changed lists the object numbers whose current value in d.Objects should be (re)written; numbers absent from d.Objects are recorded as free (deleted). Encrypted documents are not supported.
func (*Document) WriteSigned ¶
WriteSigned writes the document with an appended digital signature over its whole content: it adds a signature field, serializes with placeholders, computes the /ByteRange, signs the covered bytes with key (certificate cert embedded, adbe.pkcs7.detached, SHA-256), and fills /Contents. The in-memory document is not modified.
The document must not be encrypted (sign a plaintext document, or encrypt a signed one afterwards).
func (*Document) WriteSignedIncremental ¶
func (d *Document) WriteSignedIncremental(w io.Writer, original []byte, cert *x509.Certificate, key crypto.Signer) error
WriteSignedIncremental signs the document as an incremental update: the original bytes are preserved verbatim and only the signature objects are appended. This is the correct way to add a signature without invalidating any signature already present. original must be the bytes the document was read from.
func (*Document) WriteSignedTimestamped ¶
func (d *Document) WriteSignedTimestamped(w io.Writer, cert *x509.Certificate, key crypto.Signer, tsaCert *x509.Certificate, tsaKey crypto.Signer) error
WriteSignedTimestamped signs the document like WriteSigned and additionally embeds an RFC 3161 signature time-stamp over the signature value, produced by the supplied time-stamp authority certificate and key, yielding a PAdES-B-T signature.
type ExtractedImage ¶
type ExtractedImage struct {
ObjNum int // object number of the image XObject
Width, Height int // pixel dimensions
BitsPerComponent int // bits per colour component
ColorSpace string // colour space name (best effort)
Filter string // the image codec (the last filter in the chain)
Image image.Image // decoded pixels, or nil if the codec was not decoded
Encoded []byte // the encoded stream bytes when Image is nil
Decoded bool // whether Image holds decoded pixels
Note string // why the image was not decoded, when applicable
}
ExtractedImage is one image XObject: its geometry, its codec, and its decoded pixels when available.
type FacturXResult ¶
type FacturXResult struct {
// Violations is every non-conformance: pdf0's container findings, the PDF/A-3
// base's, and the invoice rule engine's fatal ones — the findings whose
// authority rejects a document for breaking them, plus that engine's
// statements about its own run. An empty slice is the clean answer, as it is
// for every other validator in this package.
Violations []FacturXViolation
// InvoiceWarnings is the advisory findings of the invoice rule engine: rules
// their authority reports without rejecting the document, above all the CEN
// syntax-binding rules (CII-SR-*, CII-DT-*) that hold an invoice to the
// EN 16931 core subset of CII. A conforming Factur-X EXTENDED invoice trips
// those by design — carrying more than the core is what EXTENDED is for — so
// they are reported beside the verdict rather than inside it. See
// adoptInvoiceFindings for why they are neither dropped nor merged.
InvoiceWarnings []FacturXViolation
Profile formalis.Profile // "" if not identifiable
// CIUS is the Core Invoice Usage Specification the XMP names, when the
// fx:ConformanceLevel names one instead of a data-richness profile —
// "XRECHNUNG" is the level a ZUGFeRD 2.x producer really writes. The two
// questions are separate and the metadata answers exactly one of them, so
// pdf0 asks both (formalis.ProfileFor and formalis.CIUSFor) and reports what
// it was told; a level that answers neither is a metadata finding.
//
// When the level named a CIUS, the embedded XML is validated by the rule set
// the *invoice* declares in BT-24 rather than by the EN 16931 core at a
// guessed profile, which formalis documents as the more reliable of the two
// claims.
CIUS formalis.CIUS
XMLName string // embedded invoice filename, "" if not found
XML []byte // decoded invoice XML bytes, nil if not found
// InvoiceNotEvaluated names the EN 16931 rule families the invoice rule
// engine publishes and does not evaluate, as that engine reported them for
// this run (formalis.Report.NotEvaluated). It is what lets a caller tell "no
// findings" from "no findings, and here is what nobody looked at".
//
// It is not turned into findings, deliberately. Every rule set has gaps, so a
// finding per unevaluated family would fire on every conforming invoice ever
// validated and would say nothing about this one. It is also not a limit
// trip: nothing stopped, and running the same invoice again with a larger
// budget would not close a gap that is a static property of the rule set.
//
// It is nil when the rule engine was never reached — no embedded XML — which
// is the case InvoiceComplete's false zero value already covers.
InvoiceNotEvaluated []formalis.RuleFamily
// InvoiceComplete reports that the invoice rule engine evaluated every rule
// that can be evaluated (formalis.Report.Complete): the run was not cut
// short, and no evaluable family went unchecked. It is false when no invoice
// XML was found and false when the XML could not be read, so it is never a
// claim about a document nobody validated.
//
// It describes the invoice half only. pdf0's own container half — the PDF/A-3
// base above all — implements a subset of ISO 19005 and publishes no
// equivalent coverage table, so there is no honest whole-result version of
// this question to answer, and a field called Complete would have claimed
// one.
InvoiceComplete bool
}
FacturXResult is the outcome of validating a Factur-X invoice: the container and EN 16931 violations found and, when identifiable, the declared conformance profile and the embedded invoice XML (returned for CIUS-layer validation).
func ValidateFacturX ¶
func ValidateFacturX(doc *Document, rawData []byte) FacturXResult
ValidateFacturX checks whether doc is a conforming Factur-X invoice container. rawData is the original file bytes, needed for the PDF/A-3 byte-level checks.
It is ValidateFacturXContext with a background context.
func ValidateFacturXContext ¶
func ValidateFacturXContext(ctx context.Context, doc *Document, rawData []byte) (res FacturXResult)
ValidateFacturXContext is ValidateFacturX with cancellation.
Both halves of the work honour ctx: the PDF/A-3 container validation, which is the larger of the two on every file in this repository's Factur-X corpus, and the EN 16931 rule engine, which threads the context through its own parse and rule loops.
A cancelled run reports itself the way every other pdf0 validator does — a finding under the reserved rule "limit", which IsCheckerFinding recognises — and keeps the findings gathered before it stopped. The rule engine uses that same identifier for the same event, so a caller draining Violations has one name to look for across container and invoice findings alike. What cannot happen is an empty result: a cancelled validation never looks clean.
type FacturXViolation ¶
type FacturXViolation struct {
// Rule is the identifier of the rule that was broken. pdf0's own container
// rules are "structure", "attachment", "metadata" and "invoice-xml"; the
// PDF/A-3 base's are ISO 19005 clauses under a "pdfa-3/" prefix; the invoice
// engine's are adopted verbatim (EN 16931's BR-*, and formalis's reserved
// "limit", "profile" and "root"). The reserved checker identifiers "limit"
// and "internal" keep their bare names whichever half reports them, so
// IsCheckerFinding recognises them — see adoptPDFAFindings.
Rule string
// Message describes what is wrong.
Message string
// Object is the PDF object number the finding anchors to, and 0 when it does
// not anchor to one: a document-wide container finding, or any finding about
// the invoice XML, which is a document inside the PDF and not an object of
// it. Every finding adopted from the rule engine is of the second kind.
Object int
// Source names the authority that defines Rule, for a finding adopted from
// the invoice rule engine: formalis.SourceEN16931 for a business rule,
// formalis.SourceChecker for that engine's statements about its own run. It
// is the zero Source on pdf0's own container findings, including the PDF/A-3
// ones, because those rules are not formalis's to attribute — and
// formalis.SourceNone is documented as the absent authority rather than as a
// value any formalis finding carries, so the zero value cannot be mistaken
// for a real attribution.
Source formalis.Source
}
FacturXViolation is one finding of the Factur-X container validator: either a departure from a container rule pdf0 checks itself, or one adopted from the EN 16931 rule engine the embedded invoice XML is run through.
It exists because this validator composes two rule engines and the caller gets one report. pdf0's findings anchor to a PDF object; the invoice engine's anchor to a business term in an XML document and name the authority that wrote the rule. Until formalis v0.2.0 this validator carried formalis.Violation values directly, borrowing that type's Object field for PDF object numbers, which made Factur-X and Order-X the only findings in this package that could not satisfy Violation — the exception the package documentation had to keep explaining. Both halves now arrive in a type pdf0 owns, so they combine with every other validator's findings and IsCheckerFinding applies to them.
func (FacturXViolation) Error ¶
func (v FacturXViolation) Error() string
Error renders the finding, naming the authority when the finding was adopted from the invoice rule engine. The authority is in the string and not only in the field for the reason formalis gives for putting it in its own: a rule identifier is unique within its authority and not outside it, so a logged finding that omits the authority is not identified.
func (FacturXViolation) ObjectNum ¶
func (v FacturXViolation) ObjectNum() int
ObjectNum returns the anchoring object number, 0 if N/A.
func (FacturXViolation) RuleID ¶
func (v FacturXViolation) RuleID() string
RuleID returns the Factur-X container rule identifier, or the identifier the invoice rule engine minted for an adopted finding. It is unique only within FacturXViolation.Source, which names the authority.
type IndirectObject ¶
IndirectObject represents a PDF indirect object definition (N G obj ... endobj).
func (IndirectObject) String ¶
func (obj IndirectObject) String() string
type IndirectRef ¶
IndirectRef represents a PDF indirect object reference (N G R).
func (IndirectRef) String ¶
func (ref IndirectRef) String() string
type Lexer ¶
type Lexer struct {
// contains filtered or unexported fields
}
Lexer is a PDF tokenizer that reads from an io.ReaderAt.
func NewLexerFromReaderAt ¶
NewLexerFromReaderAt creates a Lexer from an io.ReaderAt by reading all data. A reader that yields fewer than size bytes is an error: the zero padding a short read would leave behind counts as PDF whitespace, silently masking truncated input.
func (*Lexer) SetPosition ¶
SetPosition sets the current byte offset for random access.
type Object ¶
type Object interface {
// contains filtered or unexported methods
}
Object is the interface all PDF objects implement.
type Option ¶
type Option interface {
// contains filtered or unexported methods
}
Option configures a resource limit. Callers do not construct one directly; they call a With* function. Options are accepted by Read, ReadWithPassword, ReadContext, ReadWithPasswordContext and ParseXRefStream, and the resolved values are inherited by every validator and extractor that runs on the resulting Document.
func WithMaxCIDRangeSpan ¶
WithMaxCIDRangeSpan caps the number of CIDs a single /W range entry may span (default 65536, the size of the CID space). Without it a range such as [0 2000000000 500] would ask for two billion map insertions.
func WithMaxCmapWork ¶
WithMaxCmapWork caps the work spent expanding one TrueType cmap subtable of an expanding format — 4 or 12 — (default 1<<18). A hostile subtable can declare segments or groups whose combined character ranges cover the whole code space many times over.
A subtable the budget stops is returned as a *prefix* of the font's real coverage, marked partial, and the checks that would otherwise read a missing mapping as "this code has no glyph" decline instead and report the trip (see limits_report.go). Lowering this therefore costs coverage of the glyph-presence rules on large fonts; it never turns them into false positives.
func WithMaxContentStreamBytes ¶
WithMaxContentStreamBytes caps the decoded size of a single content stream or image sample buffer that will be scanned (default 64 MB). Larger streams are skipped. The largest real content stream measured is 29 MB.
func WithMaxDecodedContentBytes ¶
WithMaxDecodedContentBytes caps the total decoded content one validation run will materialize (default 512 MB). The per-stream cap stops a single stream exploding; this is the only bound on a whole run, and so the knob for "one upload must not exhaust my process". The heaviest real document measured needs 218 MB.
func WithMaxDecodedStreamBytes ¶
WithMaxDecodedStreamBytes caps the decompressed size of any single stream (default 100 MB). This is the decompression-bomb ceiling and applies to every FlateDecode and LZWDecode stream in the file; lowering it is the main lever for a service accepting untrusted uploads. The largest legitimate stream measured across the veraPDF corpus and a 978-file Common Crawl sample is 29 MB, so values below about 32 MB will start rejecting real documents.
The write-side object-stream cap derives from this value, so lowering it also makes Write emit smaller object-stream containers that the same configuration can read back.
func WithMaxICCProfileBytes ¶
WithMaxICCProfileBytes caps the decoded size of an ICC profile (default 8 MiB). The largest real profile measured is 1.8 MB.
func WithMaxObjectStreamBytes ¶
WithMaxObjectStreamBytes caps the aggregate decompressed size of all object streams in one document (default 512 MB). Object streams are the other compression-amplification path into a document: a small file can carry many containers that each inflate near the per-stream cap. The heaviest real document measured needs 9 MB.
func WithMaxPostScriptSteps ¶
WithMaxPostScriptSteps caps the total operators one type-4 (PostScript calculator) function evaluation may execute (default 1<<20), bounding a function whose loops would otherwise not terminate usefully.
func WithMaxRoleMapSteps ¶
WithMaxRoleMapSteps caps the total /RoleMap chain-follow steps across one PDF/UA structure-type check (default 1<<20), bounding a quadratic blowup on a large hostile role map.
func WithMaxTableGridFills ¶
WithMaxTableGridFills caps the number of grid slots the PDF/UA table checks will fill for one table (default 1<<24), bounding a cell whose /RowSpan and /ColSpan claim a multi-million-slot area.
func WithMaxXMPPacketBytes ¶
WithMaxXMPPacketBytes caps the size of an XMP packet that the property checks will build a node tree for (default 4 MiB). Larger packets are still checked for well-formedness, which streams; only the property-value rules are skipped.
Raising this is more expensive than it looks: tree construction is O(n²), so the worst case grows quadratically — roughly 3 s at the 4 MiB default and 12 s at 8 MiB. The largest real packet measured is 1.6 MB.
type OrderXProfile ¶
type OrderXProfile string
OrderXProfile is an Order-X conformance profile, in increasing richness.
const ( OrderXBasic OrderXProfile = "BASIC" OrderXComfort OrderXProfile = "COMFORT" OrderXExtended OrderXProfile = "EXTENDED" )
type OrderXResult ¶
type OrderXResult struct {
Violations []OrderXViolation
Profile OrderXProfile // "" if not identifiable
XMLName string // embedded order filename, "" if not found
XML []byte // decoded order XML, nil if not found
// OrderWarnings is the advisory findings of the order rule engine, kept out
// of the verdict for the reason FacturXResult.InvoiceWarnings gives. It is
// empty today and would stay empty if this field did not exist: no authority
// has flagged an Order-X rule advisory, and formalis's five ORDER-* rules are
// all fatal by its own decision. It exists so that the split at the adoption
// seam is total — a warning that arrived tomorrow would otherwise be counted
// as a non-conformance by every caller, silently, which is exactly how the
// EN 16931 syntax bindings turned every conforming EXTENDED invoice into a
// forty-finding failure the first time this bump was compiled.
OrderWarnings []OrderXViolation
// OrderNotEvaluated and OrderComplete report what the order rule engine did
// and did not evaluate, exactly as FacturXResult's invoice pair does; that
// documentation applies unchanged.
//
// OrderComplete is false for every order, and will stay false until the rule
// engine implements more than the five mandatory head terms: formalis
// publishes that gap as a fatal family under Coverage(SourceOrderX), so
// OrderNotEvaluated is never empty for a run that reached the engine. That is
// precisely the state this pair exists to make visible — a clean report from
// a rule set that checks five things — and not a defect in any order.
OrderNotEvaluated []formalis.RuleFamily
OrderComplete bool
}
OrderXResult is the outcome of validating an Order-X container.
func ValidateOrderX ¶
func ValidateOrderX(doc *Document, rawData []byte) OrderXResult
ValidateOrderX checks whether doc is a conforming Order-X order container.
It is ValidateOrderXContext with a background context.
func ValidateOrderXContext ¶
func ValidateOrderXContext(ctx context.Context, doc *Document, rawData []byte) (res OrderXResult)
ValidateOrderXContext is ValidateOrderX with cancellation. Both halves of the work honour ctx — the PDF/A-3 container validation and the order rules — and a cancelled run reports a "limit" finding rather than an empty result, exactly as ValidateFacturXContext does and for the same reasons.
type OrderXViolation ¶
OrderXViolation is one finding of the Order-X container validator: either a departure from a container rule pdf0 checks itself, or one adopted from the order rule engine the embedded order XML is run through. Its fields mean what FacturXViolation's mean, which documents them.
It is a type of its own rather than a shared invoice-container finding, for the reason every other validator in this package has one: an Order-X is a different standard judged by a different rule set, and Error has to say so — a caller holding one mixed report must be able to read "ORDER-03" and know it is the order type code and not something an invoice rule engine said. The two namespaces really do overlap, and have already collided once inside formalis itself, which renamed its Order-X rules out of CEN's BR-O-* numbering after a caller aggregating by identifier merged two unrelated defects. Sharing one type here would put that collision back one level up, in the type a caller switches on.
func (OrderXViolation) Error ¶
func (v OrderXViolation) Error() string
Error renders the finding; see FacturXViolation.Error.
func (OrderXViolation) ObjectNum ¶
func (v OrderXViolation) ObjectNum() int
ObjectNum returns the anchoring object number, 0 if N/A.
func (OrderXViolation) RuleID ¶
func (v OrderXViolation) RuleID() string
RuleID returns the Order-X container rule identifier, or the identifier the order rule engine minted for an adopted finding.
type PAdESLevel ¶
type PAdESLevel string
PAdESLevel is a PAdES baseline conformance level.
const ( PAdESNone PAdESLevel = "" // not a PAdES signature (e.g. legacy adbe.*) PAdESBB PAdESLevel = "B-B" // basic: conformant CAdES-BES PAdESBT PAdESLevel = "B-T" // + a signature timestamp PAdESBLT PAdESLevel = "B-LT" // + long-term validation material (DSS) PAdESBLTA PAdESLevel = "B-LTA" // + a document timestamp over the DSS )
type PAdESResult ¶
type PAdESResult struct {
// Field is the fully qualified name of the signature field whose /V
// references this signature, exactly as SignatureResult.Field: the /T
// partial names of the field and its ancestors joined with "." (ISO 32000-2
// §12.7.4.2). It is empty when no field references the signature, or when no
// field in the chain carries a /T.
Field string
SubFilter string // the signature /SubFilter
IsPAdES bool // uses a PAdES sub-filter
Level PAdESLevel // baseline level reached (PAdESNone if not PAdES)
Conformant bool // meets the PAdES B-B baseline requirements
Valid bool // the CMS signature cryptographically verifies
CoversDocument bool // the /ByteRange reaches the end of the file
SignerCommonName string
TimestampValid bool // the signature time-stamp verifies (imprint + TSA signature)
TimestampTime time.Time // the time asserted by a verified signature time-stamp
Issues []string // PAdES conformance problems
}
PAdESResult reports the PAdES assessment of one signature.
type PDFRViolation ¶
PDFRViolation reports a departure from the PDF/R structural profile.
func ValidatePDFR ¶
func ValidatePDFR(d *Document) []PDFRViolation
ValidatePDFR checks a document against the PDF/R structural profile.
func ValidatePDFRContext ¶
func ValidatePDFRContext(ctx context.Context, d *Document) []PDFRViolation
ValidatePDFRContext is ValidatePDFR with cancellation; a cancelled run reports itself under the rule "limit" (see cancel.go).
func (PDFRViolation) Error ¶
func (v PDFRViolation) Error() string
func (PDFRViolation) ObjectNum ¶
func (v PDFRViolation) ObjectNum() int
ObjectNum returns the anchoring object number, 0 if N/A.
func (PDFRViolation) RuleID ¶
func (v PDFRViolation) RuleID() string
RuleID returns the PDF/R rule identifier.
type PDFVTViolation ¶
type PDFVTViolation struct {
Rule string // short rule identifier, base-profile violations prefixed "pdfx-4/" or "dpart/"
Message string
Object int // object number the violation anchors to, 0 if N/A
}
PDFVTViolation reports a way in which a document departs from PDF/VT-1.
func ValidatePDFVT ¶
func ValidatePDFVT(doc *Document) []PDFVTViolation
ValidatePDFVT checks whether doc conforms to PDF/VT-1 (ISO 16612-2). It requires conformance to the PDF/X-4 base profile, a valid document part hierarchy, and PDF/VT-1 identification in XMP. An empty result means no violations were found.
func ValidatePDFVT2 ¶
func ValidatePDFVT2(doc *Document) []PDFVTViolation
ValidatePDFVT2 checks whether doc conforms to PDF/VT-2 (ISO 16612-2). PDF/VT-2 is based on PDF/X-5 rather than PDF/X-4, so it additionally permits externally referenced content (reference XObjects); it is otherwise validated like PDF/VT-1. pdf0 has no PDF/X-5 validator, so the PDF/X-4 base is used with the reference-XObject prohibition relaxed — the PDF/X-5-specific external-reference rules are not asserted.
func ValidatePDFVT2Context ¶
func ValidatePDFVT2Context(ctx context.Context, doc *Document) []PDFVTViolation
ValidatePDFVT2Context is ValidatePDFVT2 with cancellation; a cancelled run reports itself under the rule "limit" (see cancel.go).
func ValidatePDFVTContext ¶
func ValidatePDFVTContext(ctx context.Context, doc *Document) []PDFVTViolation
ValidatePDFVTContext is ValidatePDFVT with cancellation; a cancelled run reports itself under the rule "limit" (see cancel.go).
func (PDFVTViolation) Error ¶
func (v PDFVTViolation) Error() string
func (PDFVTViolation) ObjectNum ¶
func (v PDFVTViolation) ObjectNum() int
ObjectNum returns the anchoring object number, 0 if N/A.
func (PDFVTViolation) RuleID ¶
func (v PDFVTViolation) RuleID() string
RuleID returns the PDF/VT rule identifier.
type PDFXLevel ¶
type PDFXLevel int
PDFXLevel identifies a PDF/X conformance level.
const ( // PDFX4 is PDF/X-4 with an embedded ICC destination profile (ISO 15930-7). PDFX4 PDFXLevel = iota // PDFX4p is PDF/X-4p, which permits an externally referenced destination // profile instead of an embedded one. PDFX4p // PDFX1a is PDF/X-1a (ISO 15930-1/4): CMYK, grayscale and spot colour only, // no transparency, defined against PDF 1.3/1.4. PDFX1a // PDFX3 is PDF/X-3 (ISO 15930-3/6): PDF/X-1a plus ICC-managed colour, still // no transparency, PDF 1.3/1.4. PDFX3 // PDFX6 is PDF/X-6 (ISO 15930-9): the PDF 2.0-based successor to PDF/X-4. PDFX6 )
type PDFXViolation ¶
type PDFXViolation struct {
Rule string // short rule identifier, e.g. "output-intent"
Message string
Object int // object number the violation anchors to, 0 if N/A
}
PDFXViolation reports a way in which a document departs from a PDF/X level.
func ValidatePDFX ¶
func ValidatePDFX(doc *Document, level PDFXLevel) []PDFXViolation
ValidatePDFX checks whether doc conforms to the given PDF/X level. An empty result means no violations were found.
func ValidatePDFXContext ¶
func ValidatePDFXContext(ctx context.Context, doc *Document, level PDFXLevel) []PDFXViolation
ValidatePDFXContext is ValidatePDFX with cancellation; a cancelled run reports itself under the rule "limit" (see cancel.go).
func (PDFXViolation) Error ¶
func (v PDFXViolation) Error() string
func (PDFXViolation) ObjectNum ¶
func (v PDFXViolation) ObjectNum() int
ObjectNum returns the anchoring object number, 0 if N/A.
func (PDFXViolation) RuleID ¶
func (v PDFXViolation) RuleID() string
RuleID returns the PDF/X rule identifier.
type Parser ¶
type Parser struct {
// contains filtered or unexported fields
}
Parser builds PDF Object values from a token stream.
func NewParserFromLexer ¶
NewParserFromLexer creates a new Parser using the given lexer.
func (*Parser) ParseIndirectObject ¶
func (p *Parser) ParseIndirectObject() (*IndirectObject, error)
ParseIndirectObject parses an indirect object definition: N G obj ... endobj
func (*Parser) ParseObject ¶
ParseObject parses any PDF object from the token stream.
type RepairAction ¶
type RepairAction struct {
Description string
}
RepairAction records one fix applied by Repair.
type RevocationInfo ¶
type RevocationInfo struct {
Status RevocationStatus
Source string // "OCSP", "CRL" or "" when unknown
RevokedAt time.Time // when the certificate was revoked, if revoked
}
RevocationInfo reports a certificate's revocation status and where it came from.
func CheckCertRevocation ¶
func CheckCertRevocation(cert, issuer *x509.Certificate, crls, ocsps [][]byte) RevocationInfo
CheckCertRevocation determines the revocation status of cert (issued by issuer) from the supplied CRLs and OCSP responses (DER). Each source must be signed by issuer to be trusted. OCSP is consulted first; a definite verdict (good or revoked) is returned as soon as one source gives it.
type RevocationStatus ¶
type RevocationStatus int
RevocationStatus is the outcome of a revocation check.
const ( RevocationUnknown RevocationStatus = iota // no usable material said either way RevocationGood // asserted not revoked RevocationRevoked // asserted revoked )
func (RevocationStatus) String ¶
func (s RevocationStatus) String() string
type Serializer ¶
type Serializer struct {
// contains filtered or unexported fields
}
Serializer writes PDF objects to an io.Writer.
func NewSerializer ¶
func NewSerializer(w io.Writer) *Serializer
NewSerializer creates a new Serializer writing to w.
func (*Serializer) Offset ¶
func (s *Serializer) Offset() int64
Offset returns the current byte offset (total bytes written).
func (*Serializer) WriteIndirectObject ¶
func (s *Serializer) WriteIndirectObject(obj *IndirectObject) error
WriteIndirectObject writes an indirect object definition to the output.
func (*Serializer) WriteObject ¶
func (s *Serializer) WriteObject(obj Object) error
WriteObject writes any PDF object to the output.
type SignatureResult ¶
type SignatureResult struct {
// Field is the FULLY QUALIFIED name of the signature field whose /V
// references this signature dictionary: the field's own /T partial name
// prefixed by the /T of every ancestor field, joined with "." (ISO 32000-2
// §12.7.4.2). The qualified name is what identifies a field uniquely in a
// document — a partial name is only unique among its siblings — so it is
// what a caller can display, log, or look the field up by. For the common
// flat form (a top-level field, as pdf0's own signing produces) it is just
// the partial name, e.g. "Signature1".
//
// It is empty when nothing names the signature: a bare signature dictionary
// that no field's /V points at, or a field chain in which neither the field
// nor any of its ancestors carries a /T.
Field string
SignerCommonName string // Subject CN of the signing certificate
CoversWholeDocument bool // the /ByteRange covers the whole file except the /Contents window
Valid bool // the signed bytes are intact and the signature verifies
SigningTime time.Time // signing-time signed attribute, if present (self-asserted, untrusted)
TrustedChain bool // the certificate chains to a supplied trust root
ChainErr error // why the chain did not build (when roots were given)
Revocation RevocationInfo // revocation status from the document's DSS material
Err error // why signature verification failed, if it did
}
SignatureResult reports the outcome of verifying one signature field.
Valid and CoversWholeDocument are independent and must both be consulted: Valid says the bytes inside the signed /ByteRange are intact and were signed by the embedded certificate's key, but it says nothing about bytes OUTSIDE that range. A signed document can be modified after signing by an incremental update — the original signed range stays intact (Valid == true) while the rendered content changes (CoversWholeDocument == false). Use DocumentUnmodified for the combined "signed and nothing was changed" verdict.
func (SignatureResult) DocumentUnmodified ¶
func (r SignatureResult) DocumentUnmodified() bool
DocumentUnmodified reports the safe combined verdict: the signature cryptographically verifies AND it covers the whole document, so nothing was changed after signing. Callers that read only Valid accept a document whose content was altered by a post-signing incremental update; prefer this.
type Stream ¶
type Stream struct {
Dict Dictionary
Data []byte // raw (encoded) stream data
}
Stream represents a PDF stream object.
type Token ¶
type Token struct {
Type TokenType
Value []byte // raw bytes of the token
Offset int64 // byte offset in input
}
Token represents a single lexer token.
type TokenType ¶
type TokenType int
TokenType identifies the type of a lexer token.
const ( TokenBoolean TokenType = iota // true, false TokenInteger // 123, -98 TokenReal // 3.14, -.002 TokenString // (literal) or <hex> TokenName // /SomeName TokenArrayStart // [ TokenArrayEnd // ] TokenDictStart // << TokenDictEnd // >> TokenStream // stream keyword TokenEndStream // endstream keyword TokenObj // obj keyword TokenEndObj // endobj keyword TokenRef // R keyword TokenXref // xref keyword TokenTrailer // trailer keyword TokenStartXref // startxref keyword TokenNull // null keyword TokenEOF )
type UAViolation ¶
UAViolation is a PDF/UA-1 (ISO 14289-1) accessibility conformance failure.
func ValidatePDFUA ¶
func ValidatePDFUA(doc *Document) []UAViolation
ValidatePDFUA checks a document against the foundational PDF/UA-1 (ISO 14289-1) requirements: the document must be tagged, carry a structure tree and a default language, be configured to display its title, and give every figure alternate text. It is a partial validator — a clean result means the implemented checks passed, not full PDF/UA conformance.
func ValidatePDFUA2 ¶
func ValidatePDFUA2(d *Document) []UAViolation
ValidatePDFUA2 checks a document against PDF/UA-2. Findings reuse the UAViolation type; clause identifiers follow ISO 14289-2.
func ValidatePDFUA2Context ¶
func ValidatePDFUA2Context(ctx context.Context, d *Document) []UAViolation
ValidatePDFUA2Context is ValidatePDFUA2 with cancellation; see ValidatePDFUAContext for how a cancelled run reports itself.
func ValidatePDFUAContext ¶
func ValidatePDFUAContext(ctx context.Context, doc *Document) []UAViolation
ValidatePDFUAContext is ValidatePDFUA with cancellation. When ctx ends the run stops and returns the findings gathered so far plus one under the clause "limit" recording the cancellation, which IsCheckerFinding reports as a checker finding — so a cancelled run cannot be mistaken for a clean one. See cancel.go.
func (UAViolation) Error ¶
func (v UAViolation) Error() string
func (UAViolation) ObjectNum ¶
func (v UAViolation) ObjectNum() int
ObjectNum returns the anchoring object number, 0 if N/A.
func (UAViolation) RuleID ¶
func (v UAViolation) RuleID() string
RuleID returns the ISO 14289 clause identifier.
type ValidationError ¶
type ValidationError struct {
Rule string // e.g., "6.1.3" (ISO 19005 clause)
Level PDFALevel // the level that requires this rule
Message string
Object int // object number, 0 if N/A
}
ValidationError describes a single PDF/A conformance violation.
func ValidatePDFA ¶
func ValidatePDFA(doc *Document, level PDFALevel) []ValidationError
ValidatePDFA checks doc against the implemented rules for the given PDF/A level and returns the violations found. An empty result means "none of the implemented checks fired", not a guarantee of full conformance: the validator covers a subset of ISO 19005 (see the package README). Because it takes no raw bytes, it also skips every byte-level file-structure rule — use ValidatePDFABytes when you have the file bytes and want those too.
func ValidatePDFABytes ¶
func ValidatePDFABytes(doc *Document, level PDFALevel, rawData []byte) []ValidationError
ValidatePDFABytes checks doc against the implemented rules for the given PDF/A level and returns the violations found. If rawData is non-nil, the byte-level file-structure rules run too (e.g. no data after %%EOF). An empty result means no implemented check fired, not a guarantee of full conformance (the validator covers a subset of ISO 19005).
func ValidatePDFABytesContext ¶
func ValidatePDFABytesContext(ctx context.Context, doc *Document, level PDFALevel, rawData []byte) []ValidationError
ValidatePDFABytesContext is ValidatePDFABytes with cancellation; see ValidatePDFAContext for how a cancelled run reports itself.
func ValidatePDFAContext ¶
func ValidatePDFAContext(ctx context.Context, doc *Document, level PDFALevel) []ValidationError
ValidatePDFAContext is ValidatePDFA with cancellation. Validating a large document is the package's longest-running operation, so this is the variant a caller under a deadline should use.
When ctx ends the run stops and returns the findings gathered so far plus one under the rule "limit" recording the cancellation, which IsCheckerFinding reports as a checker finding. A cancelled run therefore never looks like a clean bill of health: an empty result is impossible, and the caller can tell "no violations found" apart from "pdf0 did not get to look". See cancel.go.
func (ValidationError) Error ¶
func (e ValidationError) Error() string
func (ValidationError) ObjectNum ¶
func (e ValidationError) ObjectNum() int
ObjectNum returns the anchoring object number, 0 if N/A.
func (ValidationError) RuleID ¶
func (e ValidationError) RuleID() string
RuleID returns the ISO 19005 clause identifier.
type Violation ¶
type Violation interface {
error
// RuleID returns the identifier of the violated rule — an ISO clause like
// "6.1.3" or a short rule name like "output-intent" — as carried in the
// concrete type's Rule (or Clause) field.
RuleID() string
// ObjectNum returns the object number the finding anchors to, 0 if the
// finding is not tied to a specific object.
ObjectNum() int
}
Violation is the common face of every validator finding. Each validator keeps its own concrete type — ValidationError (PDF/A), UAViolation (PDF/UA), PDFXViolation, PDFVTViolation, PDFRViolation, DPartViolation, FacturXViolation, OrderXViolation — with the fields and Error formatting of its standard, but all of them satisfy this interface, so findings from different validators can be collected, filtered and reported together:
var all []pdf0.Violation
for _, e := range pdf0.ValidatePDFA(doc, pdf0.PDFA2b) {
all = append(all, e)
}
for _, e := range pdf0.ValidatePDFUA(doc) {
all = append(all, e)
}
There is no longer an exception. The Factur-X and Order-X validators return a result struct rather than a slice, because they carry the extracted invoice XML and its coverage alongside the findings, but the findings themselves are FacturXViolation and OrderXViolation values and satisfy this interface like any other. They used to hold formalis.Violation, an external type this package could not extend, which also put them outside IsCheckerFinding — so a cancelled or panicking run had no way to say "pdf0 stopped early" that a caller could tell apart from a conformance failure. That is why those two validators had no Context variant, and why they have one now.
type XRefEntry ¶
type XRefEntry struct {
Offset int64
Generation int
Free bool
Compressed bool
StreamObjNum int // object stream containing this object
IndexInStream int // index within object stream
}
XRefEntry represents a single cross-reference table entry.
type XRefTable ¶
XRefTable holds all cross-reference entries indexed by object number.
func ParseXRefStream ¶
ParseXRefStream parses a cross-reference stream.
Resource limits default to values safe for untrusted input; pass With* options to change them. (*Document) supplies its own resolved limits when it calls this during Read, so a document read with options keeps them here.
Source Files
¶
- cancel.go
- ccitt.go
- cff_strings.go
- cms.go
- compare.go
- content_operators.go
- crypt.go
- crypt_encrypt.go
- doc.go
- doctimestamp.go
- document.go
- dpart.go
- facturx.go
- facturx_write.go
- filestructure.go
- filters.go
- final_rules.go
- font_encodings.go
- fontprog.go
- fonts.go
- function.go
- function_ps.go
- imagecolor.go
- imageextract.go
- imagejpeg.go
- imagemask.go
- incremental.go
- jbig2.go
- jbig2_halftone.go
- jbig2_huffcode.go
- jbig2_huffman.go
- jbig2_refine.go
- jbig2_symbol.go
- lexer.go
- limits.go
- limits_report.go
- mq.go
- object.go
- objstm.go
- objstm_write.go
- order_x.go
- pades.go
- pages.go
- parser.go
- pdfa.go
- pdfa_create.go
- pdfa_levela.go
- pdfr.go
- pdfua.go
- pdfua2.go
- pdfua_content.go
- pdfua_struct.go
- pdfua_tablegrid.go
- pdfvt.go
- pdfx.go
- pdfx_color.go
- preflight.go
- revocation.go
- serializer.go
- sign.go
- signatures.go
- text.go
- timestamp.go
- validator_guard.go
- violations.go
- xmp.go
- xmp_schemas.go
- xref.go
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
corpusprobe
command
Command corpusprobe stress-tests the parser against a directory of (untrusted) PDFs, recording parse outcomes and — most importantly — any panics or hangs, which represent robustness bugs: the parser must return an error, never crash or loop, on malformed input.
|
Command corpusprobe stress-tests the parser against a directory of (untrusted) PDFs, recording parse outcomes and — most importantly — any panics or hangs, which represent robustness bugs: the parser must return an error, never crash or loop, on malformed input. |
|
corpustime
command
Command corpustime times each parse stage of one PDF with a generous budget, to distinguish a truly-hanging stage from a merely-slow huge file.
|
Command corpustime times each parse stage of one PDF with a generous budget, to distinguish a truly-hanging stage from a merely-slow huge file. |
|
pdf0
command
Command pdf0 is a small command-line front end to the pdf0 library: inspect, validate, decrypt, and encrypt PDF files.
|
Command pdf0 is a small command-line front end to the pdf0 library: inspect, validate, decrypt, and encrypt PDF files. |
|
rulecoverage
command
Command rulecoverage reports how the pdf0 PDF/A validator's rule coverage compares to the veraPDF validation profiles — the machine-readable inventory of every PDF/A rule the reference validator checks.
|
Command rulecoverage reports how the pdf0 PDF/A validator's rule coverage compares to the veraPDF validation profiles — the machine-readable inventory of every PDF/A rule the reference validator checks. |
|
examples
|
|
|
extract_images
command
Command extract_images builds a small PDF holding two image XObjects, writes it, reads it back, and walks the images with the lazy Images iterator.
|
Command extract_images builds a small PDF holding two image XObjects, writes it, reads it back, and walks the images with the lazy Images iterator. |
|
sign_verify
command
Command sign_verify signs a one-page document with a self-signed certificate generated in-process and verifies it, showing the verdict a caller must actually read: DocumentUnmodified (Valid AND CoversWholeDocument) plus TrustedChain from VerifySignaturesWithRoots.
|
Command sign_verify signs a one-page document with a self-signed certificate generated in-process and verifies it, showing the verdict a caller must actually read: DocumentUnmodified (Valid AND CoversWholeDocument) plus TrustedChain from VerifySignaturesWithRoots. |
|
simple_pdf
command
|
|
|
simple_pdf17
command
|
|
|
simple_pdfa
command
|