Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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
Пример #5
0
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;
}
Пример #6
0
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;
}
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
0
// 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;
}
Пример #11
0
/*
 * 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);
}
Пример #12
0
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;
}
Пример #13
0
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;
}
Пример #14
0
/* 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;
}
Пример #15
0
/** 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;
}
Пример #16
0
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);
  }
}
Пример #17
0
/*
 * 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;
}
Пример #18
0
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);
  }
}
Пример #19
0
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('}');
}
Пример #20
0
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", &currentIterator));

					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();
	}
	}
}
Пример #21
0
    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;
        };
    }
Пример #22
0
/*
  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;
}
Пример #23
0
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;
}
Пример #24
0
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;
}
Пример #25
0
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;
}
Пример #26
0
/* 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;
}
Пример #27
0
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;
}
Пример #28
0
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;
}
Пример #29
0
/*
 * 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;
}
Пример #30
0
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;
}