diff options
Diffstat (limited to 'src/input/input_cdda.c')
-rw-r--r-- | src/input/input_cdda.c | 897 |
1 files changed, 479 insertions, 418 deletions
diff --git a/src/input/input_cdda.c b/src/input/input_cdda.c index fd4dd1fa9..1751f031c 100644 --- a/src/input/input_cdda.c +++ b/src/input/input_cdda.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2005 the xine project + * Copyright (C) 2000-2008 the xine project * * This file is part of xine, a free video player. * @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * - * Compact Disc Digital Audio (CDDA) Input Plugin + * Compact Disc Digital Audio (CDDA) Input Plugin * by Mike Melanson (melanson@pcisys.net) */ @@ -44,6 +44,7 @@ # include <sys/ioctl.h> #else /* for WIN32 */ +# include <windef.h> # include <winioctl.h> #endif @@ -70,6 +71,8 @@ #define DEFAULT_CDDA_DEVICE "/vol/dev/aliases/cdrom0" #elif defined(WIN32) #define DEFAULT_CDDA_DEVICE "d:\\" +#elif defined(__OpenBSD__) +#define DEFAULT_CDDA_DEVICE "/dev/rcd0c" #else #define DEFAULT_CDDA_DEVICE "/dev/cdrom" #endif @@ -110,7 +113,7 @@ typedef struct _cdrom_toc { *************************************************************************/ #define MAX_TRACKS 99 -#define CACHED_FRAMES 500 +#define CACHED_FRAMES 100 typedef struct { int start; @@ -126,8 +129,8 @@ typedef struct { int enabled; char *server; int port; - char *cache_dir; - + char *cache_dir; + char *cdiscid; char *disc_title; char *disc_year; @@ -135,7 +138,7 @@ typedef struct { char *disc_category; int fd; - unsigned long disc_id; + uint32_t disc_id; int disc_length; trackinfo_t *track; @@ -175,7 +178,7 @@ typedef struct { char *cdda_device; int cddb_error; - + cdda_input_plugin_t *ip; int show_hidden_files; @@ -183,7 +186,7 @@ typedef struct { int mrls_allocated_entries; xine_mrl_t **mrls; - + char *autoplaylist[MAX_TRACKS]; } cdda_input_class_t; @@ -315,54 +318,54 @@ struct SRB_ExecSCSICmd #ifdef LOG static void print_cdrom_toc(cdrom_toc *toc) { - + int i; int time1; int time2; int timediff; - + printf("\ntoc:\n"); printf("\tfirst track = %d\n", toc->first_track); printf("\tlast track = %d\n", toc->last_track); printf("\ttotal tracks = %d\n", toc->total_tracks); printf("\ntoc entries:\n"); - - + + printf("leadout track: Control: %d MSF: %02d:%02d:%04d, first frame = %d\n", toc->leadout_track.track_mode, toc->leadout_track.first_frame_minute, toc->leadout_track.first_frame_second, toc->leadout_track.first_frame_frame, toc->leadout_track.first_frame); - + /* fetch each toc entry */ - if (toc->first_track > 0) { - for (i = toc->first_track; i <= toc->last_track; i++) { + if (toc->first_track > 0) { + for (i = toc->first_track; i <= toc->last_track; i++) { printf("\ttrack mode = %d", toc->toc_entries[i-1].track_mode); - printf("\ttrack %d, audio, MSF: %02d:%02d:%02d, first frame = %d\n", - i, + printf("\ttrack %d, audio, MSF: %02d:%02d:%02d, first frame = %d\n", + i, toc->toc_entries[i-1].first_frame_minute, toc->toc_entries[i-1].first_frame_second, toc->toc_entries[i-1].first_frame_frame, toc->toc_entries[i-1].first_frame); - - time1 = ((toc->toc_entries[i-1].first_frame_minute * 60) + + + time1 = ((toc->toc_entries[i-1].first_frame_minute * 60) + toc->toc_entries[i-1].first_frame_second); - + if (i == toc->last_track) { time2 = ((toc->leadout_track.first_frame_minute * 60) + toc->leadout_track.first_frame_second); } else { - time2 = ((toc->toc_entries[i].first_frame_minute * 60) + + time2 = ((toc->toc_entries[i].first_frame_minute * 60) + toc->toc_entries[i].first_frame_second); } - + timediff = time2 - time1; - + printf("\t time: %02d:%02d\n", timediff/60, timediff%60); } - } + } } #endif @@ -370,7 +373,7 @@ static cdrom_toc * init_cdrom_toc(void) { cdrom_toc *toc; - toc = (cdrom_toc *) xine_xmalloc(sizeof (cdrom_toc)); + toc = calloc(1, sizeof (cdrom_toc)); toc->first_track = toc->last_track = toc->total_tracks = 0; toc->toc_entries = NULL; @@ -416,12 +419,11 @@ static int read_cdrom_toc(int fd, cdrom_toc *toc) { toc->ignore_last_track = 0; } toc->total_tracks = toc->last_track - toc->first_track + 1; - + /* allocate space for the toc entries */ - toc->toc_entries = - (cdrom_toc_entry *)malloc(toc->total_tracks * sizeof(cdrom_toc_entry)); + toc->toc_entries = calloc(toc->total_tracks, sizeof(cdrom_toc_entry)); if (!toc->toc_entries) { - perror("malloc"); + perror("calloc"); return -1; } @@ -529,10 +531,9 @@ static int read_cdrom_toc(int fd, cdrom_toc *toc) { toc->total_tracks = toc->last_track - toc->first_track + 1; /* allocate space for the toc entries */ - toc->toc_entries = - (cdrom_toc_entry *)malloc(toc->total_tracks * sizeof(cdrom_toc_entry)); + toc->toc_entries = calloc(toc->total_tracks, sizeof(cdrom_toc_entry)); if (!toc->toc_entries) { - perror("malloc"); + perror("calloc"); return -1; } @@ -612,7 +613,7 @@ static int read_cdrom_frames(cdda_input_plugin_t *this_gen, int frame, int num_f return 0; } -#elif defined(__FreeBSD_kernel__) || defined(__NetBSD__) +#elif defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) #include <sys/cdio.h> @@ -625,7 +626,7 @@ static int read_cdrom_toc(int fd, cdrom_toc *toc) { struct ioc_toc_header tochdr; #if defined(__FreeBSD_kernel__) struct ioc_read_toc_single_entry tocentry; -#elif defined(__NetBSD__) +#elif defined(__NetBSD__) || defined(__OpenBSD__) struct ioc_read_toc_entry tocentry; struct cd_toc_entry data; #endif @@ -642,10 +643,9 @@ static int read_cdrom_toc(int fd, cdrom_toc *toc) { toc->total_tracks = toc->last_track - toc->first_track + 1; /* allocate space for the toc entries */ - toc->toc_entries = - (cdrom_toc_entry *)malloc(toc->total_tracks * sizeof(cdrom_toc_entry)); + toc->toc_entries = calloc(toc->total_tracks, sizeof(cdrom_toc_entry)); if (!toc->toc_entries) { - perror("malloc"); + perror("calloc"); return -1; } @@ -661,7 +661,7 @@ static int read_cdrom_toc(int fd, cdrom_toc *toc) { perror("CDIOREADTOCENTRY"); return -1; } -#elif defined(__NetBSD__) +#elif defined(__NetBSD__) || defined(__OpenBSD__) memset(&data, 0, sizeof(data)); tocentry.data_len = sizeof(data); tocentry.data = &data; @@ -682,7 +682,7 @@ static int read_cdrom_toc(int fd, cdrom_toc *toc) { (tocentry.entry.addr.msf.minute * CD_SECONDS_PER_MINUTE * CD_FRAMES_PER_SECOND) + (tocentry.entry.addr.msf.second * CD_FRAMES_PER_SECOND) + tocentry.entry.addr.msf.frame; -#elif defined(__NetBSD__) +#elif defined(__NetBSD__) || defined(__OpenBSD__) toc->toc_entries[i-1].track_mode = (tocentry.data->control & 0x04) ? 1 : 0; toc->toc_entries[i-1].first_frame_minute = tocentry.data->addr.msf.minute; toc->toc_entries[i-1].first_frame_second = tocentry.data->addr.msf.second; @@ -704,7 +704,7 @@ static int read_cdrom_toc(int fd, cdrom_toc *toc) { perror("CDIOREADTOCENTRY"); return -1; } -#elif defined(__NetBSD__) +#elif defined(__NetBSD__) || defined(__OpenBSD__) memset(&data, 0, sizeof(data)); tocentry.data_len = sizeof(data); tocentry.data = &data; @@ -725,7 +725,7 @@ static int read_cdrom_toc(int fd, cdrom_toc *toc) { (tocentry.entry.addr.msf.minute * CD_SECONDS_PER_MINUTE * CD_FRAMES_PER_SECOND) + (tocentry.entry.addr.msf.second * CD_FRAMES_PER_SECOND) + tocentry.entry.addr.msf.frame; -#elif defined(__NetBSD__) +#elif defined(__NetBSD__) || defined(__OpenBSD__) toc->leadout_track.track_mode = (tocentry.data->control & 0x04) ? 1 : 0; toc->leadout_track.first_frame_minute = tocentry.data->addr.msf.minute; toc->leadout_track.first_frame_second = tocentry.data->addr.msf.second; @@ -763,7 +763,7 @@ static int read_cdrom_frames(cdda_input_plugin_t *this_gen, int frame, int num_f perror("CDIOCREADAUDIO"); return -1; } -#elif defined(__NetBSD__) +#elif defined(__NetBSD__) || defined(__OpenBSD__) scsireq_t req; int nblocks = 1; @@ -790,7 +790,7 @@ static int read_cdrom_frames(cdda_input_plugin_t *this_gen, int frame, int num_f return -1; } #endif - + data += CD_RAW_FRAME_SIZE; frame++; num_frames--; @@ -807,45 +807,44 @@ static int read_cdrom_toc(cdda_input_plugin_t *this_gen, cdrom_toc *toc) { /* This is for ASPI which obviously isn't supported! */ lprintf("Windows ASPI support is not complete yet!\n"); return -1; - + } else { DWORD dwBytesReturned; CDROM_TOC cdrom_toc; int i; - + if( DeviceIoControl( this_gen->h_device_handle, IOCTL_CDROM_READ_TOC, NULL, 0, &cdrom_toc, sizeof(CDROM_TOC), &dwBytesReturned, NULL ) == 0 ) { #ifdef LOG - DWORD dw; + DWORD dw; printf( "input_cdda: could not read TOCHDR\n" ); dw = GetLastError(); - printf("GetLastError returned %u\n", dw); + printf("GetLastError returned %u\n", dw); #endif return -1; } - + toc->first_track = cdrom_toc.FirstTrack; toc->last_track = cdrom_toc.LastTrack; toc->total_tracks = toc->last_track - toc->first_track + 1; - + /* allocate space for the toc entries */ - toc->toc_entries = - (cdrom_toc_entry *)malloc(toc->total_tracks * sizeof(cdrom_toc_entry)); + toc->toc_entries = calloc(toc->total_tracks, sizeof(cdrom_toc_entry)); if (!toc->toc_entries) { - perror("malloc"); + perror("calloc"); return -1; } - + /* fetch each toc entry */ for (i = toc->first_track; i <= toc->last_track; i++) { - + toc->toc_entries[i-1].track_mode = (cdrom_toc.TrackData[i-1].Control & 0x04) ? 1 : 0; toc->toc_entries[i-1].first_frame_minute = cdrom_toc.TrackData[i-1].Address[1]; toc->toc_entries[i-1].first_frame_second = cdrom_toc.TrackData[i-1].Address[2]; @@ -867,7 +866,7 @@ static int read_cdrom_toc(cdda_input_plugin_t *this_gen, cdrom_toc *toc) { (toc->leadout_track.first_frame_minute * CD_SECONDS_PER_MINUTE * CD_FRAMES_PER_SECOND) + (toc->leadout_track.first_frame_second * CD_FRAMES_PER_SECOND) + toc->leadout_track.first_frame_frame; - } + } return 0; } @@ -884,37 +883,37 @@ static int read_cdrom_frames(cdda_input_plugin_t *this_gen, int frame, int num_f /* This is for ASPI which obviously isn't supported! */ lprintf("Windows ASPI support is not complete yet!\n"); return -1; - + } else { memset(data, 0, CD_RAW_FRAME_SIZE * num_frames); - + while( num_frames ) { - + #ifdef LOG /*printf("\t Raw read frame %d\n", frame);*/ #endif raw_read_info.DiskOffset.QuadPart = frame * CD_SECTOR_SIZE; raw_read_info.SectorCount = 1; raw_read_info.TrackMode = CDDA; - + /* read a frame */ if( DeviceIoControl( this_gen->h_device_handle, IOCTL_CDROM_RAW_READ, - &raw_read_info, sizeof(RAW_READ_INFO), data, + &raw_read_info, sizeof(RAW_READ_INFO), data, CD_RAW_FRAME_SIZE, &dwBytesReturned, NULL ) == 0 ) { #ifdef LOG - DWORD dw; + DWORD dw; printf( "input_cdda: could not read frame\n" ); dw = GetLastError(); - printf("GetLastError returned %u\n", dw); + printf("GetLastError returned %u\n", dw); #endif return -1; } - + data += CD_RAW_FRAME_SIZE; frame++; num_frames--; @@ -1020,7 +1019,7 @@ network_command( xine_stream_t *stream, int socket, char *data_buf, char *msg, . if( n ) { if( !data_buf ) { if (stream) - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, "input_cdda: protocol error, data returned but no buffer provided.\n"); return -1; } @@ -1036,13 +1035,13 @@ network_command( xine_stream_t *stream, int socket, char *data_buf, char *msg, . #ifndef WIN32 -static int network_connect(xine_stream_t *stream, char *url ) +static int network_connect(xine_stream_t *stream, const char *got_url ) { - char *host; + char *host, *url; int port; int fd; - url = strdup(url); + url = strdup(got_url); parse_url(url, &host, &port); if( !host || !strlen(host) || !port ) @@ -1081,10 +1080,9 @@ static int network_read_cdrom_toc(xine_stream_t *stream, int fd, cdrom_toc *toc) toc->total_tracks = toc->last_track - toc->first_track + 1; /* allocate space for the toc entries */ - toc->toc_entries = - (cdrom_toc_entry *)malloc(toc->total_tracks * sizeof(cdrom_toc_entry)); + toc->toc_entries = calloc(toc->total_tracks, sizeof(cdrom_toc_entry)); if (!toc->toc_entries) { - perror("malloc"); + perror("calloc"); return -1; } @@ -1146,12 +1144,12 @@ static int network_read_cdrom_frames(xine_stream_t *stream, int fd, int first_fr */ static void cdda_device_cb(void *data, xine_cfg_entry_t *cfg) { cdda_input_class_t *class = (cdda_input_class_t *) data; - + class->cdda_device = cfg->str_value; } static void enable_cddb_changed_cb(void *data, xine_cfg_entry_t *cfg) { cdda_input_class_t *class = (cdda_input_class_t *) data; - + if(class->ip) { cdda_input_plugin_t *this = class->ip; @@ -1162,7 +1160,7 @@ static void enable_cddb_changed_cb(void *data, xine_cfg_entry_t *cfg) { } static void server_changed_cb(void *data, xine_cfg_entry_t *cfg) { cdda_input_class_t *class = (cdda_input_class_t *) data; - + if(class->ip) { cdda_input_plugin_t *this = class->ip; @@ -1173,7 +1171,7 @@ static void server_changed_cb(void *data, xine_cfg_entry_t *cfg) { } static void port_changed_cb(void *data, xine_cfg_entry_t *cfg) { cdda_input_class_t *class = (cdda_input_class_t *) data; - + if(class->ip) { cdda_input_plugin_t *this = class->ip; @@ -1184,7 +1182,7 @@ static void port_changed_cb(void *data, xine_cfg_entry_t *cfg) { } static void cachedir_changed_cb(void *data, xine_cfg_entry_t *cfg) { cdda_input_class_t *class = (cdda_input_class_t *) data; - + if(class->ip) { cdda_input_plugin_t *this = class->ip; @@ -1194,7 +1192,7 @@ static void cachedir_changed_cb(void *data, xine_cfg_entry_t *cfg) { #ifdef CDROM_SELECT_SPEED static void speed_changed_cb(void *data, xine_cfg_entry_t *cfg) { cdda_input_class_t *class = (cdda_input_class_t *) data; - + if (class->ip) { cdda_input_plugin_t *this = class->ip; if (this->fd != -1) @@ -1211,21 +1209,21 @@ static void speed_changed_cb(void *data, xine_cfg_entry_t *cfg) { static int _cdda_is_cd_changed(cdda_input_plugin_t *this) { #ifdef CDROM_MEDIA_CHANGED int err, cd_changed=0; - + if(this == NULL || this->fd < 0) return -1; - + if((err = ioctl(this->fd, CDROM_MEDIA_CHANGED, cd_changed)) < 0) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "input_cdda: ioctl(CDROM_MEDIA_CHANGED) failed: %s.\n", strerror(errno)); return -1; } - + switch(err) { case 1: return 1; break; - + default: return 0; break; @@ -1235,7 +1233,7 @@ static int _cdda_is_cd_changed(cdda_input_plugin_t *this) { #else /* * At least on solaris, CDROM_MEDIA_CHANGED does not exist. Just return an - * error for now + * error for now */ return -1; #endif @@ -1245,18 +1243,18 @@ static int _cdda_is_cd_changed(cdda_input_plugin_t *this) { * create a directory, in safe mode */ static void _cdda_mkdir_safe(xine_t *xine, char *path) { - + if(path == NULL) return; - + #ifndef WIN32 { struct stat pstat; - + if((stat(path, &pstat)) < 0) { /* file or directory no exist, create it */ if(mkdir(path, 0755) < 0) { - xprintf(xine, XINE_VERBOSITY_DEBUG, + xprintf(xine, XINE_VERBOSITY_DEBUG, "input_cdda: mkdir(%s) failed: %s.\n", path, strerror(errno)); return; } @@ -1273,10 +1271,10 @@ static void _cdda_mkdir_safe(xine_t *xine, char *path) { HANDLE hList; TCHAR szDir[MAX_PATH+3]; WIN32_FIND_DATA FileData; - + // Get the proper directory path sprintf(szDir, "%s\\*", path); - + // Get the first file hList = FindFirstFile(szDir, &FileData); if (hList == INVALID_HANDLE_VALUE) @@ -1284,9 +1282,9 @@ static void _cdda_mkdir_safe(xine_t *xine, char *path) { if(_mkdir(path) != 0) { xprintf(xine, XINE_VERBOSITY_DEBUG, "input_cdda: mkdir(%s) failed.\n", path); return; - } + } } - + FindClose(hList); } #endif /* WIN32 */ @@ -1312,18 +1310,15 @@ static void _cdda_mkdir_recursive_safe(xine_t *xine, char *path) { if(p && strlen(p)) { #ifdef WIN32 - if (*buf2 != '\0') { + if (*buf2 != '\0') { #endif - - int size = strlen(buf2); - snprintf(buf2 + size, sizeof(buf2) - size, "/%s", p); - + size_t size = strlen(buf2); + snprintf(buf2 + size, sizeof(buf2) - size, "/%s", p); #ifdef WIN32 - } - else { - snprintf(buf2, sizeof(buf2), "%s", p); - } - + } + else { + snprintf(buf2, sizeof(buf2), "%s", p); + } #endif /* WIN32 */ _cdda_mkdir_safe(xine, buf2); @@ -1336,10 +1331,10 @@ static void _cdda_mkdir_recursive_safe(xine_t *xine, char *path) { */ static char *_cdda_cddb_get_default_location(void) { static char buf[XINE_PATH_MAX + XINE_NAME_MAX + 1]; - + memset(&buf, 0, sizeof(buf)); snprintf(buf, sizeof(buf), "%s/.xine/cddbcache", (xine_get_homedir())); - + return buf; } @@ -1359,12 +1354,12 @@ static int _cdda_cddb_socket_read(cdda_input_plugin_t *this, char *str, int size * Send a command to socket */ static int _cdda_cddb_send_command(cdda_input_plugin_t *this, char *cmd) { - + if((this == NULL) || (this->cddb.fd < 0) || (cmd == NULL)) return -1; xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, ">>> %s\n", cmd); - + return (int)_x_io_tcp_write(this->stream, this->cddb.fd, cmd, strlen(cmd)); } @@ -1434,37 +1429,102 @@ static int _cdda_cddb_handle_code(char *buf) { break; } } - + return err; } +static inline char *_cdda_append (/*const*/ char *first, const char *second) +{ + if (!first) + return strdup (second); + + char *result = (char *) realloc (first, strlen (first) + strlen (second) + 1); + strcat (result, second); + return result; +} + +static void _cdda_parse_cddb_info (cdda_input_plugin_t *this, char *buffer, char **dtitle) +{ + /* buffer should be no more than 2048 bytes... */ + char buf[2048]; + int track_no; + + if (sscanf (buffer, "DTITLE=%s", &buf[0]) == 1) { + char *pt = strchr (buffer, '='); + if (pt) { + ++pt; + + *dtitle = _cdda_append (*dtitle, pt); + pt = strdup (*dtitle); + + char *title = strstr (pt, " / "); + if (title) + { + *title = 0; + title += 3; + free (this->cddb.disc_artist); + this->cddb.disc_artist = strdup (pt); + } + else + title = pt; + + free (this->cddb.disc_title); + this->cddb.disc_title = strdup (title); + + free (pt); + } + } + else if (sscanf (buffer, "DYEAR=%s", &buf[0]) == 1) { + char *pt = strchr (buffer, '='); + if (pt && strlen (pt) == 5) + this->cddb.disc_year = strdup (pt + 1); + } + else if(sscanf(buffer, "DGENRE=%s", &buf[0]) == 1) { + char *pt = strchr(buffer, '='); + if (pt) + this->cddb.disc_category = strdup (pt + 1); + } + else if (sscanf (buffer, "TTITLE%d=%s", &track_no, &buf[0]) == 2) { + char *pt = strchr(buffer, '='); + this->cddb.track[track_no].title = _cdda_append (this->cddb.track[track_no].title, pt + 1); + } + else if (!strncmp (buffer, "EXTD=", 5)) + { + if (!this->cddb.disc_year) + { + int nyear; + char *y = strstr (buffer, "YEAR:"); + if (y && sscanf (y + 5, "%4d", &nyear) == 1) + asprintf (&this->cddb.disc_year, "%d", nyear); + } + } +} + /* * Try to load cached cddb infos */ static int _cdda_load_cached_cddb_infos(cdda_input_plugin_t *this) { char cdir[XINE_PATH_MAX + XINE_NAME_MAX + 1]; + size_t cdir_size = 0; DIR *dir; if(this == NULL) return 0; - - memset(&cdir, 0, sizeof(cdir)); - snprintf(cdir, sizeof(cdir), "%s", this->cddb.cache_dir); - + + cdir_size = snprintf(cdir, sizeof(cdir), "%s", this->cddb.cache_dir); + if((dir = opendir(cdir)) != NULL) { struct dirent *pdir; - + while((pdir = readdir(dir)) != NULL) { char discid[9]; - - memset(&discid, 0, sizeof(discid)); - snprintf(discid, sizeof(discid), "%08lx", this->cddb.disc_id); - + + snprintf(discid, sizeof(discid), "%08" PRIx32, this->cddb.disc_id); + if(!strcasecmp(pdir->d_name, discid)) { FILE *fd; - int size = strlen(cdir); - - snprintf(cdir + size, sizeof(cdir) - size, "/%s", discid); + + cdir_size += snprintf(cdir + cdir_size, sizeof(cdir) - cdir_size, "/%s", discid); if((fd = fopen(cdir, "r")) == NULL) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "input_cdda: fopen(%s) failed: %s.\n", cdir, strerror(errno)); @@ -1472,101 +1532,30 @@ static int _cdda_load_cached_cddb_infos(cdda_input_plugin_t *this) { return 0; } else { - char buffer[256], *ln; - char buf[256]; - int tnum; + char buffer[2048], *ln; char *dtitle = NULL; - - while ((ln = fgets(buffer, 255, fd)) != NULL) { - - buffer[strlen(buffer) - 1] = '\0'; - - if (sscanf(buffer, "DTITLE=%s", &buf[0]) == 1) { - char *pt, *artist, *title; - - pt = strrchr(buffer, '='); - if (pt) { - pt++; - - if (dtitle != NULL) - { - dtitle = (char *) realloc(dtitle, strlen(dtitle) + strlen(pt) + 1); - strcat(dtitle, pt); - pt = dtitle; - } - dtitle = strdup(pt); - - artist = pt; - title = strstr(pt, " / "); - if (title) { - *title++ = '\0'; - title += 2; - } - else { - title = artist; - artist = NULL; - } - - if (artist) - this->cddb.disc_artist = strdup(artist); - - this->cddb.disc_title = strdup(title); - } - } - else if (sscanf(buffer, "DYEAR=%s", &buf[0]) == 1) { - char *pt; - pt = strrchr(buffer, '='); - pt++; - if (pt != NULL && strlen(pt) == 4) - this->cddb.disc_year = strdup(pt); - } - else if (sscanf(buffer, "TTITLE%d=%s", &tnum, &buf[0]) == 2) { - char *pt; - - pt = strrchr(buffer, '='); - if (pt) - pt++; - if (this->cddb.track[tnum].title == NULL) - this->cddb.track[tnum].title = strdup(pt); - else - { - this->cddb.track[tnum].title - = (char *) realloc(this->cddb.track[tnum].title, strlen(this->cddb.track[tnum].title) + strlen(pt) + 1); - strcat(this->cddb.track[tnum].title, pt); - } - } - else { - if (!strncmp(buffer, "EXTD=", 5)) { - char *y; - int nyear; - - y = strstr(buffer, "YEAR:"); - if(y) { - if (sscanf(y+5, "%4d", &nyear) == 1) { - char year[5]; - - snprintf(year, 5, "%d", nyear); - if (this->cddb.disc_year == NULL) - this->cddb.disc_year = strdup(year); - } - } - } - } + while ((ln = fgets(buffer, sizeof (buffer) - 1, fd)) != NULL) { + + int length = strlen (buffer); + if (length && buffer[length - 1] == '\n') + buffer[length - 1] = '\0'; + + _cdda_parse_cddb_info (this, buffer, &dtitle); } fclose(fd); free(dtitle); } - + closedir(dir); return 1; } } xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "input_cdda: cached entry for disc ID %08lx not found.\n", this->cddb.disc_id); + "input_cdda: cached entry for disc ID %08" PRIx32 " not found.\n", this->cddb.disc_id); closedir(dir); } - + return 0; } @@ -1576,19 +1565,19 @@ static int _cdda_load_cached_cddb_infos(cdda_input_plugin_t *this) { static void _cdda_save_cached_cddb_infos(cdda_input_plugin_t *this, char *filecontent) { char cfile[XINE_PATH_MAX + XINE_NAME_MAX + 1]; FILE *fd; - + if((this == NULL) || (filecontent == NULL)) return; - + memset(&cfile, 0, sizeof(cfile)); /* Ensure "~/.xine/cddbcache" exist */ snprintf(cfile, sizeof(cfile), "%s", this->cddb.cache_dir); - + _cdda_mkdir_recursive_safe(this->stream->xine, cfile); - - snprintf(cfile, sizeof(cfile), "%s/%08lx", this->cddb.cache_dir, this->cddb.disc_id); - + + snprintf(cfile, sizeof(cfile), "%s/%08" PRIx32 , this->cddb.cache_dir, this->cddb.disc_id); + if((fd = fopen(cfile, "w")) == NULL) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "input_cdda: fopen(%s) failed: %s.\n", cfile, strerror(errno)); @@ -1598,7 +1587,7 @@ static void _cdda_save_cached_cddb_infos(cdda_input_plugin_t *this, char *fileco fprintf(fd, "%s", filecontent); fclose(fd); } - + } /* @@ -1626,7 +1615,7 @@ static int _cdda_cddb_socket_open(cdda_input_plugin_t *this) { * Close the socket */ static void _cdda_cddb_socket_close(cdda_input_plugin_t *this) { - + if((this == NULL) || (this->cddb.fd < 0)) return; @@ -1646,7 +1635,7 @@ static int _cdda_cddb_retrieve(cdda_input_plugin_t *this) { if(this == NULL) { return 0; } - + if(_cdda_load_cached_cddb_infos(this)) { this->cddb.have_cddb_info = 1; return 1; @@ -1726,22 +1715,21 @@ static int _cdda_cddb_retrieve(cdda_input_plugin_t *this) { /* Send query command */ memset(&buffer, 0, sizeof(buffer)); - sprintf(buffer, "cddb query %08lx %d ", this->cddb.disc_id, this->cddb.num_tracks); + size_t size = sprintf(buffer, "cddb query %08" PRIx32 " %d ", this->cddb.disc_id, this->cddb.num_tracks); for (i = 0; i < this->cddb.num_tracks; i++) { - int size = strlen(buffer); - snprintf(buffer + size, sizeof(buffer) - size, "%d ", this->cddb.track[i].start); + size += snprintf(buffer + size, sizeof(buffer) - size, "%d ", this->cddb.track[i].start); } - snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), "%d\n", this->cddb.disc_length); + snprintf(buffer + strlen(buffer), sizeof(buffer) - size, "%d\n", this->cddb.disc_length); if ((err = _cdda_cddb_send_command(this, buffer)) <= 0) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "input_cdda: error while sending cddb query command.\n"); _cdda_cddb_socket_close(this); - return 0; + return 0; } memset(&buffer, 0, sizeof(buffer)); err = _cdda_cddb_socket_read(this, buffer, sizeof(buffer) - 1); - if (err < 0 || (((err = _cdda_cddb_handle_code(buffer)) != 200) && (err != 210))) { + if (err < 0 || (((err = _cdda_cddb_handle_code(buffer)) != 200) && (err != 210) && (err != 211))) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "input_cdda: cddb query command returned error code '%03d'.\n", err); _cdda_cddb_socket_close(this); @@ -1761,8 +1749,8 @@ static int _cdda_cddb_retrieve(cdda_input_plugin_t *this) { i++; } } - - if (err == 210) { + + if ((err == 210) || (err == 211)) { memset(&buffer, 0, sizeof(buffer)); err = _cdda_cddb_socket_read(this, buffer, sizeof(buffer) - 1); if (err < 0) { @@ -1792,7 +1780,7 @@ static int _cdda_cddb_retrieve(cdda_input_plugin_t *this) { return 0; } } - } + } /* Send read command */ memset(&buffer, 0, sizeof(buffer)); snprintf(buffer, sizeof(buffer), "cddb read %s %s\n", this->cddb.disc_category, this->cddb.cdiscid); @@ -1811,95 +1799,21 @@ static int _cdda_cddb_retrieve(cdda_input_plugin_t *this) { _cdda_cddb_socket_close(this); return 0; } - + this->cddb.have_cddb_info = 1; memset(&buffercache, 0, sizeof(buffercache)); while (strcmp(buffer, ".")) { - char buf[2048]; - int tnum; - int bufsize = strlen(buffercache); + size_t bufsize = strlen(buffercache); memset(&buffer, 0, sizeof(buffer)); _cdda_cddb_socket_read(this, buffer, sizeof(buffer) - 1); snprintf(buffercache + bufsize, sizeof(buffercache) - bufsize, "%s\n", buffer); - if (sscanf(buffer, "DTITLE=%s", &buf[0]) == 1) { - char *pt, *artist, *title; - - pt = strrchr(buffer, '='); - if (pt) { - pt++; - - if (dtitle != NULL) - { - dtitle = (char *) realloc(dtitle, strlen(dtitle) + strlen(pt) + 1); - strcat(dtitle, pt); - pt = dtitle; - } - dtitle = strdup(pt); - - artist = pt; - title = strstr(pt, " / "); - if (title) { - *title++ = '\0'; - title += 2; - } - else { - title = artist; - artist = NULL; - } - - if (artist) { - this->cddb.disc_artist = strdup(artist); - } - this->cddb.disc_title = strdup(title); - } - } - else if(sscanf(buffer, "DYEAR=%s", &buf[0]) == 1) { - char *pt; - - pt = strrchr(buffer, '='); - pt++; - if (pt != NULL && strlen(pt) == 4) - this->cddb.disc_year = strdup(pt); - } - else if (sscanf(buffer, "TTITLE%d=%s", &tnum, &buf[0]) == 2) { - char *pt; - - pt = strrchr(buffer, '='); - if (pt) { - pt++; - if (this->cddb.track[tnum].title == NULL) - this->cddb.track[tnum].title = strdup(pt); - else - { - this->cddb.track[tnum].title - = (char *) realloc(this->cddb.track[tnum].title, strlen(this->cddb.track[tnum].title) + strlen(pt) + 1); - strcat(this->cddb.track[tnum].title, pt); - } - } - } - else { - if (!strncmp(buffer, "EXTD=", 5)) { - char *y; - int nyear; - - y = strstr(buffer, "YEAR:"); - if (y) { - if (sscanf(y+5, "%4d", &nyear) == 1) { - char year[5]; - - snprintf(year, 5, "%d", nyear); - if (this->cddb.disc_year == NULL) - this->cddb.disc_year = strdup(year); - } - } - } - } + _cdda_parse_cddb_info (this, buffer, &dtitle); } free(dtitle); - + /* Save cddb info and close socket */ _cdda_save_cached_cddb_infos(this, buffercache); _cdda_cddb_socket_close(this); @@ -1915,24 +1829,24 @@ static int _cdda_cddb_retrieve(cdda_input_plugin_t *this) { */ static unsigned int _cdda_cddb_sum(int n) { unsigned int ret = 0; - + while(n > 0) { ret += (n % 10); n /= 10; } return ret; } -static unsigned long _cdda_calc_cddb_id(cdda_input_plugin_t *this) { +static uint32_t _cdda_calc_cddb_id(cdda_input_plugin_t *this) { int i, tsum = 0; - + if(this == NULL || (this->cddb.num_tracks <= 0)) return 0; - + for(i = 0; i < this->cddb.num_tracks; i++) tsum += _cdda_cddb_sum((this->cddb.track[i].start / CD_FRAMES_PER_SECOND)); - + return ((tsum % 0xff) << 24 - | (this->cddb.disc_length - (this->cddb.track[0].start / CD_FRAMES_PER_SECOND)) << 8 + | (this->cddb.disc_length - (this->cddb.track[0].start / CD_FRAMES_PER_SECOND)) << 8 | this->cddb.num_tracks); } @@ -1979,7 +1893,7 @@ static void _cdda_cdindex(cdda_input_plugin_t *this, cdrom_toc *toc) { /* * return cbbd disc id. */ -static unsigned long _cdda_get_cddb_id(cdda_input_plugin_t *this) { +static uint32_t _cdda_get_cddb_id(cdda_input_plugin_t *this) { if(this == NULL || (this->cddb.num_tracks <= 0)) return 0; @@ -2001,22 +1915,22 @@ static void _cdda_free_cddb_info(cdda_input_plugin_t *this) { } free(this->cddb.track); - + if(this->cddb.cdiscid) free(this->cddb.cdiscid); - + if(this->cddb.disc_title) free(this->cddb.disc_title); - + if(this->cddb.disc_artist) free(this->cddb.disc_artist); if(this->cddb.disc_category) free(this->cddb.disc_category); - + if(this->cddb.disc_year) free(this->cddb.disc_year); - + } } /* @@ -2024,12 +1938,12 @@ static void _cdda_free_cddb_info(cdda_input_plugin_t *this) { */ static int cdda_open(cdda_input_plugin_t *this_gen, - char *cdda_device, cdrom_toc *toc, int *fdd) { + const char *cdda_device, cdrom_toc *toc, int *fdd) { #ifndef WIN32 int fd = -1; if ( !cdda_device ) return -1; - + *fdd = -1; if (this_gen) @@ -2044,7 +1958,7 @@ static int cdda_open(cdda_input_plugin_t *this_gen, if (this_gen) this_gen->fd = fd; - + #ifdef CDROM_SELECT_SPEED if (this_gen->stream) { int speed; @@ -2074,17 +1988,17 @@ static int cdda_open(cdda_input_plugin_t *this_gen, else return -1; - /* We are going to assume that we are opening a + /* We are going to assume that we are opening a * device and not a file! */ if( WIN_NT ) { char psz_win32_drive[7]; - + lprintf( "using winNT/2K/XP ioctl layer" ); - + sprintf( psz_win32_drive, "\\\\.\\%c:", cdda_device[0] ); - + this_gen->h_device_handle = CreateFile( psz_win32_drive, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, @@ -2100,89 +2014,89 @@ static int cdda_open(cdda_input_plugin_t *this_gen, DWORD dwSupportInfo; int i, j, i_hostadapters; char c_drive = cdda_device[0]; - + hASPI = LoadLibrary( "wnaspi32.dll" ); if( hASPI != NULL ) { - (FARPROC) lpGetSupport = GetProcAddress( hASPI, + lpGetSupport = GetProcAddress( hASPI, "GetASPI32SupportInfo" ); - (FARPROC) lpSendCommand = GetProcAddress( hASPI, + lpSendCommand = GetProcAddress( hASPI, "SendASPI32Command" ); } - + if( hASPI == NULL || lpGetSupport == NULL || lpSendCommand == NULL ) { lprintf( "unable to load aspi or get aspi function pointers" ); - + if( hASPI ) FreeLibrary( hASPI ); return -1; } - + /* ASPI support seems to be there */ - + dwSupportInfo = lpGetSupport(); - + if( HIBYTE( LOWORD ( dwSupportInfo ) ) == SS_NO_ADAPTERS ) { lprintf( "no host adapters found (aspi)" ); FreeLibrary( hASPI ); return -1; } - + if( HIBYTE( LOWORD ( dwSupportInfo ) ) != SS_COMP ) { lprintf( "unable to initalize aspi layer" ); - + FreeLibrary( hASPI ); return -1; } - + i_hostadapters = LOBYTE( LOWORD( dwSupportInfo ) ); if( i_hostadapters == 0 ) { FreeLibrary( hASPI ); return -1; } - + c_drive = c_drive > 'Z' ? c_drive - 'a' : c_drive - 'A'; - + for( i = 0; i < i_hostadapters; i++ ) { for( j = 0; j < 15; j++ ) { struct SRB_GetDiskInfo srbDiskInfo; - + srbDiskInfo.SRB_Cmd = SC_GET_DISK_INFO; srbDiskInfo.SRB_HaId = i; srbDiskInfo.SRB_Flags = 0; srbDiskInfo.SRB_Hdr_Rsvd = 0; srbDiskInfo.SRB_Target = j; srbDiskInfo.SRB_Lun = 0; - + lpSendCommand( (void*) &srbDiskInfo ); - + if( (srbDiskInfo.SRB_Status == SS_COMP) && (srbDiskInfo.SRB_Int13HDriveInfo == c_drive) ) { /* Make sure this is a cdrom device */ struct SRB_GDEVBlock srbGDEVBlock; - + memset( &srbGDEVBlock, 0, sizeof(struct SRB_GDEVBlock) ); srbGDEVBlock.SRB_Cmd = SC_GET_DEV_TYPE; srbGDEVBlock.SRB_HaId = i; srbGDEVBlock.SRB_Target = j; - + lpSendCommand( (void*) &srbGDEVBlock ); - + if( ( srbGDEVBlock.SRB_Status == SS_COMP ) && ( srbGDEVBlock.SRB_DeviceType == DTYPE_CDROM ) ) { this_gen->i_sid = MAKEWORD( i, j ); this_gen->hASPI = (long)hASPI; this_gen->lpSendCommand = lpSendCommand; - + lprintf( "using aspi layer" ); - + return 0; } else @@ -2194,12 +2108,12 @@ static int cdda_open(cdda_input_plugin_t *this_gen, } } } - + FreeLibrary( hASPI ); - + lprintf( "unable to get haid and target (aspi)" ); } - + #endif /* WIN32 */ return -1; @@ -2244,26 +2158,18 @@ static int cdda_close(cdda_input_plugin_t *this_gen) { static uint32_t cdda_plugin_get_capabilities (input_plugin_t *this_gen) { - return INPUT_CAP_SEEKABLE | INPUT_CAP_BLOCK; + return INPUT_CAP_SEEKABLE; } static off_t cdda_plugin_read (input_plugin_t *this_gen, char *buf, off_t len) { - /* only allow reading in block-sized chunks */ - - return 0; -} - -static buf_element_t *cdda_plugin_read_block (input_plugin_t *this_gen, fifo_buffer_t *fifo, - off_t nlen) { - cdda_input_plugin_t *this = (cdda_input_plugin_t *) this_gen; - buf_element_t *buf; - unsigned char frame_data[CD_RAW_FRAME_SIZE]; int err = 0; - if (nlen != CD_RAW_FRAME_SIZE) + /* only allow reading in block-sized chunks */ + + if (len != CD_RAW_FRAME_SIZE) return 0; if (this->current_frame > this->last_frame) @@ -2278,9 +2184,9 @@ static buf_element_t *cdda_plugin_read_block (input_plugin_t *this_gen, fifo_buf this->cache_last = this->current_frame + CACHED_FRAMES - 1; if( this->cache_last > this->last_frame ) this->cache_last = this->last_frame; - -#ifndef WIN32 - if ( this->fd != -1 ) + +#ifndef WIN32 + if ( this->fd != -1 ) #else if ( this->h_device_handle ) #endif /* WIN32 */ @@ -2296,15 +2202,27 @@ static buf_element_t *cdda_plugin_read_block (input_plugin_t *this_gen, fifo_buf if( err < 0 ) return 0; - - memcpy(frame_data, this->cache[this->current_frame-this->cache_first], CD_RAW_FRAME_SIZE); + + memcpy(buf, this->cache[this->current_frame-this->cache_first], CD_RAW_FRAME_SIZE); this->current_frame++; + return CD_RAW_FRAME_SIZE; +} + +static buf_element_t *cdda_plugin_read_block (input_plugin_t *this_gen, fifo_buffer_t *fifo, + off_t nlen) { + + buf_element_t *buf; + buf = fifo->buffer_pool_alloc(fifo); buf->content = buf->mem; buf->type = BUF_DEMUX_BLOCK; - buf->size = CD_RAW_FRAME_SIZE; - memcpy(buf->mem, frame_data, CD_RAW_FRAME_SIZE); + + buf->size = cdda_plugin_read(this_gen, buf->content, nlen); + if (buf->size == 0) { + buf->free_buffer(buf); + buf = NULL; + } return buf; } @@ -2342,7 +2260,7 @@ static off_t cdda_plugin_get_length (input_plugin_t *this_gen) { static uint32_t cdda_plugin_get_blocksize (input_plugin_t *this_gen) { - return CD_RAW_FRAME_SIZE; + return 0; } static const char* cdda_plugin_get_mrl (input_plugin_t *this_gen) { @@ -2383,7 +2301,7 @@ static int cdda_plugin_open (input_plugin_t *this_gen ) { int fd = -1; char *cdda_device; int err = -1; - + lprintf("cdda_plugin_open\n"); /* get the CD TOC */ @@ -2394,7 +2312,7 @@ static int cdda_plugin_open (input_plugin_t *this_gen ) { else cdda_device = class->cdda_device; -#ifndef WIN32 +#ifndef WIN32 if( strchr(cdda_device,':') ) { fd = network_connect(this->stream, cdda_device); if( fd != -1 ) { @@ -2412,7 +2330,7 @@ static int cdda_plugin_open (input_plugin_t *this_gen ) { return 0; } -#ifndef WIN32 +#ifndef WIN32 err = read_cdrom_toc(this->fd, toc); #else err = read_cdrom_toc(this, toc); @@ -2424,18 +2342,18 @@ static int cdda_plugin_open (input_plugin_t *this_gen ) { } - - if ( (err < 0) || (toc->first_track > (this->track + 1)) || + + if ( (err < 0) || (toc->first_track > (this->track + 1)) || (toc->last_track < (this->track + 1))) { cdda_close(this); - + free_cdrom_toc(toc); return 0; } /* set up the frame boundaries for this particular track */ - this->first_frame = this->current_frame = + this->first_frame = this->current_frame = toc->toc_entries[this->track].first_frame; if (this->track + 1 == toc->last_track) this->last_frame = toc->leadout_track.first_frame - 1; @@ -2446,8 +2364,8 @@ static int cdda_plugin_open (input_plugin_t *this_gen ) { this->cache_first = this->cache_last = -1; /* get the Musicbrainz CDIndex */ - _cdda_cdindex (this, toc); - + _cdda_cdindex (this, toc); + /* * CDDB */ @@ -2458,26 +2376,26 @@ static int cdda_plugin_open (input_plugin_t *this_gen ) { if(this->cddb.num_tracks) { int t; - this->cddb.track = (trackinfo_t *) xine_xmalloc(sizeof(trackinfo_t) * this->cddb.num_tracks); + this->cddb.track = (trackinfo_t *) calloc(this->cddb.num_tracks, sizeof(trackinfo_t)); for(t = 0; t < this->cddb.num_tracks; t++) { - int length = (toc->toc_entries[t].first_frame_minute * CD_SECONDS_PER_MINUTE + + int length = (toc->toc_entries[t].first_frame_minute * CD_SECONDS_PER_MINUTE + toc->toc_entries[t].first_frame_second); - - this->cddb.track[t].start = (length * CD_FRAMES_PER_SECOND + + + this->cddb.track[t].start = (length * CD_FRAMES_PER_SECOND + toc->toc_entries[t].first_frame_frame); this->cddb.track[t].title = NULL; } - + } - this->cddb.disc_length = (toc->leadout_track.first_frame_minute * CD_SECONDS_PER_MINUTE + + this->cddb.disc_length = (toc->leadout_track.first_frame_minute * CD_SECONDS_PER_MINUTE + toc->leadout_track.first_frame_second); this->cddb.disc_id = _cdda_get_cddb_id(this); if((this->cddb.have_cddb_info == 0) || (_cdda_is_cd_changed(this) == 1)) _cdda_cddb_retrieve(this); - + if(this->cddb.disc_title) { lprintf("Disc Title: %s\n", this->cddb.disc_title); @@ -2485,17 +2403,36 @@ static int cdda_plugin_open (input_plugin_t *this_gen ) { } if(this->cddb.track[this->track].title) { - lprintf("Track %d Title: %s\n", this->track+1, this->cddb.track[this->track].title); + /* Check for track 'titles' of the form <artist> / <title>. */ + char *pt; + pt = strstr(this->cddb.track[this->track].title, " / "); + if (pt != NULL) { + char *track_artist; + track_artist = strdup(this->cddb.track[this->track].title); + track_artist[pt - this->cddb.track[this->track].title] = 0; + lprintf("Track %d Artist: %s\n", this->track+1, track_artist); + + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_ARTIST, track_artist); + free(track_artist); + pt += 3; + } + else { + if(this->cddb.disc_artist) { + lprintf("Disc Artist: %s\n", this->cddb.disc_artist); - _x_meta_info_set_utf8(this->stream, XINE_META_INFO_TITLE, this->cddb.track[this->track].title); - } - - if(this->cddb.disc_artist) { - lprintf("Disc Artist: %s\n", this->cddb.disc_artist); + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_ARTIST, this->cddb.disc_artist); + } + + pt = this->cddb.track[this->track].title; + } + lprintf("Track %d Title: %s\n", this->track+1, pt); - _x_meta_info_set_utf8(this->stream, XINE_META_INFO_ARTIST, this->cddb.disc_artist); + char tracknum[4]; + snprintf(tracknum, 4, "%d", this->track+1); + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_TRACK_NUMBER, tracknum); + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_TITLE, pt); } - + if(this->cddb.disc_category) { lprintf("Disc Category: %s\n", this->cddb.disc_category); @@ -2513,13 +2450,140 @@ static int cdda_plugin_open (input_plugin_t *this_gen ) { return 1; } -static char ** cdda_class_get_autoplay_list (input_class_t *this_gen, +static xine_mrl_t** cdda_class_get_dir(input_class_t *this_gen, + const char *filename, + int *num_files) { + cdda_input_class_t *this = (cdda_input_class_t *) this_gen; + cdda_input_plugin_t *ip; + cdrom_toc *toc; + char *base_mrl; + int len, frame; + const char * device; + int fd, i, err = -1; + int num_tracks; + + if (filename && *filename) { + device = filename; + if (strncasecmp(device,"cdda:/",6) == 0) { + device += 6; + while ('/' == *device) + device++; + device--; + } + } + else { + device = this->cdda_device; + } + lprintf("cdda_class_get_dir for >%s<\n", device); + + /* get the CD TOC */ + toc = init_cdrom_toc(); + + fd = -1; + + /* we create a new instance because getting a directory of a cd + * should not affect another cd that might be playing. */ + ip = (cdda_input_plugin_t *)xine_xmalloc(sizeof(cdda_input_plugin_t)); + ip->stream = NULL; + ip->fd = -1; + ip->net_fd = -1; + +#ifndef WIN32 + if( strchr(device,':') ) { + fd = network_connect(ip->stream, device); + if( fd != -1 ) { + err = network_read_cdrom_toc(ip->stream, fd, toc); + } + } +#endif + + if (fd == -1) { + if (cdda_open(ip, device, toc, &fd) == -1) { + lprintf("cdda_class_get_dir: opening >%s< failed %s\n", + device, strerror(errno)); + free(ip); + return NULL; + } + +#ifndef WIN32 + err = read_cdrom_toc(fd, toc); +#else + err = read_cdrom_toc(ip, toc); +#endif /* WIN32 */ + } + +#ifdef LOG + print_cdrom_toc(toc); +#endif + + cdda_close(ip); + + if ( err < 0 ) { + free(ip); + return NULL; + } + + num_tracks = toc->last_track - toc->first_track + 1; + + /* this could be done in read_cdrom_toc, but it seems other code doesn't use it */ + frame = toc->leadout_track.first_frame; + for ( i = num_tracks-1 ; i >= 0 ; i--) { + toc->toc_entries[i].total_frames = frame - toc->toc_entries[i].first_frame; + frame = toc->toc_entries[i].first_frame; + } + + if (toc->ignore_last_track) + num_tracks--; + + len = strlen(device) + 5; + base_mrl = xine_xmalloc(len+1); + sprintf(base_mrl, "cdda:%s", device); + + /* allocate space for the mrls's if needed. */ + if (num_tracks+1 > this->mrls_allocated_entries) { + this->mrls = realloc(this->mrls, (num_tracks+1) * sizeof(xine_mrl_t*)); + } + for (i = 0 ; i < num_tracks ; i++) { + if (i < this->mrls_allocated_entries) { + if (this->mrls[i]->origin) + free(this->mrls[i]->origin); + if (this->mrls[i]->mrl) + free(this->mrls[i]->mrl); + if (this->mrls[i]->link) { + free(this->mrls[i]->link); + this->mrls[i]->link = NULL; + } + } + else { + this->mrls[i] = (xine_mrl_t *) xine_xmalloc(sizeof(xine_mrl_t)); + this->mrls[i]->link = NULL; + this->mrls_allocated_entries++; + } + this->mrls[i]->origin = strdup(base_mrl); + this->mrls[i]->mrl = xine_xmalloc(len+4); + sprintf( this->mrls[i]->mrl, "%s/%d", base_mrl, i+toc->first_track); + this->mrls[i]->type = mrl_cda | mrl_file_blockdev; + this->mrls[i]->size = toc->toc_entries[i].total_frames * CD_RAW_FRAME_SIZE; + } + /* Clean up */ + while(this->mrls_allocated_entries > num_tracks) { + MRL_ZERO(this->mrls[this->mrls_allocated_entries - 1]); + free(this->mrls[this->mrls_allocated_entries--]); + } + free_cdrom_toc(toc); + free(ip); + + this->mrls[num_tracks] = NULL; + *num_files = num_tracks; + return this->mrls; +} + +static char ** cdda_class_get_autoplay_list (input_class_t *this_gen, int *num_files) { cdda_input_class_t *this = (cdda_input_class_t *) this_gen; cdda_input_plugin_t *ip = this->ip; cdrom_toc *toc; - char trackmrl[20]; int fd, i, err = -1; int num_tracks; @@ -2528,8 +2592,8 @@ static char ** cdda_class_get_autoplay_list (input_class_t *this_gen, /* free old playlist */ for( i = 0; this->autoplaylist[i]; i++ ) { free( this->autoplaylist[i] ); - this->autoplaylist[i] = NULL; - } + this->autoplaylist[i] = NULL; + } /* get the CD TOC */ toc = init_cdrom_toc(); @@ -2541,7 +2605,7 @@ static char ** cdda_class_get_autoplay_list (input_class_t *this_gen, * device we are going to open; but it is possible that this function * gets called, before a plugin instance has been created; * let's create a dummy instance in such a condition */ - ip = (cdda_input_plugin_t *)xine_xmalloc(sizeof(cdda_input_plugin_t)); + ip = calloc(1, sizeof(cdda_input_plugin_t)); ip->stream = NULL; ip->fd = -1; ip->net_fd = -1; @@ -2575,20 +2639,18 @@ static char ** cdda_class_get_autoplay_list (input_class_t *this_gen, print_cdrom_toc(toc); #endif - cdda_close(ip); - + cdda_close(ip); + if ( err < 0 ) { if (ip != this->ip) free(ip); return NULL; } - + num_tracks = toc->last_track - toc->first_track; if (toc->ignore_last_track) num_tracks--; - for ( i = 0; i <= num_tracks; i++ ) { - sprintf(trackmrl,"cdda:/%d",i+toc->first_track); - this->autoplaylist[i] = strdup(trackmrl); - } + for ( i = 0; i <= num_tracks; i++ ) + asprintf(&this->autoplaylist[i],"cdda:/%d",i+toc->first_track); *num_files = toc->last_track - toc->first_track + 1; @@ -2642,20 +2704,20 @@ static input_plugin_t *cdda_class_get_instance (input_class_t *cls_gen, xine_str } else return NULL; - this = (cdda_input_plugin_t *) xine_xmalloc (sizeof (cdda_input_plugin_t)); - + this = calloc(1, sizeof (cdda_input_plugin_t)); + class->ip = this; this->stream = stream; this->mrl = strdup(mrl); this->cdda_device = cdda_device; - + /* CD tracks start from 1; internal data structure indexes from 0 */ this->track = track - 1; this->cddb.track = NULL; this->fd = -1; this->net_fd = -1; this->class = (input_class_t *) class; - + this->input_plugin.open = cdda_plugin_open; this->input_plugin.get_capabilities = cdda_plugin_get_capabilities; this->input_plugin.read = cdda_plugin_read; @@ -2668,24 +2730,24 @@ static input_plugin_t *cdda_class_get_instance (input_class_t *cls_gen, xine_str this->input_plugin.get_optional_data = cdda_plugin_get_optional_data; this->input_plugin.dispose = cdda_plugin_dispose; this->input_plugin.input_class = cls_gen; - + /* * Lookup config entries. */ - if(xine_config_lookup_entry(this->stream->xine, "media.audio_cd.use_cddb", - &enable_entry)) + if(xine_config_lookup_entry(this->stream->xine, "media.audio_cd.use_cddb", + &enable_entry)) enable_cddb_changed_cb(class, &enable_entry); - if(xine_config_lookup_entry(this->stream->xine, "media.audio_cd.cddb_server", - &server_entry)) + if(xine_config_lookup_entry(this->stream->xine, "media.audio_cd.cddb_server", + &server_entry)) server_changed_cb(class, &server_entry); - - if(xine_config_lookup_entry(this->stream->xine, "media.audio_cd.cddb_port", - &port_entry)) + + if(xine_config_lookup_entry(this->stream->xine, "media.audio_cd.cddb_port", + &port_entry)) port_changed_cb(class, &port_entry); - if(xine_config_lookup_entry(this->stream->xine, "media.audio_cd.cddb_cachedir", - &cachedir_entry)) + if(xine_config_lookup_entry(this->stream->xine, "media.audio_cd.cddb_cachedir", + &cachedir_entry)) cachedir_changed_cb(class, &cachedir_entry); class->cddb_error = cddb_error; @@ -2731,7 +2793,7 @@ static void *init_plugin (xine_t *xine, void *data) { cdda_input_class_t *this; config_values_t *config; - this = (cdda_input_class_t *) xine_xmalloc (sizeof (cdda_input_class_t)); + this = calloc(1, sizeof (cdda_input_class_t)); this->xine = xine; this->config = xine->config; @@ -2740,8 +2802,7 @@ static void *init_plugin (xine_t *xine, void *data) { this->input_class.get_instance = cdda_class_get_instance; this->input_class.get_identifier = cdda_class_get_identifier; this->input_class.get_description = cdda_class_get_description; - /* this->input_class.get_dir = cdda_class_get_dir; */ - this->input_class.get_dir = NULL; + this->input_class.get_dir = cdda_class_get_dir; this->input_class.get_autoplay_list = cdda_class_get_autoplay_list; this->input_class.dispose = cdda_class_dispose; this->input_class.eject_media = cdda_class_eject_media; @@ -2749,15 +2810,15 @@ static void *init_plugin (xine_t *xine, void *data) { this->mrls = NULL; this->mrls_allocated_entries = 0; this->ip = NULL; - - this->cdda_device = config->register_filename(config, "media.audio_cd.device", + + this->cdda_device = config->register_filename(config, "media.audio_cd.device", DEFAULT_CDDA_DEVICE, XINE_CONFIG_STRING_IS_DEVICE_NAME, _("device used for CD audio"), _("The path to the device, usually a " "CD or DVD drive, which you intend to use " "for playing audio CDs."), 10, cdda_device_cb, (void *) this); - + config->register_bool(config, "media.audio_cd.use_cddb", 1, _("query CDDB"), _("Enables CDDB queries, which will give you " "convenient title and track names for your audio CDs.\n" @@ -2765,7 +2826,7 @@ static void *init_plugin (xine_t *xine, void *data) { "is retrieved from an internet server which might collect a profile " "of your listening habits."), 10, enable_cddb_changed_cb, (void *) this); - + config->register_string(config, "media.audio_cd.cddb_server", CDDB_SERVER, _("CDDB server name"), _("The CDDB server used to retrieve the " "title and track information from.\nThis setting is security critical, " @@ -2773,18 +2834,18 @@ static void *init_plugin (xine_t *xine, void *data) { "and could answer the queries with malicious replies. Be sure to enter " "a server you can trust."), XINE_CONFIG_SECURITY, server_changed_cb, (void *) this); - + config->register_num(config, "media.audio_cd.cddb_port", CDDB_PORT, _("CDDB server port"), _("The server port used to retrieve the " "title and track information from."), XINE_CONFIG_SECURITY, port_changed_cb, (void *) this); - - config->register_filename(config, "media.audio_cd.cddb_cachedir", + + config->register_filename(config, "media.audio_cd.cddb_cachedir", (_cdda_cddb_get_default_location()), XINE_CONFIG_STRING_IS_DIRECTORY_NAME, _("CDDB cache directory"), _("The replies from the CDDB server will be " "cached in this directory.\nThis setting is security critical, because files " "with uncontrollable names will be created in this directory. Be sure to use " - "a dedicated directory not used for anything but CDDB caching."), XINE_CONFIG_SECURITY, + "a dedicated directory not used for anything but CDDB caching."), XINE_CONFIG_SECURITY, cachedir_changed_cb, (void *) this); #ifdef CDROM_SELECT_SPEED |