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

Last change on this file since 250 was 250, checked in by Eugene Romanenko, 13 years ago

PDF plugin: poppler library updated to version 0.8.3

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