/* * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "exportable.h" #include "loadable.h" #include "uobject.h" #include "music-module.h" #include "music.h" #include "upkg.h" #define MUSIC_GET_PRIV(o) \ G_TYPE_INSTANCE_GET_PRIVATE(o, ENGINE_MUSIC_TYPE, struct music_priv) struct music_priv { struct upkg_file *f; struct music_mod *mod; unsigned loaded; }; 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); if (!priv->loaded) { g_return_val_if_fail(priv->f != NULL, -1); if (upkg_export_seek(priv->f, 0, SEEK_SET) != 0) { return -1; } priv->mod = music_mod_open(priv->f); if (!priv->mod) { 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); 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; } type = music_mod_type(priv->mod); rc = snprintf(buf, n, "%s.%s", priv->f->name, type); unload(o); return rc; } static void exportable_init(UObjectExportable *e) { e->export = export; e->export_name = export_name; } 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); size_t rc, pos = 0, buflen; unsigned char buf[32]; long size; U_OBJECT_CLASS(engine_music_parent_class)->deserialize(o, f); buflen = upkg_export_read(f, buf, sizeof buf); /* Random field #1 */ if (buflen - pos < 1) return -1; pos += 1; if (f->pkg->version > 61) { /* Random field #2 */ if (buflen - pos < 4) return -1; pos += 4; } rc = upkg_decode_index(&size, buf+pos, buflen-pos); if (rc == 0 || size < 0) return -1; pos += rc; f->base += pos; f->len = size; upkg_export_seek(f, 0, SEEK_SET); priv->f = f; return 0; } void music_register(GTypeModule *m) { 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_finalize(GObject *o) { 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_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)); uo->deserialize = deserialize; go->finalize = engine_music_finalize; music_mod_init(); } static void engine_music_class_finalize(EngineMusicClass *class) { music_mod_exit(); }