31#define MAX_CALL_DEPTH 1000
37Catalog::Catalog(XRef *xrefA) {
38 Object catDict, pagesDict;
47 numPages = pagesSize = 0;
50 xref->getCatalog(&catDict);
51 if (!catDict.isDict()) {
52 error(-1,
"Catalog object is wrong type (%s)", catDict.getTypeName());
57 catDict.dictLookup(
"Pages", &pagesDict);
60 if (!pagesDict.isDict()) {
61 error(-1,
"Top-level pages object is wrong type (%s)",
62 pagesDict.getTypeName());
65 pagesDict.dictLookup(
"Count", &obj);
67 error(-1,
"Page count in top-level pages object is wrong type (%s)",
71 pagesSize = numPages0 = obj.getInt();
73 if ((
unsigned) pagesSize >= INT_MAX /
sizeof(Page *) ||
74 (
unsigned) pagesSize >= INT_MAX /
sizeof(Ref)) {
75 error(-1,
"Invalid 'pagesSize'");
79 pages = (Page **)gmalloc(pagesSize *
sizeof(Page *));
80 pageRefs = (Ref *)gmalloc(pagesSize *
sizeof(Ref));
81 for (i = 0; i < pagesSize; ++i) {
86 numPages = readPageTree(pagesDict.getDict(), NULL, 0, 0);
87 if (numPages != numPages0) {
88 error(-1,
"Page count in top-level pages object is incorrect");
93 catDict.dictLookup(
"Dests", &dests);
96 if (catDict.dictLookup(
"Names", &obj)->isDict())
97 obj.dictLookup(
"Dests", &nameTree);
103 if (catDict.dictLookup(
"URI", &obj)->isDict()) {
104 if (obj.dictLookup(
"Base", &obj2)->isString()) {
105 baseURI = obj2.getString()->copy();
112 catDict.dictLookup(
"Metadata", &metadata);
115 catDict.dictLookup(
"StructTreeRoot", &structTreeRoot);
118 catDict.dictLookup(
"Outlines", &outline);
138 for (i = 0; i < pagesSize; ++i) {
152 structTreeRoot.free();
156GString *Catalog::readMetadata() {
162 if (!metadata.isStream()) {
165 dict = metadata.streamGetDict();
166 if (!dict->lookup(
"Subtype", &obj)->isName(
"XML")) {
167 error(-1,
"Unknown Metadata type: '%s'",
168 obj.isName() ? obj.getName() :
"???");
172 metadata.streamReset();
173 while ((c = metadata.streamGetChar()) != EOF) {
176 metadata.streamClose();
180int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs,
int start,
int callDepth) {
184 PageAttrs *attrs1, *attrs2;
188 attrs1 =
new PageAttrs(attrs, pagesDict);
189 pagesDict->lookup(
"Kids", &kids);
190 if (!kids.isArray()) {
191 error(-1,
"Kids object (page %d) is wrong type (%s)",
192 start+1, kids.getTypeName());
195 for (i = 0; i < kids.arrayGetLength(); ++i) {
196 kids.arrayGet(i, &kid);
197 if (kid.isDict(
"Page")) {
198 attrs2 =
new PageAttrs(attrs1, kid.getDict());
199 page =
new Page(xref, start+1, kid.getDict(), attrs2);
204 if (start >= pagesSize) {
206 if ((
unsigned) pagesSize >= INT_MAX /
sizeof(Page *) ||
207 (
unsigned) pagesSize >= INT_MAX /
sizeof(Ref)) {
208 error(-1,
"Invalid 'pagesSize' parameter.");
211 pages = (Page **)grealloc(pages, pagesSize *
sizeof(Page *));
212 pageRefs = (Ref *)grealloc(pageRefs, pagesSize *
sizeof(Ref));
213 for (j = pagesSize - 32; j < pagesSize; ++j) {
215 pageRefs[j].num = -1;
216 pageRefs[j].gen = -1;
220 kids.arrayGetNF(i, &kidRef);
221 if (kidRef.isRef()) {
222 pageRefs[start].num = kidRef.getRefNum();
223 pageRefs[start].gen = kidRef.getRefGen();
229 }
else if (kid.isDict()) {
230 if (callDepth > MAX_CALL_DEPTH) {
231 error(-1,
"Limit of %d recursive calls reached while reading the page tree. If your document is correct and not a test to try to force a crash, please report a bug.", MAX_CALL_DEPTH);
233 if ((start = readPageTree(kid.getDict(), attrs1, start, callDepth + 1))
238 error(-1,
"Kid object (page %d) is wrong type (%s)",
239 start+1, kid.getTypeName());
259int Catalog::findPage(
int num,
int gen) {
262 for (i = 0; i < numPages; ++i) {
263 if (pageRefs[i].num == num && pageRefs[i].gen == gen)
269LinkDest *Catalog::findDest(GString *name) {
276 if (dests.isDict()) {
277 if (!dests.dictLookup(name->getCString(), &obj1)->isNull())
282 if (!found && nameTree.isDict()) {
283 if (!findDestInTree(&nameTree, name, &obj1)->isNull())
293 if (obj1.isArray()) {
294 dest =
new LinkDest(obj1.getArray());
295 }
else if (obj1.isDict()) {
296 if (obj1.dictLookup(
"D", &obj2)->isArray())
297 dest =
new LinkDest(obj2.getArray());
299 error(-1,
"Bad named destination value");
302 error(-1,
"Bad named destination value");
305 if (dest && !dest->isOk()) {
313Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) {
315 Object kids, kid, limits, low, high;
320 if (tree->dictLookup(
"Names", &names)->isArray()) {
321 done = found = gFalse;
322 for (i = 0; !done && i < names.arrayGetLength(); i += 2) {
323 if (names.arrayGet(i, &name1)->isString()) {
324 cmp = name->cmp(name1.getString());
326 names.arrayGet(i+1, obj);
329 }
else if (cmp < 0) {
344 if (tree->dictLookup(
"Kids", &kids)->isArray()) {
345 for (i = 0; !done && i < kids.arrayGetLength(); ++i) {
346 if (kids.arrayGet(i, &kid)->isDict()) {
347 if (kid.dictLookup(
"Limits", &limits)->isArray()) {
348 if (limits.arrayGet(0, &low)->isString() &&
349 name->cmp(low.getString()) >= 0) {
350 if (limits.arrayGet(1, &high)->isString() &&
351 name->cmp(high.getString()) <= 0) {
352 findDestInTree(&kid, name, obj);