]> git.draconx.ca Git - upkg.git/commitdiff
Reorganize object hierarchy to root at "UObject".
authorNick Bowler <nbowler@draconx.ca>
Wed, 10 Jun 2009 22:42:40 +0000 (18:42 -0400)
committerNick Bowler <nbowler@draconx.ca>
Wed, 10 Jun 2009 22:42:40 +0000 (18:42 -0400)
Contrary to past belief, _every_ object serialization has a common header.
This removes the need for a specific serializable interface.

src/Makefile.am
src/engine/music.c
src/engine/music.h
src/exportable.c
src/exportable.h
src/module.c
src/serializable.c [deleted file]
src/serializable.h [deleted file]
src/uobject.c [new file with mode: 0644]
src/uobject.h [new file with mode: 0644]
src/upkg.c

index e244fbdbae24b717a734bae08d9f59d198939880..8bc2f18b868aee5101558a901233f87763f41111 100644 (file)
@@ -2,16 +2,16 @@ lib_LTLIBRARIES = libupkg.la
 
 libupkg_la_SOURCES = libupkg.c pack.c
 include_HEADERS = upkg.h
-noinst_HEADERS = pack.h serializable.h exportable.h module.h avl.h
+noinst_HEADERS = pack.h exportable.h module.h avl.h
 
 if BUILD_UPKG
 
 include engine/Makefile.inc
 
 bin_PROGRAMS  = upkg
-upkg_SOURCES  = upkg.c avl.c module.c exportable.c serializable.c
+upkg_SOURCES  = upkg.c avl.c module.c exportable.c uobject.c
 upkg_CPPFLAGS = $(GLIB_CFLAGS) $(LTDLINCL)
-upkg_LDFLAGS  = $(GLIB_LIBS) -export-dynamic
-upkg_LDADD    = libupkg.la $(LIBLTDL)
+upkg_LDFLAGS  = -export-dynamic
+upkg_LDADD    = libupkg.la $(LIBLTDL) $(GLIB_LIBS)
 
 endif
index f095c46a8f54bc550ef19e24e20551bae95150ee..7d57bdb9401b3bb36d6e4c10261ecbc1bad8d218 100644 (file)
@@ -2,8 +2,8 @@
 #include <string.h>
 #include <glib-object.h>
 
-#include "serializable.h"
 #include "exportable.h"
+#include "uobject.h"
 #include "music.h"
 #include "upkg.h"
 
@@ -20,6 +20,12 @@ struct music_priv {
        unsigned long nbuf;
 };
 
+static void exportable_init(UObjectExportable *);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED(EngineMusic, engine_music, U_OBJECT_TYPE, 0,
+       G_IMPLEMENT_INTERFACE(U_OBJECT_TYPE_EXPORTABLE, exportable_init)
+);
+
 static int export(GObject *o, FILE *f)
 {
        struct music_priv *priv = MUSIC_GET_PRIV(o);
@@ -51,13 +57,13 @@ static int export_name(GObject *o, char *buf, size_t n)
        return snprintf(buf, n, "%s", priv->f ? priv->f->name : "");
 }
 
-static void exportable_init(UPkgExportable *e)
+static void exportable_init(UObjectExportable *e)
 {
        e->export      = export;
        e->export_name = export_name;
 }
 
