Exemple #1
0
static JSObjectRef
ns_new(JSContextRef context,
       const char   *ns_name)
{
    Ns *priv = NULL;
    JSObjectRef ret = NULL;
    JSObjectRef global = NULL;
    gboolean found = FALSE;
    JSObjectRef proto = NULL;
    JSValueRef exception = NULL;

    // XXX: NOT THREAD SAFE?
    if (!gwkjs_ns_class_ref) {
        gwkjs_ns_class_ref = JSClassCreate(&gwkjs_ns_class);
        JSClassRetain(gwkjs_ns_class_ref);
    }

    global = gwkjs_get_import_global(context);
    if (!(found = gwkjs_object_has_property(context,
                                            global,
                                            gwkjs_ns_class.className))) {
        proto = JSObjectMake(context,
                             gwkjs_ns_class_ref,
                             NULL);

        gwkjs_object_set_property(context, global,
                                  gwkjs_ns_class.className,
                                  proto,
                                  GWKJS_PROTO_PROP_FLAGS,
                                  &exception);

        if (exception)
           g_error("Can't init class %s", gwkjs_ns_class.className);

        gwkjs_debug(GWKJS_DEBUG_IMPORTER, "Initialized class %s prototype %p",
                    gwkjs_ns_class.className, proto);
    } else {
        JSValueRef proto_val = gwkjs_object_get_property(context,
                                                         global,
                                                         gwkjs_ns_class.className,
                                                         &exception);

        if (exception || proto_val == NULL || !JSValueIsObject(context, proto_val))
            g_error("Can't get protoType for class %s", gwkjs_ns_class.className);

        proto = JSValueToObject(context, proto_val, NULL);
    }
    g_assert(proto != NULL);

    ret = JSObjectMake(context, gwkjs_ns_class_ref, NULL);

    if (ret == NULL)
        return ret;

    JSObjectSetPrototype(context, ret, proto);

    priv = g_slice_new0(Ns);
    GWKJS_INC_COUNTER(ns);
    
    g_assert(priv_from_js(ret) == NULL);
    JSObjectSetPrivate(ret, priv);

    gwkjs_debug_lifecycle(GWKJS_DEBUG_GNAMESPACE, "ns constructor, obj %p priv %p", ret, priv);

    priv = priv_from_js(ret);
    priv->modules = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);

    priv->gi_namespace = g_strdup(ns_name);
    return ret;
}
Exemple #2
0
/*
 * Like JSResolveOp, but flags provide contextual information as follows:
 *
 *  JSRESOLVE_QUALIFIED   a qualified property id: obj.id or obj[id], not id
 *  JSRESOLVE_ASSIGNING   obj[id] is on the left-hand side of an assignment
 *  JSRESOLVE_DETECTING   'if (o.p)...' or similar detection opcode sequence
 *  JSRESOLVE_DECLARING   var, const, or boxed prolog declaration opcode
 *  JSRESOLVE_CLASSNAME   class name used when constructing
 *
 * The *objp out parameter, on success, should be null to indicate that id
 * was not resolved; and non-null, referring to obj or one of its prototypes,
 * if id was resolved.
 */
