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

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

PDF plugin: Poppler library updated to version 0.10.0

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