home *** CD-ROM | disk | FTP | other *** search
- //========================================================================
- //
- // Lexer.cc
- //
- // Copyright 1996 Derek B. Noonburg
- //
- //========================================================================
- //
- // Ported to EPOC by Sander van der Wal
- //
- // $Log: Lexer.cpp $
- // Revision 1.3 2000-09-21 14:45:15+02 svdwal
- // Xpdf 0.91 bugfix added
- //
- // Revision 1.2 2000-09-17 13:38:23+02 svdwal
- // Ported
- //
-
- #ifdef __GNUC__
- #pragma implementation
- #endif
-
- #ifndef __E32DEF_H__
- #include <e32def.h> // remove warning about NULL redefinition
- #endif
-
- #include <ctype.h>
-
- #include "Lexer.h"
- #include "Error.h"
-
- #include "Pdf.rsg"
- #include "PROFILE.h"
-
- //------------------------------------------------------------------------
-
- // A '1' in this array means the corresponding character ends a name
- // or command.
- static const char endOfNameChars[128] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, // 2x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, // 3x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, // 5x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0 // 7x
- };
-
- //------------------------------------------------------------------------
- // Lexer
- //------------------------------------------------------------------------
- Lexer::Lexer(Stream* str)
- {
- curStr.initStream(str);
- }
-
- void Lexer::ConstructL() {
- RAutoObject obj;
-
- freeArray = gTrue;
- streams = new(ELeave) Array();
- streams->addL(curStr.copyL(&obj));
- obj.initNull();
- strPtr = 0;
-
- curStr.streamReset();
- }
-
- Lexer::Lexer() {}
-
- void Lexer::ConstructL(Object *obj) {
-
- if (obj->isStream()) {
- RAutoObject obj2;
- freeArray = gTrue;
- streams = new(ELeave) Array();
- streams->addL(obj->copyL(&obj2));
- obj2.initNull();
- } else {
- streams = obj->getArray();
- freeArray = gFalse;
- }
- strPtr = 0;
- if (streams->getLength() > 0) {
- streams->getL(strPtr, &curStr);
- curStr.streamReset();
- }
- }
-
- Lexer::~Lexer() {
- if (!curStr.isNone())
- curStr.free();
- if (freeArray)
- delete streams;
- }
-
- int Lexer::getChar() {
- register int c;
-
- c = curStr.isNone() ? EOF : curStr.streamGetChar();
- if (c != EOF)
- return c;
- while (!curStr.isNone() && (c == EOF)) {
- curStr.free();
- ++strPtr;
- if (strPtr < streams->getLength()) {
- streams->getL(strPtr, &curStr);
- curStr.streamReset();
- c = curStr.streamGetChar();
- }
- }
- return c;
- }
-
- int Lexer::lookChar() {
- register int c;
-
- c = curStr.isNone() ? EOF : curStr.streamLookChar();
- if (c != EOF)
- return c;
- while (!curStr.isNone() && (c == EOF)) {
- curStr.free();
- ++strPtr;
- if (strPtr < streams->getLength()) {
- streams->getL(strPtr, &curStr);
- curStr.streamReset();
- c = curStr.streamLookChar();
- }
- }
- return c;
- }
-
- Object *Lexer::getObjL(Object *obj) {
-
- PROFILE_START(LEXER__GETOBJ);
-
- register char *p;
- register int c;
- GBool comment, done;
- int numParen;
- register GString *s;
- int n; //, m;
-
- // skip whitespace and comments
- comment = gFalse;
- for(;;) {
- if ((c = getChar()) == EOF)
- return obj->initEOF();
- if (comment) {
- if (c == '\r' || c == '\n')
- comment = gFalse;
- } else if (c == '%') {
- comment = gTrue;
- } else if (!isspace(c)) {
- break;
- }
- }
-
- // start reading token
- switch (c) {
-
- // number
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- case '-': case '.':
- {
- GBool neg = gFalse;
- register int xi = 0;
- if (c == '-') {
- neg = gTrue;
- } else if (c == '.') {
- goto doReal;
- } else {
- xi = c - '0';
- }
- for(;;) {
- c = lookChar();
- if (isdigit(c)) {
- getChar();
- xi = xi * 10 + (c - '0');
- } else if (c == '.') {
- getChar();
- goto doReal;
- } else {
- break;
- }
- }
- if (neg)
- xi = -xi;
- obj->initInt(xi);
- break;
- doReal:
- register int scale = 1;
- for(;;) {
- c = lookChar();
- if (!isdigit(c))
- break;
- getChar();
- xi = 10 * xi + (c - '0');
- scale *= 10;
- }
- if (neg)
- xi = -xi;
- obj->initReal(double(xi)/scale);
- }
- break;
-
- // string
- case '(':
- p = tokBuf;
- n = 0;
- numParen = 1;
- done = gFalse;
- s = NULL;
- do {
- register int c2 = EOF;
- switch (c = getChar()) {
-
- case EOF:
- #if 0 // This breaks some PDF files, e.g., ones from Photoshop.
- case '\r':
- case '\n':
- #endif
- error(getPos(), R_UNTERMINATED_STRING);
- done = gTrue;
- break;
-
- case '(':
- ++numParen;
- break;
-
- case ')':
- if (--numParen == 0)
- done = gTrue;
- break;
-
- case '\\':
- switch (c = getChar()) {
- case 'n':
- c2 = '\n';
- break;
- case 'r':
- c2 = '\r';
- break;
- case 't':
- c2 = '\t';
- break;
- case 'b':
- c2 = '\b';
- break;
- case 'f':
- c2 = '\f';
- break;
- case '\\':
- case '(':
- case ')':
- c2 = c;
- break;
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- c2 = c - '0';
- c = lookChar();
- if (c >= '0' && c <= '7') {
- getChar();
- c2 = (c2 << 3) + (c - '0');
- c = lookChar();
- if (c >= '0' && c <= '7') {
- getChar();
- c2 = (c2 << 3) + (c - '0');
- }
- }
- break;
- case '\r':
- c = lookChar();
- if (c == '\n')
- getChar();
- break;
- case '\n':
- break;
- case EOF:
- error(getPos(), R_UNTERMINATED_STRING);
- done = gTrue;
- break;
- default:
- c2 = c;
- break;
- }
- break;
-
- default:
- c2 = c;
- break;
- }
-
- if (c2 != EOF) {
- if (n == tokBufSize) {
- if (!s)
- s = GString::NewLC(tokBuf, tokBufSize);
- else
- s->appendL(tokBuf, tokBufSize);
- p = tokBuf;
- n = 0;
- }
- *p++ = (char)c2;
- ++n;
- }
- } while (!done);
- if (!s)
- s = GString::NewLC(tokBuf, n);
- else
- s->appendL(tokBuf, n);
- CleanupStack::Pop(); // s
- obj->initString(s);
- break;
-
- // name
- case '/':
- p = tokBuf;
- n = 0;
- while ((c = lookChar()) != EOF && !(c < 128 && endOfNameChars[c])) {
- getChar();
- if (c == '#') {
- register int c2 = lookChar();
- if (c2 >= '0' && c2 <= '9')
- c = c2 - '0';
- else if (c2 >= 'A' && c2 <= 'F')
- c = c2 - 'A' + 10;
- else if (c2 >= 'a' && c2 <= 'f')
- c = c2 - 'a' + 10;
- else
- goto notEscChar;
- getChar();
- c <<= 4;
- c2 = getChar();
- if (c2 >= '0' && c2 <= '9')
- c += c2 - '0';
- else if (c2 >= 'A' && c2 <= 'F')
- c += c2 - 'A' + 10;
- else if (c2 >= 'a' && c2 <= 'f')
- c += c2 - 'a' + 10;
- else
- error(getPos(), R_ILLEGAL_DIGIT_IN_HEX_CHAR_IN_NAME);
- }
- notEscChar:
- if (++n == tokBufSize) {
- error(getPos(), R_NAME_TOKEN_TOO_LONG);
- break;
- }
- *p++ = (char)c;
- }
- *p = '\0';
- obj->initNameL(tokBuf);
- break;
-
- // array punctuation
- case '[':
- case ']':
- tokBuf[0] = (char)c;
- tokBuf[1] = '\0';
- obj->initCmdL(tokBuf);
- break;
-
- // hex string or dict punctuation
- case '<':
- c = lookChar();
-
- // dict punctuation
- if (c == '<') {
- getChar();
- tokBuf[0] = tokBuf[1] = '<';
- tokBuf[2] = '\0';
- obj->initCmdL(tokBuf);
-
- // hex string
- } else {
- obj->initNull();
- p = tokBuf;
- int m = n = 0;
- register int c2 = 0;
- s = NULL;
- for(;;) {
- c = getChar();
- if (c == '>') {
- break;
- }
- else if (c == EOF) {
- error(getPos(), R_UNTERMINATED_HEX_STRING);
- break;
- }
- else if (!isspace(c)) {
- c2 = c2 << 4;
- if (c >= '0' && c <= '9')
- c2 += c - '0';
- else if (c >= 'A' && c <= 'F')
- c2 += c - 'A' + 10;
- else if (c >= 'a' && c <= 'f')
- c2 += c - 'a' + 10;
- else
- error(getPos(), R_ILLEGAL_CHARACTER___02X__IN_HEX_STRING, c);
- if (++m == 2) {
- if (n == tokBufSize) {
- if (!s)
- s = GString::NewLC(tokBuf, tokBufSize);
- else
- s->appendL(tokBuf, tokBufSize);
- p = tokBuf;
- n = 0;
- }
- *p++ = (char)c2;
- ++n;
- c2 = 0;
- m = 0;
- }
- }
- }
- if (!s)
- s = GString::NewLC(tokBuf, n);
- else
- s->appendL(tokBuf, n);
- if (m == 1)
- s->appendL((char)(c2 << 4));
- CleanupStack::Pop(); // s
- obj->initString(s);
- }
- break;
-
- // dict punctuation
- case '>':
- c = lookChar();
- if (c == '>') {
- getChar();
- tokBuf[0] = tokBuf[1] = '>';
- tokBuf[2] = '\0';
- obj->initCmdL(tokBuf);
- } else {
- error(getPos(), R_ILLEGAL_CHARACTER___C_, '>');
- obj->initError();
- }
- break;
-
- // error
- case ')':
- case '{':
- case '}':
- error(getPos(), R_ILLEGAL_CHARACTER___C_, c);
- obj->initError();
- break;
-
- // command
- default:
- p = tokBuf;
- *p++ = (char)c;
- n = 1;
- while ((c = lookChar()) != EOF && !(c < 128 && endOfNameChars[c])) {
- getChar();
- if (++n == tokBufSize) {
- error(getPos(), R_COMMAND_TOKEN_TOO_LONG);
- break;
- }
- *p++ = (char)c;
- }
- *p = '\0';
- if (tokBuf[0] == 't' && !strcmp(tokBuf, "true"))
- obj->initBool(gTrue);
- else if (tokBuf[0] == 'f' && !strcmp(tokBuf, "false"))
- obj->initBool(gFalse);
- else if (tokBuf[0] == 'n' && !strcmp(tokBuf, "null"))
- obj->initNull();
- else
- obj->initCmdL(tokBuf);
- break;
- }
-
- PROFILE_STOP(LEXER__GETOBJ);
-
- return obj;
- }
-
- void Lexer::skipToNextLine() {
- int c;
-
- for(;;) {
- c = getChar();
- if (c == EOF || c == '\n')
- return;
- if (c == '\r') {
- if ((c = lookChar()) == '\n')
- getChar();
- return;
- }
- }
- }
-