muun-recovery/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/xReftable.go

920 lines
25 KiB
Go

/*
Copyright 2018 The pdfcpu Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package validate implements validation against PDF 32000-1:2008.
package validate
import (
"github.com/pdfcpu/pdfcpu/pkg/log"
pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu"
"github.com/pkg/errors"
)
// XRefTable validates a PDF cross reference table obeying the validation mode.
func XRefTable(xRefTable *pdf.XRefTable) error {
log.Info.Println("validating")
log.Validate.Println("*** validateXRefTable begin ***")
// Validate root object(aka the document catalog) and page tree.
err := validateRootObject(xRefTable)
if err != nil {
return err
}
// Validate document information dictionary.
err = validateDocumentInfoObject(xRefTable)
if err != nil {
return err
}
// Validate offspec additional streams as declared in pdf trailer.
err = validateAdditionalStreams(xRefTable)
if err != nil {
return err
}
xRefTable.Valid = true
log.Validate.Println("*** validateXRefTable end ***")
return nil
}
func validateRootVersion(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
_, err := validateNameEntry(xRefTable, rootDict, "rootDict", "Version", OPTIONAL, sinceVersion, nil)
return err
}
func validateExtensions(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
// => 7.12 Extensions Dictionary
_, err := validateDictEntry(xRefTable, rootDict, "rootDict", "Extensions", required, sinceVersion, nil)
// No validation due to lack of documentation.
return err
}
func validatePageLabels(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
// optional since PDF 1.3
// => 7.9.7 Number Trees, 12.4.2 Page Labels
// Dict or indirect ref to Dict
ir := rootDict.IndirectRefEntry("PageLabels")
if ir == nil {
if required {
return errors.Errorf("validatePageLabels: required entry \"PageLabels\" missing")
}
return nil
}
dictName := "PageLabels"
// Version check
err := xRefTable.ValidateVersion(dictName, sinceVersion)
if err != nil {
return err
}
_, _, err = validateNumberTree(xRefTable, "PageLabel", *ir, true)
return err
}
func validateNames(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
// => 7.7.4 Name Dictionary
d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "Names", required, sinceVersion, nil)
if err != nil || d == nil {
return err
}
validateNameTreeName := func(s string) bool {
return pdf.MemberOf(s, []string{"Dests", "AP", "JavaScript", "Pages", "Templates", "IDS",
"URLS", "EmbeddedFiles", "AlternatePresentations", "Renditions"})
}
for treeName, value := range d {
if ok := validateNameTreeName(treeName); !ok {
return errors.Errorf("validateNames: unknown name tree name: %s\n", treeName)
}
d, err := xRefTable.DereferenceDict(value)
if err != nil {
return err
}
if d == nil || len(d) == 0 {
continue
}
_, _, tree, err := validateNameTree(xRefTable, treeName, d, true)
if err != nil {
return err
}
// Internalize this name tree.
// If no validation takes place, name trees have to be internalized via xRefTable.LocateNameTree
// TODO Move this out of validation into Read.
if tree != nil {
xRefTable.Names[treeName] = tree
}
}
return nil
}
func validateNamedDestinations(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
// => 12.3.2.3 Named Destinations
// indRef or dict with destination array values.
d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "Dests", required, sinceVersion, nil)
if err != nil || d == nil {
return err
}
for _, o := range d {
err = validateDestination(xRefTable, o)
if err != nil {
return err
}
}
return nil
}
func validateViewerPreferences(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
// => 12.2 Viewer Preferences
dictName := "rootDict"
d, err := validateDictEntry(xRefTable, rootDict, dictName, "ViewerPreferences", required, sinceVersion, nil)
if err != nil || d == nil {
return err
}
dictName = "ViewerPreferences"
_, err = validateBooleanEntry(xRefTable, d, dictName, "HideToolbar", OPTIONAL, pdf.V10, nil)
if err != nil {
return err
}
_, err = validateBooleanEntry(xRefTable, d, dictName, "HideMenubar", OPTIONAL, pdf.V10, nil)
if err != nil {
return err
}
_, err = validateBooleanEntry(xRefTable, d, dictName, "HideWindowUI", OPTIONAL, pdf.V10, nil)
if err != nil {
return err
}
_, err = validateBooleanEntry(xRefTable, d, dictName, "FitWindow", OPTIONAL, pdf.V10, nil)
if err != nil {
return err
}
_, err = validateBooleanEntry(xRefTable, d, dictName, "CenterWindow", OPTIONAL, pdf.V10, nil)
if err != nil {
return err
}
sinceVersion = pdf.V14
if xRefTable.ValidationMode == pdf.ValidationRelaxed {
sinceVersion = pdf.V10
}
_, err = validateBooleanEntry(xRefTable, d, dictName, "DisplayDocTitle", OPTIONAL, sinceVersion, nil)
if err != nil {
return err
}
validate := func(s string) bool { return pdf.MemberOf(s, []string{"UseNone", "UseOutlines", "UseThumbs", "UseOC"}) }
_, err = validateNameEntry(xRefTable, d, dictName, "NonFullScreenPageMode", OPTIONAL, pdf.V10, validate)
if err != nil {
return err
}
validate = func(s string) bool { return pdf.MemberOf(s, []string{"L2R", "R2L"}) }
_, err = validateNameEntry(xRefTable, d, dictName, "Direction", OPTIONAL, pdf.V13, validate)
if err != nil {
return err
}
_, err = validateNameEntry(xRefTable, d, dictName, "ViewArea", OPTIONAL, pdf.V14, nil)
return err
}
func validatePageLayout(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
_, err := validateNameEntry(xRefTable, rootDict, "rootDict", "PageLayout", required, sinceVersion, nil)
return err
}
func validatePageMode(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
_, err := validateNameEntry(xRefTable, rootDict, "rootDict", "PageMode", required, sinceVersion, nil)
return err
}
func validateOpenAction(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
// => 12.3.2 Destinations, 12.6 Actions
// A value specifying a destination that shall be displayed
// or an action that shall be performed when the document is opened.
// The value shall be either an array defining a destination (see 12.3.2, "Destinations")
// or an action dictionary representing an action (12.6, "Actions").
//
// If this entry is absent, the document shall be opened
// to the top of the first page at the default magnification factor.
o, err := validateEntry(xRefTable, rootDict, "rootDict", "OpenAction", required, sinceVersion)
if err != nil || o == nil {
return err
}
switch o := o.(type) {
case pdf.Dict:
err = validateActionDict(xRefTable, o)
case pdf.Array:
err = validateDestinationArray(xRefTable, o)
default:
err = errors.New("pdfcpu: validateOpenAction: unexpected object")
}
return err
}
func validateURI(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
// => 12.6.4.7 URI Actions
// URI dict with one optional entry Base, ASCII string
d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "URI", required, sinceVersion, nil)
if err != nil || d == nil {
return err
}
// Base, optional, ASCII string
_, err = validateStringEntry(xRefTable, d, "URIdict", "Base", OPTIONAL, pdf.V10, nil)
return err
}
func validateRootMetadata(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
return validateMetadata(xRefTable, rootDict, required, sinceVersion)
}
func validateMetadata(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error {
// => 14.3 Metadata
// In general, any PDF stream or dictionary may have metadata attached to it
// as long as the stream or dictionary represents an actual information resource,
// as opposed to serving as an implementation artifact.
// Some PDF constructs are considered implementational, and hence may not have associated metadata.
if xRefTable.ValidationMode == pdf.ValidationRelaxed {
sinceVersion = pdf.V13
}
sd, err := validateStreamDictEntry(xRefTable, d, "dict", "Metadata", required, sinceVersion, nil)
if err != nil || sd == nil {
return err
}
dictName := "metaDataDict"
_, err = validateNameEntry(xRefTable, sd.Dict, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "Metadata" })
if err != nil {
return err
}
_, err = validateNameEntry(xRefTable, sd.Dict, dictName, "Subtype", OPTIONAL, sinceVersion, func(s string) bool { return s == "XML" })
return err
}
func validateMarkInfo(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
// => 14.7 Logical Structure
d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "MarkInfo", required, sinceVersion, nil)
if err != nil || d == nil {
return err
}
var isTaggedPDF bool
dictName := "markInfoDict"
// Marked, optional, boolean
marked, err := validateBooleanEntry(xRefTable, d, dictName, "Marked", OPTIONAL, pdf.V10, nil)
if err != nil {
return err
}
if marked != nil {
isTaggedPDF = marked.Value()
}
// Suspects: optional, since V1.6, boolean
suspects, err := validateBooleanEntry(xRefTable, d, dictName, "Suspects", OPTIONAL, pdf.V16, nil)
if err != nil {
return err
}
if suspects != nil && suspects.Value() {
isTaggedPDF = false
}
xRefTable.Tagged = isTaggedPDF
// UserProperties: optional, since V1.6, boolean
_, err = validateBooleanEntry(xRefTable, d, dictName, "UserProperties", OPTIONAL, pdf.V16, nil)
return err
}
func validateLang(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
_, err := validateStringEntry(xRefTable, rootDict, "rootDict", "Lang", required, sinceVersion, nil)
return err
}
func validateCaptureCommandDictArray(xRefTable *pdf.XRefTable, a pdf.Array) error {
for _, o := range a {
d, err := xRefTable.DereferenceDict(o)
if err != nil {
return err
}
if d == nil {
continue
}
err = validateCaptureCommandDict(xRefTable, d)
if err != nil {
return err
}
}
return nil
}
func validateWebCaptureInfoDict(xRefTable *pdf.XRefTable, d pdf.Dict) error {
dictName := "webCaptureInfoDict"
// V, required, since V1.3, number
_, err := validateNumberEntry(xRefTable, d, dictName, "V", REQUIRED, pdf.V13, nil)
if err != nil {
return err
}
// C, optional, since V1.3, array of web capture command dict indRefs
a, err := validateIndRefArrayEntry(xRefTable, d, dictName, "C", OPTIONAL, pdf.V13, nil)
if err != nil {
return err
}
if a != nil {
err = validateCaptureCommandDictArray(xRefTable, a)
}
return err
}
func validateSpiderInfo(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
// 14.10.2 Web Capture Information Dictionary
d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "SpiderInfo", required, sinceVersion, nil)
if err != nil || d == nil {
return err
}
return validateWebCaptureInfoDict(xRefTable, d)
}
func validateOutputIntentDict(xRefTable *pdf.XRefTable, d pdf.Dict) error {
dictName := "outputIntentDict"
// Type, optional, name
_, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "OutputIntent" })
if err != nil {
return err
}
// S: required, name
_, err = validateNameEntry(xRefTable, d, dictName, "S", REQUIRED, pdf.V10, nil)
if err != nil {
return err
}
// OutputCondition, optional, text string
_, err = validateStringEntry(xRefTable, d, dictName, "OutputCondition", OPTIONAL, pdf.V10, nil)
if err != nil {
return err
}
// OutputConditionIdentifier, required, text string
_, err = validateStringEntry(xRefTable, d, dictName, "OutputConditionIdentifier", REQUIRED, pdf.V10, nil)
if err != nil {
return err
}
// RegistryName, optional, text string
_, err = validateStringEntry(xRefTable, d, dictName, "RegistryName", OPTIONAL, pdf.V10, nil)
if err != nil {
return err
}
// Info, optional, text string
_, err = validateStringEntry(xRefTable, d, dictName, "Info", OPTIONAL, pdf.V10, nil)
if err != nil {
return err
}
// DestOutputProfile, optional, streamDict
_, err = validateStreamDictEntry(xRefTable, d, dictName, "DestOutputProfile", OPTIONAL, pdf.V10, nil)
return err
}
func validateOutputIntents(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
// => 14.11.5 Output Intents
if xRefTable.ValidationMode == pdf.ValidationRelaxed {
sinceVersion = pdf.V13
}
a, err := validateArrayEntry(xRefTable, rootDict, "rootDict", "OutputIntents", required, sinceVersion, nil)
if err != nil || a == nil {
return err
}
for _, o := range a {
d, err := xRefTable.DereferenceDict(o)
if err != nil {
return err
}
if d == nil {
continue
}
err = validateOutputIntentDict(xRefTable, d)
if err != nil {
return err
}
}
return nil
}
func validatePieceDict(xRefTable *pdf.XRefTable, d pdf.Dict) error {
dictName := "pieceDict"
for _, o := range d {
d1, err := xRefTable.DereferenceDict(o)
if err != nil {
return err
}
if d1 == nil {
continue
}
required := REQUIRED
if xRefTable.ValidationMode == pdf.ValidationRelaxed {
required = OPTIONAL
}
_, err = validateDateEntry(xRefTable, d1, dictName, "LastModified", required, pdf.V10)
if err != nil {
return err
}
_, err = validateEntry(xRefTable, d1, dictName, "Private", OPTIONAL, pdf.V10)
if err != nil {
return err
}
}
return nil
}
func validateRootPieceInfo(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
_, err := validatePieceInfo(xRefTable, rootDict, "rootDict", "PieceInfo", required, sinceVersion)
return err
}
func validatePieceInfo(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) (hasPieceInfo bool, err error) {
// 14.5 Page-Piece Dictionaries
pieceDict, err := validateDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil)
if err != nil || pieceDict == nil {
return false, err
}
err = validatePieceDict(xRefTable, pieceDict)
return hasPieceInfo, err
}
// TODO implement
func validatePermissions(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
// => 12.8.4 Permissions
d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "Permissions", required, sinceVersion, nil)
if err != nil || d == nil {
return err
}
return errors.New("pdfcpu: validatePermissions: not supported")
}
// TODO implement
func validateLegal(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
// => 12.8.5 Legal Content Attestations
d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "Legal", required, sinceVersion, nil)
if err != nil || d == nil {
return err
}
return errors.New("pdfcpu: validateLegal: not supported")
}
func validateRequirementDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error {
dictName := "requirementDict"
// Type, optional, name,
_, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "Requirement" })
if err != nil {
return err
}
// S, required, name
_, err = validateNameEntry(xRefTable, d, dictName, "S", REQUIRED, sinceVersion, func(s string) bool { return s == "EnableJavaScripts" })
if err != nil {
return err
}
// The RH entry (requirement handler dicts) shall not be used in PDF 1.7.
return nil
}
func validateRequirements(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
// => 12.10 Document Requirements
a, err := validateArrayEntry(xRefTable, rootDict, "rootDict", "Requirements", required, sinceVersion, nil)
if err != nil || a == nil {
return err
}
for _, o := range a {
d, err := xRefTable.DereferenceDict(o)
if err != nil {
return err
}
if d == nil {
continue
}
err = validateRequirementDict(xRefTable, d, sinceVersion)
if err != nil {
return err
}
}
return nil
}
func validateCollectionFieldDict(xRefTable *pdf.XRefTable, d pdf.Dict) error {
dictName := "colFlddict"
_, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "CollectionField" })
if err != nil {
return err
}
// Subtype, required name
validateCollectionFieldSubtype := func(s string) bool {
return pdf.MemberOf(s, []string{"S", "D", "N", "F", "Desc", "ModDate", "CreationDate", "Size"})
}
_, err = validateNameEntry(xRefTable, d, dictName, "Subtype", REQUIRED, pdf.V10, validateCollectionFieldSubtype)
if err != nil {
return err
}
// N, required text string
_, err = validateStringEntry(xRefTable, d, dictName, "N", REQUIRED, pdf.V10, nil)
if err != nil {
return err
}
// O, optional integer
_, err = validateIntegerEntry(xRefTable, d, dictName, "O", OPTIONAL, pdf.V10, nil)
if err != nil {
return err
}
// V, optional boolean
_, err = validateBooleanEntry(xRefTable, d, dictName, "V", OPTIONAL, pdf.V10, nil)
if err != nil {
return err
}
// E, optional boolean
_, err = validateBooleanEntry(xRefTable, d, dictName, "E", OPTIONAL, pdf.V10, nil)
return err
}
func validateCollectionSchemaDict(xRefTable *pdf.XRefTable, d pdf.Dict) error {
for k, v := range d {
if k == "Type" {
var n pdf.Name
n, err := xRefTable.DereferenceName(v, pdf.V10, nil)
if err != nil {
return err
}
if n != "CollectionSchema" {
return errors.New("pdfcpu: validateCollectionSchemaDict: invalid entry \"Type\"")
}
continue
}
d, err := xRefTable.DereferenceDict(v)
if err != nil {
return err
}
if d == nil {
continue
}
err = validateCollectionFieldDict(xRefTable, d)
if err != nil {
return err
}
}
return nil
}
func validateCollectionSortDict(xRefTable *pdf.XRefTable, d pdf.Dict) error {
dictName := "colSortDict"
// S, required name or array of names.
err := validateNameOrArrayOfNameEntry(xRefTable, d, dictName, "S", REQUIRED, pdf.V10)
if err != nil {
return err
}
// A, optional boolean or array of booleans.
err = validateBooleanOrArrayOfBooleanEntry(xRefTable, d, dictName, "A", OPTIONAL, pdf.V10)
return err
}
func validateInitialView(s string) bool { return s == "D" || s == "T" || s == "H" }
func validateCollection(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
// => 12.3.5 Collections
d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "Collection", required, sinceVersion, nil)
if err != nil || d == nil {
return err
}
dictName := "Collection"
_, err = validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "Collection" })
if err != nil {
return err
}
// Schema, optional dict
d1, err := validateDictEntry(xRefTable, d, dictName, "Schema", OPTIONAL, sinceVersion, nil)
if err != nil {
return err
}
if d1 != nil {
err = validateCollectionSchemaDict(xRefTable, d1)
if err != nil {
return err
}
}
// D, optional string
_, err = validateStringEntry(xRefTable, d, dictName, "D", OPTIONAL, sinceVersion, nil)
if err != nil {
return err
}
// View, optional name
_, err = validateNameEntry(xRefTable, d, dictName, "View", OPTIONAL, sinceVersion, validateInitialView)
if err != nil {
return err
}
// Sort, optional dict
d1, err = validateDictEntry(xRefTable, d, dictName, "Sort", OPTIONAL, sinceVersion, nil)
if err != nil {
return err
}
if d1 != nil {
err = validateCollectionSortDict(xRefTable, d1)
if err != nil {
return err
}
}
return nil
}
func validateNeedsRendering(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error {
_, err := validateBooleanEntry(xRefTable, rootDict, "rootDict", "NeedsRendering", required, sinceVersion, nil)
return err
}
func validateRootObject(xRefTable *pdf.XRefTable) error {
log.Validate.Println("*** validateRootObject begin ***")
// => 7.7.2 Document Catalog
// Entry opt since type info
// ------------------------------------------------------------------------------------
// Type n string "Catalog"
// Version y 1.4 name overrules header version if later
// Extensions y ISO 32000 dict => 7.12 Extensions Dictionary
// Pages n - (dict) => 7.7.3 Page Tree
// PageLabels y 1.3 number tree => 7.9.7 Number Trees, 12.4.2 Page Labels
// Names y 1.2 dict => 7.7.4 Name Dictionary
// Dests y only 1.1 (dict) => 12.3.2.3 Named Destinations
// ViewerPreferences y 1.2 dict => 12.2 Viewer Preferences
// PageLayout y - name /SinglePage, /OneColumn etc.
// PageMode y - name /UseNone, /FullScreen etc.
// Outlines y - (dict) => 12.3.3 Document Outline
// Threads y 1.1 (array) => 12.4.3 Articles
// OpenAction y 1.1 array or dict => 12.3.2 Destinations, 12.6 Actions
// AA y 1.4 dict => 12.6.3 Trigger Events
// URI y 1.1 dict => 12.6.4.7 URI Actions
// AcroForm y 1.2 dict => 12.7.2 Interactive Form Dictionary
// Metadata y 1.4 (stream) => 14.3.2 Metadata Streams
// StructTreeRoot y 1.3 dict => 14.7.2 Structure Hierarchy
// Markinfo y 1.4 dict => 14.7 Logical Structure
// Lang y 1.4 string
// SpiderInfo y 1.3 dict => 14.10.2 Web Capture Information Dictionary
// OutputIntents y 1.4 array => 14.11.5 Output Intents
// PieceInfo y 1.4 dict => 14.5 Page-Piece Dictionaries
// OCProperties y 1.5 dict => 8.11.4 Configuring Optional Content
// Perms y 1.5 dict => 12.8.4 Permissions
// Legal y 1.5 dict => 12.8.5 Legal Content Attestations
// Requirements y 1.7 array => 12.10 Document Requirements
// Collection y 1.7 dict => 12.3.5 Collections
// NeedsRendering y 1.7 boolean => XML Forms Architecture (XFA) Spec.
d, err := xRefTable.Catalog()
if err != nil {
return err
}
// Type
_, err = validateNameEntry(xRefTable, d, "rootDict", "Type", REQUIRED, pdf.V10, func(s string) bool { return s == "Catalog" })
if err != nil {
return err
}
// Pages
rootPageNodeDict, err := validatePages(xRefTable, d)
if err != nil {
return err
}
for _, f := range []struct {
validate func(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) (err error)
required bool
sinceVersion pdf.Version
}{
{validateRootVersion, OPTIONAL, pdf.V14},
{validateExtensions, OPTIONAL, pdf.V10},
{validatePageLabels, OPTIONAL, pdf.V13},
{validateNames, OPTIONAL, pdf.V12},
{validateNamedDestinations, OPTIONAL, pdf.V11},
{validateViewerPreferences, OPTIONAL, pdf.V12},
{validatePageLayout, OPTIONAL, pdf.V10},
{validatePageMode, OPTIONAL, pdf.V10},
{validateOutlines, OPTIONAL, pdf.V10},
{validateThreads, OPTIONAL, pdf.V11},
{validateOpenAction, OPTIONAL, pdf.V11},
{validateRootAdditionalActions, OPTIONAL, pdf.V14},
{validateURI, OPTIONAL, pdf.V11},
{validateAcroForm, OPTIONAL, pdf.V12},
{validateRootMetadata, OPTIONAL, pdf.V14},
{validateStructTree, OPTIONAL, pdf.V13},
{validateMarkInfo, OPTIONAL, pdf.V14},
{validateLang, OPTIONAL, pdf.V10},
{validateSpiderInfo, OPTIONAL, pdf.V13},
{validateOutputIntents, OPTIONAL, pdf.V14},
{validateRootPieceInfo, OPTIONAL, pdf.V14},
{validateOCProperties, OPTIONAL, pdf.V15},
{validatePermissions, OPTIONAL, pdf.V15},
{validateLegal, OPTIONAL, pdf.V17},
{validateRequirements, OPTIONAL, pdf.V17},
{validateCollection, OPTIONAL, pdf.V17},
{validateNeedsRendering, OPTIONAL, pdf.V17},
} {
if !f.required && xRefTable.Version() < f.sinceVersion {
// Ignore optional fields if currentVersion < sinceVersion
// This is really a workaround for explicitly extending relaxed validation.
continue
}
err = f.validate(xRefTable, d, f.required, f.sinceVersion)
if err != nil {
return err
}
}
// Validate remainder of annotations after AcroForm validation only.
err = validatePagesAnnotations(xRefTable, rootPageNodeDict)
if err == nil {
log.Validate.Println("*** validateRootObject end ***")
}
return err
}
func validateAdditionalStreams(xRefTable *pdf.XRefTable) error {
// Out of spec scope.
return nil
}