nsresult PREF_LockPref(const char *key, bool lockit) { if (!gHashTable.ops) return NS_ERROR_NOT_INITIALIZED; PrefHashEntry* pref = pref_HashTableLookup(key); if (!pref) return NS_ERROR_UNEXPECTED; if (lockit) { if (!PREF_IS_LOCKED(pref)) { pref->flags |= PREF_LOCKED; gIsAnyPrefLocked = true; pref_DoCallback(key); } } else { if (PREF_IS_LOCKED(pref)) { pref->flags &= ~PREF_LOCKED; pref_DoCallback(key); } } return NS_OK; }
nsresult PREF_ClearUserPref(const char *pref_name) { if (!gHashTable.ops) return NS_ERROR_NOT_INITIALIZED; nsresult rv = NS_ERROR_UNEXPECTED; PrefHashEntry* pref = pref_HashTableLookup(pref_name); if (pref && PREF_HAS_USER_VALUE(pref)) { pref->flags &= ~PREF_USERSET; if ((pref->flags & PREF_INT && pref->defaultPref.intVal == ((PRInt32) BOGUS_DEFAULT_INT_PREF_VALUE)) || (pref->flags & PREF_BOOL && pref->defaultPref.boolVal == ((PRBool) BOGUS_DEFAULT_BOOL_PREF_VALUE)) || (pref->flags & PREF_STRING && !pref->defaultPref.stringVal)) { PL_DHashTableOperate(&gHashTable, pref_name, PL_DHASH_REMOVE); } if (gCallbacksEnabled) pref_DoCallback(pref_name); gDirty = PR_TRUE; rv = NS_OK; } return rv; }
static PLDHashOperator pref_ClearUserPref(PLDHashTable *table, PLDHashEntryHdr *he, PRUint32, void *arg) { PrefHashEntry *pref = static_cast<PrefHashEntry*>(he); PLDHashOperator nextOp = PL_DHASH_NEXT; if (PREF_HAS_USER_VALUE(pref)) { pref->flags &= ~PREF_USERSET; if (!(pref->flags & PREF_HAS_DEFAULT)) { nextOp = PL_DHASH_REMOVE; } pref_DoCallback(pref->key); } return nextOp; }
nsresult PREF_ClearUserPref(const char *pref_name) { if (!gHashTable.ops) return NS_ERROR_NOT_INITIALIZED; PrefHashEntry* pref = pref_HashTableLookup(pref_name); if (pref && PREF_HAS_USER_VALUE(pref)) { pref->flags &= ~PREF_USERSET; if (!(pref->flags & PREF_HAS_DEFAULT)) { PL_DHashTableOperate(&gHashTable, pref_name, PL_DHASH_REMOVE); } pref_DoCallback(pref_name); gDirty = true; } return NS_OK; }
pref_ClearUserPref(PLDHashTable *table, PLDHashEntryHdr *he, PRUint32, void *arg) { PrefHashEntry *pref = static_cast<PrefHashEntry*>(he); PLDHashOperator nextOp = PL_DHASH_NEXT; if (PREF_HAS_USER_VALUE(pref)) { pref->flags &= ~PREF_USERSET; if ((pref->flags & PREF_INT && pref->defaultPref.intVal == ((PRInt32) BOGUS_DEFAULT_INT_PREF_VALUE)) || (pref->flags & PREF_BOOL && pref->defaultPref.boolVal == ((PRBool) BOGUS_DEFAULT_BOOL_PREF_VALUE)) || (pref->flags & PREF_STRING && !pref->defaultPref.stringVal)) { nextOp = PL_DHASH_REMOVE; } if (gCallbacksEnabled) pref_DoCallback(pref->key); } return nextOp; }
nsresult pref_HashPref(const char *key, PrefValue value, PrefType type, PRUint32 flags) { if (!gHashTable.ops) return NS_ERROR_OUT_OF_MEMORY; PrefHashEntry* pref = static_cast<PrefHashEntry*>(PL_DHashTableOperate(&gHashTable, key, PL_DHASH_ADD)); if (!pref) return NS_ERROR_OUT_OF_MEMORY; // new entry, better intialize if (!pref->key) { // initialize the pref entry pref->flags = type; pref->key = ArenaStrDup(key, &gPrefNameArena); memset(&pref->defaultPref, 0, sizeof(pref->defaultPref)); memset(&pref->userPref, 0, sizeof(pref->userPref)); } else if ((((PrefType)(pref->flags)) & PREF_VALUETYPE_MASK) != (type & PREF_VALUETYPE_MASK)) { NS_WARNING(nsPrintfCString(192, "Trying to set pref %s to with the wrong type!", key).get()); return NS_ERROR_UNEXPECTED; } bool valueChanged = false; if (flags & kPrefSetDefault) { if (!PREF_IS_LOCKED(pref)) { /* ?? change of semantics? */ if (pref_ValueChanged(pref->defaultPref, value, type) || !(pref->flags & PREF_HAS_DEFAULT)) { pref_SetValue(&pref->defaultPref, value, type); pref->flags |= PREF_HAS_DEFAULT; if (!PREF_HAS_USER_VALUE(pref)) valueChanged = true; } } } else { /* If new value is same as the default value, then un-set the user value. Otherwise, set the user value only if it has changed */ if (!pref_ValueChanged(pref->defaultPref, value, type) && (pref->flags & PREF_HAS_DEFAULT) && !(flags & kPrefForceSet)) { if (PREF_HAS_USER_VALUE(pref)) { pref->flags &= ~PREF_USERSET; if (!PREF_IS_LOCKED(pref)) valueChanged = true; } } else if ( !PREF_HAS_USER_VALUE(pref) || pref_ValueChanged(pref->userPref, value, type) ) { pref_SetValue(&pref->userPref, value, type); pref->flags |= PREF_USERSET; if (!PREF_IS_LOCKED(pref)) valueChanged = true; } } nsresult rv = NS_OK; if (valueChanged) { gDirty = true; nsresult rv2 = pref_DoCallback(key); if (NS_FAILED(rv2)) rv = rv2; } return rv; }
nsresult pref_HashPref(const char *key, PrefValue value, PrefType type, PRBool set_default) { if (!gHashTable.ops) return NS_ERROR_OUT_OF_MEMORY; PrefHashEntry* pref = static_cast<PrefHashEntry*>(PL_DHashTableOperate(&gHashTable, key, PL_DHASH_ADD)); if (!pref) return NS_ERROR_OUT_OF_MEMORY; // new entry, better intialize if (!pref->key) { // initialize the pref entry pref->flags = type; pref->key = ArenaStrDup(key, &gPrefNameArena); memset(&pref->defaultPref, 0, sizeof(pref->defaultPref)); memset(&pref->userPref, 0, sizeof(pref->userPref)); /* ugly hack -- define it to a default that no pref will ever default to this should really get fixed right by some out of band data */ if (pref->flags & PREF_BOOL) pref->defaultPref.boolVal = (PRBool) BOGUS_DEFAULT_BOOL_PREF_VALUE; if (pref->flags & PREF_INT) pref->defaultPref.intVal = (PRInt32) BOGUS_DEFAULT_INT_PREF_VALUE; } else if ((((PrefType)(pref->flags)) & PREF_VALUETYPE_MASK) != (type & PREF_VALUETYPE_MASK)) { NS_WARNING(nsPrintfCString(192, "Trying to set pref %s to with the wrong type!", key).get()); return NS_ERROR_UNEXPECTED; } PRBool valueChanged = PR_FALSE; if (set_default) { if (!PREF_IS_LOCKED(pref)) { /* ?? change of semantics? */ if (pref_ValueChanged(pref->defaultPref, value, type)) { pref_SetValue(&pref->defaultPref, value, type); if (!PREF_HAS_USER_VALUE(pref)) valueChanged = PR_TRUE; } } } else { /* If new value is same as the default value, then un-set the user value. Otherwise, set the user value only if it has changed */ if ( !pref_ValueChanged(pref->defaultPref, value, type) ) { if (PREF_HAS_USER_VALUE(pref)) { pref->flags &= ~PREF_USERSET; if (!PREF_IS_LOCKED(pref)) valueChanged = PR_TRUE; } } else if ( !PREF_HAS_USER_VALUE(pref) || pref_ValueChanged(pref->userPref, value, type) ) { pref_SetValue(&pref->userPref, value, type); pref->flags |= PREF_USERSET; if (!PREF_IS_LOCKED(pref)) valueChanged = PR_TRUE; } } nsresult rv = NS_OK; if (valueChanged) { gDirty = PR_TRUE; if (gCallbacksEnabled) { nsresult rv2 = pref_DoCallback(key); if (NS_FAILED(rv2)) rv = rv2; } #ifdef MOZ_PROFILESHARING if (gSharedPrefHandler) gSharedPrefHandler->OnPrefChanged(set_default, pref, value); #endif } return rv; }
/** * Pseudo-BNF * ---------- * function = LJUNK function-name JUNK function-args * function-name = "user_pref" | "pref" * function-args = "(" JUNK pref-name JUNK "," JUNK pref-value JUNK ")" JUNK ";" * pref-name = quoted-string * pref-value = quoted-string | "true" | "false" | integer-value * JUNK = *(WS | comment-block | comment-line) * LJUNK = *(WS | comment-block | comment-line | bcomment-line) * WS = SP | HT | LF | VT | FF | CR * SP = <US-ASCII SP, space (32)> * HT = <US-ASCII HT, horizontal-tab (9)> * LF = <US-ASCII LF, linefeed (10)> * VT = <US-ASCII HT, vertical-tab (11)> * FF = <US-ASCII FF, form-feed (12)> * CR = <US-ASCII CR, carriage return (13)> * comment-block = <C/C++ style comment block> * comment-line = <C++ style comment line> * bcomment-line = <bourne-shell style comment line> */ PRBool PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen) { 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; }