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

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

poppler update to 0.14.2

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