source: trunk/poppler/mypoppler/poppler/Parser.cc @ 277

Last change on this file since 277 was 277, checked in by rbri, 12 years ago

PDF plugin: Poppler library updated to version 0.12.3

File size: 6.7 KB
Line 
1//========================================================================
2//
3// Parser.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) 2006, 2009 Albert Astals Cid <aacid@kde.org>
17// Copyright (C) 2006 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
18//
19// To see a description of the changes please see the Changelog file that
20// came with your tarball or type make ChangeLog if you are building from git
21//
22//========================================================================
23
24#include <config.h>
25
26#ifdef USE_GCC_PRAGMAS
27#pragma implementation
28#endif
29
30#include <stddef.h>
31#include "Object.h"
32#include "Array.h"
33#include "Dict.h"
34#include "Decrypt.h"
35#include "Parser.h"
36#include "XRef.h"
37#include "Error.h"
38
39Parser::Parser(XRef *xrefA, Lexer *lexerA, GBool allowStreamsA) {
40  xref = xrefA;
41  lexer = lexerA;
42  inlineImg = 0;
43  allowStreams = allowStreamsA;
44  lexer->getObj(&buf1);
45  lexer->getObj(&buf2);
46}
47
48Parser::~Parser() {
49  buf1.free();
50  buf2.free();
51  delete lexer;
52}
53
54Object *Parser::getObj(Object *obj, Guchar *fileKey,
55                       CryptAlgorithm encAlgorithm, int keyLength,
56                       int objNum, int objGen) {
57  char *key;
58  Stream *str;
59  Object obj2;
60  int num;
61  DecryptStream *decrypt;
62  GooString *s, *s2;
63  int c;
64
65  // refill buffer after inline image data
66  if (inlineImg == 2) {
67    buf1.free();
68    buf2.free();
69    lexer->getObj(&buf1);
70    lexer->getObj(&buf2);
71    inlineImg = 0;
72  }
73
74  // array
75  if (buf1.isCmd("[")) {
76    shift();
77    obj->initArray(xref);
78    while (!buf1.isCmd("]") && !buf1.isEOF())
79      obj->arrayAdd(getObj(&obj2, fileKey, encAlgorithm, keyLength,
80                           objNum, objGen));
81    if (buf1.isEOF())
82      error(getPos(), "End of file inside array");
83    shift();
84
85  // dictionary or stream
86  } else if (buf1.isCmd("<<")) {
87    shift(objNum);
88    obj->initDict(xref);
89    while (!buf1.isCmd(">>") && !buf1.isEOF()) {
90      if (!buf1.isName()) {
91        error(getPos(), "Dictionary key must be a name object");
92        shift();
93      } else {
94        // buf1 might go away in shift(), so construct the key
95        key = copyString(buf1.getName());
96        shift();
97        if (buf1.isEOF() || buf1.isError()) {
98          gfree(key);
99          break;
100        }
101        obj->dictAdd(key, getObj(&obj2, fileKey, encAlgorithm, keyLength, objNum, objGen));
102      }
103    }
104    if (buf1.isEOF())
105      error(getPos(), "End of file inside dictionary");
106    // stream objects are not allowed inside content streams or
107    // object streams
108    if (allowStreams && buf2.isCmd("stream")) {
109      if ((str = makeStream(obj, fileKey, encAlgorithm, keyLength,
110                            objNum, objGen))) {
111        obj->initStream(str);
112      } else {
113        obj->free();
114        obj->initError();
115      }
116    } else {
117      shift();
118    }
119
120  // indirect reference or integer
121  } else if (buf1.isInt()) {
122    num = buf1.getInt();
123    shift();
124    if (buf1.isInt() && buf2.isCmd("R")) {
125      obj->initRef(num, buf1.getInt());
126      shift();
127      shift();
128    } else {
129      obj->initInt(num);
130    }
131
132  // string
133  } else if (buf1.isString() && fileKey) {
134    s = buf1.getString();
135    s2 = new GooString();
136    obj2.initNull();
137    decrypt = new DecryptStream(new MemStream(s->getCString(), 0,
138                                              s->getLength(), &obj2),
139                                fileKey, encAlgorithm, keyLength,
140                                objNum, objGen);
141    decrypt->reset();
142    while ((c = decrypt->getChar()) != EOF) {
143      s2->append((char)c);
144    }
145    delete decrypt;
146    obj->initString(s2);
147    shift();
148
149  // simple object
150  } else {
151    // avoid re-allocating memory for complex objects like strings by
152    // shallow copy of <buf1> to <obj> and nulling <buf1> so that
153    // subsequent buf1.free() won't free this memory
154    buf1.shallowCopy(obj);
155    buf1.initNull();
156    shift();
157  }
158
159  return obj;
160}
161
162Stream *Parser::makeStream(Object *dict, Guchar *fileKey,
163                           CryptAlgorithm encAlgorithm, int keyLength,
164                           int objNum, int objGen) {
165  Object obj;
166  BaseStream *baseStr;
167  Stream *str;
168  Guint pos, endPos, length;
169
170  // get stream start position
171  lexer->skipToNextLine();
172  pos = lexer->getPos();
173
174  // get length
175  dict->dictLookup("Length", &obj);
176  if (obj.isInt()) {
177    length = (Guint)obj.getInt();
178    obj.free();
179  } else {
180    error(getPos(), "Bad 'Length' attribute in stream");
181    obj.free();
182    return NULL;
183  }
184
185  // check for length in damaged file
186  if (xref && xref->getStreamEnd(pos, &endPos)) {
187    length = endPos - pos;
188  }
189
190  // in badly damaged PDF files, we can run off the end of the input
191  // stream immediately after the "stream" token
192  if (!lexer->getStream()) {
193    return NULL;
194  }
195  baseStr = lexer->getStream()->getBaseStream();
196
197  // skip over stream data
198  if (Lexer::LOOK_VALUE_NOT_CACHED != lexer->lookCharLastValueCached) {
199      // take into account the fact that we've cached one value
200      pos = pos - 1;
201      lexer->lookCharLastValueCached = Lexer::LOOK_VALUE_NOT_CACHED;
202  }
203  lexer->setPos(pos + length);
204
205  // refill token buffers and check for 'endstream'
206  shift();  // kill '>>'
207  shift();  // kill 'stream'
208  if (buf1.isCmd("endstream")) {
209    shift();
210  } else {
211    error(getPos(), "Missing 'endstream'");
212    if (xref) {
213      // shift until we find the proper endstream or we change to another object or reach eof
214      while (!buf1.isCmd("endstream") && xref->getNumEntry(lexer->getPos()) == objNum && !buf1.isEOF()) {
215        shift();
216      }
217      length = lexer->getPos() - pos;
218      if (buf1.isCmd("endstream")) {
219        obj.initInt(length);
220        dict->dictSet("Length", &obj);
221        obj.free();
222      }
223    } else {
224      // When building the xref we can't use it so use this
225      // kludge for broken PDF files: just add 5k to the length, and
226      // hope its enough
227      length += 5000;
228    }
229  }
230
231  // make base stream
232  str = baseStr->makeSubStream(pos, gTrue, length, dict);
233
234  // handle decryption
235  if (fileKey) {
236    str = new DecryptStream(str, fileKey, encAlgorithm, keyLength,
237                            objNum, objGen);
238  }
239
240  // get filters
241  str = str->addFilters(dict);
242
243  return str;
244}
245
246void Parser::shift(int objNum) {
247  if (inlineImg > 0) {
248    if (inlineImg < 2) {
249      ++inlineImg;
250    } else {
251      // in a damaged content stream, if 'ID' shows up in the middle
252      // of a dictionary, we need to reset
253      inlineImg = 0;
254    }
255  } else if (buf2.isCmd("ID")) {
256    lexer->skipChar();          // skip char after 'ID' command
257    inlineImg = 1;
258  }
259  buf1.free();
260  buf2.shallowCopy(&buf1);
261  if (inlineImg > 0)            // don't buffer inline image data
262    buf2.initNull();
263  else
264    lexer->getObj(&buf2, objNum);
265}
Note: See TracBrowser for help on using the repository browser.