]> git.draconx.ca Git - upkg.git/blob - src/engine/music.c
music: Remove file member from private struct.
[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 3 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, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <stdio.h>
20 #include <string.h>
21 #include <glib-object.h>
22
23 #include <uobject/uobject.h>
24 #include <uobject/exportable.h>
25 #include <uobject/loadable.h>
26 #include "music-module.h"
27 #include "music.h"
28 #include "upkg.h"
29
30 #define MUSIC_GET_PRIV(o) \
31         G_TYPE_INSTANCE_GET_PRIVATE(o, ENGINE_MUSIC_TYPE, struct music_priv)
32
33 struct music_priv {
34         struct music_mod *mod;
35         unsigned loaded;
36 };
37
38 static void exportable_init(UObjectExportable *);
39 static void loadable_init(UObjectLoadable *);
40
41 G_DEFINE_DYNAMIC_TYPE_EXTENDED(EngineMusic, engine_music, U_OBJECT_TYPE, 0,
42         G_IMPLEMENT_INTERFACE(U_OBJECT_TYPE_EXPORTABLE, exportable_init)
43         G_IMPLEMENT_INTERFACE(U_OBJECT_TYPE_LOADABLE, loadable_init)
44 );
45
46 static int load(GObject *o)
47 {
48         struct music_priv *priv = MUSIC_GET_PRIV(o);
49         struct upkg_file *f = U_OBJECT(o)->pkg_file;
50
51         if (!priv->loaded) {
52                 g_return_val_if_fail(f != NULL, -1);
53
54                 if (upkg_export_seek(f, 0, SEEK_SET) != 0) {
55                         return -1;
56                 }
57
58                 priv->mod = music_mod_open(f);
59                 if (!priv->mod) {
60                         return -1;
61                 }
62         }
63
64         priv->loaded++;
65         return 0;
66 }
67
68 static void unload(GObject *o)
69 {
70         struct music_priv *priv = MUSIC_GET_PRIV(o);
71         g_return_if_fail(priv->loaded > 0);
72
73         if (--priv->loaded == 0) {
74                 music_mod_close(priv->mod);
75         }
76 }
77
78 static int export(GObject *o, FILE *f)
79 {
80         struct music_priv *priv = MUSIC_GET_PRIV(o);
81         int rc;
82
83         if (load(o) != 0)
84                 return -1;
85
86         rc = music_mod_dump(priv->mod, f);
87
88         unload(o);
89
90         return rc;
91 }
92
93 static int export_name(GObject *o, char *buf, size_t n)
94 {
95         struct music_priv *priv = MUSIC_GET_PRIV(o);
96         const char *type;
97         int rc;
98
99         if (load(o) != 0) {
100                 if (n > 0) *buf = 0;
101                 return 0;
102         }
103
104         type = music_mod_type(priv->mod);
105         rc = snprintf(buf, n, "%s.%s", U_OBJECT(o)->pkg_file->name, type);
106
107         unload(o);
108
109         return rc;
110 }
111
112 static void exportable_init(UObjectExportable *e)
113 {
114         e->export      = export;
115         e->export_name = export_name;
116 }
117
118 static void loadable_init(UObjectLoadable *l)
119 {
120         l->load   = load;
121         l->unload = unload;
122 }
123
124 static int deserialize(UObject *uo)
125 {
126         struct music_priv *priv = MUSIC_GET_PRIV(uo);
127         struct upkg_file *f = uo->pkg_file;
128         size_t rc, pos = 0, buflen;
129         unsigned char buf[32];
130         long size;
131
132         U_OBJECT_CLASS(engine_music_parent_class)->deserialize(uo);
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
157         return 0;
158 }
159
160 void music_register(GTypeModule *m)
161 {
162         engine_music_register_type(m);
163 }
164
165 static void engine_music_init(EngineMusic *m)
166 {
167         struct music_priv *priv = MUSIC_GET_PRIV(m);
168         *priv = (struct music_priv){0};
169 }
170
171 static void engine_music_finalize(GObject *o)
172 {
173         struct music_priv *priv = MUSIC_GET_PRIV(o);
174
175         if (priv->loaded >= 1) {
176                 priv->loaded = 1;
177                 unload(o);
178         }
179
180         G_OBJECT_CLASS(engine_music_parent_class)->finalize(o);
181 }
182
183 static void engine_music_class_init(EngineMusicClass *class)
184 {
185         UObjectClass *uo = U_OBJECT_CLASS(class);
186         GObjectClass *go = G_OBJECT_CLASS(class);
187         g_type_class_add_private(class, sizeof (struct music_priv));
188
189         uo->deserialize = deserialize;
190         go->finalize    = engine_music_finalize;
191
192         music_mod_init();
193 }
194
195 static void engine_music_class_finalize(EngineMusicClass *class)
196 {
197         music_mod_exit();
198 }