]> git.draconx.ca Git - upkg.git/blobdiff - src/engine/music.c
uobject: Implement an interface for loading/unloading.
[upkg.git] / src / engine / music.c
index f095c46a8f54bc550ef19e24e20551bae95150ee..f770662995e8f63e2ea359117b005850783b7fc6 100644 (file)
@@ -2,8 +2,9 @@
 #include <string.h>
 #include <glib-object.h>
 
-#include "serializable.h"
 #include "exportable.h"
+#include "loadable.h"
+#include "uobject.h"
 #include "music.h"
 #include "upkg.h"
 
        G_TYPE_INSTANCE_GET_PRIVATE(o, ENGINE_MUSIC_TYPE, struct music_priv)
 
 struct music_priv {
-       unsigned type;
-
        struct upkg_file *f;
-       size_t base, len;
-
-       unsigned char buf[2048];
-       unsigned long nbuf;
+       unsigned loaded;
 };
 
-static int export(GObject *o, FILE *f)
+static void exportable_init(UObjectExportable *);
+static void loadable_init(UObjectLoadable *);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED(EngineMusic, engine_music, U_OBJECT_TYPE, 0,
+       G_IMPLEMENT_INTERFACE(U_OBJECT_TYPE_EXPORTABLE, exportable_init)
+       G_IMPLEMENT_INTERFACE(U_OBJECT_TYPE_LOADABLE, loadable_init)
+);
+
+static int load(GObject *o)
 {
        struct music_priv *priv = MUSIC_GET_PRIV(o);
-       size_t left = priv->len, rc;
 
-       unsigned char buf[1024];
+       if (!priv->loaded) {
+               g_return_val_if_fail(priv->f != NULL, -1);
 
-       if (!priv->f)
-               return -1;
+               if (upkg_export_seek(priv->f, 0, SEEK_SET) != 0) {
+                       return -1;
+               }
+       }
+
+       priv->loaded++;
+       return 0;
+}
+
+static void unload(GObject *o)
+{
+       struct music_priv *priv = MUSIC_GET_PRIV(o);
+       g_return_if_fail(priv->loaded > 0);
+
+       --priv->loaded;
+}
+
+static int export(GObject *o, FILE *f)
+{
+       struct music_priv *priv = MUSIC_GET_PRIV(o);
+       unsigned char buf[1024];
 
-       if (upkg_export_seek(priv->f, priv->base, SEEK_SET) != 0)
+       if (!priv->f || upkg_export_seek(priv->f, 0, SEEK_SET) != 0)
                return -1;
 
-       while (left > 0) {
-               rc = upkg_export_read(priv->f, buf, MIN(left, sizeof buf));
-               if (rc == 0)
+       while (!priv->f->eof) {
+               size_t rc = upkg_export_read(priv->f, buf, sizeof buf);
+               if (rc == 0) {
+                       if (priv->f->eof) break;
                        return -1;
+               }
+
                if (fwrite(buf, 1, rc, f) != rc)
                        return -1;
-               left -= rc;
        }
 
        return 0;
@@ -51,75 +76,87 @@ 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 void loadable_init(UObjectLoadable *l)
+{
+       l->load   = load;
+       l->unload = unload;
+}
+
+static int deserialize(UObject *o, struct upkg_file *f)
 {
        struct music_priv *priv = MUSIC_GET_PRIV(o);
        EngineMusic *m = ENGINE_MUSIC(o);
+       size_t rc, pos = 0, buflen;
+       unsigned char buf[32];
        long size;
 
-       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;
+       buflen = upkg_export_read(f, buf, sizeof buf);
 
        /* Random field #1 */
-       if (priv->nbuf - priv->base < 2)
+       if (buflen - pos < 1)
                return -1;
-       // unpack_16_le(priv->buf+0);
-       priv->base += 2;
+       pos += 1;
 
        if (f->pkg->version > 61) {
                /* Random field #2 */
-               if (priv->nbuf - priv->base < 4)
+               if (buflen - pos < 4)
                        return -1;
-               // unpack_32_le(priv->buf+2);
-               priv->base += 4;
+               pos += 4;
        }
 
-       rc = upkg_decode_index(&size, priv->buf+priv->base, priv->nbuf-priv->base);
+       rc = upkg_decode_index(&size, buf+pos, buflen-pos);
        if (rc == 0 || size < 0)
                return -1;
+       pos += rc;
 
-       priv->base += rc;
-       priv->len   = size;
-
-       priv->nbuf -= priv->base;
-       memmove(priv->buf, priv->buf+priv->base, priv->nbuf);
+       f->base += pos;
+       f->len   = size;
+       upkg_export_seek(f, 0, SEEK_SET);
 
        priv->f = 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)
 {
+       struct music_priv *priv = MUSIC_GET_PRIV(m);
+       *priv = (struct music_priv){0};
 }
 
-static void engine_music_class_init(EngineMusicClass *class)
+static void engine_music_finalize(GObject *o)
 {
-       g_type_class_add_private(class, sizeof (struct music_priv));
+       struct music_priv *priv = MUSIC_GET_PRIV(o);
+
+       if (priv->loaded >= 1) {
+               priv->loaded = 1;
+               unload(o);
+       }
 }
 
-static void engine_music_class_finalize(EngineMusicClass *class)
+static void engine_music_class_init(EngineMusicClass *class)
 {
-}
+       UObjectClass *uo = U_OBJECT_CLASS(class);
+       GObjectClass *go = G_OBJECT_CLASS(class);
+       g_type_class_add_private(class, sizeof (struct music_priv));
 
-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)
-);
+       uo->deserialize = deserialize;
+       go->finalize    = engine_music_finalize;
+}
 
-void music_register(GTypeModule *m)
+static void engine_music_class_finalize(EngineMusicClass *class)
 {
-       engine_music_register_type(m);
 }