]> git.draconx.ca Git - upkg.git/blobdiff - src/uobject/uobject.c
uobject: Initial support for object imports.
[upkg.git] / src / uobject / uobject.c
index b8c24796dafd601c7669482c0d78338f6ffd317f..74734dd1bfd0c73758fe73698c66b66aca0ff292 100644 (file)
@@ -190,6 +190,93 @@ decode_prop_header(struct upkg *upkg, struct prop_head *head,
        return len;
 }
 
+/*
+ * TODO: Make this use the uobject_module stuff so packages are not loaded
+ * more than once.
+ */
+static GTypeModule *
+open_import_package(UObject *uo, const struct upkg_import *i)
+{
+       GTypeModule *pkg;
+
+       assert(i->parent == NULL);
+
+       if (strcmp(i->class_package, "Core") != 0
+           || strcmp(i->class_name, "Package") != 0) {
+               u_err(uo, "import root must be Core.Package");
+               return NULL;
+       }
+
+       pkg = u_pkg_open(i->name);
+       if (!pkg || !g_type_module_use(pkg)) {
+               u_err(uo, "failed to open package: %s", i->name);
+               return NULL;
+       }
+
+       if (!U_PKG(pkg)->pkg) {
+               g_type_module_unuse(pkg);
+               u_err(uo, "failed to open package: %s", pkg->name);
+               return NULL;
+       }
+
+       return pkg;
+}
+
+/* Find the export index of a package based on the import chain from another
+ * package.  Returns the (non-negative) offset on success, or a negative value
+ * on failure. */
+static long resolve_import(struct upkg *pkg, const struct upkg_import *import)
+{
+       long current, index;
+
+       if (!import->parent)
+               return -1;
+
+       current = resolve_import(pkg, import->parent);
+       if (current != -1 && current >= 0)
+               return -42;
+
+       index = upkg_export_find(pkg, current, import->name);
+       if (index < 0)
+               return -42;
+
+       return index;
+}
+
+static GObject *get_import_object(UObject *uo, unsigned long index)
+{
+       const struct upkg_import *import;
+       GObject *obj = NULL;
+       GTypeModule *pkg;
+       long obj_index;
+
+       import = upkg_get_import(uo->pkg_file->pkg, index);
+       if (!import) {
+               u_err(uo, "invalid package import: %ld", index);
+               return NULL;
+       }
+
+       /* Get the package name at the top of the hierarchy. */
+       for (const struct upkg_import *i = import; i; i = i->parent) {
+               if (i->parent == NULL) {
+                       pkg = open_import_package(uo, i);
+                       if (!pkg)
+                               return NULL;
+               }
+       }
+
+       obj_index = resolve_import(U_PKG(pkg)->pkg, import);
+       if (obj_index < 0) {
+               u_err(uo, "could not find import in package: %s", pkg->name);
+               goto out;
+       }
+
+       obj = u_object_new_from_package(pkg, obj_index);
+out:
+       g_type_module_unuse(pkg);
+       return obj;
+}
+
 static int decode_object_property(UObject *uo, GValue *val, unsigned long len)
 {
        struct u_object_priv *priv = U_OBJECT_GET_PRIV(uo);
@@ -202,7 +289,7 @@ static int decode_object_property(UObject *uo, GValue *val, unsigned long len)
                return -1;
 
        if (index < 0) {
-               fprintf(stderr, "Imports not supported yet.\n");
+               obj = get_import_object(uo, -(index+1));
        } else {
                obj = u_object_new_from_package(uo->pkg, index-1);
        }
@@ -392,7 +479,6 @@ GObject *u_object_new_from_package(GTypeModule *pkg, unsigned long idx)
 {
        g_return_val_if_fail(IS_U_PKG(pkg), NULL);
 
-       const struct upkg_export *export;
        const char *class, *package;
        GObject *obj = NULL;
        GType type;