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

Last change on this file since 27 was 27, checked in by Eugene Romanenko, 16 years ago

poppler updated to version 0.5.2, also needed changes to be compatible with new poppler

File size: 21.5 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  if (size > 0)
941  {
942    int res = 0;
943    Guint resOffset = entries[0].offset;
944    XRefEntry e;
945    for (int i = 1; i < size; ++i)
946    {
947      e = entries[i];
948      if (e.offset < offset && e.offset >= resOffset)
949      {
950        res = i;
951        resOffset = e.offset;
952      }
953    }
954    return res;
955  }
956  else return -1;
957}
958
959Guint XRef::strToUnsigned(char *s) {
960  Guint x;
961  char *p;
962  int i;
963
964  x = 0;
965  for (p = s, i = 0; *p && isdigit(*p) && i < 10; ++p, ++i) {
966    x = 10 * x + (*p - '0');
967  }
968  return x;
969}
Note: See TracBrowser for help on using the repository browser.