added some log messages to the font directory routines.
[swftools.git] / pdf2swf / xpdf / Parser.cc
1 //========================================================================
2 //
3 // Parser.cc
4 //
5 // Copyright 1996-2003 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
26 Parser::Parser(XRef *xrefA, Lexer *lexerA) {
27   xref = xrefA;
28   lexer = lexerA;
29   inlineImg = 0;
30   lexer->getObj(&buf1);
31   lexer->getObj(&buf2);
32 }
33
34 Parser::~Parser() {
35   buf1.free();
36   buf2.free();
37   delete lexer;
38 }
39
40 #ifndef NO_DECRYPTION
41 Object *Parser::getObj(Object *obj,
42                        Guchar *fileKey, int keyLength,
43                        int objNum, int objGen) {
44 #else
45 Object *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
158 Stream *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 && xref->getStreamEnd(pos, &endPos)) {
180     length = endPos - pos;
181   }
182
183   // in badly damaged PDF files, we can run off the end of the input
184   // stream immediately after the "stream" token
185   if (!lexer->getStream()) {
186     return NULL;
187   }
188
189   // make base stream
190   str = lexer->getStream()->getBaseStream()->makeSubStream(pos, gTrue,
191                                                            length, dict);
192
193   // get filters
194   str = str->addFilters(dict);
195
196   // skip over stream data
197   lexer->setPos(pos + length);
198
199   // refill token buffers and check for 'endstream'
200   shift();  // kill '>>'
201   shift();  // kill 'stream'
202   if (buf1.isCmd("endstream")) {
203     shift();
204   } else {
205     error(getPos(), "Missing 'endstream'");
206     str->ignoreLength();
207   }
208
209   return str;
210 }
211
212 void Parser::shift() {
213   if (inlineImg > 0) {
214     if (inlineImg < 2) {
215       ++inlineImg;
216     } else {
217       // in a damaged content stream, if 'ID' shows up in the middle
218       // of a dictionary, we need to reset
219       inlineImg = 0;
220     }
221   } else if (buf2.isCmd("ID")) {
222     lexer->skipChar();          // skip char after 'ID' command
223     inlineImg = 1;
224   }
225   buf1.free();
226   buf1 = buf2;
227   if (inlineImg > 0)            // don't buffer inline image data
228     buf2.initNull();
229   else
230     lexer->getObj(&buf2);
231 }