]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/Catalog.cc
Lots of cvsignores
[evince.git] / pdf / xpdf / Catalog.cc
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 <stddef.h>
14 #include "gmem.h"
15 #include "Object.h"
16 #include "Array.h"
17 #include "Dict.h"
18 #include "Page.h"
19 #include "Error.h"
20 #include "Link.h"
21 #include "Catalog.h"
22
23 //------------------------------------------------------------------------
24 // Catalog
25 //------------------------------------------------------------------------
26
27 Catalog::Catalog(Object *catDict) {
28   Object pagesDict;
29   Object obj;
30   int i;
31
32   ok = gTrue;
33   pages = NULL;
34   pageRefs = NULL;
35   numPages = 0;
36
37   if (!catDict->isDict("Catalog")) {
38     error(-1, "Catalog object is wrong type (%s)", catDict->getTypeName());
39     goto err1;
40   }
41
42   // read page tree
43   catDict->dictLookup("Pages", &pagesDict);
44   if (!pagesDict.isDict("Pages")) {
45     error(-1, "Top-level pages object is wrong type (%s)",
46           pagesDict.getTypeName());
47     goto err2;
48   }
49   pagesDict.dictLookup("Count", &obj);
50   if (!obj.isInt()) {
51     error(-1, "Page count in top-level pages object is wrong type (%s)",
52           obj.getTypeName());
53     goto err3;
54   }
55   numPages = obj.getInt();
56   obj.free();
57   pages = (Page **)gmalloc(numPages * sizeof(Page *));
58   pageRefs = (Ref *)gmalloc(numPages * sizeof(Ref));
59   for (i = 0; i < numPages; ++i) {
60     pages[i] = NULL;
61     pageRefs[i].num = -1;
62     pageRefs[i].gen = -1;
63   }
64   readPageTree(pagesDict.getDict(), NULL, 0);
65   pagesDict.free();
66
67   // read named destination dictionary
68   catDict->dictLookup("Dests", &dests);
69
70   // read root of named destination tree
71   if (catDict->dictLookup("Names", &obj)->isDict())
72     obj.dictLookup("Dests", &nameTree);
73   else
74     nameTree.initNull();
75   obj.free();
76
77   return;
78
79  err3:
80   obj.free();
81  err2:
82   pagesDict.free();
83  err1:
84   dests.initNull();
85   nameTree.initNull();
86   ok = gFalse;
87 }
88
89 Catalog::~Catalog() {
90   int i;
91
92   if (pages) {
93     for (i = 0; i < numPages; ++i) {
94       if (pages[i])
95         delete pages[i];
96     }
97     gfree(pages);
98     gfree(pageRefs);
99   }
100   dests.free();
101   nameTree.free();
102 }
103
104 int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) {
105   Object kids;
106   Object kid;
107   Object kidRef;
108   PageAttrs *attrs1, *attrs2;
109   Page *page;
110   int i;
111
112   attrs1 = new PageAttrs(attrs, pagesDict);
113   pagesDict->lookup("Kids", &kids);
114   if (!kids.isArray()) {
115     error(-1, "Kids object (page %d) is wrong type (%s)",
116           start+1, kids.getTypeName());
117     goto err1;
118   }
119   for (i = 0; i < kids.arrayGetLength(); ++i) {
120     kids.arrayGet(i, &kid);
121     if (kid.isDict("Page")) {
122       attrs2 = new PageAttrs(attrs1, kid.getDict());
123       page = new Page(start+1, kid.getDict(), attrs2);
124       if (!page->isOk()) {
125         ++start;
126         goto err3;
127       }
128       pages[start] = page;
129       kids.arrayGetNF(i, &kidRef);
130       if (kidRef.isRef()) {
131         pageRefs[start].num = kidRef.getRefNum();
132         pageRefs[start].gen = kidRef.getRefGen();
133       }
134       kidRef.free();
135       ++start;
136     //~ found one PDF file where a Pages object is missing the /Type entry
137     // } else if (kid.isDict("Pages")) {
138     } else if (kid.isDict()) {
139       if ((start = readPageTree(kid.getDict(), attrs1, start)) < 0)
140         goto err2;
141     } else {
142       error(-1, "Kid object (page %d) is wrong type (%s)",
143             start+1, kid.getTypeName());
144       goto err2;
145     }
146     kid.free();
147   }
148   delete attrs1;
149   kids.free();
150   return start;
151
152  err3:
153   delete page;
154  err2:
155   kid.free();
156  err1:
157   kids.free();
158   delete attrs1;
159   ok = gFalse;
160   return -1;
161 }
162
163 int Catalog::findPage(int num, int gen) {
164   int i;
165
166   for (i = 0; i < numPages; ++i) {
167     if (pageRefs[i].num == num && pageRefs[i].gen == gen)
168       return i + 1;
169   }
170   return 0;
171 }
172
173 LinkDest *Catalog::findDest(GString *name) {
174   LinkDest *dest;
175   Object obj1, obj2;
176   GBool found;
177
178   // try named destination dictionary then name tree
179   found = gFalse;
180   if (dests.isDict()) {
181     if (!dests.dictLookup(name->getCString(), &obj1)->isNull())
182       found = gTrue;
183     else
184       obj1.free();
185   }
186   if (!found && nameTree.isDict()) {
187     if (!findDestInTree(&nameTree, name, &obj1)->isNull())
188       found = gTrue;
189     else
190       obj1.free();
191   }
192   if (!found)
193     return NULL;
194
195   // construct LinkDest
196   dest = NULL;
197   if (obj1.isArray()) {
198     dest = new LinkDest(obj1.getArray(), gTrue);
199   } else if (obj1.isDict()) {
200     if (obj1.dictLookup("D", &obj2)->isArray())
201       dest = new LinkDest(obj2.getArray(), gTrue);
202     else
203       error(-1, "Bad named destination value");
204     obj2.free();
205   } else {
206     error(-1, "Bad named destination value");
207   }
208   obj1.free();
209
210   return dest;
211 }
212
213 Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) {
214   Object names, name1;
215   Object kids, kid, limits, low, high;
216   GBool done, found;
217   int cmp, i;
218
219   // leaf node
220   if (tree->dictLookup("Names", &names)->isArray()) {
221     done = found = gFalse;
222     for (i = 0; !done && i < names.arrayGetLength(); i += 2) {
223       if (names.arrayGet(i, &name1)->isString()) {
224         cmp = name->cmp(name1.getString());
225         if (cmp == 0) {
226           names.arrayGet(i+1, obj);
227           found = gTrue;
228           done = gTrue;
229         } else if (cmp < 0) {
230           done = gTrue;
231         }
232         name1.free();
233       }
234     }
235     names.free();
236     if (!found)
237       obj->initNull();
238     return obj;
239   }
240   names.free();
241
242   // root or intermediate node
243   done = gFalse;
244   if (tree->dictLookup("Kids", &kids)->isArray()) {
245     for (i = 0; !done && i < kids.arrayGetLength(); ++i) {
246       if (kids.arrayGet(i, &kid)->isDict()) {
247         if (kid.dictLookup("Limits", &limits)->isArray()) {
248           if (limits.arrayGet(0, &low)->isString() &&
249               name->cmp(low.getString()) >= 0) {
250             if (limits.arrayGet(1, &high)->isString() &&
251                 name->cmp(high.getString()) <= 0) {
252               findDestInTree(&kid, name, obj);
253               done = gTrue;
254             }
255             high.free();
256           }
257           low.free();
258         }
259         limits.free();
260       }
261       kid.free();
262     }
263   }
264   kids.free();
265
266   // name was outside of ranges of all kids
267   if (!done)
268     obj->initNull();
269
270   return obj;
271 }