Beispiel #1
0
static JSBool
error_to_string(JSContext *context, uintN argc, jsval *vp)
{
    jsval v_self;
    JSObject *self;
    Error *priv;
    jsval v_out;
    gchar *descr;
    JSBool retval;

    v_self = JS_THIS(context, vp);
    if (!JSVAL_IS_OBJECT(v_self)) {
        /* Lie a bit here... */
        gjs_throw(context, "GLib.Error.prototype.toString() called on a non object");
        return JS_FALSE;
    }

    self = JSVAL_TO_OBJECT(v_self);
    priv = priv_from_js(context, self);

    if (priv == NULL)
        return JS_FALSE;

    v_out = JSVAL_VOID;
    retval = JS_FALSE;

    /* We follow the same pattern as standard JS errors, at the expense of
       hiding some useful information */

    if (priv->gerror == NULL) {
        descr = g_strdup_printf("%s.%s",
                                g_base_info_get_namespace(priv->info),
                                g_base_info_get_name(priv->info));

        if (!gjs_string_from_utf8(context, descr, -1, &v_out))
            goto out;
    } else {
        descr = g_strdup_printf("%s.%s: %s",
                                g_base_info_get_namespace(priv->info),
                                g_base_info_get_name(priv->info),
                                priv->gerror->message);

        if (!gjs_string_from_utf8(context, descr, -1, &v_out))
            goto out;
    }

    JS_SET_RVAL(context, vp, v_out);
    retval = JS_TRUE;

 out:
    g_free(descr);
    return retval;
}
Beispiel #2
0
static JSBool
gjs_ngettext(JSContext *context,
             unsigned   argc,
             jsval     *vp)
{
    jsval *argv = JS_ARGV(context, vp);
    char *msgid1;
    char *msgid2;
    guint32 n;
    const char *translated;
    JSBool result;
    jsval retval;

    if (!gjs_parse_args (context, "ngettext", "ssu", argc, argv,
                         "msgid1", &msgid1, "msgid2", &msgid2, "n", &n))
      return JS_FALSE;

    translated = ngettext(msgid1, msgid2, n);

    result = gjs_string_from_utf8(context, translated, -1, &retval);
    if (result)
        JS_SET_RVAL(context, vp, retval);
    g_free (msgid1);
    g_free (msgid2);
    return result;
}
Beispiel #3
0
static JSBool
gjs_pgettext(JSContext *context,
             unsigned   argc,
             jsval     *vp)
{
    jsval *argv = JS_ARGV(context, vp);
    char *src_context;
    char *msgid;
    const char *translated;
    JSBool result;
    jsval retval;

    if (!gjs_parse_args (context, "pgettext", "ss", argc, argv,
                         "context", &src_context, "msgid", &msgid))
      return JS_FALSE;

    translated = g_dpgettext2(NULL, src_context, msgid);
    g_free (src_context);

    result = gjs_string_from_utf8(context, translated, -1, &retval);
    if (result)
        JS_SET_RVAL(context, vp, retval);
    g_free (msgid);
    return result;
}
Beispiel #4
0
static JSBool
gjs_locale_to_lower_case (JSContext *context,
                          JSString  *src,
                          jsval     *retval)
{
    JSBool success = JS_FALSE;
    char *utf8 = NULL;
    char *lower_case_utf8 = NULL;

    if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(src), &utf8))
        goto out;

    lower_case_utf8 = g_utf8_strdown (utf8, -1);

    if (!gjs_string_from_utf8(context, lower_case_utf8, -1, retval))
        goto out;

    success = JS_TRUE;

