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

Last change on this file since 461 was 461, checked in by Silvan Scherrer, 11 years ago

poppler update to 0.14.2

File size: 29.3 KB
Line 
1//========================================================================
2//
3// XRef.cc
4//
5// Copyright 1996-2003 Glyph & Cog, LLC
6//
7//========================================================================
8
9//========================================================================
10//
11// Modified under the Poppler project - http://poppler.freedesktop.org
12//
13// All changes made under the Poppler project to this file are licensed
14// under GPL version 2 or later
15//
16// Copyright (C) 2005 Dan Sheridan <dan.sheridan@postman.org.uk>
17// Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
18// Copyright (C) 2006, 2008, 2010 Albert Astals Cid <aacid@kde.org>
19// Copyright (C) 2007-2008 Julien Rebetez <julienr@svn.gnome.org>
20// Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
21// Copyright (C) 2009 Ilya Gorenbein <igorenbein@finjan.com>
22//
23// To see a description of the changes please see the Changelog file that
24// came with your tarball or type make ChangeLog if you are building from git
25//
26//========================================================================
27
28#include <config.h>
29
30#ifdef USE_GCC_PRAGMAS
31#pragma implementation
32#endif
33
34#include <stdlib.h>
35#include <stddef.h>
36#include <string.h>
37#include <ctype.h>
38#include <limits.h>
39#include "goo/gmem.h"
40#include "Object.h"
41#include "Stream.h"
42#include "Lexer.h"
43#include "Parser.h"
44#include "Dict.h"
45#include "Error.h"
46#include "ErrorCodes.h"
47#include "XRef.h"
48#include "PopplerCache.h"
49
50//------------------------------------------------------------------------
51
52#define xrefSearchSize 1024     // read this many bytes at end of file
53                                //   to look for 'startxref'
54
55//------------------------------------------------------------------------
56// Permission bits
57// Note that the PDF spec uses 1 base (eg bit 3 is 1<<2)
58//------------------------------------------------------------------------
59
60#define permPrint         (1<<2)  // bit 3
61#define permChange        (1<<3)  // bit 4
62#define permCopy          (1<<4)  // bit 5
63#define permNotes         (1<<5)  // bit 6
64#define permFillForm      (1<<8)  // bit 9
65#define permAccessibility (1<<9)  // bit 10
66#define permAssemble      (1<<10) // bit 11
67#define permHighResPrint  (1<<11) // bit 12
68#define defPermFlags 0xfffc
69
70//------------------------------------------------------------------------
71// ObjectStream
72//------------------------------------------------------------------------
73
74class ObjectStream {
75public:
76
77  // Create an object stream, using object number <objStrNum>,
78  // generation 0.
79  ObjectStream(XRef *xref, int objStrNumA);
80
81  GBool isOk() { return ok; }
82
83  ~ObjectStream();
84
85  // Return the object number of this object stream.
86  int getObjStrNum() { return objStrNum; }
87
88  // Get the <objIdx>th object from this stream, which should be
89  // object number <objNum>, generation 0.
90  Object *getObject(int objIdx, int objNum, Object *obj);
91
92private:
93
94  int objStrNum;                // object number of the object stream
95  int nObjects;                 // number of objects in the stream
96  Object *objs;                 // the objects (length = nObjects)
97  int *objNums;                 // the object numbers (length = nObjects)
98  GBool ok;
99};
100
101class ObjectStreamKey : public PopplerCacheKey
102{
103  public:
104    ObjectStreamKey(int num) : objStrNum(num)
105    {
106    }
107
108    bool operator==(const PopplerCacheKey &key) const
109    {
110      const ObjectStreamKey *k = static_cast<const ObjectStreamKey*>(&key);
111      return objStrNum == k->objStrNum;
112    }
113
114    const int objStrNum;
115};
116
117class ObjectStreamItem : public PopplerCacheItem
118{
119  public:
120    ObjectStreamItem(ObjectStream *objStr) : objStream(objStr)
121    {
122    }
123
124    ~ObjectStreamItem()
125    {
126      delete objStream;
127    }
128
129    ObjectStream *objStream;
130};
131
132ObjectStream::ObjectStream(XRef *xref, int objStrNumA) {
133  Stream *str;
134  Parser *parser;
135  int *offsets;
136  Object objStr, obj1, obj2;
137  int first, i;
138
139  objStrNum = objStrNumA;
140  nObjects = 0;
141  objs = NULL;
142  objNums = NULL;
143  ok = gFalse;
144
145  if (!xref->fetch(objStrNum, 0, &objStr)->isStream()) {
146    goto err1;
147  }
148
149  if (!objStr.streamGetDict()->lookup("N", &obj1)->isInt()) {
150    obj1.free();
151    goto err1;
152  }
153  nObjects = obj1.getInt();
154  obj1.free();
155  if (nObjects <= 0) {
156    goto err1;
157  }
158
159  if (!objStr.streamGetDict()->lookup("First", &obj1)->isInt()) {
160    obj1.free();
161    goto err1;
162  }
163  first = obj1.getInt();
164  obj1.free();
165  if (first < 0) {
166    goto err1;
167  }
168
169  // this is an arbitrary limit to avoid integer overflow problems
170  // in the 'new Object[nObjects]' call (Acrobat apparently limits
171  // object streams to 100-200 objects)
172  if (nObjects > 1000000) {
173    error(-1, "Too many objects in an object stream");
174    goto err1;
175  }
176  objs = new Object[nObjects];
177  objNums = (int *)gmallocn(nObjects, sizeof(int));
178  offsets = (int *)gmallocn(nObjects, sizeof(int));
179
180  // parse the header: object numbers and offsets
181  objStr.streamReset();
182  obj1.initNull();
183  str = new EmbedStream(objStr.getStream(), &obj1, gTrue, first);
184  parser = new Parser(xref, new Lexer(xref, str), gFalse);
185  for (i = 0; i < nObjects; ++i) {
186    parser->getObj(&obj1);
187    parser->getObj(&obj2);
188    if (!obj1.isInt() || !obj2.isInt()) {
189      obj1.free();
190      obj2.free();
191      delete parser;
192      gfree(offsets);
193      goto err1;
194    }
195    objNums[i] = obj1.getInt();
196    offsets[i] = obj2.getInt();
197    obj1.free();
198    obj2.free();
199    if (objNums[i] < 0 || offsets[i] < 0 ||
200        (i > 0 && offsets[i] < offsets[i-1])) {
201      delete parser;
202      gfree(offsets);
203      goto err1;
204    }
205  }
206  while (str->getChar() != EOF) ;
207  delete parser;
208
209  // skip to the first object - this shouldn't be necessary because
210  // the First key is supposed to be equal to offsets[0], but just in
211  // case...
212  for (i = first; i < offsets[0]; ++i) {
213    objStr.getStream()->getChar();
214  }
215
216  // parse the objects
217  for (i = 0; i < nObjects; ++i) {
218    obj1.initNull();
219    if (i == nObjects - 1) {
220      str = new EmbedStream(objStr.getStream(), &obj1, gFalse, 0);
221    } else {
222      str = new EmbedStream(objStr.getStream(), &obj1, gTrue,
223                            offsets[i+1] - offsets[i]);
224    }
225    parser = new Parser(xref, new Lexer(xref, str), gFalse);
226    parser->getObj(&objs[i]);
227    while (str->getChar() != EOF) ;
228    delete parser;
229  }
230
231  gfree(offsets);
232  ok = gTrue;
233
234 err1:
235  objStr.free();
236}
237
238ObjectStream::~ObjectStream() {
239  int i;
240
241  if (objs) {
242    for (i = 0; i < nObjects; ++i) {
243      objs[i].free();
244    }
245    delete[] objs;
246  }
247  gfree(objNums);
248}
249
250Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) {
251  if (objIdx < 0 || objIdx >= nObjects || objNum != objNums[objIdx]) {
252    return obj->initNull();
253  }
254  return objs[objIdx].copy(obj);
255}
256
257//------------------------------------------------------------------------
258// XRef
259//------------------------------------------------------------------------
260
261XRef::XRef() {
262  ok = gTrue;
263  errCode = errNone;
264  entries = NULL;
265  size = 0;
266  streamEnds = NULL;
267  streamEndsLen = 0;
268  objStrs = new PopplerCache(5);
269}
270
271XRef::XRef(BaseStream *strA) {
272  Guint pos;
273  Object obj;
274
275  ok = gTrue;
276  errCode = errNone;
277  size = 0;
278  entries = NULL;
279  streamEnds = NULL;
280  streamEndsLen = 0;
281  objStrs = new PopplerCache(5);
282
283  encrypted = gFalse;
284  permFlags = defPermFlags;
285  ownerPasswordOk = gFalse;
286
287  // read the trailer
288  str = strA;
289  start = str->getStart();
290  pos = getStartXref();
291
292  // if there was a problem with the 'startxref' position, try to
293  // reconstruct the xref table
294  if (pos == 0) {
295    if (!(ok = constructXRef())) {
296      errCode = errDamaged;
297      return;
298    }
299
300  // read the xref table
301  } else {
302    GooVector<Guint> followedXRefStm;
303    while (readXRef(&pos, &followedXRefStm)) ;
304
305    // if there was a problem with the xref table,
306    // try to reconstruct it
307    if (!ok) {
308      if (!(ok = constructXRef())) {
309        errCode = errDamaged;
310        return;
311      }
312    }
313  }
314
315  // get the root dictionary (catalog) object
316  trailerDict.dictLookupNF("Root", &obj);
317  if (obj.isRef()) {
318    rootNum = obj.getRefNum();
319    rootGen = obj.getRefGen();
320    obj.free();
321  } else {
322    obj.free();
323    if (!(ok = constructXRef())) {
324      errCode = errDamaged;
325      return;
326    }
327  }
328
329  // now set the trailer dictionary's xref pointer so we can fetch
330  // indirect objects from it
331  trailerDict.getDict()->setXRef(this);
332}
333
334XRef::~XRef() {
335  for(int i=0; i<size; i++) {
336      entries[i].obj.free ();
337  }
338  gfree(entries);
339
340  trailerDict.free();
341  if (streamEnds) {
342    gfree(streamEnds);
343  }
344  if (objStrs) {
345    delete objStrs;
346  }
347}
348
349// Read the 'startxref' position.
350Guint XRef::getStartXref() {
351  char buf[xrefSearchSize+1];
352  char *p;
353  int c, n, i;
354
355  // read last xrefSearchSize bytes
356  str->setPos(xrefSearchSize, -1);
357  for (n = 0; n < xrefSearchSize; ++n) {
358    if ((c = str->getChar()) == EOF) {
359      break;
360    }
361    buf[n] = c;
362  }
363  buf[n] = '\0';
364
365  // find startxref
366  for (i = n - 9; i >= 0; --i) {
367    if (!strncmp(&buf[i], "startxref", 9)) {
368      break;
369    }
370  }
371  if (i < 0) {
372    return 0;
373  }
374  for (p = &buf[i+9]; isspace(*p); ++p) ;
375  lastXRefPos = strToUnsigned(p);
376
377  return lastXRefPos;
378}
379
380// Read one xref table section.  Also reads the associated trailer
381// dictionary, and returns the prev pointer (if any).
382GBool XRef::readXRef(Guint *pos, GooVector<Guint> *followedXRefStm) {
383  Parser *parser;
384  Object obj;
385  GBool more;
386
387  // start up a parser, parse one token
388  obj.initNull();
389  parser = new Parser(NULL,
390             new Lexer(NULL,
391               str->makeSubStream(start + *pos, gFalse, 0, &obj)),
392             gTrue);
393  parser->getObj(&obj);
394
395  // parse an old-style xref table
396  if (obj.isCmd("xref")) {
397    obj.free();
398    more = readXRefTable(parser, pos, followedXRefStm);
399
400  // parse an xref stream
401  } else if (obj.isInt()) {
402    obj.free();
403    if (!parser->getObj(&obj)->isInt()) {
404      goto err1;
405    }
406    obj.free();
407    if (!parser->getObj(&obj)->isCmd("obj")) {
408      goto err1;
409    }
410    obj.free();
411    if (!parser->getObj(&obj)->isStream()) {
412      goto err1;
413    }
414    more = readXRefStream(obj.getStream(), pos);
415    obj.free();
416
417  } else {
418    goto err1;
419  }
420
421  delete parser;
422  return more;
423
424 err1:
425  obj.free();
426  delete parser;
427  ok = gFalse;
428  return gFalse;
429}
430
431GBool XRef::readXRefTable(Parser *parser, Guint *pos, GooVector<Guint> *followedXRefStm) {
432  XRefEntry entry;
433  GBool more;
434  Object obj, obj2;
435  Guint pos2;
436  int first, n, newSize, i;
437
438  while (1) {
439    parser->getObj(&obj);
440    if (obj.isCmd("trailer")) {
441      obj.free();
442      break;
443    }
444    if (!obj.isInt()) {
445      goto err1;
446    }
447    first = obj.getInt();
448    obj.free();
449    if (!parser->getObj(&obj)->isInt()) {
450      goto err1;
451    }
452    n = obj.getInt();
453    obj.free();
454    if (first < 0 || n < 0 || first + n < 0) {
455      goto err1;
456    }
457    if (first + n > size) {
458      for (newSize = size ? 2 * size : 1024;
459           first + n > newSize && newSize > 0;
460           newSize <<= 1) ;
461      if (newSize < 0) {
462        goto err1;
463      }
464      if (newSize >= INT_MAX / (int)sizeof(XRefEntry)) {
465        error(-1, "Invalid 'obj' parameters'");
466        goto err1;
467      }
468 
469      entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry));
470      for (i = size; i < newSize; ++i) {
471        entries[i].offset = 0xffffffff;
472        entries[i].type = xrefEntryFree;
473        entries[i].obj.initNull ();
474        entries[i].updated = false;
475        entries[i].gen = 0;
476      }
477      size = newSize;
478    }
479    for (i = first; i < first + n; ++i) {
480      if (!parser->getObj(&obj)->isInt()) {
481        goto err1;
482      }
483      entry.offset = (Guint)obj.getInt();
484      obj.free();
485      if (!parser->getObj(&obj)->isInt()) {
486        goto err1;
487      }
488      entry.gen = obj.getInt();
489      entry.obj.initNull ();
490      entry.updated = false;
491      obj.free();
492      parser->getObj(&obj);
493      if (obj.isCmd("n")) {
494        entry.type = xrefEntryUncompressed;
495      } else if (obj.isCmd("f")) {
496        entry.type = xrefEntryFree;
497      } else {
498        goto err1;
499      }
500      obj.free();
501      if (entries[i].offset == 0xffffffff) {
502        entries[i] = entry;
503        // PDF files of patents from the IBM Intellectual Property
504        // Network have a bug: the xref table claims to start at 1
505        // instead of 0.
506        if (i == 1 && first == 1 &&
507            entries[1].offset == 0 && entries[1].gen == 65535 &&
508            entries[1].type == xrefEntryFree) {
509          i = first = 0;
510          entries[0] = entries[1];
511          entries[1].offset = 0xffffffff;
512        }
513      }
514    }
515  }
516
517  // read the trailer dictionary
518  if (!parser->getObj(&obj)->isDict()) {
519    goto err1;
520  }
521
522  // get the 'Prev' pointer
523  obj.getDict()->lookupNF("Prev", &obj2);
524  if (obj2.isInt()) {
525    *pos = (Guint)obj2.getInt();
526    more = gTrue;
527  } else if (obj2.isRef()) {
528    // certain buggy PDF generators generate "/Prev NNN 0 R" instead
529    // of "/Prev NNN"
530    *pos = (Guint)obj2.getRefNum();
531    more = gTrue;
532  } else {
533    more = gFalse;
534  }
535  obj2.free();
536
537  // save the first trailer dictionary
538  if (trailerDict.isNone()) {
539    obj.copy(&trailerDict);
540  }
541
542  // check for an 'XRefStm' key
543  if (obj.getDict()->lookup("XRefStm", &obj2)->isInt()) {
544    pos2 = (Guint)obj2.getInt();
545    for (size_t i = 0; ok == gTrue && i < followedXRefStm->size(); ++i) {
546      if (followedXRefStm->at(i) == pos2) {
547        ok = gFalse;
548      }
549    }
550    if (ok) {
551      followedXRefStm->push_back(pos2);
552      readXRef(&pos2, followedXRefStm);
553    }
554    if (!ok) {
555      obj2.free();
556      goto err1;
557    }
558  }
559  obj2.free();
560
561  obj.free();
562  return more;
563
564 err1:
565  obj.free();
566  ok = gFalse;
567  return gFalse;
568}
569
570GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) {
571  Dict *dict;
572  int w[3];
573  GBool more;
574  Object obj, obj2, idx;
575  int newSize, first, n, i;
576
577  dict = xrefStr->getDict();
578
579  if (!dict->lookupNF("Size", &obj)->isInt()) {
580    goto err1;
581  }
582  newSize = obj.getInt();
583  obj.free();
584  if (newSize < 0) {
585    goto err1;
586  }
587  if (newSize > size) {
588    if (newSize >= INT_MAX / (int)sizeof(XRefEntry)) {
589      error(-1, "Invalid 'size' parameter.");
590      return gFalse;
591    }
592    entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry));
593    for (i = size; i < newSize; ++i) {
594      entries[i].offset = 0xffffffff;
595      entries[i].type = xrefEntryFree;
596      entries[i].obj.initNull ();
597      entries[i].updated = false;
598      entries[i].gen = 0;
599    }
600    size = newSize;
601  }
602
603  if (!dict->lookupNF("W", &obj)->isArray() ||
604      obj.arrayGetLength() < 3) {
605    goto err1;
606  }
607  for (i = 0; i < 3; ++i) {
608    if (!obj.arrayGet(i, &obj2)->isInt()) {
609      obj2.free();
610      goto err1;
611    }
612    w[i] = obj2.getInt();
613    obj2.free();
614    if (w[i] < 0 || w[i] > 4) {
615      goto err1;
616    }
617  }
618  obj.free();
619
620  xrefStr->reset();
621  dict->lookupNF("Index", &idx);
622  if (idx.isArray()) {
623    for (i = 0; i+1 < idx.arrayGetLength(); i += 2) {
624      if (!idx.arrayGet(i, &obj)->isInt()) {
625        idx.free();
626        goto err1;
627      }
628      first = obj.getInt();
629      obj.free();
630      if (!idx.arrayGet(i+1, &obj)->isInt()) {
631        idx.free();
632        goto err1;
633      }
634      n = obj.getInt();
635      obj.free();
636      if (first < 0 || n < 0 ||
637          !readXRefStreamSection(xrefStr, w, first, n)) {
638        idx.free();
639        goto err0;
640      }
641    }
642  } else {
643    if (!readXRefStreamSection(xrefStr, w, 0, newSize)) {
644      idx.free();
645      goto err0;
646    }
647  }
648  idx.free();
649
650  dict->lookupNF("Prev", &obj);
651  if (obj.isInt()) {
652    *pos = (Guint)obj.getInt();
653    more = gTrue;
654  } else {
655    more = gFalse;
656  }
657  obj.free();
658  if (trailerDict.isNone()) {
659    trailerDict.initDict(dict);
660  }
661
662  return more;
663
664 err1:
665  obj.free();
666 err0:
667  ok = gFalse;
668  return gFalse;
669}
670
671GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) {
672  Guint offset;
673  int type, gen, c, newSize, i, j;
674
675  if (first + n < 0) {
676    return gFalse;
677  }
678  if (first + n > size) {
679    for (newSize = size ? 2 * size : 1024;
680         first + n > newSize && newSize > 0;
681         newSize <<= 1) ;
682    if (newSize < 0) {
683      return gFalse;
684    }
685    if (newSize >= INT_MAX / (int)sizeof(XRefEntry)) {
686      error(-1, "Invalid 'size' inside xref table.");
687      return gFalse;
688    }
689    entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry));
690    for (i = size; i < newSize; ++i) {
691      entries[i].offset = 0xffffffff;
692      entries[i].type = xrefEntryFree;
693      entries[i].obj.initNull ();
694      entries[i].updated = false;
695      entries[i].gen = 0;
696    }
697    size = newSize;
698  }
699  for (i = first; i < first + n; ++i) {
700    if (w[0] == 0) {
701      type = 1;
702    } else {
703      for (type = 0, j = 0; j < w[0]; ++j) {
704        if ((c = xrefStr->getChar()) == EOF) {
705          return gFalse;
706        }
707        type = (type << 8) + c;
708      }
709    }
710    for (offset = 0, j = 0; j < w[1]; ++j) {
711      if ((c = xrefStr->getChar()) == EOF) {
712        return gFalse;
713      }
714      offset = (offset << 8) + c;
715    }
716    for (gen = 0, j = 0; j < w[2]; ++j) {
717      if ((c = xrefStr->getChar()) == EOF) {
718        return gFalse;
719      }
720      gen = (gen << 8) + c;
721    }
722    if (entries[i].offset == 0xffffffff) {
723      switch (type) {
724      case 0:
725        entries[i].offset = offset;
726        entries[i].gen = gen;
727        entries[i].type = xrefEntryFree;
728        break;
729      case 1:
730        entries[i].offset = offset;
731        entries[i].gen = gen;
732        entries[i].type = xrefEntryUncompressed;
733        break;
734      case 2:
735        entries[i].offset = offset;
736        entries[i].gen = gen;
737        entries[i].type = xrefEntryCompressed;
738        break;
739      default:
740        return gFalse;
741      }
742    }
743  }
744
745  return gTrue;
746}
747
748// Attempt to construct an xref table for a damaged file.
749GBool XRef::constructXRef() {
750  Parser *parser;
751  Object newTrailerDict, obj;
752  char buf[256];
753  Guint pos;
754  int num, gen;
755  int newSize;
756  int streamEndsSize;
757  char *p;
758  int i;
759  GBool gotRoot;
760  char* token = NULL;
761  bool oneCycle = true;
762  int offset = 0;
763
764  gfree(entries);
765  size = 0;
766  entries = NULL;
767
768  error(-1, "PDF file is damaged - attempting to reconstruct xref table...");
769  gotRoot = gFalse;
770  streamEndsLen = streamEndsSize = 0;
771
772  str->reset();
773  while (1) {
774    pos = str->getPos();
775    if (!str->getLine(buf, 256)) {
776      break;
777    }
778    p = buf;
779
780    // skip whitespace
781    while (*p && Lexer::isSpace(*p & 0xff)) ++p;
782
783    oneCycle = true;
784    offset = 0;
785
786    while( ( token = strstr( p, "endobj" ) ) || oneCycle ) {
787      oneCycle = false;
788
789      if( token ) {
790        oneCycle = true;
791        token[0] = '\0'; 
792        offset = token - p;
793      }
794
795      // got trailer dictionary
796      if (!strncmp(p, "trailer", 7)) {
797        obj.initNull();
798        parser = new Parser(NULL,
799                 new Lexer(NULL,
800                   str->makeSubStream(pos + 7, gFalse, 0, &obj)),
801                 gFalse);
802        parser->getObj(&newTrailerDict);
803        if (newTrailerDict.isDict()) {
804          newTrailerDict.dictLookupNF("Root", &obj);
805          if (obj.isRef()) {
806            rootNum = obj.getRefNum();
807            rootGen = obj.getRefGen();
808            if (!trailerDict.isNone()) {
809              trailerDict.free();
810            }
811            newTrailerDict.copy(&trailerDict);
812            gotRoot = gTrue;
813          }
814          obj.free();
815        }
816        newTrailerDict.free();
817        delete parser;
818
819      // look for object
820      } else if (isdigit(*p)) {
821        num = atoi(p);
822        if (num > 0) {
823          do {
824            ++p;
825          } while (*p && isdigit(*p));
826          if (isspace(*p)) {
827            do {
828              ++p;
829            } while (*p && isspace(*p));
830            if (isdigit(*p)) {
831              gen = atoi(p);
832              do {
833                ++p;
834              } while (*p && isdigit(*p));
835              if (isspace(*p)) {
836                do {
837                  ++p;
838                } while (*p && isspace(*p));
839                if (!strncmp(p, "obj", 3)) {
840                  if (num >= size) {
841                    newSize = (num + 1 + 255) & ~255;
842                    if (newSize < 0) {
843                      error(-1, "Bad object number");
844                      return gFalse;
845                    }
846                    if (newSize >= INT_MAX / (int)sizeof(XRefEntry)) {
847                      error(-1, "Invalid 'obj' parameters.");
848                      return gFalse;
849                    }
850                    entries = (XRefEntry *)
851                        greallocn_checkoverflow(entries, newSize, sizeof(XRefEntry));
852                    if (entries == NULL) {
853                      size = 0;
854                      return gFalse;
855                    }
856                    for (i = size; i < newSize; ++i) {
857                      entries[i].offset = 0xffffffff;
858                      entries[i].type = xrefEntryFree;
859                      entries[i].obj.initNull ();
860                      entries[i].updated = false;
861                    }
862                    size = newSize;
863                  }
864                  if (entries[num].type == xrefEntryFree ||
865                      gen >= entries[num].gen) {
866                    entries[num].offset = pos - start;
867                    entries[num].gen = gen;
868                    entries[num].type = xrefEntryUncompressed;
869                  }
870                }
871              }
872            }
873          }
874        }
875
876      } else if (!strncmp(p, "endstream", 9)) {
877        if (streamEndsLen == streamEndsSize) {
878          streamEndsSize += 64;
879          if (streamEndsSize >= INT_MAX / (int)sizeof(int)) {
880            error(-1, "Invalid 'endstream' parameter.");
881            return gFalse;
882          }
883          streamEnds = (Guint *)greallocn(streamEnds,
884                                        streamEndsSize, sizeof(int));
885        }
886        streamEnds[streamEndsLen++] = pos;
887      }
888      if( token ) {
889        p = token + 6;// strlen( "endobj" ) = 6
890        pos += offset + 6;// strlen( "endobj" ) = 6
891        while (*p && Lexer::isSpace(*p & 0xff)) {
892          ++p;
893          ++pos;
894        }
895      }
896    }
897  }
898
899  if (gotRoot)
900    return gTrue;
901
902  error(-1, "Couldn't find trailer dictionary");
903  return gFalse;
904}
905
906void XRef::setEncryption(int permFlagsA, GBool ownerPasswordOkA,
907                         Guchar *fileKeyA, int keyLengthA,
908                         int encVersionA, int encRevisionA,
909                         CryptAlgorithm encAlgorithmA) {
910  int i;
911
912  encrypted = gTrue;
913  permFlags = permFlagsA;
914  ownerPasswordOk = ownerPasswordOkA;
915  if (keyLengthA <= 16) {
916    keyLength = keyLengthA;
917  } else {
918    keyLength = 16;
919  }
920  for (i = 0; i < keyLength; ++i) {
921    fileKey[i] = fileKeyA[i];
922  }
923  encVersion = encVersionA;
924  encRevision = encRevisionA;
925  encAlgorithm = encAlgorithmA;
926}
927
928GBool XRef::okToPrint(GBool ignoreOwnerPW) {
929  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint);
930}
931
932// we can print at high res if we are only doing security handler revision
933// 2 (and we are allowed to print at all), or with security handler rev
934// 3 and we are allowed to print, and bit 12 is set.
935GBool XRef::okToPrintHighRes(GBool ignoreOwnerPW) {
936  if (encrypted) {
937    if (2 == encRevision) {
938      return (okToPrint(ignoreOwnerPW));
939    } else if (encRevision >= 3) {
940      return (okToPrint(ignoreOwnerPW) && (permFlags & permHighResPrint));
941    } else {
942      // something weird - unknown security handler version
943      return gFalse;
944    }
945  } else {
946    return gTrue;
947  }
948}
949
950GBool XRef::okToChange(GBool ignoreOwnerPW) {
951  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permChange);
952}
953
954GBool XRef::okToCopy(GBool ignoreOwnerPW) {
955  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permCopy);
956}
957
958GBool XRef::okToAddNotes(GBool ignoreOwnerPW) {
959  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permNotes);
960}
961
962GBool XRef::okToFillForm(GBool ignoreOwnerPW) {
963  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permFillForm);
964}
965
966GBool XRef::okToAccessibility(GBool ignoreOwnerPW) {
967  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permAccessibility);
968}
969
970GBool XRef::okToAssemble(GBool ignoreOwnerPW) {
971  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permAssemble);
972}
973
974Object *XRef::fetch(int num, int gen, Object *obj) {
975  XRefEntry *e;
976  Parser *parser;
977  Object obj1, obj2, obj3;
978
979  // check for bogus ref - this can happen in corrupted PDF files
980  if (num < 0 || num >= size) {
981    goto err;
982  }
983
984  e = &entries[num];
985  if(!e->obj.isNull ()) { //check for updated object
986    obj = e->obj.copy(obj);
987    return obj;
988  }
989  switch (e->type) {
990
991  case xrefEntryUncompressed:
992    if (e->gen != gen) {
993      goto err;
994    }
995    obj1.initNull();
996    parser = new Parser(this,
997               new Lexer(this,
998                 str->makeSubStream(start + e->offset, gFalse, 0, &obj1)),
999               gTrue);
1000    parser->getObj(&obj1);
1001    parser->getObj(&obj2);
1002    parser->getObj(&obj3);
1003    if (!obj1.isInt() || obj1.getInt() != num ||
1004        !obj2.isInt() || obj2.getInt() != gen ||
1005        !obj3.isCmd("obj")) {
1006      // some buggy pdf have obj1234 for ints that represent 1234
1007      // try to recover here
1008      if (obj1.isInt() && obj1.getInt() == num &&
1009          obj2.isInt() && obj2.getInt() == gen &&
1010          obj3.isCmd()) {
1011        char *cmd = obj3.getCmd();
1012        if (strlen(cmd) > 3 &&
1013            cmd[0] == 'o' &&
1014            cmd[1] == 'b' &&
1015            cmd[2] == 'j') {
1016          char *end_ptr;
1017          long longNumber = strtol(cmd + 3, &end_ptr, 0);
1018          if (longNumber <= INT_MAX && longNumber >= INT_MIN && *end_ptr == '\0') {
1019            int number = longNumber;
1020            error(-1, "Cmd was not obj but %s, assuming the creator meant obj %d", cmd, number);
1021            obj->initInt(number);
1022            obj1.free();
1023            obj2.free();
1024            obj3.free();
1025            delete parser;
1026            break;
1027          }
1028        }
1029      }
1030      obj1.free();
1031      obj2.free();
1032      obj3.free();
1033      delete parser;
1034      goto err;
1035    }
1036    parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL,
1037                   encAlgorithm, keyLength, num, gen);
1038    obj1.free();
1039    obj2.free();
1040    obj3.free();
1041    delete parser;
1042    break;
1043
1044  case xrefEntryCompressed:
1045  {
1046    if (gen != 0) {
1047      goto err;
1048    }
1049
1050    ObjectStream *objStr = NULL;
1051    ObjectStreamKey key(e->offset);
1052    PopplerCacheItem *item = objStrs->lookup(key);
1053    if (item) {
1054      ObjectStreamItem *it = static_cast<ObjectStreamItem *>(item);
1055      objStr = it->objStream;
1056    }
1057
1058    if (!objStr) {
1059      objStr = new ObjectStream(this, e->offset);
1060      if (!objStr->isOk()) {
1061        delete objStr;
1062        objStr = NULL;
1063        goto err;
1064      } else {
1065        ObjectStreamKey *newkey = new ObjectStreamKey(e->offset);
1066        ObjectStreamItem *newitem = new ObjectStreamItem(objStr);
1067        objStrs->put(newkey, newitem);
1068      }
1069    }
1070    objStr->getObject(e->gen, num, obj);
1071  }
1072  break;
1073
1074  default:
1075    goto err;
1076  }
1077
1078  return obj;
1079
1080 err:
1081  return obj->initNull();
1082}
1083
1084Object *XRef::getDocInfo(Object *obj) {
1085  return trailerDict.dictLookup("Info", obj);
1086}
1087
1088// Added for the pdftex project.
1089Object *XRef::getDocInfoNF(Object *obj) {
1090  return trailerDict.dictLookupNF("Info", obj);
1091}
1092
1093GBool XRef::getStreamEnd(Guint streamStart, Guint *streamEnd) {
1094  int a, b, m;
1095
1096  if (streamEndsLen == 0 ||
1097      streamStart > streamEnds[streamEndsLen - 1]) {
1098    return gFalse;
1099  }
1100
1101  a = -1;
1102  b = streamEndsLen - 1;
1103  // invariant: streamEnds[a] < streamStart <= streamEnds[b]
1104  while (b - a > 1) {
1105    m = (a + b) / 2;
1106    if (streamStart <= streamEnds[m]) {
1107      b = m;
1108    } else {
1109      a = m;
1110    }
1111  }
1112  *streamEnd = streamEnds[b];
1113  return gTrue;
1114}
1115
1116int XRef::getNumEntry(Guint offset) const
1117{
1118  if (size > 0)
1119  {
1120    int res = 0;
1121    Guint resOffset = entries[0].offset;
1122    XRefEntry e;
1123    for (int i = 1; i < size; ++i)
1124    {
1125      e = entries[i];
1126      if (e.offset < offset && e.offset >= resOffset)
1127      {
1128        res = i;
1129        resOffset = e.offset;
1130      }
1131    }
1132    return res;
1133  }
1134  else return -1;
1135}
1136
1137Guint XRef::strToUnsigned(char *s) {
1138  Guint x;
1139  char *p;
1140  int i;
1141
1142  x = 0;
1143  for (p = s, i = 0; *p && isdigit(*p) && i < 10; ++p, ++i) {
1144    x = 10 * x + (*p - '0');
1145  }
1146  return x;
1147}
1148
1149void XRef::add(int num, int gen, Guint offs, GBool used) {
1150  if (num >= size) {
1151    entries = (XRefEntry *)greallocn(entries, num + 1, sizeof(XRefEntry));
1152    for (int i = size; i < num + 1; ++i) {
1153      entries[i].offset = 0xffffffff;
1154      entries[i].type = xrefEntryFree;
1155      entries[i].obj.initNull ();
1156      entries[i].updated = false;
1157      entries[i].gen = 0;
1158    }
1159    size = num + 1;
1160  }
1161  XRefEntry *e = &entries[num];
1162  e->gen = gen;
1163  e->obj.initNull ();
1164  e->updated = false;
1165  if (used) {
1166    e->type = xrefEntryUncompressed;
1167    e->offset = offs;
1168  } else {
1169    e->type = xrefEntryFree;
1170    e->offset = 0;
1171  }
1172}
1173
1174void XRef::setModifiedObject (Object* o, Ref r) {
1175  if (r.num < 0 || r.num >= size) {
1176    error(-1,"XRef::setModifiedObject on unknown ref: %i, %i\n", r.num, r.gen);
1177    return;
1178  }
1179  entries[r.num].obj.free();
1180  o->copy(&entries[r.num].obj);
1181  entries[r.num].updated = true;
1182}
1183
1184Ref XRef::addIndirectObject (Object* o) {
1185  int entryIndexToUse = -1;
1186  for (int i = 1; entryIndexToUse == -1 && i < size; ++i) {
1187    if (entries[i].type == xrefEntryFree) entryIndexToUse = i;
1188  }
1189
1190  XRefEntry *e;
1191  if (entryIndexToUse == -1) {
1192    entryIndexToUse = size;
1193    size++;
1194    entries = (XRefEntry *)greallocn(entries, size, sizeof(XRefEntry));
1195    e = &entries[entryIndexToUse];
1196    e->gen = 0;
1197  } else {
1198    //reuse a free entry
1199    e = &entries[entryIndexToUse];
1200    //we don't touch gen number, because it should have been
1201    //incremented when the object was deleted
1202  }
1203  e->type = xrefEntryUncompressed;
1204  o->copy(&e->obj);
1205  e->updated = true;
1206
1207  Ref r;
1208  r.num = entryIndexToUse;
1209  r.gen = e->gen;
1210  return r;
1211}
1212
1213void XRef::writeToFile(OutStream* outStr, GBool writeAllEntries) {
1214  //create free entries linked-list
1215  if (entries[0].gen != 65535) {
1216    error(-1, "XRef::writeToFile, entry 0 of the XRef is invalid (gen != 65535)\n");
1217  }
1218  int lastFreeEntry = 0;
1219  for (int i=0; i<size; i++) {
1220    if (entries[i].type == xrefEntryFree) {
1221      entries[lastFreeEntry].offset = i;
1222      lastFreeEntry = i;
1223    }
1224  }
1225
1226  if (writeAllEntries) {
1227    //write the new xref
1228    outStr->printf("xref\r\n");
1229    outStr->printf("%i %i\r\n", 0, size);
1230    for (int i=0; i<size; i++) {
1231      XRefEntry &e = entries[i];
1232
1233      if(e.gen > 65535) e.gen = 65535; //cap generation number to 65535 (required by PDFReference)
1234      outStr->printf("%010i %05i %c\r\n", e.offset, e.gen, (e.type==xrefEntryFree)?'f':'n');
1235    }
1236  } else {
1237    //write the new xref
1238    outStr->printf("xref\r\n");
1239    int i = 0;
1240    while (i < size) {
1241      int j;
1242      for(j=i; j<size; j++) { //look for consecutive entries
1243        if ((entries[j].type == xrefEntryFree) && (entries[j].gen == 0))
1244          break;
1245      }
1246      if (j-i != 0)
1247      {
1248        outStr->printf("%i %i\r\n", i, j-i);
1249        for (int k=i; k<j; k++) {
1250          XRefEntry &e = entries[k];
1251          if(e.gen > 65535) e.gen = 65535; //cap generation number to 65535 (required by PDFReference)
1252          outStr->printf("%010i %05i %c\r\n", e.offset, e.gen, (e.type==xrefEntryFree)?'f':'n');
1253        }
1254        i = j;
1255      }
1256      else ++i;
1257    }
1258  }
1259}
1260
Note: See TracBrowser for help on using the repository browser.