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