summaryrefslogtreecommitdiff
path: root/apps/tagdb/album.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/tagdb/album.c')
-rw-r--r--apps/tagdb/album.c454
1 files changed, 454 insertions, 0 deletions
diff --git a/apps/tagdb/album.c b/apps/tagdb/album.c
new file mode 100644
index 0000000000..53b3660c90
--- /dev/null
+++ b/apps/tagdb/album.c
@@ -0,0 +1,454 @@
1#include "malloc.h" // realloc() and free()
2#include <strings.h> // strncasecmp()
3#include <string.h> // strlen()
4
5#include "album.h"
6
7// how is our flag organized?
8#define FLAG(deleted, spare) ( 0xE0 | (deleted?0x10:0x00) | (spare & 0x0F) )
9#define FLAG_VALID(flag) ((flag & 0xE0) == 0xE0)
10#define FLAG_DELETED(flag) (flag & 0x10)
11#define FLAG_SPARE(flag) (flag & 0x0F)
12
13static int do_resize(struct album_entry *e, const uint32_t name_len, const uint32_t song_count, const int zero_fill);
14
15struct album_entry* new_album_entry(const uint32_t name_len, const uint32_t song_count) {
16 // Start my allocating memory
17 struct album_entry *e = (struct album_entry*)malloc(sizeof(struct album_entry));
18 if( e == NULL ) {
19 DEBUGF("new_album_entry: could not allocate memory\n");
20 return NULL;
21 }
22
23 // We begin empty
24 e->name = NULL;
25 e->size.name_len = 0;
26 e->key = NULL;
27 e->artist = 0;
28 e->song = NULL;
29 e->size.song_count = 0;
30
31 e->flag = FLAG(0, 0);
32
33 // and resize to the requested size
34 if( do_resize(e, name_len, song_count, 1) ) {
35 free(e);
36 return NULL;
37 }
38 return e;
39}
40
41int album_entry_destruct(struct album_entry *e) {
42 assert(e != NULL);
43 assert(FLAG_VALID(e->flag));
44
45 free(e->name);
46 free(e->key);
47 free(e->song);
48
49 free(e);
50
51 return ERR_NONE;
52}
53
54static int do_resize(struct album_entry *e, const uint32_t name_len, const uint32_t song_count, const int zero_fill) {
55 void* temp;
56
57 assert(e != NULL);
58 assert(FLAG_VALID(e->flag));
59
60 // begin with name
61 if( name_len != e->size.name_len ) {
62 temp = realloc(e->name, name_len);
63 if(temp == NULL && name_len > 0) { // if realloc(,0) don't complain about NULL-pointer
64 DEBUGF("do_resize: out of memory to resize name\n");
65 return ERR_MALLOC;
66 }
67 e->name = (char*)temp;
68
69 // if asked, fill it with zero's
70 if( zero_fill ) {
71 uint32_t i;
72 for(i=e->size.name_len; i<name_len; i++)
73 e->name[i] = (char)0x00;
74 }
75
76 e->size.name_len = name_len;
77 }
78
79 // now the song[]
80 if( song_count != e->size.song_count ) {
81 temp = realloc(e->song, song_count * sizeof(*e->song));
82 if(temp == NULL && song_count > 0) { // if realloc(,0) don't complain about NULL-pointer
83 DEBUGF("album_entry_resize: out of memory to resize song[]\n");
84 return ERR_MALLOC;
85 }
86 e->song = (uint32_t*)temp;
87
88 // if asked, fill it with zero's
89 if( zero_fill ) {
90 uint32_t i;
91 for(i=e->size.song_count; i<song_count; i++)
92 e->song[i] = (uint32_t)0x00000000;
93 }
94
95 e->size.song_count = song_count;
96 }
97
98 return ERR_NONE;
99}
100
101inline int album_entry_resize(struct album_entry *e, const uint32_t name_len, const uint32_t song_count) {
102 return do_resize(e, name_len, song_count, 1);
103}
104
105int album_entry_serialize(FILE *fd, const struct album_entry *e) {
106 uint32_t length;
107
108 assert(e != NULL);
109 assert(FLAG_VALID(e->flag));
110 assert(fd != NULL);
111
112 if( FLAG_DELETED(e->flag) ) { // we are deleted, do nothing
113 return ERR_NONE;
114 }
115
116 // First byte we write is a flag-byte
117 if( fwrite(&e->flag, 1, 1, fd) != 1 ) {
118 DEBUGF("album_entry_serialize: failed to write flag-byte\n");
119 return ERR_FILE;
120 }
121
122 // First we write the length of the name field
123 if( fwrite(&e->size.name_len, sizeof(e->size.name_len), 1, fd) != 1 ) {
124 DEBUGF("album_entry_serialize: failed to write name_len\n");
125 return ERR_FILE;
126 }
127
128 // now the name field itself
129 if( fwrite(e->name, 1, e->size.name_len, fd) != e->size.name_len ) {
130 DEBUGF("album_entry_serialize: failed to write name\n");
131 return ERR_FILE;
132 }
133
134 // the key-field (if present)
135 if( e->key != NULL ) {
136 length = strlen(e->key);
137 } else {
138 length = 0;
139 }
140 // length (always, 0 if not present)
141 if( fwrite(&length, sizeof(length), 1, fd) != 1 ) {
142 DEBUGF("album_entry_serialize: failed to write length of key\n");
143 return ERR_FILE;
144 }
145 if( e->key != NULL ) {
146 // key itself
147 if( fwrite(e->key, 1, length, fd) != length ) {
148 DEBUGF("album_entry_serialize: failed to write key\n");
149 return ERR_FILE;
150 }
151 }
152
153 // Artist field
154 if( fwrite(&e->artist, sizeof(e->artist), 1, fd) != 1 ) {
155 DEBUGF("album_entry_serialize: failed to write artist\n");
156 return ERR_FILE;
157 }
158
159 // count of songs
160 if( fwrite(&e->size.song_count, sizeof(e->size.song_count), 1, fd) != 1 ) {
161 DEBUGF("album_entry_serialize: failed to write song_count\n");
162 return ERR_FILE;
163 }
164
165 // song[] itself
166 if( fwrite(e->song, sizeof(*e->song), e->size.song_count, fd) != e->size.song_count ) {
167 DEBUGF("album_entry_serialize: failed to write songs\n");
168 return ERR_FILE;
169 }
170
171 return ERR_NONE;
172}
173
174int album_entry_unserialize(struct album_entry **e, FILE *fd) {
175 uint32_t length;
176 unsigned char flag;
177
178 assert(e != NULL);
179 assert(fd != NULL);
180
181 // First byte we read are the flags
182 if( fread(&flag, 1, 1, fd) != 1 ) {
183 DEBUGF("album_entry_unserialize: failed to read flag-byte\n");
184 return ERR_FILE;
185 }
186
187 // See what we have:
188 if( ! FLAG_VALID(flag) ) {
189 DEBUGF("album_entry_unserialize: flag-byte is invalid\n");
190 return ERR_INVALID;
191 }
192
193 // Allocate memory
194 *e = new_album_entry(0, 0);
195 if( *e == NULL ) {
196 DEBUGF("album_entry_unserialize: could not create new album_entry\n");
197 return ERR_MALLOC;
198 }
199
200 (*e)->flag = flag; // we had a valid entry, copy it over
201
202 // First we read the length of the name field
203 if( fread(&length, sizeof(length), 1, fd) != 1 ) {
204 DEBUGF("album_entry_unserialize: failed to read name_len\n");
205 album_entry_destruct(*e);
206 return ERR_FILE;
207 }
208
209 // allocate memory for the upcomming name-field
210 if( do_resize(*e, length, 0, 0) ) {
211 DEBUGF("album_entry_unserialize: failed to allocate memory for name\n");
212 album_entry_destruct(*e);
213 return ERR_MALLOC;
214 }
215
216 // read it in
217 if( fread((*e)->name, 1, (*e)->size.name_len, fd) != (*e)->size.name_len ) {
218 DEBUGF("album_entry_unserialize: failed to read name\n");
219 album_entry_destruct(*e);
220 return ERR_FILE;
221 }
222
223 if( FLAG_DELETED(flag) ) {
224 // all there is... free some memory
225 if( do_resize(*e, 0, 0, 0) ) {
226 DEBUGF("album_entry_unserialize: couldn't free() name\n");
227 return ERR_MALLOC;
228 }
229 return ERR_NONE;
230 }
231
232 // maybe a key-field
233 if( fread(&length, sizeof(length), 1, fd) != 1 ) {
234 DEBUGF("album_entry_unserialize: failed to read length of key\n");
235 album_entry_destruct(*e);
236 return ERR_FILE;
237 }
238
239 if( length > 0 ) {
240 // allocate memory
241 if( ((*e)->key = malloc(length)) == NULL ) {
242 DEBUGF("album_entry_unserialize: failed to allocate memory for key\n");
243 album_entry_destruct(*e);
244 return ERR_MALLOC;
245 }
246
247 // read it
248 if( fread((*e)->key, 1, length, fd) != length ) {
249 DEBUGF("album_entry_unserialize: failed to read key\n");
250 album_entry_destruct(*e);
251 return ERR_FILE;
252 }
253 }
254
255 // next the artist field
256 if( fread(&(*e)->artist, sizeof((*e)->artist), 1, fd) != 1 ) {
257 DEBUGF("album_entry_unserialize: failed to read artist\n");
258 album_entry_destruct(*e);
259 return ERR_FILE;
260 }
261
262 // Next the count of songs
263 if( fread(&length, sizeof(length), 1, fd) != 1 ) {
264 DEBUGF("album_entry_unserialize: failed to read song_count\n");
265 album_entry_destruct(*e);
266 return ERR_FILE;
267 }
268
269 // allocate memory for the upcomming name-field
270 if( do_resize(*e, (*e)->size.name_len, length, 0) ) {
271 DEBUGF("album_entry_unserialize: failed to allocate memory for song[]\n");
272 album_entry_destruct(*e);
273 return ERR_MALLOC;
274 }
275
276 // read it in
277 if( fread((*e)->song, sizeof(*(*e)->song), (*e)->size.song_count, fd) != (*e)->size.song_count ) {
278 DEBUGF("album_entry_unserialize: failed to read songs\n");
279 album_entry_destruct(*e);
280 return ERR_FILE;
281 }
282
283 return ERR_NONE;
284}
285
286int album_entry_write(FILE *fd, struct album_entry *e, struct album_size *s) {
287 uint32_t i, be;
288 char pad = 0x00;
289
290 assert(e != NULL);
291 assert(FLAG_VALID(e->flag));
292 assert(fd != NULL);
293
294 if( FLAG_DELETED(e->flag) ) { // we are deleted, do nothing
295 return ERR_NONE;
296 }
297
298 // resize-write to size *s
299 // First check if we are not reducing the size...
300 if( s != NULL && ( s->name_len < e->size.name_len || s->song_count < e->size.song_count ) ) {
301 // just do it in 2 steps
302 if( do_resize(e, s->name_len, s->song_count, 0) ) {
303 DEBUGF("album_entry_write: failed to reduce size of entry, failing...\n");
304 return ERR_MALLOC;
305 }
306 }
307
308 // album name
309 if( fwrite(e->name, 1, e->size.name_len, fd) != e->size.name_len ) {
310 DEBUGF("album_entry_write: failed to write name\n");
311 return ERR_FILE;
312 }
313 // pad the rest
314 i = e->size.name_len;
315 while( s != NULL && s->name_len > i) {
316 if( fwrite(&pad, 1, 1, fd) == 1 ) {
317 i++;
318 continue;
319 } else {
320 DEBUGF("album_entry_write: failed to pad name\n");
321 return ERR_FILE;
322 }
323 }
324
325 // artist
326 be = BE32(e->artist);
327 if( fwrite(&be, sizeof(be), 1, fd) != 1 ) {
328 DEBUGF("album_entry_write: failed to write artist\n");
329 return ERR_FILE;
330 }
331
332 // song offsets, but in BIG ENDIAN!
333 // so we need to iterate over each item to convert it
334 for(i=0; i<e->size.song_count; i++) {
335 be = BE32(e->song[i]);
336 if( fwrite(&be, sizeof(be), 1, fd) != 1 ) {
337 DEBUGF("album_entry_write: failed to write song[%d]\n", i);
338 return ERR_FILE;
339 }
340 }
341 // pad the rest
342 be = BE32(0x00000000);
343 for(; s != NULL && i<s->song_count; i++) {
344 if( fwrite(&be, sizeof(be), 1, fd) != 1 ) {
345 DEBUGF("album_entry_write: failed to pad song[]\n");
346 return ERR_FILE;
347 }
348 }
349
350 return 0;
351}
352
353inline int album_entry_compare(const struct album_entry *a, const struct album_entry *b) {
354 assert(a != NULL);
355 assert(b != NULL);
356 assert(a->key != NULL);
357 assert(b->key != NULL);
358 return strcasecmp(a->key, b->key);
359}
360
361struct album_size* new_album_size() {
362 struct album_size *s;
363 s = (struct album_size*)malloc(sizeof(struct album_size));
364 if( s == NULL ) {
365 DEBUGF("new_album_size: failed to allocate memory\n");
366 return NULL;
367 }
368 s->name_len = 0;
369 s->song_count = 0;
370
371 return s;
372}
373
374inline uint32_t album_size_get_length(const struct album_size *size) {
375 assert(size != NULL);
376 return size->name_len + 4 + 4*size->song_count;
377}
378
379inline int album_size_max(struct album_size *s, const struct album_entry *e) {
380 assert(s != NULL);
381 assert(e != NULL);
382 assert(FLAG_VALID(e->flag));
383
384 s->name_len = ( s->name_len >= e->size.name_len ? s->name_len : e->size.name_len );
385 s->song_count = ( s->song_count >= e->size.song_count ? s->song_count : e->size.song_count );
386 return ERR_NONE;
387}
388
389int album_size_destruct(struct album_size *s) {
390 assert(s != NULL);
391 // nothing to do...
392 free(s);
393 return ERR_NONE;
394}
395
396int album_entry_add_song_mem(struct album_entry *e, struct album_size *s, const uint32_t song) {
397 assert(e != NULL);
398 assert(FLAG_VALID(e->flag));
399
400 if( do_resize(e, e->size.name_len, e->size.song_count+1, 0) ) {
401 DEBUGF("album_entry_add_song_mem: failed to resize song[]\n");
402 return ERR_MALLOC;
403 }
404
405 e->song[e->size.song_count-1] = song;
406
407 if( s != NULL) album_size_max(s, e); // can't fail
408
409 return ERR_NONE;
410}
411
412static int delete_serialized(FILE *fd, struct album_entry *e) {
413// the entry should be both, in memory and in file at the current location
414// this function will mark the file-entry as deleted
415 uint32_t size;
416 unsigned char flag;
417
418 assert(fd != NULL);
419 assert(e != NULL);
420 assert(FLAG_VALID(e->flag));
421
422 // overwrite the beginning of the serialized data:
423 flag = FLAG(1, 0); // set the delete flag, clear the spare flags
424
425 // First byte we write is the flag-byte to indicate this is a deleted
426 if( fwrite(&flag, 1, 1, fd) != 1 ) {
427 DEBUGF("album_entry_delete_serialized: failed to write flag-byte\n");
428 return ERR_FILE;
429 }
430
431 // Then we write the length of the COMPLETE entry
432 size = album_size_get_length(&e->size) + 4; // 4 = overhead for the song[]
433 if( fwrite(&size, sizeof(size), 1, fd) != 1 ) {
434 DEBUGF("album_entry_delete_serialized: failed to write len\n");
435 return ERR_FILE;
436 }
437
438 return ERR_NONE;
439}
440
441int album_entry_add_song_file(FILE *fd, struct album_entry *e, struct album_size *s, const uint32_t song) {
442 assert(fd != NULL);
443 assert(e != NULL);
444 assert(FLAG_VALID(e->flag));
445
446 DEBUGF("album_entry_add_song_file() called\n");
447
448 if( delete_serialized(fd, e) ) {
449 DEBUGF("album_entry_add_song_file: could not mark as deleted\n");
450 return ERR_FILE;
451 }
452
453 return ERR_NO_INPLACE_UPDATE;
454}