filters

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