JSBool js_json_parse(JSContext *cx, uintN argc, Value *vp) { JSString *s = NULL; Value *argv = vp + 2; AutoValueRooter reviver(cx); if (!JS_ConvertArguments(cx, argc, Jsvalify(argv), "S / v", &s, reviver.addr())) return JS_FALSE; JSONParser *jp = js_BeginJSONParse(cx, vp); JSBool ok = jp != NULL; if (ok) { const jschar *chars; size_t length; s->getCharsAndLength(chars, length); ok = js_ConsumeJSONText(cx, jp, chars, length); ok &= !!js_FinishJSONParse(cx, jp, reviver.value()); } return ok; }
JSBool js_json_parse(JSContext *cx, uintN argc, jsval *vp) { JSString *s = NULL; jsval *argv = vp + 2; jsval reviver = JSVAL_NULL; JSAutoTempValueRooter tvr(cx, 1, &reviver); if (!JS_ConvertArguments(cx, argc, argv, "S / v", &s, &reviver)) return JS_FALSE; JSONParser *jp = js_BeginJSONParse(cx, vp); JSBool ok = jp != NULL; if (ok) { const jschar *chars; size_t length; s->getCharsAndLength(chars, length); ok = js_ConsumeJSONText(cx, jp, chars, length); ok &= js_FinishJSONParse(cx, jp, reviver); } return ok; }
static JSBool JO(JSContext *cx, jsval *vp, StringifyContext *scx) { JSObject *obj = JSVAL_TO_OBJECT(*vp); if (!scx->cb.append('{')) return JS_FALSE; jsval vec[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL}; JSAutoTempValueRooter tvr(cx, 3, vec); jsval& key = vec[0]; jsval& outputValue = vec[1]; JSObject *iterObj = NULL; jsval *keySource = vp; bool usingWhitelist = false; // if the replacer is an array, we use the keys from it if (scx->replacer && JS_IsArrayObject(cx, scx->replacer)) { usingWhitelist = true; vec[2] = OBJECT_TO_JSVAL(scx->replacer); keySource = &vec[2]; } if (!js_ValueToIterator(cx, JSITER_ENUMERATE, keySource)) return JS_FALSE; iterObj = JSVAL_TO_OBJECT(*keySource); JSBool memberWritten = JS_FALSE; bool ok = false; while (true) { outputValue = JSVAL_VOID; if (!js_CallIteratorNext(cx, iterObj, &key)) goto error_break; if (key == JSVAL_HOLE) break; jsuint index = 0; if (usingWhitelist) { // skip non-index properties if (!js_IdIsIndex(key, &index)) continue; jsval newKey; if (!scx->replacer->getProperty(cx, key, &newKey)) goto error_break; key = newKey; } JSString *ks; if (JSVAL_IS_STRING(key)) { ks = JSVAL_TO_STRING(key); } else { ks = js_ValueToString(cx, key); if (!ks) goto error_break; } JSAutoTempValueRooter keyStringRoot(cx, ks); // Don't include prototype properties, since this operation is // supposed to be implemented as if by ES3.1 Object.keys() jsid id; jsval v = JS_FALSE; if (!js_ValueToStringId(cx, STRING_TO_JSVAL(ks), &id) || !js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, id, &v)) { goto error_break; } if (v != JSVAL_TRUE) continue; if (!JS_GetPropertyById(cx, obj, id, &outputValue)) goto error_break; if (JSVAL_IS_OBJECT(outputValue) && !js_TryJSON(cx, &outputValue)) goto error_break; // call this here, so we don't write out keys if the replacer function // wants to elide the value. if (!CallReplacerFunction(cx, id, obj, scx, &outputValue)) goto error_break; JSType type = JS_TypeOfValue(cx, outputValue); // elide undefined values and functions and XML if (outputValue == JSVAL_VOID || type == JSTYPE_FUNCTION || type == JSTYPE_XML) continue; // output a comma unless this is the first member to write if (memberWritten && !scx->cb.append(',')) goto error_break; memberWritten = JS_TRUE; if (!WriteIndent(cx, scx, scx->depth)) goto error_break; // Be careful below, this string is weakly rooted JSString *s = js_ValueToString(cx, key); if (!s) goto error_break; const jschar *chars; size_t length; s->getCharsAndLength(chars, length); if (!write_string(cx, scx->cb, chars, length) || !scx->cb.append(':') || !Str(cx, id, obj, scx, &outputValue, false)) { goto error_break; } } ok = true; error_break: if (iterObj) { // Always close the iterator, but make sure not to stomp on OK JS_ASSERT(OBJECT_TO_JSVAL(iterObj) == *keySource); ok &= js_CloseIterator(cx, *keySource); } if (!ok) return JS_FALSE; if (memberWritten && !WriteIndent(cx, scx, scx->depth - 1)) return JS_FALSE; return scx->cb.append('}'); }
static JSBool JO(JSContext *cx, Value *vp, StringifyContext *scx) { JSObject *obj = &vp->toObject(); CycleDetector detect(scx, obj); if (!detect.init(cx)) return JS_FALSE; if (!scx->cb.append('{')) return JS_FALSE; Value vec[3] = { NullValue(), NullValue(), NullValue() }; AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec); Value& outputValue = vec[0]; Value& whitelistElement = vec[1]; AutoIdRooter idr(cx); jsid& id = *idr.addr(); Value *keySource = vp; bool usingWhitelist = false; // if the replacer is an array, we use the keys from it if (scx->replacer && JS_IsArrayObject(cx, scx->replacer)) { usingWhitelist = true; vec[2].setObject(*scx->replacer); keySource = &vec[2]; } JSBool memberWritten = JS_FALSE; AutoIdVector props(cx); if (!GetPropertyNames(cx, &keySource->toObject(), JSITER_OWNONLY, &props)) return JS_FALSE; for (size_t i = 0, len = props.length(); i < len; i++) { outputValue.setUndefined(); if (!usingWhitelist) { if (!js_ValueToStringId(cx, IdToValue(props[i]), &id)) return JS_FALSE; } else { // skip non-index properties jsuint index = 0; if (!js_IdIsIndex(props[i], &index)) continue; if (!scx->replacer->getProperty(cx, props[i], &whitelistElement)) return JS_FALSE; if (!js_ValueToStringId(cx, whitelistElement, &id)) return JS_FALSE; } // We should have a string id by this point. Either from // JS_Enumerate's id array, or by converting an element // of the whitelist. JS_ASSERT(JSID_IS_ATOM(id)); if (!JS_GetPropertyById(cx, obj, id, Jsvalify(&outputValue))) return JS_FALSE; if (outputValue.isObjectOrNull() && !js_TryJSON(cx, &outputValue)) return JS_FALSE; // call this here, so we don't write out keys if the replacer function // wants to elide the value. if (!CallReplacerFunction(cx, id, obj, scx, &outputValue)) return JS_FALSE; JSType type = JS_TypeOfValue(cx, Jsvalify(outputValue)); // elide undefined values and functions and XML if (outputValue.isUndefined() || type == JSTYPE_FUNCTION || type == JSTYPE_XML) continue; // output a comma unless this is the first member to write if (memberWritten && !scx->cb.append(',')) return JS_FALSE; memberWritten = JS_TRUE; if (!WriteIndent(cx, scx, scx->depth)) return JS_FALSE; // Be careful below, this string is weakly rooted JSString *s = js_ValueToString(cx, IdToValue(id)); if (!s) return JS_FALSE; const jschar *chars; size_t length; s->getCharsAndLength(chars, length); if (!write_string(cx, scx->cb, chars, length) || !scx->cb.append(':') || !(scx->gap.empty() || scx->cb.append(' ')) || !Str(cx, id, obj, scx, &outputValue, true)) { return JS_FALSE; } } if (memberWritten && !WriteIndent(cx, scx, scx->depth - 1)) return JS_FALSE; return scx->cb.append('}'); }