--- a/modules/libpref/prefread.cpp
+++ b/modules/libpref/prefread.cpp
@@ -13,39 +13,40 @@
#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
+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
+#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";
/**
@@ -64,112 +65,119 @@ static const char kFalse[] = "false";
* 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)
+pref_GrowBuf(PrefParseState* ps)
{
- int bufLen, curPos, valPos;
+ int bufLen, curPos, valPos;
- bufLen = ps->lbend - ps->lb;
- curPos = ps->lbcur - ps->lb;
- valPos = ps->vb - ps->lb;
+ 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 */
+ if (bufLen == 0)
+ bufLen = 128; /* default buffer size */
+ else
+ bufLen <<= 1; /* double buffer size */
#ifdef TEST_PREFREAD
- fprintf(stderr, ">>> realloc(%d)\n", bufLen);
+ fprintf(stderr, ">>> realloc(%d)\n", bufLen);
#endif
- ps->lb = (char*) realloc(ps->lb, bufLen);
- if (!ps->lb)
- return false;
+ 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;
+ ps->lbcur = ps->lb + curPos;
+ ps->lbend = ps->lb + bufLen;
+ ps->vb = ps->lb + valPos;
- return true;
+ 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)
+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);
- }
+ 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)
+pref_DoCallback(PrefParseState* ps)
{
- PrefValue value;
+ PrefValue value;
- switch (ps->vtype) {
+ switch (ps->vtype) {
case PrefType::String:
- value.stringVal = ps->vb;
- break;
+ 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;
+ 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;
+ value.boolVal = (ps->vb == kTrue);
+ break;
default:
- break;
- }
- (*ps->reader)(ps->closure, ps->lb, value, ps->vtype, ps->fdefault,
- ps->fstickydefault);
- return true;
+ 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)
+PREF_InitParseState(PrefParseState* ps,
+ PrefReader reader,
+ PrefParseErrorReporter reporter,
+ void* closure)
{
- memset(ps, 0, sizeof(*ps));
- ps->reader = reader;
- ps->closure = closure;
- ps->reporter = reporter;
+ memset(ps, 0, sizeof(*ps));
+ ps->reader = reader;
+ ps->closure = closure;
+ ps->reporter = reporter;
}
void
-PREF_FinalizeParseState(PrefParseState *ps)
+PREF_FinalizeParseState(PrefParseState* ps)
{
- if (ps->lb)
- free(ps->lb);
+ 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 ";"
@@ -184,474 +192,459 @@ PREF_FinalizeParseState(PrefParseState *
* 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)
+PREF_ParseBuf(PrefParseState* ps, const char* buf, int bufLen)
{
- const char *end;
- char c;
- char udigit;
- int state;
+ 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;
- // The line number is currently only used for the error/warning reporting.
- int lineNum = 0;
+ /* 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;
- state = ps->state;
- for (end = buf + bufLen; buf != end; ++buf) {
- c = *buf;
- if (c == '\r' || c == '\n' || c == 0x1A) {
- lineNum ++;
+ /* 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;
}
- 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;
- }
+ /* 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;
- 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;
+ } else {
+ /* a single utf16 character */
+ ps->utf16[0] = ps->utf16[1];
+ utf16len = 1;
+ }
- /* 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;
+ /* 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;
- /* 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];
+ ConvertUTF16toUTF8 converter(ps->lbcur);
+ converter.write(ps->utf16, utf16len);
+ ps->lbcur += converter.Size();
+ state = PREF_PARSE_QUOTED_STRING;
+ }
+ break;
- /* 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
+ /* 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;
+ --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 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;
+ /* 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.
+ /* 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;
+ if (c == '\r' || c == '\n' || c == 0x1A) {
+ state = ps->nextstate;
+ ps->nextstate = PREF_PARSE_INIT; /* reset next state */
}
+ break;
}
- ps->state = state;
- return true;
+ }
+ ps->state = state;
+ return true;
}
#ifdef TEST_PREFREAD
static void
-pref_reader(void *closure,
- const char *pref,
- PrefValue val,
- PrefType type,
- bool defPref)
+pref_reader(void* closure,
+ const char* pref,
+ PrefValue val,
+ PrefType type,
+ bool defPref)
{
- printf("%spref(\"%s\", ", defPref ? "" : "user_", pref);
- switch (type) {
+ printf("%spref(\"%s\", ", defPref ? "" : "user_", pref);
+ switch (type) {
case PREF_STRING:
- printf("\"%s\");\n", val.stringVal);
- break;
+ printf("\"%s\");\n", val.stringVal);
+ break;
case PREF_INT:
- printf("%i);\n", val.intVal);
- break;
+ printf("%i);\n", val.intVal);
+ break;
case PREF_BOOL:
- printf("%s);\n", val.boolVal == false ? "false" : "true");
- break;
- }
+ printf("%s);\n", val.boolVal == false ? "false" : "true");
+ break;
+ }
}
int
-main(int argc, char **argv)
+main(int argc, char** argv)
{
- PrefParseState ps;
- char buf[4096]; /* i/o buffer */
- FILE *fp;
- int n;
+ PrefParseState ps;
+ char buf[4096]; /* i/o buffer */
+ FILE* fp;
+ int n;
- if (argc == 1) {
- printf("usage: prefread file.js\n");
- return -1;
- }
+ 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;
- }
+ fp = fopen(argv[1], "r");
+ if (!fp) {
+ printf("failed to open file\n");
+ return -1;
+ }
- PREF_InitParseState(&ps, pref_reader, nullptr, nullptr);
+ PREF_InitParseState(&ps, pref_reader, nullptr, nullptr);
- while ((n = fread(buf, 1, sizeof(buf), fp)) > 0)
- PREF_ParseBuf(&ps, buf, n);
+ while ((n = fread(buf, 1, sizeof(buf), fp)) > 0)
+ PREF_ParseBuf(&ps, buf, n);
- PREF_FinalizeParseState(&ps);
+ PREF_FinalizeParseState(&ps);
- fclose(fp);
- return 0;
+ fclose(fp);
+ return 0;
}
#endif /* TEST_PREFREAD */