-static int deserialize(GObject *o, struct upkg_file *f)
+static int deserialize(UObject *o, struct upkg_file *f)
 {
        struct music_priv *priv = MUSIC_GET_PRIV(o);
        EngineMusic *m = ENGINE_MUSIC(o);
@@ -65,14 +71,16 @@ static int deserialize(GObject *o, struct upkg_file *f)
 
        size_t rc;
 
+       U_OBJECT_CLASS(engine_music_parent_class)->deserialize(o, f);
+
        priv->nbuf = upkg_export_read(f, priv->buf, sizeof priv->buf);
        priv->base = 0;
 
        /* Random field #1 */
-       if (priv->nbuf - priv->base < 2)
+       if (priv->nbuf - priv->base < 1)
                return -1;
        // unpack_16_le(priv->buf+0);
-       priv->base += 2;
+       priv->base += 1;
 
        if (f->pkg->version > 61) {
                /* Random field #2 */
@@ -96,9 +104,9 @@ static int deserialize(GObject *o, struct upkg_file *f)
        return 0;
 }
 
-static void serializable_init(UPkgSerializable *s)
+void music_register(GTypeModule *m)
 {
-       s->deserialize = deserialize;
+       engine_music_register_type(m);
 }
 
 static void engine_music_init(EngineMusic *m)
@@ -107,19 +115,13 @@ static void engine_music_init(EngineMusic *m)
 
 static void engine_music_class_init(EngineMusicClass *class)
 {
+       UObjectClass *uo = U_OBJECT_CLASS(class);
+
        g_type_class_add_private(class, sizeof (struct music_priv));
-}
 
-static void engine_music_class_finalize(EngineMusicClass *class)
-{
+       uo->deserialize = deserialize;
 }
 
-G_DEFINE_DYNAMIC_TYPE_EXTENDED(EngineMusic, engine_music, G_TYPE_OBJECT, 0,
-       G_IMPLEMENT_INTERFACE(UPKG_TYPE_SERIALIZABLE, serializable_init)
-       G_IMPLEMENT_INTERFACE(UPKG_TYPE_EXPORTABLE, exportable_init)
-);
-
-void music_register(GTypeModule *m)
+static void engine_music_class_finalize(EngineMusicClass *class)
 {
-       engine_music_register_type(m);
 }
index 92de5f852ac541a2d647a0d96ff7ee15ed73d36c..24f2a0c328f0d55fd5393c98ec2937757db6f6b3 100644 (file)
@@ -2,6 +2,7 @@
 #define MUSIC_H_
 
 #include <glib-object.h>
+#include "uobject.h"
 
 #define ENGINE_MUSIC_TYPE (engine_music_get_type())
 #define ENGINE_MUSIC(obj) \
@@ -17,11 +18,11 @@ typedef struct EngineMusic      EngineMusic;
 typedef struct EngineMusicClass EngineMusicClass;
 
 struct EngineMusic {
-       GObject parent;
+       UObject parent;
 };
 
 struct EngineMusicClass {
-       GObjectClass parent;
+       UObjectClass parent;
 };
 
 GType engine_music_get_type(void);
index 8947fcc44d005b83f580b1ef0b1efa88fe829918..c22a448bf97e6970512394f1877282b490733a45 100644 (file)
@@ -2,30 +2,30 @@
 #include <glib-object.h>
 #include "exportable.h"
 
-GType upkg_exportable_get_type(void)
+GType u_object_exportable_get_type(void)
 {
        static GType type = 0;
        if (type == 0) {
                static const GTypeInfo info = {
-                       sizeof (UPkgExportable),
+                       sizeof (UObjectExportable),
                        NULL,
                        NULL,
                };
 
                type = g_type_register_static(G_TYPE_INTERFACE,
-                       "UPkgExportable", &info, 0);
+                       "UObjectExportable", &info, 0);
        }
        return type;
 }
 
-int upkg_export(GObject *obj, FILE *f)
+int u_object_export(GObject *obj, FILE *f)
 {
-       g_return_val_if_fail(UPKG_IS_EXPORTABLE(obj), -1);
-       return UPKG_EXPORTABLE_GET_INTERFACE(obj)->export(obj, f);
+       g_return_val_if_fail(U_OBJECT_IS_EXPORTABLE(obj), -1);
+       return U_OBJECT_EXPORTABLE_GET_INTERFACE(obj)->export(obj, f);
 }
 
-int upkg_export_name(GObject *obj, char *buf, size_t n)
+int u_object_export_name(GObject *obj, char *buf, size_t n)
 {
-       g_return_val_if_fail(UPKG_IS_EXPORTABLE(obj), -1);
-       return UPKG_EXPORTABLE_GET_INTERFACE(obj)->export_name(obj, buf, n);
+       g_return_val_if_fail(U_OBJECT_IS_EXPORTABLE(obj), -1);
+       return U_OBJECT_EXPORTABLE_GET_INTERFACE(obj)->export_name(obj, buf, n);
 }