static JSBool
boxed_new_resolve(JSContext *context,
                  JSObject  *obj,
                  jsid       id,
                  unsigned   flags,
                  JSObject **objp)
{
    Boxed *priv;
    char *name;
    JSBool ret = JS_FALSE;

    *objp = NULL;

    if (!gjs_get_string_id(context, id, &name))
        return JS_TRUE; /* not resolved, but no error */

    priv = priv_from_js(context, obj);
    gjs_debug_jsprop(GJS_DEBUG_GBOXED, "Resolve prop '%s' hook obj %p priv %p", name, obj, priv);

    if (priv == NULL)
        goto out; /* wrong class */

    if (priv->gboxed == NULL) {
        /* We are the prototype, so look for methods and other class properties */
        GIFunctionInfo *method_info;

        method_info = g_struct_info_find_method((GIStructInfo*) priv->info,
                                                name);

        if (method_info != NULL) {
            JSObject *boxed_proto;
            const char *method_name;

#if GJS_VERBOSE_ENABLE_GI_USAGE
            _gjs_log_info_usage((GIBaseInfo*) method_info);
#endif

            method_name = g_base_info_get_name( (GIBaseInfo*) method_info);

            gjs_debug(GJS_DEBUG_GBOXED,
                      "Defining method %s in prototype for %s.%s",
                      method_name,
                      g_base_info_get_namespace( (GIBaseInfo*) priv->info),
                      g_base_info_get_name( (GIBaseInfo*) priv->info));

            boxed_proto = obj;

            if (gjs_define_function(context, boxed_proto, priv->gtype,
                                    (GICallableInfo *)method_info) == NULL) {
                g_base_info_unref( (GIBaseInfo*) method_info);
                goto out;
            }

            *objp = boxed_proto; /* we defined the prop in object_proto */

            g_base_info_unref( (GIBaseInfo*) method_info);
        }
    } else {
        /* We are an instance, not a prototype, so look for
         * per-instance props that we want to define on the
         * JSObject. Generally we do not want to cache these in JS, we
         * want to always pull them from the C object, or JS would not
         * see any changes made from C. So we use the get/set prop
         * hooks, not this resolve hook.
         */
    }
    ret = JS_TRUE;

 out:
    g_free(name);
    return ret;
}
Exemple #3
0
static JSBool
boxed_field_getter (JSContext *context,
                    JSObject  *obj,
                    jsid       id,
                    jsval     *value)
{
    Boxed *priv;
    GIFieldInfo *field_info;
    GITypeInfo *type_info;
    GArgument arg;
    gboolean success = FALSE;

    priv = priv_from_js(context, obj);
    if (!priv)
        return JS_FALSE;

    field_info = get_field_info(context, priv, id);
    if (!field_info)
        return JS_FALSE;

    type_info = g_field_info_get_type (field_info);

    if (priv->gboxed == NULL) { /* direct access to proto field */
        gjs_throw(context, "Can't get field %s.%s from a prototype",
                  g_base_info_get_name ((GIBaseInfo *)priv->info),
                  g_base_info_get_name ((GIBaseInfo *)field_info));
        goto out;
    }

    if (!g_type_info_is_pointer (type_info) &&
        g_type_info_get_tag (type_info) == GI_TYPE_TAG_INTERFACE) {

        GIBaseInfo *interface_info = g_type_info_get_interface(type_info);

        if (g_base_info_get_type (interface_info) == GI_INFO_TYPE_STRUCT ||
            g_base_info_get_type (interface_info) == GI_INFO_TYPE_BOXED) {

            success = get_nested_interface_object (context, obj, priv,
                                                   field_info, type_info, interface_info,
                                                   value);

            g_base_info_unref ((GIBaseInfo *)interface_info);

            goto out;
        }

        g_base_info_unref ((GIBaseInfo *)interface_info);
    }

    if (!g_field_info_get_field (field_info, priv->gboxed, &arg)) {
        gjs_throw(context, "Reading field %s.%s is not supported",
                  g_base_info_get_name ((GIBaseInfo *)priv->info),
                  g_base_info_get_name ((GIBaseInfo *)field_info));
        goto out;
    }

    if (!gjs_value_from_g_argument (context, value,
                                    type_info,
                                    &arg,
                                    TRUE))
        goto out;

    success = TRUE;

out:
    g_base_info_unref ((GIBaseInfo *)field_info);
    g_base_info_unref ((GIBaseInfo *)type_info);

    return success;
}
Exemple #4
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;
}
Exemple #5
0
static JSObject*
importer_new(JSContext *context,
             gboolean   is_root)
{
    JSObject *importer;
    Importer *priv;
    JSObject *global;
    JSBool found;

    global = gjs_get_import_global(context);

    if (!JS_HasProperty(context, global, gjs_importer_class.name, &found))
        g_error("HasProperty call failed creating importer class");

    if (!found) {
        JSObject *prototype;
        prototype = JS_InitClass(context, global,
                                 /* parent prototype JSObject* for
                                  * prototype; NULL for
                                  * Object.prototype
                                  */
                                 NULL,
                                 &gjs_importer_class,
                                 /* constructor for instances (NULL for
                                  * none - just name the prototype like
                                  * Math - rarely correct)
                                  */
                                 gjs_importer_constructor,
                                 /* number of constructor args */
                                 0,
                                 /* props of prototype */
                                 &gjs_importer_proto_props[0],
                                 /* funcs of prototype */
                                 &gjs_importer_proto_funcs[0],
                                 /* props of constructor, MyConstructor.myprop */
                                 NULL,
                                 /* funcs of constructor, MyConstructor.myfunc() */
                                 NULL);
        if (prototype == NULL)
            g_error("Can't init class %s", gjs_importer_class.name);

        gjs_debug(GJS_DEBUG_IMPORTER, "Initialized class %s prototype %p",
                  gjs_importer_class.name, prototype);
    }

    importer = JS_NewObject(context, &gjs_importer_class, NULL, global);
    if (importer == NULL)
        g_error("No memory to create importer importer");

    priv = g_slice_new0(Importer);
    priv->is_root = is_root;

    GJS_INC_COUNTER(importer);

    g_assert(priv_from_js(context, importer) == NULL);
    JS_SetPrivate(importer, priv);

    gjs_debug_lifecycle(GJS_DEBUG_IMPORTER,
                        "importer constructor, obj %p priv %p", importer, priv);

    return importer;
}
Exemple #6
0
GJS_NATIVE_CONSTRUCTOR_DECLARE(union)
{
    GJS_NATIVE_CONSTRUCTOR_VARIABLES(union)
    Union *priv;
    Union *proto_priv;
    JSObject *proto;
    void *gboxed;

    GJS_NATIVE_CONSTRUCTOR_PRELUDE(union);

    priv = g_slice_new0(Union);

    GJS_INC_COUNTER(boxed);

    g_assert(priv_from_js(context, object) == NULL);
    JS_SetPrivate(object, priv);

    gjs_debug_lifecycle(GJS_DEBUG_GBOXED,
                        "union constructor, obj %p priv %p",
                        object, priv);

    proto = JS_GetPrototype(object);
    gjs_debug_lifecycle(GJS_DEBUG_GBOXED, "union instance __proto__ is %p", proto);

    /* If we're the prototype, then post-construct we'll fill in priv->info.
     * If we are not the prototype, though, then we'll get ->info from the
     * prototype and then create a GObject if we don't have one already.
     */
    proto_priv = priv_from_js(context, proto);
    if (proto_priv == NULL) {
Exemple #7
0
/* a hook on getting a property; set value_p to override property's value.
 * Return value is JS_FALSE on OOM/exception.
 */
static JSBool
param_get_prop(JSContext *context,
               JSObject  *obj,
               jsid       id,
               jsval     *value_p)
{
    JSBool success;
    Param *priv;
    GParamSpec *pspec;
    char *name;
    GType gtype;
    GIObjectInfo *info = NULL, *parent_info = NULL;
    GIFieldInfo *field_info = NULL;
    GITypeInfo *type_info = NULL;
    GIArgument arg;

    if (!gjs_get_string_id(context, id, &name))
        return JS_TRUE; /* not something we affect, but no error */

    priv = priv_from_js(context, obj);

    if (priv == NULL) {
        g_free(name);
        return JS_FALSE; /* wrong class */
    }

    success = JS_FALSE;
    pspec = priv->gparam;

    gtype = G_TYPE_FROM_INSTANCE(pspec);
    info = (GIObjectInfo*)g_irepository_find_by_gtype(g_irepository_get_default(), gtype);

    if (info == NULL) {
        /* We may have a non-introspectable GParamSpec subclass here. Just return VOID. */
        *value_p = JSVAL_VOID;
        success = JS_TRUE;
        goto out;
    }

    parent_info = g_object_info_get_parent(info);

    field_info = find_field_info(info, name);

    if (field_info == NULL) {
        /* Try it on the parent GParamSpec for generic GParamSpec properties. */
        field_info = find_field_info(parent_info, name);
    }

    if (field_info == NULL) {
        *value_p = JSVAL_VOID;
        success = JS_TRUE;
        goto out;
    }

    type_info = g_field_info_get_type(field_info);

    if (!g_field_info_get_field(field_info, priv->gparam, &arg)) {
        gjs_throw(context, "Reading field %s.%s is not supported",
                  g_base_info_get_name(info),
                  g_base_info_get_name((GIBaseInfo*)field_info));
        goto out;
    }

    if (!gjs_value_from_g_argument(context, value_p, type_info, &arg, TRUE))
        goto out;

    success = JS_TRUE;

 out:
    if (field_info != NULL)
        g_base_info_unref((GIBaseInfo*)field_info);
    if (type_info != NULL)
        g_base_info_unref((GIBaseInfo*)type_info);
    if (info != NULL)
        g_base_info_unref((GIBaseInfo*)info);
    if (parent_info != NULL)
        g_base_info_unref((GIBaseInfo*)parent_info);
    g_free(name);

    return success;
}
Exemple #8
0
/* fromString() function implementation */
static JSBool
from_string_func(JSContext *context,
                 unsigned   argc,
                 jsval     *vp)
{
    JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
    ByteArrayInstance *priv;
    char *encoding;
    gboolean encoding_is_utf8;
    JSObject *obj;
    JSBool retval = JS_FALSE;

    obj = byte_array_new(context);
    if (obj == NULL)
        return JS_FALSE;

    JS_AddObjectRoot(context, &obj);

    priv = priv_from_js(context, obj);
    g_assert (priv != NULL);

    g_assert(argc > 0); /* because we specified min args 1 */

    priv->array = gjs_g_byte_array_new(0);

    if (!JSVAL_IS_STRING(argv[0])) {
        gjs_throw(context,
                  "byteArray.fromString() called with non-string as first arg");
        goto out;
    }

    if (argc > 1 &&
        JSVAL_IS_STRING(argv[1])) {
        if (!gjs_string_to_utf8(context, argv[1], &encoding))
            goto out;

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

    if (encoding_is_utf8) {
        /* optimization? avoids iconv overhead and runs
         * libmozjs hardwired utf16-to-utf8.
         */
        char *utf8 = NULL;
        if (!gjs_string_to_utf8(context,
                                argv[0],
                                &utf8))
            goto out;

        g_byte_array_set_size(priv->array, 0);
        g_byte_array_append(priv->array, (guint8*) utf8, strlen(utf8));
        g_free(utf8);
    } else {
        char *encoded;
        gsize bytes_written;
        GError *error;
        const jschar *u16_chars;
        gsize u16_len;

        u16_chars = JS_GetStringCharsAndLength(context, JSVAL_TO_STRING(argv[0]), &u16_len);
        if (u16_chars == NULL)
            goto out;

        error = NULL;
        encoded = g_convert((char*) u16_chars,
                            u16_len * 2,
                            encoding, /* to_encoding */
                            "UTF-16", /* from_encoding */
                            NULL, /* bytes read */
                            &bytes_written,
                            &error);
        g_free(encoding);
        if (encoded == NULL) {
            /* frees the GError */
            gjs_throw_g_error(context, error);
            goto out;
        }

        g_byte_array_set_size(priv->array, 0);
        g_byte_array_append(priv->array, (guint8*) encoded, bytes_written);

        g_free(encoded);
    }

    argv.rval().set(OBJECT_TO_JSVAL(obj));

    retval = JS_TRUE;
 out:
    JS_RemoveObjectRoot(context, &obj);
    return retval;
}
Exemple #9
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;
}
Exemple #10
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;
    }
}
Exemple #11
0
/*
 * Like JSResolveOp, but flags provide contextual information as follows:
 *
 *  JSRESOLVE_QUALIFIED   a qualified property id: obj.id or obj[id], not id
 *  JSRESOLVE_ASSIGNING   obj[id] is on the left-hand side of an assignment
 *  JSRESOLVE_DETECTING   'if (o.p)...' or similar detection opcode sequence
 *  JSRESOLVE_DECLARING   var, const, or boxed prolog declaration opcode
 *  JSRESOLVE_CLASSNAME   class name used when constructing
 *
 * The *objp out parameter, on success, should be null to indicate that id
 * was not resolved; and non-null, referring to obj or one of its prototypes,
 * if id was resolved.
 */
