tremor uses integer types
[mplayer/glamo.git] / libmpdemux / cddb.c
blob6bca6a87caaf324f84cadba2172c4944bfcaedab
1 /*
2 * CDDB HTTP protocol
3 * by Bertrand Baudet <bertrand_baudet@yahoo.com>
4 * (C) 2002, MPlayer team.
6 * Implementation follow the freedb.howto1.06.txt specification
7 * from http://freedb.freedb.org
8 *
9 * discid computation by Jeremy D. Zawodny
10 * Copyright (c) 1998-2000 Jeremy D. Zawodny <Jeremy@Zawodny.com>
11 * Code release under GPL
15 #include "config.h"
17 #if defined(HAVE_CDDA) && defined(MPLAYER_NETWORK)
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <fcntl.h>
22 #include <stdarg.h>
23 #include <errno.h>
24 #include <netdb.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <sys/ioctl.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
31 #if defined(__linux__)
32 #include <linux/cdrom.h>
33 #elif defined(__FreeBSD__) || defined(__bsdi__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
34 #include <sys/cdio.h>
35 #endif
37 #include "cdd.h"
38 #include "../version.h"
39 #include "stream.h"
40 #include "network.h"
42 #define DEFAULT_FREEDB_SERVER "freedb.freedb.org"
43 #define DEFAULT_CACHE_DIR "/.cddb/"
45 stream_t* open_cdda(char *dev, char *track);
47 static cd_toc_t cdtoc[100];
49 #if defined(__linux__)
50 int
51 read_toc(const char *dev) {
52 int drive;
53 struct cdrom_tochdr tochdr;
54 struct cdrom_tocentry tocentry;
55 int i;
57 drive = open(dev, O_RDONLY | O_NONBLOCK);
58 if( drive<0 ) {
59 return drive;
62 ioctl(drive, CDROMREADTOCHDR, &tochdr);
63 for (i = tochdr.cdth_trk0; i <= tochdr.cdth_trk1; i++) {
64 tocentry.cdte_track = i;
65 tocentry.cdte_format = CDROM_MSF;
66 ioctl(drive, CDROMREADTOCENTRY, &tocentry);
67 cdtoc[i-1].min = tocentry.cdte_addr.msf.minute;
68 cdtoc[i-1].sec = tocentry.cdte_addr.msf.second;
69 cdtoc[i-1].frame = tocentry.cdte_addr.msf.frame;
70 cdtoc[i-1].frame += cdtoc[i-1].min*60*75;
71 cdtoc[i-1].frame += cdtoc[i-1].sec*75;
73 tocentry.cdte_track = 0xAA;
74 tocentry.cdte_format = CDROM_MSF;
75 ioctl(drive, CDROMREADTOCENTRY, &tocentry);
76 cdtoc[tochdr.cdth_trk1].min = tocentry.cdte_addr.msf.minute;
77 cdtoc[tochdr.cdth_trk1].sec = tocentry.cdte_addr.msf.second;
78 cdtoc[tochdr.cdth_trk1].frame = tocentry.cdte_addr.msf.frame;
79 cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].min*60*75;
80 cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].sec*75;
81 close(drive);
82 return tochdr.cdth_trk1;
85 #elif defined(__FreeBSD__) || defined(__bsdi__) || defined(__DragonFly__)
86 int
87 read_toc(const char *dev) {
88 int drive;
89 struct ioc_toc_header tochdr;
90 struct ioc_read_toc_single_entry tocentry;
91 int i;
93 drive = open(dev, O_RDONLY | O_NONBLOCK);
94 if( drive<0 ) {
95 return drive;
98 ioctl(drive, CDIOREADTOCHEADER, &tochdr);
99 for (i = tochdr.starting_track; i <= tochdr.ending_track; i++) {
100 tocentry.track = i;
101 tocentry.address_format = CD_MSF_FORMAT;
102 ioctl(drive, CDIOREADTOCENTRY, &tocentry);
103 cdtoc[i-1].min = tocentry.entry.addr.msf.minute;
104 cdtoc[i-1].sec = tocentry.entry.addr.msf.second;
105 cdtoc[i-1].frame = tocentry.entry.addr.msf.frame;
106 cdtoc[i-1].frame += cdtoc[i-1].min*60*75;
107 cdtoc[i-1].frame += cdtoc[i-1].sec*75;
109 tocentry.track = 0xAA;
110 tocentry.address_format = CD_MSF_FORMAT;
111 ioctl(drive, CDIOREADTOCENTRY, &tocentry);
112 cdtoc[tochdr.ending_track].min = tocentry.entry.addr.msf.minute;
113 cdtoc[tochdr.ending_track].sec = tocentry.entry.addr.msf.second;
114 cdtoc[tochdr.ending_track].frame = tocentry.entry.addr.msf.frame;
115 cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].min*60*75;
116 cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].sec*75;
117 close(drive);
118 return tochdr.ending_track;
121 #elif defined(__NetBSD__) || defined(__OpenBSD__)
123 read_toc(const char *dev) {
124 int drive;
125 struct ioc_toc_header tochdr;
126 struct ioc_read_toc_entry tocentry;
127 int i;
128 struct cd_toc_entry toc_buffer;
130 drive = open(dev, O_RDONLY | O_NONBLOCK);
131 if( drive<0 ) {
132 return drive;
135 ioctl(drive, CDIOREADTOCHEADER, &tochdr);
136 for (i = tochdr.starting_track; i <= tochdr.ending_track; i++) {
137 tocentry.starting_track = i;
138 tocentry.address_format = CD_MSF_FORMAT;
139 tocentry.data = &toc_buffer;
140 tocentry.data_len = sizeof(toc_buffer);
141 ioctl(drive, CDIOREADTOCENTRYS, &tocentry);
142 cdtoc[i-1].min = toc_buffer.addr.msf.minute;
143 cdtoc[i-1].sec = toc_buffer.addr.msf.second;
144 cdtoc[i-1].frame = toc_buffer.addr.msf.frame;
145 cdtoc[i-1].frame += cdtoc[i-1].min*60*75;
146 cdtoc[i-1].frame += cdtoc[i-1].sec*75;
148 tocentry.starting_track = 0xAA;
149 tocentry.address_format = CD_MSF_FORMAT;
150 ioctl(drive, CDIOREADTOCENTRYS, &tocentry);
151 cdtoc[tochdr.ending_track].min = toc_buffer.addr.msf.minute;
152 cdtoc[tochdr.ending_track].sec = toc_buffer.addr.msf.second;
153 cdtoc[tochdr.ending_track].frame = toc_buffer.addr.msf.frame;
154 cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].min*60*75;
155 cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].sec*75;
156 close(drive);
157 return tochdr.ending_track;
159 #endif
161 unsigned int
162 cddb_sum(int n) {
163 unsigned int ret;
165 ret = 0;
166 while (n > 0) {
167 ret += (n % 10);
168 n /= 10;
170 return ret;
173 unsigned long
174 cddb_discid(int tot_trks) {
175 unsigned int i, t = 0, n = 0;
177 i = 0;
178 while (i < (unsigned int)tot_trks) {
179 n = n + cddb_sum((cdtoc[i].min * 60) + cdtoc[i].sec);
180 i++;
182 t = ((cdtoc[tot_trks].min * 60) + cdtoc[tot_trks].sec) -
183 ((cdtoc[0].min * 60) + cdtoc[0].sec);
184 return ((n % 0xff) << 24 | t << 8 | tot_trks);
190 cddb_http_request(char *command, int (*reply_parser)(HTTP_header_t*,cddb_data_t*), cddb_data_t *cddb_data) {
191 char request[4096];
192 int fd, ret = 0;
193 URL_t *url;
194 HTTP_header_t *http_hdr;
196 if( reply_parser==NULL || command==NULL || cddb_data==NULL ) return -1;
198 sprintf( request, "http://%s/~cddb/cddb.cgi?cmd=%s%s&proto=%d", cddb_data->freedb_server, command, cddb_data->cddb_hello, cddb_data->freedb_proto_level );
199 printf("Request[%s]\n", request );
201 url = url_new(request);
202 if( url==NULL ) {
203 printf("Not a valid URL\n");
204 return -1;
207 fd = http_send_request(url,0);
208 if( fd<0 ) {
209 printf("failed to send the http request\n");
210 return -1;
213 http_hdr = http_read_response( fd );
214 if( http_hdr==NULL ) {
215 printf("Failed to read the http response\n");
216 return -1;
219 http_debug_hdr(http_hdr);
220 printf("body=[%s]\n", http_hdr->body );
222 switch(http_hdr->status_code) {
223 case 200:
224 ret = reply_parser(http_hdr, cddb_data);
225 break;
226 case 400:
227 printf("Not Found\n");
228 break;
229 default:
230 printf("Unknown Error code\n");
233 http_free( http_hdr );
234 url_free( url );
236 return ret;
240 cddb_read_cache(cddb_data_t *cddb_data) {
241 char file_name[100];
242 struct stat stats;
243 int file_fd, ret;
244 size_t file_size;
246 if( cddb_data==NULL || cddb_data->cache_dir==NULL ) return -1;
248 sprintf( file_name, "%s%08lx", cddb_data->cache_dir, cddb_data->disc_id);
250 file_fd = open(file_name, O_RDONLY);
251 if( file_fd<0 ) {
252 printf("No cache found\n");
253 return -1;
256 ret = fstat( file_fd, &stats );
257 if( ret<0 ) {
258 perror("fstat");
259 file_size = 4096;
260 } else {
261 file_size = stats.st_size;
264 cddb_data->xmcd_file = (char*)malloc(file_size);
265 if( cddb_data->xmcd_file==NULL ) {
266 printf("Memory allocation failed\n");
267 close(file_fd);
268 return -1;
270 cddb_data->xmcd_file_size = read(file_fd, cddb_data->xmcd_file, file_size);
271 if( cddb_data->xmcd_file_size!=file_size ) {
272 printf("Not all the xmcd file has been read\n");
273 close(file_fd);
274 return -1;
277 close(file_fd);
279 return 0;
283 cddb_write_cache(cddb_data_t *cddb_data) {
284 // We have the file, save it for cache.
285 struct stat file_stat;
286 char file_name[100];
287 int file_fd, ret;
288 int wrote=0;
290 if( cddb_data==NULL || cddb_data->cache_dir==NULL ) return -1;
292 // Check if the CDDB cache dir exist
293 ret = stat( cddb_data->cache_dir, &file_stat );
294 if( ret<0 ) {
295 // Directory not present, create it.
296 ret = mkdir( cddb_data->cache_dir, 0755 );
297 if( ret<0 ) {
298 perror("mkdir");
299 printf("Failed to create directory %s\n", cddb_data->cache_dir );
300 return -1;
304 sprintf( file_name, "%s%08lx", cddb_data->cache_dir, cddb_data->disc_id );
306 file_fd = creat(file_name, S_IREAD|S_IWRITE);
307 if( file_fd<0 ) {
308 perror("create");
309 return -1;
312 wrote = write(file_fd, cddb_data->xmcd_file, cddb_data->xmcd_file_size);
313 if( wrote<0 ) {
314 perror("write");
315 close(file_fd);
316 return -1;
318 if( (unsigned int)wrote!=cddb_data->xmcd_file_size ) {
319 printf("Not all the xmcd file has been written\n");
320 close(file_fd);
321 return -1;
324 close(file_fd);
326 return 0;
330 cddb_read_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
331 unsigned long disc_id;
332 char category[100];
333 char *ptr=NULL, *ptr2=NULL;
334 int ret, status;
336 if( http_hdr==NULL || cddb_data==NULL ) return -1;
338 ret = sscanf( http_hdr->body, "%d ", &status);
339 if( ret!=1 ) {
340 printf("Parse error\n");
341 return -1;
344 switch(status) {
345 case 210:
346 ret = sscanf( http_hdr->body, "%d %s %08lx", &status, category, &disc_id);
347 if( ret!=3 ) {
348 printf("Parse error\n");
349 return -1;
351 // Check if it's a xmcd database file
352 ptr = strstr(http_hdr->body, "# xmcd");
353 if( ptr==NULL ) {
354 printf("Invalid xmcd database file returned\n");
355 return -1;
357 // Ok found the beginning of the file
358 // look for the end
359 ptr2 = strstr(ptr, "\r\n.\r\n");
360 if( ptr2==NULL ) {
361 ptr2 = strstr(ptr, "\n.\n");
362 if( ptr2==NULL ) {
363 printf("Unable to find '.'\n");
364 ptr2=ptr+strlen(ptr); //return -1;
367 // Ok found the end
368 // do a sanity check
369 if( http_hdr->body_size<(unsigned int)(ptr2-ptr) ) {
370 printf("Unexpected fix me\n");
371 return -1;
373 cddb_data->xmcd_file = ptr;
374 cddb_data->xmcd_file_size = ptr2-ptr+2;
375 cddb_data->xmcd_file[cddb_data->xmcd_file_size] = '\0';
376 // Avoid the http_free function to free the xmcd file...save a mempcy...
377 http_hdr->body = NULL;
378 http_hdr->body_size = 0;
379 return cddb_write_cache(cddb_data);
380 default:
381 printf("Unhandled code\n");
383 return 0;
387 cddb_request_titles(cddb_data_t *cddb_data) {
388 char command[1024];
389 sprintf( command, "cddb+read+%s+%08lx", cddb_data->category, cddb_data->disc_id);
390 return cddb_http_request(command, cddb_read_parse, cddb_data);
394 cddb_parse_matches_list(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
395 char album_title[100];
396 char *ptr = NULL;
397 int ret;
399 ptr = strstr(http_hdr->body, "\n");
400 if( ptr==NULL ) {
401 printf("Unable to find end of line\n");
402 return -1;
404 ptr++;
405 // We have a list of exact/inexact matches, so which one do we use?
406 // So let's take the first one.
407 ret = sscanf(ptr, "%s %08lx %s", cddb_data->category, &(cddb_data->disc_id), album_title);
408 if( ret!=3 ) {
409 printf("Parse error\n");
410 return -1;
412 ptr = strstr(http_hdr->body, album_title);
413 if( ptr!=NULL ) {
414 char *ptr2;
415 int len;
416 ptr2 = strstr(ptr, "\n");
417 if( ptr2==NULL ) {
418 len = (http_hdr->body_size)-(ptr-(http_hdr->body));
419 } else {
420 len = ptr2-ptr+1;
422 strncpy(album_title, ptr, len);
423 album_title[len-2]='\0';
425 printf("Parse OK, found: %s\n", album_title);
426 return 0;
430 cddb_query_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
431 char album_title[100];
432 char *ptr = NULL;
433 int ret, status;
435 ret = sscanf( http_hdr->body, "%d ", &status);
436 if( ret!=1 ) {
437 printf("Parse error\n");
438 return -1;
441 switch(status) {
442 case 200:
443 // Found exact match
444 ret = sscanf(http_hdr->body, "%d %s %08lx %s", &status, cddb_data->category, &(cddb_data->disc_id), album_title);
445 if( ret!=4 ) {
446 printf("Parse error\n");
447 return -1;
449 ptr = strstr(http_hdr->body, album_title);
450 if( ptr!=NULL ) {
451 char *ptr2;
452 int len;
453 ptr2 = strstr(ptr, "\n");
454 if( ptr2==NULL ) {
455 len = (http_hdr->body_size)-(ptr-(http_hdr->body));
456 } else {
457 len = ptr2-ptr+1;
459 strncpy(album_title, ptr, len);
460 album_title[len-2]='\0';
462 printf("Parse OK, found: %s\n", album_title);
463 return cddb_request_titles(cddb_data);
464 case 202:
465 // No match found
466 printf("Album not found\n");
467 break;
468 case 210:
469 // Found exact matches, list follows
470 cddb_parse_matches_list(http_hdr, cddb_data);
471 return cddb_request_titles(cddb_data);
473 body=[210 Found exact matches, list follows (until terminating `.')
474 misc c711930d Santana / Supernatural
475 rock c711930d Santana / Supernatural
476 blues c711930d Santana / Supernatural
479 case 211:
480 // Found inexact matches, list follows
481 cddb_parse_matches_list(http_hdr, cddb_data);
482 return cddb_request_titles(cddb_data);
483 case 500:
484 printf("Server returns: Command syntax error\n");
485 break;
486 default:
487 printf("Unhandled code\n");
489 return -1;
493 cddb_proto_level_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
494 int max;
495 int ret, status;
496 char *ptr;
498 ret = sscanf( http_hdr->body, "%d ", &status);
499 if( ret!=1 ) {
500 printf("Parse error\n");
501 return -1;
504 switch(status) {
505 case 210:
506 ptr = strstr(http_hdr->body, "max proto:");
507 if( ptr==NULL ) {
508 printf("Parse error\n");
509 return -1;
511 ret = sscanf(ptr, "max proto: %d", &max);
512 if( ret!=1 ) {
513 printf("Parse error\n");
514 return -1;
516 cddb_data->freedb_proto_level = max;
517 return 0;
518 default:
519 printf("Unhandled code\n");
521 return -1;
525 cddb_get_proto_level(cddb_data_t *cddb_data) {
526 return cddb_http_request("stat", cddb_proto_level_parse, cddb_data);
530 cddb_freedb_sites_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) {
531 int ret, status;
533 ret = sscanf( http_hdr->body, "%d ", &status);
534 if( ret!=1 ) {
535 printf("Parse error\n");
536 return -1;
539 switch(status) {
540 case 210:
541 // TODO: Parse the sites
542 ret = cddb_data->anonymous; // For gcc complaining about unused parameter.
543 return 0;
544 case 401:
545 printf("No sites information available\n");
546 break;
547 default:
548 printf("Unhandled code\n");
550 return -1;
554 cddb_get_freedb_sites(cddb_data_t *cddb_data) {
555 return cddb_http_request("sites", cddb_freedb_sites_parse, cddb_data);
558 void
559 cddb_create_hello(cddb_data_t *cddb_data) {
560 char host_name[51];
561 char *user_name;
563 if( cddb_data->anonymous ) { // Default is anonymous
564 /* Note from Eduardo PĂ©rez Ureta <eperez@it.uc3m.es> :
565 * We don't send current user/host name in hello to prevent spam.
566 * Software that sends this is considered spyware
567 * that most people don't like.
569 user_name = "anonymous";
570 strcpy(host_name, "localhost");
571 } else {
572 if( gethostname(host_name, 50)<0 ) {
573 strcpy(host_name, "localhost");
575 user_name = getenv("LOGNAME");
577 sprintf( cddb_data->cddb_hello, "&hello=%s+%s+%s+%s", user_name, host_name, "MPlayer", VERSION );
580 int
581 cddb_retrieve(cddb_data_t *cddb_data) {
582 char offsets[1024], command[1024];
583 char *ptr;
584 unsigned int i, time_len;
585 int ret;
587 ptr = offsets;
588 for( i=0; i<cddb_data->tracks ; i++ ) {
589 ptr += sprintf(ptr, "%d+", cdtoc[i].frame );
590 if (ptr-offsets > sizeof offsets - 40) break;
592 ptr[0]=0;
593 time_len = (cdtoc[cddb_data->tracks].frame)/75;
595 cddb_data->freedb_server = DEFAULT_FREEDB_SERVER;
596 cddb_data->freedb_proto_level = 1;
597 cddb_data->xmcd_file = NULL;
599 cddb_create_hello(cddb_data);
600 if( cddb_get_proto_level(cddb_data)<0 ) {
601 printf("Failed to get the protocol level\n");
602 return -1;
605 //cddb_get_freedb_sites(&cddb_data);
607 sprintf(command, "cddb+query+%08lx+%d+%s%d", cddb_data->disc_id, cddb_data->tracks, offsets, time_len );
608 ret = cddb_http_request(command, cddb_query_parse, cddb_data);
609 if( ret<0 ) return -1;
611 if( cddb_data->cache_dir!=NULL ) {
612 free(cddb_data->cache_dir);
614 return 0;
618 cddb_resolve(const char *dev, char **xmcd_file) {
619 char cddb_cache_dir[] = DEFAULT_CACHE_DIR;
620 char *home_dir = NULL;
621 cddb_data_t cddb_data;
622 int ret;
624 ret = read_toc(dev);
625 if( ret<0 ) {
626 printf("Failed to open %s device.\n", dev);
627 return -1;
629 cddb_data.tracks = ret;
630 cddb_data.disc_id = cddb_discid(cddb_data.tracks);
631 cddb_data.anonymous = 1; // Don't send user info by default
633 // Check if there is a CD in the drive
634 // FIXME: That's not really a good way to check
635 if( cddb_data.disc_id==0 ) {
636 printf("No CD in the drive\n");
637 return -1;
640 home_dir = getenv("HOME");
641 if( home_dir==NULL ) {
642 cddb_data.cache_dir = NULL;
643 } else {
644 cddb_data.cache_dir = (char*)malloc(strlen(home_dir)+strlen(cddb_cache_dir)+1);
645 if( cddb_data.cache_dir==NULL ) {
646 printf("Memory allocation failed\n");
647 return -1;
649 sprintf(cddb_data.cache_dir, "%s%s", home_dir, cddb_cache_dir );
652 // Check for a cached file
653 if( cddb_read_cache(&cddb_data)<0 ) {
654 // No Cache found
655 if( cddb_retrieve(&cddb_data)<0 ) {
656 return -1;
660 if( cddb_data.xmcd_file!=NULL ) {
661 // printf("%s\n", cddb_data.xmcd_file );
662 *xmcd_file = cddb_data.xmcd_file;
663 return 0;
666 return -1;
669 /*******************************************************************************************************************
671 * xmcd parser
673 *******************************************************************************************************************/
674 char*
675 xmcd_parse_dtitle(cd_info_t *cd_info, char *line) {
676 char *ptr, *album;
677 ptr = strstr(line, "DTITLE=");
678 if( ptr!=NULL ) {
679 ptr += 7;
680 album = strstr(ptr, "/");
681 if( album==NULL ) return NULL;
682 cd_info->album = (char*)malloc(strlen(album+2)+1);
683 if( cd_info->album==NULL ) {
684 return NULL;
686 strcpy( cd_info->album, album+2 );
687 album--;
688 album[0] = '\0';
689 cd_info->artist = (char*)malloc(strlen(ptr)+1);
690 if( cd_info->artist==NULL ) {
691 return NULL;
693 strcpy( cd_info->artist, ptr );
695 return ptr;
698 char*
699 xmcd_parse_dgenre(cd_info_t *cd_info, char *line) {
700 char *ptr;
701 ptr = strstr(line, "DGENRE=");
702 if( ptr!=NULL ) {
703 ptr += 7;
704 cd_info->genre = (char*)malloc(strlen(ptr)+1);
705 if( cd_info->genre==NULL ) {
706 return NULL;
708 strcpy( cd_info->genre, ptr );
710 return ptr;
713 char*
714 xmcd_parse_ttitle(cd_info_t *cd_info, char *line) {
715 unsigned int track_nb;
716 unsigned long sec, off;
717 char *ptr;
718 ptr = strstr(line, "TTITLE");
719 if( ptr!=NULL ) {
720 ptr += 6;
721 // Here we point to the track number
722 track_nb = atoi(ptr);
723 ptr = strstr(ptr, "=");
724 if( ptr==NULL ) return NULL;
725 ptr++;
727 sec = cdtoc[track_nb].frame;
728 off = cdtoc[track_nb+1].frame-sec+1;
730 cd_info_add_track( cd_info, ptr, track_nb+1, (unsigned int)(off/(60*75)), (unsigned int)((off/75)%60), (unsigned int)(off%75), sec, off );
732 return ptr;
735 cd_info_t*
736 cddb_parse_xmcd(char *xmcd_file) {
737 cd_info_t *cd_info = NULL;
738 int length, pos = 0;
739 char *ptr, *ptr2;
740 unsigned int audiolen;
741 if( xmcd_file==NULL ) return NULL;
743 cd_info = cd_info_new();
744 if( cd_info==NULL ) {
745 return NULL;
748 length = strlen(xmcd_file);
749 ptr = xmcd_file;
750 while( ptr!=NULL && pos<length ) {
751 // Read a line
752 ptr2 = ptr;
753 while( ptr2[0]!='\0' && ptr2[0]!='\r' && ptr2[0]!='\n' ) ptr2++;
754 if( ptr2[0]=='\0' ) {
755 break;
757 ptr2[0] = '\0';
758 // Ignore comments
759 if( ptr[0]!='#' ) {
760 // Search for the album title
761 if( xmcd_parse_dtitle(cd_info, ptr) );
762 // Search for the genre
763 else if( xmcd_parse_dgenre(cd_info, ptr) );
764 // Search for a track title
765 else if( xmcd_parse_ttitle(cd_info, ptr) ) audiolen++; // <-- audiolen++ to shut up gcc warning
767 if( ptr2[1]=='\n' ) ptr2++;
768 pos = (ptr2+1)-ptr;
769 ptr = ptr2+1;
772 audiolen = cdtoc[cd_info->nb_tracks].frame-cdtoc[0].frame;
773 cd_info->min = (unsigned int)(audiolen/(60*75));
774 cd_info->sec = (unsigned int)((audiolen/75)%60);
775 cd_info->msec = (unsigned int)(audiolen%75);
777 return cd_info;
780 #endif