1 //========================================================================
5 // Copyright 1996 Derek B. Noonburg
7 //========================================================================
10 #pragma implementation
23 //------------------------------------------------------------------------
25 //------------------------------------------------------------------------
27 Catalog::Catalog(Object *catDict) {
37 if (!catDict->isDict("Catalog")) {
38 error(-1, "Catalog object is wrong type (%s)", catDict->getTypeName());
43 catDict->dictLookup("Pages", &pagesDict);
44 if (!pagesDict.isDict("Pages")) {
45 error(-1, "Top-level pages object is wrong type (%s)",
46 pagesDict.getTypeName());
49 pagesDict.dictLookup("Count", &obj);
51 error(-1, "Page count in top-level pages object is wrong type (%s)",
55 numPages = obj.getInt();
57 pages = (Page **)gmalloc(numPages * sizeof(Page *));
58 pageRefs = (Ref *)gmalloc(numPages * sizeof(Ref));
59 for (i = 0; i < numPages; ++i) {
64 readPageTree(pagesDict.getDict(), NULL, 0);
67 // read named destination dictionary
68 catDict->dictLookup("Dests", &dests);
70 // read root of named destination tree
71 if (catDict->dictLookup("Names", &obj)->isDict())
72 obj.dictLookup("Dests", &nameTree);
79 if (catDict->dictLookup("URI", &obj)->isDict()) {
80 if (obj.dictLookup("Base", &obj2)->isString()) {
81 baseURI = obj2.getString()->copy();
103 for (i = 0; i < numPages; ++i) {
117 int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) {
121 PageAttrs *attrs1, *attrs2;
125 attrs1 = new PageAttrs(attrs, pagesDict);
126 pagesDict->lookup("Kids", &kids);
127 if (!kids.isArray()) {
128 error(-1, "Kids object (page %d) is wrong type (%s)",
129 start+1, kids.getTypeName());
132 for (i = 0; i < kids.arrayGetLength(); ++i) {
133 kids.arrayGet(i, &kid);
134 if (kid.isDict("Page")) {
135 attrs2 = new PageAttrs(attrs1, kid.getDict());
136 page = new Page(start+1, kid.getDict(), attrs2);
142 kids.arrayGetNF(i, &kidRef);
143 if (kidRef.isRef()) {
144 pageRefs[start].num = kidRef.getRefNum();
145 pageRefs[start].gen = kidRef.getRefGen();
149 //~ found one PDF file where a Pages object is missing the /Type entry
150 // } else if (kid.isDict("Pages")) {
151 } else if (kid.isDict()) {
152 if ((start = readPageTree(kid.getDict(), attrs1, start)) < 0)
155 error(-1, "Kid object (page %d) is wrong type (%s)",
156 start+1, kid.getTypeName());
176 int Catalog::findPage(int num, int gen) {
179 for (i = 0; i < numPages; ++i) {
180 if (pageRefs[i].num == num && pageRefs[i].gen == gen)
186 LinkDest *Catalog::findDest(GString *name) {
191 // try named destination dictionary then name tree
193 if (dests.isDict()) {
194 if (!dests.dictLookup(name->getCString(), &obj1)->isNull())
199 if (!found && nameTree.isDict()) {
200 if (!findDestInTree(&nameTree, name, &obj1)->isNull())
208 // construct LinkDest
210 if (obj1.isArray()) {
211 dest = new LinkDest(obj1.getArray(), gTrue);
212 } else if (obj1.isDict()) {
213 if (obj1.dictLookup("D", &obj2)->isArray())
214 dest = new LinkDest(obj2.getArray(), gTrue);
216 error(-1, "Bad named destination value");
219 error(-1, "Bad named destination value");
226 Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) {
228 Object kids, kid, limits, low, high;
233 if (tree->dictLookup("Names", &names)->isArray()) {
234 done = found = gFalse;
235 for (i = 0; !done && i < names.arrayGetLength(); i += 2) {
236 if (names.arrayGet(i, &name1)->isString()) {
237 cmp = name->cmp(name1.getString());
239 names.arrayGet(i+1, obj);
242 } else if (cmp < 0) {
255 // root or intermediate node
257 if (tree->dictLookup("Kids", &kids)->isArray()) {
258 for (i = 0; !done && i < kids.arrayGetLength(); ++i) {
259 if (kids.arrayGet(i, &kid)->isDict()) {
260 if (kid.dictLookup("Limits", &limits)->isArray()) {
261 if (limits.arrayGet(0, &low)->isString() &&
262 name->cmp(low.getString()) >= 0) {
263 if (limits.arrayGet(1, &high)->isString() &&
264 name->cmp(high.getString()) <= 0) {
265 findDestInTree(&kid, name, obj);
279 // name was outside of ranges of all kids