]> git.draconx.ca Git - upkg.git/blob - src/engine/music.c
434d881fda70d1fe51f1efd2bd3989f05a4eadb6
[upkg.git] / src / engine / music.c
1 /*
2  *  upkg: tool for manipulating Unreal Tournament packages.
3  *  Copyright (C) 2009 Nick Bowler
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <glib-object.h>
23
24 #include <uobject/uobject.h>
25 #include <uobject/exportable.h>
26 #include <uobject/loadable.h>
27 #include "music-module.h"
28 #include "music.h"
29 #include "upkg.h"
30
31 #define MUSIC_GET_PRIV(o) \
32         G_TYPE_INSTANCE_GET_PRIVATE(o, ENGINE_MUSIC_TYPE, struct music_priv)
33
34 struct music_priv {
35         struct upkg_file *f;
36         struct music_mod *mod;
37         unsigned loaded;
38 };
39
40 static void exportable_init(UObjectExportable *);
41 static void loadable_init(UObjectLoadable *);
42
43 G_DEFINE_DYNAMIC_TYPE_EXTENDED(EngineMusic, engine_music, UOBJECT_TYPE, 0,
44         G_IMPLEMENT_INTERFACE(UOBJECT_TYPE_EXPORTABLE, exportable_init)
45         G_IMPLEMENT_INTERFACE(UOBJECT_TYPE_LOADABLE, loadable_init)
46 );
47
48 static int load(GObject *o)
49 {
50         struct music_priv *priv = MUSIC_GET_PRIV(o);
51
52         if (!priv->loaded) {
53                 g_return_val_if_fail(priv->f != NULL, -1);
54
55                 if (upkg_export_seek(priv->f, 0, SEEK_SET) != 0) {
56                         return -1;
57                 }
58
59                 priv->mod = music_mod_open(priv->f);
60                 if (!priv->mod) {
61                         return -1;
62                 }
63         }
64
65         priv->loaded++;
66         return 0;
67 }
68
69 static void unload(GObject *o)
70 {
71         struct music_priv *priv = MUSIC_GET_PRIV(o);
72         g_return_if_fail(priv->loaded > 0);
73
74         if (--priv->loaded == 0) {
75                 music_mod_close(priv->mod);
76         }
77 }
78
79 static int export(GObject *o, FILE *f)
80 {
81         struct music_priv *priv = MUSIC_GET_PRIV(o);
82         int rc;
83
84         if (load(o) != 0)
85                 return -1;
86
87         rc = music_mod_dump(priv->mod, f);
88
89         unload(o);
90
91         return rc;
92 }
93
94 static int export_name(GObject *o, char *buf, size_t n)
95 {
96         struct music_priv *priv = MUSIC_GET_PRIV(o);
97         const char *type;
98         int rc;
99
100         if (load(o) != 0) {
101                 if (n > 0) *buf = 0;
102                 return 0;
103         }
104
105         type = music_mod_type(priv->mod);
106         rc = snprintf(buf, n, "%s.%s", priv->f->name, type);
107
108         unload(o);
109
110         return rc;
111 }
112
113 static void exportable_init(UObjectExportable *e)
114 {
115         e->export      = export;
116         e->export_name = export_name;
117 }
118
119 static void loadable_init(UObjectLoadable *l)
120 {
121         l->load   = load;
122         l->unload = unload;
123 }
124
125 static int deserialize(UObject *o, struct upkg_file *f)
126 {
127         struct music_priv *priv = MUSIC_GET_PRIV(o);
128         size_t rc, pos = 0, buflen;
129         unsigned char buf[32];
130         long size;
131
132         UOBJECT_CLASS(engine_music_parent_class)->deserialize(o, f);
133
134         buflen = upkg_export_read(f, buf, sizeof buf);
135
136         /* Random field #1 */
137         if (buflen - pos < 1)
138                 return -1;
139         pos += 1;
140
141         if (f->pkg->version > 61) {
142                 /* Random field #2 */
143                 if (buflen - pos < 4)
144                         return -1;
145                 pos += 4;
146         }
147
148         rc = upkg_decode_index(&size, buf+pos, buflen-pos);
149         if (rc == 0 || size < 0)
150                 return -1;
151         pos += rc;
152
153         f->base += pos;
154         f->len   = size;
155         upkg_export_seek(f, 0, SEEK_SET);
156         priv->f = f;
157
158         return 0;
159 }
160
161 void music_register(GTypeModule *m)
162 {
163         engine_music_register_type(m);
164 }
165
166 static void engine_music_init(EngineMusic *m)
167 {
168         struct music_priv *priv = MUSIC_GET_PRIV(m);
169         *priv = (struct music_priv){0};
170 }
171
172 static void engine_music_finalize(GObject *o)
173 {
174         struct music_priv *priv = MUSIC_GET_PRIV(o);
175
176         if (priv->loaded >= 1) {
177                 priv->loaded = 1;
178                 unload(o);
179         }
180
181         G_OBJECT_CLASS(engine_music_parent_class)->finalize(o);
182 }
183
184 static void engine_music_class_init(EngineMusicClass *class)
185 {
186         UObjectClass *uo = UOBJECT_CLASS(class);
187         GObjectClass *go = G_OBJECT_CLASS(class);
188         g_type_class_add_private(class, sizeof (struct music_priv));
189
190         uo->deserialize = deserialize;
191         go->finalize    = engine_music_finalize;
192
193         music_mod_init();
194 }
195
196 static void engine_music_class_finalize(EngineMusicClass *class)
197 {
198         music_mod_exit();
199 }