out:
    g_free(utf8);
    g_free(lower_case_utf8);

    return success;
}
Beispiel #5
0
static void
gjstest_test_func_gjs_jsapi_util_string_js_string_utf8(void)
{
    GjsUnitTestFixture fixture;
    JSContext *context;
    JSObject *global;

    const char *utf8_string = "\303\211\303\226 foobar \343\203\237";
    char *utf8_result;
    jsval js_string;

    _gjs_unit_test_fixture_begin(&fixture);
    context = fixture.context;
    global = JS_GetGlobalObject(context);
    JSCompartment *oldCompartment = JS_EnterCompartment(context, global);

    g_assert(gjs_string_from_utf8(context, utf8_string, -1, &js_string) == JS_TRUE);
    g_assert(JSVAL_IS_STRING(js_string));
    g_assert(gjs_string_to_utf8(context, js_string, &utf8_result) == JS_TRUE);

    JS_LeaveCompartment(context, oldCompartment);
    _gjs_unit_test_fixture_finish(&fixture);

    g_assert(g_str_equal(utf8_string, utf8_result));

    g_free(utf8_result);
}
Beispiel #6
0
static JSBool
gjs_dgettext(JSContext *context,
             unsigned   argc,
             jsval     *vp)
{
    jsval *argv = JS_ARGV(context, vp);
    char *domain;
    char *msgid;
    const char *translated;
    JSBool result;
    jsval retval;

    if (!gjs_parse_args (context, "dgettext", "zs", argc, argv,
                         "domain", &domain, "msgid", &msgid))
      return JS_FALSE;

    translated = dgettext(domain, msgid);
    g_free (domain);

    result = gjs_string_from_utf8(context, translated, -1, &retval);
    if (result)
        JS_SET_RVAL(context, vp, retval);
    g_free (msgid);
    return result;
}
Beispiel #7
0
JSBool
gjs_string_from_filename(JSContext  *context,
                         const char *filename_string,
                         gssize      n_bytes,
                         jsval      *value_p)
{
    gsize written;
    GError *error;
    gchar *utf8_string;

    error = NULL;
    utf8_string = g_filename_to_utf8(filename_string, n_bytes, NULL,
                                     &written, &error);
    if (error) {
        gjs_throw(context,
                  "Could not convert UTF-8 string '%s' to a filename: '%s'",
                  filename_string,
                  error->message);
        g_error_free(error);
        g_free(utf8_string);
        return JS_FALSE;
    }

    if (!gjs_string_from_utf8(context, utf8_string, written, value_p))
        return JS_FALSE;

    g_free(utf8_string);

    return JS_TRUE;
}
Beispiel #8
0
bool
gjs_string_from_filename(JSContext             *context,
                         const char            *filename_string,
                         ssize_t                n_bytes,
                         JS::MutableHandleValue value_p)
{
    gsize written;
    GError *error;
    gchar *utf8_string;

    error = NULL;
    utf8_string = g_filename_to_utf8(filename_string, n_bytes, NULL,
                                     &written, &error);
    if (error) {
        gjs_throw(context,
                  "Could not convert UTF-8 string '%s' to a filename: '%s'",
                  filename_string,
                  error->message);
        g_error_free(error);
        g_free(utf8_string);
        return false;
    }

    if (!gjs_string_from_utf8(context, utf8_string, written, value_p))
        return false;

    g_free(utf8_string);

    return true;
}
Beispiel #9
0
JSBool
gjs_js_define_system_stuff(JSContext  *context,
                           JSObject  **module_out)
{
    GjsContext *gjs_context;
    char *program_name;
    jsval value;
    JSBool retval;
    JSObject *module;

    module = JS_NewObject (context, NULL, NULL, NULL);

    if (!JS_DefineFunctions(context, module, &module_funcs[0]))
        return JS_FALSE;

    retval = JS_FALSE;

    gjs_context = (GjsContext*) JS_GetContextPrivate(context);
    g_object_get(gjs_context,
                 "program-name", &program_name,
                 NULL);

    if (!gjs_string_from_utf8(context, program_name,
                              -1, &value))
        goto out;

    /* The name is modeled after program_invocation_name,
       part of the glibc */
    if (!JS_DefineProperty(context, module,
                           "programInvocationName",
                           value,
                           JS_PropertyStub,
                           JS_StrictPropertyStub,
                           GJS_MODULE_PROP_FLAGS | JSPROP_READONLY))
        goto out;

    if (!JS_DefineProperty(context, module,
                           "version",
                           INT_TO_JSVAL(GJS_VERSION),
                           JS_PropertyStub,
                           JS_StrictPropertyStub,
                           GJS_MODULE_PROP_FLAGS | JSPROP_READONLY))
        goto out;

    retval = JS_TRUE;

 out:
    g_free(program_name);
    *module_out = module;

    return retval;
}
Beispiel #10
0
/* define properties that JS Error() expose, such as
   fileName, lineNumber and stack
*/
static void
define_error_properties(JSContext *context,
                        JSObject  *obj)
{
    JSStackFrame *frame;
    JSScript *script;
    jsbytecode *pc;
    jsval v;
    GString *stack;
    const char *filename;
    GjsContext *gjs_context;

    /* find the JS frame that triggered the error */
    frame = NULL;
    while (JS_FrameIterator(context, &frame)) {
        if (JS_IsScriptFrame(context, frame))
            break;
    }

    /* someone called gjs_throw at top of the stack?
       well, no stack in that case
    */
    if (!frame)
        return;

    script = JS_GetFrameScript(context, frame);
    pc = JS_GetFramePC(context, frame);

    stack = g_string_new(NULL);
    gjs_context = JS_GetContextPrivate(context);
    gjs_context_print_stack_to_buffer(gjs_context, frame, stack);

    if (gjs_string_from_utf8(context, stack->str, stack->len, &v))
        JS_DefineProperty(context, obj, "stack", v,
                          NULL, NULL, JSPROP_ENUMERATE);

    filename = JS_GetScriptFilename(context, script);
    if (gjs_string_from_filename(context, filename, -1, &v))
        JS_DefineProperty(context, obj, "fileName", v,
                          NULL, NULL, JSPROP_ENUMERATE);

    v = INT_TO_JSVAL(JS_PCToLineNumber(context, script, pc));
    JS_DefineProperty(context, obj, "lineNumber", v,
                      NULL, NULL, JSPROP_ENUMERATE);

    g_string_free(stack, TRUE);
}
Beispiel #11
0
static JSBool
get_name_func (JSContext *context,
               JSObject  *obj,
               jsid       id,
               jsval     *vp)
{
    GType gtype;
    JSBool ret;
    jsval retval;

    gtype = GPOINTER_TO_SIZE(priv_from_js(context, obj));

    ret = gjs_string_from_utf8(context, g_type_name(gtype), -1, &retval);
    if (ret)
        JS_SET_RVAL(context, vp, retval);
    return ret;
}
Beispiel #12
0
static JSBool
error_get_message(JSContext *context, JSObject *obj, jsid id, jsval *vp)
{
    Error *priv;

    priv = priv_from_js(context, obj);

    if (priv == NULL)
        return JS_FALSE;

    if (priv->gerror == NULL) {
        /* Object is prototype, not instance */
        gjs_throw(context, "Can't get a field from a GError prototype");
        return JS_FALSE;
    }

    return gjs_string_from_utf8(context, priv->gerror->message, -1, vp);
}
Beispiel #13
0
static JSBool
to_string_func(JSContext *context,
               uintN      argc,
               jsval     *vp)
{
    JSObject *obj = JS_THIS_OBJECT(context, vp);
    GType gtype;
    gchar *strval;
    JSBool ret;
    jsval retval;
    
    gtype = GPOINTER_TO_SIZE(priv_from_js(context, obj));

    strval = g_strdup_printf("[object GType for '%s']",
                             g_type_name(gtype));
    ret = gjs_string_from_utf8(context, strval, -1, &retval);
    if (ret)
        JS_SET_RVAL(context, vp, retval);
    g_free(strval);
    return ret;
}
Beispiel #14
0
static JSBool
gjs_address_of(JSContext *context,
               unsigned   argc,
               jsval     *vp)
{
    jsval *argv = JS_ARGV(cx, vp);
    JSObject *target_obj;
    JSBool ret;
    char *pointer_string;
    jsval retval;

    if (!gjs_parse_args(context, "addressOf", "o", argc, argv, "object", &target_obj))
        return JS_FALSE;

    pointer_string = g_strdup_printf("%p", target_obj);

    ret = gjs_string_from_utf8(context, pointer_string, -1, &retval);
    if (ret)
        JS_SET_RVAL(context, vp, retval);

    return ret;
}
Beispiel #15
0
static JSBool
get_name (JSContext *context,
          JS::HandleObject obj,
          JS::HandleId id,
          jsval *vp)
{
    Ns *priv;
    jsval retval;
    JSBool ret = JS_FALSE;

    priv = priv_from_js(context, obj);

    if (priv == NULL)
        goto out;

    if (gjs_string_from_utf8(context, priv->gi_namespace, -1, &retval)) {
        *vp = retval;
        ret = JS_TRUE;
    }

 out:
    return ret;
}
Beispiel #16
0
static JSBool
gjs_locale_to_unicode (JSContext  *context,
                       const char *src,
                       jsval      *retval)
{
    JSBool success;
    char *utf8;
    GError *error = NULL;

    utf8 = g_locale_to_utf8(src, -1, NULL, NULL, &error);
    if (!utf8) {
        gjs_throw(context,
                  "Failed to convert locale string to UTF8: %s",
                  error->message);
        g_error_free(error);
        return JS_FALSE;
    }

    success = gjs_string_from_utf8(context, utf8, -1, retval);
    g_free (utf8);

    return success;
}
Beispiel #17
0
static JSBool
gjs_format_int_alternative_output(JSContext *context,
                                  uintN      argc,
                                  jsval     *vp)
{
    jsval *argv = JS_ARGV(cx, vp);
    char *str;
    jsval rval;
    int intval;
    JSBool ret;

    if (!gjs_parse_args(context, "format_int_alternative_output", "i", argc, argv,
                        "intval", &intval))
        return JS_FALSE;

    str = g_strdup_printf("%Id", intval);
    ret = gjs_string_from_utf8(context, str, -1, &rval);
    if (ret)
        JS_SET_RVAL(context, vp, rval);
    g_free (str);

    return ret;
}
Beispiel #18
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_runtime_get_const_string(JS_GetRuntime(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 = JSVAL_TO_PRIVATE(*state_p);

        if (iter->index < iter->elements->len) {
            if (!gjs_string_from_utf8(context,
                                         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 = JSVAL_TO_PRIVATE(*state_p);

            importer_iterator_free(iter);

            *state_p = JSVAL_NULL;
        }
    }
    }

    return JS_TRUE;
}
Beispiel #19
0
JSBool
gjs_js_define_system_stuff(JSContext *context,
                           JSObject  *module)
{
    GjsContext *gjs_context;
    char *program_name;
    jsval value;
    JSBool retval;

    if (!JS_DefineFunction(context, module,
                           "addressOf",
                           (JSNative) gjs_address_of,
                           1, GJS_MODULE_PROP_FLAGS))
        return JS_FALSE;

    if (!JS_DefineFunction(context, module,
                           "refcount",
                           (JSNative) gjs_refcount,
                           1, GJS_MODULE_PROP_FLAGS))
        return JS_FALSE;

    if (!JS_DefineFunction(context, module,
                           "breakpoint",
                           (JSNative) gjs_breakpoint,
                           0, GJS_MODULE_PROP_FLAGS))
        return JS_FALSE;

    if (!JS_DefineFunction(context, module,
                           "gc",
                           (JSNative) gjs_gc,
                           0, GJS_MODULE_PROP_FLAGS))
        return JS_FALSE;

    if (!JS_DefineFunction(context, module,
                           "exit",
                           (JSNative) gjs_exit,
                           1, GJS_MODULE_PROP_FLAGS))
        return JS_FALSE;

    retval = JS_FALSE;

    gjs_context = JS_GetContextPrivate(context);
    g_object_get(gjs_context,
                 "program-name", &program_name,
                 NULL);

    if (!gjs_string_from_utf8(context, program_name,
                              -1, &value))
        goto out;

    /* The name is modeled after program_invocation_name,
       part of the glibc */
    if (!JS_DefineProperty(context, module,
                           "programInvocationName",
                           value,
                           JS_PropertyStub,
                           JS_StrictPropertyStub,
                           GJS_MODULE_PROP_FLAGS | JSPROP_READONLY))
        goto out;

    if (!JS_DefineProperty(context, module,
                           "version",
                           INT_TO_JSVAL(GJS_VERSION),
                           JS_PropertyStub,
                           JS_StrictPropertyStub,
                           GJS_MODULE_PROP_FLAGS | JSPROP_READONLY))
        goto out;

    retval = JS_TRUE;

 out:
    g_free(program_name);

    return retval;
}
Beispiel #20
0
static JSBool
gjs_value_from_g_value_internal(JSContext    *context,
                                jsval        *value_p,
                                const GValue *gvalue,
                                gboolean      no_copy,
                                GSignalQuery *signal_query,
                                gint          arg_n)
{
    GType gtype;

    gtype = G_VALUE_TYPE(gvalue);

    gjs_debug_marshal(GJS_DEBUG_GCLOSURE,
                      "Converting gtype %s to jsval",
                      g_type_name(gtype));

    if (gtype == G_TYPE_STRING) {
        const char *v;
        v = g_value_get_string(gvalue);
        if (v == NULL) {
            gjs_debug_marshal(GJS_DEBUG_GCLOSURE,
                              "Converting NULL string to JSVAL_NULL");
            *value_p = JSVAL_NULL;
        } else {
            if (!gjs_string_from_utf8(context, v, -1, value_p))
                return JS_FALSE;
        }
    } else if (gtype == G_TYPE_CHAR) {
        char v;
        v = g_value_get_schar(gvalue);
        *value_p = INT_TO_JSVAL(v);
    } else if (gtype == G_TYPE_UCHAR) {
        unsigned char v;
        v = g_value_get_uchar(gvalue);
        *value_p = INT_TO_JSVAL(v);
    } else if (gtype == G_TYPE_INT) {
        int v;
        v = g_value_get_int(gvalue);
        return JS_NewNumberValue(context, v, value_p);
    } else if (gtype == G_TYPE_UINT) {
        uint v;
        v = g_value_get_uint(gvalue);
        return JS_NewNumberValue(context, v, value_p);
    } else if (gtype == G_TYPE_DOUBLE) {
        double d;
        d = g_value_get_double(gvalue);
        return JS_NewNumberValue(context, d, value_p);
    } else if (gtype == G_TYPE_FLOAT) {
        double d;
        d = g_value_get_float(gvalue);
        return JS_NewNumberValue(context, d, value_p);
    } else if (gtype == G_TYPE_BOOLEAN) {
        gboolean v;
        v = g_value_get_boolean(gvalue);
        *value_p = BOOLEAN_TO_JSVAL(v);
    } else if (g_type_is_a(gtype, G_TYPE_OBJECT) || g_type_is_a(gtype, G_TYPE_INTERFACE)) {
        GObject *gobj;
        JSObject *obj;

        gobj = g_value_get_object(gvalue);

        obj = gjs_object_from_g_object(context, gobj);
        *value_p = OBJECT_TO_JSVAL(obj);
    } else if (gtype == G_TYPE_STRV) {
        if (!gjs_array_from_strv (context,
                                  value_p,
                                  g_value_get_boxed (gvalue))) {
            gjs_throw(context, "Failed to convert strv to array");
            return JS_FALSE;
        }
    } else if (g_type_is_a(gtype, G_TYPE_HASH_TABLE) ||
               g_type_is_a(gtype, G_TYPE_ARRAY) ||
               g_type_is_a(gtype, G_TYPE_BYTE_ARRAY) ||
               g_type_is_a(gtype, G_TYPE_PTR_ARRAY)) {
        gjs_throw(context,
                  "Unable to introspect element-type of container in GValue");
        return JS_FALSE;
    } else if (g_type_is_a(gtype, G_TYPE_BOXED) ||
               g_type_is_a(gtype, G_TYPE_VARIANT)) {
        GjsBoxedCreationFlags boxed_flags;
        GIBaseInfo *info;
        void *gboxed;
        JSObject *obj;

        if (g_type_is_a(gtype, G_TYPE_BOXED))
            gboxed = g_value_get_boxed(gvalue);
        else
            gboxed = g_value_get_variant(gvalue);
        boxed_flags = GJS_BOXED_CREATION_NONE;

        /* special case GError */
        if (g_type_is_a(gtype, G_TYPE_ERROR)) {
            obj = gjs_error_from_gerror(context, gboxed, FALSE);
            *value_p = OBJECT_TO_JSVAL(obj);

            return TRUE;
        }

        /* The only way to differentiate unions and structs is from
         * their g-i info as both GBoxed */
        info = g_irepository_find_by_gtype(g_irepository_get_default(),
                                           gtype);
        if (info == NULL) {
            gjs_throw(context,
                      "No introspection information found for %s",
                      g_type_name(gtype));
            return JS_FALSE;
        }

        if (g_base_info_get_type(info) == GI_INFO_TYPE_STRUCT &&
            g_struct_info_is_foreign((GIStructInfo*)info)) {
            JSBool ret;
            GIArgument arg;
            arg.v_pointer = gboxed;
            ret = gjs_struct_foreign_convert_from_g_argument(context, value_p, info, &arg);
            g_base_info_unref(info);
            return ret;
        }

        switch (g_base_info_get_type(info)) {
        case GI_INFO_TYPE_BOXED:
        case GI_INFO_TYPE_STRUCT:
            if (no_copy)
                boxed_flags |= GJS_BOXED_CREATION_NO_COPY;
            obj = gjs_boxed_from_c_struct(context, (GIStructInfo *)info, gboxed, boxed_flags);
            break;
        case GI_INFO_TYPE_UNION:
            obj = gjs_union_from_c_union(context, (GIUnionInfo *)info, gboxed);
            break;
        default:
            gjs_throw(context,
                      "Unexpected introspection type %d for %s",
                      g_base_info_get_type(info),
                      g_type_name(gtype));
            g_base_info_unref(info);
            return JS_FALSE;
        }

        *value_p = OBJECT_TO_JSVAL(obj);
        g_base_info_unref(info);
    } else if (g_type_is_a(gtype, G_TYPE_ENUM)) {
        return convert_int_to_enum(context, value_p, gtype, g_value_get_enum(gvalue));
    } else if (g_type_is_a(gtype, G_TYPE_PARAM)) {
        GParamSpec *gparam;
        JSObject *obj;

        gparam = g_value_get_param(gvalue);

        obj = gjs_param_from_g_param(context, gparam);
        *value_p = OBJECT_TO_JSVAL(obj);
    } else if (signal_query && g_type_is_a(gtype, G_TYPE_POINTER)) {
        JSBool res;
        GArgument arg;
        GIArgInfo *arg_info;
        GIBaseInfo *obj;
        GISignalInfo *signal_info;
        GITypeInfo type_info;

        obj = g_irepository_find_by_gtype(NULL, signal_query->itype);
        if (!obj) {
            gjs_throw(context, "Signal argument with GType %s isn't introspectable",
                      g_type_name(signal_query->itype));
            return JS_FALSE;
        }

        signal_info = g_object_info_find_signal((GIObjectInfo*)obj, signal_query->signal_name);

        if (!signal_info) {
            gjs_throw(context, "Unknown signal.");
            g_base_info_unref((GIBaseInfo*)obj);
            return JS_FALSE;
        }
        arg_info = g_callable_info_get_arg(signal_info, arg_n - 1);
        g_arg_info_load_type(arg_info, &type_info);

        arg.v_pointer = g_value_get_pointer(gvalue);

        res = gjs_value_from_g_argument(context, value_p, &type_info, &arg, TRUE);

        g_base_info_unref((GIBaseInfo*)arg_info);
        g_base_info_unref((GIBaseInfo*)signal_info);
        g_base_info_unref((GIBaseInfo*)obj);
        return res;
    } else if (g_type_is_a(gtype, G_TYPE_POINTER)) {
        gpointer pointer;

        pointer = g_value_get_pointer(gvalue);

        if (pointer == NULL) {
            *value_p = JSVAL_NULL;
        } else {
            gjs_throw(context,
                      "Can't convert non-null pointer to JS value");
            return JS_FALSE;
        }
    } else if (g_value_type_transformable(gtype, G_TYPE_DOUBLE)) {
        GValue double_value = { 0, };
        double v;
        g_value_init(&double_value, G_TYPE_DOUBLE);
        g_value_transform(gvalue, &double_value);
        v = g_value_get_double(&double_value);
        return JS_NewNumberValue(context, v, value_p);
    } else if (g_value_type_transformable(gtype, G_TYPE_INT)) {
        GValue int_value = { 0, };
        int v;
        g_value_init(&int_value, G_TYPE_INT);
        g_value_transform(gvalue, &int_value);
        v = g_value_get_int(&int_value);
        return JS_NewNumberValue(context, v, value_p);
    } else {
        gjs_throw(context,
                  "Don't know how to convert GType %s to JavaScript object",
                  g_type_name(gtype));
        return JS_FALSE;
    }

    return JS_TRUE;
}
Beispiel #21
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,
                       JS::HandleObject object,
                       JSIterateOp enum_op,
                       JS::MutableHandleValue statep,
                       JS::MutableHandleId idp)
{
    ImporterIterator *iter;

    switch (enum_op) {
    case JSENUMERATE_INIT_ALL:
    case JSENUMERATE_INIT: {
        Importer *priv;
        JSObject *search_path;
        jsval search_path_val;
        uint32_t search_path_len;
        uint32_t i;
        jsid search_path_name;

        statep.set(JSVAL_NULL);

        idp.set(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 (!search_path_val.isObject()) {
            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) {
            std::string dirname;
            std::string init_path;
            const char *filename;
            jsval elem;
            std::vector<std::string> dir;

            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 = pathCombine(dirname, MODULE_INIT_FILENAME);

            load_module_elements(context, object, iter, init_path);

            dir = enumerateFilesInDirectory(dirname);

            if (dir.size() == 0) {
                continue;
            }

            for(auto filename : dir) {
                std::string full_path;

                /* skip hidden files and directories (.svn, .git, ...) */
                if (filename[0] == '.')
                    continue;

                /* skip module init file */
                if (filename == MODULE_INIT_FILENAME)
                    continue;

                full_path = pathCombine(dirname, filename);

                if (is_directory(full_path)) {
                    iter->elements.push_back(filename);
                } else {
                    if (filename.rfind(MODULE_SUFFIX) != std::string::npos ||
                        filename.rfind(JS_SUFFIX) != std::string::npos) {
                        iter->elements.push_back(filename.substr(0, filename.size()-3));
                    }
                }
            }
        }

        statep.set(PRIVATE_TO_JSVAL(iter));

        idp.set(INT_TO_JSID(iter->elements.size()));

        break;
    }

    case JSENUMERATE_NEXT: {
        jsval element_val;

        if (JSVAL_IS_NULL(statep)) /* Iterating prototype */
            return JS_TRUE;

        iter = (ImporterIterator*) JSVAL_TO_PRIVATE(statep);

        if (iter->index < iter->elements.size()) {
            if (!gjs_string_from_utf8(context,
                                         iter->elements.at(iter->index++),
                                         &element_val))
                return JS_FALSE;

            jsid id;
            if (!JS_ValueToId(context, element_val, &id))
                return JS_FALSE;
            idp.set(id);

            break;
        }
        /* else fall through to destroying the iterator */
    }

    case JSENUMERATE_DESTROY: {
        if (!JSVAL_IS_NULL(statep)) {
            iter = (ImporterIterator*) JSVAL_TO_PRIVATE(statep);

            importer_iterator_free(iter);

            statep.set(JSVAL_NULL);
        }
    }
    }

    return JS_TRUE;
}
Beispiel #22
0
/* implement toString() with an optional encoding arg */
static JSBool
to_string_func(JSContext *context,
               unsigned   argc,
               jsval     *vp)
{
    JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
    JSObject *object = JSVAL_TO_OBJECT(argv.thisv());
    ByteArrayInstance *priv;
    char *encoding;
    gboolean encoding_is_utf8;
    gchar *data;

    priv = priv_from_js(context, object);

    if (priv == NULL)
        return JS_TRUE; /* prototype, not instance */

    byte_array_ensure_array(priv);

    if (argc >= 1 &&
        JSVAL_IS_STRING(argv[0])) {
        if (!gjs_string_to_utf8(context, argv[0], &encoding))
            return JS_FALSE;

        /* maybe we should be smarter about utf8 synonyms here.
         * doesn't matter much though. encoding_is_utf8 is
         * just an optimization anyway.
         */
        if (strcmp(encoding, "UTF-8") == 0) {
            encoding_is_utf8 = TRUE;
            g_free(encoding);
            encoding = NULL;
        } else {
            encoding_is_utf8 = FALSE;
        }
    } else {
        encoding_is_utf8 = TRUE;
    }

    if (priv->array->len == 0)
        /* the internal data pointer could be NULL in this case */
        data = (gchar*)"";
    else
        data = (gchar*)priv->array->data;

    if (encoding_is_utf8) {
        /* optimization, avoids iconv overhead and runs
         * libmozjs hardwired utf8-to-utf16
         */
        jsval retval;
        JSBool ok;

        ok = gjs_string_from_utf8(context,
                                  data,
                                  priv->array->len,
                                  &retval);
        if (ok)
            argv.rval().set(retval);
        return ok;
    } else {
        JSBool ok = JS_FALSE;
        gsize bytes_written;
        GError *error;
        JSString *s;
        char *u16_str;

        error = NULL;
        u16_str = g_convert(data,
                           priv->array->len,
                           "UTF-16",
                           encoding,
                           NULL, /* bytes read */
                           &bytes_written,
                           &error);
        g_free(encoding);
        if (u16_str == NULL) {
            /* frees the GError */
            gjs_throw_g_error(context, error);
            return JS_FALSE;
        }

        /* bytes_written should be bytes in a UTF-16 string so
         * should be a multiple of 2
         */
        g_assert((bytes_written % 2) == 0);

        s = JS_NewUCStringCopyN(context,
                                (jschar*) u16_str,
                                bytes_written / 2);
        if (s != NULL) {
            ok = JS_TRUE;
            argv.rval().set(STRING_TO_JSVAL(s));
        }

        g_free(u16_str);
        return ok;
    }
}
Beispiel #23
0
/*
 * See:
 * https://bugzilla.mozilla.org/show_bug.cgi?id=166436
 * https://bugzilla.mozilla.org/show_bug.cgi?id=215173
 *
 * Very surprisingly, jsapi.h lacks any way to "throw new Error()"
 *
 * So here is an awful hack inspired by
 * http://egachine.berlios.de/embedding-sm-best-practice/embedding-sm-best-practice.html#error-handling
 */
static void
gjs_throw_valist(JSContext       *context,
                 const char      *error_class,
                 const char      *format,
                 va_list          args)
{
    char *s;
    JSBool result;
    jsval v_constructor, v_message;
    JSObject *err_obj;

    s = g_strdup_vprintf(format, args);

    JS_BeginRequest(context);

    if (JS_IsExceptionPending(context)) {
        /* Often it's unclear whether a given jsapi.h function
         * will throw an exception, so we will throw ourselves
         * "just in case"; in those cases, we don't want to
         * overwrite an exception that already exists.
         * (Do log in case our second exception adds more info,
         * but don't log as topic ERROR because if the exception is
         * caught we don't want an ERROR in the logs.)
         */
        gjs_debug(GJS_DEBUG_CONTEXT,
                  "Ignoring second exception: '%s'",
                  s);
        g_free(s);
        JS_EndRequest(context);
        return;
    }

    result = JS_FALSE;

    (void)JS_EnterLocalRootScope(context);

    if (!gjs_string_from_utf8(context, s, -1, &v_message)) {
        JS_ReportError(context, "Failed to copy exception string");
        goto out;
    }

    if (!gjs_object_get_property(context, JS_GetGlobalObject(context),
                                 error_class, &v_constructor)) {
        JS_ReportError(context, "??? Missing Error constructor in global object?");
        goto out;
    }

    /* throw new Error(message) */
    err_obj = JS_New(context, JSVAL_TO_OBJECT(v_constructor), 1, &v_message);
    JS_SetPendingException(context, OBJECT_TO_JSVAL(err_obj));

    result = JS_TRUE;

 out:

    JS_LeaveLocalRootScope(context);

    if (!result) {
        /* try just reporting it to error handler? should not
         * happen though pretty much
         */
        JS_ReportError(context,
                       "Failed to throw exception '%s'",
                       s);
    }
    g_free(s);

    JS_EndRequest(context);
}
Beispiel #24
0
/*
 * See:
 * https://bugzilla.mozilla.org/show_bug.cgi?id=166436
 * https://bugzilla.mozilla.org/show_bug.cgi?id=215173
 *
 * Very surprisingly, jsapi.h lacks any way to "throw new Error()"
 *
 * So here is an awful hack inspired by
 * http://egachine.berlios.de/embedding-sm-best-practice/embedding-sm-best-practice.html#error-handling
 */
static void
gjs_throw_valist(JSContext       *context,
                    const char      *format,
                    va_list          args)
{
    char *s;
    jsval retval;
    jsval argv[1];
    JSFunction *func;
    const char *body;
    JSBool result;
    const char *names[] = { "message" };
    guint options;

    s = g_strdup_vprintf(format, args);

    JS_BeginRequest(context);

    if (JS_IsExceptionPending(context)) {
        /* Often it's unclear whether a given jsapi.h function
         * will throw an exception, so we will throw ourselves
         * "just in case"; in those cases, we don't want to
         * overwrite an exception that already exists.
         * (Do log in case our second exception adds more info,
         * but don't log as topic ERROR because if the exception is
         * caught we don't want an ERROR in the logs.)
         */
        gjs_debug(GJS_DEBUG_CONTEXT,
                  "Ignoring second exception: '%s'",
                  s);
        g_free(s);
        return;
    }

    result = JS_FALSE;

    JS_EnterLocalRootScope(context);

    if (!gjs_string_from_utf8(context, s, -1, &argv[0])) {
        JS_ReportError(context, "Failed to copy exception string");
        goto out;
    }

    body = "throw new Error(message);";
    func = JS_CompileFunction(context,
                              JS_GetGlobalObject(context), /* parent object (scope chain) */
                              NULL, /* name of function if we wanted to define it in parent */
                              1, /* nargs */
                              &names[0], /* array of arg names if we had args */
                              body,
                              strlen(body),
                              "gjs_throw", /* file */
                              0); /* line */

    if (func == NULL) {
        JS_ReportError(context, "Failed to compile function");
        goto out;
    }

    /* we need JS_CallFunctionValue() to leave the exception set */
    options = JS_GetOptions(context);
    if (!(options & JSOPTION_DONT_REPORT_UNCAUGHT)) {
        JS_SetOptions(context, options | JSOPTION_DONT_REPORT_UNCAUGHT);
    }

    retval = JSVAL_VOID;

    /* note the return value is whether function succeeded, which it shouldn't, since it
     * throws...
     */
    JS_CallFunctionValue(context,
                         JS_GetGlobalObject(context),
                         OBJECT_TO_JSVAL(JS_GetFunctionObject(func)),
                         1, &argv[0],
                         &retval);

    if (!(options & JSOPTION_DONT_REPORT_UNCAUGHT)) {
        JS_SetOptions(context, options);
    }

    if (!JS_IsExceptionPending(context)) {
        JS_ReportError(context,
                       "Failed to set exception by calling our exception-setting function");
        goto out;
    }

    result = JS_TRUE;

 out:

    JS_LeaveLocalRootScope(context);

    if (!result) {
        /* try just reporting it to error handler? should not
         * happen though pretty much
         */
        JS_ReportError(context,
                       "Failed to throw exception '%s'",
                       s);
    }
    g_free(s);

    JS_EndRequest(context);
}