1 //========================================================================
5 // Copyright 1996 Derek B. Noonburg
7 //========================================================================
10 #pragma implementation
23 //------------------------------------------------------------------------
25 //------------------------------------------------------------------------
27 Catalog::Catalog(Object *catDict) {
36 numPages = pagesSize = 0;
38 if (!catDict->isDict()) {
39 error(-1, "Catalog object is wrong type (%s)", catDict->getTypeName());
44 catDict->dictLookup("Pages", &pagesDict);
45 // This should really be isDict("Pages"), but I've seen at least one
46 // PDF file where the /Type entry is missing.
47 if (!pagesDict.isDict()) {
48 error(-1, "Top-level pages object is wrong type (%s)",
49 pagesDict.getTypeName());
52 pagesDict.dictLookup("Count", &obj);
54 error(-1, "Page count in top-level pages object is wrong type (%s)",
58 pagesSize = numPages0 = obj.getInt();
60 pages = (Page **)gmalloc(pagesSize * sizeof(Page *));
61 pageRefs = (Ref *)gmalloc(pagesSize * sizeof(Ref));
62 for (i = 0; i < pagesSize; ++i) {
67 numPages = readPageTree(pagesDict.getDict(), NULL, 0);
68 if (numPages != numPages0) {
69 error(-1, "Page count in top-level pages object is incorrect");
73 // read named destination dictionary
74 catDict->dictLookup("Dests", &dests);
76 // read root of named destination tree
77 if (catDict->dictLookup("Names", &obj)->isDict())
78 obj.dictLookup("Dests", &nameTree);
85 if (catDict->dictLookup("URI", &obj)->isDict()) {
86 if (obj.dictLookup("Base", &obj2)->isString()) {
87 baseURI = obj2.getString()->copy();
105 Catalog::~Catalog() {
109 for (i = 0; i < pagesSize; ++i) {
124 int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) {
128 PageAttrs *attrs1, *attrs2;
132 attrs1 = new PageAttrs(attrs, pagesDict);
133 pagesDict->lookup("Kids", &kids);
134 if (!kids.isArray()) {
135 error(-1, "Kids object (page %d) is wrong type (%s)",
136 start+1, kids.getTypeName());
139 for (i = 0; i < kids.arrayGetLength(); ++i) {
140 kids.arrayGet(i, &kid);
141 if (kid.isDict("Page")) {
142 attrs2 = new PageAttrs(attrs1, kid.getDict());
143 page = new Page(start+1, kid.getDict(), attrs2);
148 if (start >= pagesSize) {
150 pages = (Page **)grealloc(pages, pagesSize * sizeof(Page *));
151 pageRefs = (Ref *)grealloc(pageRefs, pagesSize * sizeof(Ref));
152 for (j = pagesSize - 32; j < pagesSize; ++j) {
154 pageRefs[j].num = -1;
155 pageRefs[j].gen = -1;
159 kids.arrayGetNF(i, &kidRef);
160 if (kidRef.isRef()) {
161 pageRefs[start].num = kidRef.getRefNum();
162 pageRefs[start].gen = kidRef.getRefGen();
166 // This should really be isDict("Pages"), but I've seen at least one
167 // PDF file where the /Type entry is missing.
168 } else if (kid.isDict()) {
169 if ((start = readPageTree(kid.getDict(), attrs1, start)) < 0)
172 error(-1, "Kid object (page %d) is wrong type (%s)",
173 start+1, kid.getTypeName());
193 int Catalog::findPage(int num, int gen) {
196 for (i = 0; i < numPages; ++i) {
197 if (pageRefs[i].num == num && pageRefs[i].gen == gen)
203 LinkDest *Catalog::findDest(GString *name) {
208 // try named destination dictionary then name tree
210 if (dests.isDict()) {
211 if (!dests.dictLookup(name->getCString(), &obj1)->isNull())
216 if (!found && nameTree.isDict()) {
217 if (!findDestInTree(&nameTree, name, &obj1)->isNull())
225 // construct LinkDest
227 if (obj1.isArray()) {
228 dest = new LinkDest(obj1.getArray(), gTrue);
229 } else if (obj1.isDict()) {
230 if (obj1.dictLookup("D", &obj2)->isArray())
231 dest = new LinkDest(obj2.getArray(), gTrue);
233 error(-1, "Bad named destination value");
236 error(-1, "Bad named destination value");
243 Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) {
245 Object kids, kid, limits, low, high;
250 if (tree->dictLookup("Names", &names)->isArray()) {
251 done = found = gFalse;
252 for (i = 0; !done && i < names.arrayGetLength(); i += 2) {
253 if (names.arrayGet(i, &name1)->isString()) {
254 cmp = name->cmp(name1.getString());
256 names.arrayGet(i+1, obj);
259 } else if (cmp < 0) {
272 // root or intermediate node
274 if (tree->dictLookup("Kids", &kids)->isArray()) {
275 for (i = 0; !done && i < kids.arrayGetLength(); ++i) {
276 if (kids.arrayGet(i, &kid)->isDict()) {
277 if (kid.dictLookup("Limits", &limits)->isArray()) {
278 if (limits.arrayGet(0, &low)->isString() &&
279 name->cmp(low.getString()) >= 0) {
280 if (limits.arrayGet(1, &high)->isString() &&
281 name->cmp(high.getString()) <= 0) {
282 findDestInTree(&kid, name, obj);
296 // name was outside of ranges of all kids