]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/Catalog.cc
drag and drop, removed redundant verb popup code.
[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, obj2;
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   // read base URI
78   baseURI = NULL;
79   if (catDict->dictLookup("URI", &obj)->isDict()) {
80     if (obj.dictLookup("Base", &obj2)->isString()) {
81       baseURI = obj2.getString()->copy();
82     }
83     obj2.free();
84   }
85   obj.free();
86
87   return;
88
89  err3:
90   obj.free();
91  err2:
92   pagesDict.free();
93  err1:
94   dests.initNull();
95   nameTree.initNull();
96   ok = gFalse;
97 }
98
99 Catalog::~Catalog() {
100   int i;
101
102   if (pages) {
103     for (i = 0; i < numPages; ++i) {
104       if (pages[i])
105         delete pages[i];
106     }
107     gfree(pages);
108     gfree(pageRefs);
109   }
110   dests.free();
111   nameTree.free();
112   if (baseURI) {
113     delete baseURI;
114   }
115 }
116
117 int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) {
118   Object kids;
119   Object kid;
120   Object kidRef;
121   PageAttrs *attrs1, *attrs2;
122   Page *page;
123   int i;
124
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());
130     goto err1;
131   }
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);
137       if (!page->isOk()) {
138         ++start;
139         goto err3;
140       }
141       pages[start] = page;
142       kids.arrayGetNF(i, &kidRef);
143       if (kidRef.isRef()) {
144         pageRefs[start].num = kidRef.getRefNum();
145         pageRefs[start].gen = kidRef.getRefGen();
146       }
147       kidRef.free();
148       ++start;
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)
153         goto err2;
154     } else {
155       error(-1, "Kid object (page %d) is wrong type (%s)",
156             start+1, kid.getTypeName());
157       goto err2;
158     }
159     kid.free();
160   }
161   delete attrs1;
162   kids.free();
163   return start;
164
165  err3:
166   delete page;
167  err2:
168   kid.free();
169  err1:
170   kids.free();
171   delete attrs1;
172   ok = gFalse;
173   return -1;
174 }
175
176 int Catalog::findPage(int num, int gen) {
177   int i;
178
179   for (i = 0; i < numPages; ++i) {
180     if (pageRefs[i].num == num && pageRefs[i].gen == gen)
181       return i + 1;
182   }
183   return 0;
184 }
185
186 LinkDest *Catalog::findDest(GString *name) {
187   LinkDest *dest;
188   Object obj1, obj2;
189   GBool found;
190
191   // try named destination dictionary then name tree
192   found = gFalse;
193   if (dests.isDict()) {
194     if (!dests.dictLookup(name->getCString(), &obj1)->isNull())
195       found = gTrue;
196     else
197       obj1.free();
198   }
199   if (!found && nameTree.isDict()) {
200     if (!findDestInTree(&nameTree, name, &obj1)->isNull())
201       found = gTrue;
202     else
203       obj1.free();
204   }
205   if (!found)
206     return NULL;
207
208   // construct LinkDest
209   dest = NULL;
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);
215     else
216       error(-1, "Bad named destination value");
217     obj2.free();
218   } else {
219     error(-1, "Bad named destination value");
220   }
221   obj1.free();
222
223   return dest;
224 }
225
226 Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) {
227   Object names, name1;
228   Object kids, kid, limits, low, high;
229   GBool done, found;
230   int cmp, i;
231
232   // leaf node
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());
238         if (cmp == 0) {
239           names.arrayGet(i+1, obj);
240           found = gTrue;
241           done = gTrue;
242         } else if (cmp < 0) {
243           done = gTrue;
244         }
245         name1.free();
246       }
247     }
248     names.free();
249     if (!found)
250       obj->initNull();
251     return obj;
252   }
253   names.free();
254
255   // root or intermediate node
256   done = gFalse;
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);
266               done = gTrue;
267             }
268             high.free();
269           }
270           low.free();
271         }
272         limits.free();
273       }
274       kid.free();
275     }
276   }
277   kids.free();
278
279   // name was outside of ranges of all kids
280   if (!done)
281     obj->initNull();
282
283   return obj;
284 }