diff options
Diffstat (limited to 'apps/tagdb/db.c')
-rw-r--r-- | apps/tagdb/db.c | 603 |
1 files changed, 603 insertions, 0 deletions
diff --git a/apps/tagdb/db.c b/apps/tagdb/db.c new file mode 100644 index 0000000000..1c84b2b75c --- /dev/null +++ b/apps/tagdb/db.c | |||
@@ -0,0 +1,603 @@ | |||
1 | #include <string.h> // strlen() strcpy() strcat() | ||
2 | |||
3 | #include "malloc.h" | ||
4 | #include "db.h" | ||
5 | #include "header.h" | ||
6 | |||
7 | #include "artist.h" | ||
8 | #include "album.h" | ||
9 | #include "song.h" | ||
10 | #include "file.h" | ||
11 | |||
12 | #include "tag_dummy.h" | ||
13 | |||
14 | #define CEIL32BIT(x) ( ((x) + 3) & 0xfffffffc ) | ||
15 | #define CEIL32BIT_LEN(x) CEIL32BIT(strlen(x) + 1) // +1 because we want to store the \0 at least once | ||
16 | |||
17 | #define CATCH_MALLOC(condition) \ | ||
18 | while( condition ) { \ | ||
19 | int rc_catch_malloc = free_ram(); \ | ||
20 | if (rc_catch_malloc != ERR_NONE) { \ | ||
21 | DEBUGF("catch_malloc: " #condition ": could not free memory, failing...\n"); \ | ||
22 | return rc_catch_malloc; \ | ||
23 | } \ | ||
24 | } | ||
25 | |||
26 | #define CATCH_MALLOC_ERR(expr) CATCH_MALLOC( (expr) == ERR_MALLOC ) | ||
27 | #define CATCH_MALLOC_NULL(expr) CATCH_MALLOC( (expr) == NULL ) | ||
28 | // Loop the expression as long as it returns ERR_MALLOC (for CATCH_MALLOC_ERR) | ||
29 | // or NULL (for CATCH_MALLOC_NULL) | ||
30 | // on each failure, call free_ram() to free some ram. if free_ram() fails, return | ||
31 | // the fail-code | ||
32 | #define CATCH_ERR(expr) \ | ||
33 | CATCH_MALLOC_ERR(rc = expr); \ | ||
34 | if( rc != ERR_NONE ) { \ | ||
35 | DEBUGF("catch_err: " #expr ": failed\n"); \ | ||
36 | return rc; \ | ||
37 | } | ||
38 | // Catches all errors: if it's a MALLOC one, try to free memory, | ||
39 | // if it's another one, return the code | ||
40 | |||
41 | static int fill_artist_offsets(struct artist_entry *e, struct artist_size *max_s); | ||
42 | static int fill_album_offsets(struct album_entry *e, struct album_size *max_s); | ||
43 | static int fill_song_offsets(struct song_entry *e, struct song_size *max_s); | ||
44 | static int fill_file_offsets(struct file_entry *e, struct file_size *max_s); | ||
45 | |||
46 | static int do_add(const struct tag_info *t); | ||
47 | |||
48 | static int tag_empty_get(struct tag_info *t); | ||
49 | /* Adds "<no artist tag>" and "<no album tag>" if they're empty | ||
50 | */ | ||
51 | |||
52 | static int free_ram(); | ||
53 | static char in_file = 0; | ||
54 | |||
55 | static int do_write(FILE *fd); | ||
56 | |||
57 | static struct array_buffer *artists; | ||
58 | static struct array_buffer *albums; | ||
59 | static struct array_buffer *songs; | ||
60 | static struct array_buffer *files; | ||
61 | static uint32_t artist_start=0, album_start=0, song_start=0, file_start=0; | ||
62 | static uint32_t artist_entry_len, album_entry_len, song_entry_len, file_entry_len; | ||
63 | static char *artists_file, *albums_file, *songs_file, *files_file; | ||
64 | |||
65 | int db_construct() { | ||
66 | void *max_size; | ||
67 | |||
68 | // struct array_buffer* new_array_buffer( int (*cmp)(const void *a, const void *b), | ||
69 | // int (*serialize)(FILE *fd, const void *e), | ||
70 | // int (*unserialize)(void **e, FILE *fd), | ||
71 | // uint32_t (*get_length)(const void *size), | ||
72 | // int (*write)(FILE *fd, void *e, const void *size), | ||
73 | // int (*destruct)(void *e), | ||
74 | // char* file_name, | ||
75 | // void* max_size, | ||
76 | // int (*max_size_update)(void *max_size, const void *e), | ||
77 | // int (*max_size_destruct)(void *max_size), | ||
78 | // int (*add_item_mem)(void *e, void *s, uint32_t item), | ||
79 | // int (*add_item_file)(FILE *fd, void *e, void *s, uint32_t item) | ||
80 | // ); | ||
81 | |||
82 | if(!( max_size = (void*)new_artist_size() )) { | ||
83 | DEBUGF("new_db: new_artist_size() failed\n"); | ||
84 | return ERR_MALLOC; | ||
85 | } | ||
86 | if(!( artists = new_array_buffer( (int (*)(const void *a, const void *b)) artist_entry_compare, | ||
87 | (int (*)(FILE *fd, const void *e)) artist_entry_serialize, | ||
88 | (int (*)(void **e, FILE *fd)) artist_entry_unserialize, | ||
89 | (uint32_t (*)(const void *size)) artist_size_get_length, | ||
90 | (int (*)(FILE *fd, void *e, const void *size)) artist_entry_write, | ||
91 | (int (*)(void *e)) artist_entry_destruct, | ||
92 | NULL, // don't allow to switch to file | ||
93 | max_size, | ||
94 | (int (*)(void *max_size, const void *e)) artist_size_max, | ||
95 | (int (*)(void *max_size)) artist_size_destruct, | ||
96 | (int (*)(void *e, void *s, uint32_t item)) artist_entry_add_album_mem, | ||
97 | (int (*)(FILE *fd, void *e, void *s, uint32_t item)) artist_entry_add_album_file, | ||
98 | (int (*)(void *e, void *s)) fill_artist_offsets | ||
99 | ) )) { | ||
100 | DEBUGF("new_db: new_array_buffer() failed on artists[]\n"); | ||
101 | return ERR_MALLOC; | ||
102 | } | ||
103 | if(!( artists_file = malloc(12) )) { // artists.tmp | ||
104 | DEBUGF("new_db: could not malloc() for artists[] file_name\n"); | ||
105 | return ERR_MALLOC; | ||
106 | } | ||
107 | strcpy(artists_file, "artists.tmp"); | ||
108 | |||
109 | if(!( max_size = (void*)new_album_size() )) { | ||
110 | DEBUGF("new_db: new_album_size() failed\n"); | ||
111 | return ERR_MALLOC; | ||
112 | } | ||
113 | if(!( albums = new_array_buffer( (int (*)(const void *a, const void *b)) album_entry_compare, | ||
114 | (int (*)(FILE *fd, const void *e)) album_entry_serialize, | ||
115 | (int (*)(void **e, FILE *fd)) album_entry_unserialize, | ||
116 | (uint32_t (*)(const void *size)) album_size_get_length, | ||
117 | (int (*)(FILE *fd, void *e, const void *size)) album_entry_write, | ||
118 | (int (*)(void *e)) album_entry_destruct, | ||
119 | NULL, // don't allow to switch to file | ||
120 | max_size, | ||
121 | (int (*)(void *max_size, const void *e)) album_size_max, | ||
122 | (int (*)(void *max_size)) album_size_destruct, | ||
123 | (int (*)(void *e, void *s, uint32_t item)) album_entry_add_song_mem, | ||
124 | (int (*)(FILE *fd, void *e, void *s, uint32_t item)) album_entry_add_song_file, | ||
125 | (int (*)(void *e, void *s)) fill_album_offsets | ||
126 | ) )) { | ||
127 | DEBUGF("new_db: new_array_buffer() failed on albums[]\n"); | ||
128 | return ERR_MALLOC; | ||
129 | } | ||
130 | if(!( albums_file = malloc(11) )) { // albums.tmp | ||
131 | DEBUGF("new_db: could not malloc() for albums[] file_name\n"); | ||
132 | return ERR_MALLOC; | ||
133 | } | ||
134 | strcpy(albums_file, "albums.tmp"); | ||
135 | |||
136 | if(!( max_size = (void*)new_song_size() )) { | ||
137 | DEBUGF("new_db: new_song_size() failed\n"); | ||
138 | return ERR_MALLOC; | ||
139 | } | ||
140 | if(!( songs = new_array_buffer( (int (*)(const void *a, const void *b)) song_entry_compare, | ||
141 | (int (*)(FILE *fd, const void *e)) song_entry_serialize, | ||
142 | (int (*)(void **e, FILE *fd)) song_entry_unserialize, | ||
143 | (uint32_t (*)(const void *size)) song_size_get_length, | ||
144 | (int (*)(FILE *fd, void *e, const void *size)) song_entry_write, | ||
145 | (int (*)(void *e)) song_entry_destruct, | ||
146 | NULL, // may switch to file, but we'd like to know about it | ||
147 | max_size, | ||
148 | (int (*)(void *max_size, const void *e)) song_size_max, | ||
149 | (int (*)(void *max_size)) song_size_destruct, | ||
150 | NULL, | ||
151 | NULL, | ||
152 | (int (*)(void *e, void *s)) fill_song_offsets | ||
153 | ) )) { | ||
154 | DEBUGF("new_db: new_array_buffer() failed on songs[]\n"); | ||
155 | return ERR_MALLOC; | ||
156 | } | ||
157 | if(!( songs_file = malloc(10) )) { // songs.tmp | ||
158 | DEBUGF("new_db: could not malloc() for songs[] file_name\n"); | ||
159 | return ERR_MALLOC; | ||
160 | } | ||
161 | strcpy(songs_file, "songs.tmp"); | ||
162 | |||
163 | if(!( max_size = (void*)new_file_size() )) { | ||
164 | DEBUGF("new_db: new_file_size() failed\n"); | ||
165 | return ERR_MALLOC; | ||
166 | } | ||
167 | if(!( files = new_array_buffer( (int (*)(const void *a, const void *b)) file_entry_compare, | ||
168 | (int (*)(FILE *fd, const void *e)) file_entry_serialize, | ||
169 | (int (*)(void **e, FILE *fd)) file_entry_unserialize, | ||
170 | (uint32_t (*)(const void *size)) file_size_get_length, | ||
171 | (int (*)(FILE *fd, void *e, const void *size)) file_entry_write, | ||
172 | (int (*)(void *e)) file_entry_destruct, | ||
173 | NULL, | ||
174 | max_size, | ||
175 | (int (*)(void *max_size, const void *e)) file_size_max, | ||
176 | (int (*)(void *max_size)) file_size_destruct, | ||
177 | NULL, | ||
178 | NULL, | ||
179 | (int (*)(void *e, void *s)) fill_file_offsets | ||
180 | ) )) { | ||
181 | DEBUGF("new_db: new_array_buffer() failed on files[]\n"); | ||
182 | return ERR_MALLOC; | ||
183 | } | ||
184 | if(!( files_file = malloc(10) )) { // files.tmp | ||
185 | DEBUGF("new_db: could not malloc() for files[] file_name\n"); | ||
186 | return ERR_MALLOC; | ||
187 | } | ||
188 | strcpy(files_file, "files.tmp"); | ||
189 | |||
190 | return ERR_NONE; | ||
191 | } | ||
192 | |||
193 | int db_destruct() { | ||
194 | int rc; | ||
195 | |||
196 | CATCH_ERR( array_buffer_destruct(artists, 1) ); | ||
197 | artists = NULL; | ||
198 | free(artists_file); | ||
199 | artists_file = NULL; | ||
200 | |||
201 | CATCH_ERR( array_buffer_destruct(albums, 1) ); | ||
202 | albums = NULL; | ||
203 | free(albums_file); | ||
204 | albums_file = NULL; | ||
205 | |||
206 | CATCH_ERR( array_buffer_destruct(songs, 1) ); | ||
207 | songs = NULL; | ||
208 | free(songs_file); | ||
209 | songs_file = NULL; | ||
210 | |||
211 | CATCH_ERR( array_buffer_destruct(files, 1) ); | ||
212 | files = NULL; | ||
213 | free(files_file); | ||
214 | files_file = NULL; | ||
215 | |||
216 | return ERR_NONE; | ||
217 | } | ||
218 | |||
219 | static int do_add(const struct tag_info *t) { | ||
220 | struct artist_entry *artist; uint32_t artistn; | ||
221 | struct album_entry *album; uint32_t albumn; | ||
222 | struct song_entry *song; uint32_t songn; | ||
223 | struct file_entry *file; uint32_t filen; | ||
224 | int rc; | ||
225 | |||
226 | // create file | ||
227 | CATCH_MALLOC_NULL( file = new_file_entry( CEIL32BIT( strlen(t->directory) + 1 + strlen(t->filename) + 1 ) ) ); // "dir"."/"."file"."\0" | ||
228 | |||
229 | // fill in file | ||
230 | strcpy(file->name, t->directory); | ||
231 | strcat(file->name, "/"); | ||
232 | strcat(file->name, t->filename); | ||
233 | file->hash = 0xffffffff; // TODO | ||
234 | file->song = songn = array_buffer_get_next_index(songs); | ||
235 | file->rundb = 0xffffffff; // TODO | ||
236 | |||
237 | // add | ||
238 | CATCH_ERR( array_buffer_add(files, file, &filen) ); | ||
239 | |||
240 | // create artist | ||
241 | CATCH_MALLOC_NULL( artist = new_artist_entry( CEIL32BIT_LEN(t->artist), 0) ); | ||
242 | // fill in | ||
243 | strcpy(artist->name, t->artist); | ||
244 | // see if it is already in | ||
245 | CATCH_MALLOC_ERR( rc = array_buffer_find_entry(artists, artist, &artistn) ); | ||
246 | if( rc == ERR_NONE ) { // found it | ||
247 | // remove our self-made one | ||
248 | artist_entry_destruct(artist); | ||
249 | artist = NULL; | ||
250 | } else if( rc == ERR_NOTFOUND ) { // didn't find it | ||
251 | // fill in the rest and add | ||
252 | CATCH_ERR( artist_entry_resize(artist, artist->size.name_len, 1) ); | ||
253 | artist->album[0] = albumn = array_buffer_get_next_index(albums); // if artist isn't in, album will not be in either | ||
254 | CATCH_ERR( array_buffer_add(artists, artist, &artistn) ); | ||
255 | // leave artist != NULL, to indicate that we made a new one | ||
256 | } else { //error | ||
257 | DEBUGF("do_add: could not search for artist in artists[]\n"); | ||
258 | return rc; | ||
259 | } | ||
260 | |||
261 | |||
262 | // create album | ||
263 | CATCH_MALLOC_NULL( album = new_album_entry(0,0) ); | ||
264 | // malloc for key | ||
265 | CATCH_MALLOC_NULL( album->key = malloc( strlen(t->album) + 3 + strlen(t->artist) + 3 + strlen(t->directory) + 1 ) ); | ||
266 | // fill in | ||
267 | strcpy(album->key, t->album); | ||
268 | strcat(album->key, "___"); | ||
269 | strcat(album->key, t->artist); | ||
270 | strcat(album->key, "___"); | ||
271 | strcat(album->key, t->directory); | ||
272 | // see if it is already in | ||
273 | CATCH_MALLOC_ERR( rc = array_buffer_find_entry(albums, album, &albumn) ); | ||
274 | if( rc == ERR_NONE ) { // found it | ||
275 | assert(artist == NULL); // make sure artist was found; else we have trouble! | ||
276 | // Remove our search-album and add the song to the already existing one | ||
277 | album_entry_destruct(album); | ||
278 | album = NULL; | ||
279 | CATCH_ERR( array_buffer_entry_update(albums, albumn, songn) ); | ||
280 | } else if( rc == ERR_NOTFOUND ) { // didn't find it | ||
281 | // fill in the rest of the info in this album and add it | ||
282 | CATCH_ERR( album_entry_resize(album, CEIL32BIT_LEN(t->album), 1 ) ); | ||
283 | strcpy(album->name, t->album); | ||
284 | album->artist = artistn; | ||
285 | album->song[0] = songn; | ||
286 | CATCH_ERR( array_buffer_add(albums, album, &albumn) ); | ||
287 | } else { // error | ||
288 | DEBUGF("do_add: could not search for album in albums[]\n"); | ||
289 | return rc; | ||
290 | } | ||
291 | |||
292 | |||
293 | if( album != NULL && artist == NULL ) { | ||
294 | // we have a new album from an already existing artist | ||
295 | // add it! | ||
296 | CATCH_ERR( array_buffer_entry_update(artists, artistn, albumn) ); | ||
297 | } | ||
298 | |||
299 | |||
300 | // song | ||
301 | CATCH_MALLOC_NULL( song = new_song_entry( CEIL32BIT_LEN(t->song), CEIL32BIT_LEN(t->genre)) ); | ||
302 | // fill in | ||
303 | strcpy(song->name, t->song); | ||
304 | song->artist = artistn; | ||
305 | song->album = albumn; | ||
306 | song->file = filen; | ||
307 | strcpy(song->genre, t->genre); | ||
308 | song->bitrate = t->bitrate; | ||
309 | song->year = t->year; | ||
310 | song->playtime = t->playtime; | ||
311 | song->track = t->track; | ||
312 | song->samplerate = t->samplerate; | ||
313 | // add | ||
314 | CATCH_ERR( array_buffer_add(songs, song, NULL) ); | ||
315 | |||
316 | return ERR_NONE; | ||
317 | } | ||
318 | |||
319 | static int tag_empty_get(struct tag_info *t) { | ||
320 | assert( t != NULL ); | ||
321 | |||
322 | if( t->song == NULL ) { | ||
323 | CATCH_MALLOC_NULL( t->song = (char*)malloc(14) ); | ||
324 | strcpy(t->song, "<no song tag>"); | ||
325 | } | ||
326 | if( t->genre == NULL ) { | ||
327 | CATCH_MALLOC_NULL( t->genre = (char*)malloc(15) ); | ||
328 | strcpy(t->genre, "<no genre tag>"); | ||
329 | } | ||
330 | if( t->artist == NULL ) { | ||
331 | CATCH_MALLOC_NULL( t->artist = (char*)malloc(16) ); | ||
332 | strcpy(t->artist, "<no artist tag>"); | ||
333 | } | ||
334 | if( t->album == NULL ) { | ||
335 | CATCH_MALLOC_NULL( t->album = (char*)malloc(15) ); | ||
336 | strcpy(t->album, "<no album tag>"); | ||
337 | } | ||
338 | |||
339 | return ERR_NONE; | ||
340 | } | ||
341 | |||
342 | int db_add(char* file_path, const char* strip_path, const char* add_path) { | ||
343 | char *basename, *dir; | ||
344 | struct tag_info *t; | ||
345 | int rc; | ||
346 | |||
347 | assert(file_path != NULL); | ||
348 | |||
349 | // Create a new tag_info structure | ||
350 | CATCH_MALLOC_NULL( t = new_tag_info() ); | ||
351 | |||
352 | // fill in the file_name | ||
353 | basename = strrchr(file_path, '/'); // TODO: add \ for windows | ||
354 | if( basename == NULL ) { | ||
355 | basename = file_path; // no / in the path, so it's only a filename | ||
356 | dir = NULL; | ||
357 | } else { | ||
358 | dir = file_path; | ||
359 | basename[0] = '\0'; // set the / to \0 to split the string | ||
360 | basename++; // skip past the / | ||
361 | } | ||
362 | CATCH_MALLOC_NULL( t->filename = malloc(strlen(basename)+1) ); // +1 for the '\0' termination | ||
363 | strcpy(t->filename, basename); | ||
364 | |||
365 | // convert the path | ||
366 | if( strip_path != NULL && strlen(strip_path) > 0) { | ||
367 | if( dir == NULL || strncmp(file_path, strip_path, strlen(strip_path)) ) { | ||
368 | printf("db_add: could not strip path from \"%s\"\n", file_path); | ||
369 | } else { | ||
370 | dir += strlen(strip_path); // skip the path to strip | ||
371 | } | ||
372 | } | ||
373 | if( add_path != NULL ) { | ||
374 | CATCH_MALLOC_NULL( t->directory = malloc( strlen(add_path) + strlen(dir) + 1 ) ); // +1 for '\0' termination | ||
375 | strcpy(t->directory, add_path); | ||
376 | strcat(t->directory, dir); | ||
377 | } else { | ||
378 | CATCH_MALLOC_NULL( t->directory = malloc( strlen(dir) + 1 ) ); | ||
379 | strcpy(t->directory, dir); | ||
380 | } | ||
381 | |||
382 | // restore the file_path to it's original state | ||
383 | if( dir != NULL) *(basename-1) = '/'; | ||
384 | |||
385 | // So far we have: | ||
386 | // filename | ||
387 | // directory | ||
388 | // try to get the rest from tag-information: | ||
389 | //tag_id3v2_get(file_path, t); | ||
390 | //tag_id3v1_get(file_path, t); | ||
391 | tag_dummy(file_path, t); | ||
392 | |||
393 | // If it is still empty here, skip this file | ||
394 | if( t->artist==NULL && t->song==NULL && t->album==NULL && t->genre==NULL) { | ||
395 | tag_info_destruct(t); // we won't need it anymore | ||
396 | return ERR_NONE; | ||
397 | } | ||
398 | |||
399 | // fill in empty tags with "<no ... tag>" | ||
400 | CATCH_ERR( tag_empty_get(t) ); | ||
401 | |||
402 | // all filled in, now add it | ||
403 | CATCH_ERR( do_add(t) ); | ||
404 | |||
405 | tag_info_destruct(t); // we won't need it anymore | ||
406 | |||
407 | return ERR_NONE; | ||
408 | } | ||
409 | |||
410 | static int free_ram() { | ||
411 | // put things in file that we won't need to search a lot: | ||
412 | // files[] and songs[] are write only | ||
413 | // artists[] and albums[] should stay in memory as long as possible | ||
414 | // albums[] is updated for every song; | ||
415 | // artists[] for every album: artists[] will be the first to loose ram... | ||
416 | if(!( in_file & 0x01 )) { // files[] is still in ram | ||
417 | in_file |= 0x01; | ||
418 | // switch files[] to file-mode | ||
419 | files->file_name = files_file; | ||
420 | files_file = NULL; // since array_buffer will clean this up | ||
421 | return array_buffer_switch_to_file(files); | ||
422 | } else if(!( in_file & 0x02 )) { // song[] is still in ram | ||
423 | in_file |= 0x02; | ||
424 | // switch songs[] to file-mode | ||
425 | songs->file_name = songs_file; | ||
426 | songs_file = NULL; // since array_buffer will clean this up | ||
427 | return array_buffer_switch_to_file(songs); | ||
428 | } else if(!( in_file & 0x04 )) { // artists[] is still in ram | ||
429 | in_file |= 0x04; | ||
430 | // switch artists[] to file-mode | ||
431 | artists->file_name = artists_file; | ||
432 | artists_file = NULL; // since array_buffer will clean this up | ||
433 | return array_buffer_switch_to_file(artists); | ||
434 | } else if(!( in_file & 0x08 )) { // albums[] is still in ram | ||
435 | in_file |= 0x08; | ||
436 | // switch albums[] to file-mode | ||
437 | albums->file_name = albums_file; | ||
438 | albums_file = NULL; // since array_buffer will clean this up | ||
439 | return array_buffer_switch_to_file(albums); | ||
440 | } else { | ||
441 | // all is already in file mode, sorry... | ||
442 | DEBUGF("free_ram: everything is already in file-mode, cannot free more ram, sorry...\n"); | ||
443 | return ERR_MALLOC; | ||
444 | } | ||
445 | } | ||
446 | |||
447 | static int fill_artist_offsets(struct artist_entry *e, struct artist_size *max_s) { | ||
448 | uint32_t i; | ||
449 | |||
450 | assert(e != NULL); | ||
451 | assert(album_start != 0); | ||
452 | |||
453 | for(i=0; i<e->size.album_count; i++) { | ||
454 | e->album[i] = album_start + e->album[i] * album_entry_len; | ||
455 | } | ||
456 | return ERR_NONE; | ||
457 | } | ||
458 | |||
459 | static int fill_album_offsets(struct album_entry *e, struct album_size *max_s) { | ||
460 | uint32_t i; | ||
461 | |||
462 | assert(e != NULL); | ||
463 | assert(song_start != 0); | ||
464 | |||
465 | e->artist = artist_start + e->artist * artist_entry_len; | ||
466 | for(i=0; i<e->size.song_count; i++) { | ||
467 | e->song[i] = song_start + e->song[i] * song_entry_len; | ||
468 | } | ||
469 | return ERR_NONE; | ||
470 | } | ||
471 | |||
472 | static int fill_song_offsets(struct song_entry *e, struct song_size *max_s) { | ||
473 | |||
474 | assert(e != NULL); | ||
475 | assert(artist_start != 0); | ||
476 | assert(album_start != 0); | ||
477 | assert(file_start != 0); | ||
478 | |||
479 | e->artist = artist_start + e->artist * artist_entry_len; | ||
480 | e->album = album_start + e->album * album_entry_len; | ||
481 | e->file = file_start + e->file * file_entry_len; | ||
482 | return ERR_NONE; | ||
483 | } | ||
484 | |||
485 | static int fill_file_offsets(struct file_entry *e, struct file_size *max_s) { | ||
486 | |||
487 | assert(e != NULL); | ||
488 | assert(song_start != 0); | ||
489 | |||
490 | e->song = song_start + e->song * song_entry_len; | ||
491 | return ERR_NONE; | ||
492 | } | ||
493 | |||
494 | static int do_write(FILE *fd) { | ||
495 | int rc; | ||
496 | struct header h; | ||
497 | |||
498 | assert(fd != NULL); | ||
499 | |||
500 | // make a header | ||
501 | h.magic[0] = 'R'; h.magic[1] = 'D'; h.magic[2] = 'B'; | ||
502 | h.version = 0x03; | ||
503 | |||
504 | h.artist_start = artist_start = HEADER_SIZE; | ||
505 | h.album_start = album_start = h.artist_start + array_buffer_get_length(artists); // TODO error check | ||
506 | h.song_start = song_start = h.album_start + array_buffer_get_length(albums); | ||
507 | h.file_start = file_start = h.song_start + array_buffer_get_length(songs); | ||
508 | |||
509 | h.artist_count = artists->count; | ||
510 | h.album_count = albums->count; | ||
511 | h.song_count = songs->count; | ||
512 | h.file_count = files->count; | ||
513 | |||
514 | h.artist_len = ((struct artist_size*)artists->max_size)->name_len; | ||
515 | h.album_len = ((struct album_size*)albums->max_size)->name_len; | ||
516 | h.song_len = ((struct song_size*)songs->max_size)->name_len; | ||
517 | h.genre_len = ((struct song_size*)songs->max_size)->genre_len; | ||
518 | h.file_len = ((struct file_size*)files->max_size)->name_len; | ||
519 | |||
520 | artist_entry_len = artist_size_get_length(artists->max_size); // TODO error check | ||
521 | album_entry_len = album_size_get_length(albums->max_size); | ||
522 | song_entry_len = song_size_get_length(songs->max_size); | ||
523 | file_entry_len = file_size_get_length(files->max_size); | ||
524 | |||
525 | h.song_array_count = ((struct album_size*)albums->max_size)->song_count; | ||
526 | h.album_array_count = ((struct artist_size*)artists->max_size)->album_count; | ||
527 | |||
528 | h.flags.reserved = 0; | ||
529 | h.flags.rundb_dirty = 1; | ||
530 | |||
531 | // write the header | ||
532 | CATCH_ERR( header_write(fd, &h) ); | ||
533 | |||
534 | // write the arrays | ||
535 | CATCH_ERR( array_buffer_write(fd, artists) ); | ||
536 | CATCH_ERR( array_buffer_write(fd, albums) ); | ||
537 | CATCH_ERR( array_buffer_write(fd, songs) ); | ||
538 | CATCH_ERR( array_buffer_write(fd, files) ); | ||
539 | |||
540 | return ERR_NONE; | ||
541 | } | ||
542 | |||
543 | int db_write(FILE *fd) { | ||
544 | int rc; | ||
545 | // sort everything | ||
546 | CATCH_ERR( array_buffer_sort(artists) ); | ||
547 | CATCH_ERR( array_buffer_sort(albums) ); | ||
548 | CATCH_ERR( array_buffer_sort(songs) ); | ||
549 | CATCH_ERR( array_buffer_sort(files) ); | ||
550 | |||
551 | CATCH_ERR( do_write(fd) ); | ||
552 | |||
553 | return ERR_NONE; | ||
554 | } | ||
555 | |||
556 | struct tag_info* new_tag_info() { | ||
557 | struct tag_info *t; | ||
558 | t = malloc(sizeof(struct tag_info)); | ||
559 | if( t == NULL ) { | ||
560 | DEBUGF("new_tag_info: could not malloc() for tag_info\n"); | ||
561 | return NULL; | ||
562 | } | ||
563 | |||
564 | t->directory = NULL; | ||
565 | t->filename = NULL; | ||
566 | t->song = NULL; | ||
567 | t->artist = NULL; | ||
568 | t->album = NULL; | ||
569 | t->genre = NULL; | ||
570 | t->bitrate = 0; | ||
571 | t->year = 0; | ||
572 | t->playtime = 0; | ||
573 | t->track = 0; | ||
574 | t->samplerate = 0; | ||
575 | |||
576 | return t; | ||
577 | } | ||
578 | |||
579 | int tag_info_destruct(struct tag_info *t) { | ||
580 | assert(t != NULL); | ||
581 | |||
582 | free(t->directory); | ||
583 | t->directory = NULL; | ||
584 | free(t->filename); | ||
585 | t->filename = NULL; | ||
586 | free(t->song); | ||
587 | t->song = NULL; | ||
588 | free(t->artist); | ||
589 | t->artist = NULL; | ||
590 | free(t->album); | ||
591 | t->album = NULL; | ||
592 | free(t->genre); | ||
593 | t->genre = NULL; | ||
594 | t->bitrate = 0; | ||
595 | t->year = 0; | ||
596 | t->playtime = 0; | ||
597 | t->track = 0; | ||
598 | t->samplerate = 0; | ||
599 | |||
600 | free(t); | ||
601 | |||
602 | return ERR_NONE; | ||
603 | } | ||