diff --git a/THANKS b/THANKS index 393e3ea3..2e2f1fce 100644 --- a/THANKS +++ b/THANKS @@ -1,3 +1,6 @@ +Svend S. Sorensen + cdrdao TOC-reading code + Nicolas Boullis Build issues, library symbol versioning, Debian packaging and issues diff --git a/include/cdio/cdio.h b/include/cdio/cdio.h index c024cd5e..ad1ec70b 100644 --- a/include/cdio/cdio.h +++ b/include/cdio/cdio.h @@ -1,5 +1,5 @@ /* -*- c -*- - $Id: cdio.h,v 1.44 2004/04/30 06:54:15 rocky Exp $ + $Id: cdio.h,v 1.45 2004/05/04 02:06:48 rocky Exp $ Copyright (C) 2001 Herbert Valerio Riedel Copyright (C) 2003, 2004 Rocky Bernstein @@ -79,6 +79,9 @@ extern "C" { DRIVER_SOLARIS, /**< Sun Solaris Driver */ DRIVER_OSX, /**< Apple OSX Driver */ DRIVER_WIN32, /**< Microsoft Windows Driver */ + DRIVER_CDRDAO, /**< cdrdao format CD image. This is listed + before BINCUE, to make the code prefer cdrdao + over BINCUE when both exist. */ DRIVER_BINCUE, /**< BIN/CUE format CD image. This is listed before NRG, to make the code prefer BINCUE over NRG when both exist. */ @@ -200,6 +203,13 @@ extern "C" { */ const char * cdio_get_driver_name (const CdIo *obj); + /*! + Return the driver id. + if CdIo is NULL (we haven't initialized a specific device driver), + then return DRIVER_UNKNOWN. + */ + driver_id_t cdio_get_driver_id (const CdIo *obj); + /*! Return the number of the first track. CDIO_INVALID_TRACK is returned on error. @@ -361,6 +371,9 @@ extern "C" { /*! True if BIN/CUE driver is available. */ bool cdio_have_bincue (void); + /*! True if cdrdao CDRDAO driver is available. */ + bool cdio_have_cdrdao (void); + /*! Like cdio_have_xxx but uses an enumeration instead. */ bool cdio_have_driver (driver_id_t driver_id); @@ -403,6 +416,19 @@ extern "C" { CdIo * cdio_open_am_bincue (const char *psz_cue_name, const char *psz_access_mode); + /*! Set up cdrdao CD disk-image for reading. Source is the .toc file + + NULL is returned on error. + */ + CdIo * cdio_open_cdrdao (const char *psz_toc_name); + + /*! Set up cdrdao CD disk-image for reading. Source is the .toc file + + NULL is returned on error. + */ + CdIo * cdio_open_am_cdrdao (const char *psz_toc_name, + const char *psz_access_mode); + /*! Return a string containing the default CUE file that would be used when none is specified. @@ -412,6 +438,15 @@ extern "C" { char **cdio_get_devices_bincue(void); + /*! Return a string containing the default CUE file that would + be used when none is specified. + + NULL is returned on error or there is no device. + */ + char * cdio_get_default_device_cdrdao(void); + + char **cdio_get_devices_cdrdao(void); + /*! Set up CD-ROM for reading. The device_name is the some sort of device name. @@ -646,9 +681,13 @@ extern "C" { */ char *cdio_is_cuefile(const char *cue_name); + /*! Return true if toc_name is a cdrdao TOC file or false + if not a TOC file. + */ + bool cdio_is_tocfile(const char *toc_name); + /*! Return corresponding CUE file if bin_name is a fin file or NULL - if not a BIN file. NOTE: when we handle TOC something will have to - change here.... + if not a BIN file. */ char *cdio_is_binfile(const char *bin_name); diff --git a/include/cdio/types.h b/include/cdio/types.h index 5e41bfd1..eff6e29b 100644 --- a/include/cdio/types.h +++ b/include/cdio/types.h @@ -1,5 +1,5 @@ /* - $Id: types.h,v 1.13 2004/04/25 14:07:23 rocky Exp $ + $Id: types.h,v 1.14 2004/05/04 02:06:48 rocky Exp $ Copyright (C) 2000 Herbert Valerio Riedel Copyright (C) 2002, 2003, 2004 Rocky Bernstein @@ -288,6 +288,20 @@ typedef int cdio_fs_anal_t; (CDIO_DRIVE_CAP_DVD_R|CDIO_DRIVE_CAP_DVD_RAM) /**< Has some sort of DVD writer ability */ +/*! + track flags + Q Sub-channel Control Field (4.2.3.3) +*/ +typedef enum { + CDIO_TRACK_FLAG_NONE = 0x00, /**< no flags set */ + CDIO_TRACK_FLAG_PRE_EMPHASIS = 0x01, /**< audio track recorded with + pre-emphasis */ + CDIO_TRACK_FLAG_COPY_PERMITTED = 0x02, /**< digital copy permitted */ + CDIO_TRACK_FLAG_DATA = 0x04, /**< data track */ + CDIO_TRACK_FLAG_FOUR_CHANNEL_AUDIO = 0x08, /**< 4 audio channels */ + CDIO_TRACK_FLAG_SCMS = 0x10 /**< SCMS (5.29.2.7) */ +} cdio_track_flag; + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/lib/Makefile.am b/lib/Makefile.am index 2dac4862..74d00f93 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.33 2004/04/30 09:59:54 rocky Exp $ +# $Id: Makefile.am,v 1.34 2004/05/04 02:06:48 rocky Exp $ # # Copyright (C) 2003, 2004 Rocky Bernstein # @@ -72,6 +72,7 @@ libcdio_sources = \ FreeBSD/freebsd_cam.c \ FreeBSD/freebsd_ioctl.c \ image/bincue.c \ + image/cdrdao.c \ image_common.h \ image/nrg.c \ logging.c \ diff --git a/lib/cdio.c b/lib/cdio.c index 8c01f72a..6c2a97d0 100644 --- a/lib/cdio.c +++ b/lib/cdio.c @@ -1,5 +1,5 @@ /* - $Id: cdio.c,v 1.48 2004/04/30 06:54:15 rocky Exp $ + $Id: cdio.c,v 1.49 2004/05/04 02:06:48 rocky Exp $ Copyright (C) 2003, 2004 Rocky Bernstein Copyright (C) 2001 Herbert Valerio Riedel @@ -37,7 +37,7 @@ #include #include "cdio_private.h" -static const char _rcsid[] = "$Id: cdio.c,v 1.48 2004/04/30 06:54:15 rocky Exp $"; +static const char _rcsid[] = "$Id: cdio.c,v 1.49 2004/05/04 02:06:48 rocky Exp $"; const char *track_format2str[6] = @@ -153,6 +153,18 @@ CdIo_driver_t CdIo_all_drivers[CDIO_MAX_DRIVER+1] = { &cdio_get_devices_win32 }, + {DRIVER_CDRDAO, + CDIO_SRC_IS_DISK_IMAGE_MASK, + "CDRDAO", + "cdrdao (TOC) disk image driver", + &cdio_have_cdrdao, + &cdio_open_cdrdao, + &cdio_open_am_cdrdao, + &cdio_get_default_device_cdrdao, + NULL, + &cdio_get_devices_cdrdao + }, + {DRIVER_BINCUE, CDIO_SRC_IS_DISK_IMAGE_MASK, "BIN/CUE", @@ -434,9 +446,22 @@ cdio_get_drive_cap_dev (const char *device) const char * cdio_get_driver_name (const CdIo *cdio) { + if (NULL==cdio) return NULL; return CdIo_all_drivers[cdio->driver_id].name; } + /*! + Return the driver id. + if CdIo is NULL (we haven't initialized a specific device driver), + then return DRIVER_UNKNOWN. + */ +driver_id_t +cdio_get_driver_id (const CdIo *cdio) +{ + if (NULL==cdio) return DRIVER_UNKNOWN; + return cdio->driver_id; +} + /*! Return the number of of the first track. @@ -846,43 +871,13 @@ cdio_open (const char *orig_source_name, driver_id_t driver_id) else source_name = strdup(orig_source_name); - retry: switch (driver_id) { case DRIVER_UNKNOWN: { CdIo *cdio=scan_for_driver(CDIO_MIN_DRIVER, CDIO_MAX_DRIVER, source_name); - if (cdio != NULL && cdio_is_device(source_name, cdio->driver_id)) { - driver_id = cdio->driver_id; - } else { - struct stat buf; - if (0 != stat(source_name, &buf)) { - return NULL; - } - if (S_ISREG(buf.st_mode)) { - /* FIXME: check to see if is a text file. If so, then - set SOURCE_CUE. */ - int i=strlen(source_name)-strlen("bin"); - if (i > 0 - && ( (source_name)[i] =='n' || (source_name)[i] =='N' ) - && ( (source_name)[i+1] =='r' || (source_name)[i+1] =='R' ) - && ( (source_name)[i+2] =='g' || (source_name)[i+2] =='G' ) ) - driver_id = DRIVER_NRG; - else if (i > 0 - && ( (source_name)[i] =='c' || (source_name)[i] =='C') - && ( (source_name)[i+1] =='u' || (source_name)[i+1] =='U') - && ( (source_name)[i+2] =='e' || (source_name)[i+2] =='E') ) - driver_id = DRIVER_BINCUE; - else - driver_id = DRIVER_BINCUE; - } else { - cdio_destroy(cdio); - return NULL; - } - - } - cdio_destroy(cdio); - goto retry; + free(source_name); + return cdio; } case DRIVER_DEVICE: { @@ -900,6 +895,7 @@ cdio_open (const char *orig_source_name, driver_id_t driver_id) case DRIVER_OSX: case DRIVER_NRG: case DRIVER_BINCUE: + case DRIVER_CDRDAO: if ((*CdIo_all_drivers[driver_id].have_driver)()) { CdIo *ret = (*CdIo_all_drivers[driver_id].driver_open)(source_name); if (ret) ret->driver_id = driver_id; diff --git a/lib/image/cdrdao.c b/lib/image/cdrdao.c new file mode 100644 index 00000000..cd39cff2 --- /dev/null +++ b/lib/image/cdrdao.c @@ -0,0 +1,1249 @@ +/* + $Id: cdrdao.c,v 1.1 2004/05/04 02:06:48 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + toc reading routine adapted from cuetools + Copyright (C) 2003 Svend Sanjay Sorensen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* This code implements low-level access functions for a CD images + residing inside a disk file (*.bin) and its associated cue sheet. + (*.cue). +*/ + +static const char _rcsid[] = "$Id: cdrdao.c,v 1.1 2004/05/04 02:06:48 rocky Exp $"; + +#include "cdio_assert.h" +#include "cdio_private.h" +#include "_cdio_stdio.h" + +#include +#include +#include + +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STRINGS_H +#include +#endif +#ifdef HAVE_GLOB_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif + +#include + +/* FIXME: should put in a common definition somewhere. */ +#ifdef HAVE_MEMSET +#define BZERO(ptr, size) memset(ptr, 0, size) +#elif HAVE_BZERO +#define BZERO(ptr, size) bzero(ptr, size) +#else + Error -- you need either memset or bzero +#endif + +/* reader */ + +#define DEFAULT_CDIO_DEVICE "videocd.bin" +#define DEFAULT_CDIO_CDRDAO "videocd.toc" + +typedef struct { + track_t track_num; /* Probably is index+1 */ + msf_t start_msf; + lba_t start_lba; + lba_t length; + lba_t pregap; + int start_index; + int sec_count; /* Number of sectors in this track. Does not + include pregap */ + int num_indices; + int flags; /* "DCP", "4CH", "PRE" */ + char *isrc; /* IRSC Code (5.22.4) exactly 12 bytes. */ + char *filename; /* name given inside TOC file. */ + CdioDataSource *data_source; + track_format_t track_format; + bool track_green; + uint16_t datasize; /* How much is in the portion we return back? */ + uint16_t datastart; /* Offset from begining that data starts */ + uint16_t endsize; /* How much stuff at the end to skip over. This + stuff may have error correction (EDC, or ECC).*/ + uint16_t blocksize; /* total block size = start + size + end */ + + +} track_info_t; + +typedef struct { + /* Things common to all drivers like this. + This must be first. */ + generic_img_private_t gen; + internal_position_t pos; + + bool sector_2336; /* Playstation (PSX) uses 2336-byte sectors */ + + char *toc_name; + char *mcn; /* Media Catalog Number (5.22.3) + exactly 13 bytes */ + track_info_t tocent[100]; /* entry info for each track */ + track_t total_tracks; /* number of tracks in image */ + track_t first_track_num; /* track number of first track */ + track_format_t mode; + bool b_have_cdrdao; +} _img_private_t; + +static uint32_t _stat_size_cdrdao (void *env); +static bool parse_tocfile (_img_private_t *cd, const char *toc_name); + +#include "image_common.h" + +/* returns 0 if field is a CD-TEXT keyword, returns non-zero otherwise */ +static int +cdtext_is_keyword (char *key) +{ + const char *cdtext_keywords[] = + { + "ARRANGER", /* name(s) of the arranger(s) */ + "COMPOSER", /* name(s) of the composer(s) */ + "DISC ID", /* disc identification information */ + "GENRE", /* genre identification and genre information */ + "ISRC", /* ISRC code of each track */ + "MESSAGE", /* message(s) from the content provider and/or artist */ + "PERFORMER", /* name(s) of the performer(s) */ + "SIZE_INFO", /* size information of the block */ + "SONGWRITER", /* name(s) of the songwriter(s) */ + "TITLE", /* title of album name or track titles */ + "TOC_INFO", /* table of contents information */ + "TOC_INFO2" /* second table of contents information */ + "UPC_EAN", + }; + + char *item; + + item = bsearch(key, + cdtext_keywords, 12, + sizeof (char *), + (int (*)(const void *, const void *)) + strcmp); + return (NULL != item) ? 0 : 1; +} + +static lba_t +msf_to_lba (int minutes, int seconds, int frames) +{ + return ((minutes * CDIO_CD_SECS_PER_MIN + seconds) * CDIO_CD_FRAMES_PER_SEC + + frames); +} + +static lba_t +msf_lba_from_mmssff (char *s) +{ + int field; + lba_t ret; + char c; + + if (0 == strcmp (s, "0")) + return 0; + + c = *s++; + if(c >= '0' && c <= '9') + field = (c - '0'); + else + return CDIO_INVALID_LBA; + while(':' != (c = *s++)) { + if(c >= '0' && c <= '9') + field = field * 10 + (c - '0'); + else + return CDIO_INVALID_LBA; + } + + ret = msf_to_lba (field, 0, 0); + + c = *s++; + if(c >= '0' && c <= '9') + field = (c - '0'); + else + return CDIO_INVALID_LBA; + if(':' != (c = *s++)) { + if(c >= '0' && c <= '9') { + field = field * 10 + (c - '0'); + c = *s++; + if(c != ':') + return CDIO_INVALID_LBA; + } + else + return CDIO_INVALID_LBA; + } + + if(field >= CDIO_CD_SECS_PER_MIN) + return CDIO_INVALID_LBA; + + ret += msf_to_lba (0, field, 0); + + c = *s++; + if(c >= '0' && c <= '9') + field = (c - '0'); + else + return -1; + if('\0' != (c = *s++)) { + if(c >= '0' && c <= '9') { + field = field * 10 + (c - '0'); + c = *s++; + } + else + return CDIO_INVALID_LBA; + } + + if('\0' != c) + return -1; + + if(field >= CDIO_CD_FRAMES_PER_SEC) + return CDIO_INVALID_LBA; + + ret += field; + + return ret; +} + +/*! + Initialize image structures. + */ +static bool +_init_cdrdao (_img_private_t *_obj) +{ + lsn_t lead_lsn; + + if (_obj->gen.init) + return false; + + /* Have to set init before calling _stat_size_cdrdao() or we will + get into infinite recursion calling passing right here. + */ + _obj->gen.init = true; + _obj->first_track_num=1; + _obj->mcn=NULL; + + /* Read in TOC sheet. */ + if ( !parse_tocfile(_obj, _obj->toc_name) ) return false; + + lead_lsn = _stat_size_cdrdao( (_img_private_t *) _obj); + + if (-1 == lead_lsn) + return false; + + /* Fake out leadout track and sector count for last track*/ + cdio_lsn_to_msf (lead_lsn, &_obj->tocent[_obj->total_tracks].start_msf); + _obj->tocent[_obj->total_tracks].start_lba = cdio_lsn_to_lba(lead_lsn); + _obj->tocent[_obj->total_tracks-1].sec_count = + cdio_lsn_to_lba(lead_lsn - _obj->tocent[_obj->total_tracks-1].start_lba); + + return true; +} + +/*! + Reads into buf the next size bytes. + Returns -1 on error. + Would be libc's seek() but we have to adjust for the extra track header + information in each sector. +*/ +static off_t +_lseek_cdrdao (void *env, off_t offset, int whence) +{ + _img_private_t *_obj = env; + + /* real_offset is the real byte offset inside the disk image + The number below was determined empirically. I'm guessing + the 1st 24 bytes of a bin file are used for something. + */ + off_t real_offset=0; + + unsigned int i; + + _obj->pos.lba = 0; + for (i=0; i<_obj->total_tracks; i++) { + track_info_t *this_track=&(_obj->tocent[i]); + _obj->pos.index = i; + if ( (this_track->sec_count*this_track->datasize) >= offset) { + int blocks = offset / this_track->datasize; + int rem = offset % this_track->datasize; + int block_offset = blocks * this_track->blocksize; + real_offset += block_offset + rem; + _obj->pos.buff_offset = rem; + _obj->pos.lba += blocks; + break; + } + real_offset += this_track->sec_count*this_track->blocksize; + offset -= this_track->sec_count*this_track->datasize; + _obj->pos.lba += this_track->sec_count; + } + + if (i==_obj->total_tracks) { + cdio_warn ("seeking outside range of disk image"); + return -1; + } else { + real_offset += _obj->tocent[i].datastart; + return cdio_stream_seek(_obj->gen.data_source, real_offset, whence); + } +} + +/*! + Reads into buf the next size bytes. + Returns -1 on error. + FIXME: + At present we assume a read doesn't cross sector or track + boundaries. +*/ +static ssize_t +_read_cdrdao (void *env, void *data, size_t size) +{ + _img_private_t *_obj = env; + char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; + char *p = data; + ssize_t final_size=0; + ssize_t this_size; + track_info_t *this_track=&(_obj->tocent[_obj->pos.index]); + ssize_t skip_size = this_track->datastart + this_track->endsize; + + while (size > 0) { + int rem = this_track->datasize - _obj->pos.buff_offset; + if (size <= rem) { + this_size = cdio_stream_read(_obj->gen.data_source, buf, size, 1); + final_size += this_size; + memcpy (p, buf, this_size); + break; + } + + /* Finish off reading this sector. */ + cdio_warn ("Reading across block boundaries not finished"); + + size -= rem; + this_size = cdio_stream_read(_obj->gen.data_source, buf, rem, 1); + final_size += this_size; + memcpy (p, buf, this_size); + p += this_size; + this_size = cdio_stream_read(_obj->gen.data_source, buf, rem, 1); + + /* Skip over stuff at end of this sector and the beginning of the next. + */ + cdio_stream_read(_obj->gen.data_source, buf, skip_size, 1); + + /* Get ready to read another sector. */ + _obj->pos.buff_offset=0; + _obj->pos.lba++; + + /* Have gone into next track. */ + if (_obj->pos.lba >= _obj->tocent[_obj->pos.index+1].start_lba) { + _obj->pos.index++; + this_track=&(_obj->tocent[_obj->pos.index]); + skip_size = this_track->datastart + this_track->endsize; + } + } + return final_size; +} + +/*! + Return the size of the CD in logical block address (LBA) units. + */ +static uint32_t +_stat_size_cdrdao (void *env) +{ + _img_private_t *_obj = env; + long size; + int blocksize = _obj->sector_2336 + ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE_RAW; + + _init_cdrdao (_obj); + + size = cdio_stream_stat (_obj->gen.data_source); + + if (size % blocksize) + { + cdio_warn ("image %s size (%ld) not multiple of blocksize (%d)", + _obj->gen.source_name, size, blocksize); + if (size % M2RAW_SECTOR_SIZE == 0) + cdio_warn ("this may be a 2336-type disc image"); + else if (size % CDIO_CD_FRAMESIZE_RAW == 0) + cdio_warn ("this may be a 2352-type disc image"); + /* exit (EXIT_FAILURE); */ + } + + size /= blocksize; + + return size; +} + +#define MAXLINE 512 +#define UNIMPLIMENTED_MSG \ + cdio_log(log_level, "%s line %d: unimplimented keyword: %s", \ + toc_name, line_num, keyword) + + +static bool +parse_tocfile (_img_private_t *cd, const char *toc_name) +{ + char line[MAXLINE]; + FILE *fp; + int line_num=-1; + char *keyword, *field; + int i = -1; + cdio_log_level_t log_level = (NULL == cd) ? CDIO_LOG_DEBUG : CDIO_LOG_WARN; + + if (NULL == toc_name) + return false; + + fp = fopen (toc_name, "r"); + if (fp == NULL) { + cdio_log(log_level, "error opening %s for reading: %s", + toc_name, strerror(errno)); + return false; + } + + while ((fgets(line, MAXLINE, fp)) != NULL) { + + /* strip comment from line */ + /* todo: // in quoted strings? */ + /* //comment */ + if (NULL != (field = strstr (line, "//"))) + *field = '\0'; + + if (NULL != (keyword = strtok (line, " \t\n\r"))) { + /* CATALOG "ddddddddddddd" */ + if (0 == strcmp ("CATALOG", keyword)) { + if (-1 == i) { + if (NULL != (field = strtok (NULL, "\"\t\n\r"))) + if (NULL != cd) + cd->mcn = strdup (field); + if (NULL != (field = strtok (NULL, " \t\n\r"))) { + cdio_log(log_level, "%d: format error: %s", line_num, keyword); + goto err_exit; + } + } else { + goto err_exit; + } + + /* CD_DA | CD_ROM | CD_ROM_XA */ + } else if (0 == strcmp ("CD_DA", keyword)) { + if (-1 == i) { + if (NULL != cd) + cd->mode = TRACK_FORMAT_AUDIO; + } else { + goto not_in_global_section; + } + } else if (0 == strcmp ("CD_ROM", keyword)) { + if (-1 == i) { + if (NULL != cd) + cd->mode = TRACK_FORMAT_DATA; + } else { + goto not_in_global_section; + } + + } else if (0 == strcmp ("CD_ROM_XA", keyword)) { + if (-1 == i) { + if (NULL != cd) + cd->mode = TRACK_FORMAT_XA; + } else { + goto not_in_global_section; + } + + /* TRACK [] */ + } else if (0 == strcmp ("TRACK", keyword)) { + i++; + /* cd->tocent[i].cdtext = NULL; */ + if (NULL != (field = strtok (NULL, " \t\n\r"))) { + if (0 == strcmp ("AUDIO", field)) { + if (NULL != cd) { + cd->tocent[i].track_format = TRACK_FORMAT_AUDIO; + cd->tocent[i].blocksize = CDIO_CD_FRAMESIZE_RAW; + cd->tocent[i].datasize = CDIO_CD_FRAMESIZE_RAW; + cd->tocent[i].datastart = 0; + cd->tocent[i].endsize = 0; + } + } else if (0 == strcmp ("MODE1", field)) { + if (NULL != cd) { + cd->tocent[i].track_format = TRACK_FORMAT_DATA; + cd->tocent[i].blocksize = CDIO_CD_FRAMESIZE_RAW; + cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE + + CDIO_CD_HEADER_SIZE; + cd->tocent[i].datasize = CDIO_CD_FRAMESIZE; + cd->tocent[i].endsize = CDIO_CD_EDC_SIZE + + CDIO_CD_M1F1_ZERO_SIZE + CDIO_CD_ECC_SIZE; + } + } else if (0 == strcmp ("MODE1_RAW", field)) { + if (NULL != cd) { + cd->tocent[i].track_format = TRACK_FORMAT_DATA; + cd->tocent[i].blocksize = CDIO_CD_FRAMESIZE_RAW; + cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE + + CDIO_CD_HEADER_SIZE; + cd->tocent[i].datasize = CDIO_CD_FRAMESIZE; + cd->tocent[i].endsize = CDIO_CD_EDC_SIZE + + CDIO_CD_M1F1_ZERO_SIZE + CDIO_CD_ECC_SIZE; + } + } else if (0 == strcmp ("MODE2", field)) { + if (NULL != cd) { + cd->tocent[i].track_format = TRACK_FORMAT_XA; + cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE + + CDIO_CD_HEADER_SIZE; + cd->tocent[i].datasize = M2RAW_SECTOR_SIZE; + cd->tocent[i].endsize = 0; + } + } else if (0 == strcmp ("MODE2_FORM1", field)) { + if (NULL != cd) { + cd->tocent[i].track_format = TRACK_FORMAT_XA; + cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE + + CDIO_CD_HEADER_SIZE; + cd->tocent[i].datasize = CDIO_CD_FRAMESIZE_RAW; + cd->tocent[i].endsize = 0; + } + } else if (0 == strcmp ("MODE2_FORM2", field)) { + if (NULL != cd) { + cd->tocent[i].track_format = TRACK_FORMAT_XA; + cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE + + CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE; + cd->tocent[i].datasize = CDIO_CD_FRAMESIZE; + cd->tocent[i].endsize = CDIO_CD_SYNC_SIZE + + CDIO_CD_ECC_SIZE; + } + } else if (0 == strcmp ("MODE2_FORM_MIX", field)) { + if (NULL != cd) { + cd->tocent[i].track_format = TRACK_FORMAT_XA; + cd->tocent[i].datasize = M2RAW_SECTOR_SIZE; + cd->tocent[i].blocksize = CDIO_CD_FRAMESIZE_RAW; + cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE + + CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE; + cd->tocent[i].track_green = true; + cd->tocent[i].endsize = 0; + } + } else if (0 == strcmp ("MODE2_RAW", field)) { + if (NULL != cd) { + cd->tocent[i].track_format = TRACK_FORMAT_XA; + cd->tocent[i].blocksize = CDIO_CD_FRAMESIZE_RAW; + cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE + + CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE; + cd->tocent[i].datasize = CDIO_CD_FRAMESIZE; + cd->tocent[i].track_green = true; + cd->tocent[i].endsize = 0; + } + } else { + goto format_error; + } + } + if (NULL != (field = strtok (NULL, " \t\n\r"))) { + /* todo: set sub-channel-mode */ + if (0 == strcmp ("RW", field)) + ; + else if (0 == strcmp ("RW_RAW", field)) + ; + } + if (NULL != (field = strtok (NULL, " \t\n\r"))) { + goto format_error; + } + + /* track flags */ + /* [NO] COPY | [NO] PRE_EMPHASIS */ + } else if (0 == strcmp ("NO", keyword)) { + if (NULL != (field = strtok (NULL, " \t\n\r"))) { + if (0 == strcmp ("COPY", field)) { + if (NULL != cd) + cd->tocent[i].flags &= ~CDIO_TRACK_FLAG_COPY_PERMITTED; + + } else if (0 == strcmp ("PRE_EMPHASIS", field)) + if (NULL != cd) { + cd->tocent[i].flags &= ~CDIO_TRACK_FLAG_PRE_EMPHASIS; + goto err_exit; + } + } else { + goto format_error; + } + if (NULL != (field = strtok (NULL, " \t\n\r"))) { + goto format_error; + } + } else if (0 == strcmp ("COPY", keyword)) { + if (NULL != cd) + cd->tocent[i].flags |= CDIO_TRACK_FLAG_COPY_PERMITTED; + } else if (0 == strcmp ("PRE_EMPHASIS", keyword)) { + if (NULL != cd) + cd->tocent[i].flags |= CDIO_TRACK_FLAG_PRE_EMPHASIS; + /* TWO_CHANNEL_AUDIO */ + } else if (0 == strcmp ("TWO_CHANNEL_AUDIO", keyword)) { + if (NULL != cd) + cd->tocent[i].flags &= ~CDIO_TRACK_FLAG_FOUR_CHANNEL_AUDIO; + /* FOUR_CHANNEL_AUDIO */ + } else if (0 == strcmp ("FOUR_CHANNEL_AUDIO", keyword)) { + if (NULL != cd) + cd->tocent[i].flags |= CDIO_TRACK_FLAG_FOUR_CHANNEL_AUDIO; + + /* ISRC "CCOOOYYSSSSS" */ + } else if (0 == strcmp ("ISRC", keyword)) { + if (NULL != (field = strtok (NULL, "\"\t\n\r"))) { + if (NULL != cd) + cd->tocent[i].isrc = strdup(field); + } else { + goto format_error; + } + + /* SILENCE */ + } else if (0 == strcmp ("SILENCE", keyword)) { + UNIMPLIMENTED_MSG; + + /* ZERO */ + } else if (0 == strcmp ("ZERO", keyword)) { + UNIMPLIMENTED_MSG; + + /* [FILE|AUDIOFILE] "" [] */ + } else if (0 == strcmp ("FILE", keyword) + || 0 == strcmp ("AUDIOFILE", keyword)) { + if (0 <= i) { + if (NULL != (field = strtok (NULL, "\"\t\n\r"))) { + if (NULL != cd) { + cd->tocent[i].filename = strdup (field); + /* Todo: do something about reusing existing files. */ + if (!(cd->tocent[i].data_source = cdio_stdio_new (field))) { + cdio_warn ("init failed"); + goto err_exit; + } + /* HACK! Need to really fix up read/seeking routines. + And add a "basename" routine. + */ + cd->gen.data_source = cd->tocent[i].data_source; + cd->gen.source_name = cd->tocent[i].filename; + } + } + + if (NULL != (field = strtok (NULL, " \t\n\r"))) { + lba_t lba = cdio_lsn_to_lba(msf_lba_from_mmssff (field)); + if (CDIO_INVALID_LBA == lba) { + cdio_log(log_level, "%d: invalid MSF string %s", + line_num, field); + goto err_exit; + } + + if (NULL != cd) { + cd->tocent[i].start_lba = lba; + cdio_lba_to_msf(lba, &(cd->tocent[i].start_msf)); + } + } + if (NULL != (field = strtok (NULL, " \t\n\r"))) + if (NULL != cd) + cd->tocent[i].length = msf_lba_from_mmssff (field); + if (NULL != (field = strtok (NULL, " \t\n\r"))) { + goto format_error; + } + } else { + goto not_in_global_section; + } + + /* DATAFILE "" [] */ + } else if (0 == strcmp ("DATAFILE", keyword)) { + goto unimplimented_error; + + /* FIFO "" [] */ + } else if (0 == strcmp ("FIFO", keyword)) { + goto unimplimented_error; + + /* START MM:SS:FF */ + } else if (0 == strcmp ("START", keyword)) { + if (0 <= i) { + if (NULL != (field = strtok (NULL, " \t\n\r"))) { + /* todo: line is too long! */ + if (NULL != cd) { + cd->tocent[i].start_lba += msf_lba_from_mmssff (field); + cdio_lba_to_msf(cd->tocent[i].start_lba, + &(cd->tocent[i].start_msf)); + } + } + + if (NULL != (field = strtok (NULL, " \t\n\r"))) { + goto format_error; + } + } else { + goto not_in_global_section; + } + + /* PREGAP MM:SS:FF */ + } else if (0 == strcmp ("PREGAP", keyword)) { + if (0 <= i) { + if (NULL != (field = strtok (NULL, " \t\n\r"))) { + if (NULL != cd) + cd->tocent[i].pregap = msf_lba_from_mmssff (field); + } else { + goto format_error; + } + if (NULL != (field = strtok (NULL, " \t\n\r"))) { + goto format_error; + } + } else { + goto not_in_global_section; + } + + /* INDEX MM:SS:FF */ + } else if (0 == strcmp ("INDEX", keyword)) { + if (0 <= i) { + if (NULL != (field = strtok (NULL, " \t\n\r"))) { + if (NULL != cd) { +#if 0 + if (1 == cd->tocent[i].nindex) { + cd->tocent[i].indexes[1] = cd->tocent[i].indexes[0]; + cd->tocent[i].nindex++; + } + cd->tocent[i].indexes[cd->tocent[i].nindex++] = + msf_lba_from_mmssff (field) + cd->tocent[i].indexes[0]; +#else + ; + +#endif + } + } else { + goto format_error; + } + if (NULL != (field = strtok (NULL, " \t\n\r"))) { + goto format_error; + } + } else { + goto not_in_global_section; + } + + /* CD_TEXT { ... } */ + /* todo: opening { must be on same line as CD_TEXT */ + } else if (0 == strcmp ("CD_TEXT", keyword)) { + } else if (0 == strcmp ("LANGUAGE_MAP", keyword)) { + } else if (0 == strcmp ("LANGUAGE", keyword)) { + } else if (0 == strcmp ("}", keyword)) { + } else if (0 == cdtext_is_keyword (keyword)) { + if (-1 == i) { + if (NULL != cd) { +#if 0 + if (NULL == cd->cdtext) + cd->cdtext = cdtext_init (); + cdtext_set (keyword, strtok (NULL, "\"\t\n\r"), cd->cdtext); +#else + ; + +#endif + } + } else { + if (NULL != cd) { +#if 0 + if (NULL == cd->tocent[i].cdtext) + cd->tocent[i].cdtext = cdtext_init (); + cdtext_set (keyword, strtok (NULL, "\"\t\n\r"), + cd->tocent[i].cdtext); +#else + ; + +#endif + } + } + + /* unrecognized line */ + } else { + cdio_log(log_level, "%s line %d: warning: unrecognized keyword: %s", + toc_name, line_num, keyword); + goto err_exit; + } + } + } + + if (NULL != cd) cd->total_tracks = i+1; + return true; + + unimplimented_error: + UNIMPLIMENTED_MSG; + goto err_exit; + + format_error: + cdio_log(log_level, "%s line %d: format error: %s", + toc_name, line_num, keyword); + goto err_exit; + + not_in_global_section: + cdio_log(log_level, "%s line %d: only allowed in global section: %s", + toc_name, line_num, keyword); + + err_exit: + fclose (fp); + return false; +} + +/*! + Reads a single audio sector from CD device into data starting + from lsn. Returns 0 if no error. + */ +static int +_read_audio_sectors_cdrdao (void *env, void *data, lsn_t lsn, + unsigned int nblocks) +{ + _img_private_t *_obj = env; + int ret; + + _init_cdrdao (_obj); + + /* Why the adjustment of 272, I don't know. It seems to work though */ + if (lsn != 0) { + ret = cdio_stream_seek (_obj->gen.data_source, + (lsn * CDIO_CD_FRAMESIZE_RAW) - 272, SEEK_SET); + if (ret!=0) return ret; + + ret = cdio_stream_read (_obj->gen.data_source, data, + CDIO_CD_FRAMESIZE_RAW, nblocks); + } else { + /* We need to pad out the first 272 bytes with 0's */ + BZERO(data, 272); + + ret = cdio_stream_seek (_obj->gen.data_source, 0, SEEK_SET); + + if (ret!=0) return ret; + + ret = cdio_stream_read (_obj->gen.data_source, (uint8_t *) data+272, + CDIO_CD_FRAMESIZE_RAW - 272, nblocks); + } + + /* ret is number of bytes if okay, but we need to return 0 okay. */ + return ret == 0; +} + +/*! + Reads a single mode2 sector from cd device into data starting + from lsn. Returns 0 if no error. + */ +static int +_read_mode1_sector_cdrdao (void *env, void *data, lsn_t lsn, + bool b_form2) +{ + _img_private_t *_obj = env; + int ret; + char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; + int blocksize = _obj->sector_2336 + ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE_RAW; + + _init_cdrdao (_obj); + + ret = cdio_stream_seek (_obj->gen.data_source, lsn * blocksize, SEEK_SET); + if (ret!=0) return ret; + + /* FIXME: Not completely sure the below is correct. */ + ret = cdio_stream_read (_obj->gen.data_source, + _obj->sector_2336 + ? (buf + CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE) + : buf, + blocksize, 1); + if (ret==0) return ret; + + memcpy (data, buf + CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE, + b_form2 ? M2RAW_SECTOR_SIZE: CDIO_CD_FRAMESIZE); + + return 0; +} + +/*! + Reads nblocks of mode1 sectors from cd device into data starting + from lsn. + Returns 0 if no error. + */ +static int +_read_mode1_sectors_cdrdao (void *env, void *data, uint32_t lsn, + bool b_form2, unsigned int nblocks) +{ + _img_private_t *_obj = env; + int i; + int retval; + unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE; + + for (i = 0; i < nblocks; i++) { + if ( (retval = _read_mode1_sector_cdrdao (_obj, + ((char *)data) + (blocksize * i), + lsn + i, b_form2)) ) + return retval; + } + return 0; +} + +/*! + Reads a single mode1 sector from cd device into data starting + from lsn. Returns 0 if no error. + */ +static int +_read_mode2_sector_cdrdao (void *env, void *data, lsn_t lsn, + bool b_form2) +{ + _img_private_t *_obj = env; + int ret; + char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; + + /* NOTE: The logic below seems a bit wrong and convoluted + to me, but passes the regression tests. (Perhaps it is why we get + valgrind errors in vcdxrip). Leave it the way it was for now. + Review this sector 2336 stuff later. + */ + + int blocksize = _obj->sector_2336 + ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE_RAW; + + _init_cdrdao (_obj); + + ret = cdio_stream_seek (_obj->gen.data_source, lsn * blocksize, SEEK_SET); + if (ret!=0) return ret; + + ret = cdio_stream_read (_obj->gen.data_source, + _obj->sector_2336 + ? (buf + CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE) + : buf, + blocksize, 1); + if (ret==0) return ret; + + + /* See NOTE above. */ + if (b_form2) + memcpy (data, buf + CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE, + M2RAW_SECTOR_SIZE); + else + memcpy (data, buf + CDIO_CD_XA_SYNC_HEADER, CDIO_CD_FRAMESIZE); + + return 0; +} + +/*! + Reads nblocks of mode2 sectors from cd device into data starting + from lsn. + Returns 0 if no error. + */ +static int +_read_mode2_sectors_cdrdao (void *env, void *data, uint32_t lsn, + bool b_form2, unsigned int nblocks) +{ + _img_private_t *_obj = env; + int i; + int retval; + unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE; + + for (i = 0; i < nblocks; i++) { + if ( (retval = _read_mode2_sector_cdrdao (_obj, + ((char *)data) + (blocksize * i), + lsn + i, b_form2)) ) + return retval; + } + return 0; +} + +#define free_if_notnull(obj) \ + if (NULL != obj) { free(obj); obj=NULL; }; + +static void +_free_cdrdao (void *obj) +{ + _img_private_t *env = obj; + int i; + + if (NULL == env) return; + free_if_notnull(env->mcn); + for (i=0; itotal_tracks; i++) { + free_if_notnull(env->tocent[i].isrc); + free_if_notnull(env->tocent[i].filename); + } + free_if_notnull(env->toc_name); + cdio_generic_stdio_free(env); + free(env); +} + +/*! + Eject media -- there's nothing to do here except free resources. + We always return 2. + */ +static int +_eject_media_cdrdao(void *obj) +{ + _free_cdrdao (obj); + return 2; +} + +/*! + Set the arg "key" with "value" in the source device. + Currently "source" to set the source device in I/O operations + is the only valid key. + + 0 is returned if no error was found, and nonzero if there as an error. +*/ +static int +_set_arg_cdrdao (void *env, const char key[], const char value[]) +{ + _img_private_t *_obj = env; + + if (!strcmp (key, "sector")) + { + if (!strcmp (value, "2336")) + _obj->sector_2336 = true; + else if (!strcmp (value, "2352")) + _obj->sector_2336 = false; + else + return -2; + } + else if (!strcmp (key, "toc")) + { + free_if_notnull (_obj->toc_name); + + if (!value) + return -2; + + _obj->toc_name = strdup (value); + } + else + return -1; + + return 0; +} + +/*! + Return the value associated with the key "arg". +*/ +static const char * +_get_arg_cdrdao (void *env, const char key[]) +{ + _img_private_t *_obj = env; + + if (!strcmp (key, "source")) { + return _obj->gen.source_name; + } else if (!strcmp (key, "toc")) { + return _obj->toc_name; + } + return NULL; +} + +/*! + Return an array of strings giving possible TOC disk images. + */ +char ** +cdio_get_devices_cdrdao (void) +{ + char **drives = NULL; + unsigned int num_files=0; +#ifdef HAVE_GLOB_H + unsigned int i; + glob_t globbuf; + globbuf.gl_offs = 0; + glob("*.toc", GLOB_DOOFFS, NULL, &globbuf); + for (i=0; igen.init) _init_cdrdao(_obj); + + if (track_num > _obj->total_tracks || track_num == 0) + return TRACK_FORMAT_ERROR; + + return _obj->tocent[track_num-1].track_format; +} + +/*! + Return true if we have XA data (green, mode2 form1) or + XA data (green, mode2 form2). That is track begins: + sync - header - subheader + 12 4 - 8 + + FIXME: there's gotta be a better design for this and get_track_format? +*/ +static bool +_get_track_green_cdrdao(void *env, track_t track_num) +{ + _img_private_t *_obj = env; + + if (!_obj->gen.init) _init_cdrdao(_obj); + + if (track_num > _obj->total_tracks || track_num == 0) + return false; + + return _obj->tocent[track_num-1].track_green; +} + +/*! + Return the starting LSN track number + track_num in obj. Track numbers start at 1. + The "leadout" track is specified either by + using track_num LEADOUT_TRACK or the total tracks+1. + False is returned if there is no track entry. +*/ +static lba_t +_get_lba_track_cdrdao(void *env, track_t track_num) +{ + _img_private_t *_obj = env; + _init_cdrdao (_obj); + + if (track_num == CDIO_CDROM_LEADOUT_TRACK) track_num = _obj->total_tracks+1; + + if (track_num <= _obj->total_tracks+1 && track_num != 0) { + return _obj->tocent[track_num-1].start_lba; + } else + return CDIO_INVALID_LBA; +} + +/*! + Check that a TOC file is valid. + +*/ +/* Later we'll probably parse the entire file. For now though, this gets us + started for now. +*/ +bool +cdio_is_tocfile(const char *toc_name) +{ + int i; + + if (toc_name == NULL) return false; + + i=strlen(toc_name)-strlen("toc"); + + if (i>0) { + if ( (toc_name[i]=='t' && toc_name[i+1]=='o' && toc_name[i+2]=='c') + || (toc_name[i]=='T' && toc_name[i+1]=='O' && toc_name[i+2]=='C') ) { + return parse_tocfile(NULL, toc_name); + } + } + return false; +} + +/*! + Initialization routine. This is the only thing that doesn't + get called via a function pointer. In fact *we* are the + ones to set that up. + */ +CdIo * +cdio_open_am_cdrdao (const char *psz_source_name, const char *psz_access_mode) +{ + if (psz_access_mode != NULL) + cdio_warn ("there is only one access mode for toc. Arg %s ignored", + psz_access_mode); + return cdio_open_cdrdao(psz_source_name); +} + +/*! + Initialization routine. This is the only thing that doesn't + get called via a function pointer. In fact *we* are the + ones to set that up. + */ +CdIo * +cdio_open_cdrdao (const char *toc_name) +{ + CdIo *ret; + _img_private_t *_data; + + cdio_funcs _funcs = { + .eject_media = _eject_media_cdrdao, + .free = _free_cdrdao, + .get_arg = _get_arg_cdrdao, + .get_devices = cdio_get_devices_cdrdao, + .get_default_device = cdio_get_default_device_cdrdao, + .get_drive_cap = _get_drive_cap_cdrdao, + .get_first_track_num= _get_first_track_num_image, + .get_mcn = _get_mcn_image, + .get_num_tracks = _get_num_tracks_image, + .get_track_format = _get_track_format_cdrdao, + .get_track_green = _get_track_green_cdrdao, + .get_track_lba = _get_lba_track_cdrdao, + .get_track_msf = _get_track_msf_image, + .lseek = _lseek_cdrdao, + .read = _read_cdrdao, + .read_audio_sectors = _read_audio_sectors_cdrdao, + .read_mode1_sector = _read_mode1_sector_cdrdao, + .read_mode1_sectors = _read_mode1_sectors_cdrdao, + .read_mode2_sector = _read_mode2_sector_cdrdao, + .read_mode2_sectors = _read_mode2_sectors_cdrdao, + .set_arg = _set_arg_cdrdao, + .stat_size = _stat_size_cdrdao + }; + + if (NULL == toc_name) return NULL; + + _data = _cdio_malloc (sizeof (_img_private_t)); + (_data)->gen.init = false; + (_data)->sector_2336 = false; + (_data)->toc_name = NULL; + + ret = cdio_new (_data, &_funcs); + + if (ret == NULL) return NULL; + + if (!cdio_is_tocfile(toc_name)) { + cdio_debug ("source name %s is not recognized as a TOC file", toc_name); + return NULL; + } + + _set_arg_cdrdao (_data, "toc", toc_name); + + if (_init_cdrdao(_data)) { + return ret; + } else { + _free_cdrdao(_data); + free(ret); + return NULL; + } +} + +bool +cdio_have_cdrdao (void) +{ + return true; +} diff --git a/src/cd-info.c b/src/cd-info.c index 8390f1ee..69cd3a7b 100644 --- a/src/cd-info.c +++ b/src/cd-info.c @@ -1,5 +1,5 @@ /* - $Id: cd-info.c,v 1.58 2004/04/25 00:46:34 rocky Exp $ + $Id: cd-info.c,v 1.59 2004/05/04 02:06:48 rocky Exp $ Copyright (C) 2003, 2004 Rocky Bernstein Copyright (C) 1996, 1997, 1998 Gerd Knorr @@ -105,6 +105,7 @@ enum { OP_SOURCE_AUTO, OP_SOURCE_BIN, OP_SOURCE_CUE, + OP_SOURCE_CDRDAO, OP_SOURCE_NRG , OP_SOURCE_DEVICE, @@ -197,6 +198,9 @@ parse_options (int argc, const char *argv[]) {"nrg-file", 'N', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, &source_name, OP_SOURCE_NRG, "set Nero CD-ROM disk image file as source", "FILE"}, + {"toc-file", 't', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, &source_name, + OP_SOURCE_CDRDAO, "set cdrdao CD-ROM disk image file as source", "FILE"}, + {"quiet", 'q', POPT_ARG_NONE, &opts.silent, 0, "Don't produce warning output" }, @@ -215,6 +219,7 @@ parse_options (int argc, const char *argv[]) case OP_SOURCE_AUTO: case OP_SOURCE_BIN: case OP_SOURCE_CUE: + case OP_SOURCE_CDRDAO: case OP_SOURCE_NRG: case OP_SOURCE_DEVICE: if (opts.source_image != IMAGE_UNKNOWN) { @@ -232,6 +237,9 @@ parse_options (int argc, const char *argv[]) case OP_SOURCE_CUE: opts.source_image = IMAGE_CUE; break; + case OP_SOURCE_CDRDAO: + opts.source_image = IMAGE_CDRDAO; + break; case OP_SOURCE_NRG: opts.source_image = IMAGE_NRG; break; @@ -255,7 +263,8 @@ parse_options (int argc, const char *argv[]) if ( remaining_arg != NULL) { if (opts.source_image != IMAGE_UNKNOWN) { fprintf (stderr, - "%s: Source specified in option %s and as %s\n", + "%s: Source '%s' given as an argument of an option and as " + "unnamed option '%s'\n", program_name, source_name, remaining_arg); poptFreeContext(optCon); free(program_name); @@ -444,10 +453,10 @@ print_cddb_info(CdIo *cdio, track_t num_tracks, track_t first_track_num) { #ifdef HAVE_VCDINFO static void -print_vcd_info(void) { +print_vcd_info(driver_id_t driver) { vcdinfo_open_return_t open_rc; vcdinfo_obj_t *obj; - open_rc = vcdinfo_open(&obj, &source_name, DRIVER_UNKNOWN, NULL); + open_rc = vcdinfo_open(&obj, &source_name, driver, NULL); switch (open_rc) { case VCDINFO_OPEN_VCD: if (vcdinfo_get_format_version (obj) == VCD_TYPE_INVALID) { @@ -691,7 +700,7 @@ print_analysis(int ms_offset, cdio_iso_analysis_t cdio_iso_analysis, if (fs & (CDIO_FS_ANAL_VIDEOCD|CDIO_FS_ANAL_CVD|CDIO_FS_ANAL_SVCD)) if (!opts.no_vcd) { printf("\n"); - print_vcd_info(); + print_vcd_info(cdio_get_driver_id(cdio)); } #endif @@ -811,6 +820,14 @@ main(int argc, const char *argv[]) program_name, source_name); } break; + + case IMAGE_CDRDAO: + cdio = cdio_open (source_name, DRIVER_CDRDAO); + if (cdio==NULL) { + err_exit("%s: Error in opening TOC with input %s\n", + program_name, source_name); + } + break; } if (cdio==NULL) { diff --git a/src/cd-read.c b/src/cd-read.c index f62608e0..15a149bb 100644 --- a/src/cd-read.c +++ b/src/cd-read.c @@ -1,5 +1,5 @@ /* - $Id: cd-read.c,v 1.16 2004/02/07 02:40:20 rocky Exp $ + $Id: cd-read.c,v 1.17 2004/05/04 02:06:48 rocky Exp $ Copyright (C) 2003 Rocky Bernstein @@ -41,6 +41,7 @@ enum { OP_SOURCE_BIN, OP_SOURCE_CUE, OP_SOURCE_NRG = DRIVER_NRG, + OP_SOURCE_CDRDAO = DRIVER_CDRDAO, OP_SOURCE_DEVICE = DRIVER_DEVICE, /* These are the remaining configuration options */ @@ -219,6 +220,9 @@ parse_options (int argc, const char *argv[]) {"nrg-file", 'N', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, &source_name, OP_SOURCE_NRG, "set Nero CD-ROM disk image file as source", "FILE"}, + {"toc-file", 't', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, &source_name, + OP_SOURCE_CDRDAO, "set \"TOC\" CD-ROM disk image file as source", "FILE"}, + {"output-file", 'o', POPT_ARG_STRING, &opts.output_file, 0, "Output blocks to file rather than give a hexdump."}, @@ -472,6 +476,14 @@ main(int argc, const char *argv[]) source_name); } break; + + case IMAGE_CDRDAO: + cdio = cdio_open (source_name, DRIVER_CDRDAO); + if (cdio==NULL) { + err_exit("Error in opening TOC file %s for input\n", + source_name); + } + break; } if (opts.access_mode!=NULL) { diff --git a/src/util.h b/src/util.h index bd90bb28..0bee05ed 100644 --- a/src/util.h +++ b/src/util.h @@ -1,5 +1,5 @@ /* - $Id: util.h,v 1.3 2004/04/25 00:46:34 rocky Exp $ + $Id: util.h,v 1.4 2004/05/04 02:06:48 rocky Exp $ Copyright (C) 2003, 2004 Rocky Bernstein @@ -85,6 +85,7 @@ typedef enum IMAGE_BIN, IMAGE_CUE, IMAGE_NRG, + IMAGE_CDRDAO, IMAGE_UNKNOWN } source_image_t; diff --git a/test/Makefile.am b/test/Makefile.am index bd745836..218fdf15 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.18 2004/02/29 15:04:27 rocky Exp $ +# $Id: Makefile.am,v 1.19 2004/05/04 02:06:48 rocky Exp $ # # Copyright (C) 2003, 2004 Rocky Bernstein # @@ -41,8 +41,8 @@ check_PROGRAMS = $(hack) check_DATA = vcd_demo.right \ videocd.right videocd.nrg \ - cdda.right cdda.cue cdda.bin \ - isofs-m1.right isofs-m1.cue isofs-m1.bin \ + cdda.right cdda.toc cdda.cue cdda.bin \ + isofs-m1.right isfs-m1.toc isofs-m1.cue isofs-m1.bin \ check_opts0.right check_opts1.right check_opts2.right \ check_opts3.right check_opts4.right check_opts5.right \ check_opts6.right check_opts7.right \ diff --git a/test/check_cue.sh.in b/test/check_cue.sh.in index c4d6e367..2589c424 100644 --- a/test/check_cue.sh.in +++ b/test/check_cue.sh.in @@ -1,6 +1,8 @@ #!/bin/sh -#$Id: check_cue.sh.in,v 1.15 2003/10/06 04:04:05 rocky Exp $ -# Tests to see that BIN/CUE file iamge reading is correct (via cd-info). +#$Id: check_cue.sh.in,v 1.16 2004/05/04 02:06:49 rocky Exp $ +# Tests to see that BIN/CUE and BIN/TOC file iamge reading is correct +# (via cd-info). + if test -n "@VCDINFO_LIBS@" ; then vcd_opt='--no-vcd' fi @@ -29,15 +31,30 @@ test_cdinfo "--quiet --bin-file ${srcdir}/${fname}.bin --no-cddb" \ RC=$? check_result $RC "cd-info BIN test $testnum" +test_cdinfo "--quiet --toc-file ${srcdir}/${fname}.toc --no-cddb" \ + ${fname}.dump ${srcdir}/${fname}.right +RC=$? +check_result $RC "cd-info TOC test $testnum" + fname=isofs-m1 -testnum='ISO 9660 mode1' +testnum='ISO 9660 mode1 CUE' if test -f ${srcdir}/${fname}.bin ; then test_cdinfo "-q --cue-file ${srcdir}/${fname}.cue --iso9660" \ ${fname}.dump ${srcdir}/${fname}.right RC=$? check_result $RC "cd-info CUE test $testnum" else - echo "Don't see CUE file ${srcdir}/${fname}.bin. Test $testum skipped." + echo "Don't see CUE file ${srcdir}/${fname}.bin. Test $testnum skipped." +fi + +testnum='ISO 9660 mode1 TOC' +if test -f ${srcdir}/${fname}.bin ; then + test_cdinfo "-q --toc-file ${srcdir}/${fname}.toc --iso9660" \ + ${fname}.dump ${srcdir}/${fname}.right + RC=$? + check_result $RC "cd-info TOC test $testnum" +else + echo "Don't see TOC file ${srcdir}/${fname}.bin. Test $testnum skipped." fi fname=vcd_demo @@ -53,7 +70,16 @@ if test -f ${srcdir}/${fname}.cue ; then RC=$? check_result $RC "cd-info CUE test $testnum" else - echo "Don't see CUE file ${srcdir}/${fname}.cue. Test $testum skipped." + echo "Don't see CUE file ${srcdir}/${fname}.cue. Test $testnum skipped." +fi + +if test -f ${srcdir}/${fname}.toc ; then + test_cdinfo "-q -t ${srcdir}/vcd_demo.toc --iso9660" \ + ${fname}.dump $right + RC=$? + check_result $RC "cd-info TOC test $testnum" +else + echo "Don't see TOC file ${srcdir}/${fname}.toc. Test $testnum skipped." fi fname=svcd_ogt_test_ntsc diff --git a/test/isofs-m1.toc b/test/isofs-m1.toc new file mode 100644 index 00000000..15bd806d --- /dev/null +++ b/test/isofs-m1.toc @@ -0,0 +1,5 @@ +CATALOG "0000010271955" +CD_DA + +TRACK MODE1_RAW +FILE "isofs-m1.bin" 00:00:00 00:00:00 diff --git a/test/vcd_demo.toc b/test/vcd_demo.toc new file mode 100644 index 00000000..438c0eff --- /dev/null +++ b/test/vcd_demo.toc @@ -0,0 +1,15 @@ +CD_DA + +TRACK MODE2_RAW +COPY +FILE "vcd_demo.bin" 00:00:00 00:13:57 + +TRACK MODE2_RAW +COPY +FILE "vcd_demo.bin" 00:13:57 00:07:14 +START 00:02:00 + +TRACK MODE2_RAW +COPY +FILE "vcd_demo.bin" 00:20:71 00:00:00 +START 00:02:00