/*
* 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
#include
#include
#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();
}