Back to index

lightning-sunbird  0.9+nobinonly
Classes | Typedefs | Functions | Variables
prefread.h File Reference
#include "prtypes.h"
#include "prefapi.h"
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  PrefParseState

Typedefs

typedef struct PrefParseState PrefParseState

Functions

void PREF_InitParseState (PrefParseState *ps, PrefReader reader, void *closure)
 PREF_InitParseState.
void PREF_FinalizeParseState (PrefParseState *ps)
 PREF_FinalizeParseState.
PRBool PREF_ParseBuf (PrefParseState *ps, const char *buf, int bufLen)
 PREF_ParseBuf.

Variables

NSPR_BEGIN_EXTERN_C typedef void(* PrefReader )(void *closure, const char *pref, PrefValue val, PrefType type, PRBool defPref)
 Callback function used to notify consumer of preference name value pairs.

Class Documentation

struct PrefParseState

Definition at line 68 of file prefread.h.

Collaboration diagram for PrefParseState:
Class Members
void * closure
int esclen
char esctmp
PRBool fdefault
char * lb
char * lbcur
char * lbend
int nextstate
char quotechar
PrefReader reader
int sindex
const char * smatch
int state
PRUnichar utf16
char * vb
PrefType vtype

Typedef Documentation


Function Documentation

PREF_FinalizeParseState.

Called to release any memory in use by the PrefParseState instance.

Parameters:
psPrefParseState instance.

Definition at line 177 of file prefread.cpp.

{
    if (ps->lb)
        free(ps->lb);
}

Here is the caller graph for this function:

void PREF_InitParseState ( PrefParseState ps,
PrefReader  reader,
void closure 
)

PREF_InitParseState.

Called to initialize a PrefParseState instance.

Parameters:
psPrefParseState instance.
readerPrefReader callback function, which will be called once for each preference name value pair extracted.
closurePrefReader closure.

Definition at line 169 of file prefread.cpp.

