/* bool newResolve (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsid id, in PRUint32 flags, out JSObjectPtr objp); */ NS_IMETHODIMP calDateTime::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, PRUint32 flags, JSObject * *objp, bool *_retval) { NS_ENSURE_ARG_POINTER(objp); NS_ENSURE_ARG_POINTER(_retval); if (JSID_IS_STRING(id)) { size_t length; JSString *idString = JSID_TO_STRING(id); const jschar *str = JS_GetStringCharsAndLength(cx, idString, &length); nsDependentString const name(reinterpret_cast<PRUnichar const*>(str), length); if (name.EqualsLiteral("jsDate")) { *_retval = JS_DefineUCProperty(cx, obj, str, length, JSVAL_VOID, nsnull, nsnull, 0); *objp = obj; return *_retval ? NS_OK : NS_ERROR_FAILURE; } } *_retval = PR_TRUE; return NS_OK; }
nsresult nsDOMWorkerTimeout::ExpressionCallback::Run(nsDOMWorkerTimeout* aTimeout, JSContext* aCx) { JSObject* global = JS_GetGlobalObject(aCx); NS_ENSURE_TRUE(global, NS_ERROR_FAILURE); JSPrincipals* principal = nsDOMWorkerSecurityManager::WorkerPrincipal(); NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE); JSString* expression = JS_ValueToString(aCx, mExpression); NS_ENSURE_TRUE(expression, NS_ERROR_FAILURE); size_t stringLength; const jschar* string = JS_GetStringCharsAndLength(aCx, expression, &stringLength); NS_ENSURE_TRUE(string, NS_ERROR_FAILURE); PRBool success = JS_EvaluateUCScriptForPrincipals(aCx, global, principal, string, stringLength, mFileName.get(), mLineNumber, nsnull); if (!success) { return NS_ERROR_FAILURE; } return NS_OK; }
/** * gjs_string_get_uint16_data: * @context: js context * @value: a jsval * @data_p: address to return allocated data buffer * @len_p: address to return length of data (number of 16-bit integers) * * Get the binary data (as a sequence of 16-bit integers) in the JSString * contained in @value. * Throws a JS exception if value is not a string. * * Returns: JS_FALSE if exception thrown **/ JSBool gjs_string_get_uint16_data(JSContext *context, jsval value, guint16 **data_p, gsize *len_p) { const jschar *js_data; JSBool retval = JS_FALSE; JS_BeginRequest(context); if (!JSVAL_IS_STRING(value)) { gjs_throw(context, "Value is not a string, can't return binary data from it"); goto out; } js_data = JS_GetStringCharsAndLength(context, JSVAL_TO_STRING(value), len_p); if (js_data == NULL) goto out; *data_p = (guint16*) g_memdup(js_data, sizeof(*js_data)*(*len_p)); retval = JS_TRUE; out: JS_EndRequest(context); return retval; }
/** * gjs_string_get_char16_data: * @context: js context * @value: a JS::Value * @data_p: address to return allocated data buffer * @len_p: address to return length of data (number of 16-bit characters) * * Get the binary data (as a sequence of 16-bit characters) in the JSString * contained in @value. * Throws a JS exception if value is not a string. * * Returns: false if exception thrown **/ bool gjs_string_get_char16_data(JSContext *context, JS::Value value, char16_t **data_p, size_t *len_p) { const char16_t *js_data; bool retval = false; JS_BeginRequest(context); if (!value.isString()) { gjs_throw(context, "Value is not a string, can't return binary data from it"); goto out; } js_data = JS_GetStringCharsAndLength(context, value.toString(), len_p); if (js_data == NULL) goto out; *data_p = (char16_t *) g_memdup(js_data, sizeof(*js_data) * (*len_p)); retval = true; out: JS_EndRequest(context); return retval; }
bool ScriptInterface::EnumeratePropertyNamesWithPrefix(JS::HandleValue objVal, const char* prefix, std::vector<std::string>& out) { JSAutoRequest rq(m->m_cx); if (!objVal.isObjectOrNull()) { LOGERROR("EnumeratePropertyNamesWithPrefix expected object type!"); return false; } if(objVal.isNull()) return true; // reached the end of the prototype chain JS::RootedObject obj(m->m_cx, &objVal.toObject()); JS::RootedObject it(m->m_cx, JS_NewPropertyIterator(m->m_cx, obj)); if (!it) return false; while (true) { JS::RootedId idp(m->m_cx); JS::RootedValue val(m->m_cx); if (! JS_NextProperty(m->m_cx, it, idp.address()) || ! JS_IdToValue(m->m_cx, idp, &val)) return false; if (val.isUndefined()) break; // end of iteration if (!val.isString()) continue; // ignore integer properties JS::RootedString name(m->m_cx, val.toString()); size_t len = strlen(prefix)+1; std::vector<char> buf(len); size_t prefixLen = strlen(prefix) * sizeof(char); JS_EncodeStringToBuffer(m->m_cx, name, &buf[0], prefixLen); buf[len-1]= '\0'; if(0 == strcmp(&buf[0], prefix)) { size_t len; const jschar* chars = JS_GetStringCharsAndLength(m->m_cx, name, &len); out.push_back(std::string(chars, chars+len)); } } // Recurse up the prototype chain JS::RootedObject prototype(m->m_cx); if (JS_GetPrototype(m->m_cx, obj, &prototype)) { JS::RootedValue prototypeVal(m->m_cx, JS::ObjectOrNullValue(prototype)); if (! EnumeratePropertyNamesWithPrefix(prototypeVal, prefix, out)) return false; } return true; }
NS_IMETHODIMP StatementParams::NewResolve(nsIXPConnectWrappedNative *aWrapper, JSContext *aCtx, JSObject *aScopeObj, jsid aId, uint32_t aFlags, JSObject **_objp, bool *_retval) { NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED); // We do not throw at any point after this unless our index is out of range // because we want to allow the prototype chain to be checked for the // property. JS::RootedObject scope(aCtx, aScopeObj); JS::RootedId id(aCtx, aId); bool resolved = false; bool ok = true; if (JSID_IS_INT(id)) { uint32_t idx = JSID_TO_INT(id); // Ensure that our index is within range. We do not care about the // prototype chain being checked here. if (idx >= mParamCount) return NS_ERROR_INVALID_ARG; ok = ::JS_DefineElement(aCtx, scope, idx, JSVAL_VOID, nullptr, nullptr, JSPROP_ENUMERATE); resolved = true; } else if (JSID_IS_STRING(id)) { JSString *str = JSID_TO_STRING(id); size_t nameLength; const jschar *nameChars = JS_GetStringCharsAndLength(aCtx, str, &nameLength); NS_ENSURE_TRUE(nameChars, NS_ERROR_UNEXPECTED); // Check to see if there's a parameter with this name, and if not, let // the rest of the prototype chain be checked. NS_ConvertUTF16toUTF8 name(nameChars, nameLength); uint32_t idx; nsresult rv = mStatement->GetParameterIndex(name, &idx); if (NS_SUCCEEDED(rv)) { ok = ::JS_DefinePropertyById(aCtx, scope, id, JSVAL_VOID, nullptr, nullptr, JSPROP_ENUMERATE); resolved = true; } } *_retval = ok; *_objp = resolved && ok ? scope.get() : nullptr; return NS_OK; }
template<> bool ScriptInterface::FromJSVal<std::wstring>(JSContext* cx, jsval v, std::wstring& out) { WARN_IF_NOT(JSVAL_IS_STRING(v) || JSVAL_IS_NUMBER(v), v); // allow implicit number conversions JSString* ret = JS_ValueToString(cx, v); if (!ret) FAIL("Argument must be convertible to a string"); size_t length; const jschar* ch = JS_GetStringCharsAndLength(cx, ret, &length); if (!ch) FAIL("JS_GetStringsCharsAndLength failed"); // out of memory out = std::wstring(ch, ch + length); return true; }
CStrW ScriptingHost::ValueToUCString( const jsval value ) { JSString* string = JS_ValueToString(m_Context, value); if (string == NULL) throw PSERROR_Scripting_ConversionFailed(); size_t length; const jschar *strptr = JS_GetStringCharsAndLength(m_Context, string, &length); if (!strptr) throw PSERROR_Scripting_ConversionFailed(); return std::wstring(strptr, strptr+length); }
JSBool js_babedash_constructParticleDefs(JSContext* cx,uint32_t argc,jsval *vp) { CCLog("--js_babedash_constructParticleDefs-- constructing particle defs"); jsval *argv = JS_ARGV(cx, vp); jsval val = JSVAL_NULL; JSObject* defsObj = NULL; defsObj = JSVAL_TO_OBJECT(argv[0]); if(defsObj == NULL) { CCLog("particle defs obj is NULL!"); return JS_FALSE; } std::string plistFile; BDResourceManager::GetInstance()->SetParticleDefs(new CCDictionary()); for(int i = 0;;i++) { JS_GetElement(cx,defsObj,i,&val); if(!JSVAL_IS_VOID(val)) { JSString* jsstr; if(JSVAL_IS_STRING(val)) { jsstr=JSVAL_TO_STRING(val); } else { jsstr=JS_ValueToString(cx,val); } size_t len = 0; const jschar* p = JS_GetStringCharsAndLength(cx,jsstr,&len); WCharArrToString((unsigned short*)p,plistFile); BDParticleSystemDef* particleDef = new BDParticleSystemDef(); particleDef->initWithFile(plistFile.c_str()); BDResourceManager::GetInstance()->GetParticleDefs()->setObject(particleDef,plistFile); } else break; } return JS_TRUE; }
JSBool JetpackChild::EvalInSandbox(JSContext* cx, uintN argc, jsval* vp) { if (argc != 2) { JS_ReportError(cx, "evalInSandbox takes two arguments"); return JS_FALSE; } jsval* argv = JS_ARGV(cx, vp); JSObject* obj; if (!JSVAL_IS_OBJECT(argv[0]) || !(obj = JSVAL_TO_OBJECT(argv[0]))) { JS_ReportError(cx, "The first argument to evalInSandbox must be a global object created using createSandbox."); JS_ASSERT(JS_FALSE); return JS_FALSE; } // Unwrap, and switch compartments obj = js::UnwrapObject(obj); JSAutoEnterCompartment ac; if (!ac.enter(cx, obj)) return JS_FALSE; if (&sGlobalClass != JS_GetClass(cx, obj) || obj == JS_GetGlobalObject(cx)) { JS_ReportError(cx, "The first argument to evalInSandbox must be a global object created using createSandbox."); JS_ASSERT(JS_FALSE); return JS_FALSE; } if (!JS_WrapValue(cx, &argv[1])) return JS_FALSE; JSString* str = JS_ValueToString(cx, argv[1]); if (!str) return JS_FALSE; size_t length; const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length); if (!chars) return JS_FALSE; js::AutoValueRooter ignored(cx); return JS_EvaluateUCScript(cx, obj, chars, length, "", 1, ignored.jsval_addr()); }
nsresult leakmonJSObjectInfo::AppendProperty(jsid aID, JSContext *aCx, leakmonObjectsInReportTable &aObjectsInReport) { jsval n; JSBool ok = JS_IdToValue(aCx, aID, &n); NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); // n should be an integer, a string, or an XML QName, // AttributeName, or AnyName // XXX This can execute JS code! How bad is that? // shaver didn't seem too scared when I described it to him. // XXX Could I avoid JS_ValueToString and still handle XML objects // correctly? JSString *nstr = JS_ValueToString(aCx, n); NS_ENSURE_TRUE(nstr, NS_ERROR_OUT_OF_MEMORY); size_t propname_len; const jschar *propname = JS_GetStringCharsAndLength(aCx, nstr, &propname_len); NS_ENSURE_TRUE(propname, NS_ERROR_OUT_OF_MEMORY); // XXX JS_GetUCProperty can execute JS code! How bad is that? // shaver didn't seem too scared when I described it to him. // Since js_GetProperty starts with a call to js_LookupProperty, // it's clear that JS_LookupUCProperty does less than // JS_GetUCProperty, so prefer Lookup over Get (although it's not // clear to me exactly what the differences are). jsval v; ok = JS_LookupPropertyById(aCx, JSVAL_TO_OBJECT(mJSValue), aID, &v); NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); leakmonJSObjectInfo *info; void *key = reinterpret_cast<void*>(JSVAL_BITS(v)); if (!aObjectsInReport.Get(key, &info)) { info = new leakmonJSObjectInfo(v); NS_ENSURE_TRUE(info, NS_ERROR_OUT_OF_MEMORY); aObjectsInReport.Put(key, info); } PropertyStruct *ps = mProperties.AppendElement(); ps->mName.Assign(reinterpret_cast<const PRUnichar*>(propname), propname_len); ps->mValue = info; return NS_OK; }
static JSBool ReceiverCommon(JSContext* cx, uintN argc, jsval* vp, const char* methodName, uintN arity, ReceiverResult* result) { if (argc != arity) { JS_ReportError(cx, "%s requires exactly %d arguments", methodName, arity); return JS_FALSE; } // Not currently possible, but think of the future. if (arity < 1) return JS_TRUE; jsval* argv = JS_ARGV(cx, vp); JSString* str = JS_ValueToString(cx, argv[0]); if (!str) { JS_ReportError(cx, "%s expects a stringifiable value as its first argument", methodName); return JS_FALSE; } size_t length; const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length); if (!chars) return JS_FALSE; result->msgName.Assign(chars, length); if (arity < 2) return JS_TRUE; if (JS_TypeOfValue(cx, argv[1]) != JSTYPE_FUNCTION) { JS_ReportError(cx, "%s expects a function as its second argument", methodName); return JS_FALSE; } // GC-safe because argv is rooted. result->receiver = argv[1]; return JS_TRUE; }
static JSBool MessageCommon(JSContext* cx, uintN argc, jsval* vp, MessageResult* result) { if (argc < 1) { JS_ReportError(cx, "Message requires a name, at least"); return JS_FALSE; } jsval* argv = JS_ARGV(cx, vp); JSString* msgNameStr = JS_ValueToString(cx, argv[0]); if (!msgNameStr) { JS_ReportError(cx, "Could not convert value to string"); return JS_FALSE; } size_t length; const jschar* chars = JS_GetStringCharsAndLength(cx, msgNameStr, &length); if (!chars) return JS_FALSE; result->msgName.Assign(chars, length); result->data.Clear(); if (!result->data.SetCapacity(argc)) { JS_ReportOutOfMemory(cx); return JS_FALSE; } for (uintN i = 1; i < argc; ++i) { Variant* vp = result->data.AppendElement(); if (!JetpackActorCommon::jsval_to_Variant(cx, argv[i], vp)) { JS_ReportError(cx, "Invalid message argument at position %d", i); return JS_FALSE; } } return JS_TRUE; }
/** * gjs_string_to_ucs4: * @cx: a #JSContext * @value: JS::Value containing a string * @ucs4_string_p: return location for a #gunichar array * @len_p: return location for @ucs4_string_p length * * Returns: true on success, false otherwise in which case a JS error is thrown */ bool gjs_string_to_ucs4(JSContext *cx, JS::HandleValue value, gunichar **ucs4_string_p, size_t *len_p) { if (ucs4_string_p == NULL) return true; if (!value.isString()) { gjs_throw(cx, "Value is not a string, cannot convert to UCS-4"); return false; } JSAutoRequest ar(cx); JS::RootedString str(cx, value.toString()); size_t utf16_len; GError *error = NULL; const char16_t *utf16 = JS_GetStringCharsAndLength(cx, str, &utf16_len); if (utf16 == NULL) { gjs_throw(cx, "Failed to get UTF-16 string data"); return false; } if (ucs4_string_p != NULL) { long length; *ucs4_string_p = g_utf16_to_ucs4(reinterpret_cast<const gunichar2 *>(utf16), utf16_len, NULL, &length, &error); if (*ucs4_string_p == NULL) { gjs_throw(cx, "Failed to convert UTF-16 string to UCS-4: %s", error->message); g_clear_error(&error); return false; } if (len_p != NULL) *len_p = (size_t) length; } return true; }
static void ValueToString(JSContext *cx, jsval aJSValue, nsString& aString) { if (JSVAL_IS_VOID(aJSValue)) { aString.Assign(kUndefined, STRLEN_ARRAY(kUndefined)); } else if (JSVAL_IS_NULL(aJSValue)) { aString.Assign(kNull, STRLEN_ARRAY(kNull)); } else if (JSVAL_IS_INT(aJSValue)) { jsint i = JSVAL_TO_INT(aJSValue); char buf[20]; PR_snprintf(buf, sizeof(buf), "%d", i); aString.Assign(NS_ConvertASCIItoUTF16(buf)); } else if (JSVAL_IS_DOUBLE(aJSValue)) { jsdouble d = JSVAL_TO_DOUBLE(aJSValue); char buf[50]; PR_snprintf(buf, sizeof(buf), "%f", d); aString.Assign(NS_ConvertASCIItoUTF16(buf)); } else if (JSVAL_IS_BOOLEAN(aJSValue)) { JSBool b = JSVAL_TO_BOOLEAN(aJSValue); if (b) aString.Assign(kTrue, STRLEN_ARRAY(kTrue)); else aString.Assign(kFalse, STRLEN_ARRAY(kFalse)); } else if (JSVAL_IS_STRING(aJSValue)) { JSString *str = JSVAL_TO_STRING(aJSValue); size_t len; const jschar *chars = JS_GetStringCharsAndLength(cx, str, &len); NS_ASSERTION(chars, "out of memory"); if (chars) { NS_ASSERTION(sizeof(jschar) == sizeof(PRUnichar), "char size mismatch"); aString.Assign(reinterpret_cast<const PRUnichar*>(chars), len); } } else { JSObject *obj = JSVAL_TO_OBJECT(aJSValue); JSClass *clazz = JS_GetClass(cx, obj); aString.Assign(PRUnichar('[')); aString.Append(NS_ConvertASCIItoUTF16(clazz->name)); aString.Append(PRUnichar(']')); } }
/* bool setProperty (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsid id, in JSValPtr vp); */ NS_IMETHODIMP calDateTime::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, jsval * vp, bool *_retval) { NS_ENSURE_ARG_POINTER(_retval); if (JSID_IS_STRING(id)) { size_t length; JSString *idString = JSID_TO_STRING(id); const jschar *str = JS_GetStringCharsAndLength(cx, idString, &length); nsDependentString const val(reinterpret_cast<PRUnichar const*>(str), length); if (val.EqualsLiteral("jsDate") && vp) { JSObject *dobj; if (!JSVAL_IS_OBJECT(*vp) || !js_DateIsValid(cx, (dobj = JSVAL_TO_OBJECT(*vp)))) { mIsValid = PR_FALSE; } else { jsdouble utcMsec = js_DateGetMsecSinceEpoch(cx, dobj); PRTime utcTime, thousands; LL_F2L(utcTime, utcMsec); LL_I2L(thousands, 1000); LL_MUL(utcTime, utcTime, thousands); nsresult rv = SetNativeTime(utcTime); if (NS_SUCCEEDED(rv)) { mIsValid = PR_TRUE; } else { mIsValid = PR_FALSE; } } *_retval = PR_TRUE; return NS_SUCCESS_I_DID_SOMETHING; } } *_retval = PR_TRUE; return NS_OK; }
/* bool getProperty (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsid id, in JSValPtr vp); */ NS_IMETHODIMP calDateTime::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj_, jsid id, jsval * vp, bool *_retval) { NS_ENSURE_ARG_POINTER(vp); NS_ENSURE_ARG_POINTER(_retval); if (JSID_IS_STRING(id)) { size_t length; JSString *idString = JSID_TO_STRING(id); const jschar *str = JS_GetStringCharsAndLength(cx, idString, &length); nsDependentString const val(reinterpret_cast<PRUnichar const*>(str), length); if (val.EqualsLiteral("jsDate")) { PRTime tmp, thousand; jsdouble msec; LL_I2L(thousand, 1000); LL_DIV(tmp, mNativeTime, thousand); LL_L2D(msec, tmp); ensureTimezone(); JSObject *obj; bool b; if (NS_SUCCEEDED(mTimezone->GetIsFloating(&b)) && b) { obj = js_NewDateObject(cx, mYear, mMonth, mDay, mHour, mMinute, mSecond); } else { obj = js_NewDateObjectMsec(cx, msec); } *vp = OBJECT_TO_JSVAL(obj); *_retval = PR_TRUE; return NS_SUCCESS_I_DID_SOMETHING; } } *_retval = PR_TRUE; return NS_OK; }
bool ScriptInterface::EnumeratePropertyNamesWithPrefix(jsval obj, const char* prefix, std::vector<std::string>& out) { utf16string prefix16 (prefix, prefix+strlen(prefix)); if (! JSVAL_IS_OBJECT(obj)) return false; // TODO: log error messages JSObject* it = JS_NewPropertyIterator(m->m_cx, JSVAL_TO_OBJECT(obj)); if (!it) return false; while (true) { jsid idp; jsval val; if (! JS_NextProperty(m->m_cx, it, &idp) || ! JS_IdToValue(m->m_cx, idp, &val)) return false; if (val == JSVAL_VOID) break; // end of iteration if (! JSVAL_IS_STRING(val)) continue; // ignore integer properties JSString* name = JSVAL_TO_STRING(val); size_t len; const jschar* chars = JS_GetStringCharsAndLength(m->m_cx, name, &len); if (chars && len >= prefix16.size() && memcmp(chars, prefix16.c_str(), prefix16.size()*2) == 0) out.push_back(std::string(chars, chars+len)); // handles Unicode poorly } // Recurse up the prototype chain JSObject* prototype = JS_GetPrototype(m->m_cx, JSVAL_TO_OBJECT(obj)); if (prototype) { if (! EnumeratePropertyNamesWithPrefix(OBJECT_TO_JSVAL(prototype), prefix, out)) return false; } return true; }
char* enc_string(JSContext* cx, jsval arg, size_t* buflen) { JSString* str = NULL; const jschar* src = NULL; char* bytes = NULL; size_t srclen = 0; size_t byteslen = 0; str = JS_ValueToString(cx, arg); if(!str) goto error; #ifdef HAVE_JS_GET_STRING_CHARS_AND_LENGTH src = JS_GetStringCharsAndLength(cx, str, &srclen); #else src = JS_GetStringChars(str); srclen = JS_GetStringLength(str); #endif if(!enc_charbuf(src, srclen, NULL, &byteslen)) goto error; bytes = JS_malloc(cx, (byteslen) + 1); bytes[byteslen] = 0; if(!enc_charbuf(src, srclen, bytes, &byteslen)) goto error; if(buflen) *buflen = byteslen; goto success; error: if(bytes != NULL) JS_free(cx, bytes); bytes = NULL; success: return bytes; }
bool Load(JSContext* aCx, uintN aURLCount, jsval* aURLs) { WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx); NS_ASSERTION(worker, "This should never be null!"); if (!aURLCount) { return true; } if (aURLCount > MAX_CONCURRENT_SCRIPTS) { JS_ReportError(aCx, "Cannot load more than %d scripts at one time!", MAX_CONCURRENT_SCRIPTS); return false; } nsTArray<ScriptLoadInfo> loadInfos; loadInfos.SetLength(PRUint32(aURLCount)); for (uintN index = 0; index < aURLCount; index++) { JSString* str = JS_ValueToString(aCx, aURLs[index]); if (!str) { return false; } size_t length; const jschar* buffer = JS_GetStringCharsAndLength(aCx, str, &length); if (!buffer) { return false; } loadInfos[index].mURL.Assign(buffer, length); } return LoadAllScripts(aCx, worker, loadInfos, false); }
/* fromString() function implementation */ static JSBool from_string_func(JSContext *context, unsigned argc, jsval *vp) { JS::CallArgs argv = JS::CallArgsFromVp (argc, vp); ByteArrayInstance *priv; char *encoding; gboolean encoding_is_utf8; JSObject *obj; JSBool retval = JS_FALSE; obj = byte_array_new(context); if (obj == NULL) return JS_FALSE; JS_AddObjectRoot(context, &obj); priv = priv_from_js(context, obj); g_assert (priv != NULL); g_assert(argc > 0); /* because we specified min args 1 */ priv->array = gjs_g_byte_array_new(0); if (!JSVAL_IS_STRING(argv[0])) { gjs_throw(context, "byteArray.fromString() called with non-string as first arg"); goto out; } if (argc > 1 && JSVAL_IS_STRING(argv[1])) { if (!gjs_string_to_utf8(context, argv[1], &encoding)) goto out; /* maybe we should be smarter about utf8 synonyms here. * doesn't matter much though. encoding_is_utf8 is * just an optimization anyway. */ if (strcmp(encoding, "UTF-8") == 0) { encoding_is_utf8 = TRUE; g_free(encoding); encoding = NULL; } else { encoding_is_utf8 = FALSE; } } else { encoding_is_utf8 = TRUE; } if (encoding_is_utf8) { /* optimization? avoids iconv overhead and runs * libmozjs hardwired utf16-to-utf8. */ char *utf8 = NULL; if (!gjs_string_to_utf8(context, argv[0], &utf8)) goto out; g_byte_array_set_size(priv->array, 0); g_byte_array_append(priv->array, (guint8*) utf8, strlen(utf8)); g_free(utf8); } else { char *encoded; gsize bytes_written; GError *error; const jschar *u16_chars; gsize u16_len; u16_chars = JS_GetStringCharsAndLength(context, JSVAL_TO_STRING(argv[0]), &u16_len); if (u16_chars == NULL) goto out; error = NULL; encoded = g_convert((char*) u16_chars, u16_len * 2, encoding, /* to_encoding */ "UTF-16", /* from_encoding */ NULL, /* bytes read */ &bytes_written, &error); g_free(encoding); if (encoded == NULL) { /* frees the GError */ gjs_throw_g_error(context, error); goto out; } g_byte_array_set_size(priv->array, 0); g_byte_array_append(priv->array, (guint8*) encoded, bytes_written); g_free(encoded); } argv.rval().set(OBJECT_TO_JSVAL(obj)); retval = JS_TRUE; out: JS_RemoveObjectRoot(context, &obj); return retval; }
// Convert from a jsval to an AtNode static AtSmartPtr<AtNode> ConvertNode(JSContext* cx, jsval node) { AtSmartPtr<AtNode> obj (new AtNode()); // Non-objects get converted into strings if (!JSVAL_IS_OBJECT(node)) { JSString* str = JS_ValueToString(cx, node); if (!str) return obj; // error size_t valueLen; const jschar* valueChars = JS_GetStringCharsAndLength(cx, str, &valueLen); if (!valueChars) return obj; // error wxString valueWx(reinterpret_cast<const char*>(valueChars), wxMBConvUTF16(), valueLen*2); obj->value = valueWx.c_str(); // Annotate numbers/booleans specially, to allow round-tripping if (JSVAL_IS_NUMBER(node)) { obj->children.insert(AtNode::child_pairtype( "@number", AtSmartPtr<AtNode>(new AtNode()) )); } else if (JSVAL_IS_BOOLEAN(node)) { obj->children.insert(AtNode::child_pairtype( "@boolean", AtSmartPtr<AtNode>(new AtNode()) )); } return obj; } JSObject* it = JS_NewPropertyIterator(cx, JSVAL_TO_OBJECT(node)); if (!it) return obj; // error while (true) { jsid idp; jsval val; if (! JS_NextProperty(cx, it, &idp) || ! JS_IdToValue(cx, idp, &val)) return obj; // error if (val == JSVAL_VOID) break; // end of iteration if (! JSVAL_IS_STRING(val)) continue; // ignore integer properties JSString* name = JSVAL_TO_STRING(val); size_t len; const jschar* chars = JS_GetStringCharsAndLength(cx, name, &len); wxString nameWx(reinterpret_cast<const char*>(chars), wxMBConvUTF16(), len*2); std::string nameStr(nameWx.ToUTF8().data()); jsval vp; if (!JS_GetPropertyById(cx, JSVAL_TO_OBJECT(node), idp, &vp)) return obj; // error // Unwrap arrays into a special format like <$name><item>$i0</item><item>... // (This assumes arrays aren't nested) if (JSVAL_IS_OBJECT(vp) && JS_IsArrayObject(cx, JSVAL_TO_OBJECT(vp))) { AtSmartPtr<AtNode> child(new AtNode()); child->children.insert(AtNode::child_pairtype( "@array", AtSmartPtr<AtNode>(new AtNode()) )); jsuint arrayLength; if (!JS_GetArrayLength(cx, JSVAL_TO_OBJECT(vp), &arrayLength)) return obj; // error for (jsuint i = 0; i < arrayLength; ++i) { jsval val; if (!JS_GetElement(cx, JSVAL_TO_OBJECT(vp), i, &val)) return obj; // error child->children.insert(AtNode::child_pairtype( "item", ConvertNode(cx, val) )); } obj->children.insert(AtNode::child_pairtype( nameStr, child )); } else { obj->children.insert(AtNode::child_pairtype( nameStr, ConvertNode(cx, vp) )); } } return obj; }
// Clone a new value (and root it and add it to the mapping) jsval Clone(jsval val) { if (JSVAL_IS_DOUBLE(val)) { jsval rval; CLONE_REQUIRE(JS_NewNumberValue(cxTo, JSVAL_TO_DOUBLE(val), &rval), L"JS_NewNumberValue"); m_RooterTo.Push(rval); return rval; } if (JSVAL_IS_STRING(val)) { size_t len; const jschar* chars = JS_GetStringCharsAndLength(cxFrom, JSVAL_TO_STRING(val), &len); CLONE_REQUIRE(chars, L"JS_GetStringCharsAndLength"); JSString* str = JS_NewUCStringCopyN(cxTo, chars, len); CLONE_REQUIRE(str, L"JS_NewUCStringCopyN"); jsval rval = STRING_TO_JSVAL(str); m_Mapping[JSVAL_TO_GCTHING(val)] = rval; m_RooterTo.Push(rval); return rval; } ENSURE(JSVAL_IS_OBJECT(val)); JSObject* newObj; if (JS_IsArrayObject(cxFrom, JSVAL_TO_OBJECT(val))) { jsuint length; CLONE_REQUIRE(JS_GetArrayLength(cxFrom, JSVAL_TO_OBJECT(val), &length), L"JS_GetArrayLength"); newObj = JS_NewArrayObject(cxTo, length, NULL); CLONE_REQUIRE(newObj, L"JS_NewArrayObject"); } else { newObj = JS_NewObject(cxTo, NULL, NULL, NULL); CLONE_REQUIRE(newObj, L"JS_NewObject"); } m_Mapping[JSVAL_TO_GCTHING(val)] = OBJECT_TO_JSVAL(newObj); m_RooterTo.Push(newObj); AutoJSIdArray ida (cxFrom, JS_Enumerate(cxFrom, JSVAL_TO_OBJECT(val))); CLONE_REQUIRE(ida.get(), L"JS_Enumerate"); AutoGCRooter idaRooter(scriptInterfaceFrom); idaRooter.Push(ida.get()); for (size_t i = 0; i < ida.length(); ++i) { jsid id = ida[i]; jsval idval, propval; CLONE_REQUIRE(JS_IdToValue(cxFrom, id, &idval), L"JS_IdToValue"); CLONE_REQUIRE(JS_GetPropertyById(cxFrom, JSVAL_TO_OBJECT(val), id, &propval), L"JS_GetPropertyById"); jsval newPropval = GetOrClone(propval); if (JSVAL_IS_INT(idval)) { // int jsids are portable across runtimes CLONE_REQUIRE(JS_SetPropertyById(cxTo, newObj, id, &newPropval), L"JS_SetPropertyById"); } else if (JSVAL_IS_STRING(idval)) { // string jsids are runtime-specific, so we need to copy the string content JSString* idstr = JS_ValueToString(cxFrom, idval); CLONE_REQUIRE(idstr, L"JS_ValueToString (id)"); size_t len; const jschar* chars = JS_GetStringCharsAndLength(cxFrom, idstr, &len); CLONE_REQUIRE(idstr, L"JS_GetStringCharsAndLength (id)"); CLONE_REQUIRE(JS_SetUCProperty(cxTo, newObj, chars, len, &newPropval), L"JS_SetUCProperty"); } else { // this apparently could be an XML object; ignore it } } return OBJECT_TO_JSVAL(newObj); }