~ubuntu-branches/ubuntu/raring/luatex/raring

« back to all changes in this revision

Viewing changes to source/libs/xpdf/xpdf-3.02/xpdf/Catalog.cc

  • Committer: Package Import Robot
  • Author(s): Norbert Preining
  • Date: 2011-05-20 09:40:39 UTC
  • mfrom: (0.8.1) (1.8.1) (19.2.3 oneiric)
  • Revision ID: package-import@ubuntu.com-20110520094039-7sezr4kqonjqxqz6
Tags: 0.70.1-1
* new upstream release (probably) matching TeX Live 2011
* deactivate fix-luatex-build-with-old-libpng patch, included upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//========================================================================
2
 
//
3
 
// Catalog.cc
4
 
//
5
 
// Copyright 1996-2007 Glyph & Cog, LLC
6
 
//
7
 
//========================================================================
8
 
 
9
 
#include <aconf.h>
10
 
 
11
 
#ifdef USE_GCC_PRAGMAS
12
 
#pragma implementation
13
 
#endif
14
 
 
15
 
#include <stddef.h>
16
 
#include "gmem.h"
17
 
#include "Object.h"
18
 
#include "XRef.h"
19
 
#include "Array.h"
20
 
#include "Dict.h"
21
 
#include "Page.h"
22
 
#include "Error.h"
23
 
#include "Link.h"
24
 
#include "Catalog.h"
25
 
 
26
 
//------------------------------------------------------------------------
27
 
// Catalog
28
 
//------------------------------------------------------------------------
29
 
 
30
 
Catalog::Catalog(XRef *xrefA) {
31
 
  Object catDict, pagesDict, pagesDictRef;
32
 
  Object obj, obj2;
33
 
  char *alreadyRead;
34
 
  int numPages0;
35
 
  int i;
36
 
 
37
 
  ok = gTrue;
38
 
  xref = xrefA;
39
 
  pages = NULL;
40
 
  pageRefs = NULL;
41
 
  numPages = pagesSize = 0;
42
 
  baseURI = NULL;
43
 
 
44
 
  xref->getCatalog(&catDict);
45
 
  if (!catDict.isDict()) {
46
 
    error(-1, "Catalog object is wrong type (%s)", catDict.getTypeName());
47
 
    goto err1;
48
 
  }
49
 
 
50
 
  // read page tree
51
 
  catDict.dictLookup("Pages", &pagesDict);
52
 
  // This should really be isDict("Pages"), but I've seen at least one
53
 
  // PDF file where the /Type entry is missing.
54
 
  if (!pagesDict.isDict()) {
55
 
    error(-1, "Top-level pages object is wrong type (%s)",
56
 
          pagesDict.getTypeName());
57
 
    goto err2;
58
 
  }
59
 
  pagesDict.dictLookup("Count", &obj);
60
 
  // some PDF files actually use real numbers here ("/Count 9.0")
61
 
  if (!obj.isNum()) {
62
 
    error(-1, "Page count in top-level pages object is wrong type (%s)",
63
 
          obj.getTypeName());
64
 
    goto err3;
65
 
  }
66
 
  pagesSize = numPages0 = (int)obj.getNum();
67
 
  obj.free();
68
 
  pages = (Page **)gmallocn(pagesSize, sizeof(Page *));
69
 
  pageRefs = (Ref *)gmallocn(pagesSize, sizeof(Ref));
70
 
  for (i = 0; i < pagesSize; ++i) {
71
 
    pages[i] = NULL;
72
 
    pageRefs[i].num = -1;
73
 
    pageRefs[i].gen = -1;
74
 
  }
75
 
  alreadyRead = (char *)gmalloc(xref->getNumObjects());
76
 
  memset(alreadyRead, 0, xref->getNumObjects());
77
 
  if (catDict.dictLookupNF("Pages", &pagesDictRef)->isRef() &&
78
 
      pagesDictRef.getRefNum() >= 0 &&
79
 
      pagesDictRef.getRefNum() < xref->getNumObjects()) {
80
 
    alreadyRead[pagesDictRef.getRefNum()] = 1;
81
 
  }
82
 
  pagesDictRef.free();
83
 
  numPages = readPageTree(pagesDict.getDict(), NULL, 0, alreadyRead);
84
 
  gfree(alreadyRead);
85
 
  if (numPages != numPages0) {
86
 
    error(-1, "Page count in top-level pages object is incorrect");
87
 
  }
88
 
  pagesDict.free();
89
 
 
90
 
  // read named destination dictionary
91
 
  catDict.dictLookup("Dests", &dests);
92
 
 
93
 
  // read root of named destination tree
94
 
  if (catDict.dictLookup("Names", &obj)->isDict())
95
 
    obj.dictLookup("Dests", &nameTree);
96
 
  else
97
 
    nameTree.initNull();
98
 
  obj.free();
99
 
 
100
 
  // read base URI
101
 
  if (catDict.dictLookup("URI", &obj)->isDict()) {
102
 
    if (obj.dictLookup("Base", &obj2)->isString()) {
103
 
      baseURI = obj2.getString()->copy();
104
 
    }
105
 
    obj2.free();
106
 
  }
107
 
  obj.free();
108
 
 
109
 
  // get the metadata stream
110
 
  catDict.dictLookup("Metadata", &metadata);
111
 
 
112
 
  // get the structure tree root
113
 
  catDict.dictLookup("StructTreeRoot", &structTreeRoot);
114
 
 
115
 
  // get the outline dictionary
116
 
  catDict.dictLookup("Outlines", &outline);
117
 
 
118
 
  // get the AcroForm dictionary
119
 
  catDict.dictLookup("AcroForm", &acroForm);
120
 
 
121
 
  catDict.free();
122
 
  return;
123
 
 
124
 
 err3:
125
 
  obj.free();
126
 
 err2:
127
 
  pagesDict.free();
128
 
 err1:
129
 
  catDict.free();
130
 
  dests.initNull();
131
 
  nameTree.initNull();
132
 
  ok = gFalse;
133
 
}
134
 
 
135
 