{
    memset(ps, 0, sizeof(*ps));
    ps->reader = reader;
    ps->closure = closure;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRBool PREF_ParseBuf ( PrefParseState ps,
const char *  buf,
int  bufLen 
)

PREF_ParseBuf.

Called to parse a buffer containing some portion of a preference file. This function may be called repeatedly as new data is made available. The PrefReader callback function passed PREF_InitParseState will be called as preference name value pairs are extracted from the data.

Parameters:
psPrefParseState instance. Must have been initialized.
bufRaw buffer containing data to be parsed.
bufLenLength of buffer.
Returns:
PR_FALSE if buffer contains malformed content.

Definition at line 205 of file prefread.cpp.

{
    const char *end;
    char c;
    char udigit;
    int state;

    state = ps->state;
    for (end = buf + bufLen; buf != end; ++buf) {
        c = *buf;
        switch (state) {
        /* initial state */
        case PREF_PARSE_INIT:
            if (ps->lbcur != ps->lb) { /* reset state */
                ps->lbcur = ps->lb;
                ps->vb    = NULL;
                ps->vtype = PREF_INVALID;
                ps->fdefault = PR_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 'p':       /* indicating pref */
                ps->smatch = (c == 'u' ? kUserPref : 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 {
                NS_WARNING("malformed pref file");
                return PR_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 PR_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->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)) {
                NS_WARNING("malformed pref file");
                return PR_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)) {
                NS_WARNING("malformed pref file");
                return PR_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 = PREF_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 = PREF_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 = PREF_INT;
                /* write c to line buffer... */
                if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps))
                    return PR_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)) {
                NS_WARNING("malformed pref file");
                return PR_FALSE;
            }
            break;
        case PREF_PARSE_INT_VALUE:
            /* grow line buffer if necessary... */
            if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps))
                return PR_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 {
                    NS_WARNING("malformed pref file");
                    return PR_FALSE;
                }
            }
            break;

        /* comment parsing */
        case PREF_PARSE_COMMENT_MAYBE_START:
            switch (c) {
            case '*': /* comment block */
                state = PREF_PARSE_COMMENT_BLOCK;
                break;
            case '/': /* comment line */
                state = PREF_PARSE_UNTIL_EOL;
                break;
            default:
                /* pref file is malformed */
                NS_WARNING("malformed pref file");
                return PR_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:
                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 PR_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 */
                NS_WARNING("preserving invalid or incomplete hex escape");
                *ps->lbcur++ = '\\';  /* original escape slash */
                if ((ps->lbcur + ps->esclen) >= ps->lbend && !pref_GrowBuf(ps))
                    return PR_FALSE;
                for (int i = 0; i < ps->esclen; ++i)
                    *ps->lbcur++ = ps->esctmp[i];

                /* push the non-hex character back for re-parsing. */
                /* (++buf at the top of the loop keeps this safe)  */
                --buf;
                state = PREF_PARSE_QUOTED_STRING;
                continue;
            }

            /* have a digit */
            ps->esctmp[ps->esclen++] = c; /* preserve it */
            ps->utf16[1] <<= BITS_PER_HEX_DIGIT;
            ps->utf16[1] |= udigit;
            ps->sindex--;
            if (ps->sindex == 0) {
                /* have the full escape. Convert to UTF8 */
                int utf16len = 0;
                if (ps->utf16[0]) {
                    /* already have a high surrogate, this is a two char seq */
                    utf16len = 2;
                }
                else if (0xD800 == (0xFC00 & ps->utf16[1])) {
                    /* a high surrogate, can't convert until we have the low */
                    ps->utf16[0] = ps->utf16[1];
                    ps->utf16[1] = 0;
                    state = PREF_PARSE_UTF16_LOW_SURROGATE;
                    break;
                }
                else {
                    /* a single utf16 character */
                    ps->utf16[0] = ps->utf16[1];
                    utf16len = 1;
                }

                /* actual conversion */
                /* make sure there's room, 6 bytes is max utf8 len (in */
                /* theory; 4 bytes covers the actual utf16 range) */
                if (ps->lbcur+6 >= ps->lbend && !pref_GrowBuf(ps))
                    return PR_FALSE;

                ConvertUTF16toUTF8 converter(ps->lbcur);
                converter.write(ps->utf16, utf16len);
                ps->lbcur += converter.Size();
                state = PREF_PARSE_QUOTED_STRING;
            }
            break;

        /* looking for beginning of utf16 low surrogate */
        case PREF_PARSE_UTF16_LOW_SURROGATE:
            if (ps->sindex == 0 && c == '\\') {
                ++ps->sindex;
            }
            else if (ps->sindex == 1 && c == 'u') {
                /* escape sequence is correct, now parse hex */
                ps->sindex = UTF16_ESC_NUM_DIGITS;
                ps->esctmp[0] = 'u';
                ps->esclen = 1;
                state = PREF_PARSE_HEX_ESCAPE;
            }
            else {
                /* didn't find expected low surrogate. Ignore high surrogate
                 * (it would just get converted to nothing anyway) and start
                 * over with this character */
                 --buf;
                 if (ps->sindex == 1)
                     state = PREF_PARSE_ESC_SEQUENCE;
                 else
                     state = PREF_PARSE_QUOTED_STRING;
                 continue;
            }
            break;

        /* function open and close parsing */
        case PREF_PARSE_UNTIL_OPEN_PAREN:
            /* tolerate only whitespace and embedded comments */
            if (c == '(')
                state = PREF_PARSE_UNTIL_NAME;
            else if (c == '/') {
                ps->nextstate = state; /* return here when done with comment */
                state = PREF_PARSE_COMMENT_MAYBE_START;
            }
            else if (!isspace(c)) {
                NS_WARNING("malformed pref file");
                return PR_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)) {
                NS_WARNING("malformed pref file");
                return PR_FALSE;
            }
            break;

        /* function terminator ';' parsing */
        case PREF_PARSE_UNTIL_SEMICOLON:
            /* tolerate only whitespace and embedded comments */
            if (c == ';') {
                if (!pref_DoCallback(ps))
                    return PR_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)) {
                NS_WARNING("malformed pref file");
                return PR_FALSE;
            }
            break;

        /* eol parsing */
        case PREF_PARSE_UNTIL_EOL:
            /* need to handle mac, unix, or dos line endings.
             * PREF_PARSE_INIT will eat the next \n in case
             * we have \r\n. */
            if (c == '\r' || c == '\n' || c == 0x1A) {
                state = ps->nextstate;
                ps->nextstate = PREF_PARSE_INIT; /* reset next state */
            }
            break;
        }
    }
    ps->state = state;
    return PR_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Callback function used to notify consumer of preference name value pairs.

The pref name and value must be copied by the implementor of the callback if they are needed beyond the scope of the callback function.

Parameters:
closureuser data passed to PREF_InitParseState
prefpreference name
valpreference value
typepreference type (PREF_STRING, PREF_INT, or PREF_BOOL)
defPrefpreference type (PR_TRUE: default, PR_FALSE: user preference)

Definition at line 61 of file prefread.h.