summaryrefslogtreecommitdiff
path: root/apps/tagdb/artist.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/tagdb/artist.c')
-rw-r--r--apps/tagdb/artist.c370
1 files changed, 370 insertions, 0 deletions
diff --git a/apps/tagdb/artist.c b/apps/tagdb/artist.c
new file mode 100644
index 0000000000..82db81df2f
--- /dev/null
+++ b/apps/tagdb/artist.c
@@ -0,0 +1,370 @@
1#include "malloc.h" // realloc() and free()
2#include <string.h> // strncasecmp()
3
4#include "artist.h"
5
6// how is our flag organized?
7#define FLAG(deleted, spare) ( 0xC0 | (deleted?0x10:0x00) | (spare & 0x0F) )
8#define FLAG_VALID(flag) ((flag & 0xE0) == 0xC0)
9#define FLAG_DELETED(flag) (flag & 0x10)
10#define FLAG_SPARE(flag) (flag & 0x0F)
11
12static int do_resize(struct artist_entry *e, const uint32_t name_len, const uint32_t album_count, const int zero_fill);
13
14struct artist_entry* new_artist_entry(const uint32_t name_len, const uint32_t album_count) {
15 // start by allocating memory
16 struct artist_entry *e = (struct artist_entry*)malloc(sizeof(struct artist_entry));
17 if( e == NULL ) {
18 DEBUGF("new_artist_entry: could not allocate memory\n");
19 return NULL;
20 }
21
22 // We begin empty
23 e->name = NULL;
24 e->size.name_len = 0;
25 e->album = NULL;
26 e->size.album_count = 0;
27 e->flag = FLAG(0, 0);
28
29 // and resize to the requested size
30 if( do_resize(e, name_len, album_count, 1) ) {
31 free(e);
32 return NULL;
33 }
34 return e;
35}
36
37int artist_entry_destruct(struct artist_entry *e) {
38 assert(e != NULL);
39 assert(FLAG_VALID(e->flag));
40
41 free(e->name);
42 free(e->album);
43
44 free(e);
45
46 return ERR_NONE;
47}
48
49static int do_resize(struct artist_entry *e, const uint32_t name_len, const uint32_t album_count, const int zero_fill) {
50 void* temp;
51
52 assert(e != NULL);
53 assert(FLAG_VALID(e->flag));
54
55 // begin with name
56 if( name_len != e->size.name_len ) {
57 temp = realloc(e->name, name_len);
58 if(temp == NULL && name_len > 0) { // if realloc(,0) don't complain about NULL-pointer
59 DEBUGF("artist_entry_resize: out of memory to resize name\n");
60 return ERR_MALLOC;
61 }
62 e->name = (char*)temp;
63
64 // if asked, fill it with zero's
65 if( zero_fill ) {
66 uint32_t i;
67 for(i=e->size.name_len; i<name_len; i++)
68 e->name[i] = (char)0x00;
69 }
70
71 e->size.name_len = name_len;
72 }
73
74 // now the album
75 if( album_count != e->size.album_count ) {
76 temp = realloc(e->album, album_count * sizeof(*e->album));
77 if(temp == NULL && album_count > 0) { // if realloc(,0) don't complain about NULL-pointer
78 DEBUGF("artist_entry_resize: out of memory to resize album[]\n");
79 return ERR_MALLOC;
80 }
81 e->album = (uint32_t*)temp;
82
83 // if asked, fill it with zero's
84 if( zero_fill ) {
85 uint32_t i;
86 for(i=e->size.album_count; i<album_count; i++)
87 e->album[i] = (uint32_t)0x00000000;
88 }
89
90 e->size.album_count = album_count;
91 }
92
93 return ERR_NONE;
94}
95
96int artist_entry_resize(struct artist_entry *e, const uint32_t name_len, const uint32_t album_count) {
97 return do_resize(e, name_len, album_count, 1);
98}
99
100int artist_entry_serialize(FILE *fd, const struct artist_entry *e) {
101 assert(fd != NULL);
102 assert(e != NULL);
103 assert(FLAG_VALID(e->flag));
104
105 if( FLAG_DELETED(e->flag) ) { // we are deleted, do nothing
106 return ERR_NONE;
107 }
108
109 // First byte we write is a flag-byte to indicate this is a valid record
110 if( fwrite(&e->flag, 1, 1, fd) != 1 ) {
111 DEBUGF("artist_entry_serialize: failed to write flag-byte\n");
112 return ERR_FILE;
113 }
114
115 // First we write the length of the name field
116 if( fwrite(&e->size.name_len, sizeof(e->size.name_len), 1, fd) != 1 ) {
117 DEBUGF("artist_entry_serialize: failed to write name_len\n");
118 return ERR_FILE;
119 }
120
121 // now the name field itself
122 if( fwrite(e->name, 1, e->size.name_len, fd) != e->size.name_len ) {
123 DEBUGF("artist_entry_serialize: failed to write name\n");
124 return ERR_FILE;
125 }
126
127 // count of albums
128 if( fwrite(&e->size.album_count, sizeof(e->size.album_count), 1, fd) != 1 ) {
129 DEBUGF("artist_entry_serialize: failed to write album_count\n");
130 return ERR_FILE;
131 }
132
133 // album[] itself
134 if( fwrite(e->album, sizeof(*e->album), e->size.album_count, fd) != e->size.album_count ) {
135 DEBUGF("artist_entry_serialize: failed to write albums\n");
136 return ERR_FILE;
137 }
138
139 return ERR_NONE;
140}
141
142int artist_entry_unserialize(struct artist_entry **e, FILE *fd) {
143 uint32_t length;
144 unsigned char flag;
145
146 assert(e != NULL);
147 assert(fd != NULL);
148
149 // First byte we read is flag-byte
150 if( fread(&flag, 1, 1, fd) != 1 ) {
151 DEBUGF("artist_entry_unserialize: failed to read flag-byte\n");
152 return ERR_FILE;
153 }
154
155 // See what we have:
156 if( ! FLAG_VALID(flag) ) {
157 DEBUGF("artist_entry_unserialize: flag-byte not found\n");
158 return ERR_INVALID;
159 }
160
161 // Allocate memory
162 *e = new_artist_entry(0, 0);
163 if( *e == NULL ) {
164 DEBUGF("artist_entry_unserialize: could not create new artist_entry\n");
165 return ERR_MALLOC;
166 }
167
168 (*e)->flag = flag;
169
170 // First we read the length of the name field
171 if( fread(&length, sizeof(length), 1, fd) != 1 ) {
172 DEBUGF("artist_entry_unserialize: failed to read name_len\n");
173 artist_entry_destruct(*e);
174 return ERR_FILE;
175 }
176
177 // allocate memory for the upcomming name-field
178 if( do_resize((*e), length, 0, 0) ) {
179 DEBUGF("artist_entry_unserialize: failed to allocate memory for name\n");
180 artist_entry_destruct(*e);
181 return ERR_MALLOC;
182 }
183
184 // read it in
185 if( fread((*e)->name, 1, (*e)->size.name_len, fd) != (*e)->size.name_len ) {
186 DEBUGF("artist_entry_unserialize: failed to read name\n");
187 artist_entry_destruct(*e);
188 return ERR_FILE;
189 }
190
191 if( FLAG_DELETED(flag) ) {
192 // all there is... free some memory
193 if( do_resize(*e, 0, 0, 0) ) {
194 DEBUGF("artist_entry_unserialize: couldn't free() name\n");
195 return ERR_MALLOC;
196 }
197 return ERR_NONE;
198 }
199
200 // Next the count of albums
201 if( fread(&length, sizeof(length), 1, fd) != 1 ) {
202 DEBUGF("artist_entry_unserialize: failed to read album_count\n");
203 artist_entry_destruct(*e);
204 return ERR_FILE;
205 }
206
207 // allocate memory for the upcomming name-field
208 if( do_resize(*e, (*e)->size.name_len, length, 0) ) {
209 DEBUGF("artist_entry_unserialize: failed to allocate memory for album[]\n");
210 artist_entry_destruct(*e);
211 return ERR_MALLOC;
212 }
213
214 // read it in
215 if( fread((*e)->album, sizeof(*(*e)->album), (*e)->size.album_count, fd) != (*e)->size.album_count ) {
216 DEBUGF("artist_entry_unserialize: failed to read albums\n");
217 artist_entry_destruct(*e);
218 return ERR_FILE;
219 }
220
221 return ERR_NONE;
222}
223
224int artist_entry_write(FILE *fd, const struct artist_entry *e, const struct artist_size *s) {
225 uint32_t i, be;
226 char pad = 0x00;
227
228 assert(fd != NULL);
229 assert(e != NULL);
230 assert(FLAG_VALID(e->flag));
231
232 if( FLAG_DELETED(e->flag) ) { // we are deleted, do nothing
233 return ERR_NONE;
234 }
235
236 // artist name
237 if( fwrite(e->name, 1, e->size.name_len, fd) != e->size.name_len ) {
238 DEBUGF("artist_entry_write: failed to write name\n");
239 return ERR_FILE;
240 }
241 // padd the rest
242 i = e->size.name_len;
243 while( s != NULL && s->name_len > i) {
244 if( fwrite(&pad, 1, 1, fd) == 1 ) {
245 i++;
246 continue;
247 } else {
248 DEBUGF("artist_entry_write: failed to padd name\n");
249 return ERR_FILE;
250 }
251 }
252
253 // album offsets, but in BIG ENDIAN!
254 // so we need to iterate over each item to convert it
255 for(i=0; i<e->size.album_count; i++) {
256 be = BE32(e->album[i]);
257 if( fwrite(&be, sizeof(be), 1, fd) != 1 ) {
258 DEBUGF("artist_entry_write: failed to write album[%d]\n", i);
259 return ERR_FILE;
260 }
261 }
262 // padd the rest
263 be = BE32(0x00000000);
264 for(; s != NULL && i<s->album_count; i++) {
265 if( fwrite(&be, sizeof(be), 1, fd) != 1 ) {
266 DEBUGF("artist_entry_write: failed to padd album[]\n");
267 return ERR_FILE;
268 }
269 }
270
271 return ERR_NONE;
272}
273
274inline int artist_entry_compare(const struct artist_entry *a, const struct artist_entry *b) {
275 assert(a != NULL);
276 assert(b != NULL);
277 if( a->name == NULL || b->name == NULL )
278 return 1; // never match on no-names
279 return strcasecmp(a->name, b->name);
280}
281
282struct artist_size* new_artist_size() {
283 struct artist_size *s;
284 s = (struct artist_size*)malloc(sizeof(struct artist_size));
285 if( s == NULL ) {
286 DEBUGF("new_artist_size: failed to allocate memory\n");
287 return NULL;
288 }
289 s->name_len = 0;
290 s->album_count = 0;
291
292 return s;
293}
294
295inline uint32_t artist_size_get_length(const struct artist_size *size) {
296 assert(size != NULL);
297 return size->name_len + 4*size->album_count;
298}
299
300inline int artist_size_max(struct artist_size *s, const struct artist_entry *e) {
301 s->name_len = ( s->name_len >= e->size.name_len ? s->name_len : e->size.name_len );
302 s->album_count = ( s->album_count >= e->size.album_count ? s->album_count : e->size.album_count );
303 return ERR_NONE;
304}
305
306int artist_size_destruct(struct artist_size *s) {
307 assert(s != NULL);
308 // nothing to do...
309 free(s);
310 return ERR_NONE;
311}
312
313int artist_entry_add_album_mem(struct artist_entry *e, struct artist_size *s, const uint32_t album) {
314 assert(e != NULL);
315 assert(FLAG_VALID(e->flag));
316
317 if( do_resize(e, e->size.name_len, e->size.album_count+1, 0) ) {
318 DEBUGF("artist_entry_add_song_mem: failed to resize album[]\n");
319 return ERR_MALLOC;
320 }
321
322 e->album[e->size.album_count-1] = album;
323
324 if(s != NULL) artist_size_max(s, e); // can't fail
325
326 return ERR_NONE;
327}
328
329static int delete_serialized(FILE *fd, struct artist_entry *e) {
330// the entry should be both, in memory and in file at the current location
331// this function will mark the file-entry as deleted
332 uint32_t size;
333 unsigned char flag;
334 // overwrite the beginning of the serialized data:
335 assert(fd != NULL);
336 assert(e != NULL);
337 assert(FLAG_VALID(e->flag));
338
339 flag = FLAG(1, 0); // mark as deleted
340
341 // First byte we write is the flag-byte to indicate this is a deleted
342 if( fwrite(&flag, 1, 1, fd) != 1 ) {
343 DEBUGF("artist_entry_delete_serialized: failed to write flag-byte\n");
344 return ERR_FILE;
345 }
346
347 // Then we write the length of the COMPLETE entry
348 size = artist_size_get_length(&e->size) + 4; // 4 = overhead for the album[]
349 if( fwrite(&size, sizeof(size), 1, fd) != 1 ) {
350 DEBUGF("artist_entry_delete_serialized: failed to write len\n");
351 return ERR_FILE;
352 }
353
354 return ERR_NONE;
355}
356
357int artist_entry_add_album_file(FILE *fd, struct artist_entry *e, struct artist_size *s, const uint32_t album) {
358 assert(fd != NULL);
359 assert(e != NULL);
360 assert(FLAG_VALID(e->flag));
361
362 DEBUGF("artist_entry_add_song_file() called\n");
363
364 if( delete_serialized(fd, e) ) {
365 DEBUGF("artist_entry_add_album_file: could not mark as deleted\n");
366 return ERR_FILE;
367 }
368
369 return ERR_NO_INPLACE_UPDATE;
370}