Catalog::~Catalog() {
136
 
  int i;
137
 
 
138
 
  if (pages) {
139
 
    for (i = 0; i < pagesSize; ++i) {
140
 
      if (pages[i]) {
141
 
        delete pages[i];
142
 
      }
143
 
    }
144
 
    gfree(pages);
145
 
    gfree(pageRefs);
146
 
  }
147
 
  dests.free();
148
 
  nameTree.free();
149
 
  if (baseURI) {
150
 
    delete baseURI;
151
 
  }
152
 
  metadata.free();
153
 
  structTreeRoot.free();
154
 
  outline.free();
155
 
  acroForm.free();
156
 
}
157
 
 
158
 
GString *Catalog::readMetadata() {
159
 
  GString *s;
160
 
  Dict *dict;
161
 
  Object obj;
162
 
  int c;
163
 
 
164
 
  if (!metadata.isStream()) {
165
 
    return NULL;
166
 
  }
167
 
  dict = metadata.streamGetDict();
168
 
  if (!dict->lookup("Subtype", &obj)->isName("XML")) {
169
 
    error(-1, "Unknown Metadata type: '%s'",
170
 
          obj.isName() ? obj.getName() : "???");
171
 
  }
172
 
  obj.free();
173
 
  s = new GString();
174
 
  metadata.streamReset();
175
 
  while ((c = metadata.streamGetChar()) != EOF) {
176
 
    s->append(c);
177
 
  }
178
 
  metadata.streamClose();
179
 
  return s;
180
 
}
181
 
 
182
 
int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start,
183
 
                          char *alreadyRead) {
184
 
  Object kids;
185
 
  Object kid;
186
 
  Object kidRef;
187
 
  PageAttrs *attrs1, *attrs2;
188
 
  Page *page;
189
 
  int i, j;
190
 
 
191
 
  attrs1 = new PageAttrs(attrs, pagesDict);
192
 
  pagesDict->lookup("Kids", &kids);
193
 
  if (!kids.isArray()) {
194
 
    error(-1, "Kids object (page %d) is wrong type (%s)",
195
 
          start+1, kids.getTypeName());
196
 
    goto err1;
197
 
  }
198
 
  for (i = 0; i < kids.arrayGetLength(); ++i) {
199
 
    kids.arrayGetNF(i, &kidRef);
200
 
    if (kidRef.isRef() &&
201
 
        kidRef.getRefNum() >= 0 &&
202
 
        kidRef.getRefNum() < xref->getNumObjects()) {
203
 
      if (alreadyRead[kidRef.getRefNum()]) {
204
 
        error(-1, "Loop in Pages tree");
205
 
        kidRef.free();
206
 
        continue;
207
 
      }
208
 
      alreadyRead[kidRef.getRefNum()] = 1;
209
 
    }
210
 
    kids.arrayGet(i, &kid);
211
 
    if (kid.isDict("Page")) {
212
 
      attrs2 = new PageAttrs(attrs1, kid.getDict());
213
 
      page = new Page(xref, start+1, kid.getDict(), attrs2);
214
 
      if (!page->isOk()) {
215
 
        ++start;
216
 
        goto err3;
217
 
      }
218
 
      if (start >= pagesSize) {
219
 
        pagesSize += 32;
220
 
        pages = (Page **)greallocn(pages, pagesSize, sizeof(Page *));
221
 
        pageRefs = (Ref *)greallocn(pageRefs, pagesSize, sizeof(Ref));
222
 
        for (j = pagesSize - 32; j < pagesSize; ++j) {
223
 
          pages[j] = NULL;
224
 
          pageRefs[j].num = -1;
225
 
          pageRefs[j].gen = -1;
226
 
        }
227
 
      }
228
 
      pages[start] = page;
229
 
      if (kidRef.isRef()) {
230
 
        pageRefs[start].num = kidRef.getRefNum();
231
 
        pageRefs[start].gen = kidRef.getRefGen();
232
 
      }
233
 
      ++start;
234
 
    // This should really be isDict("Pages"), but I've seen at least one
235
 
    // PDF file where the /Type entry is missing.
236
 
    } else if (kid.isDict()) {
237
 
      if ((start = readPageTree(kid.getDict(), attrs1, start, alreadyRead))
238
 
          < 0)
239
 
        goto err2;
240
 
    } else {
241
 
      error(-1, "Kid object (page %d) is wrong type (%s)",
242
 
            start+1, kid.getTypeName());
243
 
    }
244
 
    kid.free();
245
 
    kidRef.free();
246
 
  }
247
 
  delete attrs1;
248
 
  kids.free();
249
 
  return start;
250
 
 
251
 
 err3:
252
 
  delete page;
253
 
 err2:
254
 
  kid.free();
255
 
 err1:
256
 
  kids.free();
257
 
  delete attrs1;
258
 
  ok = gFalse;
259
 
  return -1;
260
 
}
261
 
 
262
 
