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

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

PDF plugin: Poppler library updated to version 0.8.4

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      entry.updated = false;
431      obj.free();
432      parser->getObj(&obj);
433      if (obj.isCmd("n")) {
434        entry.type = xrefEntryUncompressed;
435      } else if (obj.isCmd("f")) {
436        entry.type = xrefEntryFree;
437      } else {
438        goto err1;
439      }
440      obj.free();
441      if (entries[i].offset == 0xffffffff) {
442        entries[i] = entry;
443        // PDF files of patents from the IBM Intellectual Property
444        // Network have a bug: the xref table claims to start at 1
445        // instead of 0.
446        if (i == 1 && first == 1 &&
447            entries[1].offset == 0 && entries[1].gen == 65535 &&
448            entries[1].type == xrefEntryFree) {
449          i = first = 0;
450          entries[0] = entries[1];
451          entries[1].offset = 0xffffffff;
452        }
453      }
454    }
455  }
456
457  // read the trailer dictionary
458  if (!parser->getObj(&obj)->isDict()) {
459    goto err1;
460  }
461
462  // get the 'Prev' pointer
463  obj.getDict()->lookupNF("Prev", &obj2);
464  if (obj2.isInt()) {
465    *pos = (Guint)obj2.getInt();
466    more = gTrue;
467  } else if (obj2.isRef()) {
468    // certain buggy PDF generators generate "/Prev NNN 0 R" instead
469    // of "/Prev NNN"
470    *pos = (Guint)obj2.getRefNum();
471    more = gTrue;
472  } else {
473    more = gFalse;
474  }
475  obj2.free();
476
477  // save the first trailer dictionary
478  if (trailerDict.isNone()) {
479    obj.copy(&trailerDict);
480  }
481
482  // check for an 'XRefStm' key
483  if (obj.getDict()->lookup("XRefStm", &obj2)->isInt()) {
484    pos2 = (Guint)obj2.getInt();
485    readXRef(&pos2);
486    if (!ok) {
487      obj2.free();
488      goto err1;
489    }
490  }
491  obj2.free();
492
493  obj.free();
494  return more;
495
496 err1:
497  obj.free();
498  ok = gFalse;
499  return gFalse;
500}
501
502GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) {
503  Dict *dict;
504  int w[3];
505  GBool more;
506  Object obj, obj2, idx;
507  int newSize, first, n, i;
508
509  dict = xrefStr->getDict();
510
511  if (!dict->lookupNF("Size", &obj)->isInt()) {
512    goto err1;
513  }
514  newSize = obj.getInt();
515  obj.free();
516  if (newSize < 0) {
517    goto err1;
518  }
519  if (newSize > size) {
520    if (newSize * (int)sizeof(XRefEntry)/sizeof(XRefEntry) != newSize) {
521      error(-1, "Invalid 'size' parameter.");
522      return gFalse;
523    }
524    entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry));
525    for (i = size; i < newSize; ++i) {
526      entries[i].offset = 0xffffffff;
527      entries[i].type = xrefEntryFree;
528      entries[i].obj.initNull ();
529      entries[i].updated = false;
530    }
531    size = newSize;
532  }
533
534  if (!dict->lookupNF("W", &obj)->isArray() ||
535      obj.arrayGetLength() < 3) {
536    goto err1;
537  }
538  for (i = 0; i < 3; ++i) {
539    if (!obj.arrayGet(i, &obj2)->isInt()) {
540      obj2.free();
541      goto err1;
542    }
543    w[i] = obj2.getInt();
544    obj2.free();
545    if (w[i] < 0 || w[i] > 4) {
546      goto err1;
547    }
548  }
549  obj.free();
550
551  xrefStr->reset();
552  dict->lookupNF("Index", &idx);
553  if (idx.isArray()) {
554    for (i = 0; i+1 < idx.arrayGetLength(); i += 2) {
555      if (!idx.arrayGet(i, &obj)->isInt()) {
556        idx.free();
557        goto err1;
558      }
559      first = obj.getInt();
560      obj.free();
561      if (!idx.arrayGet(i+1, &obj)->isInt()) {
562        idx.free();
563        goto err1;
564      }
565      n = obj.getInt();
566      obj.free();
567      if (first < 0 || n < 0 ||
568          !readXRefStreamSection(xrefStr, w, first, n)) {
569        idx.free();
570        goto err0;
571      }
572    }
573  } else {
574    if (!readXRefStreamSection(xrefStr, w, 0, newSize)) {
575      idx.free();
576      goto err0;
577    }
578  }
579  idx.free();
580
581  dict->lookupNF("Prev", &obj);
582  if (obj.isInt()) {
583    *pos = (Guint)obj.getInt();
584    more = gTrue;
585  } else {
586    more = gFalse;
587  }
588  obj.free();
589  if (trailerDict.isNone()) {
590    trailerDict.initDict(dict);
591  }
592
593  return more;
594
595 err1:
596  obj.free();
597 err0:
598  ok = gFalse;
599  return gFalse;
600}
601
602GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) {
603  Guint offset;
604  int type, gen, c, newSize, i, j;
605
606  if (first + n < 0) {
607    return gFalse;
608  }
609  if (first + n > size) {
610    for (newSize = size ? 2 * size : 1024;
611         first + n > newSize && newSize > 0;
612         newSize <<= 1) ;
613    if (newSize < 0) {
614      return gFalse;
615    }
616    if (newSize*(int)sizeof(XRefEntry)/sizeof(XRefEntry) != newSize) {
617      error(-1, "Invalid 'size' inside xref table.");
618      return gFalse;
619    }
620    entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry));
621    for (i = size; i < newSize; ++i) {
622      entries[i].offset = 0xffffffff;
623      entries[i].type = xrefEntryFree;
624      entries[i].obj.initNull ();
625      entries[i].updated = false;
626    }
627    size = newSize;
628  }
629  for (i = first; i < first + n; ++i) {
630    if (w[0] == 0) {
631      type = 1;
632    } else {
633      for (type = 0, j = 0; j < w[0]; ++j) {
634        if ((c = xrefStr->getChar()) == EOF) {
635          return gFalse;
636        }
637        type = (type << 8) + c;
638      }
639    }
640    for (offset = 0, j = 0; j < w[1]; ++j) {
641      if ((c = xrefStr->getChar()) == EOF) {
642        return gFalse;
643      }
644      offset = (offset << 8) + c;
645    }
646    for (gen = 0, j = 0; j < w[2]; ++j) {
647      if ((c = xrefStr->getChar()) == EOF) {
648        return gFalse;
649      }
650      gen = (gen << 8) + c;
651    }
652    if (entries[i].offset == 0xffffffff) {
653      switch (type) {
654      case 0:
655        entries[i].offset = offset;
656        entries[i].gen = gen;
657        entries[i].type = xrefEntryFree;
658        break;
659      case 1:
660        entries[i].offset = offset;
661        entries[i].gen = gen;
662        entries[i].type = xrefEntryUncompressed;
663        break;
664      case 2:
665        entries[i].offset = offset;
666        entries[i].gen = gen;
667        entries[i].type = xrefEntryCompressed;
668        break;
669      default:
670        return gFalse;
671      }
672    }
673  }
674
675  return gTrue;
676}
677
678// Attempt to construct an xref table for a damaged file.
679GBool XRef::constructXRef() {
680  Parser *parser;
681  Object newTrailerDict, obj;
682  char buf[256];
683  Guint pos;
684  int num, gen;
685  int newSize;
686  int streamEndsSize;
687  char *p;
688  int i;
689  GBool gotRoot;
690
691  gfree(entries);
692  size = 0;
693  entries = NULL;
694
695  error(-1, "PDF file is damaged - attempting to reconstruct xref table...");
696  gotRoot = gFalse;
697  streamEndsLen = streamEndsSize = 0;
698
699  str->reset();
700  while (1) {
701    pos = str->getPos();
702    if (!str->getLine(buf, 256)) {
703      break;
704    }
705    p = buf;
706
707    // skip whitespace
708    while (*p && Lexer::isSpace(*p & 0xff)) ++p;
709
710    // got trailer dictionary
711    if (!strncmp(p, "trailer", 7)) {
712      obj.initNull();
713      parser = new Parser(NULL,
714                 new Lexer(NULL,
715                   str->makeSubStream(pos + 7, gFalse, 0, &obj)),
716                 gFalse);
717      parser->getObj(&newTrailerDict);
718      if (newTrailerDict.isDict()) {
719        newTrailerDict.dictLookupNF("Root", &obj);
720        if (obj.isRef()) {
721          rootNum = obj.getRefNum();
722          rootGen = obj.getRefGen();
723          if (!trailerDict.isNone()) {
724            trailerDict.free();
725          }
726          newTrailerDict.copy(&trailerDict);
727          gotRoot = gTrue;
728        }
729        obj.free();
730      }
731      newTrailerDict.free();
732      delete parser;
733
734    // look for object
735    } else if (isdigit(*p)) {
736      num = atoi(p);
737      if (num > 0) {
738        do {
739          ++p;
740        } while (*p && isdigit(*p));
741        if (isspace(*p)) {
742          do {
743            ++p;
744          } while (*p && isspace(*p));
745          if (isdigit(*p)) {
746            gen = atoi(p);
747            do {
748              ++p;
749            } while (*p && isdigit(*p));
750            if (isspace(*p)) {
751              do {
752                ++p;
753              } while (*p && isspace(*p));
754              if (!strncmp(p, "obj", 3)) {
755                if (num >= size) {
756                  newSize = (num + 1 + 255) & ~255;
757                  if (newSize < 0) {
758                    error(-1, "Bad object number");
759                    return gFalse;
760                  }
761                  if (newSize*(int)sizeof(XRefEntry)/sizeof(XRefEntry) != newSize) {
762                    error(-1, "Invalid 'obj' parameters.");
763                    return gFalse;
764                  }
765                  entries = (XRefEntry *)
766                      greallocn(entries, newSize, sizeof(XRefEntry));
767                  for (i = size; i < newSize; ++i) {
768                    entries[i].offset = 0xffffffff;
769                    entries[i].type = xrefEntryFree;
770                    entries[i].obj.initNull ();
771                    entries[i].updated = false;
772                  }
773                  size = newSize;
774                }
775                if (entries[num].type == xrefEntryFree ||
776                    gen >= entries[num].gen) {
777                  entries[num].offset = pos - start;
778                  entries[num].gen = gen;
779                  entries[num].type = xrefEntryUncompressed;
780                }
781              }
782            }
783          }
784        }
785      }
786
787    } else if (!strncmp(p, "endstream", 9)) {
788      if (streamEndsLen == streamEndsSize) {
789        streamEndsSize += 64;
790        if (streamEndsSize*(int)sizeof(int)/sizeof(int) != streamEndsSize) {
791          error(-1, "Invalid 'endstream' parameter.");
792          return gFalse;
793        }
794        streamEnds = (Guint *)greallocn(streamEnds,
795                                        streamEndsSize, sizeof(int));
796      }
797      streamEnds[streamEndsLen++] = pos;
798    }
799  }
800
801  if (gotRoot)
802    return gTrue;
803
804  error(-1, "Couldn't find trailer dictionary");
805  return gFalse;
806}
807
808void XRef::setEncryption(int permFlagsA, GBool ownerPasswordOkA,
809                         Guchar *fileKeyA, int keyLengthA,
810                         int encVersionA, int encRevisionA,
811                         CryptAlgorithm encAlgorithmA) {
812  int i;
813
814  encrypted = gTrue;
815  permFlags = permFlagsA;
816  ownerPasswordOk = ownerPasswordOkA;
817  if (keyLengthA <= 16) {
818    keyLength = keyLengthA;
819  } else {
820    keyLength = 16;
821  }
822  for (i = 0; i < keyLength; ++i) {
823    fileKey[i] = fileKeyA[i];
824  }
825  encVersion = encVersionA;
826  encRevision = encRevisionA;
827  encAlgorithm = encAlgorithmA;
828}
829
830GBool XRef::okToPrint(GBool ignoreOwnerPW) {
831  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint);
832}
833
834// we can print at high res if we are only doing security handler revision
835// 2 (and we are allowed to print at all), or with security handler rev
836// 3 and we are allowed to print, and bit 12 is set.
837GBool XRef::okToPrintHighRes(GBool ignoreOwnerPW) {
838  if (2 == encRevision) {
839    return (okToPrint(ignoreOwnerPW));
840  } else if (encRevision >= 3) {
841    return (okToPrint(ignoreOwnerPW) && (permFlags & permHighResPrint));
842  } else {
843    // something weird - unknown security handler version
844    return gFalse;
845  }
846}
847
848GBool XRef::okToChange(GBool ignoreOwnerPW) {
849  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permChange);
850}
851
852GBool XRef::okToCopy(GBool ignoreOwnerPW) {
853  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permCopy);
854}
855
856GBool XRef::okToAddNotes(GBool ignoreOwnerPW) {
857  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permNotes);
858}
859
860GBool XRef::okToFillForm(GBool ignoreOwnerPW) {
861  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permFillForm);
862}
863
864GBool XRef::okToAccessibility(GBool ignoreOwnerPW) {
865  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permAccessibility);
866}
867
868GBool XRef::okToAssemble(GBool ignoreOwnerPW) {
869  return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permAssemble);
870}
871
872Object *XRef::fetch(int num, int gen, Object *obj) {
873  XRefEntry *e;
874  Parser *parser;
875  Object obj1, obj2, obj3;
876
877  // check for bogus ref - this can happen in corrupted PDF files
878  if (num < 0 || num >= size) {
879    goto err;
880  }
881
882  e = &entries[num];
883  if(!e->obj.isNull ()) { //check for updated object
884    obj = e->obj.copy(obj);
885    return obj;
886  }
887  switch (e->type) {
888
889  case xrefEntryUncompressed:
890    if (e->gen != gen) {
891      goto err;
892    }
893    obj1.initNull();
894    parser = new Parser(this,
895               new Lexer(this,
896                 str->makeSubStream(start + e->offset, gFalse, 0, &obj1)),
897               gTrue);
898    parser->getObj(&obj1);
899    parser->getObj(&obj2);
900    parser->getObj(&obj3);
901    if (!obj1.isInt() || obj1.getInt() != num ||
902        !obj2.isInt() || obj2.getInt() != gen ||
903        !obj3.isCmd("obj")) {
904      obj1.free();
905      obj2.free();
906      obj3.free();
907      delete parser;
908      goto err;
909    }
910    parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL,
911                   encAlgorithm, keyLength, num, gen);
912    obj1.free();
913    obj2.free();
914    obj3.free();
915    delete parser;
916    break;
917
918  case xrefEntryCompressed:
919    if (gen != 0) {
920      goto err;
921    }
922    if (!objStr || objStr->getObjStrNum() != (int)e->offset) {
923      if (objStr) {
924        delete objStr;
925      }
926      objStr = new ObjectStream(this, e->offset);
927    }
928    objStr->getObject(e->gen, num, obj);
929    break;
930
931  default:
932    goto err;
933  }
934
935  return obj;
936
937 err:
938  return obj->initNull();
939}
940
941Object *XRef::getDocInfo(Object *obj) {
942  return trailerDict.dictLookup("Info", obj);
943}
944
945// Added for the pdftex project.
946Object *XRef::getDocInfoNF(Object *obj) {
947  return trailerDict.dictLookupNF("Info", obj);
948}
949
950GBool XRef::getStreamEnd(Guint streamStart, Guint *streamEnd) {
951  int a, b, m;
952
953  if (streamEndsLen == 0 ||
954      streamStart > streamEnds[streamEndsLen - 1]) {
955    return gFalse;
956  }
957
958  a = -1;
959  b = streamEndsLen - 1;
960  // invariant: streamEnds[a] < streamStart <= streamEnds[b]
961  while (b - a > 1) {
962    m = (a + b) / 2;
963    if (streamStart <= streamEnds[m]) {
964      b = m;
965    } else {
966      a = m;
967    }
968  }
969  *streamEnd = streamEnds[b];
970  return gTrue;
971}
972
973int XRef::getNumEntry(Guint offset) const
974{
975  if (size > 0)
976  {
977    int res = 0;
978    Guint resOffset = entries[0].offset;
979    XRefEntry e;
980    for (int i = 1; i < size; ++i)
981    {
982      e = entries[i];
983      if (e.offset < offset && e.offset >= resOffset)
984      {
985        res = i;
986        resOffset = e.offset;
987      }
988    }
989    return res;
990  }
991  else return -1;
992}
993
994Guint XRef::strToUnsigned(char *s) {
995  Guint x;
996  char *p;
997  int i;
998
999  x = 0;
1000  for (p = s, i = 0; *p && isdigit(*p) && i < 10; ++p, ++i) {
1001    x = 10 * x + (*p - '0');
1002  }
1003  return x;
1004}
1005
1006void XRef::add(int num, int gen, Guint offs, GBool used) {
1007  size += 1;
1008  entries = (XRefEntry *)greallocn(entries, size, sizeof(XRefEntry));
1009  XRefEntry *e = &entries[size-1];
1010
1011  e->gen = gen;
1012  e->num = num;
1013  e->obj.initNull ();
1014  e->updated = false;
1015  if (used) {
1016    e->type = xrefEntryUncompressed;
1017    e->offset = offs;
1018  } else {
1019    e->type = xrefEntryFree;
1020    e->offset = 0;
1021  }
1022}
1023
1024void XRef::setModifiedObject (Object* o, Ref r) {
1025  if (r.num < 0 || r.num >= size) {
1026    error(-1,"XRef::setModifiedObject on unknown ref: %i, %i\n", r.num, r.gen);
1027    return;
1028  }
1029  o->copy(&entries[r.num].obj);
1030  entries[r.num].updated = true;
1031}
1032
1033Ref XRef::addIndirectObject (Object* o) {
1034  //Find the next free entry
1035  // lastEntry is the last free entry we encountered,
1036  // entry 0 is always free
1037  int lastEntry = 0;
1038  int newEntry = entries[0].offset;
1039
1040  do {
1041    lastEntry = newEntry;
1042    newEntry = entries[newEntry].offset;
1043    //we are looking for a free entry that we can reuse
1044    //(=> gen number != 65535)
1045  } while ((newEntry != 0) && (entries[newEntry].gen == 65535));
1046
1047  //the linked list of free entry is empty => create a new one
1048  if (newEntry == 0) {
1049    newEntry = size;
1050    size++;
1051    entries = (XRefEntry *)greallocn(entries, size, sizeof(XRefEntry));
1052    entries[newEntry].gen = 0;
1053    entries[newEntry].num = newEntry;
1054  } else { //reuse a free entry
1055    //'remove' the entry we are using from the free entry linked list
1056    entries[lastEntry].offset = entries[newEntry].offset;
1057    entries[newEntry].num = newEntry;
1058    //we don't touch gen number, because it should have been
1059    //incremented when the object was deleted
1060  }
1061
1062  entries[newEntry].type = xrefEntryUncompressed;
1063  o->copy(&entries[newEntry].obj);
1064  entries[newEntry].updated = true;
1065
1066  Ref r;
1067  r.num = entries[newEntry].num;
1068  r.gen = entries[newEntry].gen;
1069  return r;
1070}
1071
1072
1073//used to sort the entries
1074int compare (const void* a, const void* b)
1075{
1076  return (((XRefEntry*)a)->num - ((XRefEntry*)b)->num);
1077}
1078
1079void XRef::writeToFile(OutStream* outStr) {
1080  qsort(entries, size, sizeof(XRefEntry), compare);
1081  //create free entries linked-list
1082  if (entries[0].gen != 65535) {
1083    error(-1, "XRef::writeToFile, entry 0 of the XRef is invalid (gen != 65535)\n");
1084  }
1085  int lastFreeEntry = 0; 
1086  for (int i=0; i<size; i++) {
1087    if (entries[i].type == xrefEntryFree) {
1088      entries[lastFreeEntry].offset = entries[i].num;
1089      lastFreeEntry = i;
1090    }
1091  }
1092  //write the new xref
1093  int j;
1094  outStr->printf("xref\r\n");
1095  for (int i=0; i<size; i++) {
1096    for(j=i; j<size; j++) { //look for consecutive entries
1097      if (j!=i && entries[j].num != entries[j-1].num+1) 
1098              break;
1099    }
1100    outStr->printf("%i %i\r\n", entries[i].num, j-i);
1101    for (int k=i; k<j; k++) {
1102      if(entries[k].gen > 65535) entries[k].gen = 65535; //cap generation number to 65535 (required by PDFReference)
1103      outStr->printf("%010i %05i %c\r\n", entries[k].offset, entries[k].gen, (entries[k].type==xrefEntryFree)?'f':'n');
1104    }
1105    i = j-1;
1106  }
1107}
1108
Note: See TracBrowser for help on using the repository browser.