]> git.draconx.ca Git - upkg.git/blob - src/engine/music.c
uobject: Implement an interface for loading/unloading.
[upkg.git] / src / engine / music.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <glib-object.h>
4
5 #include "exportable.h"
6 #include "loadable.h"
7 #include "uobject.h"
8 #include "music.h"
9 #include "upkg.h"
10
11 #define MUSIC_GET_PRIV(o) \
12         G_TYPE_INSTANCE_GET_PRIVATE(o, ENGINE_MUSIC_TYPE, struct music_priv)
13
14 struct music_priv {
15         struct upkg_file *f;
16         unsigned loaded;
17 };
18
19 static void exportable_init(UObjectExportable *);
20 static void loadable_init(UObjectLoadable *);
21
22 G_DEFINE_DYNAMIC_TYPE_EXTENDED(EngineMusic, engine_music, U_OBJECT_TYPE, 0,
23         G_IMPLEMENT_INTERFACE(U_OBJECT_TYPE_EXPORTABLE, exportable_init)
24         G_IMPLEMENT_INTERFACE(U_OBJECT_TYPE_LOADABLE, loadable_init)
25 );
26
27 static int load(GObject *o)
28 {
29         struct music_priv *priv = MUSIC_GET_PRIV(o);
30
31         if (!priv->loaded) {
32                 g_return_val_if_fail(priv->f != NULL, -1);
33
34                 if (upkg_export_seek(priv->f, 0, SEEK_SET) != 0) {
35                         return -1;
36                 }
37         }
38
39         priv->loaded++;
40         return 0;
41 }
42
43 static void unload(GObject *o)
44 {
45         struct music_priv *priv = MUSIC_GET_PRIV(o);
46         g_return_if_fail(priv->loaded > 0);
47
48         --priv->loaded;
49 }
50
51 static int export(GObject *o, FILE *f)
52 {
53         struct music_priv *priv = MUSIC_GET_PRIV(o);
54         unsigned char buf[1024];
55
56         if (!priv->f || upkg_export_seek(priv->f, 0, SEEK_SET) != 0)
57                 return -1;
58
59         while (!priv->f->eof) {
60                 size_t rc = upkg_export_read(priv->f, buf, sizeof buf);
61                 if (rc == 0) {
62                         if (priv->f->eof) break;
63                         return -1;
64                 }
65
66                 if (fwrite(buf, 1, rc, f) != rc)
67                         return -1;
68         }
69
70         return 0;
71 }
72
73 static int export_name(GObject *o, char *buf, size_t n)
74 {
75         struct music_priv *priv = MUSIC_GET_PRIV(o);
76         return snprintf(buf, n, "%s", priv->f ? priv->f->name : "");
77 }
78
79 static void exportable_init(UObjectExportable *e)
80 {
81         e->export      = export;
82         e->export_name = export_name;
83 }
84
85 static void loadable_init(UObjectLoadable *l)
86 {
87         l->load   = load;
88         l->unload = unload;
89 }
90
91 static int deserialize(UObject *o, struct upkg_file *f)
92 {
93         struct music_priv *priv = MUSIC_GET_PRIV(o);
94         EngineMusic *m = ENGINE_MUSIC(o);
95         size_t rc, pos = 0, buflen;
96         unsigned char buf[32];
97         long size;
98
99         U_OBJECT_CLASS(engine_music_parent_class)->deserialize(o, f);
100
101         buflen = upkg_export_read(f, buf, sizeof buf);
102
103         /* Random field #1 */
104         if (buflen - pos < 1)
105                 return -1;
106         pos += 1;
107
108         if (f->pkg->version > 61) {
109                 /* Random field #2 */
110                 if (buflen - pos < 4)
111                         return -1;
112                 pos += 4;
113         }
114
115         rc = upkg_decode_index(&size, buf+pos, buflen-pos);
116         if (rc == 0 || size < 0)
117                 return -1;
118         pos += rc;
119
120         f->base += pos;
121         f->len   = size;
122         upkg_export_seek(f, 0, SEEK_SET);
123
124         priv->f = f;
125
126         return 0;
127 }
128
129 void music_register(GTypeModule *m)
130 {
131         engine_music_register_type(m);
132 }
133
134 static void engine_music_init(EngineMusic *m)
135 {
136         struct music_priv *priv = MUSIC_GET_PRIV(m);
137         *priv = (struct music_priv){0};
138 }
139
140 static void engine_music_finalize(GObject *o)
141 {
142         struct music_priv *priv = MUSIC_GET_PRIV(o);
143
144         if (priv->loaded >= 1) {
145                 priv->loaded = 1;
146                 unload(o);
147         }
148 }
149
150 static void engine_music_class_init(EngineMusicClass *class)
151 {
152         UObjectClass *uo = U_OBJECT_CLASS(class);
153         GObjectClass *go = G_OBJECT_CLASS(class);
154         g_type_class_add_private(class, sizeof (struct music_priv));
155
156         uo->deserialize = deserialize;
157         go->finalize    = engine_music_finalize;
158 }
159
160 static void engine_music_class_finalize(EngineMusicClass *class)
161 {
162 }