int Catalog::findPage(int num, int gen) {
263
 
  int i;
264
 
 
265
 
  for (i = 0; i < numPages; ++i) {
266
 
    if (pageRefs[i].num == num && pageRefs[i].gen == gen)
267
 
      return i + 1;
268
 
  }
269
 
  return 0;
270
 
}
271
 
 
272
 
LinkDest *Catalog::findDest(GString *name) {
273
 
  LinkDest *dest;
274
 
  Object obj1, obj2;
275
 
  GBool found;
276
 
 
277
 
  // try named destination dictionary then name tree
278
 
  found = gFalse;
279
 
  if (dests.isDict()) {
280
 
    if (!dests.dictLookup(name->getCString(), &obj1)->isNull())
281
 
      found = gTrue;
282
 
    else
283
 
      obj1.free();
284
 
  }
285
 
  if (!found && nameTree.isDict()) {
286
 
    if (!findDestInTree(&nameTree, name, &obj1)->isNull())
287
 
      found = gTrue;
288
 
    else
289
 
      obj1.free();
290
 
  }
291
 
  if (!found)
292
 
    return NULL;
293
 
 
294
 
  // construct LinkDest
295
 
  dest = NULL;
296
 
  if (obj1.isArray()) {
297
 
    dest = new LinkDest(obj1.getArray());
298
 
  } else if (obj1.isDict()) {
299
 
    if (obj1.dictLookup("D", &obj2)->isArray())
300
 
      dest = new LinkDest(obj2.getArray());
301
 
    else
302
 
      error(-1, "Bad named destination value");
303
 
    obj2.free();
304
 
  } else {
305
 
    error(-1, "Bad named destination value");
306
 
  }
307
 
  obj1.free();
308
 
  if (dest && !dest->isOk()) {
309
 
    delete dest;
310
 
    dest = NULL;
311
 
  }
312
 
 
313
 
  return dest;
314
 
}
315
 
 
316
 
Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) {
317
 
  Object names, name1;
318
 
  Object kids, kid, limits, low, high;
319
 
  GBool done, found;
320
 
  int cmp, i;
321
 
 
322
 
  // leaf node
323
 
  if (tree->dictLookup("Names", &names)->isArray()) {
324
 
    done = found = gFalse;
325
 
    for (i = 0; !done && i < names.arrayGetLength(); i += 2) {
326
 
      if (names.arrayGet(i, &name1)->isString()) {
327
 
        cmp = name->cmp(name1.getString());
328
 
        if (cmp == 0) {
329
 
          names.arrayGet(i+1, obj);
330
 
          found = gTrue;
331
 
          done = gTrue;
332
 
        } else if (cmp < 0) {
333
 
          done = gTrue;
334
 
        }
335
 
      }
336
 
      name1.free();
337
 
    }
338
 
    names.free();
339
 
    if (!found)
340
 
      obj->initNull();
341
 
    return obj;
342
 
  }
343
 
  names.free();
344
 
 
345
 
  // root or intermediate node
346
 
  done = gFalse;
347
 
  if (tree->dictLookup("Kids", &kids)->isArray()) {
348
 
    for (i = 0; !done && i < kids.arrayGetLength(); ++i) {
349
 
      if (kids.arrayGet(i, &kid)->isDict()) {
350
 
        if (kid.dictLookup("Limits", &limits)->isArray()) {
351
 
          if (limits.arrayGet(0, &low)->isString() &&
352
 
              name->cmp(low.getString()) >= 0) {
353
 
            if (limits.arrayGet(1, &high)->isString() &&
354
 
                name->cmp(high.getString()) <= 0) {
355
 
              findDestInTree(&kid, name, obj);
356
 
              done = gTrue;
357
 
            }
358
 
            high.free();
359
 
          }
360
 
          low.free();
361
 
        }
362
 
        limits.free();
363
 
      }
364
 
      kid.free();
365
 
    }
366
 
  }
367
 
  kids.free();
368
 
 
369
 
  // name was outside of ranges of all kids
370
 
  if (!done)
371
 
    obj->initNull();
372
 
 
373
 
  return obj;
374
 
}