/* ES5 15.12.2. */ JSBool js_json_parse(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); /* Step 1. */ JSString *str = (argc >= 1) ? ToString(cx, args[0]) : cx->names().undefined; if (!str) return false; JSStableString *stable = str->ensureStable(cx); if (!stable) return false; JS::Anchor<JSString *> anchor(stable); RootedValue reviver(cx, (argc >= 2) ? args[1] : UndefinedValue()); /* Steps 2-5. */ return ParseJSONWithReviver(cx, stable->chars(), stable->length(), reviver, args.rval()); }
bool JSStructuredCloneReader::startRead(Value *vp) { uint32_t tag, data; if (!in.readPair(&tag, &data)) return false; switch (tag) { case SCTAG_NULL: vp->setNull(); break; case SCTAG_UNDEFINED: vp->setUndefined(); break; case SCTAG_BOOLEAN: case SCTAG_BOOLEAN_OBJECT: vp->setBoolean(!!data); if (tag == SCTAG_BOOLEAN_OBJECT && !js_PrimitiveToObject(context(), vp)) return false; break; case SCTAG_STRING: case SCTAG_STRING_OBJECT: { JSString *str = readString(data); if (!str) return false; vp->setString(str); if (tag == SCTAG_STRING_OBJECT && !js_PrimitiveToObject(context(), vp)) return false; break; } case SCTAG_NUMBER_OBJECT: { double d; if (!in.readDouble(&d) || !checkDouble(d)) return false; vp->setDouble(d); if (!js_PrimitiveToObject(context(), vp)) return false; break; } case SCTAG_DATE_OBJECT: { double d; if (!in.readDouble(&d) || !checkDouble(d)) return false; if (!IsNaN(d) && d != TimeClip(d)) { JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "date"); return false; } JSObject *obj = js_NewDateObjectMsec(context(), d); if (!obj) return false; vp->setObject(*obj); break; } case SCTAG_REGEXP_OBJECT: { RegExpFlag flags = RegExpFlag(data); uint32_t tag2, nchars; if (!in.readPair(&tag2, &nchars)) return false; if (tag2 != SCTAG_STRING) { JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "regexp"); return false; } JSString *str = readString(nchars); if (!str) return false; JSStableString *stable = str->ensureStable(context()); if (!stable) return false; size_t length = stable->length(); const StableCharPtr chars = stable->chars(); RegExpObject *reobj = RegExpObject::createNoStatics(context(), chars.get(), length, flags, NULL); if (!reobj) return false; vp->setObject(*reobj); break; } case SCTAG_ARRAY_OBJECT: case SCTAG_OBJECT_OBJECT: { JSObject *obj = (tag == SCTAG_ARRAY_OBJECT) ? NewDenseEmptyArray(context()) : NewBuiltinClassInstance(context(), &ObjectClass); if (!obj || !objs.append(ObjectValue(*obj))) return false; vp->setObject(*obj); break; } case SCTAG_BACK_REFERENCE_OBJECT: { if (data >= allObjs.length()) { JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "invalid back reference in input"); return false; } *vp = allObjs[data]; return true; } case SCTAG_TRANSFER_MAP_HEADER: // A map header cannot be here but just at the beginning of the buffer. JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "invalid input"); return false; case SCTAG_TRANSFER_MAP: // A map cannot be here but just at the beginning of the buffer. JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "invalid input"); return false; case SCTAG_ARRAY_BUFFER_OBJECT: if (!readArrayBuffer(data, vp)) return false; break; case SCTAG_TYPED_ARRAY_OBJECT: // readTypedArray adds the array to allObjs uint64_t arrayType; if (!in.read(&arrayType)) return false; return readTypedArray(arrayType, data, vp); break; default: { if (tag <= SCTAG_FLOAT_MAX) { double d = ReinterpretPairAsDouble(tag, data); if (!checkDouble(d)) return false; vp->setNumber(d); break; } if (SCTAG_TYPED_ARRAY_V1_MIN <= tag && tag <= SCTAG_TYPED_ARRAY_V1_MAX) { // A v1-format typed array // readTypedArray adds the array to allObjs return readTypedArray(TagToV1ArrayType(tag), data, vp, true); } if (!callbacks || !callbacks->read) { JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "unsupported type"); return false; } JSObject *obj = callbacks->read(context(), this, tag, data, closure); if (!obj) return false; vp->setObject(*obj); } } if (vp->isObject() && !allObjs.append(*vp)) return false; return true; }