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

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

First import

File size: 9.7 KB
Line 
1//========================================================================
2//
3// Lexer.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 <stdlib.h>
16#include <stddef.h>
17#include <string.h>
18#include <ctype.h>
19#include "Lexer.h"
20#include "Error.h"
21#include "XRef.h"
22
23//------------------------------------------------------------------------
24
25// A '1' in this array means the character is white space.  A '1' or
26// '2' means the character ends a name or command.
27static char specialChars[256] = {
28  1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0,   // 0x
29  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 1x
30  1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2,   // 2x
31  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0,   // 3x
32  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 4x
33  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0,   // 5x
34  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 6x
35  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0,   // 7x
36  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 8x
37  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 9x
38  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // ax
39  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // bx
40  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // cx
41  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // dx
42  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // ex
43  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0    // fx
44};
45
46//------------------------------------------------------------------------
47// Lexer
48//------------------------------------------------------------------------
49
50Lexer::Lexer(XRef *xrefA, Stream *str) {
51  Object obj;
52
53  xref = xrefA;
54
55  curStr.initStream(str);
56  streams = new Array(xref);
57  streams->add(curStr.copy(&obj));
58  strPtr = 0;
59  freeArray = gTrue;
60  curStr.streamReset();
61}
62
63Lexer::Lexer(XRef *xrefA, Object *obj) {
64  Object obj2;
65
66  xref = xrefA;
67
68  if (obj->isStream()) {
69    streams = new Array(xref);
70    freeArray = gTrue;
71    streams->add(obj->copy(&obj2));
72  } else {
73    streams = obj->getArray();
74    freeArray = gFalse;
75  }
76  strPtr = 0;
77  if (streams->getLength() > 0) {
78    streams->get(strPtr, &curStr);
79    curStr.streamReset();
80  }
81}
82
83Lexer::~Lexer() {
84  if (!curStr.isNone()) {
85    curStr.streamClose();
86    curStr.free();
87  }
88  if (freeArray) {
89    delete streams;
90  }
91}
92
93int Lexer::getChar() {
94  int c;
95
96  c = EOF;
97  while (!curStr.isNone() && (c = curStr.streamGetChar()) == EOF) {
98    curStr.streamClose();
99    curStr.free();
100    ++strPtr;
101    if (strPtr < streams->getLength()) {
102      streams->get(strPtr, &curStr);
103      curStr.streamReset();
104    }
105  }
106  return c;
107}
108
109int Lexer::lookChar() {
110  if (curStr.isNone()) {
111    return EOF;
112  }
113  return curStr.streamLookChar();
114}
115
116Object *Lexer::getObj(Object *obj, int objNum) {
117  char *p;
118  int c, c2;
119  GBool comment, neg, done;
120  int numParen;
121  int xi;
122  double xf, scale;
123  GooString *s;
124  int n, m;
125
126  // skip whitespace and comments
127  comment = gFalse;
128  while (1) {
129    if ((c = getChar()) == EOF) {
130      return obj->initEOF();
131    }
132    if (comment) {
133      if (c == '\r' || c == '\n')
134        comment = gFalse;
135    } else if (c == '%') {
136      comment = gTrue;
137    } else if (specialChars[c] != 1) {
138      break;
139    }
140  }
141
142  // start reading token
143  switch (c) {
144
145  // number
146  case '0': case '1': case '2': case '3': case '4':
147  case '5': case '6': case '7': case '8': case '9':
148  case '-': case '.':
149    neg = gFalse;
150    xi = 0;
151    if (c == '-') {
152      neg = gTrue;
153    } else if (c == '.') {
154      goto doReal;
155    } else {
156      xi = c - '0';
157    }
158    while (1) {
159      c = lookChar();
160      if (isdigit(c)) {
161        getChar();
162        xi = xi * 10 + (c - '0');
163      } else if (c == '.') {
164        getChar();
165        goto doReal;
166      } else {
167        break;
168      }
169    }
170    if (neg)
171      xi = -xi;
172    obj->initInt(xi);
173    break;
174  doReal:
175    xf = xi;
176    scale = 0.1;
177    while (1) {
178      c = lookChar();
179      if (c == '-') {
180        // ignore minus signs in the middle of numbers to match
181        // Adobe's behavior
182        error(getPos(), "Badly formatted number");
183        getChar();
184        continue;
185      }
186      if (!isdigit(c)) {
187        break;
188      }
189      getChar();
190      xf = xf + scale * (c - '0');
191      scale *= 0.1;
192    }
193    if (neg)
194      xf = -xf;
195    obj->initReal(xf);
196    break;
197
198  // string
199  case '(':
200    p = tokBuf;
201    n = 0;
202    numParen = 1;
203    done = gFalse;
204    s = NULL;
205    do {
206      c2 = EOF;
207      switch (c = getChar()) {
208
209      case EOF:
210#if 0
211      // This breaks some PDF files, e.g., ones from Photoshop.
212      case '\r':
213      case '\n':
214#endif
215        error(getPos(), "Unterminated string");
216        done = gTrue;
217        break;
218
219      case '(':
220        ++numParen;
221        c2 = c;
222        break;
223
224      case ')':
225        if (--numParen == 0) {
226          done = gTrue;
227        } else {
228          c2 = c;
229        }
230        break;
231
232      case '\\':
233        switch (c = getChar()) {
234        case 'n':
235          c2 = '\n';
236          break;
237        case 'r':
238          c2 = '\r';
239          break;
240        case 't':
241          c2 = '\t';
242          break;
243        case 'b':
244          c2 = '\b';
245          break;
246        case 'f':
247          c2 = '\f';
248          break;
249        case '\\':
250        case '(':
251        case ')':
252          c2 = c;
253          break;
254        case '0': case '1': case '2': case '3':
255        case '4': case '5': case '6': case '7':
256          c2 = c - '0';
257          c = lookChar();
258          if (c >= '0' && c <= '7') {
259            getChar();
260            c2 = (c2 << 3) + (c - '0');
261            c = lookChar();
262            if (c >= '0' && c <= '7') {
263              getChar();
264              c2 = (c2 << 3) + (c - '0');
265            }
266          }
267          break;
268        case '\r':
269          c = lookChar();
270          if (c == '\n') {
271            getChar();
272          }
273          break;
274        case '\n':
275          break;
276        case EOF:
277          error(getPos(), "Unterminated string");
278          done = gTrue;
279          break;
280        default:
281          c2 = c;
282          break;
283        }
284        break;
285
286      default:
287        c2 = c;
288        break;
289      }
290
291      if (c2 != EOF) {
292        if (n == tokBufSize) {
293          if (!s)
294            s = new GooString(tokBuf, tokBufSize);
295          else
296            s->append(tokBuf, tokBufSize);
297          p = tokBuf;
298          n = 0;
299         
300          // we are growing see if the document is not malformed and we are growing too much
301          if (objNum != -1)
302          {
303            int newObjNum = xref->getNumEntry(getPos());
304            if (newObjNum != objNum)
305            {
306              error(getPos(), "Unterminated string");
307              done = gTrue;
308            }
309          }
310        }
311        *p++ = (char)c2;
312        ++n;
313      }
314    } while (!done);
315    if (!s)
316      s = new GooString(tokBuf, n);
317    else
318      s->append(tokBuf, n);
319    obj->initString(s);
320    break;
321
322  // name
323  case '/':
324    p = tokBuf;
325    n = 0;
326    while ((c = lookChar()) != EOF && !specialChars[c]) {
327      getChar();
328      if (c == '#') {
329        c2 = lookChar();
330        if (c2 >= '0' && c2 <= '9') {
331          c = c2 - '0';
332        } else if (c2 >= 'A' && c2 <= 'F') {
333          c = c2 - 'A' + 10;
334        } else if (c2 >= 'a' && c2 <= 'f') {
335          c = c2 - 'a' + 10;
336        } else {
337          goto notEscChar;
338        }
339        getChar();
340        c <<= 4;
341        c2 = getChar();
342        if (c2 >= '0' && c2 <= '9') {
343          c += c2 - '0';
344        } else if (c2 >= 'A' && c2 <= 'F') {
345          c += c2 - 'A' + 10;
346        } else if (c2 >= 'a' && c2 <= 'f') {
347          c += c2 - 'a' + 10;
348        } else {
349          error(getPos(), "Illegal digit in hex char in name");
350        }
351      }
352     notEscChar:
353      if (++n == tokBufSize) {
354        error(getPos(), "Name token too long");
355        break;
356      }
357      *p++ = c;
358    }
359    *p = '\0';
360    obj->initName(tokBuf);
361    break;
362
363  // array punctuation
364  case '[':
365  case ']':
366    tokBuf[0] = c;
367    tokBuf[1] = '\0';
368    obj->initCmd(tokBuf);
369    break;
370
371  // hex string or dict punctuation
372  case '<':
373    c = lookChar();
374
375    // dict punctuation
376    if (c == '<') {
377      getChar();
378      tokBuf[0] = tokBuf[1] = '<';
379      tokBuf[2] = '\0';
380      obj->initCmd(tokBuf);
381
382    // hex string
383    } else {
384      p = tokBuf;
385      m = n = 0;
386      c2 = 0;
387      s = NULL;
388      while (1) {
389        c = getChar();
390        if (c == '>') {
391          break;
392        } else if (c == EOF) {
393          error(getPos(), "Unterminated hex string");
394          break;
395        } else if (specialChars[c] != 1) {
396          c2 = c2 << 4;
397          if (c >= '0' && c <= '9')
398            c2 += c - '0';
399          else if (c >= 'A' && c <= 'F')
400            c2 += c - 'A' + 10;
401          else if (c >= 'a' && c <= 'f')
402            c2 += c - 'a' + 10;
403          else
404            error(getPos(), "Illegal character <%02x> in hex string", c);
405          if (++m == 2) {
406            if (n == tokBufSize) {
407              if (!s)
408                s = new GooString(tokBuf, tokBufSize);
409              else
410                s->append(tokBuf, tokBufSize);
411              p = tokBuf;
412              n = 0;
413            }
414            *p++ = (char)c2;
415            ++n;
416            c2 = 0;
417            m = 0;
418          }
419        }
420      }
421      if (!s)
422        s = new GooString(tokBuf, n);
423      else
424        s->append(tokBuf, n);
425      if (m == 1)
426        s->append((char)(c2 << 4));
427      obj->initString(s);
428    }
429    break;
430
431  // dict punctuation
432  case '>':
433    c = lookChar();
434    if (c == '>') {
435      getChar();
436      tokBuf[0] = tokBuf[1] = '>';
437      tokBuf[2] = '\0';
438      obj->initCmd(tokBuf);
439    } else {
440      error(getPos(), "Illegal character '>'");
441      obj->initError();
442    }
443    break;
444
445  // error
446  case ')':
447  case '{':
448  case '}':
449    error(getPos(), "Illegal character '%c'", c);
450    obj->initError();
451    break;
452
453  // command
454  default:
455    p = tokBuf;
456    *p++ = c;
457    n = 1;
458    while ((c = lookChar()) != EOF && !specialChars[c]) {
459      getChar();
460      if (++n == tokBufSize) {
461        error(getPos(), "Command token too long");
462        break;
463      }
464      *p++ = c;
465    }
466    *p = '\0';
467    if (tokBuf[0] == 't' && !strcmp(tokBuf, "true")) {
468      obj->initBool(gTrue);
469    } else if (tokBuf[0] == 'f' && !strcmp(tokBuf, "false")) {
470      obj->initBool(gFalse);
471    } else if (tokBuf[0] == 'n' && !strcmp(tokBuf, "null")) {
472      obj->initNull();
473    } else {
474      obj->initCmd(tokBuf);
475    }
476    break;
477  }
478
479  return obj;
480}
481
482void Lexer::skipToNextLine() {
483  int c;
484
485  while (1) {
486    c = getChar();
487    if (c == EOF || c == '\n') {
488      return;
489    }
490    if (c == '\r') {
491      if ((c = lookChar()) == '\n') {
492        getChar();
493      }
494      return;
495    }
496  }
497}
498
499GBool Lexer::isSpace(int c) {
500  return c >= 0 && c <= 0xff && specialChars[c] == 1;
501}
Note: See TracBrowser for help on using the repository browser.