static JSBool
union_new_resolve(JSContext *context,
                  JS::HandleObject obj,
                  JS::HandleId id,
                  unsigned flags,
                  JS::MutableHandleObject objp)
{
    Union *priv;
    char *name;
    JSBool ret = JS_TRUE;

    if (!gjs_get_string_id(context, id, &name))
        return JS_TRUE; /* not resolved, but no error */

    priv = priv_from_js(context, obj);
    gjs_debug_jsprop(GJS_DEBUG_GBOXED, "Resolve prop '%s' hook obj %p priv %p", name, *obj, priv);

    if (priv == NULL) {
        ret = JS_FALSE; /* wrong class */
        goto out;
    }

    if (priv->gboxed == NULL) {
        /* We are the prototype, so look for methods and other class properties */
        GIFunctionInfo *method_info;

        method_info = g_union_info_find_method((GIUnionInfo*) priv->info,
                                               name);

        if (method_info != NULL) {
            JSObject *union_proto;
            const char *method_name;

#if GJS_VERBOSE_ENABLE_GI_USAGE
            _gjs_log_info_usage((GIBaseInfo*) method_info);
#endif
            if (g_function_info_get_flags (method_info) & GI_FUNCTION_IS_METHOD) {
                method_name = g_base_info_get_name( (GIBaseInfo*) method_info);

                gjs_debug(GJS_DEBUG_GBOXED,
                          "Defining method %s in prototype for %s.%s",
                          method_name,
                          g_base_info_get_namespace( (GIBaseInfo*) priv->info),
                          g_base_info_get_name( (GIBaseInfo*) priv->info));

                union_proto = obj;

                if (gjs_define_function(context, union_proto,
                                        g_registered_type_info_get_g_type(priv->info),
                                        method_info) == NULL) {
                    g_base_info_unref( (GIBaseInfo*) method_info);
                    ret = JS_FALSE;
                    goto out;
                }

                objp.set(union_proto); /* we defined the prop in object_proto */
            }

            g_base_info_unref( (GIBaseInfo*) method_info);
        }
    } else {
        /* We are an instance, not a prototype, so look for
         * per-instance props that we want to define on the
         * JSObject. Generally we do not want to cache these in JS, we
         * want to always pull them from the C object, or JS would not
         * see any changes made from C. So we use the get/set prop
         * hooks, not this resolve hook.
         */
    }

 out:
    g_free(name);
    return ret;
}
Exemple #12
0
JSObject*
gjs_keep_alive_new(JSContext *context)
{
    KeepAlive *priv;
    JSObject *keep_alive = NULL;
    JSObject *global;
    JSBool found;

    /* This function creates an unattached KeepAlive object; following our
     * general strategy, we have a single KeepAlive class with a constructor
     * stored on our single "load global" pseudo-global object, and we create
     * instances with the load global as parent.
     */

    g_assert(context != NULL);

    JS_BeginRequest(context);

    global = gjs_get_import_global(context);

    g_assert(global != NULL);

    if (!JS_HasProperty(context, global, gjs_keep_alive_class.name, &found))
        goto out;

    if (!found) {
        JSObject *prototype;

        gjs_debug(GJS_DEBUG_KEEP_ALIVE,
                  "Initializing keep-alive class in context %p global %p",
                  context, global);

        prototype = JS_InitClass(context, global,
                                 /* parent prototype JSObject* for
                                  * prototype; NULL for
                                  * Object.prototype
                                  */
                                 NULL,
                                 &gjs_keep_alive_class,
                                 /* constructor for instances (NULL for
                                  * none - just name the prototype like
                                  * Math - rarely correct)
                                  */
                                 gjs_keep_alive_constructor,
                                 /* number of constructor args */
                                 0,
                                 /* props of prototype */
                                 &gjs_keep_alive_proto_props[0],
                                 /* funcs of prototype */
                                 &gjs_keep_alive_proto_funcs[0],
                                 /* props of constructor, MyConstructor.myprop */
                                 NULL,
                                 /* funcs of constructor, MyConstructor.myfunc() */
                                 NULL);
        if (prototype == NULL)
            g_error("Can't init class %s", gjs_keep_alive_class.name);

        gjs_debug(GJS_DEBUG_KEEP_ALIVE, "Initialized class %s prototype %p",
                  gjs_keep_alive_class.name, prototype);
    }

    gjs_debug(GJS_DEBUG_KEEP_ALIVE,
              "Creating new keep-alive object for context %p global %p",
              context, global);

    keep_alive = JS_NewObject(context, &gjs_keep_alive_class, NULL, global);
    if (keep_alive == NULL) {
        gjs_log_exception(context);
        g_error("Failed to create keep_alive object");
    }

    priv = g_slice_new0(KeepAlive);
    priv->children = g_hash_table_new_full(child_hash, child_equal, NULL, child_free);

    g_assert(priv_from_js(context, keep_alive) == NULL);
    JS_SetPrivate(keep_alive, priv);

    gjs_debug_lifecycle(GJS_DEBUG_KEEP_ALIVE,
                        "keep_alive constructor, obj %p priv %p", keep_alive, priv);

 out:
    JS_EndRequest(context);

    return keep_alive;
}
Exemple #13
0
/*
 * Like JSResolveOp, but flags provide contextual information as follows:
 *
 *  JSRESOLVE_QUALIFIED   a qualified property id: obj.id or obj[id], not id
 *  JSRESOLVE_ASSIGNING   obj[id] is on the left-hand side of an assignment
 *  JSRESOLVE_DETECTING   'if (o.p)...' or similar detection opcode sequence
 *  JSRESOLVE_DECLARING   var, const, or function prolog declaration opcode
 *  JSRESOLVE_CLASSNAME   class name used when constructing
 *
 * The *objp out parameter, on success, should be null to indicate that id
 * was not resolved; and non-null, referring to obj or one of its prototypes,
 * if id was resolved.
 */
