1 /*
2     $Id: cddb_disc.c,v 1.25 2007/08/07 03:12:53 jcaratzas Exp $
3 
4     Copyright (C) 2003, 2004, 2005 Kris Verbeeck <airborne@advalvas.be>
5 
6     This library is free software; you can redistribute it and/or
7     modify it under the terms of the GNU Library General Public
8     License as published by the Free Software Foundation; either
9     version 2 of the License, or (at your option) any later version.
10 
11     This library is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14     Library General Public License for more details.
15 
16     You should have received a copy of the GNU Library General Public
17     License along with this library; if not, write to the
18     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19     Boston, MA  02111-1307, USA.
20 */
21 
22 
23 #include "cddb/cddb_ni.h"
24 
25 #include <math.h>
26 #include <stdlib.h>
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #endif
30 
31 
32 const char *CDDB_CATEGORY[CDDB_CAT_LAST] = {
33     "data", "folk", "jazz", "misc", "rock", "country", "blues", "newage",
34     "reggae", "classical", "soundtrack",
35     "invalid"
36 };
37 
38 
39 /* --- private functions */
40 
41 
cddb_disc_iconv(iconv_t cd,cddb_disc_t * disc)42 int cddb_disc_iconv(iconv_t cd, cddb_disc_t *disc)
43 {
44     char *result;
45     cddb_track_t *track;
46 
47     if (!cd) {
48         return TRUE;            /* no user character set defined */
49     }
50     if (disc->genre) {
51         if (cddb_str_iconv(cd, disc->genre, &result)) {
52             free(disc->genre);
53             disc->genre = result;
54         } else {
55             return FALSE;
56         }
57     }
58     if (disc->title) {
59         if (cddb_str_iconv(cd, disc->title, &result)) {
60             free(disc->title);
61             disc->title = result;
62         } else {
63             return FALSE;
64         }
65     }
66     if (disc->artist) {
67         if (cddb_str_iconv(cd, disc->artist, &result)) {
68             free(disc->artist);
69             disc->artist = result;
70         } else {
71             return FALSE;
72         }
73     }
74     if (disc->ext_data) {
75         if (cddb_str_iconv(cd, disc->ext_data, &result)) {
76             free(disc->ext_data);
77             disc->ext_data = result;
78         } else {
79             return FALSE;
80         }
81     }
82     track = disc->tracks;
83     while (track) {
84         if (!cddb_track_iconv(cd, track)) {
85             return FALSE;
86         }
87         track = track->next;
88     }
89     return TRUE;
90 }
91 
92 
93 /* --- construction / destruction */
94 
95 
cddb_disc_new(void)96 cddb_disc_t *cddb_disc_new(void)
97 {
98     cddb_disc_t *disc;
99 
100     disc = (cddb_disc_t*)calloc(1, sizeof(cddb_disc_t));
101     if (disc) {
102         disc->category = CDDB_CAT_INVALID;
103     } else {
104         cddb_log_crit(cddb_error_str(CDDB_ERR_OUT_OF_MEMORY));
105     }
106 
107     return disc;
108 }
109 
cddb_disc_destroy(cddb_disc_t * disc)110 void cddb_disc_destroy(cddb_disc_t *disc)
111 {
112     cddb_track_t *track, *next;
113 
114     if (disc) {
115         FREE_NOT_NULL(disc->genre);
116         FREE_NOT_NULL(disc->title);
117         FREE_NOT_NULL(disc->artist);
118         FREE_NOT_NULL(disc->ext_data);
119         track = disc->tracks;
120         while (track) {
121             next = track->next;
122             cddb_track_destroy(track);
123             track = next;
124         }
125         free(disc);
126     }
127 }
128 
cddb_disc_clone(const cddb_disc_t * disc)129 cddb_disc_t *cddb_disc_clone(const cddb_disc_t *disc)
130 {
131     cddb_disc_t *clone;
132     cddb_track_t *track;
133 
134     cddb_log_debug("cddb_disc_clone()");
135     clone = cddb_disc_new();
136     clone->discid = disc->discid;
137     clone->category = disc->category;
138     clone->year = disc->year;
139     clone->genre = (disc->genre ? strdup(disc->genre) : NULL);
140     clone->title = (disc->title ? strdup(disc->title) : NULL);
141     clone->artist = (disc->artist ? strdup(disc->artist) : NULL);
142     clone->length = disc->length;
143     clone->revision = disc->revision;
144     clone->ext_data = (disc->ext_data ? strdup(disc->ext_data) : NULL);
145     /* clone the tracks */
146     track = disc->tracks;
147     while (track) {
148         cddb_disc_add_track(clone, cddb_track_clone(track));
149         track = track->next;
150     }
151     return clone;
152 }
153 
154 
155 /* --- track manipulation */
156 
157 
cddb_disc_add_track(cddb_disc_t * disc,cddb_track_t * track)158 void cddb_disc_add_track(cddb_disc_t *disc, cddb_track_t *track)
159 {
160     cddb_log_debug("cddb_disc_add_track()");
161     if (!disc->tracks) {
162         /* first track on disc */
163         disc->tracks = track;
164     } else {
165         /* next track on disc */
166         cddb_track_t *t;
167 
168         t = disc->tracks;
169         while (t->next) {
170             t = t->next;
171         }
172         t->next = track;
173         track->prev = t;
174     }
175     disc->track_cnt++;
176     track->num = disc->track_cnt;
177     track->disc = disc;
178 }
179 
cddb_disc_get_track(const cddb_disc_t * disc,int track_no)180 cddb_track_t *cddb_disc_get_track(const cddb_disc_t *disc, int track_no)
181 {
182     cddb_track_t *track;
183 
184     if (track_no >= disc->track_cnt) {
185         return NULL;
186     }
187 
188     for (track = disc->tracks;
189          track_no > 0;
190          track_no--, track = track->next) { /* no-op */ }
191     /* XXX: should we check track->num?? */
192     return track;
193 }
194 
cddb_disc_get_track_first(cddb_disc_t * disc)195 cddb_track_t *cddb_disc_get_track_first(cddb_disc_t *disc)
196 {
197     disc->iterator = disc->tracks;
198     return disc->iterator;
199 }
200 
cddb_disc_get_track_next(cddb_disc_t * disc)201 cddb_track_t *cddb_disc_get_track_next(cddb_disc_t *disc)
202 {
203     if (disc->iterator != NULL) {
204         disc->iterator = disc->iterator->next;
205     }
206     return disc->iterator;
207 }
208 
209 
210 /* --- setters / getters --- */
211 
212 
cddb_disc_get_discid(const cddb_disc_t * disc)213 unsigned int cddb_disc_get_discid(const cddb_disc_t *disc)
214 {
215     if (disc) {
216         return disc->discid;
217     } return 0;
218 }
219 
cddb_disc_set_discid(cddb_disc_t * disc,unsigned int id)220 void cddb_disc_set_discid(cddb_disc_t *disc, unsigned int id)
221 {
222     if (disc) {
223         disc->discid = id;
224     }
225 }
226 
cddb_disc_get_category(const cddb_disc_t * disc)227 cddb_cat_t cddb_disc_get_category(const cddb_disc_t *disc)
228 {
229     if (disc) {
230         return disc->category;
231     }
232     return CDDB_CAT_INVALID;
233 }
234 
cddb_disc_set_category(cddb_disc_t * disc,cddb_cat_t cat)235 void cddb_disc_set_category(cddb_disc_t *disc, cddb_cat_t cat)
236 {
237     if (disc) {
238         disc->category = cat;
239     }
240 }
241 
cddb_disc_get_category_str(cddb_disc_t * disc)242 const char *cddb_disc_get_category_str(cddb_disc_t *disc)
243 {
244     const char *cat = NULL;
245 
246     if (disc) {
247         cat = CDDB_CATEGORY[disc->category];
248     }
249     RETURN_STR_OR_EMPTY(cat);
250 }
251 
cddb_disc_set_category_str(cddb_disc_t * disc,const char * cat)252 void cddb_disc_set_category_str(cddb_disc_t *disc, const char *cat)
253 {
254     int i;
255 
256     FREE_NOT_NULL(disc->genre);
257     disc->genre = strdup(cat);
258     disc->category = CDDB_CAT_MISC;
259     for (i = 0; i < CDDB_CAT_LAST; i++) {
260         if (strcmp(cat, CDDB_CATEGORY[i]) == 0) {
261             disc->category = i;
262             return;
263         }
264     }
265 }
266 
cddb_disc_get_genre(const cddb_disc_t * disc)267 const char *cddb_disc_get_genre(const cddb_disc_t *disc)
268 {
269     const char *genre = NULL;
270 
271     if (disc) {
272         genre = disc->genre;
273     }
274     RETURN_STR_OR_EMPTY(genre);
275 }
276 
cddb_disc_set_genre(cddb_disc_t * disc,const char * genre)277 void cddb_disc_set_genre(cddb_disc_t *disc, const char *genre)
278 {
279     if (disc) {
280         FREE_NOT_NULL(disc->genre);
281         disc->genre = strdup(genre);
282     }
283 }
284 
cddb_disc_get_length(const cddb_disc_t * disc)285 unsigned int cddb_disc_get_length(const cddb_disc_t *disc)
286 {
287     if (disc) {
288         return disc->length;
289     }
290     return 0;
291 }
292 
cddb_disc_set_length(cddb_disc_t * disc,unsigned int l)293 void cddb_disc_set_length(cddb_disc_t *disc, unsigned int l)
294 {
295     if (disc) {
296         disc->length = l;
297     }
298 }
299 
cddb_disc_get_revision(const cddb_disc_t * disc)300 unsigned int cddb_disc_get_revision(const cddb_disc_t *disc)
301 {
302     if (disc) {
303         return disc->revision;
304     }
305     return 0;
306 }
307 
cddb_disc_set_revision(cddb_disc_t * disc,unsigned int rev)308 void cddb_disc_set_revision(cddb_disc_t *disc, unsigned int rev)
309 {
310     if (disc) {
311         disc->revision = rev;
312     }
313 }
314 
cddb_disc_get_year(const cddb_disc_t * disc)315 unsigned int cddb_disc_get_year(const cddb_disc_t *disc)
316 {
317     if (disc) {
318         return disc->year;
319     }
320     return 0;
321 }
322 
cddb_disc_set_year(cddb_disc_t * disc,unsigned int y)323 void cddb_disc_set_year(cddb_disc_t *disc, unsigned int y)
324 {
325     if (disc) {
326         disc->year = y;
327     }
328 }
329 
cddb_disc_get_track_count(const cddb_disc_t * disc)330 int cddb_disc_get_track_count(const cddb_disc_t *disc)
331 {
332     if (disc) {
333         return disc->track_cnt;
334     }
335     return -1;
336 }
337 
cddb_disc_get_title(const cddb_disc_t * disc)338 const char *cddb_disc_get_title(const cddb_disc_t *disc)
339 {
340     const char *title = NULL;
341 
342     if (disc) {
343         title = disc->title;
344     }
345     RETURN_STR_OR_EMPTY(title);
346 }
347 
cddb_disc_set_title(cddb_disc_t * disc,const char * title)348 void cddb_disc_set_title(cddb_disc_t *disc, const char *title)
349 {
350     if (disc) {
351         FREE_NOT_NULL(disc->title);
352         if (title) {
353             disc->title = strdup(title);
354         }
355     }
356 }
357 
cddb_disc_append_title(cddb_disc_t * disc,const char * title)358 void cddb_disc_append_title(cddb_disc_t *disc, const char *title)
359 {
360     int old_len = 0, len;
361 
362     if (disc && title) {
363         /* only append if there is something to append */
364         if (disc->title) {
365             old_len = strlen(disc->title);
366         }
367         len = strlen(title);
368         disc->title = realloc(disc->title, old_len+len+1);
369         strcpy(disc->title+old_len, title);
370         disc->title[old_len+len] = '\0';
371     }
372 }
373 
cddb_disc_get_artist(const cddb_disc_t * disc)374 const char *cddb_disc_get_artist(const cddb_disc_t *disc)
375 {
376     const char *artist = NULL;
377 
378     if (disc) {
379         artist = disc->artist;
380     }
381     RETURN_STR_OR_EMPTY(artist);
382 }
383 
cddb_disc_set_artist(cddb_disc_t * disc,const char * artist)384 void cddb_disc_set_artist(cddb_disc_t *disc, const char *artist)
385 {
386     if (disc) {
387         FREE_NOT_NULL(disc->artist);
388         if (artist) {
389             disc->artist = strdup(artist);
390         }
391     }
392 }
393 
cddb_disc_append_artist(cddb_disc_t * disc,const char * artist)394 void cddb_disc_append_artist(cddb_disc_t *disc, const char *artist)
395 {
396     int old_len = 0, len;
397 
398     if (disc && artist) {
399         /* only append if there is something to append */
400         if (disc->artist) {
401             old_len = strlen(disc->artist);
402         }
403         len = strlen(artist);
404         disc->artist = realloc(disc->artist, old_len+len+1);
405         strcpy(disc->artist+old_len, artist);
406         disc->artist[old_len+len] = '\0';
407     }
408 }
409 
cddb_disc_get_ext_data(const cddb_disc_t * disc)410 const char *cddb_disc_get_ext_data(const cddb_disc_t *disc)
411 {
412     const char *ext_data = NULL;
413 
414     if (disc) {
415         ext_data = disc->ext_data;
416     }
417     RETURN_STR_OR_EMPTY(ext_data);
418 }
419 
cddb_disc_set_ext_data(cddb_disc_t * disc,const char * ext_data)420 void cddb_disc_set_ext_data(cddb_disc_t *disc, const char *ext_data)
421 {
422     if (disc) {
423         FREE_NOT_NULL(disc->ext_data);
424         if (ext_data) {
425             disc->ext_data = strdup(ext_data);
426         }
427     }
428 }
429 
cddb_disc_append_ext_data(cddb_disc_t * disc,const char * ext_data)430 void cddb_disc_append_ext_data(cddb_disc_t *disc, const char *ext_data)
431 {
432     int old_len = 0, len;
433 
434     if (disc && ext_data) {
435         /* only append if there is something to append */
436         if (disc->ext_data) {
437             old_len = strlen(disc->ext_data);
438         }
439         len = strlen(ext_data);
440         disc->ext_data = realloc(disc->ext_data, old_len+len+1);
441         strcpy(disc->ext_data+old_len, ext_data);
442         disc->ext_data[old_len+len] = '\0';
443     }
444 }
445 
446 
447 /* --- miscellaneous */
448 
449 
cddb_disc_copy(cddb_disc_t * dst,cddb_disc_t * src)450 void cddb_disc_copy(cddb_disc_t *dst, cddb_disc_t *src)
451 {
452     cddb_track_t *src_track, *dst_track;
453 
454     cddb_log_debug("cddb_disc_copy()");
455     if (src->discid != 0) {
456         dst->discid = src->discid;
457     }
458     if (src->category != CDDB_CAT_INVALID) {
459         dst->category = src->category;
460     }
461     if (src->year != 0) {
462         dst->year = src->year;
463     }
464     if (src->genre != NULL) {
465         FREE_NOT_NULL(dst->genre);
466         dst->genre = strdup(src->genre);
467     }
468     if (src->title != NULL) {
469         FREE_NOT_NULL(dst->title);
470         dst->title = strdup(src->title);
471     }
472     if (src->artist) {
473         FREE_NOT_NULL(dst->artist);
474         dst->artist = strdup(src->artist);
475     }
476     if (src->length != 0) {
477         dst->length = src->length;
478     }
479     if (src->revision != 0) {
480         dst->revision = src->revision;
481     }
482     if (src->ext_data != NULL) {
483         FREE_NOT_NULL(dst->ext_data);
484         dst->ext_data = strdup(src->ext_data);
485     }
486     /* copy the tracks */
487     src_track = src->tracks;
488     dst_track = dst->tracks;
489     while (src_track) {
490         if (dst_track == NULL) {
491             dst_track = cddb_track_new();
492             cddb_disc_add_track(dst, dst_track);
493         }
494         cddb_track_copy(dst_track, src_track);
495         src_track = src_track->next;
496         dst_track = dst_track->next;
497     }
498 }
499 
cddb_disc_calc_discid(cddb_disc_t * disc)500 int cddb_disc_calc_discid(cddb_disc_t *disc)
501 {
502     long result = 0;
503     long tmp;
504     cddb_track_t *track, *first;
505 
506     cddb_log_debug("cddb_disc_calc_discid()");
507     for (first = track = cddb_disc_get_track_first(disc);
508          track != NULL;
509          track = cddb_disc_get_track_next(disc)) {
510         tmp = FRAMES_TO_SECONDS(track->frame_offset);
511         do {
512             result += tmp % 10;
513             tmp /= 10;
514         } while (tmp != 0);
515     }
516 
517     if (first == NULL) {
518         /* set disc id to zero if there are no tracks */
519         disc->discid = 0;
520     } else {
521         /* first byte is offsets of tracks
522          * 2 next bytes total length in seconds
523          * last byte is nr of tracks
524          */
525         disc->discid = (result % 0xff) << 24 |
526                        (disc->length - FRAMES_TO_SECONDS(first->frame_offset)) << 8 |
527                        disc->track_cnt;
528     }
529     cddb_log_debug("...Disc ID: %08x", disc->discid);
530 
531     return TRUE;
532 }
533 
cddb_disc_print(cddb_disc_t * disc)534 void cddb_disc_print(cddb_disc_t *disc)
535 {
536     cddb_track_t *track;
537     int cnt;
538 
539     printf("Disc ID: %08x\n", disc->discid);
540     printf("CDDB category: %s (%d)\n", CDDB_CATEGORY[disc->category], disc->category);
541     printf("Music genre: '%s'\n", STR_OR_NULL(disc->genre));
542     printf("Year: %d\n", disc->year);
543     printf("Artist: '%s'\n", STR_OR_NULL(disc->artist));
544     printf("Title: '%s'\n", STR_OR_NULL(disc->title));
545     printf("Extended data: '%s'\n", STR_OR_NULL(disc->ext_data));
546     printf("Length: %d seconds\n", disc->length);
547     printf("Revision: %d\n", disc->revision);
548     printf("Number of tracks: %d\n", disc->track_cnt);
549     track = disc->tracks;
550     cnt = 1;
551     while (track) {
552         printf("  Track %2d\n", cnt);
553         cddb_track_print(track);
554         track = track->next;
555         cnt++;
556     }
557 }
558