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

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 16 years ago

First import

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