This repository has been archived by the owner on Aug 7, 2021. It is now read-only.
forked from pdfcpu/pdfcpu
/
validateOutlineTree.go
155 lines (122 loc) · 3.67 KB
/
validateOutlineTree.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package pdfcpu
import (
"github.com/pkg/errors"
)
func validateOutlineItemDict(xRefTable *XRefTable, dict *PDFDict) error {
dictName := "outlineItemDict"
var indRef *PDFIndirectRef
// Title, required, text string
_, err := validateStringEntry(xRefTable, dict, dictName, "Title", REQUIRED, V10, nil)
if err != nil {
return err
}
// Parent, required, dict indRef
indRef, err = validateIndRefEntry(xRefTable, dict, dictName, "Parent", REQUIRED, V10)
if err != nil {
return err
}
_, err = xRefTable.DereferenceDict(*indRef)
if err != nil {
return err
}
// Count, optional, int
_, err = validateIntegerEntry(xRefTable, dict, dictName, "Count", OPTIONAL, V10, nil)
if err != nil {
return err
}
// SE, optional, dict indRef, since V1.3
indRef, err = validateIndRefEntry(xRefTable, dict, dictName, "SE", OPTIONAL, V13)
if err != nil {
return err
}
if indRef != nil {
_, err = xRefTable.DereferenceDict(*indRef)
if err != nil {
return err
}
}
// C, optional, array of 3 numbers, since V1.4
_, err = validateNumberArrayEntry(xRefTable, dict, dictName, "C", OPTIONAL, V14, func(a PDFArray) bool { return len(a) == 3 })
if err != nil {
return err
}
// F, optional integer, since V1.4
_, err = validateIntegerEntry(xRefTable, dict, dictName, "F", OPTIONAL, V14, nil)
if err != nil {
return err
}
// Optional A or Dest, since V1.1
return validateActionOrDestination(xRefTable, dict, dictName, V11)
}
func validateOutlineTree(xRefTable *XRefTable, first, last *PDFIndirectRef) error {
var (
dict *PDFDict
objNumber int
err error
)
// Process linked list of outline items.
for indRef := first; indRef != nil; indRef = dict.IndirectRefEntry("Next") {
objNumber = indRef.ObjectNumber.Value()
// outline item dict
dict, err = xRefTable.DereferenceDict(*indRef)
if err != nil {
return err
}
if dict == nil {
return errors.Errorf("validateOutlineTree: object #%d is nil.", objNumber)
}
err = validateOutlineItemDict(xRefTable, dict)
if err != nil {
return err
}
firstChild := dict.IndirectRefEntry("First")
lastChild := dict.IndirectRefEntry("Last")
if firstChild == nil && lastChild == nil {
// Leaf
continue
}
if firstChild != nil && lastChild != nil {
// Recurse into subtree.
err = validateOutlineTree(xRefTable, firstChild, lastChild)
if err != nil {
return err
}
continue
}
return errors.New("validateOutlineTree: corrupted, needs both first and last or neither for a leaf")
}
// Relaxed validation
if objNumber != last.ObjectNumber.Value() && xRefTable.ValidationMode == ValidationStrict {
return errors.Errorf("validateOutlineTree: corrupted child list %d <> %d\n", objNumber, last.ObjectNumber)
}
return nil
}
func validateOutlines(xRefTable *XRefTable, rootDict *PDFDict, required bool, sinceVersion PDFVersion) error {
// => 12.3.3 Document Outline
indRef, err := validateIndRefEntry(xRefTable, rootDict, "rootDict", "Outlines", OPTIONAL, sinceVersion)
if err != nil || indRef == nil {
return err
}
dict, err := xRefTable.DereferenceDict(*indRef)
if err != nil || dict == nil {
return err
}
// Type, optional, name
_, err = validateNameEntry(xRefTable, dict, "outlineDict", "Type", OPTIONAL, V10, func(s string) bool { return s == "Outlines" })
if err != nil {
return err
}
first := dict.IndirectRefEntry("First")
last := dict.IndirectRefEntry("Last")
if first == nil {
if last != nil {
return errors.New("validateOutlines: corrupted, root needs both first and last")
}
// leaf
return nil
}
if last == nil {
return errors.New("validateOutlines: corrupted, root needs both first and last")
}
return validateOutlineTree(xRefTable, first, last)
}