1 #include "malloc.h" // realloc() and free()
2 #include <strings.h> // strncasecmp()
3 #include <string.h> // strlen()
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)
13 static int do_resize(struct album_entry
*e
, const uint32_t name_len
, const uint32_t song_count
, const int zero_fill
);
15 struct 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
));
19 DEBUGF("new_album_entry: could not allocate memory\n");
29 e
->size
.song_count
= 0;
33 // and resize to the requested size
34 if( do_resize(e
, name_len
, song_count
, 1) ) {
41 int album_entry_destruct(struct album_entry
*e
) {
43 assert(FLAG_VALID(e
->flag
));
54 static int do_resize(struct album_entry
*e
, const uint32_t name_len
, const uint32_t song_count
, const int zero_fill
) {
58 assert(FLAG_VALID(e
->flag
));
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");
67 e
->name
= (char*)temp
;
69 // if asked, fill it with zero's
72 for(i
=e
->size
.name_len
; i
<name_len
; i
++)
73 e
->name
[i
] = (char)0x00;
76 e
->size
.name_len
= name_len
;
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");
86 e
->song
= (uint32_t*)temp
;
88 // if asked, fill it with zero's
91 for(i
=e
->size
.song_count
; i
<song_count
; i
++)
92 e
->song
[i
] = (uint32_t)0x00000000;
95 e
->size
.song_count
= song_count
;
101 inline 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);
105 int album_entry_serialize(FILE *fd
, const struct album_entry
*e
) {
109 assert(FLAG_VALID(e
->flag
));
112 if( FLAG_DELETED(e
->flag
) ) { // we are deleted, do nothing
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");
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");
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");
134 // the key-field (if present)
135 if( e
->key
!= NULL
) {
136 length
= strlen(e
->key
);
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");
145 if( e
->key
!= NULL
) {
147 if( fwrite(e
->key
, 1, length
, fd
) != length
) {
148 DEBUGF("album_entry_serialize: failed to write key\n");
154 if( fwrite(&e
->artist
, sizeof(e
->artist
), 1, fd
) != 1 ) {
155 DEBUGF("album_entry_serialize: failed to write artist\n");
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");
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");
174 int album_entry_unserialize(struct album_entry
**e
, FILE *fd
) {
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");
188 if( ! FLAG_VALID(flag
) ) {
189 DEBUGF("album_entry_unserialize: flag-byte is invalid\n");
194 *e
= new_album_entry(0, 0);
196 DEBUGF("album_entry_unserialize: could not create new album_entry\n");
200 (*e
)->flag
= flag
; // we had a valid entry, copy it over
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
);
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
);
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
);
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");
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
);
241 if( ((*e
)->key
= malloc(length
)) == NULL
) {
242 DEBUGF("album_entry_unserialize: failed to allocate memory for key\n");
243 album_entry_destruct(*e
);
248 if( fread((*e
)->key
, 1, length
, fd
) != length
) {
249 DEBUGF("album_entry_unserialize: failed to read key\n");
250 album_entry_destruct(*e
);
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
);
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
);
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
);
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
);
286 int album_entry_write(FILE *fd
, struct album_entry
*e
, struct album_size
*s
) {
291 assert(FLAG_VALID(e
->flag
));
294 if( FLAG_DELETED(e
->flag
) ) { // we are deleted, do nothing
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");
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");
314 i
= e
->size
.name_len
;
315 while( s
!= NULL
&& s
->name_len
> i
) {
316 if( fwrite(&pad
, 1, 1, fd
) == 1 ) {
320 DEBUGF("album_entry_write: failed to pad name\n");
326 be
= BE32(e
->artist
);
327 if( fwrite(&be
, sizeof(be
), 1, fd
) != 1 ) {
328 DEBUGF("album_entry_write: failed to write artist\n");
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
);
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");
353 inline int album_entry_compare(const struct album_entry
*a
, const struct album_entry
*b
) {
356 assert(a
->key
!= NULL
);
357 assert(b
->key
!= NULL
);
358 return strcasecmp(a
->key
, b
->key
);
361 struct album_size
* new_album_size() {
362 struct album_size
*s
;
363 s
= (struct album_size
*)malloc(sizeof(struct album_size
));
365 DEBUGF("new_album_size: failed to allocate memory\n");
374 inline 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
;
379 inline int album_size_max(struct album_size
*s
, const struct album_entry
*e
) {
382 assert(FLAG_VALID(e
->flag
));
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
);
389 int album_size_destruct(struct album_size
*s
) {
396 int album_entry_add_song_mem(struct album_entry
*e
, struct album_size
*s
, const uint32_t song
) {
398 assert(FLAG_VALID(e
->flag
));
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");
405 e
->song
[e
->size
.song_count
-1] = song
;
407 if( s
!= NULL
) album_size_max(s
, e
); // can't fail
412 static 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
420 assert(FLAG_VALID(e
->flag
));
422 // overwrite the beginning of the serialized data:
423 flag
= FLAG(1, 0); // set the delete flag, clear the spare flags
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");
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");
441 int album_entry_add_song_file(FILE *fd
, struct album_entry
*e
, struct album_size
*s
, const uint32_t song
) {
444 assert(FLAG_VALID(e
->flag
));
446 DEBUGF("album_entry_add_song_file() called\n");
448 if( delete_serialized(fd
, e
) ) {
449 DEBUGF("album_entry_add_song_file: could not mark as deleted\n");
453 return ERR_NO_INPLACE_UPDATE
;