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

Last change on this file since 134 was 134, checked in by Eugene Romanenko, 15 years ago

poppler updated to version 0.5.4

File size: 4.9 KB
Line 
1//========================================================================
2//
3// Parser.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 <stddef.h>
16#include "Object.h"
17#include "Array.h"
18#include "Dict.h"
19#include "Parser.h"
20#include "XRef.h"
21#include "Error.h"
22#include "Decrypt.h"
23#include "UGooString.h"
24
25Parser::Parser(XRef *xrefA, Lexer *lexerA) {
26  xref = xrefA;
27  lexer = lexerA;
28  inlineImg = 0;
29  lexer->getObj(&buf1);
30  lexer->getObj(&buf2);
31}
32
33Parser::~Parser() {
34  buf1.free();
35  buf2.free();
36  delete lexer;
37}
38
39Object *Parser::getObj(Object *obj,
40                       Guchar *fileKey, int keyLength,
41                       int objNum, int objGen) {
42  Stream *str;
43  Object obj2;
44  int num;
45  Decrypt *decrypt;
46  GooString *s;
47  char *p;
48  int i;
49
50  // refill buffer after inline image data
51  if (inlineImg == 2) {
52    buf1.free();
53    buf2.free();
54    lexer->getObj(&buf1);
55    lexer->getObj(&buf2);
56    inlineImg = 0;
57  }
58
59  // array
60  if (buf1.isCmd("[")) {
61    shift();
62    obj->initArray(xref);
63    while (!buf1.isCmd("]") && !buf1.isEOF())
64      obj->arrayAdd(getObj(&obj2, fileKey, keyLength, objNum, objGen));
65    if (buf1.isEOF())
66      error(getPos(), "End of file inside array");
67    shift();
68
69  // dictionary or stream
70  } else if (buf1.isCmd("<<")) {
71    shift(objNum);
72    obj->initDict(xref);
73    while (!buf1.isCmd(">>") && !buf1.isEOF()) {
74      if (!buf1.isName()) {
75        error(getPos(), "Dictionary key must be a name object");
76        shift();
77      } else {
78        // buf1 might go away in shift(), so construct the key
79        UGooString *key = new UGooString(buf1.getName());
80        shift();
81        if (buf1.isEOF() || buf1.isError()) {
82          gfree(key);
83          break;
84        }
85        obj->dictAddOwnKeyVal(key, getObj(&obj2, fileKey, keyLength, objNum, objGen));
86      }
87    }
88    if (buf1.isEOF())
89      error(getPos(), "End of file inside dictionary");
90    if (buf2.isCmd("stream")) {
91      if ((str = makeStream(obj))) {
92        obj->initStream(str);
93        if (fileKey) {
94          str->getBaseStream()->doDecryption(fileKey, keyLength,
95                                             objNum, objGen);
96        }
97      } else {
98        obj->free();
99        obj->initError();
100      }
101    } else {
102      shift();
103    }
104
105  // indirect reference or integer
106  } else if (buf1.isInt()) {
107    num = buf1.getInt();
108    shift();
109    if (buf1.isInt() && buf2.isCmd("R")) {
110      obj->initRef(num, buf1.getInt());
111      shift();
112      shift();
113    } else {
114      obj->initInt(num);
115    }
116
117  // string
118  } else if (buf1.isString() && fileKey) {
119    buf1.copy(obj);
120    s = obj->getString();
121    decrypt = new Decrypt(fileKey, keyLength, objNum, objGen);
122    for (i = 0, p = obj->getString()->getCString();
123         i < s->getLength();
124         ++i, ++p) {
125      *p = decrypt->decryptByte(*p);
126    }
127    delete decrypt;
128    shift();
129
130  // simple object
131  } else {
132    // avoid re-allocating memory for complex objects like strings by
133    // shallow copy of <buf1> to <obj> and nulling <buf1> so that
134    // subsequent buf1.free() won't free this memory
135    buf1.shallowCopy(obj);
136    buf1.initNull();
137    shift();
138  }
139
140  return obj;
141}
142
143Stream *Parser::makeStream(Object *dict) {
144  Object obj;
145  BaseStream *baseStr;
146  Stream *str;
147  Guint pos, endPos, length;
148
149  // get stream start position
150  lexer->skipToNextLine();
151  pos = lexer->getPos();
152
153  // get length
154  dict->dictLookup("Length", &obj);
155  if (obj.isInt()) {
156    length = (Guint)obj.getInt();
157    obj.free();
158  } else {
159    error(getPos(), "Bad 'Length' attribute in stream");
160    obj.free();
161    return NULL;
162  }
163
164  // check for length in damaged file
165  if (xref && xref->getStreamEnd(pos, &endPos)) {
166    length = endPos - pos;
167  }
168
169  // in badly damaged PDF files, we can run off the end of the input
170  // stream immediately after the "stream" token
171  if (!lexer->getStream()) {
172    return NULL;
173  }
174  baseStr = lexer->getStream()->getBaseStream();
175
176  // skip over stream data
177  lexer->setPos(pos + length);
178
179  // refill token buffers and check for 'endstream'
180  shift();  // kill '>>'
181  shift();  // kill 'stream'
182  if (buf1.isCmd("endstream")) {
183    shift();
184  } else {
185    error(getPos(), "Missing 'endstream'");
186    // kludge for broken PDF files: just add 5k to the length, and
187    // hope its enough
188    length += 5000;
189  }
190
191  // make base stream
192  str = baseStr->makeSubStream(pos, gTrue, length, dict);
193
194  // get filters
195  str = str->addFilters(dict);
196
197  return str;
198}
199
200void Parser::shift(int objNum) {
201  if (inlineImg > 0) {
202    if (inlineImg < 2) {
203      ++inlineImg;
204    } else {
205      // in a damaged content stream, if 'ID' shows up in the middle
206      // of a dictionary, we need to reset
207      inlineImg = 0;
208    }
209  } else if (buf2.isCmd("ID")) {
210    lexer->skipChar();          // skip char after 'ID' command
211    inlineImg = 1;
212  }
213  buf1.free();
214  buf2.shallowCopy(&buf1);
215  if (inlineImg > 0)            // don't buffer inline image data
216    buf2.initNull();
217  else
218    lexer->getObj(&buf2, objNum);
219}
Note: See TracBrowser for help on using the repository browser.