diff options
Diffstat (limited to 'modules/libpref/prefread.cpp')
-rw-r--r-- | modules/libpref/prefread.cpp | 657 |
1 files changed, 0 insertions, 657 deletions
diff --git a/modules/libpref/prefread.cpp b/modules/libpref/prefread.cpp deleted file mode 100644 index 605dcaac6..000000000 --- a/modules/libpref/prefread.cpp +++ /dev/null @@ -1,657 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include "prefread.h" -#include "nsString.h" -#include "nsUTF8Utils.h" - -#ifdef TEST_PREFREAD -#include <stdio.h> -#define NS_WARNING(_s) printf(">>> " _s "!\n") -#define NS_NOTREACHED(_s) NS_WARNING(_s) -#else -#include "nsDebug.h" // for NS_WARNING -#endif - -/* pref parser states */ -enum { - PREF_PARSE_INIT, - PREF_PARSE_MATCH_STRING, - PREF_PARSE_UNTIL_NAME, - PREF_PARSE_QUOTED_STRING, - PREF_PARSE_UNTIL_COMMA, - PREF_PARSE_UNTIL_VALUE, - PREF_PARSE_INT_VALUE, - PREF_PARSE_COMMENT_MAYBE_START, - PREF_PARSE_COMMENT_BLOCK, - PREF_PARSE_COMMENT_BLOCK_MAYBE_END, - PREF_PARSE_ESC_SEQUENCE, - PREF_PARSE_HEX_ESCAPE, - PREF_PARSE_UTF16_LOW_SURROGATE, - PREF_PARSE_UNTIL_OPEN_PAREN, - PREF_PARSE_UNTIL_CLOSE_PAREN, - PREF_PARSE_UNTIL_SEMICOLON, - PREF_PARSE_UNTIL_EOL -}; - -#define UTF16_ESC_NUM_DIGITS 4 -#define HEX_ESC_NUM_DIGITS 2 -#define BITS_PER_HEX_DIGIT 4 - -static const char kUserPref[] = "user_pref"; -static const char kPref[] = "pref"; -static const char kPrefSticky[] = "sticky_pref"; -static const char kTrue[] = "true"; -static const char kFalse[] = "false"; - -/** - * pref_GrowBuf - * - * this function will increase the size of the buffer owned - * by the given pref parse state. We currently use a simple - * doubling algorithm, but the only hard requirement is that - * it increase the buffer by at least the size of the ps->esctmp - * buffer used for escape processing (currently 6 bytes). - * - * this buffer is used to store partial pref lines. it is - * freed when the parse state is destroyed. - * - * @param ps - * parse state instance - * - * this function updates all pointers that reference an - * address within lb since realloc may relocate the buffer. - * - * @return false if insufficient memory. - */ -static bool -pref_GrowBuf(PrefParseState *ps) -{ - int bufLen, curPos, valPos; - - bufLen = ps->lbend - ps->lb; - curPos = ps->lbcur - ps->lb; - valPos = ps->vb - ps->lb; - - if (bufLen == 0) - bufLen = 128; /* default buffer size */ - else - bufLen <<= 1; /* double buffer size */ - -#ifdef TEST_PREFREAD - fprintf(stderr, ">>> realloc(%d)\n", bufLen); -#endif - - ps->lb = (char*) realloc(ps->lb, bufLen); - if (!ps->lb) - return false; - - ps->lbcur = ps->lb + curPos; - ps->lbend = ps->lb + bufLen; - ps->vb = ps->lb + valPos; - - return true; -} - -/** - * Report an error or a warning. If not specified, just dump to stderr. - */ -static void -pref_ReportParseProblem(PrefParseState& ps, const char* aMessage, int aLine, bool aError) -{ - if (ps.reporter) { - ps.reporter(aMessage, aLine, aError); - } else { - printf_stderr("**** Preference parsing %s (line %d) = %s **\n", - (aError ? "error" : "warning"), aLine, aMessage); - } -} - -/** - * pref_DoCallback - * - * this function is called when a complete pref name-value pair has - * been extracted from the input data. - * - * @param ps - * parse state instance - * - * @return false to indicate a fatal error. - */ -static bool -pref_DoCallback(PrefParseState *ps) -{ - PrefValue value; - - switch (ps->vtype) { - case PrefType::String: - value.stringVal = ps->vb; - break; - case PrefType::Int: - if ((ps->vb[0] == '-' || ps->vb[0] == '+') && ps->vb[1] == '\0') { - pref_ReportParseProblem(*ps, "invalid integer value", 0, true); - NS_WARNING("malformed integer value"); - return false; - } - value.intVal = atoi(ps->vb); - break; - case PrefType::Bool: - value.boolVal = (ps->vb == kTrue); - break; - default: - break; - } - (*ps->reader)(ps->closure, ps->lb, value, ps->vtype, ps->fdefault, - ps->fstickydefault); - return true; -} - -void -PREF_InitParseState(PrefParseState *ps, PrefReader reader, - PrefParseErrorReporter reporter, void *closure) -{ - memset(ps, 0, sizeof(*ps)); - ps->reader = reader; - ps->closure = closure; - ps->reporter = reporter; -} - -void -PREF_FinalizeParseState(PrefParseState *ps) -{ - if (ps->lb) - free(ps->lb); -} - -/** - * Pseudo-BNF - * ---------- - * function = LJUNK function-name JUNK function-args - * function-name = "user_pref" | "pref" | "sticky_pref" - * function-args = "(" JUNK pref-name JUNK "," JUNK pref-value JUNK ")" JUNK ";" - * pref-name = quoted-string - * pref-value = quoted-string | "true" | "false" | integer-value - * JUNK = *(WS | comment-block | comment-line) - * LJUNK = *(WS | comment-block | comment-line | bcomment-line) - * WS = SP | HT | LF | VT | FF | CR - * SP = <US-ASCII SP, space (32)> - * HT = <US-ASCII HT, horizontal-tab (9)> - * LF = <US-ASCII LF, linefeed (10)> - * VT = <US-ASCII HT, vertical-tab (11)> - * FF = <US-ASCII FF, form-feed (12)> - * CR = <US-ASCII CR, carriage return (13)> - * comment-block = <C/C++ style comment block> - * comment-line = <C++ style comment line> - * bcomment-line = <bourne-shell style comment line> - */ -bool -PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen) -{ - const char *end; - char c; - char udigit; - int state; - - // The line number is currently only used for the error/warning reporting. - int lineNum = 0; - - state = ps->state; - for (end = buf + bufLen; buf != end; ++buf) { - c = *buf; - if (c == '\r' || c == '\n' || c == 0x1A) { - lineNum ++; - } - - switch (state) { - /* initial state */ - case PREF_PARSE_INIT: - if (ps->lbcur != ps->lb) { /* reset state */ - ps->lbcur = ps->lb; - ps->vb = nullptr; - ps->vtype = PrefType::Invalid; - ps->fdefault = false; - ps->fstickydefault = false; - } - switch (c) { - case '/': /* begin comment block or line? */ - state = PREF_PARSE_COMMENT_MAYBE_START; - break; - case '#': /* accept shell style comments */ - state = PREF_PARSE_UNTIL_EOL; - break; - case 'u': /* indicating user_pref */ - case 's': /* indicating sticky_pref */ - case 'p': /* indicating pref */ - if (c == 'u') { - ps->smatch = kUserPref; - } else if (c == 's') { - ps->smatch = kPrefSticky; - } else { - ps->smatch = kPref; - } - ps->sindex = 1; - ps->nextstate = PREF_PARSE_UNTIL_OPEN_PAREN; - state = PREF_PARSE_MATCH_STRING; - break; - /* else skip char */ - } - break; - - /* string matching */ - case PREF_PARSE_MATCH_STRING: - if (c == ps->smatch[ps->sindex++]) { - /* if we've matched all characters, then move to next state. */ - if (ps->smatch[ps->sindex] == '\0') { - state = ps->nextstate; - ps->nextstate = PREF_PARSE_INIT; /* reset next state */ - } - /* else wait for next char */ - } - else { - pref_ReportParseProblem(*ps, "non-matching string", lineNum, true); - NS_WARNING("malformed pref file"); - return false; - } - break; - - /* quoted string parsing */ - case PREF_PARSE_QUOTED_STRING: - /* we assume that the initial quote has already been consumed */ - if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps)) - return false; /* out of memory */ - if (c == '\\') - state = PREF_PARSE_ESC_SEQUENCE; - else if (c == ps->quotechar) { - *ps->lbcur++ = '\0'; - state = ps->nextstate; - ps->nextstate = PREF_PARSE_INIT; /* reset next state */ - } - else - *ps->lbcur++ = c; - break; - - /* name parsing */ - case PREF_PARSE_UNTIL_NAME: - if (c == '\"' || c == '\'') { - ps->fdefault = (ps->smatch == kPref || ps->smatch == kPrefSticky); - ps->fstickydefault = (ps->smatch == kPrefSticky); - ps->quotechar = c; - ps->nextstate = PREF_PARSE_UNTIL_COMMA; /* return here when done */ - state = PREF_PARSE_QUOTED_STRING; - } - else if (c == '/') { /* allow embedded comment */ - ps->nextstate = state; /* return here when done with comment */ - state = PREF_PARSE_COMMENT_MAYBE_START; - } - else if (!isspace(c)) { - pref_ReportParseProblem(*ps, "need space, comment or quote", lineNum, true); - NS_WARNING("malformed pref file"); - return false; - } - break; - - /* parse until we find a comma separating name and value */ - case PREF_PARSE_UNTIL_COMMA: - if (c == ',') { - ps->vb = ps->lbcur; - state = PREF_PARSE_UNTIL_VALUE; - } - else if (c == '/') { /* allow embedded comment */ - ps->nextstate = state; /* return here when done with comment */ - state = PREF_PARSE_COMMENT_MAYBE_START; - } - else if (!isspace(c)) { - pref_ReportParseProblem(*ps, "need space, comment or comma", lineNum, true); - NS_WARNING("malformed pref file"); - return false; - } - break; - - /* value parsing */ - case PREF_PARSE_UNTIL_VALUE: - /* the pref value type is unknown. so, we scan for the first - * character of the value, and determine the type from that. */ - if (c == '\"' || c == '\'') { - ps->vtype = PrefType::String; - ps->quotechar = c; - ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN; - state = PREF_PARSE_QUOTED_STRING; - } - else if (c == 't' || c == 'f') { - ps->vb = (char *) (c == 't' ? kTrue : kFalse); - ps->vtype = PrefType::Bool; - ps->smatch = ps->vb; - ps->sindex = 1; - ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN; - state = PREF_PARSE_MATCH_STRING; - } - else if (isdigit(c) || (c == '-') || (c == '+')) { - ps->vtype = PrefType::Int; - /* write c to line buffer... */ - if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps)) - return false; /* out of memory */ - *ps->lbcur++ = c; - state = PREF_PARSE_INT_VALUE; - } - else if (c == '/') { /* allow embedded comment */ - ps->nextstate = state; /* return here when done with comment */ - state = PREF_PARSE_COMMENT_MAYBE_START; - } - else if (!isspace(c)) { - pref_ReportParseProblem(*ps, "need value, comment or space", lineNum, true); - NS_WARNING("malformed pref file"); - return false; - } - break; - case PREF_PARSE_INT_VALUE: - /* grow line buffer if necessary... */ - if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps)) - return false; /* out of memory */ - if (isdigit(c)) - *ps->lbcur++ = c; - else { - *ps->lbcur++ = '\0'; /* stomp null terminator; we are done. */ - if (c == ')') - state = PREF_PARSE_UNTIL_SEMICOLON; - else if (c == '/') { /* allow embedded comment */ - ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN; - state = PREF_PARSE_COMMENT_MAYBE_START; - } - else if (isspace(c)) - state = PREF_PARSE_UNTIL_CLOSE_PAREN; - else { - pref_ReportParseProblem(*ps, "while parsing integer", lineNum, true); - NS_WARNING("malformed pref file"); - return false; - } - } - break; - - /* comment parsing */ - case PREF_PARSE_COMMENT_MAYBE_START: - switch (c) { - case '*': /* comment block */ - state = PREF_PARSE_COMMENT_BLOCK; - break; - case '/': /* comment line */ - state = PREF_PARSE_UNTIL_EOL; - break; - default: - /* pref file is malformed */ - pref_ReportParseProblem(*ps, "while parsing comment", lineNum, true); - NS_WARNING("malformed pref file"); - return false; - } - break; - case PREF_PARSE_COMMENT_BLOCK: - if (c == '*') - state = PREF_PARSE_COMMENT_BLOCK_MAYBE_END; - break; - case PREF_PARSE_COMMENT_BLOCK_MAYBE_END: - switch (c) { - case '/': - state = ps->nextstate; - ps->nextstate = PREF_PARSE_INIT; - break; - case '*': /* stay in this state */ - break; - default: - state = PREF_PARSE_COMMENT_BLOCK; - } - break; - - /* string escape sequence parsing */ - case PREF_PARSE_ESC_SEQUENCE: - /* not necessary to resize buffer here since we should be writing - * only one character and the resize check would have been done - * for us in the previous state */ - switch (c) { - case '\"': - case '\'': - case '\\': - break; - case 'r': - c = '\r'; - break; - case 'n': - c = '\n'; - break; - case 'x': /* hex escape -- always interpreted as Latin-1 */ - case 'u': /* UTF16 escape */ - ps->esctmp[0] = c; - ps->esclen = 1; - ps->utf16[0] = ps->utf16[1] = 0; - ps->sindex = (c == 'x' ) ? - HEX_ESC_NUM_DIGITS : - UTF16_ESC_NUM_DIGITS; - state = PREF_PARSE_HEX_ESCAPE; - continue; - default: - pref_ReportParseProblem(*ps, "preserving unexpected JS escape sequence", - lineNum, false); - NS_WARNING("preserving unexpected JS escape sequence"); - /* Invalid escape sequence so we do have to write more than - * one character. Grow line buffer if necessary... */ - if ((ps->lbcur+1) == ps->lbend && !pref_GrowBuf(ps)) - return false; /* out of memory */ - *ps->lbcur++ = '\\'; /* preserve the escape sequence */ - break; - } - *ps->lbcur++ = c; - state = PREF_PARSE_QUOTED_STRING; - break; - - /* parsing a hex (\xHH) or utf16 escape (\uHHHH) */ - case PREF_PARSE_HEX_ESCAPE: - if ( c >= '0' && c <= '9' ) - udigit = (c - '0'); - else if ( c >= 'A' && c <= 'F' ) - udigit = (c - 'A') + 10; - else if ( c >= 'a' && c <= 'f' ) - udigit = (c - 'a') + 10; - else { - /* bad escape sequence found, write out broken escape as-is */ - pref_ReportParseProblem(*ps, "preserving invalid or incomplete hex escape", - lineNum, false); - NS_WARNING("preserving invalid or incomplete hex escape"); - *ps->lbcur++ = '\\'; /* original escape slash */ - if ((ps->lbcur + ps->esclen) >= ps->lbend && !pref_GrowBuf(ps)) - return false; - for (int i = 0; i < ps->esclen; ++i) - *ps->lbcur++ = ps->esctmp[i]; - - /* push the non-hex character back for re-parsing. */ - /* (++buf at the top of the loop keeps this safe) */ - --buf; - state = PREF_PARSE_QUOTED_STRING; - continue; - } - - /* have a digit */ - ps->esctmp[ps->esclen++] = c; /* preserve it */ - ps->utf16[1] <<= BITS_PER_HEX_DIGIT; - ps->utf16[1] |= udigit; - ps->sindex--; - if (ps->sindex == 0) { - /* have the full escape. Convert to UTF8 */ - int utf16len = 0; - if (ps->utf16[0]) { - /* already have a high surrogate, this is a two char seq */ - utf16len = 2; - } - else if (0xD800 == (0xFC00 & ps->utf16[1])) { - /* a high surrogate, can't convert until we have the low */ - ps->utf16[0] = ps->utf16[1]; - ps->utf16[1] = 0; - state = PREF_PARSE_UTF16_LOW_SURROGATE; - break; - } - else { - /* a single utf16 character */ - ps->utf16[0] = ps->utf16[1]; - utf16len = 1; - } - - /* actual conversion */ - /* make sure there's room, 6 bytes is max utf8 len (in */ - /* theory; 4 bytes covers the actual utf16 range) */ - if (ps->lbcur+6 >= ps->lbend && !pref_GrowBuf(ps)) - return false; - - ConvertUTF16toUTF8 converter(ps->lbcur); - converter.write(ps->utf16, utf16len); - ps->lbcur += converter.Size(); - state = PREF_PARSE_QUOTED_STRING; - } - break; - - /* looking for beginning of utf16 low surrogate */ - case PREF_PARSE_UTF16_LOW_SURROGATE: - if (ps->sindex == 0 && c == '\\') { - ++ps->sindex; - } - else if (ps->sindex == 1 && c == 'u') { - /* escape sequence is correct, now parse hex */ - ps->sindex = UTF16_ESC_NUM_DIGITS; - ps->esctmp[0] = 'u'; - ps->esclen = 1; - state = PREF_PARSE_HEX_ESCAPE; - } - else { - /* didn't find expected low surrogate. Ignore high surrogate - * (it would just get converted to nothing anyway) and start - * over with this character */ - --buf; - if (ps->sindex == 1) - state = PREF_PARSE_ESC_SEQUENCE; - else - state = PREF_PARSE_QUOTED_STRING; - continue; - } - break; - - /* function open and close parsing */ - case PREF_PARSE_UNTIL_OPEN_PAREN: - /* tolerate only whitespace and embedded comments */ - if (c == '(') - state = PREF_PARSE_UNTIL_NAME; - else if (c == '/') { - ps->nextstate = state; /* return here when done with comment */ - state = PREF_PARSE_COMMENT_MAYBE_START; - } - else if (!isspace(c)) { - pref_ReportParseProblem(*ps, "need space, comment or open parentheses", - lineNum, true); - NS_WARNING("malformed pref file"); - return false; - } - break; - case PREF_PARSE_UNTIL_CLOSE_PAREN: - /* tolerate only whitespace and embedded comments */ - if (c == ')') { - state = PREF_PARSE_UNTIL_SEMICOLON; - } else if (c == '/') { - ps->nextstate = state; /* return here when done with comment */ - state = PREF_PARSE_COMMENT_MAYBE_START; - } else if (!isspace(c)) { - pref_ReportParseProblem(*ps, "need space, comment or closing parentheses", - lineNum, true); - NS_WARNING("malformed pref file"); - return false; - } - break; - - /* function terminator ';' parsing */ - case PREF_PARSE_UNTIL_SEMICOLON: - /* tolerate only whitespace and embedded comments */ - if (c == ';') { - if (!pref_DoCallback(ps)) - return false; - state = PREF_PARSE_INIT; - } - else if (c == '/') { - ps->nextstate = state; /* return here when done with comment */ - state = PREF_PARSE_COMMENT_MAYBE_START; - } - else if (!isspace(c)) { - pref_ReportParseProblem(*ps, "need space, comment or semicolon", - lineNum, true); - NS_WARNING("malformed pref file"); - return false; - } - break; - - /* eol parsing */ - case PREF_PARSE_UNTIL_EOL: - /* need to handle mac, unix, or dos line endings. - * PREF_PARSE_INIT will eat the next \n in case - * we have \r\n. */ - if (c == '\r' || c == '\n' || c == 0x1A) { - state = ps->nextstate; - ps->nextstate = PREF_PARSE_INIT; /* reset next state */ - } - break; - } - } - ps->state = state; - return true; -} - -#ifdef TEST_PREFREAD - -static void -pref_reader(void *closure, - const char *pref, - PrefValue val, - PrefType type, - bool defPref) -{ - printf("%spref(\"%s\", ", defPref ? "" : "user_", pref); - switch (type) { - case PREF_STRING: - printf("\"%s\");\n", val.stringVal); - break; - case PREF_INT: - printf("%i);\n", val.intVal); - break; - case PREF_BOOL: - printf("%s);\n", val.boolVal == false ? "false" : "true"); - break; - } -} - -int -main(int argc, char **argv) -{ - PrefParseState ps; - char buf[4096]; /* i/o buffer */ - FILE *fp; - int n; - - if (argc == 1) { - printf("usage: prefread file.js\n"); - return -1; - } - - fp = fopen(argv[1], "r"); - if (!fp) { - printf("failed to open file\n"); - return -1; - } - - PREF_InitParseState(&ps, pref_reader, nullptr, nullptr); - - while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) - PREF_ParseBuf(&ps, buf, n); - - PREF_FinalizeParseState(&ps); - - fclose(fp); - return 0; -} - -#endif /* TEST_PREFREAD */ |