NS_IMETHODIMP SmsManager::Send(const jsval& aNumber, const nsAString& aMessage, jsval* aReturn) { nsresult rv; nsIScriptContext* sc = GetContextForEventHandlers(&rv); NS_ENSURE_STATE(sc); JSContext* cx = sc->GetNativeContext(); NS_ASSERTION(cx, "Failed to get a context!"); if (!aNumber.isString() && !(aNumber.isObject() && JS_IsArrayObject(cx, &aNumber.toObject()))) { return NS_ERROR_INVALID_ARG; } JSObject* global = sc->GetNativeGlobal(); NS_ASSERTION(global, "Failed to get global object!"); JSAutoRequest ar(cx); JSAutoCompartment ac(cx, global); if (aNumber.isString()) { return Send(cx, global, aNumber.toString(), aMessage, aReturn); } // Must be an object then. if (!aNumber.isObject()) { return NS_ERROR_FAILURE; } JSObject& numbers = aNumber.toObject(); uint32_t size; if (!JS_GetArrayLength(cx, &numbers, &size)) { return NS_ERROR_FAILURE; } JS::AutoValueVector requests(cx); if (!requests.resize(size)) { return NS_ERROR_FAILURE; } JSString *str; for (uint32_t i = 0; i < size; ++i) { jsval number; if (!JS_GetElement(cx, &numbers, i, &number)) { return NS_ERROR_INVALID_ARG; } str = JS_ValueToString(cx, number); if (!str) { return NS_ERROR_FAILURE; } nsresult rv = Send(cx, global, str, aMessage, &requests[i]); NS_ENSURE_SUCCESS(rv, rv); } JSObject* obj = JS_NewArrayObject(cx, requests.length(), requests.begin()); if (!obj) { return NS_ERROR_FAILURE; } aReturn->setObject(*obj); return NS_OK; }
NS_IMETHODIMP nsSpeechTask::SendAudio(JS::Handle<JS::Value> aData, JS::Handle<JS::Value> aLandmarks, JSContext* aCx) { MOZ_ASSERT(XRE_IsParentProcess()); if(NS_WARN_IF(!(mStream))) { return NS_ERROR_NOT_AVAILABLE; } if(NS_WARN_IF(mStream->IsDestroyed())) { return NS_ERROR_NOT_AVAILABLE; } if(NS_WARN_IF(!(mChannels))) { return NS_ERROR_FAILURE; } if(NS_WARN_IF(!(aData.isObject()))) { return NS_ERROR_INVALID_ARG; } if (mIndirectAudio) { NS_WARNING("Can't call SendAudio from an indirect audio speech service."); return NS_ERROR_FAILURE; } JS::Rooted<JSObject*> darray(aCx, &aData.toObject()); JSAutoCompartment ac(aCx, darray); JS::Rooted<JSObject*> tsrc(aCx, nullptr); // Allow either Int16Array or plain JS Array if (JS_IsInt16Array(darray)) { tsrc = darray; } else { bool isArray; if (!JS_IsArrayObject(aCx, darray, &isArray)) { return NS_ERROR_UNEXPECTED; } if (isArray) { tsrc = JS_NewInt16ArrayFromArray(aCx, darray); } } if (!tsrc) { return NS_ERROR_DOM_TYPE_MISMATCH_ERR; } uint32_t dataLen = JS_GetTypedArrayLength(tsrc); RefPtr<mozilla::SharedBuffer> samples; { JS::AutoCheckCannotGC nogc; bool isShared; int16_t* data = JS_GetInt16ArrayData(tsrc, &isShared, nogc); if (isShared) { // Must opt in to using shared data. return NS_ERROR_DOM_TYPE_MISMATCH_ERR; } samples = makeSamples(data, dataLen); } SendAudioImpl(samples, dataLen); return NS_OK; }
static JSBool do_import(JSContext *context, JSObject *obj, Importer *priv, const char *name) { char *filename; char *full_path; char *dirname = NULL; jsval search_path_val; JSObject *search_path; JSObject *module_obj = NULL; guint32 search_path_len; guint32 i; JSBool result; GPtrArray *directories; jsid search_path_name; GFile *gfile; gboolean exists; search_path_name = gjs_context_get_const_string(context, GJS_STRING_SEARCH_PATH); if (!gjs_object_require_property(context, obj, "importer", search_path_name, &search_path_val)) { return JS_FALSE; } if (!JSVAL_IS_OBJECT(search_path_val)) { gjs_throw(context, "searchPath property on importer is not an object"); return JS_FALSE; } search_path = JSVAL_TO_OBJECT(search_path_val); if (!JS_IsArrayObject(context, search_path)) { gjs_throw(context, "searchPath property on importer is not an array"); return JS_FALSE; } if (!JS_GetArrayLength(context, search_path, &search_path_len)) { gjs_throw(context, "searchPath array has no length"); return JS_FALSE; } result = JS_FALSE; filename = g_strdup_printf("%s.js", name); full_path = NULL; directories = NULL; /* First try importing an internal module like byteArray */ if (priv->is_root && gjs_is_registered_native_module(context, obj, name) && import_native_file(context, obj, name)) { gjs_debug(GJS_DEBUG_IMPORTER, "successfully imported module '%s'", name); result = JS_TRUE; goto out; } for (i = 0; i < search_path_len; ++i) { jsval elem; elem = JSVAL_VOID; if (!JS_GetElement(context, search_path, i, &elem)) { /* this means there was an exception, while elem == JSVAL_VOID * means no element found */ goto out; } if (JSVAL_IS_VOID(elem)) continue; if (!JSVAL_IS_STRING(elem)) { gjs_throw(context, "importer searchPath contains non-string"); goto out; } g_free(dirname); dirname = NULL; if (!gjs_string_to_utf8(context, elem, &dirname)) goto out; /* Error message already set */ /* Ignore empty path elements */ if (dirname[0] == '\0') continue; /* Try importing __init__.js and loading the symbol from it */ if (full_path) g_free(full_path); full_path = g_build_filename(dirname, MODULE_INIT_FILENAME, NULL); module_obj = load_module_init(context, obj, full_path); if (module_obj != NULL) { jsval obj_val; if (JS_GetProperty(context, module_obj, name, &obj_val)) { if (!JSVAL_IS_VOID(obj_val) && JS_DefineProperty(context, obj, name, obj_val, NULL, NULL, GJS_MODULE_PROP_FLAGS & ~JSPROP_PERMANENT)) { result = JS_TRUE; goto out; } } } /* Second try importing a directory (a sub-importer) */ if (full_path) g_free(full_path); full_path = g_build_filename(dirname, name, NULL); gfile = g_file_new_for_commandline_arg(full_path); if (g_file_query_file_type(gfile, (GFileQueryInfoFlags) 0, NULL) == G_FILE_TYPE_DIRECTORY) { gjs_debug(GJS_DEBUG_IMPORTER, "Adding directory '%s' to child importer '%s'", full_path, name); if (directories == NULL) { directories = g_ptr_array_new(); } g_ptr_array_add(directories, full_path); /* don't free it twice - pass ownership to ptr array */ full_path = NULL; } g_object_unref(gfile); /* If we just added to directories, we know we don't need to * check for a file. If we added to directories on an earlier * iteration, we want to ignore any files later in the * path. So, always skip the rest of the loop block if we have * directories. */ if (directories != NULL) { continue; } /* Third, if it's not a directory, try importing a file */ g_free(full_path); full_path = g_build_filename(dirname, filename, NULL); gfile = g_file_new_for_commandline_arg(full_path); exists = g_file_query_exists(gfile, NULL); if (!exists) { gjs_debug(GJS_DEBUG_IMPORTER, "JS import '%s' not found in %s", name, dirname); g_object_unref(gfile); continue; } if (import_file_on_module (context, obj, name, gfile)) { gjs_debug(GJS_DEBUG_IMPORTER, "successfully imported module '%s'", name); result = JS_TRUE; } g_object_unref(gfile); /* Don't keep searching path if we fail to load the file for * reasons other than it doesn't exist... i.e. broken files * block searching for nonbroken ones */ goto out; } if (directories != NULL) { /* NULL-terminate the char** */ g_ptr_array_add(directories, NULL); if (import_directory(context, obj, name, (const char**) directories->pdata)) { gjs_debug(GJS_DEBUG_IMPORTER, "successfully imported directory '%s'", name); result = JS_TRUE; } } out: if (directories != NULL) { char **str_array; /* NULL-terminate the char** * (maybe for a second time, but doesn't matter) */ g_ptr_array_add(directories, NULL); str_array = (char**) directories->pdata; g_ptr_array_free(directories, FALSE); g_strfreev(str_array); } g_free(full_path); g_free(filename); g_free(dirname); if (!result && !JS_IsExceptionPending(context)) { /* If no exception occurred, the problem is just that we got to the * end of the path. Be sure an exception is set. */ gjs_throw(context, "No JS module '%s' found in search path", name); } return result; }
JSBool systemExecute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {// begin systemExecute // default return value *rval = INT_TO_JSVAL(-1); if(argc != 3) return JS_FALSE; if(JSVAL_IS_STRING(argv[0]) == false || JSVAL_IS_OBJECT(argv[1]) == false || JSVAL_IS_BOOLEAN(argv[2]) == false) return JS_FALSE; char *pExecutable = JS_GetStringBytes(JSVAL_TO_STRING(argv[0])); JSObject *pArgs = JSVAL_TO_OBJECT(argv[1]); bool bWait = JSVAL_TO_BOOLEAN(argv[2]); int status = 0; jsuint nArgsLength = 0; jsval jsValue; struct stat sbFileInfo; if(JS_IsArrayObject(cx, pArgs) == false) return JS_FALSE; JS_GetArrayLength(cx,pArgs,&nArgsLength); char **args = new char *[JSVAL_TO_INT(nArgsLength)+2]; args[0] = pExecutable; args[JSVAL_TO_INT(nArgsLength)+1] = NULL; for(jsuint i = 1;i <= nArgsLength;i++) { if(JS_GetElement(cx, pArgs, i, &jsValue) == JS_FALSE) {// begin failure to get item JS_ReportError(cx, "exec() JS_GetElement failed to get an array item."); return JS_FALSE; }// end failure to get item args[JSVAL_TO_INT(i)] = JS_GetStringBytes(JSVAL_TO_STRING(jsValue)); } if(getuid() == 0) {// begin running as root JS_ReportError(cx, "exec() disallowed while running as root."); return JS_FALSE; }// end running as root if(stat(pExecutable , &sbFileInfo) != 0) {// begin can't stat file JS_ReportError(cx, "exec() Can't stat \"%s\" errno(%i).", pExecutable, errno); return JS_FALSE; }// end can't stat file if((sbFileInfo.st_mode & S_ISUID) == S_ISUID || (sbFileInfo.st_mode & S_ISGID) == S_ISGID) {// begin setuid/setgid files disallowed JS_ReportError(cx, "exec() disallowed execution of \"%s\" since it is a setuid/setgid file.", pExecutable); return JS_FALSE; }// end setuid/setgid files disallowed enterLock(); // clear file descriptor table of forked process and fork #ifdef __linux__ pid_t pidRtn = fork(); #elif __FreeBSD__ pid_t pidRtn = rfork(RFPROC|RFCFDG); #endif if(pidRtn == 0) {// begin child process #ifdef __linux__ close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); #endif char **pEnv = environ; //char *pEnv[] = {NULL}; execve(pExecutable,args,pEnv); printf("Error: execve failure errno(%d)\n",errno); _exit(errno); }// end child process else if(bWait && pidRtn != -1) {// begin wait for execution to finish printf("Waiting on pid %d...",pidRtn); do {// begin wait for child waitpid(pidRtn,&status,WUNTRACED); }// end wait for child while(WIFEXITED(status) == false && WIFSIGNALED(status) == false); printf("Done...\n"); }// end wait for execution to finish else if(pidRtn == -1) {// begin rfork failure printf("Error: execve failure errno(%d)\n",errno); }// end rfork failure leaveLock(); // cleanup delete []args; if(pidRtn != -1) *rval = INT_TO_JSVAL(WEXITSTATUS(status)); // success return child's exit status else *rval = INT_TO_JSVAL(-1); // failure return JS_TRUE; }// end systemExecute
NS_IMETHODIMP IDBDatabase::CreateObjectStore(const nsAString& aName, const jsval& aOptions, JSContext* aCx, nsIIDBObjectStore** _retval) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction(); if (!transaction || transaction->Mode() != nsIIDBTransaction::VERSION_CHANGE) { return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; } DatabaseInfo* databaseInfo = transaction->DBInfo(); mozilla::dom::IDBObjectStoreParameters params; nsString keyPath; keyPath.SetIsVoid(true); nsTArray<nsString> keyPathArray; if (!JSVAL_IS_VOID(aOptions) && !JSVAL_IS_NULL(aOptions)) { nsresult rv = params.Init(aCx, &aOptions); NS_ENSURE_SUCCESS(rv, rv); // Get keyPath jsval val = params.keyPath; if (!JSVAL_IS_VOID(val) && !JSVAL_IS_NULL(val)) { if (!JSVAL_IS_PRIMITIVE(val) && JS_IsArrayObject(aCx, JSVAL_TO_OBJECT(val))) { JSObject* obj = JSVAL_TO_OBJECT(val); jsuint length; if (!JS_GetArrayLength(aCx, obj, &length)) { return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } if (!length) { return NS_ERROR_DOM_SYNTAX_ERR; } keyPathArray.SetCapacity(length); for (jsuint index = 0; index < length; index++) { jsval val; JSString* jsstr; nsDependentJSString str; if (!JS_GetElement(aCx, obj, index, &val) || !(jsstr = JS_ValueToString(aCx, val)) || !str.init(aCx, jsstr)) { return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } if (!IDBObjectStore::IsValidKeyPath(aCx, str)) { return NS_ERROR_DOM_SYNTAX_ERR; } keyPathArray.AppendElement(str); } NS_ASSERTION(!keyPathArray.IsEmpty(), "This shouldn't have happened!"); } else { JSString* jsstr; nsDependentJSString str; if (!(jsstr = JS_ValueToString(aCx, val)) || !str.init(aCx, jsstr)) { return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } if (!IDBObjectStore::IsValidKeyPath(aCx, str)) { return NS_ERROR_DOM_SYNTAX_ERR; } keyPath = str; } } } if (databaseInfo->ContainsStoreName(aName)) { return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR; } if (params.autoIncrement && ((!keyPath.IsVoid() && keyPath.IsEmpty()) || !keyPathArray.IsEmpty())) { return NS_ERROR_DOM_INVALID_ACCESS_ERR; } nsRefPtr<ObjectStoreInfo> newInfo(new ObjectStoreInfo()); newInfo->name = aName; newInfo->id = databaseInfo->nextObjectStoreId++; newInfo->keyPath = keyPath; newInfo->keyPathArray = keyPathArray; newInfo->nextAutoIncrementId = params.autoIncrement ? 1 : 0; newInfo->comittedAutoIncrementId = newInfo->nextAutoIncrementId; if (!databaseInfo->PutObjectStore(newInfo)) { NS_WARNING("Put failed!"); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } // Don't leave this in the hash if we fail below! AutoRemoveObjectStore autoRemove(databaseInfo, aName); nsRefPtr<IDBObjectStore> objectStore = transaction->GetOrCreateObjectStore(aName, newInfo); NS_ENSURE_TRUE(objectStore, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); nsRefPtr<CreateObjectStoreHelper> helper = new CreateObjectStoreHelper(transaction, objectStore); nsresult rv = helper->DispatchToTransactionPool(); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); autoRemove.forget(); objectStore.forget(_retval); return NS_OK; }
nsresult Key::EncodeJSValInternal(JSContext* aCx, const jsval aVal, uint8_t aTypeOffset, uint16_t aRecursionDepth) { NS_ENSURE_TRUE(aRecursionDepth < MaxRecursionDepth, NS_ERROR_DOM_INDEXEDDB_DATA_ERR); MOZ_STATIC_ASSERT(eMaxType * MaxArrayCollapse < 256, "Unable to encode jsvals."); if (JSVAL_IS_STRING(aVal)) { nsDependentJSString str; if (!str.init(aCx, aVal)) { return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } EncodeString(str, aTypeOffset); return NS_OK; } if (JSVAL_IS_INT(aVal)) { EncodeNumber((double)JSVAL_TO_INT(aVal), eFloat + aTypeOffset); return NS_OK; } if (JSVAL_IS_DOUBLE(aVal)) { double d = JSVAL_TO_DOUBLE(aVal); if (MOZ_DOUBLE_IS_NaN(d)) { return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; } EncodeNumber(d, eFloat + aTypeOffset); return NS_OK; } if (!JSVAL_IS_PRIMITIVE(aVal)) { JSObject* obj = JSVAL_TO_OBJECT(aVal); if (JS_IsArrayObject(aCx, obj)) { aTypeOffset += eMaxType; if (aTypeOffset == eMaxType * MaxArrayCollapse) { mBuffer.Append(aTypeOffset); aTypeOffset = 0; } NS_ASSERTION((aTypeOffset % eMaxType) == 0 && aTypeOffset < (eMaxType * MaxArrayCollapse), "Wrong typeoffset"); uint32_t length; if (!JS_GetArrayLength(aCx, obj, &length)) { return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } for (uint32_t index = 0; index < length; index++) { jsval val; if (!JS_GetElement(aCx, obj, index, &val)) { return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } nsresult rv = EncodeJSValInternal(aCx, val, aTypeOffset, aRecursionDepth + 1); if (NS_FAILED(rv)) { return rv; } aTypeOffset = 0; } mBuffer.Append(eTerminator + aTypeOffset); return NS_OK; } if (JS_ObjectIsDate(aCx, obj)) { if (!js_DateIsValid(obj)) { return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; } EncodeNumber(js_DateGetMsecSinceEpoch(obj), eDate + aTypeOffset); return NS_OK; } } return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; }
static JSBool setDash_func(JSContext *context, uintN argc, jsval *vp) { jsval *argv = JS_ARGV(context, vp); JSObject *obj = JS_THIS_OBJECT(context, vp); guint i; cairo_t *cr; JSObject *dashes; double offset; JSBool retval = JS_FALSE; guint len; GArray *dashes_c = NULL; if (!gjs_parse_args(context, "setDash", "of", argc, argv, "dashes", &dashes, "offset", &offset)) return JS_FALSE; JS_AddObjectRoot(context, &dashes); if (!JS_IsArrayObject(context, dashes)) { gjs_throw(context, "dashes must be an array"); goto out; } if (!JS_GetArrayLength(context, dashes, &len)) { gjs_throw(context, "Can't get length of dashes"); goto out; } dashes_c = g_array_sized_new (FALSE, FALSE, sizeof(double), len); for (i = 0; i < len; ++i) { jsval elem; double b; elem = JSVAL_VOID; if (!JS_GetElement(context, dashes, i, &elem)) { goto out; } if (JSVAL_IS_VOID(elem)) continue; if (!JS_ValueToNumber(context, elem, &b)) goto out; if (b <= 0) { gjs_throw(context, "Dash value must be positive"); goto out; } g_array_append_val(dashes_c, b); } cr = gjs_cairo_context_get_context(context, obj); cairo_set_dash(cr, (double*)dashes_c->data, dashes_c->len, offset); JS_SET_RVAL(context, vp, JSVAL_VOID); retval = JS_TRUE; out: if (dashes_c != NULL) g_array_free (dashes_c, TRUE); JS_RemoveObjectRoot(context, &dashes); return retval; }
JSBool js_cocos2dx_extension_WebSocket_constructor(JSContext *cx, uint32_t argc, jsval *vp) { jsval *argv = JS_ARGV(cx, vp); if (argc == 1 || argc == 2) { std::string url; do { JSBool ok = jsval_to_std_string(cx, argv[0], &url); JSB_PRECONDITION2( ok, cx, JS_FALSE, "Error processing arguments"); } while (0); JSObject *obj = JS_NewObject(cx, js_cocos2dx_websocket_class, js_cocos2dx_websocket_prototype, NULL); cocos2d::extension::WebSocket* cobj = new cocos2d::extension::WebSocket(); JSB_WebSocketDelegate* delegate = new JSB_WebSocketDelegate(); delegate->setJSDelegate(obj); if (argc == 2) { std::vector<std::string> protocols; if (JSVAL_IS_STRING(argv[1])) { std::string protocol; do { JSBool ok = jsval_to_std_string(cx, argv[1], &protocol); JSB_PRECONDITION2( ok, cx, JS_FALSE, "Error processing arguments"); } while (0); protocols.push_back(protocol); } else if (argv[1].isObject()) { JSBool ok = JS_TRUE; JSObject* arg2 = JSVAL_TO_OBJECT(argv[1]); JSB_PRECONDITION(JS_IsArrayObject( cx, arg2 ), "Object must be an array"); uint32_t len = 0; JS_GetArrayLength(cx, arg2, &len); for( uint32_t i=0; i< len;i++ ) { jsval valarg; JS_GetElement(cx, arg2, i, &valarg); std::string protocol; do { ok = jsval_to_std_string(cx, valarg, &protocol); JSB_PRECONDITION2( ok, cx, JS_FALSE, "Error processing arguments"); } while (0); protocols.push_back(protocol); } } cobj->init(*delegate, url, &protocols); } else { cobj->init(*delegate, url); } JS_DefineProperty(cx, obj, "URL", argv[0] , NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); //protocol not support yet (always return "") JS_DefineProperty(cx, obj, "protocol", c_string_to_jsval(cx, "") , NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); // link the native object with the javascript object js_proxy_t *p = jsb_new_proxy(cobj, obj); JS_AddNamedObjectRoot(cx, &p->obj, "WebSocket"); JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj)); return JS_TRUE; } JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 0); return JS_FALSE; }
nsresult Key::EncodeJSVal(JSContext* aCx, const jsval aVal, PRUint8 aTypeOffset) { PR_STATIC_ASSERT(eMaxType * MaxArrayCollapse < 256); if (JSVAL_IS_STRING(aVal)) { nsDependentJSString str; if (!str.init(aCx, aVal)) { return NS_ERROR_OUT_OF_MEMORY; } EncodeString(str, aTypeOffset); return NS_OK; } if (JSVAL_IS_INT(aVal)) { EncodeNumber((double)JSVAL_TO_INT(aVal), eFloat + aTypeOffset); return NS_OK; } if (JSVAL_IS_DOUBLE(aVal)) { double d = JSVAL_TO_DOUBLE(aVal); if (DOUBLE_IS_NaN(d)) { return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; } EncodeNumber(d, eFloat + aTypeOffset); return NS_OK; } if (!JSVAL_IS_PRIMITIVE(aVal)) { JSObject* obj = JSVAL_TO_OBJECT(aVal); if (JS_IsArrayObject(aCx, obj)) { aTypeOffset += eMaxType; if (aTypeOffset == eMaxType * MaxArrayCollapse) { mBuffer.Append(aTypeOffset); aTypeOffset = 0; } NS_ASSERTION((aTypeOffset % eMaxType) == 0 && aTypeOffset < (eMaxType * MaxArrayCollapse), "Wrong typeoffset"); jsuint length; if (!JS_GetArrayLength(aCx, obj, &length)) { return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } for (jsuint index = 0; index < length; index++) { jsval val; if (!JS_GetElement(aCx, obj, index, &val)) { return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } nsresult rv = EncodeJSVal(aCx, val, aTypeOffset); NS_ENSURE_SUCCESS(rv, rv); aTypeOffset = 0; } mBuffer.Append(eTerminator + aTypeOffset); return NS_OK; } if (JS_ObjectIsDate(aCx, obj)) { EncodeNumber(js_DateGetMsecSinceEpoch(aCx, obj), eDate + aTypeOffset); return NS_OK; } } return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; }
// 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(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 = JS_GetStringLength(name); jschar* chars = JS_GetStringChars(name); wxString nameWx(reinterpret_cast<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; }
/* * call-seq: * each {| element | block } * each {| name, value | block } * * Calls <em>block</em> with each item in this JavaScript array, or with * each +name+/+value+ pair (like a Hash) for any other JavaScript * object. */ static VALUE each(VALUE self) { RubyLandProxy* proxy; Data_Get_Struct(self, RubyLandProxy, proxy); JSContext * context = johnson_get_current_context(proxy->runtime); PREPARE_RUBY_JROOTS(context, 5); jsval proxy_value; JCHECK(get_jsval_for_proxy(proxy, &proxy_value)); JROOT(proxy_value); JSObject* value = JSVAL_TO_OBJECT(proxy_value); JROOT(value); // arrays behave like you'd expect, indexes in order if (JS_IsArrayObject(context, value)) { jsuint length; JCHECK(JS_GetArrayLength(context, value, &length)); jsuint i = 0; for (i = 0; i < length; ++i) { jsval element; JCHECK(JS_GetElement(context, value, (signed) i, &element)); CALL_RUBY_WRAPPER(rb_yield, CONVERT_TO_RUBY(proxy->runtime, element)); } } else { // not an array? behave like each on Hash; yield [key, value] JSIdArray* ids = JS_Enumerate(context, value); JCHECK(ids); JCLEANUP(destroy_id_array, ids); int i; for (i = 0; i < ids->length; ++i) { jsval js_key, js_value; JCHECK(JS_IdToValue(context, ids->vector[i], &js_key)); JROOT(js_key); if (JSVAL_IS_STRING(js_key)) { // regular properties have string keys JCHECK(JS_GetProperty(context, value, JS_GetStringBytes(JSVAL_TO_STRING(js_key)), &js_value)); } else { // it's a numeric property, use array access JCHECK(JS_GetElement(context, value, JSVAL_TO_INT(js_key), &js_value)); } JROOT(js_value); VALUE key = CONVERT_TO_RUBY(proxy->runtime, js_key); VALUE value = CONVERT_TO_RUBY(proxy->runtime, js_value); CALL_RUBY_WRAPPER(rb_yield, rb_ary_new3(2L, key, value)); JUNROOT(js_value); JUNROOT(js_key); } } JRETURN_RUBY(self); }
JSBool netlocalgroupaddmembers(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval) { JS_BeginRequest(cx); if(argc < 2) { JS_ReportError(cx, "Must pass members to be added."); JS_EndRequest(cx); return JS_FALSE; } LOCALGROUP_MEMBERS_INFO_0 * members; DWORD * lookupResult; DWORD memberCount = 0; JSString * groupName = JS_ValueToString(cx, argv[0]); argv[0] = STRING_TO_JSVAL(groupName); if(JSVAL_IS_OBJECT(argv[1]) && JS_IsArrayObject(cx, JSVAL_TO_OBJECT(argv[1]))) { JSObject * memberArray; JS_ValueToObject(cx, argv[1], &memberArray); argv[1] = OBJECT_TO_JSVAL(memberArray); JS_GetArrayLength(cx, memberArray, (jsuint*)&memberCount); members = (LOCALGROUP_MEMBERS_INFO_0*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LOCALGROUP_MEMBERS_INFO_0) * memberCount); lookupResult = (DWORD*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DWORD) * memberCount); JS_EnterLocalRootScope(cx); for(DWORD i = 0; i < memberCount; i++) { jsval curMemberVal; JSString * curMemberString; JS_GetElement(cx, memberArray, (jsint)i, &curMemberVal); curMemberString = JS_ValueToString(cx, curMemberVal); members[i].lgrmi0_sid = convert_jsstring_to_sid(cx, curMemberString, &lookupResult[i]); } JS_LeaveLocalRootScope(cx); } else { JSString * memberString = JS_ValueToString(cx, argv[1]); argv[1] = STRING_TO_JSVAL(memberString); members = (LOCALGROUP_MEMBERS_INFO_0*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LOCALGROUP_MEMBERS_INFO_0)); lookupResult = (DWORD*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DWORD)); members->lgrmi0_sid = convert_jsstring_to_sid(cx, memberString, lookupResult); memberCount = 1; } for(DWORD i = 0; i < memberCount; i++) { if(lookupResult[i] == 0) { JS_YieldRequest(cx); lookupResult[i] = NetLocalGroupAddMembers(NULL, (LPWSTR)JS_GetStringChars(groupName), 0, (LPBYTE)&members[i], 1); } } JSObject * retArray = JS_NewArrayObject(cx, 0, NULL); *rval = OBJECT_TO_JSVAL(retArray); for(DWORD i = 0; i < memberCount; i++) { jsval curResultVal; JS_NewNumberValue(cx, lookupResult[i], &curResultVal); JS_DefineElement(cx, retArray, i, curResultVal, NULL, NULL, 0); HeapFree(GetProcessHeap(), 0, members[i].lgrmi0_sid); } HeapFree(GetProcessHeap(), 0, members); HeapFree(GetProcessHeap(), 0, lookupResult); JS_EndRequest(cx); return JS_TRUE; }
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_GetLengthProperty(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 = OBJ_GET_PROPERTY(cx, obj, INT_TO_JSID(i), &outputValue); i++; } 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; } if (!outputString) { ok = JS_FALSE; 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 ok &= js_CloseIterator(cx, *vp); // 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; }
/* Wrap a JS value to export into perl * Returns a new SV, REFCNT_dec is caller's responsability */ JSBool PJS_ReflectJS2Perl( pTHX_ JSContext *cx, jsval value, SV** sv, int full ) { if(JSVAL_IS_PRIMITIVE(value)) { *sv = PrimJSVALToSV(aTHX_ cx, value); if(*sv) return JS_TRUE; } else if(JSVAL_IS_OBJECT(value)) { PJS_Context *pcx = PJS_GET_CONTEXT(cx); JSObject *object = JSVAL_TO_OBJECT(value); JSClass *clasp = PJS_GET_CLASS(cx, object); const char *classname = clasp->name; JSObject *passport; SV *wrapper; SV *box; char hkey[32]; jsval temp = JSVAL_VOID; snprintf(hkey, 32, "%p", (void *)object); PJS_DEBUG2("Wrapping a %s(%s)\n", classname, hkey); if(PJS_getFlag(pcx, "ConvertRegExp") && strEQ(classname, "RegExp")) { jsval src; char *str; if(JS_CallFunctionName(cx, object, "toSource", 0, NULL, &src) && (str = JS_GetStringBytes(JS_ValueToString(cx, src))) ) { dSP; SV *tmp = newSVpvf("qr%s", str); eval_sv(tmp, G_SCALAR); sv_free(tmp); // Don't leak SPAGAIN; tmp = POPs; PUTBACK; if(!SvTRUE(ERRSV)) { *sv = SvREFCNT_inc_simple_NN(tmp); return JS_TRUE; } } return JS_FALSE; } if(IS_PERL_CLASS(clasp)) { /* IS_PERL_CLASS means actual perl object is there */ SV *priv = (SV *)JS_GetPrivate(cx, object); if(priv && SvOK(priv) && SvROK(priv)) { *sv = SvREFCNT_inc_simple_NN(priv); return JS_TRUE; } croak("A private %s?!\n", classname); return JS_FALSE; } /* Common JSObject case */ /* Check registered perl visitors */ JS_LookupProperty(cx, pcx->pvisitors, hkey, &temp); if(temp != JSVAL_VOID) { /* Already registered, so exits a reference in perl space * _must_ hold a PASSPORT */ assert(JSVAL_TO_OBJECT(temp) == object); box = PJS_GetPassport(aTHX_ cx, object); SvREFCNT_inc_void_NN(box); /* In perl should be one more */ PJS_DEBUG1("Cached!: %s\n", hkey); } else { /* Check if with a PASSPORT */ JS_LookupPropertyWithFlags(cx, object, PJS_PASSPORT_PROP, 0, &temp); if(JSVAL_IS_OBJECT(temp) && (passport = JSVAL_TO_OBJECT(temp)) && PJS_GET_CLASS(cx, passport) == &passport_class && JS_GetReservedSlot(cx, passport, 0, &temp) && object == (JSObject *)JSVAL_TO_PRIVATE(temp) ) { /* Yes, reentering perl */ box = (SV *)JS_GetPrivate(cx, passport); /* Here we don't increment refcount, the ownership in passport is * transferred to perl land. */ PJS_DEBUG1("Reenter: %s\n", hkey); } else { /* No, first time, must wrap the object */ SV *boxref; const char *package; SV *robj = newSV(0); SV *rjsv = newSV(0); if (JS_ObjectIsFunction(cx, object)) package = PJS_FUNCTION_PACKAGE; else if(JS_IsArrayObject(cx, object)) package = PJS_ARRAY_PACKAGE; else if(strEQ(classname, PJS_PACKAGE_CLASS_NAME)) package = PJS_STASH_PACKAGE; #if JS_HAS_XML_SUPPORT else if(strEQ(classname, "XML")) package = PJS_XMLOBJ_PACKAGE; #endif else if(strEQ(classname, "Error")) package = PJS_ERROR_PACKAGE; else { SV **sv = hv_fetch(get_hv(NAMESPACE"ClassMap", 1), classname, strlen(classname), 0); if(sv) package = SvPV_nolen(*sv); else package = PJS_OBJECT_PACKAGE; } sv_setref_pv(robj, PJS_RAW_OBJECT, (void*)object); sv_setref_iv(rjsv, PJS_RAW_JSVAL, (IV)value); boxref = PJS_CallPerlMethod(aTHX_ cx, "__new", sv_2mortal(newSVpv(package, 0)), // package sv_2mortal(robj), // content sv_2mortal(rjsv), // jsval NULL ); if(!boxref) return JS_FALSE; if(!SvOK(boxref) || !sv_derived_from(boxref, PJS_BOXED_PACKAGE)) croak("PJS_Assert: Contructor must return a "NAMESPACE"Boxed"); /* Create a new PASSPORT */ passport = JS_NewObject(cx, &passport_class, NULL, object); if(!passport || !JS_DefineProperty(cx, object, PJS_PASSPORT_PROP, OBJECT_TO_JSVAL(passport), NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT)) return JS_FALSE; box = SvRV(boxref); /* boxref is mortal, so we need to increment its rc, at end of * scope, PASSPORT owns created box */ JS_SetPrivate(cx, passport, (void *)SvREFCNT_inc_simple_NN(box)); JS_SetReservedSlot(cx, passport, 0, PRIVATE_TO_JSVAL(object)); PJS_DEBUG2("New boxed: %s brc: %d\n", hkey, SvREFCNT(box)); } /* Root object adding it to pvisitors list, will be unrooted by * jsc_free_root at Boxed DESTROY time */ JS_DefineProperty(cx, pcx->pvisitors, hkey, value, NULL, NULL, 0); } /* Here the RC of box in PASSPORT reflects wrapper's ownership */ if(full && PJS_getFlag(pcx, "AutoTie") && (strEQ(classname, "Object") || strEQ(classname, "Array")) ) { /* Return tied */ AV *avbox = (AV *)SvRV(box); SV **last; SV *tied; SV *tier; if(strEQ(classname, "Array")) { last = av_fetch(avbox, 6, 1); if(last && SvOK(*last) && SvROK(*last)) { // Cached *sv = newSVsv(*last); sv_free(box); /* Hard copy 'sv' owns the reference */ return JS_TRUE; } tied = (SV *)newAV(); } else { // Object last = av_fetch(avbox, 5, 1); if(last && SvOK(*last) && SvROK(*last)) { // Cached *sv = newSVsv(*last); sv_free(box); /* Hard copy 'sv' owns the reference */ return JS_TRUE; } tied = (SV *)newHV(); } /* hv_magic below own a reference to box, we use an explicit path, * to make clear that to perl land only one reference is given */ tier = newRV_inc(box); hv_magic((HV *)tied, (GV *)tier, PERL_MAGIC_tied); sv_free(tier); wrapper = newRV_noinc(tied); /* Don't leak the hidden tied variable */ /* Save in cache a weaken copy, the cache itself dosn't hold a reference */ sv_setsv(*last, wrapper); sv_rvweaken(*last); PJS_DEBUG1("Return tied for %s\n", SvPV_nolen(tier)); } else { wrapper = newRV_noinc(box); /* Transfer ownership to wrapper */ #if PERL_VERSION < 9 sv_bless(wrapper, SvSTASH(box)); #endif } *sv = wrapper; return JS_TRUE; } return JS_FALSE; }
/** Needs nargs to be at least 2 for GC roots. * * JS method returns true if values were read. */ static JSBool query_readQuery(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { extern cfgHnd cfg; query_private_t *hnd = JS_GetPrivate(cx, obj); node *n; JSString *str; int retval; jsrefcount depth; jsval val; if (hnd->query) return gpsee_throw(cx, OBJECT_ID ".readQuery.alreadyRead"); else hnd->query = JS_malloc(cx, sizeof(*hnd->query)); if (argc > 0) { str = JS_ValueToString(cx, argv[0]); hnd->uploadDir = JS_strdup(cx, JS_GetStringBytes(str)); } else hnd->uploadDir = cfg_value(cfg, OBJECT_ID ".default_upload_dir"); /* fix this later by making upload files == /dev/null in libcgihtml.so when upload dir is null */ if (!hnd->uploadDir) gpsee_log(cx, GLOG_NOTICE, "Unspecified upload dir is a security problem! Specify rc." OBJECT_ID ".default_upload_dir!"); depth = JS_SuspendRequest(cx); retval = read_cgi_input(cx, hnd->query, hnd->uploadDir); JS_ResumeRequest(cx, depth); *rval = retval ? JSVAL_TRUE : JSVAL_FALSE; for (n = hnd->query->head; n; n = n->next) { /* temporary fix? we don't want to overwrite our module readQuery() member */ if (!n->entry.name || !strcmp(n->entry.name,"readQuery")) continue; if (n->entry.value == NULL) n->entry.value = strdup(""); /* Match eekim's horrible semantics */ /* later optimization note: almost all of the cases where we'd need to * create arrays instead of strings are also cases where the CGI * variables of the same name are adjacent in the query */ if ((JS_GetProperty(cx, obj, n->entry.name, &val) == JS_TRUE) && (!JSVAL_IS_VOID(val))) { /* Already seen a CGI variable with this name */ if (JSVAL_IS_STRING(val)) /* Only seen one, create a new array */ { argv[0] = val; argv[1] = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, n->entry.value)); argv[0] = OBJECT_TO_JSVAL(JS_NewArrayObject(cx, 2, argv)); if (JS_SetProperty(cx, obj, n->entry.name, argv + 0) == JS_FALSE) return gpsee_throw(cx, OBJECT_ID ".readQuery.property.recreate.%s", n->entry.name); } else { jsuint length; /* seen many: append to the array */ if (JS_IsArrayObject(cx, JSVAL_TO_OBJECT(val)) != JS_TRUE) return gpsee_throw(cx, OBJECT_ID ".readQuery.property.type.%s", n->entry.name); if (JS_GetArrayLength(cx, JSVAL_TO_OBJECT(val), &length) != JS_TRUE) return gpsee_throw(cx, OBJECT_ID ".readQuery.property.%s.length.get", n->entry.name); if (JS_DefineElement(cx, JSVAL_TO_OBJECT(val), length, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, n->entry.value)), JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE) != JS_TRUE) return gpsee_throw(cx, OBJECT_ID ".readQuery.property.%s.element.%u", n->entry.name, length); if (JS_SetArrayLength(cx, JSVAL_TO_OBJECT(val), length + 1) != JS_TRUE) return gpsee_throw(cx, OBJECT_ID ".readQuery.property.%s.length.set", n->entry.name); } } else { /* First time for this property, insert it as a string */ argv[0] = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, n->entry.value)); if (JS_SetProperty(cx, obj, n->entry.name, argv + 0) == JS_FALSE) return gpsee_throw(cx, OBJECT_ID ".readQuery.property.create.%s", n->entry.name); } } return JS_TRUE; }
void js_debug_property(JSContext *cx, jsval vp) { func(" vp mem address %p", &vp); int tag = JSVAL_TAG(vp); func(" type tag is %i: %s",tag, (tag==0x0)?"object": (tag==0x1)?"integer": (tag==0x2)?"double": (tag==0x4)?"string": (tag==0x6)?"boolean": "unknown"); switch(tag) { case 0x0: { JSObject *obj = JSVAL_TO_OBJECT(vp); jsval val; if( JS_IsArrayObject(cx, obj) ) { jsuint len; JS_GetArrayLength(cx, obj, &len); func(" object is an array of %u elements", len); for(jsuint c = 0; c<len; c++) { func(" dumping element %u:",c); JS_GetElement(cx, obj, c, &val); if(val == JSVAL_VOID) func(" content is VOID"); else js_debug_property(cx, val); } } else { func(" object type is unknown to us (not an array?)"); } } break; case 0x1: { JS_PROP_INT(num, vp); func(" Sint[ %i ] Uint[ %u ]", num, num); } break; case 0x2: { JS_PROP_DOUBLE(num, vp); func(" double is %.4f",num); } break; case 0x4: { char *cap = NULL; JS_PROP_STRING(cap); func(" string is \"%s\"",cap); } break; case 0x6: { bool b = false; b = JSVAL_TO_BOOLEAN(vp); func(" boolean is %i",b); } break; default: func(" tag %u is unhandled, probably double"); JS_PROP_DOUBLE(num, vp); func(" Double [ %.4f ] - Sint[ %i ] - Uint[ %u ]", num, num, num); } }
/* * Convert a JS value to an instance of java.lang.Object or one of its subclasses, * performing any necessary type coercion. If non-trivial coercion is required, * the cost value is incremented. If the java_value pass-by-reference argument * is non-NULL, the resulting Java value is stored there. * * Returns JS_TRUE if the conversion is possible, JS_FALSE otherwise */ JSBool jsj_ConvertJSValueToJavaObject(JSContext *cx, JNIEnv *jEnv, jsval v, JavaSignature *signature, int *cost, jobject *java_value, JSBool *is_local_refp) { JSString *jsstr; jclass target_java_class; JS_ASSERT(IS_REFERENCE_TYPE(signature->type)); /* Initialize to default case, in which no new Java object is synthesized to perform the conversion and, therefore, no JNI local references are being held. */ *is_local_refp = JS_FALSE; /* Get the Java type of the target value */ target_java_class = signature->java_class; if (JSVAL_IS_OBJECT(v)) { JSObject *js_obj = JSVAL_TO_OBJECT(v); /* JS null is always assignable to a Java object */ if (!js_obj) { if (java_value) *java_value = NULL; return JS_TRUE; } if (JS_InstanceOf(cx, js_obj, &JavaObject_class, 0) || JS_InstanceOf(cx, js_obj, &JavaArray_class, 0)) { /* The source value is a Java object wrapped inside a JavaScript object. Unwrap the JS object and return the original Java object if it's class makes it assignment-compatible with the target class using Java's assignability rules. */ JavaObjectWrapper *java_wrapper = JS_GetPrivate(cx, js_obj); jobject java_obj = java_wrapper->java_obj; if ((*jEnv)->IsInstanceOf(jEnv, java_obj, target_java_class)) { if (java_value) *java_value = java_obj; return JS_TRUE; } /* Fall through, to attempt conversion to a Java string */ } else if (JS_InstanceOf(cx, js_obj, &JavaClass_class, 0)) { /* We're dealing with the reflection of a Java class */ JavaClassDescriptor *java_class_descriptor = JS_GetPrivate(cx, js_obj); /* Check if target type is java.lang.Class class */ if ((*jEnv)->IsAssignableFrom(jEnv, jlClass, target_java_class)) { if (java_value) *java_value = java_class_descriptor->java_class; return JS_TRUE; } /* Check if target type is netscape.javascript.JSObject wrapper class */ if (convert_js_obj_to_JSObject_wrapper(cx, jEnv, js_obj, signature, cost, java_value)) { if (java_value && *java_value) *is_local_refp = JS_TRUE; return JS_TRUE; } /* Fall through, to attempt conversion to a Java string */ } else if (JS_InstanceOf(cx, js_obj, &JavaMember_class, 0)) { if (!JS_ConvertValue(cx, v, JSTYPE_OBJECT, &v)) return JS_FALSE; return jsj_ConvertJSValueToJavaObject(cx, jEnv, v, signature, cost, java_value, is_local_refp); /* JS Arrays are converted, element by element, to Java arrays */ } else if (JS_IsArrayObject(cx, js_obj) && (signature->type == JAVA_SIGNATURE_ARRAY)) { if (convert_js_array_to_java_array(cx, jEnv, js_obj, signature, java_value)) { if (java_value && *java_value) *is_local_refp = JS_TRUE; return JS_TRUE; } return JS_FALSE; } else { /* Otherwise, see if the target type is the netscape.javascript.JSObject wrapper class or one of its subclasses, in which case a reference is passed to the original JS object by wrapping it inside an instance of netscape.javascript.JSObject */ if (convert_js_obj_to_JSObject_wrapper(cx, jEnv, js_obj, signature, cost, java_value)) { if (java_value && *java_value) *is_local_refp = JS_TRUE; return JS_TRUE; } /* Fall through, to attempt conversion to a Java string */ } } else if (JSVAL_IS_NUMBER(v)) { /* JS numbers, integral or not, can be converted to instances of java.lang.Double */ if ((*jEnv)->IsAssignableFrom(jEnv, jlDouble, target_java_class)) { if (java_value) { jsdouble d; if (!JS_ValueToNumber(cx, v, &d)) goto conversion_error; *java_value = (*jEnv)->NewObject(jEnv, jlDouble, jlDouble_Double, d); if (*java_value) { *is_local_refp = JS_TRUE; } else { jsj_UnexpectedJavaError(cx, jEnv, "Couldn't construct instance of java.lang.Double"); return JS_FALSE; } } return JS_TRUE; } /* Fall through, to attempt conversion to a java.lang.String ... */ } else if (JSVAL_IS_BOOLEAN(v)) { /* JS boolean values can be converted to instances of java.lang.Boolean */ if ((*jEnv)->IsAssignableFrom(jEnv, jlBoolean, target_java_class)) { if (java_value) { JSBool b; if (!JS_ValueToBoolean(cx, v, &b)) goto conversion_error; *java_value = (*jEnv)->NewObject(jEnv, jlBoolean, jlBoolean_Boolean, b); if (*java_value) { *is_local_refp = JS_TRUE; } else { jsj_UnexpectedJavaError(cx, jEnv, "Couldn't construct instance " "of java.lang.Boolean"); return JS_FALSE; } } return JS_TRUE; } /* Fall through, to attempt conversion to a java.lang.String ... */ } /* If the source JS type is either a string or undefined, or if no conversion is possible from a number, boolean or JS object, see if the target type is java.lang.String */ if ((*jEnv)->IsAssignableFrom(jEnv, jlString, target_java_class)) { /* Convert to JS string, if necessary, and then to a Java Unicode string */ jsstr = JS_ValueToString(cx, v); if (jsstr) { if (java_value) { *java_value = jsj_ConvertJSStringToJavaString(cx, jEnv, jsstr); if (*java_value) { *is_local_refp = JS_TRUE; } else { return JS_FALSE; } } return JS_TRUE; } } conversion_error: return JS_FALSE; }
void js_debug_argument(JSContext *cx, jsval vp) { func(" arg mem address %p", &vp); int tag = JSVAL_TAG(vp); func(" type tag is %i: %s",tag, (tag==0x0)?"object": (tag==0x1)?"integer": (tag==0x2)?"double": (tag==0x4)?"string": (tag==0x6)?"boolean": "unknown"); switch(tag) { case 0x0: { JSObject *obj = JSVAL_TO_OBJECT(vp); jsval val; if( JS_IsArrayObject(cx, obj) ) { jsuint len; JS_GetArrayLength(cx, obj, &len); func(" object is an array of %u elements", len); for(jsuint c = 0; c<len; c++) { func(" dumping element %u:",c); JS_GetElement(cx, obj, c, &val); if(val == JSVAL_VOID) func(" content is VOID"); else js_debug_argument(cx, val); } } else { func(" object type is unknown to us (not an array?)"); } } break; case 0x1: { jsint num = js_get_int(vp); func(" Sint[ %i ] Uint[ %u ] Double [ %.2f ]", num, num, num); } break; case 0x2: { jsdouble num = js_get_double(vp); func(" Double [ %.2f ]", num); } break; case 0x4: { char *cap; if(JSVAL_IS_STRING(vp)) { cap = JS_GetStringBytes( JS_ValueToString(cx, vp) ); func(" string is \"%s\"",cap); } else { JS_ReportError(cx,"%s: argument value is not a string",__FUNCTION__); ::error("%s: argument value is not a string",__FUNCTION__); } } break; case 0x6: { bool b = false; b = JSVAL_TO_BOOLEAN(vp); func(" boolean is %i",b); } break; default: func(" arg %u is unhandled, probably double"); jsint num = js_get_double(vp); func(" Double [ %.4f ] - Sint[ %i ] - Uint[ %u ]", num, num, num); } }
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('}'); }
void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val) { JSContext* cx = m_ScriptInterface.GetContext(); JSAutoRequest rq(cx); switch (JS_TypeOfValue(cx, val)) { case JSTYPE_VOID: { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_VOID); break; } case JSTYPE_NULL: // This type is never actually returned (it's a JS2 feature) { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_NULL); break; } case JSTYPE_OBJECT: { if (val.isNull()) { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_NULL); break; } JS::RootedObject obj(cx, &val.toObject()); // If we've already serialized this object, just output a reference to it u32 tag = GetScriptBackrefTag(obj); if (tag) { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_BACKREF); m_Serializer.NumberU32_Unbounded("tag", tag); break; } // Arrays are special cases of Object if (JS_IsArrayObject(cx, obj)) { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_ARRAY); // TODO: probably should have a more efficient storage format // Arrays like [1, 2, ] have an 'undefined' at the end which is part of the // length but seemingly isn't enumerated, so store the length explicitly uint length = 0; if (!JS_GetArrayLength(cx, obj, &length)) throw PSERROR_Serialize_ScriptError("JS_GetArrayLength failed"); m_Serializer.NumberU32_Unbounded("array length", length); } else if (JS_IsTypedArrayObject(obj)) { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_TYPED_ARRAY); m_Serializer.NumberU8_Unbounded("array type", GetArrayType(JS_GetArrayBufferViewType(obj))); m_Serializer.NumberU32_Unbounded("byte offset", JS_GetTypedArrayByteOffset(obj)); m_Serializer.NumberU32_Unbounded("length", JS_GetTypedArrayLength(obj)); // Now handle its array buffer // this may be a backref, since ArrayBuffers can be shared by multiple views JS::RootedValue bufferVal(cx, JS::ObjectValue(*JS_GetArrayBufferViewBuffer(cx, obj))); HandleScriptVal(bufferVal); break; } else if (JS_IsArrayBufferObject(obj)) { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_ARRAY_BUFFER); #if BYTE_ORDER != LITTLE_ENDIAN #error TODO: need to convert JS ArrayBuffer data to little-endian #endif u32 length = JS_GetArrayBufferByteLength(obj); m_Serializer.NumberU32_Unbounded("buffer length", length); JS::AutoCheckCannotGC nogc; m_Serializer.RawBytes("buffer data", (const u8*)JS_GetArrayBufferData(obj, nogc), length); break; } else { // Find type of object const JSClass* jsclass = JS_GetClass(obj); if (!jsclass) throw PSERROR_Serialize_ScriptError("JS_GetClass failed"); // TODO: Remove this workaround for upstream API breakage when updating SpiderMonkey // See https://bugzilla.mozilla.org/show_bug.cgi?id=1236373 #define JSCLASS_CACHED_PROTO_WIDTH js::JSCLASS_CACHED_PROTO_WIDTH JSProtoKey protokey = JSCLASS_CACHED_PROTO_KEY(jsclass); #undef JSCLASS_CACHED_PROTO_WIDTH if (protokey == JSProto_Object) { // Object class - check for user-defined prototype JS::RootedObject proto(cx); JS_GetPrototype(cx, obj, &proto); if (!proto) throw PSERROR_Serialize_ScriptError("JS_GetPrototype failed"); if (m_SerializablePrototypes->empty() || !IsSerializablePrototype(proto)) { // Standard Object prototype m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT); // TODO: maybe we should throw an error for unrecognized non-Object prototypes? // (requires fixing AI serialization first and excluding component scripts) } else { // User-defined custom prototype m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_PROTOTYPE); const std::wstring prototypeName = GetPrototypeName(proto); m_Serializer.String("proto name", prototypeName, 0, 256); // Does it have custom Serialize function? // if so, we serialize the data it returns, rather than the object's properties directly bool hasCustomSerialize; if (!JS_HasProperty(cx, obj, "Serialize", &hasCustomSerialize)) throw PSERROR_Serialize_ScriptError("JS_HasProperty failed"); if (hasCustomSerialize) { JS::RootedValue serialize(cx); if (!JS_GetProperty(cx, obj, "Serialize", &serialize)) throw PSERROR_Serialize_ScriptError("JS_GetProperty failed"); // If serialize is null, so don't serialize anything more if (!serialize.isNull()) { JS::RootedValue data(cx); if (!m_ScriptInterface.CallFunction(val, "Serialize", &data)) throw PSERROR_Serialize_ScriptError("Prototype Serialize function failed"); HandleScriptVal(data); } break; } } } else if (protokey == JSProto_Number) { // Standard Number object m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_NUMBER); // Get primitive value double d; if (!JS::ToNumber(cx, val, &d)) throw PSERROR_Serialize_ScriptError("JS::ToNumber failed"); m_Serializer.NumberDouble_Unbounded("value", d); break; } else if (protokey == JSProto_String) { // Standard String object m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_STRING); // Get primitive value JS::RootedString str(cx, JS::ToString(cx, val)); if (!str) throw PSERROR_Serialize_ScriptError("JS_ValueToString failed"); ScriptString("value", str); break; } else if (protokey == JSProto_Boolean) { // Standard Boolean object m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_BOOLEAN); // Get primitive value bool b = JS::ToBoolean(val); m_Serializer.Bool("value", b); break; } // TODO: Follow upstream progresses about a JS::IsMapObject // https://bugzilla.mozilla.org/show_bug.cgi?id=1285909 else if (protokey == JSProto_Map) { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_MAP); m_Serializer.NumberU32_Unbounded("map size", JS::MapSize(cx, obj)); JS::RootedValue keyValueIterator(cx); if (!JS::MapEntries(cx, obj, &keyValueIterator)) throw PSERROR_Serialize_ScriptError("JS::MapEntries failed"); JS::ForOfIterator it(cx); if (!it.init(keyValueIterator)) throw PSERROR_Serialize_ScriptError("JS::ForOfIterator::init failed"); JS::RootedValue keyValuePair(cx); bool done; while (true) { if (!it.next(&keyValuePair, &done)) throw PSERROR_Serialize_ScriptError("JS::ForOfIterator::next failed"); if (done) break; JS::RootedObject keyValuePairObj(cx, &keyValuePair.toObject()); JS::RootedValue key(cx); JS::RootedValue value(cx); ENSURE(JS_GetElement(cx, keyValuePairObj, 0, &key)); ENSURE(JS_GetElement(cx, keyValuePairObj, 1, &value)); HandleScriptVal(key); HandleScriptVal(value); } break; } // TODO: Follow upstream progresses about a JS::IsSetObject // https://bugzilla.mozilla.org/show_bug.cgi?id=1285909 else if (protokey == JSProto_Set) { // TODO: When updating SpiderMonkey to a release after 38 use the C++ API for Sets. // https://bugzilla.mozilla.org/show_bug.cgi?id=1159469 u32 setSize; m_ScriptInterface.GetProperty(val, "size", setSize); m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_SET); m_Serializer.NumberU32_Unbounded("set size", setSize); JS::RootedValue valueIterator(cx); m_ScriptInterface.CallFunction(val, "values", &valueIterator); for (u32 i=0; i<setSize; ++i) { JS::RootedValue currentIterator(cx); JS::RootedValue value(cx); ENSURE(m_ScriptInterface.CallFunction(valueIterator, "next", ¤tIterator)); m_ScriptInterface.GetProperty(currentIterator, "value", &value); HandleScriptVal(value); } break; } else { // Unrecognized class LOGERROR("Cannot serialise JS objects with unrecognized class '%s'", jsclass->name); throw PSERROR_Serialize_InvalidScriptValue(); } } // Find all properties (ordered by insertion time) JS::AutoIdArray ida (cx, JS_Enumerate(cx, obj)); if (!ida) throw PSERROR_Serialize_ScriptError("JS_Enumerate failed"); m_Serializer.NumberU32_Unbounded("num props", (u32)ida.length()); for (size_t i = 0; i < ida.length(); ++i) { JS::RootedId id(cx, ida[i]); JS::RootedValue idval(cx); JS::RootedValue propval(cx); // Forbid getters, which might delete values and mess things up. JS::Rooted<JSPropertyDescriptor> desc(cx); if (!JS_GetPropertyDescriptorById(cx, obj, id, &desc)) throw PSERROR_Serialize_ScriptError("JS_GetPropertyDescriptorById failed"); if (desc.hasGetterObject()) throw PSERROR_Serialize_ScriptError("Cannot serialize property getters"); // Get the property name as a string if (!JS_IdToValue(cx, id, &idval)) throw PSERROR_Serialize_ScriptError("JS_IdToValue failed"); JS::RootedString idstr(cx, JS::ToString(cx, idval)); if (!idstr) throw PSERROR_Serialize_ScriptError("JS_ValueToString failed"); ScriptString("prop name", idstr); if (!JS_GetPropertyById(cx, obj, id, &propval)) throw PSERROR_Serialize_ScriptError("JS_GetPropertyById failed"); HandleScriptVal(propval); } break; } case JSTYPE_FUNCTION: { // We can't serialise functions, but we can at least name the offender (hopefully) std::wstring funcname(L"(unnamed)"); JS::RootedFunction func(cx, JS_ValueToFunction(cx, val)); if (func) { JS::RootedString string(cx, JS_GetFunctionId(func)); if (string) { if (JS_StringHasLatin1Chars(string)) { size_t length; JS::AutoCheckCannotGC nogc; const JS::Latin1Char* ch = JS_GetLatin1StringCharsAndLength(cx, nogc, string, &length); if (ch && length > 0) funcname.assign(ch, ch + length); } else { size_t length; JS::AutoCheckCannotGC nogc; const char16_t* ch = JS_GetTwoByteStringCharsAndLength(cx, nogc, string, &length); if (ch && length > 0) funcname.assign(ch, ch + length); } } } LOGERROR("Cannot serialise JS objects of type 'function': %s", utf8_from_wstring(funcname)); throw PSERROR_Serialize_InvalidScriptValue(); } case JSTYPE_STRING: { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_STRING); JS::RootedString stringVal(cx, val.toString()); ScriptString("string", stringVal); break; } case JSTYPE_NUMBER: { // To reduce the size of the serialized data, we handle integers and doubles separately. // We can't check for val.isInt32 and val.isDouble directly, because integer numbers are not guaranteed // to be represented as integers. A number like 33 could be stored as integer on the computer of one player // and as double on the other player's computer. That would cause out of sync errors in multiplayer games because // their binary representation and thus the hash would be different. double d; d = val.toNumber(); i32 integer; if (JS_DoubleIsInt32(d, &integer)) { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_INT); m_Serializer.NumberI32_Unbounded("value", integer); } else { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_DOUBLE); m_Serializer.NumberDouble_Unbounded("value", d); } break; } case JSTYPE_BOOLEAN: { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_BOOLEAN); bool b = val.toBoolean(); m_Serializer.NumberU8_Unbounded("value", b ? 1 : 0); break; } default: { debug_warn(L"Invalid TypeOfValue"); throw PSERROR_Serialize_InvalidScriptValue(); } } }
void Server::invokeCallback( const JSCallback & theCallback, const request & theRequest, reply & theReply) { std::string myResponseString; try { jsval argv[4], rval; argv[0] = jslib::as_jsval(theCallback.context, theRequest.method); argv[1] = jslib::as_jsval(theCallback.context, theRequest.body); argv[2] = jslib::as_jsval(theCallback.context, theRequest.uri ); argv[3] = jslib::as_jsval(theCallback.context, theRequest.headers ); jslib::JSA_CallFunctionValue(theCallback.context, theCallback.object, theCallback.functionValue, 4, argv, &rval); if (JSVAL_IS_VOID(rval)) { theReply.status = reply::no_content; return; } // changed to adhere to industry standard: // the callback must return either: // body // [statuscode, body] // [statucode, headers, body] // // where body is a string, statuscode an integer and headers a hash. if (JSVAL_IS_OBJECT(rval)) { JSObject * myJsObject; jsuint arrayLength; if(JS_ValueToObject(theCallback.context, rval, &myJsObject)) { if (JS_IsArrayObject(theCallback.context, myJsObject) && JS_GetArrayLength(theCallback.context, myJsObject, &arrayLength)) { jsval curElement; // first element: status JS_GetElement(theCallback.context, myJsObject, 0, &curElement); if (!JSVAL_IS_VOID(curElement)) { int myStatusCode; jslib::convertFrom(theCallback.context, curElement, myStatusCode); theReply.status = static_cast<reply::status_type>(myStatusCode); } else { theReply.status = reply::ok; } // 2nd element (if array has three elements) headers if (arrayLength == 3) { JS_GetElement(theCallback.context, myJsObject, 1, &curElement); if (JSVAL_IS_OBJECT(curElement)) { JSObject *headers = JSVAL_TO_OBJECT(curElement); JSIdArray *props = JS_Enumerate(theCallback.context, headers); for (int i = 0; props && i < props->length; ++i) { jsid propid = props->vector[i]; jsval propname; if (!JS_IdToValue(theCallback.context, propid, &propname)) { AC_WARNING << "Weird case"; continue; } std::string header_name; if (!jslib::convertFrom(theCallback.context, propname, header_name)) { JS_ReportError(theCallback.context, "Server::handleRequest: header_name is not a string!"); } jsval propval; if (!JS_GetProperty(theCallback.context, headers, header_name.c_str(), &propval)) { AC_WARNING << "Weird case"; continue; } std::string header_value; if (!jslib::convertFrom(theCallback.context, propval, header_value)) { JS_ReportError(theCallback.context, "Server::handleRequest: header_value is not a a string!"); } theReply.headers.insert(make_pair(header_name, header_value)); } } } // last element: Body JS_GetElement(theCallback.context, myJsObject, arrayLength-1, &curElement); if (!JSVAL_IS_VOID(curElement)) { jslib::convertFrom(theCallback.context, curElement, theReply.content); } return; } } } // default (backwards-compatible): treat jsval as string... if (!jslib::convertFrom(theCallback.context, rval, myResponseString)) { JS_ReportError(theCallback.context, "Server::handleRequest: Callback does not return a string!"); } theReply.content = myResponseString; theReply.status = reply::ok; theReply.headers.insert(make_pair("Content-Type", theCallback.contentType)); return; } catch (Exception e) { theReply.status = reply::internal_server_error; theReply.content = std::string("An internal error occured: ") + asl::compose_message(e); AC_ERROR << e; return; }; }
/* Helper for weighted regions. */ static nsresult setHelper(nsCameraControl *aCameraContol, PRUint32 aKey, const JS::Value & aValue, JSContext *cx) { nsCameraControl::CameraRegion *parsedRegions; PRUint32 length = 0; if (aValue.isObject()) { JSObject *regions = JSVAL_TO_OBJECT(aValue); if (JS_IsArrayObject(cx, regions)) { if (JS_GetArrayLength(cx, regions, &length)) { DOM_CAMERA_LOGI("%s:%d : got %d regions\n", __func__, __LINE__, length); parsedRegions = new nsCameraControl::CameraRegion[length]; for (PRUint32 i = 0; i < length; ++i) { jsval v; if (JS_GetElement(cx, regions, i, &v)) { if (v.isObject()) { nsCameraControl::CameraRegion* parsed = &parsedRegions[i]; JSObject *r = JSVAL_TO_OBJECT(v); jsval p; /* TODO: move these Gonk-specific values somewhere else */ PRInt32 top = -1000; PRInt32 left = -1000; PRInt32 bottom = 1000; PRInt32 right = 1000; PRUint32 weight = 1; if (JS_GetProperty(cx, r, "top", &p)) { if (JSVAL_IS_INT(p)) { top = JSVAL_TO_INT(p); } } if (JS_GetProperty(cx, r, "left", &p)) { if (JSVAL_IS_INT(p)) { left = JSVAL_TO_INT(p); } } if (JS_GetProperty(cx, r, "bottom", &p)) { if (JSVAL_IS_INT(p)) { bottom = JSVAL_TO_INT(p); } } if (JS_GetProperty(cx, r, "right", &p)) { if (JSVAL_IS_INT(p)) { right = JSVAL_TO_INT(p); } } if (JS_GetProperty(cx, r, "weight", &p)) { if (JSVAL_IS_INT(p)) { weight = JSVAL_TO_INT(p); } } DOM_CAMERA_LOGI("region %d: top=%d, left=%d, bottom=%d, right=%d, weight=%d\n", i, top, left, bottom, right, weight ); parsed->mTop = top; parsed->mLeft = left; parsed->mBottom = bottom; parsed->mRight = right; parsed->mWeight = weight; } } } } } } aCameraContol->SetParameter(aKey, parsedRegions, length); delete[] parsedRegions; return NS_OK; }
static void StartElementHandler(void *userdata, const char *name, const char **atts) { XMLGraphCallback * cb = (XMLGraphCallback *)userdata; int i; JSObject *element, *attobj, *array; JSContext *cx = cb->cb.cx; jsval rval; if (!cb->current) { if (!JS_EvaluateScript(cx, JS_GetGlobalObject(cx), xmljs_newObj_str, xmljs_newObj_size, "XMLGraph internal", 0, &rval)) { JS_ReportError(cx, "failed to create new Object"); return; } element = JSVAL_TO_OBJECT(rval); cb->current = element; if (!JS_DefineProperty(cx, cb->cb.obj, "graph", rval, NULL, NULL, JSPROP_ENUMERATE)) { JS_ReportError(cx, "failed to define graph prop"); return; } } if (!JS_EvaluateScript(cx, JS_GetGlobalObject(cx), xmljs_newObj_str, xmljs_newObj_size, "XMLGraph internal", 0, &rval)) { JS_ReportError(cx, "failed to create new Object"); return; } element = JSVAL_TO_OBJECT(rval); /* populate and set __attributes__ */ if (atts[0]) { JSString *attstr; if (!JS_EvaluateScript(cx, JS_GetGlobalObject(cx), xmljs_newObj_str, xmljs_newObj_size, "XMLGraph internal", 0, &rval)) return; attobj = JSVAL_TO_OBJECT(rval); for (i = 0; atts[i]; i+=2) { /* * if we have an attribute that matches nameBy, use * the value of that attribute to name the node */ if (cb->nameBy && !strcmp(cb->nameBy, atts[i])) name = atts[i+1]; attstr = JS_NewStringCopyZ(cx, atts[i+1]); if (!attstr || !JS_DefineProperty(cx, attobj, atts[i], STRING_TO_JSVAL(attstr), NULL, NULL, JSPROP_ENUMERATE)) return; } if (!JS_DefineProperty(cx, element, "__attributes__", OBJECT_TO_JSVAL(attobj), NULL, NULL, 0)) return; } /* Check for existing property with this name */ if (!JS_GetProperty(cx, cb->current, name, &rval)) return; if (JSVAL_IS_OBJECT(rval)) { JSObject *existing = JSVAL_TO_OBJECT(rval); if (JS_IsArrayObject(cx, existing)) { /* already an array, so append */ jsuint length; if (!JS_GetArrayLength(cx, existing, &length) || !JS_DefineElement(cx, existing, (jsint)length, OBJECT_TO_JSVAL(element), NULL, NULL, JSPROP_ENUMERATE)) return; } else { /* replace with an array [current, new] */ jsval vector[2]; vector[0] = OBJECT_TO_JSVAL(existing); vector[1] = OBJECT_TO_JSVAL(element); array = JS_NewArrayObject(cx, 2, vector); if (!array || !JS_DefineProperty(cx, cb->current, name, OBJECT_TO_JSVAL(array), NULL, NULL, JSPROP_ENUMERATE)) return; } } else if (!JS_DefineProperty(cx, cb->current, name, OBJECT_TO_JSVAL(element), NULL, NULL, JSPROP_ENUMERATE)) return; /* define backpointer __up__ */ if (!JS_DefineProperty(cx, element, xmlg_up_str, OBJECT_TO_JSVAL(cb->current), NULL, NULL, 0)) return; /* * XXX DefineProperty(element, "__element__", elementstr) */ cb->current = element; }
bool ExposedPropertiesOnly::check(JSContext *cx, HandleObject wrapper, HandleId id, Wrapper::Action act) { RootedObject wrappedObject(cx, Wrapper::wrappedObject(wrapper)); if (act == Wrapper::CALL) return true; // For the case of getting a property descriptor, we allow if either GET or SET // is allowed, and rely on FilteringWrapper to filter out any disallowed accessors. if (act == Wrapper::GET_PROPERTY_DESCRIPTOR) { return check(cx, wrapper, id, Wrapper::GET) || check(cx, wrapper, id, Wrapper::SET); } RootedId exposedPropsId(cx, GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS)); // We need to enter the wrappee's compartment to look at __exposedProps__, // but we want to be in the wrapper's compartment if we call Deny(). // // Unfortunately, |cx| can be in either compartment when we call ::check. :-( JSAutoCompartment ac(cx, wrappedObject); bool found = false; if (!JS_HasPropertyById(cx, wrappedObject, exposedPropsId, &found)) return false; // Always permit access to "length" and indexed properties of arrays. if ((JS_IsArrayObject(cx, wrappedObject) || JS_IsTypedArrayObject(wrappedObject)) && ((JSID_IS_INT(id) && JSID_TO_INT(id) >= 0) || (JSID_IS_STRING(id) && JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), "length")))) { return true; // Allow } // If no __exposedProps__ existed, deny access. if (!found) { return false; } if (id == JSID_VOID) return true; RootedValue exposedProps(cx); if (!JS_LookupPropertyById(cx, wrappedObject, exposedPropsId, &exposedProps)) return false; if (exposedProps.isNullOrUndefined()) return false; if (!exposedProps.isObject()) { EnterAndThrow(cx, wrapper, "__exposedProps__ must be undefined, null, or an Object"); return false; } RootedObject hallpass(cx, &exposedProps.toObject()); if (!AccessCheck::subsumes(js::UncheckedUnwrap(hallpass), wrappedObject)) { EnterAndThrow(cx, wrapper, "Invalid __exposedProps__"); return false; } Access access = NO_ACCESS; Rooted<JSPropertyDescriptor> desc(cx); if (!JS_GetPropertyDescriptorById(cx, hallpass, id, &desc)) { return false; // Error } if (!desc.object() || !desc.isEnumerable()) return false; if (!desc.value().isString()) { EnterAndThrow(cx, wrapper, "property must be a string"); return false; } JSFlatString *flat = JS_FlattenString(cx, desc.value().toString()); if (!flat) return false; size_t length = JS_GetStringLength(JS_FORGET_STRING_FLATNESS(flat)); for (size_t i = 0; i < length; ++i) { char16_t ch = JS_GetFlatStringCharAt(flat, i); switch (ch) { case 'r': if (access & READ) { EnterAndThrow(cx, wrapper, "duplicate 'readable' property flag"); return false; } access = Access(access | READ); break; case 'w': if (access & WRITE) { EnterAndThrow(cx, wrapper, "duplicate 'writable' property flag"); return false; } access = Access(access | WRITE); break; default: EnterAndThrow(cx, wrapper, "properties can only be readable or read and writable"); return false; } } if (access == NO_ACCESS) { EnterAndThrow(cx, wrapper, "specified properties must have a permission bit set"); return false; } if ((act == Wrapper::SET && !(access & WRITE)) || (act != Wrapper::SET && !(access & READ))) { return false; } return true; }
NS_IMETHODIMP IDBDatabase::Transaction(const jsval& aStoreNames, PRUint16 aMode, JSContext* aCx, PRUint8 aOptionalArgCount, nsIIDBTransaction** _retval) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); if (IndexedDatabaseManager::IsShuttingDown()) { return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } if (mClosed) { return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; } if (mRunningVersionChange) { return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; } if (aOptionalArgCount) { if (aMode != nsIIDBTransaction::READ_WRITE && aMode != nsIIDBTransaction::READ_ONLY) { return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR; } } else { aMode = nsIIDBTransaction::READ_ONLY; } nsresult rv; nsTArray<nsString> storesToOpen; if (!JSVAL_IS_PRIMITIVE(aStoreNames)) { JSObject* obj = JSVAL_TO_OBJECT(aStoreNames); // See if this is a JS array. if (JS_IsArrayObject(aCx, obj)) { jsuint length; if (!JS_GetArrayLength(aCx, obj, &length)) { return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } if (!length) { return NS_ERROR_DOM_INVALID_ACCESS_ERR; } storesToOpen.SetCapacity(length); for (jsuint index = 0; index < length; index++) { jsval val; JSString* jsstr; nsDependentJSString str; if (!JS_GetElement(aCx, obj, index, &val) || !(jsstr = JS_ValueToString(aCx, val)) || !str.init(aCx, jsstr)) { return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } storesToOpen.AppendElement(str); } NS_ASSERTION(!storesToOpen.IsEmpty(), "Must have something here or else code below will " "misbehave!"); } else { // Perhaps some kind of wrapped object? nsIXPConnect* xpc = nsContentUtils::XPConnect(); NS_ASSERTION(xpc, "This should never be null!"); nsCOMPtr<nsIXPConnectWrappedNative> wrapper; rv = xpc->GetWrappedNativeOfJSObject(aCx, obj, getter_AddRefs(wrapper)); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); if (wrapper) { nsISupports* wrappedObject = wrapper->Native(); NS_ENSURE_TRUE(wrappedObject, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); // We only accept DOMStringList. nsCOMPtr<nsIDOMDOMStringList> list = do_QueryInterface(wrappedObject); if (list) { PRUint32 length; rv = list->GetLength(&length); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); if (!length) { return NS_ERROR_DOM_INVALID_ACCESS_ERR; } storesToOpen.SetCapacity(length); for (PRUint32 index = 0; index < length; index++) { nsString* item = storesToOpen.AppendElement(); NS_ASSERTION(item, "This should never fail!"); rv = list->Item(index, *item); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); } NS_ASSERTION(!storesToOpen.IsEmpty(), "Must have something here or else code below will " "misbehave!"); } } } } // If our list is empty here then the argument must have been an object that // we don't support or a primitive. Either way we convert to a string. if (storesToOpen.IsEmpty()) { JSString* jsstr; nsDependentJSString str; if (!(jsstr = JS_ValueToString(aCx, aStoreNames)) || !str.init(aCx, jsstr)) { return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } storesToOpen.AppendElement(str); } // Now check to make sure the object store names we collected actually exist. DatabaseInfo* info = Info(); for (PRUint32 index = 0; index < storesToOpen.Length(); index++) { if (!info->ContainsStoreName(storesToOpen[index])) { return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR; } } nsRefPtr<IDBTransaction> transaction = IDBTransaction::Create(this, storesToOpen, aMode, false); NS_ENSURE_TRUE(transaction, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); transaction.forget(_retval); return NS_OK; }
/* fromArray() function implementation */ static JSBool from_array_func(JSContext *context, unsigned argc, jsval *vp) { JS::CallArgs argv = JS::CallArgsFromVp (argc, vp); ByteArrayInstance *priv; guint32 len; guint32 i; JSObject *obj; JSBool ret = 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 (!JS_IsArrayObject(context, JSVAL_TO_OBJECT(argv[0]))) { gjs_throw(context, "byteArray.fromArray() called with non-array as first arg"); goto out; } if (!JS_GetArrayLength(context, JSVAL_TO_OBJECT(argv[0]), &len)) { gjs_throw(context, "byteArray.fromArray() can't get length of first array arg"); goto out; } g_byte_array_set_size(priv->array, len); for (i = 0; i < len; ++i) { jsval elem; guint8 b; elem = JSVAL_VOID; if (!JS_GetElement(context, JSVAL_TO_OBJECT(argv[0]), i, &elem)) { /* this means there was an exception, while elem == JSVAL_VOID * means no element found */ goto out; } if (JSVAL_IS_VOID(elem)) continue; if (!gjs_value_to_byte(context, elem, &b)) goto out; g_array_index(priv->array, guint8, i) = b; } ret = JS_TRUE; argv.rval().set(OBJECT_TO_JSVAL(obj)); out: JS_RemoveObjectRoot(context, &obj); return ret; }
bool ExposedPropertiesOnly::check(JSContext* cx, HandleObject wrapper, HandleId id, Wrapper::Action act) { RootedObject wrappedObject(cx, Wrapper::wrappedObject(wrapper)); if (act == Wrapper::CALL) return false; // For the case of getting a property descriptor, we allow if either GET or SET // is allowed, and rely on FilteringWrapper to filter out any disallowed accessors. if (act == Wrapper::GET_PROPERTY_DESCRIPTOR) { return check(cx, wrapper, id, Wrapper::GET) || check(cx, wrapper, id, Wrapper::SET); } RootedId exposedPropsId(cx, GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS)); // We need to enter the wrappee's compartment to look at __exposedProps__, // but we want to be in the wrapper's compartment if we call Deny(). // // Unfortunately, |cx| can be in either compartment when we call ::check. :-( JSAutoCompartment ac(cx, wrappedObject); bool found = false; if (!JS_HasPropertyById(cx, wrappedObject, exposedPropsId, &found)) return false; // If no __exposedProps__ existed, deny access. if (!found) { // Previously we automatically granted access to indexed properties and // .length for Array COWs. We're not doing that anymore, so make sure to // let people know what's going on. bool isArray; if (!JS_IsArrayObject(cx, wrappedObject, &isArray)) return false; if (!isArray) isArray = JS_IsTypedArrayObject(wrappedObject); bool isIndexedAccessOnArray = isArray && JSID_IS_INT(id) && JSID_TO_INT(id) >= 0; bool isLengthAccessOnArray = isArray && JSID_IS_STRING(id) && JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), "length"); if (isIndexedAccessOnArray || isLengthAccessOnArray) { JSAutoCompartment ac2(cx, wrapper); ReportWrapperDenial(cx, id, WrapperDenialForCOW, "Access to elements and length of privileged Array not permitted"); } return false; } if (id == JSID_VOID) return true; Rooted<JSPropertyDescriptor> desc(cx); if (!JS_GetPropertyDescriptorById(cx, wrappedObject, exposedPropsId, &desc)) return false; if (!desc.object()) return false; if (desc.hasGetterOrSetter()) { EnterAndThrow(cx, wrapper, "__exposedProps__ must be a value property"); return false; } RootedValue exposedProps(cx, desc.value()); if (exposedProps.isNullOrUndefined()) return false; if (!exposedProps.isObject()) { EnterAndThrow(cx, wrapper, "__exposedProps__ must be undefined, null, or an Object"); return false; } RootedObject hallpass(cx, &exposedProps.toObject()); if (!AccessCheck::subsumes(js::UncheckedUnwrap(hallpass), wrappedObject)) { EnterAndThrow(cx, wrapper, "Invalid __exposedProps__"); return false; } Access access = NO_ACCESS; if (!JS_GetPropertyDescriptorById(cx, hallpass, id, &desc)) { return false; // Error } if (!desc.object() || !desc.enumerable()) return false; if (!desc.value().isString()) { EnterAndThrow(cx, wrapper, "property must be a string"); return false; } JSFlatString* flat = JS_FlattenString(cx, desc.value().toString()); if (!flat) return false; size_t length = JS_GetStringLength(JS_FORGET_STRING_FLATNESS(flat)); for (size_t i = 0; i < length; ++i) { char16_t ch = JS_GetFlatStringCharAt(flat, i); switch (ch) { case 'r': if (access & READ) { EnterAndThrow(cx, wrapper, "duplicate 'readable' property flag"); return false; } access = Access(access | READ); break; case 'w': if (access & WRITE) { EnterAndThrow(cx, wrapper, "duplicate 'writable' property flag"); return false; } access = Access(access | WRITE); break; default: EnterAndThrow(cx, wrapper, "properties can only be readable or read and writable"); return false; } } if (access == NO_ACCESS) { EnterAndThrow(cx, wrapper, "specified properties must have a permission bit set"); return false; } if ((act == Wrapper::SET && !(access & WRITE)) || (act != Wrapper::SET && !(access & READ))) { return false; } // Inspect the property on the underlying object to check for red flags. bool skipCallableChecks = CompartmentPrivate::Get(wrappedObject)->skipCOWCallableChecks; if (!JS_GetPropertyDescriptorById(cx, wrappedObject, id, &desc)) return false; // Reject accessor properties. if (!skipCallableChecks && desc.hasGetterOrSetter()) { EnterAndThrow(cx, wrapper, "Exposing privileged accessor properties is prohibited"); return false; } // Reject privileged or cross-origin callables. if (!skipCallableChecks && desc.value().isObject()) { RootedObject maybeCallable(cx, js::UncheckedUnwrap(&desc.value().toObject())); if (JS::IsCallable(maybeCallable) && !AccessCheck::subsumes(wrapper, maybeCallable)) { EnterAndThrow(cx, wrapper, "Exposing privileged or cross-origin callable is prohibited"); return false; } } return true; }
std::vector<std::string> CTemplateLoader::FindPlaceableTemplates(const std::string& path, bool includeSubdirectories, ETemplatesType templatesType, ScriptInterface& scriptInterface) { JSContext* cx = scriptInterface.GetContext(); JSAutoRequest rq(cx); std::vector<std::string> templates; Status ok; VfsPath templatePath; if (templatesType == SIMULATION_TEMPLATES || templatesType == ALL_TEMPLATES) { JS::RootedValue placeablesFilter(cx); scriptInterface.ReadJSONFile("simulation/data/placeablesFilter.json", &placeablesFilter); JS::RootedObject folders(cx); if (scriptInterface.GetProperty(placeablesFilter, "templates", &folders)) { if (!(JS_IsArrayObject(cx, folders))) { LOGERROR("FindPlaceableTemplates: Argument must be an array!"); return templates; } u32 length; if (!JS_GetArrayLength(cx, folders, &length)) { LOGERROR("FindPlaceableTemplates: Failed to get array length!"); return templates; } templatePath = VfsPath(TEMPLATE_ROOT) / path; //I have every object inside, just run for each for (u32 i=0; i<length; ++i) { JS::RootedValue val(cx); if (!JS_GetElement(cx, folders, i, &val)) { LOGERROR("FindPlaceableTemplates: Failed to read array element!"); return templates; } std::string directoryPath; std::wstring fileFilter; scriptInterface.GetProperty(val, "directory", directoryPath); scriptInterface.GetProperty(val, "file", fileFilter); VfsPaths filenames; if (vfs::GetPathnames(g_VFS, templatePath / (directoryPath + "/"), fileFilter.c_str(), filenames) != INFO::OK) continue; for (const VfsPath& filename : filenames) { // Strip the .xml extension VfsPath pathstem = filename.ChangeExtension(L""); // Strip the root from the path std::wstring name = pathstem.string().substr(ARRAY_SIZE(TEMPLATE_ROOT) - 1); templates.emplace_back(name.begin(), name.end()); } } } } if (templatesType == ACTOR_TEMPLATES || templatesType == ALL_TEMPLATES) { templatePath = VfsPath(ACTOR_ROOT) / path; if (includeSubdirectories) ok = vfs::ForEachFile(g_VFS, templatePath, AddActorToTemplates, (uintptr_t)&templates, L"*.xml", vfs::DIR_RECURSIVE); else ok = vfs::ForEachFile(g_VFS, templatePath, AddActorToTemplates, (uintptr_t)&templates, L"*.xml"); WARN_IF_ERR(ok); } if (templatesType != SIMULATION_TEMPLATES && templatesType != ACTOR_TEMPLATES && templatesType != ALL_TEMPLATES) LOGERROR("Undefined template type (valid: all, simulation, actor)"); return templates; }
/* * Like JSEnumerateOp, but enum provides contextual information as follows: * * JSENUMERATE_INIT: allocate private enum struct in state_p, return number * of elements in *id_p * JSENUMERATE_NEXT: return next property id in *id_p, and if no new property * free state_p and set to JSVAL_NULL * JSENUMERATE_DESTROY : destroy state_p * * Note that in a for ... in loop, this will be called first on the object, * then on its prototype. * */ static JSBool importer_new_enumerate(JSContext *context, JSObject **object, JSIterateOp enum_op, jsval *state_p, jsid *id_p) { ImporterIterator *iter; switch (enum_op) { case JSENUMERATE_INIT_ALL: case JSENUMERATE_INIT: { Importer *priv; JSObject *search_path; jsval search_path_val; guint32 search_path_len; guint32 i; jsid search_path_name; if (state_p) *state_p = JSVAL_NULL; if (id_p) *id_p = INT_TO_JSID(0); priv = priv_from_js(context, *object); if (!priv) /* we are enumerating the prototype properties */ return JS_TRUE; search_path_name = gjs_context_get_const_string(context, GJS_STRING_SEARCH_PATH); if (!gjs_object_require_property(context, *object, "importer", search_path_name, &search_path_val)) return JS_FALSE; if (!JSVAL_IS_OBJECT(search_path_val)) { gjs_throw(context, "searchPath property on importer is not an object"); return JS_FALSE; } search_path = JSVAL_TO_OBJECT(search_path_val); if (!JS_IsArrayObject(context, search_path)) { gjs_throw(context, "searchPath property on importer is not an array"); return JS_FALSE; } if (!JS_GetArrayLength(context, search_path, &search_path_len)) { gjs_throw(context, "searchPath array has no length"); return JS_FALSE; } iter = importer_iterator_new(); for (i = 0; i < search_path_len; ++i) { char *dirname = NULL; char *init_path; const char *filename; jsval elem; GDir *dir = NULL; elem = JSVAL_VOID; if (!JS_GetElement(context, search_path, i, &elem)) { /* this means there was an exception, while elem == JSVAL_VOID * means no element found */ importer_iterator_free(iter); return JS_FALSE; } if (JSVAL_IS_VOID(elem)) continue; if (!JSVAL_IS_STRING(elem)) { gjs_throw(context, "importer searchPath contains non-string"); importer_iterator_free(iter); return JS_FALSE; } if (!gjs_string_to_utf8(context, elem, &dirname)) { importer_iterator_free(iter); return JS_FALSE; /* Error message already set */ } init_path = g_build_filename(dirname, MODULE_INIT_FILENAME, NULL); load_module_elements(context, *object, iter, init_path); g_free(init_path); dir = g_dir_open(dirname, 0, NULL); if (!dir) { g_free(dirname); continue; } while ((filename = g_dir_read_name(dir))) { char *full_path; /* skip hidden files and directories (.svn, .git, ...) */ if (filename[0] == '.') continue; /* skip module init file */ if (strcmp(filename, MODULE_INIT_FILENAME) == 0) continue; full_path = g_build_filename(dirname, filename, NULL); if (g_file_test(full_path, G_FILE_TEST_IS_DIR)) { g_ptr_array_add(iter->elements, g_strdup(filename)); } else { if (g_str_has_suffix(filename, "." G_MODULE_SUFFIX) || g_str_has_suffix(filename, ".js")) { g_ptr_array_add(iter->elements, g_strndup(filename, strlen(filename) - 3)); } } g_free(full_path); } g_dir_close(dir); g_free(dirname); } if (state_p) *state_p = PRIVATE_TO_JSVAL(iter); if (id_p) *id_p = INT_TO_JSID(iter->elements->len); break; } case JSENUMERATE_NEXT: { jsval element_val; if (!state_p) { gjs_throw(context, "Enumerate with no iterator set?"); return JS_FALSE; } if (JSVAL_IS_NULL(*state_p)) /* Iterating prototype */ return JS_TRUE; iter = (ImporterIterator*) JSVAL_TO_PRIVATE(*state_p); if (iter->index < iter->elements->len) { if (!gjs_string_from_utf8(context, (const char*) g_ptr_array_index(iter->elements, iter->index++), -1, &element_val)) return JS_FALSE; if (!JS_ValueToId(context, element_val, id_p)) return JS_FALSE; break; } /* else fall through to destroying the iterator */ } case JSENUMERATE_DESTROY: { if (state_p && !JSVAL_IS_NULL(*state_p)) { iter = (ImporterIterator*) JSVAL_TO_PRIVATE(*state_p); importer_iterator_free(iter); *state_p = JSVAL_NULL; } } } return JS_TRUE; }
nsresult WebCL_getVariantsFromJSArray (JSContext *cx, nsIVariant* aVariant, nsTArray<nsIVariant*> & aResultOut) { D_METHOD_START; nsresult rv; NS_ENSURE_ARG_POINTER (aVariant); PRUint16 variantType = 0; rv = aVariant->GetDataType (&variantType); switch (variantType) { // Accept VTYPE_ARRAY, VTYPE_EMPTY_ARRAY case nsIDataType::VTYPE_ARRAY: case nsIDataType::VTYPE_EMPTY_ARRAY: // Array detected break; case nsIDataType::VTYPE_INTERFACE: case nsIDataType::VTYPE_INTERFACE_IS: // Might be a proxy object holding the array break; default: D_LOG (LOG_LEVEL_ERROR, "Argument aVariant is not an array (type: %u).", variantType); return NS_ERROR_INVALID_ARG; } if (!cx) { nsCOMPtr<nsIThreadJSContextStack> stack = do_GetService ("@mozilla.org/js/xpc/ContextStack;1", &rv); NS_ENSURE_SUCCESS (rv, rv); cx = stack->GetSafeJSContext (); NS_ENSURE_TRUE (cx, NS_ERROR_FAILURE); } nsCOMPtr<nsIXPConnect> xpc = do_GetService (nsIXPConnect::GetCID (), &rv); NS_ENSURE_SUCCESS (rv, rv); js::Value jsVal; rv = xpc->VariantToJS(cx, JS_GetGlobalObject(cx), aVariant, &jsVal); NS_ENSURE_SUCCESS (rv, rv); if ( !jsVal.isObject ()) { D_LOG (LOG_LEVEL_ERROR, "Argument aVariant is not a JSObject."); return NS_ERROR_INVALID_ARG; } JSObject* jsArrObj = jsVal.toObjectOrNull (); if (jsArrObj && js::IsObjectProxy (jsArrObj)) { jsArrObj = js::UnwrapObject (jsArrObj); } if (!jsArrObj || !JS_IsArrayObject (cx, jsArrObj)) { D_LOG (LOG_LEVEL_ERROR, "Argument aVariant is not a JS Array Object."); return NS_ERROR_INVALID_ARG; } nsTArray <nsIVariant*> res; JS_BeginRequest (cx); JSBool ok = JS_TRUE; uint32_t jsArrLen = 0; ok = JS_GetArrayLength(cx, jsArrObj, &jsArrLen); if (!ok) { JS_EndRequest(cx); D_LOG (LOG_LEVEL_ERROR, "Failed to get array length."); return NS_ERROR_FAILURE; } res.SetCapacity (jsArrLen); for (uint32_t i = 0; i < jsArrLen; ++i) { jsval elem; JSBool ok = JS_GetElement (cx, jsArrObj, i, &elem); if (ok) { nsCOMPtr<nsIVariant> variant; rv = xpc->JSValToVariant (cx, &elem, getter_AddRefs(variant)); if (NS_SUCCEEDED (rv)) { res.AppendElement (variant); NS_ADDREF (variant); } else { D_LOG (LOG_LEVEL_WARNING, "Failed to convert element at position %d to nsIVariant. (rv %d)", i+1, rv); } } else { D_LOG (LOG_LEVEL_WARNING, "Failed to get element at position %d to nsIVariant. (rv %d)", i+1, rv); } } JS_EndRequest(cx); aResultOut.SwapElements (res); return NS_OK; }