index 9fe07e9f359a274c555ad2001652bf87523b4565..623099e2dd26891bc0e96491fcf999196c7032e0 100644 (file)
@@ -4,26 +4,26 @@
 #include <stdio.h>
 #include <glib-object.h>
 
-#define UPKG_TYPE_EXPORTABLE (upkg_exportable_get_type())
-#define UPKG_EXPORTABLE(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, \
-       UPKG_TYPE_EXPORTABLE, UPkgExportable)
-#define UPKG_IS_EXPORTABLE(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, \
-       UPKG_TYPE_EXPORTABLE)
-#define UPKG_EXPORTABLE_GET_INTERFACE(inst) G_TYPE_INSTANCE_GET_INTERFACE \
-       (inst, UPKG_TYPE_EXPORTABLE, UPkgExportable)
+#define U_OBJECT_TYPE_EXPORTABLE (u_object_exportable_get_type())
+#define U_OBJECT_EXPORTABLE(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, \
+       U_OBJECT_TYPE_EXPORTABLE, UObjectExportable)
+#define U_OBJECT_IS_EXPORTABLE(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, \
+       U_OBJECT_TYPE_EXPORTABLE)
+#define U_OBJECT_EXPORTABLE_GET_INTERFACE(inst) G_TYPE_INSTANCE_GET_INTERFACE \
+       (inst, U_OBJECT_TYPE_EXPORTABLE, UObjectExportable)
 
-typedef struct UPkgExportable UPkgExportable;
+typedef struct UObjectExportable UObjectExportable;
 
