VXIcharToJschar(const VXIchar * x) : cstr(NULL), len(0) { if (x == NULL) return; len = wcslen(x); cstr = new jschar[len + 1]; if (cstr == NULL) return; for (unsigned int i = 0; i < len + 1; ++i) // We throw out any surrogate characters (0xD800 - 0xDFFF) cstr[i] = ((x[i] ^ 0xD800) < 0x0100) ? jschar(0xBF) : jschar(x[i]); }
JSBool js_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, JSONWriteCallback callback, void *data, uint32 depth) { if (depth > JSON_MAX_DEPTH) return JS_FALSE; /* encoding error */ JSBool ok = JS_TRUE; JSObject *obj = JSVAL_TO_OBJECT(*vp); JSBool isArray = JS_IsArrayObject(cx, obj); jschar output = jschar(isArray ? '[' : '{'); if (!callback(&output, 1, data)) return JS_FALSE; JSObject *iterObj = NULL; jsint i = 0; jsuint length = 0; if (isArray) { if (!JS_GetArrayLength(cx, obj, &length)) return JS_FALSE; } else { if (!js_ValueToIterator(cx, JSITER_ENUMERATE, vp)) return JS_FALSE; iterObj = JSVAL_TO_OBJECT(*vp); } jsval outputValue = JSVAL_VOID; JSAutoTempValueRooter tvr(cx, 1, &outputValue); jsval key; JSBool memberWritten = JS_FALSE; do { outputValue = JSVAL_VOID; if (isArray) { if ((jsuint)i >= length) break; ok = JS_GetElement(cx, obj, i++, &outputValue); } else { ok = js_CallIteratorNext(cx, iterObj, &key); if (!ok) break; if (key == JSVAL_HOLE) break; JSString *ks; if (JSVAL_IS_STRING(key)) { ks = JSVAL_TO_STRING(key); } else { ks = JS_ValueToString(cx, key); if (!ks) { ok = JS_FALSE; break; } } ok = JS_GetUCProperty(cx, obj, JS_GetStringChars(ks), JS_GetStringLength(ks), &outputValue); } if (!ok) break; // if this is an array, holes are transmitted as null if (isArray && outputValue == JSVAL_VOID) { outputValue = JSVAL_NULL; } else if (JSVAL_IS_OBJECT(outputValue)) { ok = js_TryJSON(cx, &outputValue); if (!ok) break; } // elide undefined values if (outputValue == JSVAL_VOID) continue; // output a comma unless this is the first member to write if (memberWritten) { output = jschar(','); ok = callback(&output, 1, data); if (!ok) break; } memberWritten = JS_TRUE; JSType type = JS_TypeOfValue(cx, outputValue); // Can't encode these types, so drop them if (type == JSTYPE_FUNCTION || type == JSTYPE_XML) break; // Be careful below, this string is weakly rooted. JSString *s; // If this isn't an array, we need to output a key if (!isArray) { s = JS_ValueToString(cx, key); if (!s) { ok = JS_FALSE; break; } ok = write_string(cx, callback, data, JS_GetStringChars(s), JS_GetStringLength(s)); if (!ok) break; output = jschar(':'); ok = callback(&output, 1, data); if (!ok) break; } if (!JSVAL_IS_PRIMITIVE(outputValue)) { // recurse ok = js_Stringify(cx, &outputValue, replacer, callback, data, depth + 1); } else { JSString *outputString; s = JS_ValueToString(cx, outputValue); if (!s) { ok = JS_FALSE; break; } if (type == JSTYPE_STRING) { ok = write_string(cx, callback, data, JS_GetStringChars(s), JS_GetStringLength(s)); if (!ok) break; continue; } if (type == JSTYPE_NUMBER) { if (JSVAL_IS_DOUBLE(outputValue)) { jsdouble d = *JSVAL_TO_DOUBLE(outputValue); if (!JSDOUBLE_IS_FINITE(d)) outputString = JS_NewStringCopyN(cx, "null", 4); else outputString = s; } else { outputString = s; } } else if (type == JSTYPE_BOOLEAN) { outputString = s; } else if (JSVAL_IS_NULL(outputValue)) { outputString = JS_NewStringCopyN(cx, "null", 4); } else { ok = JS_FALSE; // encoding error break; } ok = callback(JS_GetStringChars(outputString), JS_GetStringLength(outputString), data); } } while (ok); if (iterObj) { // Always close the iterator, but make sure not to stomp on OK js_CloseIteratorState(cx, iterObj); // encoding error or propagate? FIXME: Bug 408838. } if (!ok) { JS_ReportError(cx, "Error during JSON encoding."); return JS_FALSE; } output = jschar(isArray ? ']' : '}'); ok = callback(&output, 1, data); return ok; }
JSBool js_TryJSON(JSContext *cx, jsval *vp) { // Checks whether the return value implements toJSON() JSBool ok = JS_TRUE; if (!JSVAL_IS_PRIMITIVE(*vp)) { JSObject *obj = JSVAL_TO_OBJECT(*vp); ok = js_TryMethod(cx, obj, cx->runtime->atomState.toJSONAtom, 0, NULL, vp); } return ok; } static const jschar quote = jschar('"'); static const jschar backslash = jschar('\\'); static const jschar unicodeEscape[] = {'\\', 'u', '0', '0'}; static JSBool write_string(JSContext *cx, JSONWriteCallback callback, void *data, const jschar *buf, uint32 len) { if (!callback("e, 1, data)) return JS_FALSE; uint32 mark = 0; uint32 i; for (i = 0; i < len; ++i) { if (buf[i] == quote || buf[i] == backslash) { if (!callback(&buf[mark], i - mark, data) || !callback(&backslash, 1, data) || !callback(&buf[i], 1, data)) {