source: trunk/poppler/mypoppler/poppler/XRef.cc @ 2

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 15 years ago

First import

File size: 21.4 KB
Line 
1 //========================================================================
2//
3// XRef.cc
4//
5// Copyright 1996-2003 Glyph & Cog, LLC
6//
7//========================================================================
8
9#include <config.h>
10
11#ifdef USE_GCC_PRAGMAS
12#pragma implementation
13#endif
14
15#include <stdlib.h>
16#include <stddef.h>
17#include <string.h>
18#include <ctype.h>
19#include "goo/gmem.h"
20#include "Object.h"
21#include "Stream.h"
22#include "Lexer.h"
23#include "Parser.h"
24#include "Dict.h"
25#include "Error.h"
26#include "ErrorCodes.h"
27#include "UGooString.h"
28#include "XRef.h"
29
30//------------------------------------------------------------------------
31
32#define xrefSearchSize 1024     // read this many bytes at end of file
33                                //   to look for 'startxref'
34
35//------------------------------------------------------------------------
36// Permission bits
37// Note that the PDF spec uses 1 base (eg bit 3 is 1<<2)
38//------------------------------------------------------------------------
39
40#define permPrint         (1<<2)  // bit 3
41#define permChange        (1<<3)  // bit 4
42#define permCopy          (1<<4)  // bit 5
43#define permNotes         (1<<5)  // bit 6
44#define permFillForm      (1<<8)  // bit 9
45#define permAccessibility (1<<9)  // bit 10
46#define permAssemble      (1<<10) // bit 11
47#define permHighResPrint  (1<<11) // bit 12
48#define defPermFlags 0xfffc
49
50//------------------------------------------------------------------------
51// ObjectStream
52//------------------------------------------------------------------------
53
54class ObjectStream {
55public:
56
57  // Create an object stream, using object number <objStrNum>,
58  // generation 0.
59  ObjectStream(XRef *xref, int objStrNumA);
60
61  ~ObjectStream();
62
63  // Return the object number of this object stream.
64  int getObjStrNum() { return objStrNum; }
65
66  // Get the <objIdx>th object from this stream, which should be
67  // object number <objNum>, generation 0.
68  Object *getObject(int objIdx, int objNum, Object *obj);
69
70private:
71
72  int objStrNum;                // object number of the object stream
73  int nObjects;                 // number of objects in the stream
74  Object *objs;                 // the objects (length = nObjects)
75  int *objNums;                 // the object numbers (length = nObjects)
76};
77
78ObjectStream::ObjectStream(XRef *xref, int objStrNumA) {
79  Stream *str;
80  Parser *parser;
81  int *offsets;
82  Object objStr, obj1, obj2;
83  int first, i;
84
85  objStrNum = objStrNumA;
86  nObjects = 0;
87  objs = NULL;
88  objNums = NULL;
89
90  if (!xref->fetch(objStrNum, 0, &objStr)->isStream()) {
91    goto err1;
92  }
93
94  if (!objStr.streamGetDict()->lookup("N", &obj1)->isInt()) {
95    obj1.free();
96    goto err1;
97  }
98  nObjects = obj1.getInt();
99  obj1.free();
100  if (nObjects <= 0) {
101    goto err1;
102  }
103
104  if (!objStr.streamGetDict()->lookup("First", &obj1)->isInt()) {
105    obj1.free();
106    goto err1;
107  }
108  first = obj1.getInt();
109  obj1.free();
110  if (first < 0) {
111    goto err1;
112  }
113
114  if (nObjects*(int)sizeof(int)/sizeof(int) != nObjects) {
115    error(-1, "Invalid 'nObjects'");
116    goto err1;
117  }
118 
119  objs = new Object[nObjects];
120  objNums = (int *)gmallocn(nObjects, sizeof(int));
121  offsets = (int *)gmallocn(nObjects, sizeof(int));
122
123  // parse the header: object numbers and offsets
124  objStr.streamReset();
125  obj1.initNull();
126  str = new EmbedStream(objStr.getStream(), &obj1, gTrue, first);
127  parser = new Parser(xref, new Lexer(xref, str));
128  for (i = 0; i < nObjects; ++i) {
129    parser->getObj(&obj1);
130    parser->getObj(&obj2);
131    if (!obj1.isInt() || !obj2.isInt()) {
132      obj1.free();
133      obj2.free();
134      delete parser;
135      gfree(offsets);
136      goto err1;
137    }
138    objNums[i] = obj1.getInt();
139    offsets[i] = obj2.getInt();
140    obj1.free();
141    obj2.free();
142    if (objNums[i] < 0 || offsets[i] < 0 ||
143        (i > 0 && offsets[i] < offsets[i-1])) {
144      delete parser;
145      gfree(offsets);
146      goto err1;
147    }
148  }
149  while (str->getChar() != EOF) ;
150  delete parser;
151
152  // skip to the first object - this shouldn't be necessary because
153  // the First key is supposed to be equal to offsets[0], but just in
154  // case...
155  for (i = first; i < offsets[0]; ++i) {
156    objStr.getStream()->getChar();
157  }
158
159  // parse the objects
160  for (i = 0; i < nObjects; ++i) {
161    obj1.initNull();
162    if (i == nObjects - 1) {
163      str = new EmbedStream(objStr.getStream(), &obj1, gFalse, 0);
164    } else {
165      str = new EmbedStream(objStr.getStream(), &obj1, gTrue,
166                            offsets[i+1] - offsets[i]);
167    }
168    parser = new Parser(xref, new Lexer(xref, str));
169    parser->getObj(&objs[i]);
170    while (str->getChar() != EOF) ;
171    delete parser;
172  }
173
174  gfree(offsets);
175
176 err1:
177  objStr.free();
178  return;
179}
180
181ObjectStream::~ObjectStream() {
182  int i;
183
184  if (objs) {
185    for (i = 0; i < nObjects; ++i) {
186      objs[i].free();
187    }
188    delete[] objs;
189  }
190  gfree(objNums);
191}
192
193Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) {
194  if (objIdx < 0 || objIdx >= nObjects || objNum != objNums[objIdx]) {
195    return obj->initNull();
196  }
197  return objs[objIdx].copy(obj);
198}
199
200//------------------------------------------------------------------------
201// XRef
202//------------------------------------------------------------------------
203
204XRef::XRef(BaseStream *strA) {
205  Guint pos;
206  Object obj;
207
208  ok = gTrue;
209  errCode = errNone;
210  size = 0;
211  entries = NULL;
212  streamEnds = NULL;
213  streamEndsLen = 0;
214  objStr = NULL;
215
216  encrypted = gFalse;
217  permFlags = defPermFlags;
218  ownerPasswordOk = gFalse;
219
220  // read the trailer
221  str = strA;
222  start = str->getStart();
223  pos = getStartXref();
224
225  // if there was a problem with the 'startxref' position, try to
226  // reconstruct the xref table
227  if (pos == 0) {
228    if (!(ok = constructXRef())) {
229      errCode = errDamaged;
230      return;
231    }
232
233  // read the xref table
234  } else {
235    while (readXRef(&pos)) ;
236
237    // if there was a problem with the xref table,
238    // try to reconstruct it
239    if (!ok) {
240      if (!(ok = constructXRef())) {
241        errCode = errDamaged;
242        return;
243      }
244    }
245  }
246
247  // get the root dictionary (catalog) object
248  trailerDict.dictLookupNF("Root", &obj);
249  if (obj.isRef()) {
250    rootNum = obj.getRefNum();
251    rootGen = obj.getRefGen();
252    obj.free();
253  } else {
254    obj.free();
255    if (!(ok = constructXRef())) {
256      errCode = errDamaged;
257      return;
258    }
259  }
260
261  // now set the trailer dictionary's xref pointer so we can fetch
262  // indirect objects from it
263  trailerDict.getDict()->setXRef(this);
264}
265
266XRef::~XRef() {
267  gfree(entries);
268  trailerDict.free();
269  if (streamEnds) {
270    gfree(streamEnds);
271  }
272  if (objStr) {
273    delete objStr;
274  }
275}
276
277// Read the 'startxref' position.
278Guint XRef::getStartXref() {
279  char buf[xrefSearchSize+1];
280  char *p;
281  int c, n, i;
282
283  // read last xrefSearchSize bytes
284  str->setPos(xrefSearchSize, -1);
285  for (n = 0; n < xrefSearchSize; ++n) {
286    if ((c = str->getChar()) == EOF) {
287      break;
288    }
289    buf[n] = c;
290  }
291  buf[n] = '\0';
292
293  // find startxref
294  for (i = n - 9; i >= 0; --i) {
295    if (!strncmp(&buf[i], "startxref", 9)) {
296      break;
297    }
298  }
299  if (i < 0) {
300    return 0;
301  }
302  for (p = &buf[i+9]; isspace(*p); ++p) ;
303  lastXRefPos = strToUnsigned(p);
304
305  return lastXRefPos;
306}
307
308// Read one xref table section.  Also reads the associated trailer
309// dictionary, and returns the prev pointer (if any).
310GBool XRef::readXRef(Guint *pos) {
311  Parser *parser;
312  Object obj;
313  GBool more;
314
315  // start up a parser, parse one token
316  obj.initNull();
317  parser = new Parser(NULL,
318             new Lexer(NULL,
319               str->makeSubStream(start + *pos, gFalse, 0, &obj)));
320  parser->getObj(&obj);
321
322  // parse an old-style xref table
323  if (obj.isCmd("xref")) {
324    obj.free();
325    more = readXRefTable(parser, pos);
326
327  // parse an xref stream
328  } else if (obj.isInt()) {
329    obj.free();
330    if (!parser->getObj(&obj)->isInt()) {
331      goto err1;
332    }
333    obj.free();
334    if (!parser->getObj(&obj)->isCmd("obj")) {
335      goto err1;
336    }
337    obj.free();
338    if (!parser->getObj(&obj)->isStream()) {
339      goto err1;
340    }
341    more = readXRefStream(obj.getStream(), pos);
342    obj.free();
343
344  } else {
345    goto err1;
346  }
347
348  delete parser;
349  return more;
350
351 err1:
352  obj.free();
353  delete parser;
354  ok = gFalse;
355  return gFalse;
356}
357
358GBool XRef::readXRefTable(Parser *parser, Guint *pos) {
359  XRefEntry entry;
360  GBool more;
361  Object obj, obj2;
362  Guint pos2;
363  int first, n, newSize, i;
364
365  while (1) {
366    parser->getObj(&obj);
367    if (obj.isCmd("trailer")) {
368      obj.free();
369      break;
370    }
371    if (!obj.isInt()) {
372      goto err1;
373    }
374    first = obj.getInt();
375    obj.free();
376    if (!parser->getObj(&obj)->isInt()) {
377      goto err1;
378    }
379    n = obj.getInt();
380    obj.free();
381    if (first < 0 || n < 0 || first + n < 0) {
382      goto err1;
383    }
384    if (first + n > size) {
385      for (newSize = size ? 2 * size : 1024;
386           first + n > newSize && newSize > 0;
387           newSize <<= 1) ;
388      if (newSize < 0) {
389        goto err1;
390      }
391      if (newSize*(int)sizeof(XRefEntry)/sizeof(XRefEntry) != newSize) {
392        error(-1, "Invalid 'obj' parameters'");
393        goto err1;
394      }
395 
396      entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry));
397      for (i = size; i < newSize; ++i) {
398        entries[i].offset = 0xffffffff;
399        entries[i].type = xrefEntryFree;
400      }
401      size = newSize;
402    }
403    for (i = first; i < first + n; ++i) {
404      if (!parser->getObj(&obj)->isInt()) {
405        goto err1;
406      }
407      entry.offset = (Guint)obj.getInt();
408      obj.free();
409      if (!parser->getObj(&obj)->isInt()) {
410        goto err1;
411      }
412      entry.gen = obj.getInt();
413      obj.free();
414      parser->getObj(&obj);
415      if (obj.isCmd("n")) {
416        entry.type = xrefEntryUncompressed;
417      } else if (obj.isCmd("f")) {
418        entry.type = xrefEntryFree;
419      } else {
420        goto err1;
421      }
422      obj.free();
423      if (entries[i].offset == 0xffffffff) {
424        entries[i] = entry;
425        // PDF files of patents from the IBM Intellectual Property
426        // Network have a bug: the xref table claims to start at 1
427        // instead of 0.
428        if (i == 1 && first == 1 &&
429            entries[1].offset == 0 && entries[1].gen == 65535 &&
430            entries[1].type == xrefEntryFree) {
431          i = first = 0;
432          entries[0] = entries[1];
433          entries[1].offset = 0xffffffff;
434        }
435      }
436    }
437  }
438
439  // read the trailer dictionary
440  if (!parser->getObj(&obj)->isDict()) {
441    goto err1;
442  }
443
444  // get the 'Prev' pointer
445  obj.getDict()->lookupNF("Prev", &obj2);
446  if (obj2.isInt()) {
447    *pos = (Guint)obj2.getInt();
448    more = gTrue;
449  } else if (obj2.isRef()) {
450    // certain buggy PDF generators generate "/Prev NNN 0 R" instead
451    // of "/Prev NNN"
452    *pos = (Guint)obj2.getRefNum();
453    more = gTrue;
454  } else {
455    more = gFalse;
456  }
457  obj2.free();
458
459  // save the first trailer dictionary
460  if (trailerDict.isNone()) {
461    obj.copy(&trailerDict);
462  }
463
464  // check for an 'XRefStm' key
465  if (obj.getDict()->lookup("XRefStm", &obj2)->isInt()) {
466    pos2 = (Guint)obj2.getInt();
467    readXRef(&pos2);
468    if (!ok) {
469      obj2.free();
470      goto err1;
471    }
472  }
473  obj2.free();
474
475  obj.free();
476  return more;
477
478 err1:
479  obj.free();
480  ok = gFalse;
481  return gFalse;
482}
483
484GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) {
485  Dict *dict;
486  int w[3];
487  GBool more;
488  Object obj, obj2, idx;
489  int newSize, first, n, i;
490
491  dict = xrefStr->getDict();
492
493  if (!dict->lookupNF("Size", &obj)->isInt()) {
494    goto err1;
495  }
496  newSize = obj.getInt();
497  obj.free();
498  if (newSize < 0) {
499    goto err1;
500  }
501  if (newSize > size) {
502    if (newSize * (int)sizeof(XRefEntry)/sizeof(XRefEntry) != newSize) {
503      error(-1, "Invalid 'size' parameter.");
504      return gFalse;
505    }
506    entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry));
507    for (i = size; i < newSize; ++i) {
508      entries[i].offset = 0xffffffff;
509      entries[i].type = xrefEntryFree;
510    }
511    size = newSize;
512  }
513
514  if (!dict->lookupNF("W", &obj)->isArray() ||
515      obj.arrayGetLength() < 3) {
516    goto err1;
517  }
518  for (i = 0; i < 3; ++i) {
519    if (!obj.arrayGet(i, &obj2)->isInt()) {
520      obj2.free();
521      goto err1;
522    }
523    w[i] = obj2.getInt();
524    obj2.free();
525    if (w[i] < 0 || w[i] > 4) {
526      goto err1;
527    }
528  }
529  obj.free();
530
531  xrefStr->reset();
532  dict->lookupNF("Index", &idx);
533  if (idx.isArray()) {
534    for (i = 0; i+1 < idx.arrayGetLength(); i += 2) {
535      if (!idx.arrayGet(i, &obj)->isInt()) {
536        idx.free();
537        goto err1;
538      }
539      first = obj.getInt();
540      obj.free();
541      if (!idx.arrayGet(i+1, &obj)->isInt()) {
542        idx.free();
543        goto err1;
544      }
545      n = obj.getInt();
546      obj.free();
547      if (first < 0 || n < 0 ||
548          !readXRefStreamSection(xrefStr, w, first, n)) {
549        idx.free();
550        goto err0;
551      }
552    }
553  } else {
554    if (!readXRefStreamSection(xrefStr, w, 0, newSize)) {
555      idx.free();
556      goto err0;
557    }
558  }
559  idx.free();
560
561  dict->lookupNF("Prev", &obj);
562  if (obj.isInt()) {
563    *pos = (Guint)obj.getInt();
564    more = gTrue;
565  } else {
566    more = gFalse;
567  }
568  obj.free();
569  if (trailerDict.isNone()) {
570    trailerDict.initDict(dict);
571  }
572
573  return more;
574
575 err1:
576  obj.free();
577 err0:
578  ok = gFalse;
579  return gFalse;
580}
581
582GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) {
583  Guint offset;
584  int type, gen, c, newSize, i, j;
585
586  if (first + n < 0) {
587    return gFalse;
588  }
589  if (first + n > size) {
590    for (newSize = size ? 2 * size : 1024;
591         first + n > newSize && newSize > 0;
592         newSize <<= 1) ;
593    if (newSize < 0) {
594      return gFalse;
595    }
596    if (newSize*(int)sizeof(XRefEntry)/sizeof(XRefEntry) != newSize) {
597      error(-1, "Invalid 'size' inside xref table.");
598      return gFalse;
599    }
600    entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry));
601    for (i = size; i < newSize; ++i) {
602      entries[i].offset = 0xffffffff;
603      entries[i].type = xrefEntryFree;
604    }
605    size = newSize;
606  }
607  for (i = first; i < first + n; ++i) {
608    if (w[0] == 0) {
609      type = 1;
610    } else {
611      for (type = 0, j = 0; j < w[0]; ++j) {
612        if ((c = xrefStr->getChar()) == EOF) {
613          return gFalse;
614        }
615        type = (type << 8) + c;
616      }
617    }
618    for (offset = 0, j = 0; j < w[1]; ++j) {
619      if ((c = xrefStr->getChar()) == EOF) {
620        return gFalse;
621      }
622      offset = (offset << 8) + c;
623    }
624    for (gen = 0, j = 0; j < w[2]; ++j) {
625      if ((c = xrefStr->getChar()) == EOF) {
626        return gFalse;
627      }
628      gen = (gen << 8) + c;
629    }
630    if (entries[i].offset == 0xffffffff) {
631      switch (type) {
632      case 0:
633        entries[i].offset = offset;
634        entries[i].gen = gen;
635        entries[i].type = xrefEntryFree;
636        break;
637      case 1:
638        entries[i].offset = offset;
639        entries[i].gen = gen;
640        entries[i].type = xrefEntryUncompressed;
641        break;
642      case 2:
643        entries[i].offset = offset;
644        entries[i].gen = gen;
645        entries[i].type = xrefEntryCompressed;
646        break;
647      default:
648        return gFalse;
649      }
650    }
651  }
652
653  return gTrue;
654}
655
656// Attempt to construct an xref table for a damaged file.
657GBool XRef::constructXRef() {
658  Parser *parser;
659  Object newTrailerDict, obj;
660  char buf[256];
661  Guint pos;
662  int num, gen;
663  int newSize;
664  int streamEndsSize;
665  char *p;
666  int i;
667  GBool gotRoot;
668
669  gfree(entries);
670  size = 0;
671  entries = NULL;
672
673  error(0, "PDF file is damaged - attempting to reconstruct xref table...");
674  gotRoot = gFalse;
675  streamEndsLen = streamEndsSize = 0;
676
677  str->reset();
678  while (1) {
679    pos = str->getPos();
680    if (!str->getLine(buf, 256)) {
681      break;
682    }
683    p = buf;
684
685    // got trailer dictionary
686    if (!strncmp(p, "trailer", 7)) {
687      obj.initNull();
688      parser = new Parser(NULL,
689                 new Lexer(NULL,
690                   str->makeSubStream(pos + 7, gFalse, 0, &obj)));
691      parser->getObj(&newTrailerDict);
692      if (newTrailerDict.isDict()) {
693        newTrailerDict.dictLookupNF("Root", &obj);
694        if (obj.isRef()) {
695          rootNum = obj.getRefNum();
696          rootGen = obj.getRefGen();
697          if (!trailerDict.isNone()) {
698            trailerDict.free();
699          }
700          newTrailerDict.copy(&trailerDict);
701          gotRoot = gTrue;
702        }
703        obj.free();
704      }
705      newTrailerDict.free();
706      delete parser;
707
708    // look for object
709    } else if (isdigit(*p)) {
710      num = atoi(p);
711      if (num > 0) {
712        do {
713          ++p;
714        } while (*p && isdigit(*p));
715        if (isspace(*p)) {
716          do {
717            ++p;
718          } while (*p && isspace(*p));
719          if (isdigit(*p)) {
720            gen = atoi(p);
721            do {
722              ++p;
723            } while (*p && isdigit(*p));
724            if (isspace(*p)) {
725              do {
726                ++p;
727              } while (*p && isspace(*p));
728              if (!strncmp(p, "obj", 3)) {
729                if (num >= size) {
730                  newSize = (num + 1 + 255) & ~255;
731                  if (newSize < 0) {
732                    error(-1, "Bad object number");
733                    return gFalse;
734                  }
735                  if (newSize*(int)sizeof(XRefEntry)/sizeof(XRefEntry) != newSize) {
736                    error(-1, "Invalid 'obj' parameters.");
737                    return gFalse;
738                  }
739                  entries = (XRefEntry *)
740                      greallocn(entries, newSize, sizeof(XRefEntry));
741                  for (i = size; i < newSize; ++i) {
742                    entries[i].offset = 0xffffffff;
743                    entries[i].type = xrefEntryFree;
744                  }
745                  size = newSize;
746                }
747                if (entries[num].type == xrefEntryFree ||
748                    gen >= entries[num].gen) {
749                  entries[num].offset = pos - start;
750                  entries[num].gen = gen;
751                  entries[num].type = xrefEntryUncompressed;
752                }
753              }
754            }
755          }
756        }
757      }
758
759    } else if (!strncmp(p, "endstream", 9)) {
760      if (streamEndsLen == streamEndsSize) {
761        streamEndsSize += 64;
762        if (streamEndsSize*(int)sizeof(int)/sizeof(int) != streamEndsSize) {
763          error(-1, "Invalid 'endstream' parameter.");
764          return gFalse;
765        }
766        streamEnds = (Guint *)greallocn(streamEnds,
767                                        streamEndsSize, sizeof(int));
768      }
769      streamEnds[streamEndsLen++] = pos;
770    }
771  }
772
773  if (gotRoot)
774    return gTrue;
775
776  error(-1, "Couldn't find trailer dictionary");
777  return gFalse;
778}
779
780void XRef::setEncryption(int permFlagsA, GBool ownerPasswordOkA,
781                         Guchar *fileKeyA, int keyLengthA,
782                         int encVersionA, int encRevisionA) {
783  int i;
784
785  encrypted = gTrue;
786  permFlags = permFlagsA;
787  ownerPasswordOk = ownerPasswordOkA;
788  if (keyLengthA <= 16) {
789    keyLength = keyLengthA;
790  } else {
791    keyLength = 16;
792  }
793  for (i = 0; i < keyLength; ++i) {
794    fileKey[i] = fileKeyA[i];
795  }
796  encVersion = encVersionA;
797  encRevision = encRevisionA;
798}
799
800GBool XRef::okToPrint(GBool ignoreOwnerPW) {
801  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint);
802}
803
804// we can print at high res if we are only doing security handler revision
805// 2 (and we are allowed to print at all), or with security handler rev
806// 3 and we are allowed to print, and bit 12 is set.
807GBool XRef::okToPrintHighRes(GBool ignoreOwnerPW) {
808  if (2 == encRevision) {
809    return (okToPrint(ignoreOwnerPW));
810  } else if (encRevision >= 3) {
811    return (okToPrint(ignoreOwnerPW) && (permFlags & permHighResPrint));
812  } else {
813    // something weird - unknown security handler version
814    return gFalse;
815  }
816}
817
818GBool XRef::okToChange(GBool ignoreOwnerPW) {
819  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permChange);
820}
821
822GBool XRef::okToCopy(GBool ignoreOwnerPW) {
823  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permCopy);
824}
825
826GBool XRef::okToAddNotes(GBool ignoreOwnerPW) {
827  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permNotes);
828}
829
830GBool XRef::okToFillForm(GBool ignoreOwnerPW) {
831  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permFillForm);
832}
833
834GBool XRef::okToAccessibility(GBool ignoreOwnerPW) {
835  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permAccessibility);
836}
837
838GBool XRef::okToAssemble(GBool ignoreOwnerPW) {
839  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permAssemble);
840}
841
842Object *XRef::fetch(int num, int gen, Object *obj) {
843  XRefEntry *e;
844  Parser *parser;
845  Object obj1, obj2, obj3;
846
847  // check for bogus ref - this can happen in corrupted PDF files
848  if (num < 0 || num >= size) {
849    goto err;
850  }
851
852  e = &entries[num];
853  switch (e->type) {
854
855  case xrefEntryUncompressed:
856    if (e->gen != gen) {
857      goto err;
858    }
859    obj1.initNull();
860    parser = new Parser(this,
861               new Lexer(this,
862                 str->makeSubStream(start + e->offset, gFalse, 0, &obj1)));
863    parser->getObj(&obj1);
864    parser->getObj(&obj2);
865    parser->getObj(&obj3);
866    if (!obj1.isInt() || obj1.getInt() != num ||
867        !obj2.isInt() || obj2.getInt() != gen ||
868        !obj3.isCmd("obj")) {
869      obj1.free();
870      obj2.free();
871      obj3.free();
872      delete parser;
873      goto err;
874    }
875    parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength,
876                   num, gen);
877    obj1.free();
878    obj2.free();
879    obj3.free();
880    delete parser;
881    break;
882
883  case xrefEntryCompressed:
884    if (gen != 0) {
885      goto err;
886    }
887    if (!objStr || objStr->getObjStrNum() != (int)e->offset) {
888      if (objStr) {
889        delete objStr;
890      }
891      objStr = new ObjectStream(this, e->offset);
892    }
893    objStr->getObject(e->gen, num, obj);
894    break;
895
896  default:
897    goto err;
898  }
899
900  return obj;
901
902 err:
903  return obj->initNull();
904}
905
906Object *XRef::getDocInfo(Object *obj) {
907  return trailerDict.dictLookup("Info", obj);
908}
909
910// Added for the pdftex project.
911Object *XRef::getDocInfoNF(Object *obj) {
912  return trailerDict.dictLookupNF("Info", obj);
913}
914
915GBool XRef::getStreamEnd(Guint streamStart, Guint *streamEnd) {
916  int a, b, m;
917
918  if (streamEndsLen == 0 ||
919      streamStart > streamEnds[streamEndsLen - 1]) {
920    return gFalse;
921  }
922
923  a = -1;
924  b = streamEndsLen - 1;
925  // invariant: streamEnds[a] < streamStart <= streamEnds[b]
926  while (b - a > 1) {
927    m = (a + b) / 2;
928    if (streamStart <= streamEnds[m]) {
929      b = m;
930    } else {
931      a = m;
932    }
933  }
934  *streamEnd = streamEnds[b];
935  return gTrue;
936}
937
938int XRef::getNumEntry(int offset) const
939{
940  int res = -1;
941  int resOffset = -1;
942  XRefEntry e;
943  for (int i = 0; i < size; ++i)
944  {
945    e = entries[i];
946    if (e.offset < offset && e.offset > resOffset)
947    {
948      res = i;
949      resOffset = e.offset;
950    }
951  }
952  return res;
953}
954
955Guint XRef::strToUnsigned(char *s) {
956  Guint x;
957  char *p;
958  int i;
959
960  x = 0;
961  for (p = s, i = 0; *p && isdigit(*p) && i < 10; ++p, ++i) {
962    x = 10 * x + (*p - '0');
963  }
964  return x;
965}
Note: See TracBrowser for help on using the repository browser.