const char* jsd_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval) { jsval val = jsdval->val; JSCompartment* oldCompartment = NULL; if(!jsdval->className && !JSVAL_IS_PRIMITIVE(val)) { JSContext* cx = jsdc->dumbContext; JS::RootedObject obj(cx, JSVAL_TO_OBJECT(val)); JS_BeginRequest(cx); oldCompartment = JS_EnterCompartment(cx, obj); jsdval->className = JS_GetDebugClassName(obj); JS_LeaveCompartment(cx, oldCompartment); JS_EndRequest(cx); } return jsdval->className; }
bool ScriptEvent_OnSwapBuffers(HDC hDC, BOOL & bSwapRes) { JSAutoCompartment ac(g_JsCx, g_JsGlobal); jsval f; if(!JS_GetProperty(g_JsCx, g_JsGlobal, "onSwapBuffers", &f) || JSVAL_IS_PRIMITIVE(f)) return false; jsval y; jsval x[1] = { JS_NumberValue((unsigned int)hDC) }; if(!JS_CallFunctionValue(g_JsCx, g_JsGlobal, f, 1, x, &y)) return false; bSwapRes = JS::ToBoolean(y); return true; }
/* * Retrieve a JSFunction* from a JSDValue*. This differs from * JS_ValueToFunction by fully unwrapping the object first. */ JSFunction* jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; JS::RootedObject obj(cx); JS::RootedFunction fun(cx); JSCompartment* oldCompartment = NULL; if (JSVAL_IS_PRIMITIVE(jsdval->val)) return NULL; obj = js::UncheckedUnwrap(JSVAL_TO_OBJECT(jsdval->val)); oldCompartment = JS_EnterCompartment(cx, obj); fun = JS_ValueToFunction(cx, OBJECT_TO_JSVAL(obj)); JS_LeaveCompartment(cx, oldCompartment); return fun; }
// static nsresult IDBKeyRange::FromJSVal(JSContext* aCx, const jsval& aVal, IDBKeyRange** aKeyRange) { nsresult rv; nsRefPtr<IDBKeyRange> keyRange; if (JSVAL_IS_VOID(aVal) || JSVAL_IS_NULL(aVal)) { // undefined and null returns no IDBKeyRange. } else if (JSVAL_IS_PRIMITIVE(aVal)) { // A valid key returns an 'only' IDBKeyRange. keyRange = new IDBKeyRange(false, false, true); rv = GetKeyFromJSVal(aCx, aVal, keyRange->Lower()); if (NS_FAILED(rv)) { return rv; } } else { // An object is not permitted unless it's another IDBKeyRange. nsIXPConnect* xpc = nsContentUtils::XPConnect(); NS_ASSERTION(xpc, "This should never be null!"); nsCOMPtr<nsIXPConnectWrappedNative> wrapper; rv = xpc->GetWrappedNativeOfJSObject(aCx, JSVAL_TO_OBJECT(aVal), getter_AddRefs(wrapper)); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); nsCOMPtr<nsIIDBKeyRange> iface; if (!wrapper || !(iface = do_QueryInterface(wrapper->Native()))) { // Some random JS object? return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; } keyRange = static_cast<IDBKeyRange*>(iface.get()); } keyRange.forget(aKeyRange); return NS_OK; }
// Call WaiveXrayAndWrap when you have a JS object that you don't want to be // wrapped in an Xray wrapper. cx->compartment is the compartment that will be // using the returned object. If the object to be wrapped is already in the // correct compartment, then this returns the unwrapped object. bool WrapperFactory::WaiveXrayAndWrap(JSContext *cx, jsval *vp) { if (JSVAL_IS_PRIMITIVE(*vp)) return JS_WrapValue(cx, vp); JSObject *obj = js::UnwrapObject(JSVAL_TO_OBJECT(*vp)); obj = GetCurrentOuter(cx, obj); if (js::IsObjectInContextCompartment(obj, cx)) { *vp = OBJECT_TO_JSVAL(obj); return true; } obj = WaiveXray(cx, obj); if (!obj) return false; *vp = OBJECT_TO_JSVAL(obj); return JS_WrapValue(cx, vp); }
// Call WaiveXrayAndWrap when you have a JS object that you don't want to be // wrapped in an Xray wrapper. cx->compartment is the compartment that will be // using the returned object. If the object to be wrapped is already in the // correct compartment, then this returns the unwrapped object. bool WrapperFactory::WaiveXrayAndWrap(JSContext *cx, jsval *vp) { if (JSVAL_IS_PRIMITIVE(*vp)) return JS_WrapValue(cx, vp); JSObject *obj = JSVAL_TO_OBJECT(*vp)->unwrap(); obj = GetCurrentOuter(cx, obj); if (obj->compartment() == cx->compartment) { *vp = OBJECT_TO_JSVAL(obj); return true; } obj = WaiveXray(cx, obj); if (!obj) return false; *vp = OBJECT_TO_JSVAL(obj); return JS_WrapValue(cx, vp); }
jsval jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval) { JSObject* obj; JSContext* cx; jsval val = jsdval->val; if (!JSVAL_IS_PRIMITIVE(val)) { cx = JSD_GetDefaultJSContext(jsdc); obj = JS_ObjectToOuterObject(cx, JSVAL_TO_OBJECT(val)); if (!obj) { JS_ClearPendingException(cx); val = JSVAL_NULL; } else val = OBJECT_TO_JSVAL(obj); } return val; }
JSDValue* jsd_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval) { if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO))) { JSObject* obj; JSObject* proto; JS_ASSERT(!jsdval->proto); SET_BIT_FLAG(jsdval->flags, GOT_PROTO); if(JSVAL_IS_PRIMITIVE(jsdval->val)) return NULL; obj = JSVAL_TO_OBJECT(jsdval->val); proto = JS_GetPrototype(obj); if(!proto) return NULL; jsdval->proto = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(proto)); } if(jsdval->proto) jsdval->proto->nref++; return jsdval->proto; }
JSBool XPC_COW_RewrapForContent(JSContext *cx, JSObject *wrapperObj, jsval *vp) { jsval v = *vp; if (JSVAL_IS_PRIMITIVE(v)) { return JS_TRUE; } JSObject *obj = GetWrappedJSObject(cx, JSVAL_TO_OBJECT(v)); if (!obj) { *vp = JSVAL_NULL; return JS_TRUE; } if (JS_ObjectIsFunction(cx, obj)) { return XPC_COW_WrapFunction(cx, wrapperObj, obj, vp); } return XPC_COW_WrapObject(cx, JS_GetScopeChain(cx), OBJECT_TO_JSVAL(obj), vp); }
XPCVariant::XPCVariant(XPCCallContext& ccx, jsval aJSVal) : mJSVal(aJSVal) { nsVariant::Initialize(&mData); if(!JSVAL_IS_PRIMITIVE(mJSVal)) { // If the incoming object is an XPCWrappedNative, then it could be a // double-wrapped object, and we should return the double-wrapped // object back out to script. JSObject* proto; XPCWrappedNative* wn = XPCWrappedNative::GetWrappedNativeOfJSObject(ccx, JSVAL_TO_OBJECT(mJSVal), nsnull, &proto); mReturnRawObject = !wn && !proto; } else mReturnRawObject = JS_FALSE; }
JS_FRIEND_API(bool) JS_FASTCALL js_CloseIterator(JSContext *cx, jsval v) { JSObject *obj; JSClass *clasp; JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); obj = JSVAL_TO_OBJECT(v); clasp = OBJ_GET_CLASS(cx, obj); if (clasp == &js_IteratorClass) { js_CloseNativeIterator(cx, obj); } #if JS_HAS_GENERATORS else if (clasp == &js_GeneratorClass) { if (!CloseGenerator(cx, obj)) return JS_FALSE; } #endif return JS_TRUE; }
js_CallIteratorNext(JSContext *cx, JSObject *iterobj, jsval *rval) { uintN flags; /* Fast path for native iterators */ if (OBJ_GET_CLASS(cx, iterobj) == &js_IteratorClass) { flags = JSVAL_TO_INT(STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_FLAGS)); if (flags & JSITER_ENUMERATE) return CallEnumeratorNext(cx, iterobj, flags, rval); /* * Call next directly as all the methods of the native iterator are * read-only and permanent. */ if (!IteratorNextImpl(cx, iterobj, rval)) return JS_FALSE; } else { jsid id = ATOM_TO_JSID(cx->runtime->atomState.nextAtom); if (!JS_GetMethodById(cx, iterobj, id, &iterobj, rval)) return JS_FALSE; if (!js_InternalCall(cx, iterobj, *rval, 0, NULL, rval)) { /* Check for StopIteration. */ if (!cx->throwing || JSVAL_IS_PRIMITIVE(cx->exception) || OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(cx->exception)) != &js_StopIterationClass) { return JS_FALSE; } /* Inline JS_ClearPendingException(cx). */ cx->throwing = JS_FALSE; cx->exception = JSVAL_VOID; *rval = JSVAL_HOLE; return JS_TRUE; } } return JS_TRUE; }
static JSBool XrayWrapperConstructor(JSContext *cx, uintN argc, jsval *vp) { if (argc == 0) { return ThrowException(NS_ERROR_XPC_NOT_ENOUGH_ARGS, cx); } if (JSVAL_IS_PRIMITIVE(vp[2])) { return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); } JSObject *obj = JSVAL_TO_OBJECT(vp[2]); if (!obj->isWrapper()) { *vp = OBJECT_TO_JSVAL(obj); return JS_TRUE; } obj = obj->unwrap(); *vp = OBJECT_TO_JSVAL(obj); return JS_WrapValue(cx, vp); }
XPCVariant::XPCVariant(JSContext* cx, jsval aJSVal) : mJSVal(aJSVal), mCCGeneration(0) { nsVariant::Initialize(&mData); if (!JSVAL_IS_PRIMITIVE(mJSVal)) { // XXXbholley - The innerization here was from bug 638026. Blake says // the basic problem was that we were storing the C++ inner but the JS // outer, which meant that, after navigation, the JS inner could be // collected, which would cause us to try to recreate the JS inner at // some later point after teardown, which would crash. This is shouldn't // be a problem anymore because SetParentToWindow will do the right // thing, but I'm saving the cleanup here for another day. Blake thinks // that we should just not store the WN if we're creating a variant for // an outer window. JSObject *obj = JS_ObjectToInnerObject(cx, JSVAL_TO_OBJECT(mJSVal)); mJSVal = OBJECT_TO_JSVAL(obj); JSObject *unwrapped = js::UnwrapObjectChecked(obj, /* stopAtOuter = */ false); mReturnRawObject = !(unwrapped && IS_WN_WRAPPER(unwrapped)); } else mReturnRawObject = false; }
void DEBUG_CheckForComponentsInScope(JSContext* cx, JSObject* obj, JSObject* startingObj, JSBool OKIfNotInitialized, XPCJSRuntime* runtime) { if(OKIfNotInitialized) return; if(!(JS_GetOptions(cx) & JSOPTION_PRIVATE_IS_NSISUPPORTS)) return; const char* name = runtime->GetStringName(XPCJSRuntime::IDX_COMPONENTS); jsval prop; if(JS_LookupProperty(cx, obj, name, &prop) && !JSVAL_IS_PRIMITIVE(prop)) return; // This is pretty much always bad. It usually means that native code is // making a callback to an interface implemented in JavaScript, but the // document where the JS object was created has already been cleared and the // global properties of that document's window are *gone*. Generally this // indicates a problem that should be addressed in the design and use of the // callback code. NS_ERROR("XPConnect is being called on a scope without a 'Components' property! (stack and details follow)"); printf("The current JS stack is:\n"); xpc_DumpJSStack(cx, JS_TRUE, JS_TRUE, JS_TRUE); printf("And the object whose scope lacks a 'Components' property is:\n"); js_DumpObject(startingObj); JSObject *p = startingObj; while(p->isWrapper()) { p = p->getProxyPrivate().toObjectOrNull(); if(!p) break; printf("which is a wrapper for:\n"); js_DumpObject(p); } }
static JSBool XPC_XOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) { JSObject *iface = GetWrappedObject(cx, obj); XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { return ThrowException(NS_ERROR_FAILURE, cx); } nsresult rv = CanAccessWrapper(cx, iface, nsnull); if (NS_FAILED(rv)) { if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { // Don't do this test across origins. return ThrowException(rv, cx); } return JS_FALSE; } JSClass *clasp = STOBJ_GET_CLASS(iface); *bp = JS_FALSE; if (!clasp->hasInstance) { return JS_TRUE; } // Prematurely unwrap the left hand side. if (!JSVAL_IS_PRIMITIVE(v)) { JSObject *test = JSVAL_TO_OBJECT(v); // GetWrappedObject does an instanceof check. test = GetWrappedObject(cx, test); if (test) { v = OBJECT_TO_JSVAL(test); } } return clasp->hasInstance(cx, iface, v, bp); }
static JSBool XrayWrapperConstructor(JSContext *cx, unsigned argc, jsval *vp) { if (argc == 0) { return ThrowException(NS_ERROR_XPC_NOT_ENOUGH_ARGS, cx); } if (JSVAL_IS_PRIMITIVE(vp[2])) { return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); } JSObject *obj = JSVAL_TO_OBJECT(vp[2]); if (!js::IsWrapper(obj)) { *vp = OBJECT_TO_JSVAL(obj); return true; } obj = js::UnwrapObject(obj); *vp = OBJECT_TO_JSVAL(obj); return JS_WrapValue(cx, vp); }
static const nsID* GetIIDArg(PRUint32 argc, jsval* argv, JSContext* cx) { const nsID* iid; // If an IID was passed in then use it if(argc) { JSObject* iidobj; jsval val = *argv; if(JSVAL_IS_PRIMITIVE(val) || !(iidobj = JSVAL_TO_OBJECT(val)) || !(iid = xpc_JSObjectToID(cx, iidobj))) { return nsnull; } } else iid = &NS_GET_IID(nsISupports); return iid; }
/* [implicit_jscontext] uint32_t getAlignmentOffset (in jsval source); */ NS_IMETHODIMP dpoCContext::GetAlignmentOffset(const JS::Value & source, JSContext* cx, uint32_t *_retval) { JSObject *object; uint8_t *data; if (JSVAL_IS_PRIMITIVE(source)) { return NS_ERROR_INVALID_ARG; } object = JSVAL_TO_OBJECT(source); if (JS_IsTypedArrayObject(object)) { data = GetPointerFromTA(object, cx); } else if (JS_IsArrayBufferObject(object)) { data = JS_GetArrayBufferData(object); } else { return NS_ERROR_INVALID_ARG; } *_retval = (((uintptr_t) data) + alignment_size) / alignment_size * alignment_size - ((uintptr_t) data); return NS_OK; }
JSErrorReport * js_ErrorFromException(JSContext *cx, jsval exn) { JSObject *obj; JSExnPrivate *privateData; jsval privateValue; if (JSVAL_IS_PRIMITIVE(exn)) return NULL; obj = JSVAL_TO_OBJECT(exn); if (OBJ_GET_CLASS(cx, obj) != &ExceptionClass) return NULL; privateValue = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); if (JSVAL_IS_VOID(privateValue)) return NULL; privateData = (JSExnPrivate*) JSVAL_TO_PRIVATE(privateValue); if (!privateData) return NULL; JS_ASSERT(privateData->errorReport); return privateData->errorReport; }
leakmonJSObjectInfo::AppendSelfToString(nsString& aString) { if (!JSVAL_IS_PRIMITIVE(mJSValue)) { char buf[30]; PR_snprintf(buf, sizeof(buf), " (%p", static_cast<void*>(JSVAL_TO_OBJECT(mJSValue))); aString.Append(NS_ConvertASCIItoUTF16(buf)); if (!mFileName.IsEmpty()) { aString.Append(PRUnichar(',')); aString.Append(PRUnichar(' ')); aString.Append(mFileName); PR_snprintf(buf, sizeof(buf), ", %d-%d", mLineStart, mLineEnd); aString.Append(NS_ConvertASCIItoUTF16(buf)); } aString.Append(PRUnichar(')')); } aString.Append(PRUnichar(' ')); aString.Append(PRUnichar('=')); aString.Append(PRUnichar(' ')); aString.Append(mString); }
js::ValueRef wrap(JSContext *cx, jsval val) { if ( JSVAL_IS_BOOLEAN(val)) { return JSVAL_TO_BOOLEAN(val) ? true : false; } if ( JSVAL_IS_NULL(val)){ fprintf(stderr, "is null\n"); } if ( JSVAL_IS_VOID(val)){ fprintf(stderr, "is void\n"); } if ( JSVAL_IS_INT (val)){ fprintf(stderr, "is int\n"); } if ( JSVAL_IS_STRING(val)) { JSString *str = JSVAL_TO_STRING(val); //todo: memory leak is my middle name js::String *jsstr = new js::String((std::string)JS_EncodeString(cx, str)); return *jsstr; } if ( !JSVAL_IS_PRIMITIVE(val)) { JSObject* obj=JSVAL_TO_OBJECT(val); if (JS_IsArrayObject(cx, obj)){ std::vector<js::ValueRef> els; jsuint length; JS_GetArrayLength(cx, obj, &length); for (int i = 0; i < length; i++){ jsval ret; JS_GetElement(cx, obj, i, &ret); els.push_back(wrap(cx, ret)); } // leaking memory js::Array *array=new js::Array(els); return (*array); } } return (std::string)"<unknown type>"; }
/* PRBool hasInstance (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval val, out PRBool bp); */ NS_IMETHODIMP nsJSCID::HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, const jsval &val, PRBool *bp, PRBool *_retval) { *bp = JS_FALSE; nsresult rv = NS_OK; if(!JSVAL_IS_PRIMITIVE(val)) { // we have a JSObject JSObject* obj = JSVAL_TO_OBJECT(val); NS_ASSERTION(obj, "when is an object not an object?"); // is this really a native xpcom object with a wrapper? JSObject* obj2; XPCWrappedNative* other_wrapper = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj, nsnull, &obj2); if(!other_wrapper || !obj2) return NS_OK; nsIClassInfo* ci = other_wrapper ? other_wrapper->GetClassInfo() : GetSlimWrapperProto(obj2)->GetClassInfo(); // We consider CID equality to be the thing that matters here. // This is perhaps debatable. if(ci) { nsID cid; if(NS_SUCCEEDED(ci->GetClassIDNoAlloc(&cid))) *bp = cid.Equals(mDetails.ID()); } } return rv; }
static bool JSValToMatrixElts(JSContext* cx, const jsval& val, double* (&elts)[N], nsresult* rv) { JSObject* obj; jsuint length; if (JSVAL_IS_PRIMITIVE(val) || !(obj = JSVAL_TO_OBJECT(val)) || !JS_GetArrayLength(cx, obj, &length) || N != length) { // Not an array-like thing or wrong size *rv = NS_ERROR_INVALID_ARG; return false; } for (PRUint32 i = 0; i < N; ++i) { jsval elt; double d; if (!JS_GetElement(cx, obj, i, &elt)) { *rv = NS_ERROR_FAILURE; return false; } if (!CoerceDouble(elt, &d)) { *rv = NS_ERROR_INVALID_ARG; return false; } if (!FloatValidate(d)) { // This is weird, but it's the behavior of SetTransform() *rv = NS_OK; return false; } *elts[i] = d; } *rv = NS_OK; return true; }
VARTYPE XPCDispConvert::JSTypeToCOMType(XPCCallContext& ccx, jsval val) { if(JSVAL_IS_PRIMITIVE(val)) { if(JSVAL_IS_STRING(val)) { return VT_BSTR; } if(JSVAL_IS_INT(val)) { return VT_I4; } if(JSVAL_IS_DOUBLE(val)) { return VT_R8; } if(JSVAL_IS_BOOLEAN(val)) { return VT_BOOL; } if(JSVAL_IS_VOID(val)) { return VT_EMPTY; } if(JSVAL_IS_NULL(val)) { return VT_NULL; } } else { if(JS_IsArrayObject(ccx, JSVAL_TO_OBJECT(val))) return VT_ARRAY | VT_VARIANT; return VT_DISPATCH; } NS_ERROR("XPCDispConvert::JSTypeToCOMType was unable to identify the type of the jsval"); return VT_EMPTY; }
JSBool jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; jsval val = jsdval->val; JSFunction* fun; JSExceptionState* exceptionState; if(jsd_IsValueFunction(jsdc, jsdval)) { JSBool ok = JS_FALSE; JS_BeginRequest(cx); exceptionState = JS_SaveExceptionState(cx); fun = JS_ValueToFunction(cx, val); JS_RestoreExceptionState(cx, exceptionState); if(fun) ok = JS_GetFunctionScript(cx, fun) ? JS_FALSE : JS_TRUE; JS_EndRequest(cx); JS_ASSERT(fun); return ok; } return !JSVAL_IS_PRIMITIVE(val); }
XPCVariant::XPCVariant(XPCCallContext& ccx, jsval aJSVal) : mJSVal(aJSVal), mCCGeneration(0) { nsVariant::Initialize(&mData); if (!JSVAL_IS_PRIMITIVE(mJSVal)) { JSObject *obj = JS_ObjectToInnerObject(ccx, JSVAL_TO_OBJECT(mJSVal)); mJSVal = OBJECT_TO_JSVAL(obj); // If the incoming object is an XPCWrappedNative, then it could be a // double-wrapped object, and we should return the double-wrapped // object back out to script. JSObject* proto; XPCWrappedNative* wn = XPCWrappedNative::GetWrappedNativeOfJSObject(ccx, JSVAL_TO_OBJECT(mJSVal), nullptr, &proto); mReturnRawObject = !wn && !proto; } else mReturnRawObject = false; }
JSDValue* jsd_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO))) { JS::RootedObject obj(cx); JS::RootedObject proto(cx); JS_ASSERT(!jsdval->proto); SET_BIT_FLAG(jsdval->flags, GOT_PROTO); if(JSVAL_IS_PRIMITIVE(jsdval->val)) return NULL; obj = JSVAL_TO_OBJECT(jsdval->val); if(!JS_GetPrototype(cx, obj, proto.address())) return NULL; if(!proto) return NULL; jsdval->proto = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(proto)); } if(jsdval->proto) jsdval->proto->nref++; return jsdval->proto; }
static JSBool js_json_stringify(JSContext *cx, JSObject* pThis, uintN argc, jsval *vp, jsval* rval) { JSObject *obj; jsval *argv = vp; // Must throw an Error if there isn't a first arg if (!JS_ConvertArguments(cx, argc, argv, "o", &obj)) return JS_FALSE; // Only use objects and arrays as the root for now jsval v = OBJECT_TO_JSVAL(obj); JSBool ok = js_TryJSON(cx, &v); JSType type; if (!(ok && !JSVAL_IS_PRIMITIVE(v) && (type = JS_TypeOfValue(cx, v)) != JSTYPE_FUNCTION && type != JSTYPE_XML)) { JS_ReportError(cx, "Invalid argument."); return JS_FALSE; } JSString *s = JS_NewStringCopyN(cx, "", 0); if (!s) ok = JS_FALSE; if (ok) { jsval sv = STRING_TO_JSVAL(s); StringifyClosure sc; sc.cx = cx; sc.s = &sv; JSAutoTempValueRooter tvr(cx, 1, sc.s); ok = js_Stringify(cx, &v, NULL, &WriteCallback, &sc, 0); *rval = *sc.s; } return ok; }
JSBool js_json_stringify(JSContext *cx, uintN argc, jsval *vp) { JSObject *obj; jsval *argv = vp + 2; // Must throw an Error if there isn't a first arg if (!JS_ConvertArguments(cx, argc, argv, "o", &obj)) return JS_FALSE; // Only use objects and arrays as the root for now *vp = OBJECT_TO_JSVAL(obj); JSBool ok = js_TryJSON(cx, vp); JSType type; if (!ok || JSVAL_IS_PRIMITIVE(*vp) || ((type = JS_TypeOfValue(cx, *vp)) == JSTYPE_FUNCTION || type == JSTYPE_XML)) { JS_ReportError(cx, "Invalid argument"); return JS_FALSE; } JSString *s = JS_NewStringCopyN(cx, "", 0); if (!s) ok = JS_FALSE; if (ok) { jsval vec[2] = {STRING_TO_JSVAL(s), JSVAL_VOID}; StringifyClosure sc(cx, 2, vec); JSAutoTempValueRooter resultTvr(cx, 1, sc.s); ok = js_Stringify(cx, vp, NULL, &WriteCallback, &sc, 0); *vp = *sc.s; } return ok; }