LCOV - code coverage report
Current view: top level - modules/libpref - prefread.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 185 290 63.8 %
Date: 2017-07-14 16:53:18 Functions: 7 8 87.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       3             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include <stdlib.h>
       6             : #include <string.h>
       7             : #include <ctype.h>
       8             : #include "prefread.h"
       9             : #include "nsString.h"
      10             : #include "nsUTF8Utils.h"
      11             : 
      12             : #ifdef TEST_PREFREAD
      13             : #include <stdio.h>
      14             : #define NS_WARNING(_s) printf(">>> " _s "!\n")
      15             : #define NS_NOTREACHED(_s) NS_WARNING(_s)
      16             : #else
      17             : #include "nsDebug.h" // for NS_WARNING
      18             : #endif
      19             : 
      20             : /* pref parser states */
      21             : enum {
      22             :     PREF_PARSE_INIT,
      23             :     PREF_PARSE_MATCH_STRING,
      24             :     PREF_PARSE_UNTIL_NAME,
      25             :     PREF_PARSE_QUOTED_STRING,
      26             :     PREF_PARSE_UNTIL_COMMA,
      27             :     PREF_PARSE_UNTIL_VALUE,
      28             :     PREF_PARSE_INT_VALUE,
      29             :     PREF_PARSE_COMMENT_MAYBE_START,
      30             :     PREF_PARSE_COMMENT_BLOCK,
      31             :     PREF_PARSE_COMMENT_BLOCK_MAYBE_END,
      32             :     PREF_PARSE_ESC_SEQUENCE,
      33             :     PREF_PARSE_HEX_ESCAPE,
      34             :     PREF_PARSE_UTF16_LOW_SURROGATE,
      35             :     PREF_PARSE_UNTIL_OPEN_PAREN,
      36             :     PREF_PARSE_UNTIL_CLOSE_PAREN,
      37             :     PREF_PARSE_UNTIL_SEMICOLON,
      38             :     PREF_PARSE_UNTIL_EOL
      39             : };
      40             : 
      41             : #define UTF16_ESC_NUM_DIGITS    4
      42             : #define HEX_ESC_NUM_DIGITS      2
      43             : #define BITS_PER_HEX_DIGIT      4
      44             : 
      45             : static const char kUserPref[] = "user_pref";
      46             : static const char kPref[] = "pref";
      47             : static const char kPrefSticky[] = "sticky_pref";
      48             : static const char kTrue[] = "true";
      49             : static const char kFalse[] = "false";
      50             : 
      51             : /**
      52             :  * pref_GrowBuf
      53             :  *
      54             :  * this function will increase the size of the buffer owned
      55             :  * by the given pref parse state.  We currently use a simple
      56             :  * doubling algorithm, but the only hard requirement is that
      57             :  * it increase the buffer by at least the size of the ps->esctmp
      58             :  * buffer used for escape processing (currently 6 bytes).
      59             :  *
      60             :  * this buffer is used to store partial pref lines.  it is
      61             :  * freed when the parse state is destroyed.
      62             :  *
      63             :  * @param ps
      64             :  *        parse state instance
      65             :  *
      66             :  * this function updates all pointers that reference an
      67             :  * address within lb since realloc may relocate the buffer.
      68             :  *
      69             :  * @return false if insufficient memory.
      70             :  */
      71             : static bool
      72          68 : pref_GrowBuf(PrefParseState *ps)
      73             : {
      74             :     int bufLen, curPos, valPos;
      75             : 
      76          68 :     bufLen = ps->lbend - ps->lb;
      77          68 :     curPos = ps->lbcur - ps->lb;
      78          68 :     valPos = ps->vb    - ps->lb;
      79             : 
      80          68 :     if (bufLen == 0)
      81          35 :         bufLen = 128;  /* default buffer size */
      82             :     else
      83          33 :         bufLen <<= 1;  /* double buffer size */
      84             : 
      85             : #ifdef TEST_PREFREAD
      86             :     fprintf(stderr, ">>> realloc(%d)\n", bufLen);
      87             : #endif
      88             : 
      89          68 :     ps->lb = (char*) realloc(ps->lb, bufLen);
      90          68 :     if (!ps->lb)
      91           0 :         return false;
      92             : 
      93          68 :     ps->lbcur = ps->lb + curPos;
      94          68 :     ps->lbend = ps->lb + bufLen;
      95          68 :     ps->vb    = ps->lb + valPos;
      96             : 
      97          68 :     return true;
      98             : }
      99             : 
     100             : /**
     101             :  * Report an error or a warning.  If not specified, just dump to stderr.
     102             :  */
     103             : static void
     104           0 : pref_ReportParseProblem(PrefParseState& ps, const char* aMessage, int aLine, bool aError)
     105             : {
     106           0 :     if (ps.reporter) {
     107           0 :         ps.reporter(aMessage, aLine, aError);
     108             :     } else {
     109           0 :         printf_stderr("**** Preference parsing %s (line %d) = %s **\n",
     110           0 :                       (aError ? "error" : "warning"), aLine, aMessage);
     111             :     }
     112           0 : }
     113             : 
     114             : /**
     115             :  * pref_DoCallback
     116             :  *
     117             :  * this function is called when a complete pref name-value pair has
     118             :  * been extracted from the input data.
     119             :  *
     120             :  * @param ps
     121             :  *        parse state instance
     122             :  *
     123             :  * @return false to indicate a fatal error.
     124             :  */
     125             : static bool
     126        9303 : pref_DoCallback(PrefParseState *ps)
     127             : {
     128             :     PrefValue  value;
     129             : 
     130        9303 :     switch (ps->vtype) {
     131             :     case PrefType::String:
     132        2400 :         value.stringVal = ps->vb;
     133        2400 :         break;
     134             :     case PrefType::Int:
     135        2394 :         if ((ps->vb[0] == '-' || ps->vb[0] == '+') && ps->vb[1] == '\0') {
     136           0 :             pref_ReportParseProblem(*ps, "invalid integer value", 0, true);
     137           0 :             NS_WARNING("malformed integer value");
     138           0 :             return false;
     139             :         }
     140        2394 :         value.intVal = atoi(ps->vb);
     141        2394 :         break;
     142             :     case PrefType::Bool:
     143        4509 :         value.boolVal = (ps->vb == kTrue);
     144        4509 :         break;
     145             :     default:
     146           0 :         break;
     147             :     }
     148       18606 :     (*ps->reader)(ps->closure, ps->lb, value, ps->vtype, ps->fdefault,
     149       18606 :                   ps->fstickydefault);
     150        9303 :     return true;
     151             : }
     152             : 
     153             : void
     154          35 : PREF_InitParseState(PrefParseState *ps, PrefReader reader,
     155             :                     PrefParseErrorReporter reporter, void *closure)
     156             : {
     157          35 :     memset(ps, 0, sizeof(*ps));
     158          35 :     ps->reader = reader;
     159          35 :     ps->closure = closure;
     160          35 :     ps->reporter = reporter;
     161          35 : }
     162             : 
     163             : void
     164          35 : PREF_FinalizeParseState(PrefParseState *ps)
     165             : {
     166          35 :     if (ps->lb)
     167          35 :         free(ps->lb);
     168          35 : }
     169             : 
     170             : /**
     171             :  * Pseudo-BNF
     172             :  * ----------
     173             :  * function      = LJUNK function-name JUNK function-args
     174             :  * function-name = "user_pref" | "pref" | "sticky_pref"
     175             :  * function-args = "(" JUNK pref-name JUNK "," JUNK pref-value JUNK ")" JUNK ";"
     176             :  * pref-name     = quoted-string
     177             :  * pref-value    = quoted-string | "true" | "false" | integer-value
     178             :  * JUNK          = *(WS | comment-block | comment-line)
     179             :  * LJUNK         = *(WS | comment-block | comment-line | bcomment-line)
     180             :  * WS            = SP | HT | LF | VT | FF | CR
     181             :  * SP            = <US-ASCII SP, space (32)>
     182             :  * HT            = <US-ASCII HT, horizontal-tab (9)>
     183             :  * LF            = <US-ASCII LF, linefeed (10)>
     184             :  * VT            = <US-ASCII HT, vertical-tab (11)>
     185             :  * FF            = <US-ASCII FF, form-feed (12)>
     186             :  * CR            = <US-ASCII CR, carriage return (13)>
     187             :  * comment-block = <C/C++ style comment block>
     188             :  * comment-line  = <C++ style comment line>
     189             :  * bcomment-line = <bourne-shell style comment line>
     190             :  */
     191             : bool
     192          35 : PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen)
     193             : {
     194             :     const char *end;
     195             :     char c;
     196             :     char udigit;
     197             :     int state;
     198             : 
     199             :     // The line number is currently only used for the error/warning reporting.
     200          35 :     int lineNum = 0;
     201             : 
     202          35 :     state = ps->state;
     203     1000323 :     for (end = buf + bufLen; buf != end; ++buf) {
     204     1000288 :         c = *buf;
     205     1000288 :         if (c == '\r' || c == '\n' || c == 0x1A) {
     206       20956 :             lineNum ++;
     207             :         }
     208             : 
     209     1000288 :         switch (state) {
     210             :         /* initial state */
     211             :         case PREF_PARSE_INIT:
     212       30941 :             if (ps->lbcur != ps->lb) { /* reset state */
     213        9303 :                 ps->lbcur = ps->lb;
     214        9303 :                 ps->vb    = nullptr;
     215        9303 :                 ps->vtype = PrefType::Invalid;
     216        9303 :                 ps->fdefault = false;
     217        9303 :                 ps->fstickydefault = false;
     218             :             }
     219       30941 :             switch (c) {
     220             :             case '/':       /* begin comment block or line? */
     221        7729 :                 state = PREF_PARSE_COMMENT_MAYBE_START;
     222        7729 :                 break;
     223             :             case '#':       /* accept shell style comments */
     224           3 :                 state = PREF_PARSE_UNTIL_EOL;
     225           3 :                 break;
     226             :             case 'u':       /* indicating user_pref */
     227             :             case 's':       /* indicating sticky_pref */
     228             :             case 'p':       /* indicating pref */
     229        9303 :                 if (c == 'u') {
     230         267 :                   ps->smatch = kUserPref;
     231        9036 :                 } else if (c == 's') {
     232           9 :                   ps->smatch = kPrefSticky;
     233             :                 } else {
     234        9027 :                   ps->smatch = kPref;
     235             :                 }
     236        9303 :                 ps->sindex = 1;
     237        9303 :                 ps->nextstate = PREF_PARSE_UNTIL_OPEN_PAREN;
     238        9303 :                 state = PREF_PARSE_MATCH_STRING;
     239        9303 :                 break;
     240             :             /* else skip char */
     241             :             }
     242       30941 :             break;
     243             : 
     244             :         /* string matching */
     245             :         case PREF_PARSE_MATCH_STRING:
     246       44763 :             if (c == ps->smatch[ps->sindex++]) {
     247             :                 /* if we've matched all characters, then move to next state. */
     248       44763 :                 if (ps->smatch[ps->sindex] == '\0') {
     249       13812 :                     state = ps->nextstate;
     250       13812 :                     ps->nextstate = PREF_PARSE_INIT; /* reset next state */
     251             :                 }
     252             :                 /* else wait for next char */
     253             :             }
     254             :             else {
     255           0 :                 pref_ReportParseProblem(*ps, "non-matching string", lineNum, true);
     256           0 :                 NS_WARNING("malformed pref file");
     257           0 :                 return false;
     258             :             }
     259       44763 :             break;
     260             : 
     261             :         /* quoted string parsing */
     262             :         case PREF_PARSE_QUOTED_STRING:
     263             :             /* we assume that the initial quote has already been consumed */
     264      381528 :             if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps))
     265           0 :                 return false; /* out of memory */
     266      381528 :             if (c == '\\')
     267         870 :                 state = PREF_PARSE_ESC_SEQUENCE;
     268      380658 :             else if (c == ps->quotechar) {
     269       11703 :                 *ps->lbcur++ = '\0';
     270       11703 :                 state = ps->nextstate;
     271       11703 :                 ps->nextstate = PREF_PARSE_INIT; /* reset next state */
     272             :             }
     273             :             else
     274      368955 :                 *ps->lbcur++ = c;
     275      381528 :             break;
     276             : 
     277             :         /* name parsing */
     278             :         case PREF_PARSE_UNTIL_NAME:
     279        9303 :             if (c == '\"' || c == '\'') {
     280        9303 :                 ps->fdefault = (ps->smatch == kPref || ps->smatch == kPrefSticky);
     281        9303 :                 ps->fstickydefault = (ps->smatch == kPrefSticky);
     282        9303 :                 ps->quotechar = c;
     283        9303 :                 ps->nextstate = PREF_PARSE_UNTIL_COMMA; /* return here when done */
     284        9303 :                 state = PREF_PARSE_QUOTED_STRING;
     285             :             }
     286           0 :             else if (c == '/') {       /* allow embedded comment */
     287           0 :                 ps->nextstate = state; /* return here when done with comment */
     288           0 :                 state = PREF_PARSE_COMMENT_MAYBE_START;
     289             :             }
     290           0 :             else if (!isspace(c)) {
     291           0 :                 pref_ReportParseProblem(*ps, "need space, comment or quote", lineNum, true);
     292           0 :                 NS_WARNING("malformed pref file");
     293           0 :                 return false;
     294             :             }
     295        9303 :             break;
     296             : 
     297             :         /* parse until we find a comma separating name and value */
     298             :         case PREF_PARSE_UNTIL_COMMA:
     299        9303 :             if (c == ',') {
     300        9303 :                 ps->vb = ps->lbcur;
     301        9303 :                 state = PREF_PARSE_UNTIL_VALUE;
     302             :             }
     303           0 :             else if (c == '/') {       /* allow embedded comment */
     304           0 :                 ps->nextstate = state; /* return here when done with comment */
     305           0 :                 state = PREF_PARSE_COMMENT_MAYBE_START;
     306             :             }
     307           0 :             else if (!isspace(c)) {
     308           0 :                 pref_ReportParseProblem(*ps, "need space, comment or comma", lineNum, true);
     309           0 :                 NS_WARNING("malformed pref file");
     310           0 :                 return false;
     311             :             }
     312        9303 :             break;
     313             : 
     314             :         /* value parsing */
     315             :         case PREF_PARSE_UNTIL_VALUE:
     316             :             /* the pref value type is unknown.  so, we scan for the first
     317             :              * character of the value, and determine the type from that. */
     318       23430 :             if (c == '\"' || c == '\'') {
     319        2400 :                 ps->vtype = PrefType::String;
     320        2400 :                 ps->quotechar = c;
     321        2400 :                 ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN;
     322        2400 :                 state = PREF_PARSE_QUOTED_STRING;
     323             :             }
     324       21030 :             else if (c == 't' || c == 'f') {
     325        4509 :                 ps->vb = (char *) (c == 't' ? kTrue : kFalse);
     326        4509 :                 ps->vtype = PrefType::Bool;
     327        4509 :                 ps->smatch = ps->vb;
     328        4509 :                 ps->sindex = 1;
     329        4509 :                 ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN;
     330        4509 :                 state = PREF_PARSE_MATCH_STRING;
     331             :             }
     332       16521 :             else if (isdigit(c) || (c == '-') || (c == '+')) {
     333        2394 :                 ps->vtype = PrefType::Int;
     334             :                 /* write c to line buffer... */
     335        2394 :                 if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps))
     336           0 :                     return false; /* out of memory */
     337        2394 :                 *ps->lbcur++ = c;
     338        2394 :                 state = PREF_PARSE_INT_VALUE;
     339             :             }
     340       14127 :             else if (c == '/') {       /* allow embedded comment */
     341           0 :                 ps->nextstate = state; /* return here when done with comment */
     342           0 :                 state = PREF_PARSE_COMMENT_MAYBE_START;
     343             :             }
     344       14127 :             else if (!isspace(c)) {
     345           0 :                 pref_ReportParseProblem(*ps, "need value, comment or space", lineNum, true);
     346           0 :                 NS_WARNING("malformed pref file");
     347           0 :                 return false;
     348             :             }
     349       23430 :             break;
     350             :         case PREF_PARSE_INT_VALUE:
     351             :             /* grow line buffer if necessary... */
     352        5644 :             if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps))
     353           0 :                 return false; /* out of memory */
     354        5644 :             if (isdigit(c))
     355        3250 :                 *ps->lbcur++ = c;
     356             :             else {
     357        2394 :                 *ps->lbcur++ = '\0'; /* stomp null terminator; we are done. */
     358        2394 :                 if (c == ')')
     359        2394 :                     state = PREF_PARSE_UNTIL_SEMICOLON;
     360           0 :                 else if (c == '/') { /* allow embedded comment */
     361           0 :                     ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN;
     362           0 :                     state = PREF_PARSE_COMMENT_MAYBE_START;
     363             :                 }
     364           0 :                 else if (isspace(c))
     365           0 :                     state = PREF_PARSE_UNTIL_CLOSE_PAREN;
     366             :                 else {
     367           0 :                     pref_ReportParseProblem(*ps, "while parsing integer", lineNum, true);
     368           0 :                     NS_WARNING("malformed pref file");
     369           0 :                     return false;
     370             :                 }
     371             :             }
     372        5644 :             break;
     373             : 
     374             :         /* comment parsing */
     375             :         case PREF_PARSE_COMMENT_MAYBE_START:
     376        7729 :             switch (c) {
     377             :             case '*': /* comment block */
     378          94 :                 state = PREF_PARSE_COMMENT_BLOCK;
     379          94 :                 break;
     380             :             case '/': /* comment line */
     381        7635 :                 state = PREF_PARSE_UNTIL_EOL;
     382        7635 :                 break;
     383             :             default:
     384             :                 /* pref file is malformed */
     385           0 :                 pref_ReportParseProblem(*ps, "while parsing comment", lineNum, true);
     386           0 :                 NS_WARNING("malformed pref file");
     387           0 :                 return false;
     388             :             }
     389        7729 :             break;
     390             :         case PREF_PARSE_COMMENT_BLOCK:
     391       23764 :             if (c == '*')
     392         498 :                 state = PREF_PARSE_COMMENT_BLOCK_MAYBE_END;
     393       23764 :             break;
     394             :         case PREF_PARSE_COMMENT_BLOCK_MAYBE_END:
     395         498 :             switch (c) {
     396             :             case '/':
     397          94 :                 state = ps->nextstate;
     398          94 :                 ps->nextstate = PREF_PARSE_INIT;
     399          94 :                 break;
     400             :             case '*':       /* stay in this state */
     401           0 :                 break;
     402             :             default:
     403         404 :                 state = PREF_PARSE_COMMENT_BLOCK;
     404             :             }
     405         498 :             break;
     406             : 
     407             :         /* string escape sequence parsing */
     408             :         case PREF_PARSE_ESC_SEQUENCE:
     409             :             /* not necessary to resize buffer here since we should be writing
     410             :              * only one character and the resize check would have been done
     411             :              * for us in the previous state */
     412         870 :             switch (c) {
     413             :             case '\"':
     414             :             case '\'':
     415             :             case '\\':
     416         513 :                 break;
     417             :             case 'r':
     418           0 :                 c = '\r';
     419           0 :                 break;
     420             :             case 'n':
     421           3 :                 c = '\n';
     422           3 :                 break;
     423             :             case 'x': /* hex escape -- always interpreted as Latin-1 */
     424             :             case 'u': /* UTF16 escape */
     425         354 :                 ps->esctmp[0] = c;
     426         354 :                 ps->esclen = 1;
     427         354 :                 ps->utf16[0] = ps->utf16[1] = 0;
     428         354 :                 ps->sindex = (c == 'x' ) ?
     429             :                                 HEX_ESC_NUM_DIGITS :
     430             :                                 UTF16_ESC_NUM_DIGITS;
     431         354 :                 state = PREF_PARSE_HEX_ESCAPE;
     432         354 :                 continue;
     433             :             default:
     434             :                 pref_ReportParseProblem(*ps, "preserving unexpected JS escape sequence",
     435           0 :                                         lineNum, false);
     436           0 :                 NS_WARNING("preserving unexpected JS escape sequence");
     437             :                 /* Invalid escape sequence so we do have to write more than
     438             :                  * one character. Grow line buffer if necessary... */
     439           0 :                 if ((ps->lbcur+1) == ps->lbend && !pref_GrowBuf(ps))
     440           0 :                     return false; /* out of memory */
     441           0 :                 *ps->lbcur++ = '\\'; /* preserve the escape sequence */
     442           0 :                 break;
     443             :             }
     444         516 :             *ps->lbcur++ = c;
     445         516 :             state = PREF_PARSE_QUOTED_STRING;
     446         516 :             break;
     447             : 
     448             :         /* parsing a hex (\xHH) or utf16 escape (\uHHHH) */
     449             :         case PREF_PARSE_HEX_ESCAPE:
     450        1416 :             if ( c >= '0' && c <= '9' )
     451        1032 :                 udigit = (c - '0');
     452         384 :             else if ( c >= 'A' && c <= 'F' )
     453         384 :                 udigit = (c - 'A') + 10;
     454           0 :             else if ( c >= 'a' && c <= 'f' )
     455           0 :                 udigit = (c - 'a') + 10;
     456             :             else {
     457             :                 /* bad escape sequence found, write out broken escape as-is */
     458             :                 pref_ReportParseProblem(*ps, "preserving invalid or incomplete hex escape",
     459           0 :                                         lineNum, false);
     460           0 :                 NS_WARNING("preserving invalid or incomplete hex escape");
     461           0 :                 *ps->lbcur++ = '\\';  /* original escape slash */
     462           0 :                 if ((ps->lbcur + ps->esclen) >= ps->lbend && !pref_GrowBuf(ps))
     463           0 :                     return false;
     464           0 :                 for (int i = 0; i < ps->esclen; ++i)
     465           0 :                     *ps->lbcur++ = ps->esctmp[i];
     466             : 
     467             :                 /* push the non-hex character back for re-parsing. */
     468             :                 /* (++buf at the top of the loop keeps this safe)  */
     469           0 :                 --buf;
     470           0 :                 state = PREF_PARSE_QUOTED_STRING;
     471           0 :                 continue;
     472             :             }
     473             : 
     474             :             /* have a digit */
     475        1416 :             ps->esctmp[ps->esclen++] = c; /* preserve it */
     476        1416 :             ps->utf16[1] <<= BITS_PER_HEX_DIGIT;
     477        1416 :             ps->utf16[1] |= udigit;
     478        1416 :             ps->sindex--;
     479        1416 :             if (ps->sindex == 0) {
     480             :                 /* have the full escape. Convert to UTF8 */
     481         354 :                 int utf16len = 0;
     482         354 :                 if (ps->utf16[0]) {
     483             :                     /* already have a high surrogate, this is a two char seq */
     484           0 :                     utf16len = 2;
     485             :                 }
     486         354 :                 else if (0xD800 == (0xFC00 & ps->utf16[1])) {
     487             :                     /* a high surrogate, can't convert until we have the low */
     488           0 :                     ps->utf16[0] = ps->utf16[1];
     489           0 :                     ps->utf16[1] = 0;
     490           0 :                     state = PREF_PARSE_UTF16_LOW_SURROGATE;
     491           0 :                     break;
     492             :                 }
     493             :                 else {
     494             :                     /* a single utf16 character */
     495         354 :                     ps->utf16[0] = ps->utf16[1];
     496         354 :                     utf16len = 1;
     497             :                 }
     498             : 
     499             :                 /* actual conversion */
     500             :                 /* make sure there's room, 6 bytes is max utf8 len (in */
     501             :                 /* theory; 4 bytes covers the actual utf16 range) */
     502         354 :                 if (ps->lbcur+6 >= ps->lbend && !pref_GrowBuf(ps))
     503           0 :                     return false;
     504             : 
     505         354 :                 ConvertUTF16toUTF8 converter(ps->lbcur);
     506         354 :                 converter.write(ps->utf16, utf16len);
     507         354 :                 ps->lbcur += converter.Size();
     508         354 :                 state = PREF_PARSE_QUOTED_STRING;
     509             :             }
     510        1416 :             break;
     511             : 
     512             :         /* looking for beginning of utf16 low surrogate */
     513             :         case PREF_PARSE_UTF16_LOW_SURROGATE:
     514           0 :             if (ps->sindex == 0 && c == '\\') {
     515           0 :                 ++ps->sindex;
     516             :             }
     517           0 :             else if (ps->sindex == 1 && c == 'u') {
     518             :                 /* escape sequence is correct, now parse hex */
     519           0 :                 ps->sindex = UTF16_ESC_NUM_DIGITS;
     520           0 :                 ps->esctmp[0] = 'u';
     521           0 :                 ps->esclen = 1;
     522           0 :                 state = PREF_PARSE_HEX_ESCAPE;
     523             :             }
     524             :             else {
     525             :                 /* didn't find expected low surrogate. Ignore high surrogate
     526             :                  * (it would just get converted to nothing anyway) and start
     527             :                  * over with this character */
     528           0 :                  --buf;
     529           0 :                  if (ps->sindex == 1)
     530           0 :                      state = PREF_PARSE_ESC_SEQUENCE;
     531             :                  else
     532           0 :                      state = PREF_PARSE_QUOTED_STRING;
     533           0 :                  continue;
     534             :             }
     535           0 :             break;
     536             : 
     537             :         /* function open and close parsing */
     538             :         case PREF_PARSE_UNTIL_OPEN_PAREN:
     539             :             /* tolerate only whitespace and embedded comments */
     540        9309 :             if (c == '(')
     541        9303 :                 state = PREF_PARSE_UNTIL_NAME;
     542           6 :             else if (c == '/') {
     543           0 :                 ps->nextstate = state; /* return here when done with comment */
     544           0 :                 state = PREF_PARSE_COMMENT_MAYBE_START;
     545             :             }
     546           6 :             else if (!isspace(c)) {
     547             :                 pref_ReportParseProblem(*ps, "need space, comment or open parentheses",
     548           0 :                                         lineNum, true);
     549           0 :                 NS_WARNING("malformed pref file");
     550           0 :                 return false;
     551             :             }
     552        9309 :             break;
     553             :         case PREF_PARSE_UNTIL_CLOSE_PAREN:
     554             :             /* tolerate only whitespace and embedded comments  */
     555        6915 :             if (c == ')') {
     556        6909 :                 state = PREF_PARSE_UNTIL_SEMICOLON;
     557           6 :             } else if (c == '/') {
     558           0 :                 ps->nextstate = state; /* return here when done with comment */
     559           0 :                 state = PREF_PARSE_COMMENT_MAYBE_START;
     560           6 :             } else if (!isspace(c)) {
     561             :                 pref_ReportParseProblem(*ps, "need space, comment or closing parentheses",
     562           0 :                                         lineNum, true);
     563           0 :                 NS_WARNING("malformed pref file");
     564           0 :                 return false;
     565             :             }
     566        6915 :             break;
     567             : 
     568             :         /* function terminator ';' parsing */
     569             :         case PREF_PARSE_UNTIL_SEMICOLON:
     570             :             /* tolerate only whitespace and embedded comments */
     571        9303 :             if (c == ';') {
     572        9303 :                 if (!pref_DoCallback(ps))
     573           0 :                     return false;
     574        9303 :                 state = PREF_PARSE_INIT;
     575             :             }
     576           0 :             else if (c == '/') {
     577           0 :                 ps->nextstate = state; /* return here when done with comment */
     578           0 :                 state = PREF_PARSE_COMMENT_MAYBE_START;
     579             :             }
     580           0 :             else if (!isspace(c)) {
     581             :                 pref_ReportParseProblem(*ps, "need space, comment or semicolon",
     582           0 :                                         lineNum, true);
     583           0 :                 NS_WARNING("malformed pref file");
     584           0 :                 return false;
     585             :             }
     586        9303 :             break;
     587             : 
     588             :         /* eol parsing */
     589             :         case PREF_PARSE_UNTIL_EOL:
     590             :             /* need to handle mac, unix, or dos line endings.
     591             :              * PREF_PARSE_INIT will eat the next \n in case
     592             :              * we have \r\n. */
     593      435572 :             if (c == '\r' || c == '\n' || c == 0x1A) {
     594        7638 :                 state = ps->nextstate;
     595        7638 :                 ps->nextstate = PREF_PARSE_INIT; /* reset next state */
     596             :             }
     597      435572 :             break;
     598             :         }
     599             :     }
     600          35 :     ps->state = state;
     601          35 :     return true;
     602           9 : }
     603             : 
     604             : #ifdef TEST_PREFREAD
     605             : 
     606             : static void
     607             : pref_reader(void       *closure,
     608             :             const char *pref,
     609             :             PrefValue   val,
     610             :             PrefType    type,
     611             :             bool        defPref)
     612             : {
     613             :     printf("%spref(\"%s\", ", defPref ? "" : "user_", pref);
     614             :     switch (type) {
     615             :     case PREF_STRING:
     616             :         printf("\"%s\");\n", val.stringVal);
     617             :         break;
     618             :     case PREF_INT:
     619             :         printf("%i);\n", val.intVal);
     620             :         break;
     621             :     case PREF_BOOL:
     622             :         printf("%s);\n", val.boolVal == false ? "false" : "true");
     623             :         break;
     624             :     }
     625             : }
     626             : 
     627             : int
     628             : main(int argc, char **argv)
     629             : {
     630             :     PrefParseState ps;
     631             :     char buf[4096];     /* i/o buffer */
     632             :     FILE *fp;
     633             :     int n;
     634             : 
     635             :     if (argc == 1) {
     636             :         printf("usage: prefread file.js\n");
     637             :         return -1;
     638             :     }
     639             : 
     640             :     fp = fopen(argv[1], "r");
     641             :     if (!fp) {
     642             :         printf("failed to open file\n");
     643             :         return -1;
     644             :     }
     645             : 
     646             :     PREF_InitParseState(&ps, pref_reader, nullptr, nullptr);
     647             : 
     648             :     while ((n = fread(buf, 1, sizeof(buf), fp)) > 0)
     649             :         PREF_ParseBuf(&ps, buf, n);
     650             : 
     651             :     PREF_FinalizeParseState(&ps);
     652             : 
     653             :     fclose(fp);
     654             :     return 0;
     655             : }
     656             : 
     657             : #endif /* TEST_PREFREAD */

Generated by: LCOV version 1.13