static JSBool
ns_new_resolve(JSContext *context,
               JS::HandleObject obj,
               JS::HandleId id,
               unsigned flags,
               JS::MutableHandleObject objp)
{
    Ns *priv;
    char *name;
    GIRepository *repo;
    GIBaseInfo *info;
    JSBool ret = JS_FALSE;
    gboolean defined;

    if (!gjs_get_string_id(context, id, &name))
        return JS_TRUE; /* not resolved, but no error */

    /* let Object.prototype resolve these */
    if (strcmp(name, "valueOf") == 0 ||
        strcmp(name, "toString") == 0) {
        ret = JS_TRUE;
        goto out;
    }

    priv = priv_from_js(context, obj);
    gjs_debug_jsprop(GJS_DEBUG_GNAMESPACE, "Resolve prop '%s' hook obj %p priv %p", name, *obj, priv);

    if (priv == NULL) {
        ret = JS_TRUE; /* we are the prototype, or have the wrong class */
        goto out;
    }

    JS_BeginRequest(context);

    repo = g_irepository_get_default();

    info = g_irepository_find_by_name(repo, priv->gi_namespace, name);
    if (info == NULL) {
        /* No property defined, but no error either, so return TRUE */
        JS_EndRequest(context);
        ret = JS_TRUE;
        goto out;
    }

    gjs_debug(GJS_DEBUG_GNAMESPACE,
              "Found info type %s for '%s' in namespace '%s'",
              gjs_info_type_name(g_base_info_get_type(info)),
              g_base_info_get_name(info),
              g_base_info_get_namespace(info));

    if (gjs_define_info(context, obj, info, &defined)) {
        g_base_info_unref(info);
        if (defined)
            objp.set(obj); /* we defined the property in this object */
        ret = JS_TRUE;
    } else {
        gjs_debug(GJS_DEBUG_GNAMESPACE,
                  "Failed to define info '%s'",
                  g_base_info_get_name(info));

        g_base_info_unref(info);
    }
    JS_EndRequest(context);

 out:
    g_free(name);
    return ret;
}
Exemple #14
0
static JSObject*
ns_new(JSContext    *context,
       const char   *ns_name)
{
    JSObject *ns;
    JSObject *global;
    Ns *priv;
    JSBool found;

    /* put constructor in the global namespace */
    global = gjs_get_import_global(context);

    if (!JS_HasProperty(context, global, gjs_ns_class.name, &found))
        return NULL;
    if (!found) {
        JSObject *prototype;
        prototype = JS_InitClass(context, global,
                                 /* parent prototype JSObject* for
                                  * prototype; NULL for
                                  * Object.prototype
                                  */
                                 NULL,
                                 &gjs_ns_class,
                                 /* constructor for instances (NULL for
                                  * none - just name the prototype like
                                  * Math - rarely correct)
                                  */
                                 gjs_ns_constructor,
                                 /* number of constructor args */
                                 0,
                                 /* props of prototype */
                                 &gjs_ns_proto_props[0],
                                 /* funcs of prototype */
                                 &gjs_ns_proto_funcs[0],
                                 /* props of constructor, MyConstructor.myprop */
                                 NULL,
                                 /* funcs of constructor, MyConstructor.myfunc() */
                                 NULL);
        if (prototype == NULL)
            g_error("Can't init class %s", gjs_ns_class.name);

        gjs_debug(GJS_DEBUG_GNAMESPACE, "Initialized class %s prototype %p",
                  gjs_ns_class.name, prototype);
    }

    ns = JS_NewObject(context, &gjs_ns_class, NULL, global);
    if (ns == NULL)
        g_error("No memory to create ns object");

    priv = g_slice_new0(Ns);

    GJS_INC_COUNTER(ns);

    g_assert(priv_from_js(context, ns) == NULL);
    JS_SetPrivate(ns, priv);

    gjs_debug_lifecycle(GJS_DEBUG_GNAMESPACE, "ns constructor, obj %p priv %p", ns, priv);

    priv = priv_from_js(context, ns);
    priv->gi_namespace = g_strdup(ns_name);
    return ns;
}