LCOV - code coverage report
Current view: directory - modules/libpref/src - prefread.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 260 170 65.4 %
Date: 2012-06-02 Functions: 5 5 100.0 %

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

Generated by: LCOV version 1.7