]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/Lexer.cc
drag and drop, removed redundant verb popup code.
[evince.git] / pdf / xpdf / Lexer.cc
1 //========================================================================
2 //
3 // Lexer.cc
4 //
5 // Copyright 1996 Derek B. Noonburg
6 //
7 //========================================================================
8
9 #ifdef __GNUC__
10 #pragma implementation
11 #endif
12
13 #include <stdlib.h>
14 #include <stddef.h>
15 #include <string.h>
16 #include <ctype.h>
17 #include "Lexer.h"
18 #include "Error.h"
19
20 //------------------------------------------------------------------------
21
22 // A '1' in this array means the corresponding character ends a name
23 // or command.
24 static char endOfNameChars[128] = {
25   0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,   // 0x
26   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 1x
27   1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1,   // 2x
28   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,   // 3x
29   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 4x
30   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0,   // 5x
31   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 6x
32   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0    // 7x
33 };
34
35 //------------------------------------------------------------------------
36 // Lexer
37 //------------------------------------------------------------------------
38
39 Lexer::Lexer(Stream *str) {
40   Object obj;
41
42   curStr.initStream(str);
43   streams = new Array();
44   streams->add(curStr.copy(&obj));
45   strPtr = 0;
46   freeArray = gTrue;
47   curStr.streamReset();
48 }
49
50 Lexer::Lexer(Object *obj) {
51   Object obj2;
52
53   if (obj->isStream()) {
54     streams = new Array();
55     freeArray = gTrue;
56     streams->add(obj->copy(&obj2));
57   } else {
58     streams = obj->getArray();
59     freeArray = gFalse;
60   }
61   strPtr = 0;
62   if (streams->getLength() > 0) {
63     streams->get(strPtr, &curStr);
64     curStr.streamReset();
65   }
66 }
67
68 Lexer::~Lexer() {
69   if (!curStr.isNone())
70     curStr.free();
71   if (freeArray)
72     delete streams;
73 }
74
75 int Lexer::getChar() {
76   int c;
77
78   c = EOF;
79   while (!curStr.isNone() && (c = curStr.streamGetChar()) == EOF) {
80     curStr.free();
81     ++strPtr;
82     if (strPtr < streams->getLength()) {
83       streams->get(strPtr, &curStr);
84       curStr.streamReset();
85     }
86   }
87   return c;
88 }
89
90 int Lexer::lookChar() {
91   int c;
92
93   c = EOF;
94   while (!curStr.isNone() && (c = curStr.streamLookChar()) == EOF) {
95     curStr.free();
96     ++strPtr;
97     if (strPtr < streams->getLength()) {
98       streams->get(strPtr, &curStr);
99       curStr.streamReset();
100     }
101   }
102   return c;
103 }
104
105 Object *Lexer::getObj(Object *obj) {
106   char *p;
107   int c, c2;
108   GBool comment, neg, done;
109   int numParen;
110   int xi;
111   double xf, scale;
112   GString *s;
113   int n, m;
114
115   // skip whitespace and comments
116   comment = gFalse;
117   while (1) {
118     if ((c = getChar()) == EOF)
119       return obj->initEOF();
120     if (comment) {
121       if (c == '\r' || c == '\n')
122         comment = gFalse;
123     } else if (c == '%') {
124       comment = gTrue;
125     } else if (!isspace(c)) {
126       break;
127     }
128   }
129
130   // start reading token
131   switch (c) {
132
133   // number
134   case '0': case '1': case '2': case '3': case '4':
135   case '5': case '6': case '7': case '8': case '9':
136   case '-': case '.':
137     neg = gFalse;
138     xi = 0;
139     if (c == '-') {
140       neg = gTrue;
141     } else if (c == '.') {
142       goto doReal;
143     } else {
144       xi = c - '0';
145     }
146     while (1) {
147       c = lookChar();
148       if (isdigit(c)) {
149         getChar();
150         xi = xi * 10 + (c - '0');
151       } else if (c == '.') {
152         getChar();
153         goto doReal;
154       } else {
155         break;
156       }
157     }
158     if (neg)
159       xi = -xi;
160     obj->initInt(xi);
161     break;
162   doReal:
163     xf = xi;
164     scale = 0.1;
165     while (1) {
166       c = lookChar();
167       if (!isdigit(c))
168         break;
169       getChar();
170       xf = xf + scale * (c - '0');
171       scale *= 0.1;
172     }
173     if (neg)
174       xf = -xf;
175     obj->initReal(xf);
176     break;
177
178   // string
179   case '(':
180     p = tokBuf;
181     n = 0;
182     numParen = 1;
183     done = gFalse;
184     s = NULL;
185     do {
186       c2 = EOF;
187       switch (c = getChar()) {
188
189       case EOF:
190       case '\r':
191       case '\n':
192         error(getPos(), "Unterminated string");
193         done = gTrue;
194         break;
195
196       case '(':
197         ++numParen;
198         break;
199
200       case ')':
201         if (--numParen == 0)
202           done = gTrue;
203         break;
204
205       case '\\':
206         switch (c = getChar()) {
207         case 'n':
208           c2 = '\n';
209           break;
210         case 'r':
211           c2 = '\r';
212           break;
213         case 't':
214           c2 = '\t';
215           break;
216         case 'b':
217           c2 = '\b';
218           break;
219         case 'f':
220           c2 = '\f';
221           break;
222         case '\\':
223         case '(':
224         case ')':
225           c2 = c;
226           break;
227         case '0': case '1': case '2': case '3':
228         case '4': case '5': case '6': case '7':
229           c2 = c - '0';
230           c = lookChar();
231           if (c >= '0' && c <= '7') {
232             getChar();
233             c2 = (c2 << 3) + (c - '0');
234             c = lookChar();
235             if (c >= '0' && c <= '7') {
236               getChar();
237               c2 = (c2 << 3) + (c - '0');
238             }
239           }
240           break;
241         case '\r':
242           c = lookChar();
243           if (c == '\n')
244             getChar();
245           break;
246         case '\n':
247           break;
248         case EOF:
249           error(getPos(), "Unterminated string");
250           done = gTrue;
251           break;
252         default:
253           c2 = c;
254           break;
255         }
256         break;
257
258       default:
259         c2 = c;
260         break;
261       }
262
263       if (c2 != EOF) {
264         if (n == tokBufSize) {
265           if (!s)
266             s = new GString(tokBuf, tokBufSize);
267           else
268             s->append(tokBuf, tokBufSize);
269           p = tokBuf;
270           n = 0;
271         }
272         *p++ = (char)c2;
273         ++n;
274       }
275     } while (!done);
276     if (!s)
277       s = new GString(tokBuf, n);
278     else
279       s->append(tokBuf, n);
280     obj->initString(s);
281     break;
282
283   // name
284   case '/':
285     p = tokBuf;
286     n = 0;
287     while ((c = lookChar()) != EOF && !(c < 128 && endOfNameChars[c])) {
288       getChar();
289       if (c == '#') {
290         c2 = lookChar();
291         if (c2 >= '0' && c2 <= '9')
292           c = c2 - '0';
293         else if (c2 >= 'A' && c2 <= 'F')
294           c = c2 - 'A' + 10;
295         else if (c2 >= 'a' && c2 <= 'f')
296           c = c2 - 'a' + 10;
297         else
298           goto notEscChar;
299         getChar();
300         c <<= 4;
301         c2 = getChar();
302         if (c2 >= '0' && c2 <= '9')
303           c += c2 - '0';
304         else if (c2 >= 'A' && c2 <= 'F')
305           c += c2 - 'A' + 10;
306         else if (c2 >= 'a' && c2 <= 'f')
307           c += c2 - 'a' + 10;
308         else
309           error(getPos(), "Illegal digit in hex char in name");
310       }
311      notEscChar:
312       if (++n == tokBufSize) {
313         error(getPos(), "Name token too long");
314         break;
315       }
316       *p++ = c;
317     }
318     *p = '\0';
319     obj->initName(tokBuf);
320     break;
321
322   // array punctuation
323   case '[':
324   case ']':
325     tokBuf[0] = c;
326     tokBuf[1] = '\0';
327     obj->initCmd(tokBuf);
328     break;
329
330   // hex string or dict punctuation
331   case '<':
332     c = lookChar();
333
334     // dict punctuation
335     if (c == '<') {
336       getChar();
337       tokBuf[0] = tokBuf[1] = '<';
338       tokBuf[2] = '\0';
339       obj->initCmd(tokBuf);
340
341     // hex string
342     } else {
343       p = tokBuf;
344       m = n = 0;
345       c2 = 0;
346       s = NULL;
347       while (1) {
348         c = getChar();
349         if (c == '>') {
350           break;
351         } else if (c == EOF) {
352           error(getPos(), "Unterminated hex string");
353           break;
354         } else if (!isspace(c)) {
355           c2 = c2 << 4;
356           if (c >= '0' && c <= '9')
357             c2 += c - '0';
358           else if (c >= 'A' && c <= 'F')
359             c2 += c - 'A' + 10;
360           else if (c >= 'a' && c <= 'f')
361             c2 += c - 'a' + 10;
362           else
363             error(getPos(), "Illegal character <%02x> in hex string", c);
364           if (++m == 2) {
365             if (n == tokBufSize) {
366               if (!s)
367                 s = new GString(tokBuf, tokBufSize);
368               else
369                 s->append(tokBuf, tokBufSize);
370               p = tokBuf;
371               n = 0;
372             }
373             *p++ = (char)c2;
374             ++n;
375             c2 = 0;
376             m = 0;
377           }
378         }
379       }
380       if (!s)
381         s = new GString(tokBuf, n);
382       else
383         s->append(tokBuf, n);
384       if (m == 1)
385         s->append((char)(c2 << 4));
386       obj->initString(s);
387     }
388     break;
389
390   // dict punctuation
391   case '>':
392     c = lookChar();
393     if (c == '>') {
394       getChar();
395       tokBuf[0] = tokBuf[1] = '>';
396       tokBuf[2] = '\0';
397       obj->initCmd(tokBuf);
398     } else {
399       error(getPos(), "Illegal character '>'");
400       obj->initError();
401     }
402     break;
403
404   // error
405   case ')':
406   case '{':
407   case '}':
408     error(getPos(), "Illegal character '%c'", c);
409     obj->initError();
410     break;
411
412   // command
413   default:
414     p = tokBuf;
415     *p++ = c;
416     n = 1;
417     while ((c = lookChar()) != EOF && !(c < 128 && endOfNameChars[c])) {
418       getChar();
419       if (++n == tokBufSize) {
420         error(getPos(), "Command token too long");
421         break;
422       }
423       *p++ = c;
424     }
425     *p = '\0';
426     if (tokBuf[0] == 't' && !strcmp(tokBuf, "true"))
427       obj->initBool(gTrue);
428     else if (tokBuf[0] == 'f' && !strcmp(tokBuf, "false"))
429       obj->initBool(gFalse);
430     else if (tokBuf[0] == 'n' && !strcmp(tokBuf, "null"))
431       obj->initNull();
432     else
433       obj->initCmd(tokBuf);
434     break;
435   }
436
437   return obj;
438 }
439
440 void Lexer::skipToNextLine() {
441   int c;
442
443   while (1) {
444     c = getChar();
445     if (c == EOF || c == '\n')
446       return;
447     if (c == '\r') {
448       if ((c = lookChar()) == '\n')
449         getChar();
450       return;
451     }
452   }
453 }