]> git.draconx.ca Git - upkg.git/blobdiff - src/engine/music.c
music: Remove file member from private struct.
[upkg.git] / src / engine / music.c
index 0c0cdf81be1253155ac15e6cd79299ece2d97278..8c17f9ddfa19e8a1d9d6da6b0e3ae4391395a433 100644 (file)
@@ -1,9 +1,29 @@
+/*
+ *  upkg: tool for manipulating Unreal Tournament packages.
+ *  Copyright (C) 2009 Nick Bowler
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
 #include <stdio.h>
 #include <string.h>
 #include <glib-object.h>
 
-#include "serializable.h"
-#include "exportable.h"
+#include <uobject/uobject.h>
+#include <uobject/exportable.h>
+#include <uobject/loadable.h>
+#include "music-module.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 music_mod *mod;
+       unsigned loaded;
+};
 
-       struct upkg_file *f;
-       size_t base, len;
+static void exportable_init(UObjectExportable *);
+static void loadable_init(UObjectLoadable *);
 
-       unsigned char buf[2048];
-       unsigned long nbuf;
-};
+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 export(GObject *o, FILE *f)
+static int load(GObject *o)
 {
        struct music_priv *priv = MUSIC_GET_PRIV(o);
-       size_t left = priv->len, rc;
-
-       unsigned char buf[1024];
+       struct upkg_file *f = U_OBJECT(o)->pkg_file;
 
-       if (upkg_export_seek(priv->f, priv->base, SEEK_SET) != 0)
-               return -1;
+       if (!priv->loaded) {
+               g_return_val_if_fail(f != NULL, -1);
 
-       while (left > 0) {
-               rc = upkg_export_read(priv->f, buf, MIN(left, sizeof buf));
-               if (rc == 0)
+               if (upkg_export_seek(f, 0, SEEK_SET) != 0) {
                        return -1;
-               if (fwrite(buf, 1, rc, f) != rc)
+               }
+
+               priv->mod = music_mod_open(f);
+               if (!priv->mod) {
                        return -1;
-               left -= rc;
+               }
        }
 
+       priv->loaded++;
        return 0;
 }
 
+static void unload(GObject *o)
+{
+       struct music_priv *priv = MUSIC_GET_PRIV(o);
+       g_return_if_fail(priv->loaded > 0);
+
+       if (--priv->loaded == 0) {
+               music_mod_close(priv->mod);
+       }
+}
+
+static int export(GObject *o, FILE *f)
+{
+       struct music_priv *priv = MUSIC_GET_PRIV(o);
+       int rc;
+
+       if (load(o) != 0)
+               return -1;
+
+       rc = music_mod_dump(priv->mod, f);
+
+       unload(o);
+
+       return rc;
+}
+
 static int export_name(GObject *o, char *buf, size_t n)
 {
        struct music_priv *priv = MUSIC_GET_PRIV(o);
+       const char *type;
+       int rc;
+
+       if (load(o) != 0) {
+               if (n > 0) *buf = 0;
+               return 0;
+       }
 
-       return snprintf(buf, n, "%s", priv->f->name);
+       type = music_mod_type(priv->mod);
+       rc = snprintf(buf, n, "%s.%s", U_OBJECT(o)->pkg_file->name, type);
+
+       unload(o);
+
+       return rc;
 }
 
-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)
 {
-       struct music_priv *priv = MUSIC_GET_PRIV(o);
-       EngineMusic *m = ENGINE_MUSIC(o);
+       l->load   = load;
+       l->unload = unload;
+}
+
+static int deserialize(UObject *uo)
+{
+       struct music_priv *priv = MUSIC_GET_PRIV(uo);
+       struct upkg_file *f = uo->pkg_file;
+       size_t rc, pos = 0, buflen;
+       unsigned char buf[32];
        long size;
 
-       size_t rc;
+       U_OBJECT_CLASS(engine_music_parent_class)->deserialize(uo);
 
-       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);
+       }
+
+       G_OBJECT_CLASS(engine_music_parent_class)->finalize(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)
+       music_mod_init();
+}
+
+static void engine_music_class_finalize(EngineMusicClass *class)
 {
-       engine_music_register_type(m);
+       music_mod_exit();
 }