summaryrefslogtreecommitdiff
path: root/noncore/unsupported/qpdf/xpdf/Catalog.cc
Unidiff
Diffstat (limited to 'noncore/unsupported/qpdf/xpdf/Catalog.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/unsupported/qpdf/xpdf/Catalog.cc341
1 files changed, 341 insertions, 0 deletions
diff --git a/noncore/unsupported/qpdf/xpdf/Catalog.cc b/noncore/unsupported/qpdf/xpdf/Catalog.cc
new file mode 100644
index 0000000..6a0c2d5
--- a/dev/null
+++ b/noncore/unsupported/qpdf/xpdf/Catalog.cc
@@ -0,0 +1,341 @@
1//========================================================================
2//
3// Catalog.cc
4//
5// Copyright 1996 Derek B. Noonburg
6//
7//========================================================================
8
9#ifdef __GNUC__
10#pragma implementation
11#endif
12
13#include <aconf.h>
14#include <stddef.h>
15#include "gmem.h"
16#include "Object.h"
17#include "XRef.h"
18#include "Array.h"
19#include "Dict.h"
20#include "Page.h"
21#include "Error.h"
22#include "Link.h"
23#include "Catalog.h"
24
25//------------------------------------------------------------------------
26// Catalog
27//------------------------------------------------------------------------
28
29Catalog::Catalog(XRef *xrefA, GBool printCommands) {
30 Object catDict, pagesDict;
31 Object obj, obj2;
32 int numPages0;
33 int i;
34
35 ok = gTrue;
36 xref = xrefA;
37 pages = NULL;
38 pageRefs = NULL;
39 numPages = pagesSize = 0;
40 baseURI = NULL;
41
42 xref->getCatalog(&catDict);
43 if (!catDict.isDict()) {
44 error(-1, "Catalog object is wrong type (%s)", catDict.getTypeName());
45 goto err1;
46 }
47
48 // read page tree
49 catDict.dictLookup("Pages", &pagesDict);
50 // This should really be isDict("Pages"), but I've seen at least one
51 // PDF file where the /Type entry is missing.
52 if (!pagesDict.isDict()) {
53 error(-1, "Top-level pages object is wrong type (%s)",
54 pagesDict.getTypeName());
55 goto err2;
56 }
57 pagesDict.dictLookup("Count", &obj);
58 if (!obj.isInt()) {
59 error(-1, "Page count in top-level pages object is wrong type (%s)",
60 obj.getTypeName());
61 goto err3;
62 }
63 pagesSize = numPages0 = obj.getInt();
64 obj.free();
65 pages = (Page **)gmalloc(pagesSize * sizeof(Page *));
66 pageRefs = (Ref *)gmalloc(pagesSize * sizeof(Ref));
67 for (i = 0; i < pagesSize; ++i) {
68 pages[i] = NULL;
69 pageRefs[i].num = -1;
70 pageRefs[i].gen = -1;
71 }
72 numPages = readPageTree(pagesDict.getDict(), NULL, 0, printCommands);
73 if (numPages != numPages0) {
74 error(-1, "Page count in top-level pages object is incorrect");
75 }
76 pagesDict.free();
77
78 // read named destination dictionary
79 catDict.dictLookup("Dests", &dests);
80
81 // read root of named destination tree
82 if (catDict.dictLookup("Names", &obj)->isDict())
83 obj.dictLookup("Dests", &nameTree);
84 else
85 nameTree.initNull();
86 obj.free();
87
88 // read base URI
89 if (catDict.dictLookup("URI", &obj)->isDict()) {
90 if (obj.dictLookup("Base", &obj2)->isString()) {
91 baseURI = obj2.getString()->copy();
92 }
93 obj2.free();
94 }
95 obj.free();
96
97 // get the metadata stream
98 catDict.dictLookup("Metadata", &metadata);
99
100 // get the structure tree root
101 catDict.dictLookup("StructTreeRoot", &structTreeRoot);
102
103 catDict.free();
104 return;
105
106 err3:
107 obj.free();
108 err2:
109 pagesDict.free();
110 err1:
111 catDict.free();
112 dests.initNull();
113 nameTree.initNull();
114 ok = gFalse;
115}
116
117Catalog::~Catalog() {
118 int i;
119
120 if (pages) {
121 for (i = 0; i < pagesSize; ++i) {
122 if (pages[i]) {
123 delete pages[i];
124 }
125 }
126 gfree(pages);
127 gfree(pageRefs);
128 }
129 dests.free();
130 nameTree.free();
131 if (baseURI) {
132 delete baseURI;
133 }
134 metadata.free();
135 structTreeRoot.free();
136}
137
138GString *Catalog::readMetadata() {
139 GString *s;
140 Dict *dict;
141 Object obj;
142 int c;
143
144 if (!metadata.isStream()) {
145 return NULL;
146 }
147 dict = metadata.streamGetDict();
148 if (!dict->lookup("Subtype", &obj)->isName("XML")) {
149 error(-1, "Unknown Metadata type: '%s'\n",
150 obj.isName() ? obj.getName() : "???");
151 }
152 obj.free();
153 s = new GString();
154 metadata.streamReset();
155 while ((c = metadata.streamGetChar()) != EOF) {
156 s->append(c);
157 }
158 metadata.streamClose();
159 return s;
160}
161
162int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start,
163 GBool printCommands) {
164 Object kids;
165 Object kid;
166 Object kidRef;
167 PageAttrs *attrs1, *attrs2;
168 Page *page;
169 int i, j;
170
171 attrs1 = new PageAttrs(attrs, pagesDict);
172 pagesDict->lookup("Kids", &kids);
173 if (!kids.isArray()) {
174 error(-1, "Kids object (page %d) is wrong type (%s)",
175 start+1, kids.getTypeName());
176 goto err1;
177 }
178 for (i = 0; i < kids.arrayGetLength(); ++i) {
179 kids.arrayGet(i, &kid);
180 if (kid.isDict("Page")) {
181 attrs2 = new PageAttrs(attrs1, kid.getDict());
182 page = new Page(xref, start+1, kid.getDict(), attrs2, printCommands);
183 if (!page->isOk()) {
184 ++start;
185 goto err3;
186 }
187 if (start >= pagesSize) {
188 pagesSize += 32;
189 pages = (Page **)grealloc(pages, pagesSize * sizeof(Page *));
190 pageRefs = (Ref *)grealloc(pageRefs, pagesSize * sizeof(Ref));
191 for (j = pagesSize - 32; j < pagesSize; ++j) {
192 pages[j] = NULL;
193 pageRefs[j].num = -1;
194 pageRefs[j].gen = -1;
195 }
196 }
197 pages[start] = page;
198 kids.arrayGetNF(i, &kidRef);
199 if (kidRef.isRef()) {
200 pageRefs[start].num = kidRef.getRefNum();
201 pageRefs[start].gen = kidRef.getRefGen();
202 }
203 kidRef.free();
204 ++start;
205 // This should really be isDict("Pages"), but I've seen at least one
206 // PDF file where the /Type entry is missing.
207 } else if (kid.isDict()) {
208 if ((start = readPageTree(kid.getDict(), attrs1, start, printCommands))
209 < 0)
210 goto err2;
211 } else {
212 error(-1, "Kid object (page %d) is wrong type (%s)",
213 start+1, kid.getTypeName());
214 goto err2;
215 }
216 kid.free();
217 }
218 delete attrs1;
219 kids.free();
220 return start;
221
222 err3:
223 delete page;
224 err2:
225 kid.free();
226 err1:
227 kids.free();
228 delete attrs1;
229 ok = gFalse;
230 return -1;
231}
232
233int Catalog::findPage(int num, int gen) {
234 int i;
235
236 for (i = 0; i < numPages; ++i) {
237 if (pageRefs[i].num == num && pageRefs[i].gen == gen)
238 return i + 1;
239 }
240 return 0;
241}
242
243LinkDest *Catalog::findDest(GString *name) {
244 LinkDest *dest;
245 Object obj1, obj2;
246 GBool found;
247
248 // try named destination dictionary then name tree
249 found = gFalse;
250 if (dests.isDict()) {
251 if (!dests.dictLookup(name->getCString(), &obj1)->isNull())
252 found = gTrue;
253 else
254 obj1.free();
255 }
256 if (!found && nameTree.isDict()) {
257 if (!findDestInTree(&nameTree, name, &obj1)->isNull())
258 found = gTrue;
259 else
260 obj1.free();
261 }
262 if (!found)
263 return NULL;
264
265 // construct LinkDest
266 dest = NULL;
267 if (obj1.isArray()) {
268 dest = new LinkDest(obj1.getArray(), gTrue);
269 } else if (obj1.isDict()) {
270 if (obj1.dictLookup("D", &obj2)->isArray())
271 dest = new LinkDest(obj2.getArray(), gTrue);
272 else
273 error(-1, "Bad named destination value");
274 obj2.free();
275 } else {
276 error(-1, "Bad named destination value");
277 }
278 obj1.free();
279
280 return dest;
281}
282
283Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) {
284 Object names, name1;
285 Object kids, kid, limits, low, high;
286 GBool done, found;
287 int cmp, i;
288
289 // leaf node
290 if (tree->dictLookup("Names", &names)->isArray()) {
291 done = found = gFalse;
292 for (i = 0; !done && i < names.arrayGetLength(); i += 2) {
293 if (names.arrayGet(i, &name1)->isString()) {
294 cmp = name->cmp(name1.getString());
295 if (cmp == 0) {
296 names.arrayGet(i+1, obj);
297 found = gTrue;
298 done = gTrue;
299 } else if (cmp < 0) {
300 done = gTrue;
301 }
302 name1.free();
303 }
304 }
305 names.free();
306 if (!found)
307 obj->initNull();
308 return obj;
309 }
310 names.free();
311
312 // root or intermediate node
313 done = gFalse;
314 if (tree->dictLookup("Kids", &kids)->isArray()) {
315 for (i = 0; !done && i < kids.arrayGetLength(); ++i) {
316 if (kids.arrayGet(i, &kid)->isDict()) {
317 if (kid.dictLookup("Limits", &limits)->isArray()) {
318 if (limits.arrayGet(0, &low)->isString() &&
319 name->cmp(low.getString()) >= 0) {
320 if (limits.arrayGet(1, &high)->isString() &&
321 name->cmp(high.getString()) <= 0) {
322 findDestInTree(&kid, name, obj);
323 done = gTrue;
324 }
325 high.free();
326 }
327 low.free();
328 }
329 limits.free();
330 }
331 kid.free();
332 }
333 }
334 kids.free();
335
336 // name was outside of ranges of all kids
337 if (!done)
338 obj->initNull();
339
340 return obj;
341}