-struct UPkgExportable {
+struct UObjectExportable {
        GTypeInterface parent;
 
        int (*export)(GObject *obj, FILE *f);
        int (*export_name)(GObject *obj, char *buf, size_t n);
 };
 
-GType upkg_exportable_get_type(void);
+GType u_object_exportable_get_type(void);
 
-int upkg_export(GObject *obj, FILE *f);
-int upkg_export_name(GObject *obj, char *buf, size_t n);
+int u_object_export(GObject *obj, FILE *f);
+int u_object_export_name(GObject *obj, char *buf, size_t n);
 
 #endif
index 025d600b9668bb13674cf993f07ca3e00c880e6f..24ef2508bbbf919fc729bff01e7edb141cf05e6e 100644 (file)
@@ -109,7 +109,7 @@ static int modcmp(const void *a, const void *b, void *_data)
 int module_init(void)
 {
        if (!initialized) {
-               package_tree = avl_create(modcmp, 0, &avl_allocator_default);
+               package_tree = avl_create(modcmp, NULL, NULL);
                if (!package_tree) {
                        fprintf(stderr, "%s: failed to create package tree.\n", __func__);
                        return -1;
diff --git a/src/serializable.c b/src/serializable.c
deleted file mode 100644 (file)
index fdc2cc5..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#include <glib-object.h>
-#include "serializable.h"
-#include "upkg.h"
-
-GType upkg_serializable_get_type(void)
-{
-       static GType type = 0;
-       if (type == 0) {
-               static const GTypeInfo info = {
-                       sizeof (UPkgSerializable),
-                       NULL,
-                       NULL,
-               };
-
-               type = g_type_register_static(G_TYPE_INTERFACE,
-                       "UPkgSerializable", &info, 0);
-       }
-       return type;
-}
-
-int upkg_deserialize(GObject *obj, struct upkg_file *f)
-{
-       g_return_val_if_fail(UPKG_IS_SERIALIZABLE(obj), -1);
-       return UPKG_SERIALIZABLE_GET_INTERFACE(obj)->deserialize(obj, f);
-}
diff --git a/src/serializable.h b/src/serializable.h
deleted file mode 100644 (file)
index 5d83d57..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef SERIALIZABLE_H_
-#define SERIALIZABLE_H_
-
-#include <glib-object.h>
-#include "upkg.h"
-
-#define UPKG_TYPE_SERIALIZABLE (upkg_serializable_get_type())
-#define UPKG_SERIALIZABLE(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, \
-       UPKG_TYPE_SERIALIZABLE, UPkgSerializable)
-#define UPKG_IS_SERIALIZABLE(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, \
-       UPKG_TYPE_SERIALIZABLE)
-#define UPKG_SERIALIZABLE_GET_INTERFACE(inst) G_TYPE_INSTANCE_GET_INTERFACE \
-       (inst, UPKG_TYPE_SERIALIZABLE, UPkgSerializable)
-
-typedef struct UPkgSerializable UPkgSerializable;
-
-struct UPkgSerializable {
-       GTypeInterface parent;
-
-       int (*deserialize)(GObject *obj, struct upkg_file *f);
-};
-
-GType upkg_serializable_get_type(void);
-int upkg_deserialize(GObject *obj, struct upkg_file *f);
-
-#endif
diff --git a/src/uobject.c b/src/uobject.c
new file mode 100644 (file)
index 0000000..7dedc08
--- /dev/null
@@ -0,0 +1,268 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <glib-object.h>
+
+#include "uobject.h"
+#include "upkg.h"
+#include "pack.h"
+#include "avl.h"
+
+#define U_OBJECT_GET_PRIV(o) \
+       G_TYPE_INSTANCE_GET_PRIVATE(o, U_OBJECT_TYPE, struct uobject_priv)
+
+enum {
+       PROPERTY_BYTE = 1,
+       PROPERTY_INTEGER,
+       PROPERTY_BOOLEAN,
+       PROPERTY_FLOAT,
+       PROPERTY_OBJECT,
+       PROPERTY_NAME,
+       PROPERTY_STRING,
+       PROPERTY_CLASS,
+       PROPERTY_ARRAY,
+       PROPERTY_STRUCT,
+       PROPERTY_VECTOR,
+       PROPERTY_ROTATOR,
+       PROPERTY_STR,
+       PROPERTY_MAP,
+       PROPERTY_FIXEDARRAY,
+};
+
+struct uobject_property {
+       const char *name;
+       GValue val;
+};
+
+struct uobject_priv {
+       struct upkg_file *f;
+       size_t base, len;
+
+       struct avl_table *properties;
+
+       unsigned char buf[2048];
+       unsigned long nbuf;
+};
+
+/* AVL tree functions. */
+static int propcmp(const void *_a, const void *_b, void *_data)
+{
+       const struct uobject_property *a = _a, *b = _b;
+       return strcmp(a->name, b->name);
+}
+
+static void propfree(void *item, void *data)
+{
+       free(item);
+}
+
+static unsigned long
+get_real_size(unsigned long *real, unsigned size, unsigned char *buf, size_t n)
+{
+       assert(size < 8);
+
+       *real = 0;
+       switch (size) {
+       case 0: *real =  1; return 0;
+       case 1: *real =  2; return 0;
+       case 2: *real =  4; return 0;
+       case 3: *real = 12; return 0;
+       case 4: *real = 16; return 0;
+       case 5:
+               if (n < 1) return 0;
+               *real = *buf;
+               return 1;
+       case 6:
+               if (n < 2) return 0;
+               *real = unpack_16_le(buf);
+               return 2;
+       case 7:
+               if (n < 4) return 0;
+               *real = unpack_32_le(buf);
+               return 4;
+       }
+
+       return 0;
+}
+
+static unsigned long
+decode_property(UObject *o, const char *name, struct upkg_file *f, unsigned long len)
+{
+       struct uobject_priv *priv = U_OBJECT_GET_PRIV(o);
+       unsigned long real_size, rc;
+       int type, size, top;
+       GValue val = {0};
+
+       if (priv->nbuf-len < 1)
+               return 0;
+       
+       type = (priv->buf[len] >> 0) & 0x0f;
+       size = (priv->buf[len] >> 4) & 0x07;
+       top  = (priv->buf[len] >> 7) & 0x01;
+       len += 1;
+
+       rc = get_real_size(&real_size, size, priv->buf, priv->nbuf-len);
+       if (real_size == 0)
+               return 0;
+       len += rc;
+
+       switch (type) {
+       case PROPERTY_BYTE:
+               if (priv->nbuf-len < 1)
+                       return 0;
+               g_value_init(&val, G_TYPE_UCHAR);
+               g_value_set_uchar(&val, priv->buf[len]);
+               u_object_set_property(o, name, &val);
+               break;
+       case PROPERTY_INTEGER:
+               if (priv->nbuf-len < 4)
+                       return 0;
+               g_value_init(&val, G_TYPE_ULONG);
+               g_value_set_ulong(&val, unpack_32_le(priv->buf+len));
+               u_object_set_property(o, name, &val);
+               break;
+       default:
+               fprintf(stderr, "Unhandled property type %x\n", (unsigned)type);
+       }
+
+       real_size += len;
+       if (real_size + len <= priv->nbuf) {
+               priv->nbuf -= real_size;
+               memmove(priv->buf, priv->buf+real_size, priv->nbuf);
+       } else {
+               long skip = real_size - priv->nbuf;
+               if (upkg_export_seek(f, skip, SEEK_CUR) != 0)
+                       return 0;
+               priv->nbuf = 0;
+       }
+
+       return real_size;
+}
+
+/* Deserialize properties from an Unreal package. */
+static int deserialize(UObject *o, struct upkg_file *f)
+{
+       struct uobject_priv *priv = U_OBJECT_GET_PRIV(o);
+       unsigned long rc, tot_len = 0;
+
+       while (1) {
+               unsigned long len = 0;
+               const char *name;
+               long tmp;
+
+               /* Read some data into buffer. */
+               if (!f->eof) {
+                       void  *buf = priv->buf + priv->nbuf;
+                       size_t amt = sizeof priv->buf - priv->nbuf;
+                       rc = upkg_export_read(f, buf, amt);
+                       if (rc == 0)
+                               return -1;
+                       priv->nbuf += rc;
+               }
+
+               /* Get the property name. */
+               rc = upkg_decode_index(&tmp, priv->buf+len, priv->nbuf-len);
+               if (rc == 0)
+                       return -1;
+               len += rc;
+
+               name = upkg_get_name(f->pkg, tmp);
+               if (!name) {
+                       return -1;
+               } else if (strcmp(name, "None") == 0) {
+                       tot_len += rc;
+                       break;
+               }
+
+               rc = decode_property(U_OBJECT(o), name, f, len);
+               if (rc == 0)
+                       return -1;
+               len += rc;
+
+               tot_len += len;
+       }
+
+       f->base += tot_len;
+       f->len  -= tot_len;
+       upkg_export_seek(f, 0, SEEK_SET);
+
+       return 0;
+}
+
+int u_object_deserialize(GObject *obj, struct upkg_file *f)
+{
+       g_return_val_if_fail(IS_U_OBJECT(obj), -1);
+       U_OBJECT_GET_CLASS(obj)->deserialize(obj, f);
+}
+
+static void u_object_init(UObject *o)
+{
+       struct uobject_priv *priv = U_OBJECT_GET_PRIV(o);
+       priv->properties = NULL;
+}
+
+void u_object_set_property(UObject *o, const char *name, const GValue *val)
+{
+       struct uobject_priv *priv = U_OBJECT_GET_PRIV(o);
+       struct uobject_property *prop, search = { .name = name };
+       void **p;
+
+       if (!priv->properties) {
+               priv->properties = avl_create(propcmp, NULL, NULL);
+               g_return_if_fail(priv->properties != NULL);
+       }
+
+       prop = avl_find(priv->properties, &search);
+       if (prop) {
+               g_value_unset(&prop->val);
+               g_value_init(&prop->val, G_VALUE_TYPE(val));
+               g_value_copy(val, &prop->val);
+               return;
+       }
+
+       prop = malloc(sizeof *prop);
+       g_return_if_fail(prop != NULL);
+
+       *prop = (struct uobject_property) { .name = name };
+       g_value_init(&prop->val, G_VALUE_TYPE(val));
+       g_value_copy(val, &prop->val);
+
+       g_return_if_fail(avl_probe(priv->properties, &prop) != NULL);
+}
+
+const GValue *u_object_get_property(UObject *o, const char *name)
+{
+       struct uobject_priv *priv = U_OBJECT_GET_PRIV(o);
+       struct uobject_property *prop, search = { .name = name };
+
+       if (!priv->properties)
+               return NULL;
+
+       prop = avl_find(priv->properties, &search);
+       if (!prop)
+               return NULL;
+       return &prop->val;
+}
+
+static void u_object_finalize(GObject *o)
+{
+       struct uobject_priv *priv = U_OBJECT_GET_PRIV(o);
+
+       if (priv->properties) {
+               avl_destroy(priv->properties, propfree);
+               priv->properties = NULL;
+       }
+}
+
+static void u_object_class_init(UObjectClass *class)
+{
+       GObjectClass *go = G_OBJECT_CLASS(class);
+
+       class->deserialize = deserialize;
+
+       g_type_class_add_private(class, sizeof (struct uobject_priv));
+       go->finalize = u_object_finalize;
+}
+
+G_DEFINE_TYPE(UObject, u_object, G_TYPE_OBJECT);
diff --git a/src/uobject.h b/src/uobject.h
new file mode 100644 (file)
index 0000000..63d8be2
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef UOBJECT_H_
+#define UOBJECT_H_
+
+#include <glib-object.h>
+#include "upkg.h"
+#include "avl.h"
+
+#define U_OBJECT_TYPE u_object_get_type()
+#define U_OBJECT(obj) \
+       G_TYPE_CHECK_INSTANCE_CAST(obj, U_OBJECT_TYPE, UObject)
+#define U_OBJECT_CLASS(class) \
+       G_TYPE_CHECK_CLASS_CAST(class, U_OBJECT_TYPE, UObjectClass)
+#define IS_U_OBJECT(obj) \
+       G_TYPE_CHECK_INSTANCE_TYPE(obj, U_OBJECT_TYPE)
+#define IS_U_OBJECT_CLASS(class) \
+       G_TYPE_CHECK_CLASS_TYPE(class, U_OBJECT_TYPE, UObjectClass)
+#define U_OBJECT_GET_CLASS(obj) \
+       G_TYPE_INSTANCE_GET_CLASS(obj, U_OBJECT_TYPE, UObjectClass)
+
+typedef struct UObject      UObject;
+typedef struct UObjectClass UObjectClass;
+
+struct UObject {
+       GObject parent;
+};
+
+struct UObjectClass {
+       GObjectClass parent;
+
+       int (*deserialize)(UObject *obj, struct upkg_file *f);
+};
+
+GType u_object_get_type(void);
+
+const GValue *u_object_get_property(UObject *obj, const char *name);
+void u_object_set_property(UObject *obj, const char *name, const GValue *val);
+
+int u_object_deserialize(GObject *obj, struct upkg_file *f);
+
+#endif
index c40d6d14c3f69eefb51e7508d527f850a7dee003..8c26d27152ea489cf905d2011712ca206456706c 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "upkg.h"
 #include "module.h"
-#include "serializable.h"
+#include "uobject.h"
 #include "exportable.h"
 
 void print_upkg_flags(const char *prefix, unsigned long flags)
@@ -91,13 +91,13 @@ int main(int argc, char **argv)
        if (!music)
                return EXIT_FAILURE;
        struct upkg_file *f = upkg_export_open(pkg, 0);
-       upkg_deserialize(music, f);
+       u_object_deserialize(music, f);
 
        char name[256];
-       upkg_export_name(music, name, sizeof name);
+       u_object_export_name(music, name, sizeof name);
        FILE *fp = fopen(name, "wb");
        if (!fp) return EXIT_FAILURE;
-       upkg_export(music, fp);
+       u_object_export(music, fp);
        fclose(fp);
        printf("Wrote %s\n", name);