X-Git-Url: https://git.draconx.ca/gitweb/upkg.git/blobdiff_plain/90b53df329f9a114770dccab6b7e41f9094dfac9..3d673858df99c9ff1a10eb14ca57f8447923b094:/src/engine/music.c diff --git a/src/engine/music.c b/src/engine/music.c index 0c0cdf8..8c17f9d 100644 --- a/src/engine/music.c +++ b/src/engine/music.c @@ -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 . + */ + #include #include #include -#include "serializable.h" -#include "exportable.h" +#include +#include +#include +#include "music-module.h" #include "music.h" #include "upkg.h" @@ -11,113 +31,168 @@ 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(); }