diff options
Diffstat (limited to 'src/input/vcd/libcdio')
40 files changed, 13729 insertions, 0 deletions
diff --git a/src/input/vcd/libcdio/Makefile.am b/src/input/vcd/libcdio/Makefile.am new file mode 100644 index 000000000..eef45b69f --- /dev/null +++ b/src/input/vcd/libcdio/Makefile.am @@ -0,0 +1,71 @@ +SUBDIRS = cdio + +LIBTOOL = $(SHELL) $(top_builddir)/libtool-nofpic +INCLUDES = $(LIBCDIO_CFLAGS) + +libcdio_SRCS = \ + _cdio_bincue.c \ + _cdio_bsdi.c \ + _cdio_freebsd.c \ + _cdio_generic.c \ + _cdio_linux.c \ + _cdio_osx.c \ + _cdio_nrg.c \ + _cdio_stdio.c \ + _cdio_stream.c \ + _cdio_sunos.c \ + _cdio_win32.c \ + cdio.c \ + cd_types.c \ + ds.c \ + logging.c \ + sector.c \ + util.c +libiso9660_SRCS = \ + iso9660.c \ + iso9660_fs.c \ + xa.c + +if ENABLE_VCDX +if HAVE_VCDNAV +EXTRA_DIST = $(libcdio_SRCS) $(libio9660_SRCS) +else +noinst_LTLIBRARIES = libcdio.la libiso9660.la +libcdio_la_SOURCES = $(libcdio_SRCS) +libcdio_la_LDFLAGS = -avoid-version -module +libiso9660_la_SOURCES = $(libiso9660_SRCS) +libiso9660_la_LDFLAGS = -avoid-version -module +endif +endif + +noinst_HEADERS = \ + bytesex_asm.h \ + cdio_assert.h \ + _cdio_stdio.h \ + ds.h \ + scsi_mmc.h \ + bytesex.h \ + cdio_private.h \ + _cdio_stream.h \ + iso9660_private.h + + +debug: + @list='$(SUBDIRS)'; for subdir in $$list; do \ + (cd $$subdir && $(MAKE) $@) || exit;\ + done; + @$(MAKE) CFLAGS="$(DEBUG_CFLAGS)" + +install-debug: debug + @list='$(SUBDIRS)'; for subdir in $$list; do \ + (cd $$subdir && $(MAKE) $@) || exit;\ + done; + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +mostlyclean-generic: + -rm -f *~ \#* .*~ .\#* + +maintainer-clean-generic: + -@echo "This command is intended for maintainers to use;" + -@echo "it deletes files that may require special tools to rebuild." + -rm -f Makefile.in diff --git a/src/input/vcd/libcdio/_cdio_bincue.c b/src/input/vcd/libcdio/_cdio_bincue.c new file mode 100644 index 000000000..04293c483 --- /dev/null +++ b/src/input/vcd/libcdio/_cdio_bincue.c @@ -0,0 +1,962 @@ +/* + $Id: _cdio_bincue.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $ + + Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org> + Copyright (C) 2002,2003 Rocky Bernstein <rocky@panix.com> + + 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: _cdio_bincue.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $"; + +#include "cdio_assert.h" +#include "cdio_private.h" +#include "_cdio_stdio.h" + +#include <cdio/logging.h> +#include <cdio/sector.h> +#include <cdio/util.h> + +#ifdef HAVE_STDIO_H +#include <stdio.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#ifdef HAVE_GLOB_H +#include <glob.h> +#endif +#include <ctype.h> + +/* FIXME: should put in a common definition somewhere. */ +#ifdef HAVE_BZERO +#define BZERO(ptr, size) bzero(ptr, size) +#elif HAVE_MEMSET +#define BZERO(ptr, size) memset(ptr, 0, size) +#else + Error -- you need either memset or bzero +#endif + +/* reader */ + +#define DEFAULT_CDIO_DEVICE "videocd.bin" +#define DEFAULT_CDIO_CUE "videocd.cue" + +typedef struct { + track_t track_num; /* Probably is index+1 */ + msf_t start_msf; + lba_t start_lba; + int start_index; + int sec_count; /* Number of sectors in this track. Does not + include pregap */ + int num_indices; + int flags; /* "DCP", "4CH", "PRE" */ + 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 *cue_name; + char *mcn; /* Media catalog number. */ + 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 */ + bool have_cue; +} _img_private_t; + +static bool _cdio_image_read_cue (_img_private_t *_obj); +static uint32_t _cdio_stat_size (void *env); + +/*! + Initialize image structures. + */ +static bool +_cdio_init (_img_private_t *_obj) +{ + lsn_t lead_lsn; + + if (_obj->gen.init) + return false; + + if (!(_obj->gen.data_source = cdio_stdio_new (_obj->gen.source_name))) { + cdio_error ("init failed"); + return false; + } + + /* Have to set init before calling _cdio_stat_size() or we will + get into infinite recursion calling passing right here. + */ + _obj->gen.init = true; + + lead_lsn = _cdio_stat_size( (_img_private_t *) _obj); + + if (-1 == lead_lsn) + return false; + + /* Read in CUE sheet. */ + if ((_obj->cue_name != NULL)) { + _obj->have_cue = _cdio_image_read_cue(_obj); + } + + if (!_obj->have_cue ) { + /* Time to fake things... + Make one big track, track 0 and 1 are the same. + We are guessing stuff starts at msf 00:04:00 - 2 for the 150 + sector pregap and 2 for the cue information. + */ + track_info_t *this_track=&(_obj->tocent[0]); + int blocksize = _obj->sector_2336 + ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE_RAW; + + _obj->total_tracks = 2; + _obj->first_track_num = 1; + this_track->start_msf.m = to_bcd8(0); + this_track->start_msf.s = to_bcd8(4); + this_track->start_msf.f = to_bcd8(0); + this_track->start_lba = cdio_msf_to_lba(&this_track->start_msf); + this_track->blocksize = blocksize; + this_track->track_format= TRACK_FORMAT_XA; + this_track->track_green = true; + + + _obj->tocent[1] = _obj->tocent[0]; + } + + /* 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 +_cdio_lseek (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 +_cdio_read (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 +_cdio_stat_size (void *env) +{ + _img_private_t *_obj = env; + long size; + int blocksize = _obj->sector_2336 + ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE_RAW; + + _cdio_init (_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 + +static bool +_cdio_image_read_cue (_img_private_t *_obj) +{ + FILE *fp; + char line[MAXLINE]; + + int track_num; + int min,sec,frame; + int blocksize; + int start_index; + bool seen_first_index_for_track=false; + + if ( _obj == NULL || _obj->cue_name == NULL ) return false; + + fp = fopen (_obj->cue_name, "r"); + if (fp == NULL) return false; + + _obj->total_tracks=0; + _obj->first_track_num=1; + _obj->mcn=NULL; + + while ((fgets(line, MAXLINE, fp)) != NULL) { + char s[80]; + char *p; + /*printf("Retrieved line of length %zu :\n", read); + printf("%s", line); */ + for (p=line; isspace(*p); p++) ; + if (1==sscanf(p, "FILE \"%80s[^\"]", s)) { + /* Should expand file name based on cue file basename. + free(_obj->bin_file); + _obj->bin_file = strdup(s); + */ + /* printf("Found file name %s\n", s); */ + } else if (1==sscanf(p, "CATALOG %80s", s)) { + _obj->mcn = strdup(s); + } else if (2==sscanf(p, "TRACK %d MODE2/%d", &track_num, &blocksize)) { + track_info_t *this_track=&(_obj->tocent[_obj->total_tracks]); + this_track->track_num = track_num; + this_track->num_indices = 0; + this_track->track_format= TRACK_FORMAT_XA; + this_track->track_green = true; + _obj->total_tracks++; + seen_first_index_for_track=false; + /*printf("Added track %d with blocksize %d\n", track_num, blocksize);*/ + + this_track->blocksize = blocksize; + switch(blocksize) { + case 2336: + this_track->datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE; + this_track->datasize = M2RAW_SECTOR_SIZE; + this_track->endsize = 0; + break; + default: + cdio_warn ("Unknown MODE2 size %d. Assuming 2352", blocksize); + case 2352: + if (_obj->sector_2336) { + this_track->datastart = 0; + this_track->datasize = M2RAW_SECTOR_SIZE; + this_track->endsize = blocksize - 2336; + } else { + this_track->datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE + + CDIO_CD_SUBHEADER_SIZE; + this_track->datasize = CDIO_CD_FRAMESIZE; + this_track->endsize = CDIO_CD_SYNC_SIZE + CDIO_CD_ECC_SIZE; + } + break; + } + + } else if (2==sscanf(p, "TRACK %d MODE1/%d", &track_num, &blocksize)) { + track_info_t *this_track=&(_obj->tocent[_obj->total_tracks]); + this_track->blocksize = blocksize; + this_track->blocksize = blocksize; + switch(blocksize) { + case 2048: + /* Is the below correct? */ + this_track->datastart = 0; + this_track->datasize = CDIO_CD_FRAMESIZE; + this_track->endsize = 0; + break; + default: + cdio_warn ("Unknown MODE1 size %d. Assuming 2352", blocksize); + case 2352: + this_track->datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE; + this_track->datasize = CDIO_CD_FRAMESIZE; + this_track->endsize = CDIO_CD_EDC_SIZE + CDIO_CD_M1F1_ZERO_SIZE + + CDIO_CD_ECC_SIZE; + } + + this_track->track_num = track_num; + this_track->num_indices = 0; + this_track->track_format = TRACK_FORMAT_DATA; + this_track->track_green = false; + _obj->total_tracks++; + seen_first_index_for_track=false; + /*printf("Added track %d with blocksize %d\n", track_num, blocksize);*/ + + } else if (1==sscanf(p, "TRACK %d AUDIO", &track_num)) { + track_info_t *this_track=&(_obj->tocent[_obj->total_tracks]); + this_track->blocksize = CDIO_CD_FRAMESIZE_RAW; + this_track->datasize = CDIO_CD_FRAMESIZE_RAW; + this_track->datastart = 0; + this_track->endsize = 0; + this_track->track_num = track_num; + this_track->num_indices = 0; + this_track->track_format = TRACK_FORMAT_AUDIO; + this_track->track_green = false; + _obj->total_tracks++; + seen_first_index_for_track=false; + + } else if (4==sscanf(p, "INDEX %d %d:%d:%d", + &start_index, &min, &sec, &frame)) { + track_info_t *this_track=&(_obj->tocent[_obj->total_tracks-1]); + /* FIXME! all of this is a big hack. + If start_index == 0, then this is the "last_cue" information. + The +2 below seconds is to adjust for the 150 pregap. + */ + if (start_index != 0) { + if (!seen_first_index_for_track) { + this_track->start_index = start_index; + sec += 2; + if (sec >= 60) { + min++; + sec -= 60; + } + this_track->start_msf.m = to_bcd8 (min); + this_track->start_msf.s = to_bcd8 (sec); + this_track->start_msf.f = to_bcd8 (frame); + this_track->start_lba = cdio_msf_to_lba(&this_track->start_msf); + seen_first_index_for_track=true; + } + + if (_obj->total_tracks > 1) { + /* Figure out number of sectors for previous track */ + track_info_t *prev_track=&(_obj->tocent[_obj->total_tracks-2]); + if ( this_track->start_lba < prev_track->start_lba ) { + cdio_warn("track %d at LBA %lu starts before track %d at LBA %lu", + _obj->total_tracks, + (unsigned long int) this_track->start_lba, + _obj->total_tracks-1, + (unsigned long int) prev_track->start_lba); + prev_track->sec_count = 0; + } else if ( this_track->start_lba >= prev_track->start_lba + + CDIO_PREGAP_SECTORS ) { + prev_track->sec_count = this_track->start_lba - + prev_track->start_lba - CDIO_PREGAP_SECTORS ; + } else { + cdio_warn ("%lu fewer than pregap (%d) sectors in track %d", + (long unsigned int) + this_track->start_lba - prev_track->start_lba, + CDIO_PREGAP_SECTORS, + _obj->total_tracks-1); + /* Include pregap portion in sec_count. Maybe the pregap + was omitted. */ + prev_track->sec_count = this_track->start_lba - + prev_track->start_lba; + } + } + this_track->num_indices++; + } + } + } + _obj->have_cue = _obj->total_tracks != 0; + + fclose (fp); + return true; +} + +/*! + Reads a single audio sector from CD device into data starting + from lsn. Returns 0 if no error. + */ +static int +_cdio_read_audio_sectors (void *env, void *data, lsn_t lsn, + unsigned int nblocks) +{ + _img_private_t *_obj = env; + int ret; + + _cdio_init (_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); + } + + return ret; +} + +/*! + Reads a single mode2 sector from cd device into data starting + from lsn. Returns 0 if no error. + */ +static int +_cdio_read_mode2_sector (void *env, void *data, lsn_t lsn, + bool mode2_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; + + _cdio_init (_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; + + if (mode2_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 +_cdio_read_mode2_sectors (void *env, void *data, uint32_t lsn, + bool mode2_form2, unsigned int nblocks) +{ + _img_private_t *_obj = env; + int i; + int retval; + + for (i = 0; i < nblocks; i++) { + if (mode2_form2) { + if ( (retval = _cdio_read_mode2_sector (_obj, + ((char *)data) + (M2RAW_SECTOR_SIZE * i), + lsn + i, true)) ) + return retval; + } else { + char buf[M2RAW_SECTOR_SIZE] = { 0, }; + if ( (retval = _cdio_read_mode2_sector (_obj, buf, lsn + i, true)) ) + return retval; + + memcpy (((char *)data) + (CDIO_CD_FRAMESIZE * i), + buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE); + } + } + return 0; +} + +#define free_if_notnull(obj) \ + if (NULL != obj) free(obj); + +static void +_cdio_bincue_free (void *env) { + _img_private_t *_obj = env; + + if (NULL == _obj) return; + free_if_notnull(_obj->mcn); + cdio_generic_stream_free(_obj); +} + +/*! + 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. +*/ +/*! + Set the device to use in I/O operations. +*/ +static int +_cdio_set_arg (void *env, const char key[], const char value[]) +{ + _img_private_t *_obj = env; + + if (!strcmp (key, "source")) + { + free_if_notnull (_obj->gen.source_name); + + if (!value) + return -2; + + _obj->gen.source_name = strdup (value); + } + else 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, "cue")) + { + free_if_notnull (_obj->cue_name); + + if (!value) + return -2; + + _obj->cue_name = strdup (value); + } + else + return -1; + + return 0; +} + +/*! + Return the value associated with the key "arg". +*/ +static const char * +_cdio_get_arg (void *env, const char key[]) +{ + _img_private_t *_obj = env; + + if (!strcmp (key, "source")) { + return _obj->gen.source_name; + } else if (!strcmp (key, "cue")) { + return _obj->cue_name; + } + return NULL; +} + +/*! + Return an array of strings giving possible NRG disk images. + */ +char ** +cdio_get_devices_bincue (void) +{ + char **drives = NULL; + unsigned int num_files=0; +#ifdef HAVE_GLOB_H + unsigned int i; + glob_t globbuf; + globbuf.gl_offs = 0; + glob("*.cue", GLOB_DOOFFS, NULL, &globbuf); + for (i=0; i<globbuf.gl_pathc; i++) { + cdio_add_device_list(&drives, globbuf.gl_pathv[i], &num_files); + } + globfree(&globbuf); +#else + cdio_add_device_list(&drives, DEFAULT_CDIO_DEVICE, &num_files); +#endif /*HAVE_GLOB_H*/ + cdio_add_device_list(&drives, NULL, &num_files); + return drives; +} + +/*! + Return a string containing the default CD device. + */ +char * +cdio_get_default_device_bincue(void) +{ + char **drives = cdio_get_devices_nrg(); + char *drive = (drives[0] == NULL) ? NULL : strdup(drives[0]); + cdio_free_device_list(drives); + return drive; +} + +/*! + Return the number of of the first track. + CDIO_INVALID_TRACK is returned on error. +*/ +static track_t +_cdio_get_first_track_num(void *env) +{ + _img_private_t *_obj = env; + + _cdio_init (_obj); + + return _obj->first_track_num; +} + +/*! + Return the media catalog number (MCN) from the CD or NULL if there + is none or we don't have the ability to get it. + + Note: string is malloc'd so caller has to free() the returned + string when done with it. + */ +static char * +_cdio_get_mcn(void *env) +{ + _img_private_t *_obj = env; + + _cdio_init (_obj); + + if (NULL == _obj->mcn) return NULL; + return strdup(_obj->mcn); +} + +/*! + Return the number of tracks in the current medium. + If no cuesheet is available, We fake it an just say there's + one big track. + CDIO_INVALID_TRACK is returned on error. +*/ +static track_t +_cdio_get_num_tracks(void *env) +{ + _img_private_t *_obj = env; + _cdio_init (_obj); + + return _obj->have_cue && _obj->total_tracks > 0 ? _obj->total_tracks : 1; +} + +/*! + Return the number of tracks in the current medium. + CDIO_INVALID_TRACK is returned on error. +*/ +static track_format_t +_cdio_get_track_format(void *env, track_t track_num) +{ + _img_private_t *_obj = env; + + if (!_obj->gen.init) _cdio_init(_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 +_cdio_get_track_green(void *env, track_t track_num) +{ + _img_private_t *_obj = env; + + if (!_obj->gen.init) _cdio_init(_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 +_cdio_get_track_lba(void *env, track_t track_num) +{ + _img_private_t *_obj = env; + _cdio_init (_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; +} + +/*! + Return the starting MSF (minutes/secs/frames) for the track number + track_num in obj. Tracks numbers start at 1. + The "leadout" track is specified either by + using track_num LEADOUT_TRACK or the total tracks+1. + +*/ +static bool +_cdio_get_track_msf(void *env, track_t track_num, msf_t *msf) +{ + _img_private_t *_obj = env; + _cdio_init (_obj); + + if (NULL == msf) return false; + + if (track_num == CDIO_CDROM_LEADOUT_TRACK) track_num = _obj->total_tracks+1; + + if (track_num <= _obj->total_tracks+1 && track_num != 0) { + *msf = _obj->tocent[track_num-1].start_msf; + return true; + } else + return false; +} + +/*! + Return corresponding BIN file if cue_name is a cue file or NULL + if not a CUE file. + +*/ +/* Later we'll probably parse the entire file. For now though, this gets us + started for now. +*/ +char * +cdio_is_cuefile(const char *cue_name) +{ + int i; + char *bin_name; + + if (cue_name == NULL) return false; + + bin_name=strdup(cue_name); + i=strlen(bin_name)-strlen("cue"); + + if (i>0) { + if (cue_name[i]=='c' && cue_name[i+1]=='u' && cue_name[i+2]=='e') { + bin_name[i++]='b'; bin_name[i++]='i'; bin_name[i++]='n'; + return bin_name; + } + else if (cue_name[i]=='C' && cue_name[i+1]=='U' && cue_name[i+2]=='E') { + bin_name[i++]='B'; bin_name[i++]='I'; bin_name[i++]='N'; + return bin_name; + } + } + free(bin_name); + return NULL; +} + +/*! + Return corresponding CUE file if bin_name is a bin file or NULL + if not a BIN file. + +*/ +/* Later we'll probably do better. For now though, this gets us + started for now. +*/ +char * +cdio_is_binfile(const char *bin_name) +{ + int i; + char *cue_name; + + if (bin_name == NULL) return false; + + cue_name=strdup(bin_name); + i=strlen(bin_name)-strlen("bin"); + + if (i>0) { + if (bin_name[i]=='b' && bin_name[i+1]=='i' && bin_name[i+2]=='n') { + cue_name[i++]='c'; cue_name[i++]='u'; cue_name[i++]='e'; + return cue_name; + } + else if (bin_name[i]=='B' && bin_name[i+1]=='I' && bin_name[i+2]=='N') { + cue_name[i++]='C'; cue_name[i++]='U'; cue_name[i++]='E'; + return cue_name; + } + } + free(cue_name); + return NULL; +} + +static CdIo * +cdio_open_common (_img_private_t **_data) +{ + cdio_funcs _funcs = { + .eject_media = cdio_generic_bogus_eject_media, + .free = _cdio_bincue_free, + .get_arg = _cdio_get_arg, + .get_default_device = cdio_get_default_device_bincue, + .get_first_track_num= _cdio_get_first_track_num, + .get_mcn = _cdio_get_mcn, + .get_num_tracks = _cdio_get_num_tracks, + .get_track_format = _cdio_get_track_format, + .get_track_green = _cdio_get_track_green, + .get_track_lba = _cdio_get_track_lba, + .get_track_msf = _cdio_get_track_msf, + .lseek = _cdio_lseek, + .read = _cdio_read, + .read_audio_sectors = _cdio_read_audio_sectors, + .read_mode2_sector = _cdio_read_mode2_sector, + .read_mode2_sectors = _cdio_read_mode2_sectors, + .set_arg = _cdio_set_arg, + .stat_size = _cdio_stat_size + }; + + *_data = _cdio_malloc (sizeof (_img_private_t)); + (*_data)->gen.init = false; + (*_data)->sector_2336 = false; + (*_data)->cue_name = NULL; + + return cdio_new (*_data, &_funcs); +} + +CdIo * +cdio_open_bincue (const char *source_name) +{ + char *bin_name = cdio_is_cuefile(source_name); + + if (NULL != bin_name) { + return cdio_open_cue(source_name); + } else { + char *cue_name = cdio_is_binfile(source_name); + CdIo *cdio = cdio_open_cue(cue_name); + free(cue_name); + return cdio; + } +} + +CdIo * +cdio_open_cue (const char *cue_name) +{ + CdIo *ret; + _img_private_t *_data; + char *bin_name; + + if (NULL == cue_name) return NULL; + ret = cdio_open_common(&_data); + if (ret == NULL) return NULL; + + bin_name = cdio_is_cuefile(cue_name); + + if (NULL == bin_name) { + cdio_error ("source name %s is not recognized as a CUE file", cue_name); + } + + _cdio_set_arg (_data, "cue", cue_name); + _cdio_set_arg (_data, "source", bin_name); + free(bin_name); + + if (_cdio_init(_data)) { + return ret; + } else { + cdio_generic_stream_free (_data); + return NULL; + } +} + +bool +cdio_have_bincue (void) +{ + return true; +} diff --git a/src/input/vcd/libcdio/_cdio_bsdi.c b/src/input/vcd/libcdio/_cdio_bsdi.c new file mode 100644 index 000000000..c3770b592 --- /dev/null +++ b/src/input/vcd/libcdio/_cdio_bsdi.c @@ -0,0 +1,710 @@ +/* + $Id: _cdio_bsdi.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $ + + Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org> + Copyright (C) 2002,2003 Rocky Bernstein <rocky@panix.com> + + 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 file contains BSDI-specific code and implements low-level + control of the CD drive. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +static const char _rcsid[] = "$Id: _cdio_bsdi.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $"; + +#include <cdio/sector.h> +#include <cdio/util.h> +#include "cdio_assert.h" +#include "cdio_private.h" + +#define DEFAULT_CDIO_DEVICE "/dev/rsr0c" +#include <string.h> + +#ifdef HAVE_BSDI_CDROM + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> + +/*#define USE_ETC_FSTAB*/ +#ifdef USE_ETC_FSTAB +#include <fstab.h> +#endif + +#include <dvd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/ioctl.h> + +#define TOTAL_TRACKS (_obj->tochdr.cdth_trk1) +#define FIRST_TRACK_NUM (_obj->tochdr.cdth_trk0) + +typedef struct { + /* Things common to all drivers like this. + This must be first. */ + generic_img_private_t gen; + + enum { + _AM_NONE, + _AM_IOCTL, + } access_mode; + + char *source_name; + + bool init; + + /* Track information */ + bool toc_init; /* if true, info below is valid. */ + struct cdrom_tochdr tochdr; + struct cdrom_tocentry tocent[100]; /* entry info for each track */ + +} _img_private_t; + +/* Check a drive to see if it is a CD-ROM + Return 1 if a CD-ROM. 0 if it exists but isn't a CD-ROM drive + and -1 if no device exists . +*/ +static bool +cdio_is_cdrom(char *drive, char *mnttype) +{ + bool is_cd=false; + int cdfd; + struct cdrom_tochdr tochdr; + + /* If it doesn't exist, return -1 */ + if ( !cdio_is_device_quiet_generic(drive) ) { + return(false); + } + + /* If it does exist, verify that it's an available CD-ROM */ + cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0); + + /* Should we want to test the condition in more detail: + ENOENT is the error for /dev/xxxxx does not exist; + ENODEV means there's no drive present. */ + + if ( cdfd >= 0 ) { + if ( ioctl(cdfd, CDROMREADTOCHDR, &tochdr) != -1 ) { + is_cd = true; + } + close(cdfd); + } + /* Even if we can't read it, it might be mounted */ + else if ( mnttype && (strcmp(mnttype, "cd9660") == 0) ) { + is_cd = true; + } + return(is_cd); +} + +/*! + Initialize CD device. + */ +static bool +_cdio_init (_img_private_t *_obj) +{ + if (_obj->gen.init) { + cdio_error ("init called more than once"); + return false; + } + + _obj->gen.fd = open (_obj->source_name, O_RDONLY, 0); + + if (_obj->gen.fd < 0) + { + cdio_error ("open (%s): %s", _obj->source_name, strerror (errno)); + return false; + } + + _obj->gen.init = true; + _obj->toc_init = false; + return true; +} + +/* Read audio sectors +*/ +static int +_read_audio_sectors (void *env, void *data, lsn_t lsn, + unsigned int nblocks) +{ + char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; + struct cdrom_msf *msf = (struct cdrom_msf *) &buf; + msf_t _msf; + + _img_private_t *_obj = env; + + cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf); + msf->cdmsf_min0 = from_bcd8(_msf.m); + msf->cdmsf_sec0 = from_bcd8(_msf.s); + msf->cdmsf_frame0 = from_bcd8(_msf.f); + + if (_obj->gen.ioctls_debugged == 75) + cdio_debug ("only displaying every 75th ioctl from now on"); + + if (_obj->gen.ioctls_debugged == 30 * 75) + cdio_debug ("only displaying every 30*75th ioctl from now on"); + + if (_obj->gen.ioctls_debugged < 75 + || (_obj->gen.ioctls_debugged < (30 * 75) + && _obj->gen.ioctls_debugged % 75 == 0) + || _obj->gen.ioctls_debugged % (30 * 75) == 0) + cdio_debug ("reading %2.2d:%2.2d:%2.2d", + msf->cdmsf_min0, msf->cdmsf_sec0, msf->cdmsf_frame0); + + _obj->gen.ioctls_debugged++; + + switch (_obj->access_mode) { + case _AM_NONE: + cdio_error ("no way to read audio"); + return 1; + break; + + case _AM_IOCTL: { + unsigned int i; + for (i=0; i < nblocks; i++) { + if (ioctl (_obj->gen.fd, CDROMREADRAW, &buf) == -1) { + perror ("ioctl()"); + return 1; + /* exit (EXIT_FAILURE); */ + } + memcpy (((char *)data) + (CDIO_CD_FRAMESIZE_RAW * i), buf, + CDIO_CD_FRAMESIZE_RAW); + } + break; + } + } + + return 0; +} + +/*! + Reads a single mode2 sector from cd device into data starting + from lsn. Returns 0 if no error. + */ +static int +_cdio_read_mode2_sector (void *env, void *data, lsn_t lsn, + bool mode2_form2) +{ + char buf[M2RAW_SECTOR_SIZE] = { 0, }; + struct cdrom_msf *msf = (struct cdrom_msf *) &buf; + msf_t _msf; + + _img_private_t *_obj = env; + + cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf); + msf->cdmsf_min0 = from_bcd8(_msf.m); + msf->cdmsf_sec0 = from_bcd8(_msf.s); + msf->cdmsf_frame0 = from_bcd8(_msf.f); + + if (_obj->gen.ioctls_debugged == 75) + cdio_debug ("only displaying every 75th ioctl from now on"); + + if (_obj->gen.ioctls_debugged == 30 * 75) + cdio_debug ("only displaying every 30*75th ioctl from now on"); + + if (_obj->gen.ioctls_debugged < 75 + || (_obj->gen.ioctls_debugged < (30 * 75) + && _obj->gen.ioctls_debugged % 75 == 0) + || _obj->gen.ioctls_debugged % (30 * 75) == 0) + cdio_debug ("reading %2.2d:%2.2d:%2.2d", + msf->cdmsf_min0, msf->cdmsf_sec0, msf->cdmsf_frame0); + + _obj->gen.ioctls_debugged++; + + switch (_obj->access_mode) + { + case _AM_NONE: + cdio_error ("no way to read mode2"); + return 1; + break; + + case _AM_IOCTL: + if (ioctl (_obj->gen.fd, CDROMREADMODE2, &buf) == -1) + { + perror ("ioctl()"); + return 1; + /* exit (EXIT_FAILURE); */ + } + break; + } + + if (mode2_form2) + memcpy (data, buf, M2RAW_SECTOR_SIZE); + else + memcpy (((char *)data), buf + CDIO_CD_SUBHEADER_SIZE, 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 +_cdio_read_mode2_sectors (void *env, void *data, lsn_t lsn, + bool mode2_form2, unsigned int nblocks) +{ + _img_private_t *_obj = env; + int i; + int retval; + + for (i = 0; i < nblocks; i++) { + if (mode2_form2) { + if ( (retval = _cdio_read_mode2_sector (_obj, + ((char *)data) + (M2RAW_SECTOR_SIZE * i), + lsn + i, true)) ) + return retval; + } else { + char buf[M2RAW_SECTOR_SIZE] = { 0, }; + if ( (retval = _cdio_read_mode2_sector (_obj, buf, lsn + i, true)) ) + return retval; + + memcpy (((char *)data) + (CDIO_CD_FRAMESIZE * i), + buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE); + } + } + return 0; +} + +/*! + Return the size of the CD in logical block address (LBA) units. + */ +static uint32_t +_cdio_stat_size (void *env) +{ + _img_private_t *_obj = env; + + struct cdrom_tocentry tocent; + uint32_t size; + + tocent.cdte_track = CDIO_CDROM_LEADOUT_TRACK; + tocent.cdte_format = CDROM_LBA; + if (ioctl (_obj->gen.fd, CDROMREADTOCENTRY, &tocent) == -1) + { + perror ("ioctl(CDROMREADTOCENTRY)"); + exit (EXIT_FAILURE); + } + + size = tocent.cdte_addr.lba; + + return size; +} + +/*! + Set the key "arg" to "value" in source device. +*/ +static int +_cdio_set_arg (void *env, const char key[], const char value[]) +{ + _img_private_t *_obj = env; + + if (!strcmp (key, "source")) + { + if (!value) + return -2; + + free (_obj->source_name); + + _obj->source_name = strdup (value); + } + else if (!strcmp (key, "access-mode")) + { + if (!strcmp(value, "IOCTL")) + _obj->access_mode = _AM_IOCTL; + else + cdio_error ("unknown access type: %s. ignored.", value); + } + else + return -1; + + return 0; +} + +/*! + Read and cache the CD's Track Table of Contents and track info. + Return false if successful or true if an error. +*/ +static bool +_cdio_read_toc (_img_private_t *_obj) +{ + int i; + + /* read TOC header */ + if ( ioctl(_obj->gen.fd, CDROMREADTOCHDR, &_obj->tochdr) == -1 ) { + cdio_error("%s: %s\n", + "error in ioctl CDROMREADTOCHDR", strerror(errno)); + return false; + } + + /* read individual tracks */ + for (i= FIRST_TRACK_NUM; i<=TOTAL_TRACKS; i++) { + _obj->tocent[i-1].cdte_track = i; + _obj->tocent[i-1].cdte_format = CDROM_MSF; + if ( ioctl(_obj->gen.fd, CDROMREADTOCENTRY, &_obj->tocent[i-1]) == -1 ) { + cdio_error("%s %d: %s\n", + "error in ioctl CDROMREADTOCENTRY for track", + i, strerror(errno)); + return false; + } + /**** + struct cdrom_msf0 *msf= &_obj->tocent[i-1].cdte_addr.msf; + + fprintf (stdout, "--- track# %d (msf %2.2x:%2.2x:%2.2x)\n", + i, msf->minute, msf->second, msf->frame); + ****/ + + } + + /* read the lead-out track */ + _obj->tocent[TOTAL_TRACKS].cdte_track = CDIO_CDROM_LEADOUT_TRACK; + _obj->tocent[TOTAL_TRACKS].cdte_format = CDROM_MSF; + + if (ioctl(_obj->gen.fd, CDROMREADTOCENTRY, + &_obj->tocent[TOTAL_TRACKS]) == -1 ) { + cdio_error("%s: %s\n", + "error in ioctl CDROMREADTOCENTRY for lead-out", + strerror(errno)); + return false; + } + + /* + struct cdrom_msf0 *msf= &_obj->tocent[TOTAL_TRACKS].cdte_addr.msf; + + fprintf (stdout, "--- track# %d (msf %2.2x:%2.2x:%2.2x)\n", + i, msf->minute, msf->second, msf->frame); + */ + + return true; +} + +/*! + Eject media in CD drive. If successful, as a side effect we + also free obj. + */ +static int +_cdio_eject_media (void *env) { + + _img_private_t *_obj = env; + int ret=2; + int status; + int fd; + + close(_obj->gen.fd); + _obj->gen.fd = -1; + if ((fd = open (_obj->source_name, O_RDONLY|O_NONBLOCK)) > -1) { + if((status = ioctl(fd, CDROM_DRIVE_STATUS, (void *) CDSL_CURRENT)) > 0) { + switch(status) { + case CDS_TRAY_OPEN: + if((ret = ioctl(fd, CDROMCLOSETRAY, 0)) != 0) { + cdio_error ("ioctl CDROMCLOSETRAY failed: %s\n", strerror(errno)); + } + break; + case CDS_DISC_OK: + if((ret = ioctl(fd, CDROMEJECT, 0)) != 0) { + cdio_error("ioctl CDROMEJECT failed: %s\n", strerror(errno)); + } + break; + } + ret=0; + } else { + cdio_error ("CDROM_DRIVE_STATUS failed: %s\n", strerror(errno)); + ret=1; + } + close(fd); + } + return 2; +} + +/*! + Return the value associated with the key "arg". +*/ +static const char * +_cdio_get_arg (void *env, const char key[]) +{ + _img_private_t *_obj = env; + + if (!strcmp (key, "source")) { + return _obj->source_name; + } else if (!strcmp (key, "access-mode")) { + switch (_obj->access_mode) { + case _AM_IOCTL: + return "ioctl"; + case _AM_NONE: + return "no access method"; + } + } + return NULL; +} + +/*! + Return the number of of the first track. + CDIO_INVALID_TRACK is returned on error. +*/ +static track_t +_cdio_get_first_track_num(void *env) +{ + _img_private_t *_obj = env; + + if (!_obj->toc_init) _cdio_read_toc (_obj) ; + + return FIRST_TRACK_NUM; +} + +/*! + Return the media catalog number MCN. + Note: string is malloc'd so caller should free() then returned + string when done with it. + */ +static char * +_cdio_get_mcn (void *env) { + + struct cdrom_mcn mcn; + _img_private_t *_obj = env; + if (ioctl(_obj->gen.fd, CDROM_GET_MCN, &mcn) != 0) + return NULL; + return strdup(mcn.medium_catalog_number); +} + +/*! + Return the number of tracks in the current medium. + CDIO_INVALID_TRACK is returned on error. +*/ +static track_t +_cdio_get_num_tracks(void *env) +{ + _img_private_t *_obj = env; + + if (!_obj->toc_init) _cdio_read_toc (_obj) ; + + return TOTAL_TRACKS; +} + +/*! + Get format of track. +*/ +static track_format_t +_cdio_get_track_format(void *env, track_t track_num) +{ + _img_private_t *_obj = env; + + if (!_obj->toc_init) _cdio_read_toc (_obj) ; + + if (track_num > TOTAL_TRACKS || track_num == 0) + return TRACK_FORMAT_ERROR; + + /* This is pretty much copied from the "badly broken" cdrom_count_tracks + in linux/cdrom.c. + */ + if (_obj->tocent[track_num-1].cdte_ctrl & CDROM_DATA_TRACK) { + if (_obj->tocent[track_num-1].cdte_format == 0x10) + return TRACK_FORMAT_CDI; + else if (_obj->tocent[track_num-1].cdte_format == 0x20) + return TRACK_FORMAT_XA; + else + return TRACK_FORMAT_DATA; + } else + return TRACK_FORMAT_AUDIO; + +} + +/*! + 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 +_cdio_get_track_green(void *env, track_t track_num) +{ + _img_private_t *_obj = env; + + if (!_obj->toc_init) _cdio_read_toc (_obj) ; + + if (track_num == CDIO_CDROM_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1; + + if (track_num > TOTAL_TRACKS+1 || track_num == 0) + return false; + + /* FIXME: Dunno if this is the right way, but it's what + I was using in cdinfo for a while. + */ + return ((_obj->tocent[track_num-1].cdte_ctrl & 2) != 0); +} + +/*! + Return the starting MSF (minutes/secs/frames) for 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 bool +_cdio_get_track_msf(void *env, track_t track_num, msf_t *msf) +{ + _img_private_t *_obj = env; + + if (NULL == msf) return false; + + if (!_obj->toc_init) _cdio_read_toc (_obj) ; + + if (track_num == CDIO_CDROM_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1; + + if (track_num > TOTAL_TRACKS+1 || track_num == 0) { + return false; + } else { + struct cdrom_msf0 *msf0= &_obj->tocent[track_num-1].cdte_addr.msf; + msf->m = to_bcd8(msf0->minute); + msf->s = to_bcd8(msf0->second); + msf->f = to_bcd8(msf0->frame); + return true; + } +} + +#endif /* HAVE_BSDI_CDROM */ + +/*! + Return an array of strings giving possible CD devices. + */ +char ** +cdio_get_devices_bsdi (void) +{ +#ifndef HAVE_BSDI_CDROM + return NULL; +#else + char drive[40]; + char **drives = NULL; + unsigned int num_drives=0; + bool exists=true; + char c; + + /* Scan the system for CD-ROM drives. + */ + +#ifdef USE_ETC_FSTAB + + struct fstab *fs; + setfsent(); + + /* Check what's in /etc/fstab... */ + while ( (fs = getfsent()) ) + { + if (strncmp(fs->fs_spec, "/dev/sr", 7)) + cdio_add_device_list(&drives, fs->fs_spec, &num_drives); + } + +#endif + + /* Scan the system for CD-ROM drives. + Not always 100% reliable, so use the USE_MNTENT code above first. + */ + for ( c='0'; exists && c <='9'; c++ ) { + sprintf(drive, "/dev/rsr%cc", c); + exists = cdio_is_cdrom(drive, NULL); + if ( exists ) { + cdio_add_device_list(&drives, drive, &num_drives); + } + } + cdio_add_device_list(&drives, NULL, &num_drives); + return drives; +#endif /*HAVE_BSDI_CDROM*/ +} + +/*! + Return a string containing the default CD device if none is specified. + */ +char * +cdio_get_default_device_bsdi(void) +{ + return strdup(DEFAULT_CDIO_DEVICE); +} + +/*! + 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_bsdi (const char *source_name) +{ + +#ifdef HAVE_BSDI_CDROM + CdIo *ret; + _img_private_t *_data; + + cdio_funcs _funcs = { + .eject_media = _cdio_eject_media, + .free = cdio_generic_free, + .get_arg = _cdio_get_arg, + .get_default_device = cdio_get_default_device_bsdi, + .get_devices = cdio_get_devices_bsdi, + .get_first_track_num= _cdio_get_first_track_num, + .get_mcn = _cdio_get_mcn, + .get_num_tracks = _cdio_get_num_tracks, + .get_track_format = _cdio_get_track_format, + .get_track_green = _cdio_get_track_green, + .get_track_lba = NULL, /* This could be implemented if need be. */ + .get_track_msf = _cdio_get_track_msf, + .lseek = cdio_generic_lseek, + .read = cdio_generic_read, + .read_mode2_sector = _cdio_read_mode2_sector, + .read_audio_sectors = _read_audio_sectors, + .read_mode2_sectors = _cdio_read_mode2_sectors, + .set_arg = _cdio_set_arg, + .stat_size = _cdio_stat_size + }; + + _data = _cdio_malloc (sizeof (_img_private_t)); + _data->access_mode = _AM_IOCTL; + _data->gen.init = false; + _data->gen.fd = -1; + + _cdio_set_arg(_data, "source", (NULL == source_name) + ? DEFAULT_CDIO_DEVICE: source_name); + + ret = cdio_new (_data, &_funcs); + if (ret == NULL) return NULL; + + if (_cdio_init(_data)) + return ret; + else { + cdio_generic_free (_data); + return NULL; + } + +#else + return NULL; +#endif /* HAVE_BSDI_CDROM */ + +} + +bool +cdio_have_bsdi (void) +{ +#ifdef HAVE_BSDI_CDROM + return true; +#else + return false; +#endif /* HAVE_BSDI_CDROM */ +} + diff --git a/src/input/vcd/libcdio/_cdio_freebsd.c b/src/input/vcd/libcdio/_cdio_freebsd.c new file mode 100644 index 000000000..1eaf227ef --- /dev/null +++ b/src/input/vcd/libcdio/_cdio_freebsd.c @@ -0,0 +1,635 @@ +/* + $Id: _cdio_freebsd.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $ + + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + + 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 file contains FreeBSD-specific code and implements low-level + control of the CD drive. Culled I think from xine's or mplayer's + FreeBSD code. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +static const char _rcsid[] = "$Id: _cdio_freebsd.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $"; + +#include <cdio/sector.h> +#include <cdio/util.h> +#include "cdio_assert.h" +#include "cdio_private.h" + +/* Is this the right default? */ +#define DEFAULT_CDIO_DEVICE "/dev/acd0c" + +#include <string.h> + +#ifdef HAVE_FREEBSD_CDROM + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> + +#ifdef HAVE_SYS_CDIO_H +# include <sys/cdio.h> +#endif +#include <sys/cdrio.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/ioctl.h> + +#define TOTAL_TRACKS ( _obj->tochdr.ending_track \ + - _obj->tochdr.starting_track + 1) +#define FIRST_TRACK_NUM (_obj->tochdr.starting_track) + +typedef struct { + /* Things common to all drivers like this. + This must be first. */ + generic_img_private_t gen; + + enum { + _AM_NONE, + _AM_IOCTL, + } access_mode; + + char *source_name; + + bool init; + + /* Track information */ + bool toc_init; /* if true, info below is valid. */ + struct ioc_toc_header tochdr; + struct cd_toc_entry tocent[100]; /* entry info for each track */ + +} _img_private_t; + +/* Check a drive to see if it is a CD-ROM + Return 1 if a CD-ROM. 0 if it exists but isn't a CD-ROM drive + and -1 if no device exists . +*/ +static bool +cdio_is_cdrom(char *drive, char *mnttype) +{ + bool is_cd=false; + int cdfd; + struct ioc_toc_header tochdr; + + /* If it doesn't exist, return -1 */ + if ( !cdio_is_device_quiet_generic(drive) ) { + return(false); + } + + /* If it does exist, verify that it's an available CD-ROM */ + cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0); + + /* Should we want to test the condition in more detail: + ENOENT is the error for /dev/xxxxx does not exist; + ENODEV means there's no drive present. */ + + if ( cdfd >= 0 ) { + if ( ioctl(cdfd, CDIOREADTOCHEADER, &tochdr) != -1 ) { + is_cd = true; + } + close(cdfd); + } + /* Even if we can't read it, it might be mounted */ + else if ( mnttype && (strcmp(mnttype, "iso9660") == 0) ) { + is_cd = true; + } + return(is_cd); +} + +static int +_read_mode2 (int fd, void *buf, lba_t lba, unsigned int nblocks, + bool _workaround) +{ + unsigned int l = 0; + int retval = 0; + + while (nblocks > 0) + { + const unsigned int nblocks2 = (nblocks > 25) ? 25 : nblocks; + void *buf2 = ((char *)buf ) + (l * M2RAW_SECTOR_SIZE); + + retval |= _read_mode2 (fd, buf2, lba + l, nblocks2, _workaround); + + if (retval) + break; + + nblocks -= nblocks2; + l += nblocks2; + } + + return retval; +} + +/*! + Reads a single mode2 sector from cd device into data starting from lsn. + Returns 0 if no error. + */ +static int +_cdio_read_audio_sectors (void *env, void *data, lsn_t lsn, + unsigned int nblocks) +{ + _img_private_t *_obj = env; + unsigned char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; + struct ioc_read_audio cdda; + + cdda.address.lba = lsn; + cdda.buffer = buf; + cdda.nframes = nblocks; + cdda.address_format = CD_LBA_FORMAT; + + /* read a frame */ + if(ioctl(_obj->gen.fd, CDIOCREADAUDIO, &cdda) < 0) { + perror("CDIOCREADAUDIO"); + return 1; + } + memcpy (data, buf, CDIO_CD_FRAMESIZE_RAW); + + return 0; +} + +/*! + Reads a single mode2 sector from cd device into data starting + from lsn. Returns 0 if no error. + */ +static int +_cdio_read_mode2_sector (void *env, void *data, lsn_t lsn, + bool mode2_form2) +{ + char buf[M2RAW_SECTOR_SIZE] = { 0, }; + int retval; + + if ( (retval = _cdio_read_audio_sectors (env, buf, lsn, 1)) ) + return retval; + + if (mode2_form2) + memcpy (data, buf + CDIO_CD_XA_SYNC_HEADER, 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 +_cdio_read_mode2_sectors (void *env, void *data, lsn_t lsn, + bool mode2_form2, unsigned int nblocks) +{ + _img_private_t *_obj = env; + int i; + int retval; + + for (i = 0; i < nblocks; i++) { + if (mode2_form2) { + if ( (retval = _cdio_read_mode2_sector (_obj, + ((char *)data) + (M2RAW_SECTOR_SIZE * i), + lsn + i, true)) ) + return retval; + } else { + char buf[M2RAW_SECTOR_SIZE] = { 0, }; + if ( (retval = _cdio_read_mode2_sector (_obj, buf, lsn + i, true)) ) + return retval; + + memcpy (((char *)data) + (CDIO_CD_FRAMESIZE * i), + buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE); + } + } + return 0; +} + +/*! + Return the size of the CD in logical block address (LBA) units. + */ +static uint32_t +_cdio_stat_size (void *env) +{ + _img_private_t *_obj = env; + + struct ioc_read_toc_single_entry tocent; + uint32_t size; + + tocent.track = CDIO_CDROM_LEADOUT_TRACK; + tocent.address_format = CD_LBA_FORMAT; + if (ioctl (_obj->gen.fd, CDIOREADTOCENTRY, &tocent) == -1) + { + perror ("ioctl(CDROMREADTOCENTRY)"); + exit (EXIT_FAILURE); + } + + size = tocent.entry.addr.lba; + + return size; +} + +/*! + Set the key "arg" to "value" in source device. +*/ +static int +_cdio_set_arg (void *env, const char key[], const char value[]) +{ + _img_private_t *_obj = env; + + if (!strcmp (key, "source")) + { + if (!value) + return -2; + + free (_obj->gen.source_name); + + _obj->gen.source_name = strdup (value); + } + else if (!strcmp (key, "access-mode")) + { + if (!strcmp(value, "IOCTL")) + _obj->access_mode = _AM_IOCTL; + else + cdio_error ("unknown access type: %s. ignored.", value); + } + else + return -1; + + return 0; +} + +/*! + Read and cache the CD's Track Table of Contents and track info. + Return false if successful or true if an error. +*/ +static bool +_cdio_read_toc (_img_private_t *_obj) +{ + int i; + struct ioc_read_toc_entry te; + + /* read TOC header */ + if ( ioctl(_obj->gen.fd, CDIOREADTOCHEADER, &_obj->tochdr) == -1 ) { + cdio_error("error in ioctl(CDIOREADTOCHEADER): %s\n", strerror(errno)); + return false; + } + + te.address_format = CD_LBA_FORMAT; + te.starting_track = 0; + te.data_len = (TOTAL_TRACKS+1) * sizeof(struct cd_toc_entry); + + te.data = _obj->tocent; + + if ( ioctl(_obj->gen.fd, CDIOREADTOCENTRYS, &te) == -1 ) { + cdio_error("%s %d: %s\n", + "error in ioctl CDROMREADTOCENTRYS for track", + i, strerror(errno)); + return false; + } + + return true; +} + +/*! + Eject media. Return 1 if successful, 0 otherwise. + */ +static int +_cdio_eject_media (void *env) { + + _img_private_t *_obj = env; + int ret=2; + int fd; + + if ((fd = open(_obj->gen.source_name, O_RDONLY|O_NONBLOCK)) > -1) { + ret = 1; + if (ioctl(fd, CDIOCALLOW) == -1) { + cdio_error("ioctl(fd, CDIOCALLOW) failed: %s\n", strerror(errno)); + } else if (ioctl(fd, CDIOCEJECT) == -1) { + cdio_error("ioctl(CDIOCEJECT) failed: %s\n", strerror(errno)); + } else { + ret = 0; + } + close(fd); + } + + return ret; +} + +/*! + Return the value associated with the key "arg". +*/ +static const char * +_cdio_get_arg (void *env, const char key[]) +{ + _img_private_t *_obj = env; + + if (!strcmp (key, "source")) { + return _obj->gen.source_name; + } else if (!strcmp (key, "access-mode")) { + switch (_obj->access_mode) { + case _AM_IOCTL: + return "ioctl"; + case _AM_NONE: + return "no access method"; + } + } + return NULL; +} + +/*! + Return the number of of the first track. + CDIO_INVALID_TRACK is returned on error. +*/ +static track_t +_cdio_get_first_track_num(void *env) +{ + _img_private_t *_obj = env; + + if (!_obj->toc_init) _cdio_read_toc (_obj) ; + + return FIRST_TRACK_NUM; +} + +/*! + Return the media catalog number MCN. + + Note: string is malloc'd so caller should free() then returned + string when done with it. + + FIXME: This is just a guess. + + */ +static char * +_cdio_get_mcn (void *env) { + + _img_private_t *_obj = env; + struct ioc_read_subchannel subchannel; + struct cd_sub_channel_info subchannel_info; + + subchannel.address_format = CD_LBA_FORMAT; + subchannel.data_format = CD_MEDIA_CATALOG; + subchannel.track = 0; + subchannel.data_len = 1; + subchannel.data = &subchannel_info; + + if(ioctl(_obj->gen.fd, CDIOCREADSUBCHANNEL, &subchannel) < 0) { + perror("CDIOCREADSUBCHANNEL"); + return NULL; + } + + /* Probably need a loop over tracks rather than give up if we + can't find in track 0. + */ + if (subchannel_info.what.media_catalog.mc_valid) + return strdup(subchannel_info.what.media_catalog.mc_number); + else + return NULL; +} + +/*! + Return the number of tracks in the current medium. + CDIO_INVALID_TRACK is returned on error. +*/ +static track_t +_cdio_get_num_tracks(void *env) +{ + _img_private_t *_obj = env; + + if (!_obj->toc_init) _cdio_read_toc (_obj) ; + + return TOTAL_TRACKS; +} + +/*! + Get format of track. + + FIXME: We're just guessing this from the GNU/Linux code. + +*/ +static track_format_t +_cdio_get_track_format(void *env, track_t track_num) +{ + _img_private_t *_obj = env; + struct ioc_read_subchannel subchannel; + struct cd_sub_channel_info subchannel_info; + + subchannel.address_format = CD_LBA_FORMAT; + subchannel.data_format = CD_CURRENT_POSITION; + subchannel.track = track_num; + subchannel.data_len = 1; + subchannel.data = &subchannel_info; + + if(ioctl(_obj->gen.fd, CDIOCREADSUBCHANNEL, &subchannel) < 0) { + perror("CDIOCREADSUBCHANNEL"); + return 1; + } + + if (subchannel_info.what.position.control == 0x04) { + if (subchannel_info.what.position.data_format == 0x10) + return TRACK_FORMAT_CDI; + else if (subchannel_info.what.position.data_format == 0x20) + return TRACK_FORMAT_XA; + else + return TRACK_FORMAT_DATA; + } else + return TRACK_FORMAT_AUDIO; +} + +/*! + 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 +_cdio_get_track_green(void *env, track_t track_num) +{ + _img_private_t *_obj = env; + struct ioc_read_subchannel subchannel; + struct cd_sub_channel_info subchannel_info; + + subchannel.address_format = CD_LBA_FORMAT; + subchannel.data_format = CD_CURRENT_POSITION; + subchannel.track = track_num; + subchannel.data_len = 1; + subchannel.data = &subchannel_info; + + if(ioctl(_obj->gen.fd, CDIOCREADSUBCHANNEL, &subchannel) < 0) { + perror("CDIOCREADSUBCHANNEL"); + return 1; + } + + /* FIXME: Dunno if this is the right way, but it's what + I was using in cdinfo for a while. + */ + return (subchannel_info.what.position.control & 2) != 0; +} + +/*! + 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 +_cdio_get_track_lba(void *env, track_t track_num) +{ + _img_private_t *_obj = env; + + if (!_obj->toc_init) _cdio_read_toc (_obj) ; + + if (track_num == CDIO_CDROM_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1; + + if (track_num > TOTAL_TRACKS+1 || track_num == 0) { + return CDIO_INVALID_LBA; + } else { + return _obj->tocent[track_num-1].addr.lba; + } +} + +#endif /* HAVE_FREEBSD_CDROM */ + +/*! + Return an array of strings giving possible CD devices. + */ +char ** +cdio_get_devices_freebsd (void) +{ +#ifndef HAVE_FREEBSD_CDROM + return NULL; +#else + char drive[40]; + char **drives = NULL; + unsigned int num_drives=0; + bool exists=true; + char c; + + /* Scan the system for CD-ROM drives. + */ + +#ifdef USE_ETC_FSTAB + + struct fstab *fs; + setfsent(); + + /* Check what's in /etc/fstab... */ + while ( (fs = getfsent()) ) + { + if (strncmp(fs->fs_spec, "/dev/sr", 7)) + cdio_add_device_list(&drives, fs->fs_spec, &num_drives); + } + +#endif + + /* Scan the system for CD-ROM drives. + Not always 100% reliable, so use the USE_MNTENT code above first. + */ + for ( c='0'; exists && c <='9'; c++ ) { + sprintf(drive, "/dev/acd%cc", c); + exists = cdio_is_cdrom(drive, NULL); + if ( exists ) { + cdio_add_device_list(&drives, drive, &num_drives); + } + } + cdio_add_device_list(&drives, NULL, &num_drives); + return drives; +#endif /*HAVE_FREEBSD_CDROM*/ +} + +/*! + Return a string containing the default CD device if none is specified. + */ +char * +cdio_get_default_device_freebsd() +{ + return strdup(DEFAULT_CDIO_DEVICE); +} + +/*! + 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_freebsd (const char *source_name) +{ + +#ifdef HAVE_FREEBSD_CDROM + CdIo *ret; + _img_private_t *_data; + + cdio_funcs _funcs = { + .eject_media = _cdio_eject_media, + .free = cdio_generic_free, + .get_arg = _cdio_get_arg, + .get_default_device = cdio_get_default_device_freebsd, + .get_devices = cdio_get_devices_freebsd, + .get_first_track_num= _cdio_get_first_track_num, + .get_mcn = _cdio_get_mcn, + .get_num_tracks = _cdio_get_num_tracks, + .get_track_format = _cdio_get_track_format, + .get_track_green = _cdio_get_track_green, + .get_track_lba = _cdio_get_track_lba, + .get_track_msf = NULL, + .lseek = cdio_generic_lseek, + .read = cdio_generic_read, + .read_audio_sectors = _cdio_read_audio_sectors, + .read_mode2_sector = _cdio_read_mode2_sector, + .read_mode2_sectors = _cdio_read_mode2_sectors, + .set_arg = _cdio_set_arg, + .stat_size = _cdio_stat_size + }; + + _data = _cdio_malloc (sizeof (_img_private_t)); + _data->access_mode = _AM_IOCTL; + _data->gen.init = false; + _data->gen.fd = -1; + + _cdio_set_arg(_data, "source", (NULL == source_name) + ? DEFAULT_CDIO_DEVICE: source_name); + + ret = cdio_new (_data, &_funcs); + if (ret == NULL) return NULL; + + if (cdio_generic_init(_data)) + return ret; + else { + cdio_generic_free (_data); + return NULL; + } + +#else + return NULL; +#endif /* HAVE_FREEBSD_CDROM */ + +} + +bool +cdio_have_freebsd (void) +{ +#ifdef HAVE_FREEBSD_CDROM + return true; +#else + return false; +#endif /* HAVE_FREEBSD_CDROM */ +} diff --git a/src/input/vcd/libcdio/_cdio_generic.c b/src/input/vcd/libcdio/_cdio_generic.c new file mode 100644 index 000000000..180de1086 --- /dev/null +++ b/src/input/vcd/libcdio/_cdio_generic.c @@ -0,0 +1,195 @@ +/* + $Id: _cdio_generic.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $ + + Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org> + Copyright (C) 2002,2003 Rocky Bernstein <rocky@panix.com> + + 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 file contains Linux-specific code and implements low-level + control of the CD drive. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +static const char _rcsid[] = "$Id: _cdio_generic.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $"; + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> + +#include <sys/stat.h> +#include <sys/types.h> + +#include <cdio/sector.h> +#include <cdio/util.h> +#include "cdio_assert.h" +#include "cdio_private.h" +#include "_cdio_stdio.h" + +/*! + Eject media -- there's nothing to do here. We always return 2. + Should we also free resources? + */ +int +cdio_generic_bogus_eject_media (void *user_data) { + /* Sort of a stub here. Perhaps log a message? */ + return 2; +} + + +/*! + Release and free resources associated with cd. + */ +void +cdio_generic_free (void *user_data) +{ + generic_img_private_t *_obj = user_data; + + if (NULL == _obj) return; + free (_obj->source_name); + + if (_obj->fd >= 0) + close (_obj->fd); + + free (_obj); +} + +/*! + Initialize CD device. + */ +bool +cdio_generic_init (void *user_data) +{ + generic_img_private_t *_obj = user_data; + if (_obj->init) { + cdio_error ("init called more than once"); + return false; + } + + _obj->fd = open (_obj->source_name, O_RDONLY, 0); + + if (_obj->fd < 0) + { + cdio_warn ("open (%s): %s", _obj->source_name, strerror (errno)); + return false; + } + + _obj->init = true; + _obj->toc_init = false; + return true; +} + +/*! + Reads into buf the next size bytes. + Returns -1 on error. + Is in fact libc's read(). +*/ +off_t +cdio_generic_lseek (void *user_data, off_t offset, int whence) +{ + generic_img_private_t *_obj = user_data; + return lseek(_obj->fd, offset, whence); +} + +/*! + Reads into buf the next size bytes. + Returns -1 on error. + Is in fact libc's read(). +*/ +ssize_t +cdio_generic_read (void *user_data, void *buf, size_t size) +{ + generic_img_private_t *_obj = user_data; + return read(_obj->fd, buf, size); +} + +/*! + Release and free resources associated with stream or disk image. +*/ +void +cdio_generic_stream_free (void *user_data) +{ + generic_img_private_t *_obj = user_data; + + if (NULL == _obj) return; + free (_obj->source_name); + + if (_obj->data_source) + cdio_stream_destroy (_obj->data_source); + + free (_obj); +} + + +/*! + Return true if source_name could be a device containing a CD-ROM. +*/ +bool +cdio_is_device_generic(const char *source_name) +{ + struct stat buf; + if (0 != stat(source_name, &buf)) { + cdio_warn ("Can't get file status for %s:\n%s", source_name, + strerror(errno)); + return false; + } + return (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode)); +} + +/*! + Like above, but don't give a warning device doesn't exist. +*/ +bool +cdio_is_device_quiet_generic(const char *source_name) +{ + struct stat buf; + if (0 != stat(source_name, &buf)) { + return false; + } + return (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode)); +} + +/*! + Add/allocate a drive to the end of drives. + Use cdio_free_device_list() to free this device_list. +*/ +void +cdio_add_device_list(char **device_list[], const char *drive, int *num_drives) +{ + if (NULL != drive) { + unsigned int j; + for (j=0; j<*num_drives; j++) { + if (strcmp((*device_list)[j], drive) == 0) break; + } + if (j==*num_drives) { + (*num_drives)++; + *device_list = realloc(*device_list, (*num_drives) * sizeof(char *)); + (*device_list)[*num_drives-1] = strdup(drive); + } + } else { + (*num_drives)++; + *device_list = realloc(*device_list, (*num_drives) * sizeof(char *)); + (*device_list)[*num_drives-1] = NULL; + } +} + + diff --git a/src/input/vcd/libcdio/_cdio_linux.c b/src/input/vcd/libcdio/_cdio_linux.c new file mode 100644 index 000000000..51afb728e --- /dev/null +++ b/src/input/vcd/libcdio/_cdio_linux.c @@ -0,0 +1,1028 @@ +/* + $Id: _cdio_linux.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $ + + Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org> + Copyright (C) 2002,2003 Rocky Bernstein <rocky@panix.com> + + 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 file contains Linux-specific code and implements low-level + control of the CD drive. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +static const char _rcsid[] = "$Id: _cdio_linux.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $"; + +#include <string.h> + +#include <cdio/sector.h> +#include <cdio/util.h> +#include "cdio_assert.h" +#include "cdio_private.h" +#include "scsi_mmc.h" + +#ifdef HAVE_LINUX_CDROM + +#if defined(HAVE_LINUX_VERSION_H) +# include <linux/version.h> +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16) +# define __CDIO_LINUXCD_BUILD +# else +# error "You need a kernel greater than 2.2.16 to have CDROM support" +# endif +#else +# error "You need <linux/version.h> to have CDROM support" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <mntent.h> + +#include <linux/cdrom.h> +#include <scsi/scsi.h> +#include <scsi/sg.h> +#include <scsi/scsi_ioctl.h> +#include <sys/mount.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/ioctl.h> + +#define TOTAL_TRACKS (_obj->tochdr.cdth_trk1) +#define FIRST_TRACK_NUM (_obj->tochdr.cdth_trk0) + +typedef struct { + /* Things common to all drivers like this. + This must be first. */ + generic_img_private_t gen; + + enum { + _AM_NONE, + _AM_IOCTL, + _AM_READ_CD, + _AM_READ_10 + } access_mode; + + /* Track information */ + struct cdrom_tochdr tochdr; + struct cdrom_tocentry tocent[100]; /* entry info for each track */ + +} _img_private_t; + +/* Some ioctl() errno values which occur when the tray is empty */ +#define ERRNO_TRAYEMPTY(errno) \ + ((errno == EIO) || (errno == ENOENT) || (errno == EINVAL)) + + +/* Check a drive to see if it is a CD-ROM + Return 1 if a CD-ROM. 0 if it exists but isn't a CD-ROM drive + and -1 if no device exists . +*/ +static bool +cdio_is_cdrom(char *drive, char *mnttype) +{ + bool is_cd=false; + int cdfd; + struct cdrom_tochdr tochdr; + + /* If it doesn't exist, return -1 */ + if ( !cdio_is_device_quiet_generic(drive) ) { + return(false); + } + + /* If it does exist, verify that it's an available CD-ROM */ + cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0); + if ( cdfd >= 0 ) { + if ( ioctl(cdfd, CDROMREADTOCHDR, &tochdr) != -1 ) { + is_cd = true; + } + close(cdfd); + } + /* Even if we can't read it, it might be mounted */ + else if ( mnttype && (strcmp(mnttype, "iso9660") == 0) ) { + is_cd = true; + } + return(is_cd); +} + +static char * +cdio_check_mounts(const char *mtab) +{ + FILE *mntfp; + struct mntent *mntent; + + mntfp = setmntent(mtab, "r"); + if ( mntfp != NULL ) { + char *tmp; + char *mnt_type; + char *mnt_dev; + + while ( (mntent=getmntent(mntfp)) != NULL ) { + mnt_type = malloc(strlen(mntent->mnt_type) + 1); + if (mnt_type == NULL) + continue; /* maybe you'll get lucky next time. */ + + mnt_dev = malloc(strlen(mntent->mnt_fsname) + 1); + if (mnt_dev == NULL) { + free(mnt_type); + continue; + } + + strcpy(mnt_type, mntent->mnt_type); + strcpy(mnt_dev, mntent->mnt_fsname); + + /* Handle "supermount" filesystem mounts */ + if ( strcmp(mnt_type, "supermount") == 0 ) { + tmp = strstr(mntent->mnt_opts, "fs="); + if ( tmp ) { + free(mnt_type); + mnt_type = strdup(tmp + strlen("fs=")); + if ( mnt_type ) { + tmp = strchr(mnt_type, ','); + if ( tmp ) { + *tmp = '\0'; + } + } + } + tmp = strstr(mntent->mnt_opts, "dev="); + if ( tmp ) { + free(mnt_dev); + mnt_dev = strdup(tmp + strlen("dev=")); + if ( mnt_dev ) { + tmp = strchr(mnt_dev, ','); + if ( tmp ) { + *tmp = '\0'; + } + } + } + } + if ( strcmp(mnt_type, "iso9660") == 0 ) { + if (cdio_is_cdrom(mnt_dev, mnt_type) > 0) { + free(mnt_dev); + free(mnt_type); + endmntent(mntfp); + return strdup(mnt_dev); + } + } + free(mnt_dev); + free(mnt_type); + } + endmntent(mntfp); + } + return NULL; +} + +static int +_set_bsize (int fd, unsigned int bsize) +{ + struct cdrom_generic_command cgc; + + struct + { + uint8_t reserved1; + uint8_t medium; + uint8_t reserved2; + uint8_t block_desc_length; + uint8_t density; + uint8_t number_of_blocks_hi; + uint8_t number_of_blocks_med; + uint8_t number_of_blocks_lo; + uint8_t reserved3; + uint8_t block_length_hi; + uint8_t block_length_med; + uint8_t block_length_lo; + } mh; + + memset (&mh, 0, sizeof (mh)); + memset (&cgc, 0, sizeof (struct cdrom_generic_command)); + + cgc.cmd[0] = 0x15; + cgc.cmd[1] = 1 << 4; + cgc.cmd[4] = 12; + + cgc.buflen = sizeof (mh); + cgc.buffer = (void *) &mh; + + cgc.data_direction = CGC_DATA_WRITE; + + mh.block_desc_length = 0x08; + mh.block_length_hi = (bsize >> 16) & 0xff; + mh.block_length_med = (bsize >> 8) & 0xff; + mh.block_length_lo = (bsize >> 0) & 0xff; + + return ioctl (fd, CDROM_SEND_PACKET, &cgc); +} + +/* Packet driver to read mode2 sectors. + Can read only up to 25 blocks. +*/ +static int +_cdio_mmc_read_sectors (int fd, void *buf, lba_t lba, int sector_type, + unsigned int nblocks) +{ + typedef struct cdrom_generic_command cgc_t; + cgc_t cgc; + + memset (&cgc, 0, sizeof (cgc_t)); + + cgc.cmd[0] = CDIO_MMC_GPCMD_READ_CD; + CDIO_MMC_SET_READ_TYPE (cgc.cmd, sector_type); + CDIO_MMC_SET_READ_LBA (cgc.cmd, lba); + CDIO_MMC_SET_READ_LENGTH(cgc.cmd, nblocks); + CDIO_MMC_SET_MAIN_CHANNEL_SELECTION_BITS(cgc.cmd, CDIO_MMC_MCSB_ALL_HEADERS); + + cgc.buflen = CDIO_CD_FRAMESIZE_RAW * nblocks; + cgc.buffer = buf; + +#ifdef HAVE_LINUX_CDROM_TIMEOUT + cgc.timeout = 500; +#endif + cgc.data_direction = CGC_DATA_READ; + + return ioctl (fd, CDROM_SEND_PACKET, &cgc); + + return 0; +} + +/* MMC driver to read audio sectors. + Can read only up to 25 blocks. +*/ +static int +_cdio_read_audio_sectors (void *env, void *buf, lsn_t lsn, + unsigned int nblocks) +{ + _img_private_t *_obj = env; + return _cdio_mmc_read_sectors( _obj->gen.fd, buf, lsn, + CDIO_MMC_READ_TYPE_CDDA, nblocks); +} + +/* Packet driver to read mode2 sectors. + Can read only up to 25 blocks. +*/ +static int +__read_packet_mode2_sectors (int fd, void *buf, lba_t lba, + unsigned int nblocks, bool use_read_10) +{ + struct cdrom_generic_command cgc; + + memset (&cgc, 0, sizeof (struct cdrom_generic_command)); + + cgc.cmd[0] = use_read_10 ? GPCMD_READ_10 : CDIO_MMC_GPCMD_READ_CD; + + CDIO_MMC_SET_READ_LBA(cgc.cmd, lba); + CDIO_MMC_SET_READ_LENGTH(cgc.cmd, nblocks); + + if (!use_read_10) + { + cgc.cmd[1] = 0; /* sector size mode2 */ + + cgc.cmd[9] = 0x58; /* 2336 mode2 */ + } + + cgc.buflen = 2336 * nblocks; + cgc.buffer = buf; + +#ifdef HAVE_LINUX_CDROM_TIMEOUT + cgc.timeout = 500; +#endif + cgc.data_direction = CGC_DATA_READ; + + if (use_read_10) + { + int retval; + + if ((retval = _set_bsize (fd, 2336))) + return retval; + + if ((retval = ioctl (fd, CDROM_SEND_PACKET, &cgc))) + { + _set_bsize (fd, 2048); + return retval; + } + + if ((retval = _set_bsize (fd, 2048))) + return retval; + } + else + return ioctl (fd, CDROM_SEND_PACKET, &cgc); + + return 0; +} + +static int +_read_packet_mode2_sectors (int fd, void *buf, lba_t lba, + unsigned int nblocks, bool use_read_10) +{ + unsigned int l = 0; + int retval = 0; + + while (nblocks > 0) + { + const unsigned nblocks2 = (nblocks > 25) ? 25 : nblocks; + void *buf2 = ((char *)buf ) + (l * 2336); + + retval |= __read_packet_mode2_sectors (fd, buf2, lba + l, nblocks2, + use_read_10); + + if (retval) + break; + + nblocks -= nblocks2; + l += nblocks2; + } + + return retval; +} + +/*! + Reads a single mode2 sector from cd device into data starting + from lsn. Returns 0 if no error. + */ +static int +_cdio_read_mode2_sector (void *env, void *data, lsn_t lsn, + bool mode2_form2) +{ + char buf[M2RAW_SECTOR_SIZE] = { 0, }; + struct cdrom_msf *msf = (struct cdrom_msf *) &buf; + msf_t _msf; + + _img_private_t *_obj = env; + + cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf); + msf->cdmsf_min0 = from_bcd8(_msf.m); + msf->cdmsf_sec0 = from_bcd8(_msf.s); + msf->cdmsf_frame0 = from_bcd8(_msf.f); + + retry: + switch (_obj->access_mode) + { + case _AM_NONE: + cdio_error ("no way to read mode2"); + return 1; + break; + + case _AM_IOCTL: + if (ioctl (_obj->gen.fd, CDROMREADMODE2, &buf) == -1) + { + perror ("ioctl()"); + return 1; + /* exit (EXIT_FAILURE); */ + } + break; + + case _AM_READ_CD: + case _AM_READ_10: + if (_read_packet_mode2_sectors (_obj->gen.fd, buf, lsn, 1, + (_obj->access_mode == _AM_READ_10))) + { + perror ("ioctl()"); + if (_obj->access_mode == _AM_READ_CD) + { + cdio_info ("READ_CD failed; switching to READ_10 mode..."); + _obj->access_mode = _AM_READ_10; + goto retry; + } + else + { + cdio_info ("READ_10 failed; switching to ioctl(CDROMREADMODE2) mode..."); + _obj->access_mode = _AM_IOCTL; + goto retry; + } + return 1; + } + break; + } + + if (mode2_form2) + memcpy (data, buf, M2RAW_SECTOR_SIZE); + else + memcpy (((char *)data), buf + CDIO_CD_SUBHEADER_SIZE, 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 +_cdio_read_mode2_sectors (void *env, void *data, lsn_t lsn, + bool mode2_form2, unsigned int nblocks) +{ + _img_private_t *_obj = env; + unsigned int i; + int retval; + + for (i = 0; i < nblocks; i++) { + if (mode2_form2) { + if ( (retval = _cdio_read_mode2_sector (_obj, + ((char *)data) + + (M2RAW_SECTOR_SIZE * i), + lsn + i, true)) ) + return retval; + } else { + char buf[M2RAW_SECTOR_SIZE] = { 0, }; + if ( (retval = _cdio_read_mode2_sector (_obj, buf, lsn + i, true)) ) + return retval; + + memcpy (((char *)data) + (CDIO_CD_FRAMESIZE * i), + buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE); + } + } + return 0; +} + +/*! + Return the size of the CD in logical block address (LBA) units. + */ +static uint32_t +_cdio_stat_size (void *env) +{ + _img_private_t *_obj = env; + + struct cdrom_tocentry tocent; + uint32_t size; + + tocent.cdte_track = CDIO_CDROM_LEADOUT_TRACK; + tocent.cdte_format = CDROM_LBA; + if (ioctl (_obj->gen.fd, CDROMREADTOCENTRY, &tocent) == -1) + { + perror ("ioctl(CDROMREADTOCENTRY)"); + exit (EXIT_FAILURE); + } + + size = tocent.cdte_addr.lba; + + return size; +} + +/*! + Set the arg "key" with "value" in the source device. + Currently "source" and "access-mode" are valid keys. + "source" sets the source device in I/O operations + "access-mode" sets the the method of CD access + + 0 is returned if no error was found, and nonzero if there as an error. +*/ +static int +_cdio_set_arg (void *env, const char key[], const char value[]) +{ + _img_private_t *_obj = env; + + if (!strcmp (key, "source")) + { + if (!value) + return -2; + + free (_obj->gen.source_name); + + _obj->gen.source_name = strdup (value); + } + else if (!strcmp (key, "access-mode")) + { + if (!strcmp(value, "IOCTL")) + _obj->access_mode = _AM_IOCTL; + else if (!strcmp(value, "READ_CD")) + _obj->access_mode = _AM_READ_CD; + else if (!strcmp(value, "READ_10")) + _obj->access_mode = _AM_READ_10; + else { + cdio_warn ("unknown access type: %s. ignored.", value); + } + } + else + return -1; + + return 0; +} + +/*! + Read and cache the CD's Track Table of Contents and track info. + Return false if successful or true if an error. +*/ +static bool +_cdio_read_toc (_img_private_t *_obj) +{ + int i; + + /* read TOC header */ + if ( ioctl(_obj->gen.fd, CDROMREADTOCHDR, &_obj->tochdr) == -1 ) { + cdio_error("%s: %s\n", + "error in ioctl CDROMREADTOCHDR", strerror(errno)); + return false; + } + + /* read individual tracks */ + for (i= FIRST_TRACK_NUM; i<=TOTAL_TRACKS; i++) { + _obj->tocent[i-1].cdte_track = i; + _obj->tocent[i-1].cdte_format = CDROM_MSF; + if ( ioctl(_obj->gen.fd, CDROMREADTOCENTRY, &_obj->tocent[i-1]) == -1 ) { + cdio_error("%s %d: %s\n", + "error in ioctl CDROMREADTOCENTRY for track", + i, strerror(errno)); + return false; + } + /**** + struct cdrom_msf0 *msf= &_obj->tocent[i-1].cdte_addr.msf; + + fprintf (stdout, "--- track# %d (msf %2.2x:%2.2x:%2.2x)\n", + i, msf->minute, msf->second, msf->frame); + ****/ + + } + + /* read the lead-out track */ + _obj->tocent[TOTAL_TRACKS].cdte_track = CDIO_CDROM_LEADOUT_TRACK; + _obj->tocent[TOTAL_TRACKS].cdte_format = CDROM_MSF; + + if (ioctl(_obj->gen.fd, CDROMREADTOCENTRY, + &_obj->tocent[TOTAL_TRACKS]) == -1 ) { + cdio_error("%s: %s\n", + "error in ioctl CDROMREADTOCENTRY for lead-out", + strerror(errno)); + return false; + } + + /* + struct cdrom_msf0 *msf= &_obj->tocent[TOTAL_TRACKS].cdte_addr.msf; + + fprintf (stdout, "--- track# %d (msf %2.2x:%2.2x:%2.2x)\n", + i, msf->minute, msf->second, msf->frame); + */ + + _obj->gen.toc_init = true; + return true; +} + +/* + * Eject using SCSI commands. Return 1 if successful, 0 otherwise. + */ +static int +_cdio_eject_scsi(int fd) +{ + int status; + struct sdata { + int inlen; + int outlen; + char cmd[256]; + } scsi_cmd; + + scsi_cmd.inlen = 0; + scsi_cmd.outlen = 0; + scsi_cmd.cmd[0] = ALLOW_MEDIUM_REMOVAL; + scsi_cmd.cmd[1] = 0; + scsi_cmd.cmd[2] = 0; + scsi_cmd.cmd[3] = 0; + scsi_cmd.cmd[4] = 0; + scsi_cmd.cmd[5] = 0; + status = ioctl(fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd); + if (status != 0) + return 0; + + scsi_cmd.inlen = 0; + scsi_cmd.outlen = 0; + scsi_cmd.cmd[0] = START_STOP; + scsi_cmd.cmd[1] = 0; + scsi_cmd.cmd[2] = 0; + scsi_cmd.cmd[3] = 0; + scsi_cmd.cmd[4] = 1; + scsi_cmd.cmd[5] = 0; + status = ioctl(fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd); + if (status != 0) + return 0; + + scsi_cmd.inlen = 0; + scsi_cmd.outlen = 0; + scsi_cmd.cmd[0] = START_STOP; + scsi_cmd.cmd[1] = 0; + scsi_cmd.cmd[2] = 0; + scsi_cmd.cmd[3] = 0; + scsi_cmd.cmd[4] = 2; + scsi_cmd.cmd[5] = 0; + status = ioctl(fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd); + if (status != 0) + return 0; + + /* force kernel to reread partition table when new disc inserted */ + status = ioctl(fd, BLKRRPART); + return (status == 0); +} + +/*! + Eject media in CD drive. + Return 0 if success and 1 for failure, and 2 if no routine. + */ +static int +_cdio_eject_media (void *env) { + + _img_private_t *_obj = env; + int ret=2; + int status; + int fd; + + close(_obj->gen.fd); + _obj->gen.fd = -1; + if ((fd = open (_obj->gen.source_name, O_RDONLY|O_NONBLOCK)) > -1) { + if((status = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT)) > 0) { + switch(status) { + case CDS_TRAY_OPEN: + if((ret = ioctl(fd, CDROMCLOSETRAY)) != 0) { + cdio_error ("ioctl CDROMCLOSETRAY failed: %s\n", strerror(errno)); + ret = 1; + } + break; + case CDS_DISC_OK: + if((ret = ioctl(fd, CDROMEJECT)) != 0) { + int eject_error = errno; + /* Try ejecting the SCSI way... */ + ret = _cdio_eject_scsi(fd); + if (0 != ret) { + cdio_error("ioctl CDROMEJECT failed: %s\n", strerror(eject_error)); + ret = 1; + } + } + break; + default: + cdio_error ("Unknown CD-ROM (%d)\n", status); + ret = 1; + } + } else { + cdio_error ("CDROM_DRIVE_STATUS failed: %s\n", strerror(errno)); + ret=1; + } + close(fd); + return ret; + } + return 2; +} + +/*! + Return the value associated with the key "arg". +*/ +static const char * +_cdio_get_arg (void *env, const char key[]) +{ + _img_private_t *_obj = env; + + if (!strcmp (key, "source")) { + return _obj->gen.source_name; + } else if (!strcmp (key, "access-mode")) { + switch (_obj->access_mode) { + case _AM_IOCTL: + return "ioctl"; + case _AM_READ_CD: + return "READ_CD"; + case _AM_READ_10: + return "READ_10"; + case _AM_NONE: + return "no access method"; + } + } + return NULL; +} + +/*! + Return the number of of the first track. + CDIO_INVALID_TRACK is returned on error. +*/ +static track_t +_cdio_get_first_track_num(void *env) +{ + _img_private_t *_obj = env; + + if (!_obj->gen.toc_init) _cdio_read_toc (_obj) ; + + return FIRST_TRACK_NUM; +} + +/*! + Return the media catalog number MCN. + + Note: string is malloc'd so caller should free() then returned + string when done with it. + + */ +static char * +_cdio_get_mcn (void *env) { + + struct cdrom_mcn mcn; + _img_private_t *_obj = env; + if (ioctl(_obj->gen.fd, CDROM_GET_MCN, &mcn) != 0) + return NULL; + return strdup(mcn.medium_catalog_number); +} + +/*! + Return the number of tracks in the current medium. + CDIO_INVALID_TRACK is returned on error. +*/ +static track_t +_cdio_get_num_tracks(void *env) +{ + _img_private_t *_obj = env; + + if (!_obj->gen.toc_init) _cdio_read_toc (_obj) ; + + return TOTAL_TRACKS; +} + +/*! + Get format of track. +*/ +static track_format_t +_cdio_get_track_format(void *env, track_t track_num) +{ + _img_private_t *_obj = env; + + if (!_obj->gen.toc_init) _cdio_read_toc (_obj) ; + + if (track_num > TOTAL_TRACKS || track_num == 0) + return TRACK_FORMAT_ERROR; + + /* This is pretty much copied from the "badly broken" cdrom_count_tracks + in linux/cdrom.c. + */ + if (_obj->tocent[track_num-1].cdte_ctrl & CDROM_DATA_TRACK) { + if (_obj->tocent[track_num-1].cdte_format == 0x10) + return TRACK_FORMAT_CDI; + else if (_obj->tocent[track_num-1].cdte_format == 0x20) + return TRACK_FORMAT_XA; + else + return TRACK_FORMAT_DATA; + } else + return TRACK_FORMAT_AUDIO; + +} + +/*! + 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 +_cdio_get_track_green(void *env, track_t track_num) +{ + _img_private_t *_obj = env; + + if (!_obj->gen.toc_init) _cdio_read_toc (_obj) ; + + if (track_num == CDIO_CDROM_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1; + + if (track_num > TOTAL_TRACKS+1 || track_num == 0) + return false; + + /* FIXME: Dunno if this is the right way, but it's what + I was using in cdinfo for a while. + */ + return ((_obj->tocent[track_num-1].cdte_ctrl & 2) != 0); +} + +/*! + Return the starting MSF (minutes/secs/frames) for 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 bool +_cdio_get_track_msf(void *env, track_t track_num, msf_t *msf) +{ + _img_private_t *_obj = env; + + if (NULL == msf) return false; + + if (!_obj->gen.toc_init) _cdio_read_toc (_obj) ; + + if (track_num == CDIO_CDROM_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1; + + if (track_num > TOTAL_TRACKS+1 || track_num == 0) { + return false; + } else { + struct cdrom_msf0 *msf0= &_obj->tocent[track_num-1].cdte_addr.msf; + msf->m = to_bcd8(msf0->minute); + msf->s = to_bcd8(msf0->second); + msf->f = to_bcd8(msf0->frame); + return true; + } +} + +/* checklist: /dev/cdrom, /dev/dvd /dev/hd?, /dev/scd? /dev/sr? */ +static char checklist1[][40] = { + {"cdrom"}, {"dvd"}, {""} +}; +static char checklist2[][40] = { + {"?a hd?"}, {"?0 scd?"}, {"?0 sr?"}, {""} +}; + +#endif /* HAVE_LINUX_CDROM */ + +/*! + Return an array of strings giving possible CD devices. + */ +char ** +cdio_get_devices_linux (void) +{ +#ifndef HAVE_LINUX_CDROM + return NULL; +#else + unsigned int i; + char drive[40]; + char *ret_drive; + bool exists; + char **drives = NULL; + unsigned int num_drives=0; + + /* Scan the system for CD-ROM drives. + */ + for ( i=0; strlen(checklist1[i]) > 0; ++i ) { + sprintf(drive, "/dev/%s", checklist1[i]); + if ( (exists=cdio_is_cdrom(drive, NULL)) > 0 ) { + cdio_add_device_list(&drives, drive, &num_drives); + } + } + + /* Now check the currently mounted CD drives */ + if (NULL != (ret_drive = cdio_check_mounts("/etc/mtab"))) { + cdio_add_device_list(&drives, drive, &num_drives); + } + + /* Finally check possible mountable drives in /etc/fstab */ + if (NULL != (ret_drive = cdio_check_mounts("/etc/fstab"))) { + cdio_add_device_list(&drives, drive, &num_drives); + } + + /* Scan the system for CD-ROM drives. + Not always 100% reliable, so use the USE_MNTENT code above first. + */ + for ( i=0; strlen(checklist2[i]) > 0; ++i ) { + unsigned int j; + char *insert; + exists = true; + for ( j=checklist2[i][1]; exists; ++j ) { + sprintf(drive, "/dev/%s", &checklist2[i][3]); + insert = strchr(drive, '?'); + if ( insert != NULL ) { + *insert = j; + } + if ( (exists=cdio_is_cdrom(drive, NULL)) > 0 ) { + cdio_add_device_list(&drives, drive, &num_drives); + } + } + } + cdio_add_device_list(&drives, NULL, &num_drives); + return drives; +#endif /*HAVE_LINUX_CDROM*/ +} + +/*! + Return a string containing the default CD device. + */ +char * +cdio_get_default_device_linux(void) +{ +#ifndef HAVE_LINUX_CDROM + return NULL; + +#else + unsigned int i; + char drive[40]; + bool exists; + char *ret_drive; + + /* Scan the system for CD-ROM drives. + */ + for ( i=0; strlen(checklist1[i]) > 0; ++i ) { + sprintf(drive, "/dev/%s", checklist1[i]); + if ( (exists=cdio_is_cdrom(drive, NULL)) > 0 ) { + return strdup(drive); + } + } + + /* Now check the currently mounted CD drives */ + if (NULL != (ret_drive = cdio_check_mounts("/etc/mtab"))) + return ret_drive; + + /* Finally check possible mountable drives in /etc/fstab */ + if (NULL != (ret_drive = cdio_check_mounts("/etc/fstab"))) + return ret_drive; + + /* Scan the system for CD-ROM drives. + Not always 100% reliable, so use the USE_MNTENT code above first. + */ + for ( i=0; strlen(checklist2[i]) > 0; ++i ) { + unsigned int j; + char *insert; + exists = true; + for ( j=checklist2[i][1]; exists; ++j ) { + sprintf(drive, "/dev/%s", &checklist2[i][3]); + insert = strchr(drive, '?'); + if ( insert != NULL ) { + *insert = j; + } + if ( (exists=cdio_is_cdrom(drive, NULL)) > 0 ) { + return(strdup(drive)); + } + } + } + return NULL; +#endif /*HAVE_LINUX_CDROM*/ +} +/*! + 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_linux (const char *orig_source_name) +{ + +#ifdef HAVE_LINUX_CDROM + CdIo *ret; + _img_private_t *_data; + char *source_name; + + cdio_funcs _funcs = { + .eject_media = _cdio_eject_media, + .free = cdio_generic_free, + .get_arg = _cdio_get_arg, + .get_devices = cdio_get_devices_linux, + .get_default_device = cdio_get_default_device_linux, + .get_first_track_num= _cdio_get_first_track_num, + .get_mcn = _cdio_get_mcn, + .get_num_tracks = _cdio_get_num_tracks, + .get_track_format = _cdio_get_track_format, + .get_track_green = _cdio_get_track_green, + .get_track_lba = NULL, /* This could be implemented if need be. */ + .get_track_msf = _cdio_get_track_msf, + .lseek = cdio_generic_lseek, + .read = cdio_generic_read, + .read_audio_sectors = _cdio_read_audio_sectors, + .read_mode2_sector = _cdio_read_mode2_sector, + .read_mode2_sectors = _cdio_read_mode2_sectors, + .set_arg = _cdio_set_arg, + .stat_size = _cdio_stat_size + }; + + _data = _cdio_malloc (sizeof (_img_private_t)); + _data->access_mode = _AM_READ_CD; + _data->gen.init = false; + _data->gen.fd = -1; + + if (NULL == orig_source_name) { + source_name=cdio_get_default_device_linux(); + if (NULL == source_name) return NULL; + _cdio_set_arg(_data, "source", source_name); + free(source_name); + } else + _cdio_set_arg(_data, "source", orig_source_name); + + ret = cdio_new (_data, &_funcs); + if (ret == NULL) return NULL; + + if (cdio_generic_init(_data)) + return ret; + else { + cdio_generic_free (_data); + return NULL; + } + +#else + return NULL; +#endif /* HAVE_LINUX_CDROM */ + +} + +bool +cdio_have_linux (void) +{ +#ifdef HAVE_LINUX_CDROM + return true; +#else + return false; +#endif /* HAVE_LINUX_CDROM */ +} + + diff --git a/src/input/vcd/libcdio/_cdio_nrg.c b/src/input/vcd/libcdio/_cdio_nrg.c new file mode 100644 index 000000000..4b92f105f --- /dev/null +++ b/src/input/vcd/libcdio/_cdio_nrg.c @@ -0,0 +1,938 @@ +/* + $Id: _cdio_nrg.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $ + + Copyright (C) 2001,2003 Herbert Valerio Riedel <hvr@gnu.org> + + 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 the Nero native + CD-image format residing inside a disk file (*.nrg). +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STDIO_H +#include <stdio.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_GLOB_H +#include <glob.h> +#endif + +#include <cdio/logging.h> +#include <cdio/sector.h> +#include <cdio/util.h> +#include "cdio_assert.h" +#include "bytesex.h" +#include "ds.h" +#include "cdio_private.h" +#include "_cdio_stdio.h" + +static const char _rcsid[] = "$Id: _cdio_nrg.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $"; + +/* structures used */ + +/* this ugly image format is typical for lazy win32 programmers... at + least structure were set big endian, so at reverse + engineering wasn't such a big headache... */ + +PRAGMA_BEGIN_PACKED +typedef struct { + uint32_t start GNUC_PACKED; + uint32_t length GNUC_PACKED; + uint32_t type GNUC_PACKED; /* only 0x3 seen so far... + -> MIXED_MODE2 2336 blocksize */ + uint32_t start_lsn GNUC_PACKED; /* does not include any pre-gaps! */ + uint32_t _unknown GNUC_PACKED; /* wtf is this for? -- always zero... */ +} _etnf_array_t; + +/* finally they realized that 32bit offsets are a bit outdated for IA64 *eg* */ +typedef struct { + uint64_t start GNUC_PACKED; + uint64_t length GNUC_PACKED; + uint32_t type GNUC_PACKED; + uint32_t start_lsn GNUC_PACKED; + uint64_t _unknown GNUC_PACKED; /* wtf is this for? -- always zero... */ +} _etn2_array_t; + +typedef struct { + uint8_t _unknown1 GNUC_PACKED; /* 0x41 == 'A' */ + uint8_t track GNUC_PACKED; /* binary or BCD?? */ + uint8_t index GNUC_PACKED; /* makes 0->1 transitions */ + uint8_t _unknown2 GNUC_PACKED; /* ?? */ + uint32_t lsn GNUC_PACKED; +} _cuex_array_t; + +typedef struct { + uint32_t id GNUC_PACKED; + uint32_t len GNUC_PACKED; + char data[EMPTY_ARRAY_SIZE] GNUC_PACKED; +} _chunk_t; + +PRAGMA_END_PACKED + +/* to be converted into BE */ +#define CUEX_ID 0x43554558 +#define CUES_ID 0x43554553 +#define DAOX_ID 0x44414f58 +#define DAOI_ID 0x44414f49 +#define END1_ID 0x454e4421 +#define ETN2_ID 0x45544e32 +#define ETNF_ID 0x45544e46 +#define NER5_ID 0x4e455235 +#define NERO_ID 0x4e45524f +#define SINF_ID 0x53494e46 + +/* reader */ + +#define DEFAULT_CDIO_DEVICE "image.nrg" + +typedef struct { + int track_num; /* Probably is index+1 */ + msf_t start_msf; + lba_t start_lba; + int start_index; + int sec_count; /* Number of sectors in track. Does not + include pregap before next entry. */ + int flags; /* "DCP", "4CH", "PRE" */ + track_format_t track_format; + bool track_green; + uint16_t datasize; /* How much is in the portion we return back? */ + long int 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; + +/* + Link element of track structure as a linked list. + Possibly redundant with above track_info_t */ +typedef struct { + uint32_t start_lsn; + uint32_t sec_count; /* Number of sectors in track. Does not + include pregap before next entry. */ + uint64_t img_offset; /* Bytes offset from beginning of disk image file.*/ +} _mapping_t; + + +typedef struct { + /* Things common to all drivers like this. + This must be first. */ + generic_img_private_t gen; + internal_position_t pos; + + /* This is a hack because I don't really understnad NERO better. */ + bool is_cues; + + bool sector_2336; + 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 */ + CdioList *mapping; /* List of track information */ + uint32_t size; +} _img_private_t; + +static bool _cdio_parse_nero_footer (_img_private_t *_obj); +static uint32_t _cdio_stat_size (void *env); + +/* Updates internal track TOC, so we can later + simulate ioctl(CDROMREADTOCENTRY). + */ +static void +_register_mapping (_img_private_t *_obj, lsn_t start_lsn, uint32_t sec_count, + uint64_t img_offset, uint32_t blocksize) +{ + const int track_num=_obj->total_tracks; + track_info_t *this_track=&(_obj->tocent[_obj->total_tracks]); + _mapping_t *_map = _cdio_malloc (sizeof (_mapping_t)); + + if (!_obj->mapping) + _obj->mapping = _cdio_list_new (); + + _cdio_list_append (_obj->mapping, _map); + _map->start_lsn = start_lsn; + _map->sec_count = sec_count; + + _map->img_offset = img_offset; + + _obj->size = MAX (_obj->size, (start_lsn + sec_count)); + + /* Update *this_track and track_num. These structures are + in a sense redundant witht the obj->mapping list. Perhaps one + or the other can be eliminated. + */ + + cdio_lba_to_msf (cdio_lsn_to_lba(start_lsn), &(this_track->start_msf)); + this_track->start_lba = cdio_msf_to_lba(&this_track->start_msf); + this_track->track_num = track_num+1; + this_track->blocksize = blocksize; + if (_obj->is_cues) + this_track->datastart = img_offset + 8; + else + this_track->datastart = 8; + + this_track->sec_count = sec_count; + + _obj->total_tracks++; + + /* FIXME: These are probably not right. Probably we need to look at + "type." But this hasn't been reverse engineered yet. + */ + this_track->track_format= TRACK_FORMAT_XA; + this_track->track_green = true; + + /* cdio_debug ("map: %d +%d -> %ld", start_lsn, sec_count, img_offset); */ +} + + +/* + Disk and track information for a Nero file are located at the end + of the file. This routine extracts that information. + */ +static bool +_cdio_parse_nero_footer (_img_private_t *_obj) +{ + long unsigned int footer_start; + long unsigned int size; + char *footer_buf = NULL; + + if (_obj->size) + return 0; + + size = cdio_stream_stat (_obj->gen.data_source); + if (-1 == size) return false; + + { +PRAGMA_BEGIN_PACKED + union { + struct { + uint32_t __x GNUC_PACKED; + uint32_t ID GNUC_PACKED; + uint32_t footer_ofs GNUC_PACKED; + } v50; + struct { + uint32_t ID GNUC_PACKED; + uint64_t footer_ofs GNUC_PACKED; + } v55; + } buf; +PRAGMA_END_PACKED + + cdio_assert (sizeof (buf) == 12); + + cdio_stream_seek (_obj->gen.data_source, size - sizeof (buf), SEEK_SET); + cdio_stream_read (_obj->gen.data_source, (void *) &buf, sizeof (buf), 1); + + if (buf.v50.ID == UINT32_TO_BE (0x4e45524f)) /* "NERO" */ + { + cdio_info ("detected v50 (32bit offsets) NRG magic"); + footer_start = uint32_to_be (buf.v50.footer_ofs); + } + else if (buf.v55.ID == UINT32_TO_BE (0x4e455235)) /* "NER5" */ + { + cdio_info ("detected v55 (64bit offsets) NRG magic"); + footer_start = uint64_from_be (buf.v55.footer_ofs); + } + else + { + cdio_warn ("Image not recognized as either v50 or v55 type NRG"); + return -1; + } + + cdio_debug ("nrg footer start = %ld, length = %ld", + (long) footer_start, (long) (size - footer_start)); + + cdio_assert (IN ((size - footer_start), 0, 4096)); + + footer_buf = _cdio_malloc (size - footer_start); + + cdio_stream_seek (_obj->gen.data_source, footer_start, SEEK_SET); + cdio_stream_read (_obj->gen.data_source, footer_buf, size - footer_start, 1); + } + + { + int pos = 0; + + while (pos < size - footer_start) { + _chunk_t *chunk = (void *) (footer_buf + pos); + + bool break_out = false; + + switch (UINT32_FROM_BE (chunk->id)) { + case CUES_ID: { /* "CUES" Seems to have sector size 2336 and 150 sector + pregap seems to be included at beginning of image. + */ + + + unsigned entries = UINT32_FROM_BE (chunk->len); + _cuex_array_t *_entries = (void *) chunk->data; + + cdio_assert (_obj->mapping == NULL); + + cdio_assert (sizeof (_cuex_array_t) == 8); + cdio_assert ( UINT32_FROM_BE(chunk->len) % sizeof(_cuex_array_t) + == 0 ); + + entries /= sizeof (_cuex_array_t); + + cdio_info ("CUES type image detected"); + + { + lsn_t lsn = UINT32_FROM_BE (_entries[0].lsn); + int idx; + + /*cdio_assert (lsn == 0?);*/ + + _obj->is_cues = true; /* HACK alert. */ + _obj->sector_2336 = true; + _obj->total_tracks = 0; + _obj->first_track_num = 1; + for (idx = 1; idx < entries-1; idx += 2) { + lsn_t sec_count; + + cdio_assert (_entries[idx].index == 0); + cdio_assert (_entries[idx].track == _entries[idx + 1].track); + + /* lsn and sec_count*2 aren't correct, but it comes closer on the + single example I have: svcdgs.nrg + We are picking up the wrong fields and/or not interpreting + them correctly. + */ + + lsn = UINT32_FROM_BE (_entries[idx].lsn); + sec_count = UINT32_FROM_BE (_entries[idx + 1].lsn); + + _register_mapping (_obj, lsn, sec_count*2, + (lsn+CDIO_PREGAP_SECTORS) * M2RAW_SECTOR_SIZE, + M2RAW_SECTOR_SIZE); + } + } + break; + } + + case CUEX_ID: /* "CUEX" */ { + unsigned entries = UINT32_FROM_BE (chunk->len); + _cuex_array_t *_entries = (void *) chunk->data; + + cdio_assert (_obj->mapping == NULL); + + cdio_assert ( sizeof (_cuex_array_t) == 8 ); + cdio_assert ( UINT32_FROM_BE (chunk->len) % sizeof(_cuex_array_t) + == 0 ); + + entries /= sizeof (_cuex_array_t); + + cdio_info ("DAO type image detected"); + + { + uint32_t lsn = UINT32_FROM_BE (_entries[0].lsn); + int idx; + + cdio_assert (lsn == 0xffffff6a); + + for (idx = 2; idx < entries; idx += 2) { + lsn_t lsn2; + + cdio_assert (_entries[idx].index == 1); + cdio_assert (_entries[idx].track != _entries[idx + 1].track); + + lsn = UINT32_FROM_BE (_entries[idx].lsn); + lsn2 = UINT32_FROM_BE (_entries[idx + 1].lsn); + + _register_mapping (_obj, lsn, lsn2 - lsn, + (lsn + CDIO_PREGAP_SECTORS)*M2RAW_SECTOR_SIZE, + M2RAW_SECTOR_SIZE); + } + } + break; + } + + case DAOI_ID: /* "DAOI" */ + cdio_debug ("DAOI tag detected..."); + break; + case DAOX_ID: /* "DAOX" */ + cdio_debug ("DAOX tag detected..."); + break; + + case NER5_ID: /* "NER5" */ + cdio_error ("unexpected nrg magic ID NER5 detected"); + return -1; + break; + + case NERO_ID: /* "NER0" */ + cdio_error ("unexpected nrg magic ID NER0 detected"); + return -1; + break; + + case END1_ID: /* "END!" */ + cdio_debug ("nrg end tag detected"); + break_out = true; + break; + + case ETNF_ID: /* "ETNF" */ { + unsigned entries = UINT32_FROM_BE (chunk->len); + _etnf_array_t *_entries = (void *) chunk->data; + + cdio_assert (_obj->mapping == NULL); + + cdio_assert ( sizeof (_etnf_array_t) == 20 ); + cdio_assert ( UINT32_FROM_BE(chunk->len) % sizeof(_etnf_array_t) + == 0 ); + + entries /= sizeof (_etnf_array_t); + + cdio_info ("SAO type image (ETNF) detected"); + + _obj->sector_2336 = true; + + { + int idx; + for (idx = 0; idx < entries; idx++) { + uint32_t _len = UINT32_FROM_BE (_entries[idx].length); + uint32_t _start = UINT32_FROM_BE (_entries[idx].start_lsn); + uint32_t _start2 = UINT32_FROM_BE (_entries[idx].start); + + cdio_assert (UINT32_FROM_BE (_entries[idx].type) == 3); + cdio_assert (_len % M2RAW_SECTOR_SIZE == 0); + + _len /= M2RAW_SECTOR_SIZE; + + cdio_assert (_start * M2RAW_SECTOR_SIZE == _start2); + + _start += idx * CDIO_PREGAP_SECTORS; + _register_mapping (_obj, _start, _len, _start2, M2RAW_SECTOR_SIZE); + + } + } + break; + } + + case ETN2_ID: { /* "ETN2", same as above, but with 64bit stuff instead */ + unsigned entries = uint32_from_be (chunk->len); + _etn2_array_t *_entries = (void *) chunk->data; + + cdio_assert (_obj->mapping == NULL); + + cdio_assert (sizeof (_etn2_array_t) == 32); + cdio_assert (uint32_from_be (chunk->len) % sizeof (_etn2_array_t) == 0); + + entries /= sizeof (_etn2_array_t); + + cdio_info ("SAO type image (ETN2) detected"); + + _obj->sector_2336 = true; + + { + int idx; + for (idx = 0; idx < entries; idx++) { + uint32_t _len = uint64_from_be (_entries[idx].length); + uint32_t _start = uint32_from_be (_entries[idx].start_lsn); + uint32_t _start2 = uint64_from_be (_entries[idx].start); + + cdio_assert (uint32_from_be (_entries[idx].type) == 3); + cdio_assert (_len % M2RAW_SECTOR_SIZE == 0); + + _len /= M2RAW_SECTOR_SIZE; + + cdio_assert (_start * M2RAW_SECTOR_SIZE == _start2); + + _start += idx * CDIO_PREGAP_SECTORS; + _register_mapping (_obj, _start, _len, _start2, M2RAW_SECTOR_SIZE); + } + } + break; + } + + case SINF_ID: { /* "SINF" */ + + uint32_t *_sessions = (void *) chunk->data; + + cdio_assert (UINT32_FROM_BE (chunk->len) == 4); + + cdio_debug ("SINF: %lu sessions", + (long unsigned int) UINT32_FROM_BE (*_sessions)); + } + break; + + default: + cdio_warn ("unknown tag %8.8x seen", + (unsigned int) UINT32_FROM_BE (chunk->id)); + break; + } + + if (break_out) + break; + + pos += 8; + pos += UINT32_FROM_BE (chunk->len); + } + } + + /* Fake out leadout track. */ + /* Don't use _cdio_stat_size since that will lead to recursion since + we haven't fully initialized things yet. + */ + cdio_lsn_to_msf (_obj->size, &_obj->tocent[_obj->total_tracks].start_msf); + _obj->tocent[_obj->total_tracks].start_lba = cdio_lsn_to_lba(_obj->size); + _obj->tocent[_obj->total_tracks-1].sec_count = + cdio_lsn_to_lba(_obj->size - _obj->tocent[_obj->total_tracks-1].start_lba); + + return 0; +} + +/*! + Initialize image structures. + */ +static bool +_cdio_init (_img_private_t *_obj) +{ + if (_obj->gen.init) { + cdio_error ("init called more than once"); + return false; + } + + if (!(_obj->gen.data_source = cdio_stdio_new (_obj->gen.source_name))) { + cdio_error ("init failed"); + return false; + } + + _cdio_parse_nero_footer (_obj); + _obj->gen.init = true; + 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 +_cdio_lseek (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; + unsigned int user_datasize; + + for (i=0; i<_obj->total_tracks; i++) { + track_info_t *this_track=&(_obj->tocent[i]); + switch (this_track->track_format) { + case TRACK_FORMAT_AUDIO: + user_datasize=CDIO_CD_FRAMESIZE_RAW; + break; + case TRACK_FORMAT_CDI: + user_datasize=CDIO_CD_FRAMESIZE; + break; + case TRACK_FORMAT_XA: + user_datasize=CDIO_CD_FRAMESIZE; + break; + default: + user_datasize=CDIO_CD_FRAMESIZE_RAW; + cdio_warn ("track %d has unknown format %d", + i+1, this_track->track_format); + } + + if ( (this_track->sec_count*user_datasize) >= offset) { + int blocks = offset / user_datasize; + int rem = offset % user_datasize; + int block_offset = blocks * (M2RAW_SECTOR_SIZE); + real_offset += block_offset + rem; + break; + } + real_offset += this_track->sec_count*(M2RAW_SECTOR_SIZE); + + offset -= this_track->sec_count*user_datasize; + } + + 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 +_cdio_read (void *env, void *buf, size_t size) +{ + _img_private_t *_obj = env; + return cdio_stream_read(_obj->gen.data_source, buf, size, 1); +} + +static uint32_t +_cdio_stat_size (void *env) +{ + _img_private_t *_obj = env; + + return _obj->size; +} + +/*! + Reads a single audio sector from CD device into data starting + from LSN. Returns 0 if no error. + */ +static int +_cdio_read_audio_sectors (void *env, void *data, lsn_t lsn, + unsigned int nblocks) +{ + _img_private_t *_obj = env; + + CdioListNode *node; + + if (lsn >= _obj->size) + { + cdio_warn ("trying to read beyond image size (%lu >= %lu)", + (long unsigned int) lsn, (long unsigned int) _obj->size); + return -1; + } + + _CDIO_LIST_FOREACH (node, _obj->mapping) { + _mapping_t *_map = _cdio_list_node_data (node); + + if (IN (lsn, _map->start_lsn, (_map->start_lsn + _map->sec_count - 1))) { + int ret; + long int img_offset = _map->img_offset; + + img_offset += (lsn - _map->start_lsn) * CDIO_CD_FRAMESIZE_RAW; + + ret = cdio_stream_seek (_obj->gen.data_source, img_offset, + SEEK_SET); + if (ret!=0) return ret; + ret = cdio_stream_read (_obj->gen.data_source, data, + CDIO_CD_FRAMESIZE_RAW, nblocks); + if (ret==0) return ret; + break; + } + } + + if (!node) cdio_warn ("reading into pre gap (lsn %lu)", + (long unsigned int) lsn); + + return 0; +} + +static int +_cdio_read_mode2_sector (void *env, void *data, lsn_t lsn, + bool mode2_form2) +{ + _img_private_t *_obj = env; + char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; + int blocksize = _obj->sector_2336 + ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE_RAW; + + CdioListNode *node; + + if (lsn >= _obj->size) + { + cdio_warn ("trying to read beyond image size (%lu >= %lu)", + (long unsigned int) lsn, (long unsigned int) _obj->size); + return -1; + } + + _CDIO_LIST_FOREACH (node, _obj->mapping) { + _mapping_t *_map = _cdio_list_node_data (node); + + if (IN (lsn, _map->start_lsn, (_map->start_lsn + _map->sec_count - 1))) { + int ret; + long int img_offset = _map->img_offset; + + img_offset += (lsn - _map->start_lsn) * blocksize; + + ret = cdio_stream_seek (_obj->gen.data_source, img_offset, + 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; + break; + } + } + + if (!node) + cdio_warn ("reading into pre gap (lsn %lu)", (long unsigned int) lsn); + + if (mode2_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 +_cdio_read_mode2_sectors (void *env, void *data, uint32_t lsn, + bool mode2_form2, unsigned nblocks) +{ + _img_private_t *_obj = env; + int i; + int retval; + + for (i = 0; i < nblocks; i++) { + if (mode2_form2) { + if ( (retval = _cdio_read_mode2_sector (_obj, + ((char *)data) + (M2RAW_SECTOR_SIZE * i), + lsn + i, true)) ) + return retval; + } else { + char buf[M2RAW_SECTOR_SIZE] = { 0, }; + if ( (retval = _cdio_read_mode2_sector (_obj, buf, lsn + i, true)) ) + return retval; + + memcpy (((char *)data) + (CDIO_CD_FRAMESIZE * i), + buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE); + } + } + return 0; +} + +/*! + Set the device to use in I/O operations. +*/ +static int +_cdio_set_arg (void *env, const char key[], const char value[]) +{ + _img_private_t *_obj = env; + + if (!strcmp (key, "source")) + { + free (_obj->gen.source_name); + + if (!value) + return -2; + + _obj->gen.source_name = strdup (value); + } + else + return -1; + + return 0; +} + +/*! + Return the value associated with the key "arg". +*/ +static const char * +_cdio_get_arg (void *env, const char key[]) +{ + _img_private_t *_obj = env; + + if (!strcmp (key, "source")) { + return _obj->gen.source_name; + } + return NULL; +} + +/*! + Return an array of strings giving possible NRG disk images. + */ +char ** +cdio_get_devices_nrg (void) +{ + char **drives = NULL; + unsigned int num_files=0; +#ifdef HAVE_GLOB_H + unsigned int i; + glob_t globbuf; + globbuf.gl_offs = 0; + glob("*.nrg", GLOB_DOOFFS, NULL, &globbuf); + for (i=0; i<globbuf.gl_pathc; i++) { + cdio_add_device_list(&drives, globbuf.gl_pathv[i], &num_files); + } + globfree(&globbuf); +#else + cdio_add_device_list(&drives, DEFAULT_CDIO_DEVICE, &num_files); +#endif /*HAVE_GLOB_H*/ + cdio_add_device_list(&drives, NULL, &num_files); + return drives; +} + +/*! + Return a string containing the default CD device. + */ +char * +cdio_get_default_device_nrg(void) +{ + char **drives = cdio_get_devices_nrg(); + char *drive = (drives[0] == NULL) ? NULL : strdup(drives[0]); + cdio_free_device_list(drives); + return drive; +} + +/*! + Return the number of of the first track. + CDIO_INVALID_TRACK is returned on error. +*/ +static track_t +_cdio_get_first_track_num(void *env) +{ + _img_private_t *_obj = env; + + return _obj->first_track_num; +} + +/*! + Return the number of tracks. We fake it an just say there's + one big track. +*/ +static track_t +_cdio_get_num_tracks(void *env) +{ + _img_private_t *_obj = env; + + return _obj->total_tracks; +} + +/*! + Return the number of tracks in the current medium. + CDIO_INVALID_TRACK is returned on error. +*/ +static track_format_t +_cdio_get_track_format(void *env, track_t track_num) +{ + _img_private_t *_obj = env; + + 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 +_cdio_get_track_green(void *env, track_t track_num) +{ + _img_private_t *_obj = env; + + if (track_num > _obj->total_tracks || track_num == 0) + return false; + + return _obj->tocent[track_num-1].track_green; +} + +/*! + Return the starting MSF (minutes/secs/frames) for the track number + track_num in obj. Tracks numbers start at 1. + The "leadout" track is specified either by + using track_num LEADOUT_TRACK or the total tracks+1. +*/ +static bool +_cdio_get_track_msf(void *env, track_t track_num, msf_t *msf) +{ + _img_private_t *_obj = env; + + if (NULL == msf) return 1; + + if (track_num == CDIO_CDROM_LEADOUT_TRACK) track_num = _obj->total_tracks+1; + + if (track_num <= _obj->total_tracks+1 && track_num != 0) { + *msf = _obj->tocent[track_num-1].start_msf; + return true; + } else + return false; +} + +CdIo * +cdio_open_nrg (const char *source_name) +{ + CdIo *ret; + _img_private_t *_data; + + cdio_funcs _funcs = { + .eject_media = cdio_generic_bogus_eject_media, + .free = cdio_generic_stream_free, + .get_arg = _cdio_get_arg, + .get_devices = cdio_get_devices_nrg, + .get_default_device = cdio_get_default_device_nrg, + .get_first_track_num= _cdio_get_first_track_num, + .get_num_tracks = _cdio_get_num_tracks, + .get_track_format = _cdio_get_track_format, + .get_track_green = _cdio_get_track_green, + .get_track_lba = NULL, /* Will use generic routine via msf */ + .get_track_msf = _cdio_get_track_msf, + .lseek = _cdio_lseek, + .read = _cdio_read, + .read_audio_sectors = _cdio_read_audio_sectors, + .read_mode2_sector = _cdio_read_mode2_sector, + .read_mode2_sectors = _cdio_read_mode2_sectors, + .set_arg = _cdio_set_arg, + .stat_size = _cdio_stat_size, + }; + + _data = _cdio_malloc (sizeof (_img_private_t)); + _data->gen.init = false; + + + _data->total_tracks = 0; + _data->first_track_num= 1; + _data->sector_2336 = false; /* FIXME: remove sector_2336 */ + _data->is_cues = false; /* FIXME: remove is_cues. */ + + + _cdio_set_arg(_data, "source", (NULL == source_name) + ? DEFAULT_CDIO_DEVICE: source_name); + + ret = cdio_new (_data, &_funcs); + if (ret == NULL) return NULL; + + if (_cdio_init(_data)) + return ret; + else { + cdio_generic_stream_free (_data); + return NULL; + } + +} + +bool +cdio_have_nrg (void) +{ + return true; +} diff --git a/src/input/vcd/libcdio/_cdio_osx.c b/src/input/vcd/libcdio/_cdio_osx.c new file mode 100644 index 000000000..b02151f30 --- /dev/null +++ b/src/input/vcd/libcdio/_cdio_osx.c @@ -0,0 +1,864 @@ +/* + $Id: _cdio_osx.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $ + + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> from vcdimager code + Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org> + and VideoLAN code Copyright (C) 1998-2001 VideoLAN + Authors: Johan Bilien <jobi@via.ecp.fr> + Gildas Bazin <gbazin@netcourrier.com> + Jon Lech Johansen <jon-vl@nanocrew.net> + + 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 file contains OSX-specific code and implements low-level + control of the CD drive. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +static const char _rcsid[] = "$Id: _cdio_osx.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $"; + +#include <cdio/sector.h> +#include <cdio/util.h> +#include "cdio_assert.h" +#include "cdio_private.h" + +/* Is this the right default? */ +#define DEFAULT_CDIO_DEVICE "/dev/rdisk2" + +#include <string.h> + +#ifdef HAVE_DARWIN_CDROM + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/ioctl.h> + +#include <CoreFoundation/CFBase.h> +#include <IOKit/IOKitLib.h> +#include <IOKit/storage/IOCDTypes.h> +#include <IOKit/storage/IOCDMedia.h> +#include <IOKit/storage/IOCDMediaBSDClient.h> + +#define TOTAL_TRACKS (_obj->num_tracks) + +typedef struct { + /* Things common to all drivers like this. + This must be first. */ + generic_img_private_t gen; + + enum { + _AM_NONE, + _AM_OSX, + } access_mode; + + /* Track information */ + bool toc_init; /* if true, info below is valid. */ + CDTOC *pTOC; + int i_descriptors; + track_t num_tracks; + lsn_t *pp_lba; + +} _img_private_t; + +static void +_cdio_osx_free (void *env) { + _img_private_t *_obj = env; + if (NULL == _obj) return; + cdio_generic_free(_obj); + if (NULL != _obj->pp_lba) free((void *) _obj->pp_lba); + if (NULL != _obj->pTOC) free((void *) _obj->pTOC); +} + +/**************************************************************************** + cdio_getNumberOfTracks: get number of tracks in TOC + This is an internal routine and is called once per CD open. + ****************************************************************************/ +static track_t +_cdio_getNumberOfTracks( CDTOC *pTOC, int i_descriptors ) +{ + track_t track = CDIO_INVALID_TRACK; + int i; + int i_tracks = 0; + CDTOCDescriptor *pTrackDescriptors; + + pTrackDescriptors = pTOC->descriptors; + + for( i = i_descriptors; i >= 0; i-- ) + { + track = pTrackDescriptors[i].point; + + if( track > CDIO_CD_MAX_TRACKS || track < CDIO_CD_MIN_TRACK_NO ) + continue; + + i_tracks++; + } + + return( i_tracks ); +} + +/*! + Reads nblocks of mode2 form2 sectors from cd device into data starting + from lsn. + Returns 0 if no error. + */ +static int +_cdio_read_mode2_form2_sectors (int device_handle, void *data, lsn_t lsn, + bool mode2_form2, unsigned int nblocks) +{ + dk_cd_read_t cd_read; + + memset( &cd_read, 0, sizeof(cd_read) ); + + cd_read.offset = lsn * CDIO_CD_FRAMESIZE_RAW; + cd_read.sectorArea = kCDSectorAreaSync | kCDSectorAreaHeader | + kCDSectorAreaSubHeader | kCDSectorAreaUser | + kCDSectorAreaAuxiliary; + cd_read.sectorType = kCDSectorTypeUnknown; + + cd_read.buffer = data; + cd_read.bufferLength = CDIO_CD_FRAMESIZE_RAW * nblocks; + + if( ioctl( device_handle, DKIOCCDREAD, &cd_read ) == -1 ) + { + cdio_error( "could not read block %d", lsn ); + return -1; + } + return 0; +} + + +/*! + Reads nblocks of mode2 sectors from cd device into data starting + from lsn. + Returns 0 if no error. + */ +static int +_cdio_read_mode2_sectors (void *env, void *data, lsn_t lsn, + bool mode2_form2, unsigned int nblocks) +{ + _img_private_t *_obj = env; + int i; + int retval; + + if (mode2_form2) { + return _cdio_read_mode2_form2_sectors(_obj->gen.fd, data, lsn, + mode2_form2, nblocks); + } + + for (i = 0; i < nblocks; i++) { + char buf[M2RAW_SECTOR_SIZE] = { 0, }; + retval = _cdio_read_mode2_form2_sectors (_obj->gen.fd, buf, lsn + i, + mode2_form2, 1); + if ( retval ) return retval; + + memcpy (((char *)data) + (CDIO_CD_FRAMESIZE * i), + buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE); + } + return 0; +} + +/*! + Reads a single audio sector from CD device into data starting from lsn. + Returns 0 if no error. + */ +static int +_cdio_read_audio_sectors (void *env, void *data, lsn_t lsn, + unsigned int nblocks) +{ + return _cdio_read_mode2_sectors(env, data, lsn, true, nblocks); +} + +/*! + Reads a single mode2 sector from cd device into data starting + from lsn. Returns 0 if no error. + */ +static int +_cdio_read_mode2_sector (void *env, void *data, lsn_t lsn, + bool mode2_form2) +{ + return _cdio_read_mode2_sectors(env, data, lsn, mode2_form2, 1); +} + +/*! + Set the key "arg" to "value" in source device. +*/ +static int +_cdio_set_arg (void *env, const char key[], const char value[]) +{ + _img_private_t *_obj = env; + + if (!strcmp (key, "source")) + { + if (!value) + return -2; + + free (_obj->gen.source_name); + + _obj->gen.source_name = strdup (value); + } + else if (!strcmp (key, "access-mode")) + { + if (!strcmp(value, "OSX")) + _obj->access_mode = _AM_OSX; + else + cdio_error ("unknown access type: %s. ignored.", value); + } + else + return -1; + + return 0; +} + +/*! + Read and cache the CD's Track Table of Contents and track info. + Return false if successful or true if an error. +*/ +static bool +_cdio_read_toc (_img_private_t *_obj) +{ + mach_port_t port; + char *psz_devname; + kern_return_t ret; + io_iterator_t iterator; + io_registry_entry_t service; + CFMutableDictionaryRef properties; + CFDataRef data; + + _obj->gen.fd = open( _obj->gen.source_name, O_RDONLY | O_NONBLOCK ); + if (-1 == _obj->gen.fd) { + cdio_error("Failed to open %s: %s", _obj->gen.source_name, + strerror(errno)); + return false; + } + + /* get the device name */ + if( ( psz_devname = strrchr( _obj->gen.source_name, '/') ) != NULL ) + ++psz_devname; + else + psz_devname = _obj->gen.source_name; + + /* unraw the device name */ + if( *psz_devname == 'r' ) + ++psz_devname; + + /* get port for IOKit communication */ + if( ( ret = IOMasterPort( MACH_PORT_NULL, &port ) ) != KERN_SUCCESS ) + { + cdio_error( "IOMasterPort: 0x%08x", ret ); + return false; + } + + /* get service iterator for the device */ + if( ( ret = IOServiceGetMatchingServices( + port, IOBSDNameMatching( port, 0, psz_devname ), + &iterator ) ) != KERN_SUCCESS ) + { + cdio_error( "IOServiceGetMatchingServices: 0x%08x", ret ); + return false; + } + + /* first service */ + service = IOIteratorNext( iterator ); + IOObjectRelease( iterator ); + + /* search for kIOCDMediaClass */ + while( service && !IOObjectConformsTo( service, kIOCDMediaClass ) ) + { + + ret = IORegistryEntryGetParentIterator( service, kIOServicePlane, + &iterator ); + if( ret != KERN_SUCCESS ) + { + cdio_error( "IORegistryEntryGetParentIterator: 0x%08x", ret ); + IOObjectRelease( service ); + return false; + } + + IOObjectRelease( service ); + service = IOIteratorNext( iterator ); + IOObjectRelease( iterator ); + } + + if( service == 0 ) + { + cdio_error( "search for kIOCDMediaClass came up empty" ); + return false; + } + + /* create a CF dictionary containing the TOC */ + ret = IORegistryEntryCreateCFProperties( service, &properties, + kCFAllocatorDefault, kNilOptions ); + + if( ret != KERN_SUCCESS ) + { + cdio_error( "IORegistryEntryCreateCFProperties: 0x%08x", ret ); + IOObjectRelease( service ); + return false; + } + + /* get the TOC from the dictionary */ + data = (CFDataRef) CFDictionaryGetValue( properties, + CFSTR(kIOCDMediaTOCKey) ); + if( data != NULL ) + { + CFRange range; + CFIndex buf_len; + + buf_len = CFDataGetLength( data ) + 1; + range = CFRangeMake( 0, buf_len ); + + if( ( _obj->pTOC = (CDTOC *)malloc( buf_len ) ) != NULL ) { + CFDataGetBytes( data, range, (u_char *) _obj->pTOC ); + } else { + cdio_error( "Trouble allocating CDROM TOC" ); + return false; + } + } + else + { + cdio_error( "CFDictionaryGetValue failed" ); + } + + CFRelease( properties ); + IOObjectRelease( service ); + + _obj->i_descriptors = CDTOCGetDescriptorCount ( _obj->pTOC ); + _obj->num_tracks = _cdio_getNumberOfTracks(_obj->pTOC, _obj->i_descriptors); + + /* Read in starting sectors */ + { + int i, i_leadout = -1; + CDTOCDescriptor *pTrackDescriptors; + track_t track; + int i_tracks; + + _obj->pp_lba = malloc( (_obj->num_tracks + 1) * sizeof(int) ); + if( _obj->pp_lba == NULL ) + { + cdio_error("Out of memory in allocating track starting LSNs" ); + free( _obj->pTOC ); + return false; + } + + pTrackDescriptors = _obj->pTOC->descriptors; + + for( i_tracks = 0, i = 0; i <= _obj->i_descriptors; i++ ) + { + track = pTrackDescriptors[i].point; + + if( track == 0xA2 ) + /* Note leadout should be 0xAA, But OSX seems to use 0xA2. */ + i_leadout = i; + + if( track > CDIO_CD_MAX_TRACKS || track < CDIO_CD_MIN_TRACK_NO ) + continue; + + _obj->pp_lba[i_tracks++] = + cdio_lsn_to_lba(CDConvertMSFToLBA( pTrackDescriptors[i].p )); + } + + if( i_leadout == -1 ) + { + cdio_error( "CD leadout not found" ); + free( _obj->pp_lba ); + free( (void *) _obj->pTOC ); + return false; + } + + /* set leadout sector */ + _obj->pp_lba[i_tracks] = + cdio_lsn_to_lba(CDConvertMSFToLBA( pTrackDescriptors[i_leadout].p )); + } + + _obj->toc_init = true; + + return( true ); + +} + +/*! + 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 lsn_t +_cdio_get_track_lba(void *env, track_t track_num) +{ + _img_private_t *_obj = env; + + if (!_obj->toc_init) _cdio_read_toc (_obj) ; + + if (track_num == CDIO_CDROM_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1; + + if (track_num > TOTAL_TRACKS+1 || track_num == 0) { + return CDIO_INVALID_LSN; + } else { + return _obj->pp_lba[track_num-1]; + } +} + +/*! + Eject media . Return 1 if successful, 0 otherwise. + + The only way to cleanly unmount the disc under MacOS X is to use the + 'disktool' command line utility. It uses the non-public Disk + Arbitration API, which can not be used by Cocoa or Carbon + applications. + + */ + +static int +_cdio_eject_media (void *env) { + + _img_private_t *_obj = env; + + FILE *p_eject; + char *psz_disk; + char sz_cmd[32]; + + if( ( psz_disk = (char *)strstr( _obj->gen.source_name, "disk" ) ) != NULL && + strlen( psz_disk ) > 4 ) + { +#define EJECT_CMD "/usr/sbin/disktool -e %s 0" + snprintf( sz_cmd, sizeof(sz_cmd), EJECT_CMD, psz_disk ); +#undef EJECT_CMD + + if( ( p_eject = popen( sz_cmd, "r" ) ) != NULL ) + { + char psz_result[0x200]; + int i_ret = fread( psz_result, 1, sizeof(psz_result) - 1, p_eject ); + + if( i_ret == 0 && ferror( p_eject ) != 0 ) + { + pclose( p_eject ); + return 0; + } + + pclose( p_eject ); + + psz_result[ i_ret ] = 0; + + if( strstr( psz_result, "Disk Ejected" ) != NULL ) + { + return 1; + } + } + } + + return 0; +} + +/*! + Return the size of the CD in logical block address (LBA) units. + */ +static uint32_t +_cdio_stat_size (void *env) +{ + return _cdio_get_track_lba(env, CDIO_CDROM_LEADOUT_TRACK); +} + +/*! + Return the value associated with the key "arg". +*/ +static const char * +_cdio_get_arg (void *env, const char key[]) +{ + _img_private_t *_obj = env; + + if (!strcmp (key, "source")) { + return _obj->gen.source_name; + } else if (!strcmp (key, "access-mode")) { + switch (_obj->access_mode) { + case _AM_OSX: + return "OS X"; + case _AM_NONE: + return "no access method"; + } + } + return NULL; +} + +/*! + Return the number of the first track. + CDIO_INVALID_TRACK is returned on error. +*/ +static track_t +_cdio_get_first_track_num(void *env) +{ + _img_private_t *_obj = env; + + if (!_obj->toc_init) _cdio_read_toc (_obj) ; + + { + track_t track = CDIO_INVALID_TRACK; + int i; + CDTOCDescriptor *pTrackDescriptors; + + pTrackDescriptors = _obj->pTOC->descriptors; + + for( i = 0; i < _obj->i_descriptors; i++ ) + { + track = pTrackDescriptors[i].point; + + if( track > CDIO_CD_MAX_TRACKS || track < CDIO_CD_MIN_TRACK_NO ) + continue; + return ( track ); + } + } + + return CDIO_INVALID_TRACK; +} + +/*! + Return the media catalog number MCN. + */ +static char * +_cdio_get_mcn (void *env) { + _img_private_t *_obj = env; + dk_cd_read_mcn_t cd_read; + + memset( &cd_read, 0, sizeof(cd_read) ); + + if( ioctl( _obj->gen.fd, DKIOCCDREADMCN, &cd_read ) < 0 ) + { + cdio_error( "could not read MCN, %s", strerror(errno) ); + return -1; + } + return strdup((char*)cd_read.mcn); +} + +/*! + Return the number of tracks in the current medium. + CDIO_INVALID_TRACK is returned on error. + This is the externally called interface. +*/ +static track_t +_cdio_get_num_tracks(void *env) +{ + _img_private_t *_obj = env; + + if (!_obj->toc_init) _cdio_read_toc (_obj) ; + return( _obj->num_tracks ); +} + +/*! + Get format of track. +*/ +static track_format_t +_cdio_get_track_format(void *env, track_t track_num) +{ + _img_private_t *_obj = env; + + if (!_obj->toc_init) _cdio_read_toc (_obj) ; + + if (track_num > TOTAL_TRACKS || track_num == 0) + return TRACK_FORMAT_ERROR; + +#if 0 + if (_obj->tocent[track_num-1].entry.control & CDROM_DATA_TRACK) { + if (_obj->tocent[track_num-1].cdte_format == 0x10) + return TRACK_FORMAT_CDI; + else if (_obj->tocent[track_num-1].cdte_format == 0x20) + return TRACK_FORMAT_XA; + else + return TRACK_FORMAT_DATA; + } else + return TRACK_FORMAT_AUDIO; +#else + /* FIXME! Figure out how to do. */ + return TRACK_FORMAT_DATA; +#endif + +} + +/*! + 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 +_cdio_get_track_green(void *env, track_t track_num) +{ + +#if 0 + if (!_obj->toc_init) _cdio_read_toc (_obj) ; + + if (track_num == CDIO_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1; + + if (track_num > TOTAL_TRACKS+1 || track_num == 0) + return false; + + /* FIXME: Dunno if this is the right way, but it's what + I was using in cdinfo for a while. + */ + return ((_obj->tocent[track_num-1].cdte_ctrl & 2) != 0); +#else + /* FIXME! Figure out how to do. */ + return true; +#endif +} + +#endif /* HAVE_DARWIN_CDROM */ + +/*! + Return a string containing the default CD device if none is specified. + */ +char ** +cdio_get_devices_osx(void) +{ +#ifndef HAVE_DARWIN_CDROM + return NULL; +#else + io_object_t next_media; + mach_port_t master_port; + kern_return_t kern_result; + io_iterator_t media_iterator; + CFMutableDictionaryRef classes_to_match; + char **drives = NULL; + unsigned int num_drives=0; + + kern_result = IOMasterPort( MACH_PORT_NULL, &master_port ); + if( kern_result != KERN_SUCCESS ) + { + return( nil ); + } + + classes_to_match = IOServiceMatching( kIOCDMediaClass ); + if( classes_to_match == NULL ) + { + return( nil ); + } + + CFDictionarySetValue( classes_to_match, CFSTR(kIOMediaEjectable), + kCFBooleanTrue ); + + kern_result = IOServiceGetMatchingServices( master_port, + classes_to_match, + &media_iterator ); + if( kern_result != KERN_SUCCESS ) + { + return( nil ); + } + + next_media = IOIteratorNext( media_iterator ); + if( next_media != 0 ) + { + char psz_buf[0x32]; + size_t dev_path_length; + CFTypeRef str_bsd_path; + + do + { + str_bsd_path = IORegistryEntryCreateCFProperty( next_media, + CFSTR( kIOBSDName ), + kCFAllocatorDefault, + 0 ); + if( str_bsd_path == NULL ) + { + IOObjectRelease( next_media ); + continue; + } + + snprintf( psz_buf, sizeof(psz_buf), "%s%c", _PATH_DEV, 'r' ); + dev_path_length = strlen( psz_buf ); + + if( CFStringGetCString( str_bsd_path, + (char*)&psz_buf + dev_path_length, + sizeof(psz_buf) - dev_path_length, + kCFStringEncodingASCII ) ) + { + CFRelease( str_bsd_path ); + IOObjectRelease( next_media ); + IOObjectRelease( media_iterator ); + cdio_add_device_list(&drives, psz_buf, &num_drives); + } + + CFRelease( str_bsd_path ); + IOObjectRelease( next_media ); + + } while( ( next_media = IOIteratorNext( media_iterator ) ) != 0 ); + } + IOObjectRelease( media_iterator ); + cdio_add_device_list(&drives, NULL, &num_drives); + return drives; +#endif /* HAVE_DARWIN_CDROM */ +} + +/*! + Return a string containing the default CD device if none is specified. + */ +char * +cdio_get_default_device_osx(void) +{ +#ifndef HAVE_DARWIN_CDROM + return NULL; +#else + io_object_t next_media; + mach_port_t master_port; + kern_return_t kern_result; + io_iterator_t media_iterator; + CFMutableDictionaryRef classes_to_match; + + kern_result = IOMasterPort( MACH_PORT_NULL, &master_port ); + if( kern_result != KERN_SUCCESS ) + { + return( nil ); + } + + classes_to_match = IOServiceMatching( kIOCDMediaClass ); + if( classes_to_match == NULL ) + { + return( nil ); + } + + CFDictionarySetValue( classes_to_match, CFSTR(kIOMediaEjectable), + kCFBooleanTrue ); + + kern_result = IOServiceGetMatchingServices( master_port, + classes_to_match, + &media_iterator ); + if( kern_result != KERN_SUCCESS ) + { + return( nil ); + } + + next_media = IOIteratorNext( media_iterator ); + if( next_media != 0 ) + { + char psz_buf[0x32]; + size_t dev_path_length; + CFTypeRef str_bsd_path; + + do + { + str_bsd_path = IORegistryEntryCreateCFProperty( next_media, + CFSTR( kIOBSDName ), + kCFAllocatorDefault, + 0 ); + if( str_bsd_path == NULL ) + { + IOObjectRelease( next_media ); + continue; + } + + snprintf( psz_buf, sizeof(psz_buf), "%s%c", _PATH_DEV, 'r' ); + dev_path_length = strlen( psz_buf ); + + if( CFStringGetCString( str_bsd_path, + (char*)&psz_buf + dev_path_length, + sizeof(psz_buf) - dev_path_length, + kCFStringEncodingASCII ) ) + { + CFRelease( str_bsd_path ); + IOObjectRelease( next_media ); + IOObjectRelease( media_iterator ); + return strdup( psz_buf ); + } + + CFRelease( str_bsd_path ); + IOObjectRelease( next_media ); + + } while( ( next_media = IOIteratorNext( media_iterator ) ) != 0 ); + } + IOObjectRelease( media_iterator ); + return NULL; +#endif /* HAVE_DARWIN_CDROM */ +} + +/*! + 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_osx (const char *source_name) +{ + +#ifdef HAVE_DARWIN_CDROM + CdIo *ret; + _img_private_t *_data; + + cdio_funcs _funcs = { + .eject_media = _cdio_eject_media, + .free = _cdio_osx_free, + .get_arg = _cdio_get_arg, + .get_default_device = cdio_get_default_device_osx, + .get_devices = cdio_get_devices_osx, + .get_first_track_num= _cdio_get_first_track_num, + .get_mcn = _cdio_get_mcn, + .get_num_tracks = _cdio_get_num_tracks, + .get_track_format = _cdio_get_track_format, + .get_track_green = _cdio_get_track_green, + .get_track_lba = _cdio_get_track_lba, + .get_track_msf = NULL, + .lseek = cdio_generic_lseek, + .read = cdio_generic_read, + .read_audio_sectors = _cdio_read_audio_sectors, + .read_mode2_sector = _cdio_read_mode2_sector, + .read_mode2_sectors = _cdio_read_mode2_sectors, + .set_arg = _cdio_set_arg, + .stat_size = _cdio_stat_size + }; + + _data = _cdio_malloc (sizeof (_img_private_t)); + _data->access_mode = _AM_OSX; + _data->gen.init = false; + _data->gen.fd = -1; + + _cdio_set_arg(_data, "source", (NULL == source_name) + ? DEFAULT_CDIO_DEVICE: source_name); + + ret = cdio_new (_data, &_funcs); + if (ret == NULL) return NULL; + + if (cdio_generic_init(_data)) + return ret; + else { + cdio_generic_free (_data); + return NULL; + } + +#else + return NULL; +#endif /* HAVE_DARWIN_CDROM */ + +} + +bool +cdio_have_osx (void) +{ +#ifdef HAVE_DARWIN_CDROM + return true; +#else + return false; +#endif /* HAVE_DARWIN_CDROM */ +} + + diff --git a/src/input/vcd/libcdio/_cdio_stdio.c b/src/input/vcd/libcdio/_cdio_stdio.c new file mode 100644 index 000000000..b8d8daa67 --- /dev/null +++ b/src/input/vcd/libcdio/_cdio_stdio.c @@ -0,0 +1,212 @@ +/* + $Id: _cdio_stdio.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + + 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 +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <errno.h> + +#include <cdio/logging.h> +#include <cdio/util.h> +#include "_cdio_stream.h" +#include "_cdio_stdio.h" + +static const char _rcsid[] = "$Id: _cdio_stdio.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $"; + +#define CDIO_STDIO_BUFSIZE (128*1024) + +typedef struct { + char *pathname; + FILE *fd; + char *fd_buf; + off_t st_size; /* used only for source */ +} _UserData; + +static int +_stdio_open (void *user_data) +{ + _UserData *const ud = user_data; + + if ((ud->fd = fopen (ud->pathname, "rb"))) + { + ud->fd_buf = _cdio_malloc (CDIO_STDIO_BUFSIZE); + setvbuf (ud->fd, ud->fd_buf, _IOFBF, CDIO_STDIO_BUFSIZE); + } + + return (ud->fd == NULL); +} + +static int +_stdio_close(void *user_data) +{ + _UserData *const ud = user_data; + + if (fclose (ud->fd)) + cdio_error ("fclose (): %s", strerror (errno)); + + ud->fd = NULL; + + free (ud->fd_buf); + ud->fd_buf = NULL; + + return 0; +} + +static void +_stdio_free(void *user_data) +{ + _UserData *const ud = user_data; + + if (ud->pathname) + free(ud->pathname); + + if (ud->fd) /* should be NULL anyway... */ + _stdio_close(user_data); + + free(ud); +} + +/*! + Like fseek(3) and in fact may be the same. + + This function sets the file position indicator for the stream + pointed to by stream. The new position, measured in bytes, is obtained + by adding offset bytes to the position specified by whence. If whence + is set to SEEK_SET, SEEK_CUR, or SEEK_END, the offset is relative to + the start of the file, the current position indicator, or end-of-file, + respectively. A successful call to the fseek function clears the end- + of-file indicator for the stream and undoes any effects of the + ungetc(3) function on the same stream. + + RETURN VALUE + Upon successful completion, return 0, + Otherwise, -1 is returned and the global variable errno is set to indi- + cate the error. +*/ +static long +_stdio_seek(void *user_data, long offset, int whence) +{ + _UserData *const ud = user_data; + + if ( (offset=fseek (ud->fd, offset, whence)) ) { + cdio_error ("fseek (): %s", strerror (errno)); + } + + return offset; +} + +static long int +_stdio_stat(void *user_data) +{ + const _UserData *const ud = user_data; + + return ud->st_size; +} + +/*! + Like fread(3) and in fact is about the same. + + DESCRIPTION: + The function fread reads nmemb elements of data, each size bytes long, + from the stream pointed to by stream, storing them at the location + given by ptr. + + RETURN VALUE: + return the number of items successfully read or written (i.e., + not the number of characters). If an error occurs, or the + end-of-file is reached, the return value is a short item count + (or zero). + + We do not distinguish between end-of-file and error, and callers + must use feof(3) and ferror(3) to determine which occurred. + */ +static long +_stdio_read(void *user_data, void *buf, long count) +{ + _UserData *const ud = user_data; + long read; + + read = fread(buf, 1, count, ud->fd); + + if (read != count) + { /* fixme -- ferror/feof */ + if (feof (ud->fd)) + { + cdio_debug ("fread (): EOF encountered"); + clearerr (ud->fd); + } + else if (ferror (ud->fd)) + { + cdio_error ("fread (): %s", strerror (errno)); + clearerr (ud->fd); + } + else + cdio_debug ("fread (): short read and no EOF?!?"); + } + + return read; +} + +CdioDataSource* +cdio_stdio_new(const char pathname[]) +{ + CdioDataSource *new_obj = NULL; + cdio_stream_io_functions funcs = { 0, }; + _UserData *ud = NULL; + struct stat statbuf; + + if (stat (pathname, &statbuf) == -1) + { + cdio_error ("could not stat() file `%s': %s", pathname, strerror (errno)); + return NULL; + } + + ud = _cdio_malloc (sizeof (_UserData)); + + ud->pathname = strdup(pathname); + ud->st_size = statbuf.st_size; /* let's hope it doesn't change... */ + + funcs.open = _stdio_open; + funcs.seek = _stdio_seek; + funcs.stat = _stdio_stat; + funcs.read = _stdio_read; + funcs.close = _stdio_close; + funcs.free = _stdio_free; + + new_obj = cdio_stream_new(ud, &funcs); + + return new_obj; +} + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/_cdio_stdio.h b/src/input/vcd/libcdio/_cdio_stdio.h new file mode 100644 index 000000000..013dff58b --- /dev/null +++ b/src/input/vcd/libcdio/_cdio_stdio.h @@ -0,0 +1,40 @@ +/* + $Id: _cdio_stdio.h,v 1.1 2003/10/13 11:47:11 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + + 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 +*/ + + +#ifndef __CDIO_STDIO_H__ +#define __CDIO_STDIO_H__ + +#include "_cdio_stream.h" + +CdioDataSource* +cdio_stdio_new(const char pathname[]); + +#endif /* __CDIO_STREAM_STDIO_H__ */ + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/_cdio_stream.c b/src/input/vcd/libcdio/_cdio_stream.c new file mode 100644 index 000000000..ee2f2b086 --- /dev/null +++ b/src/input/vcd/libcdio/_cdio_stream.c @@ -0,0 +1,198 @@ +/* + $Id: _cdio_stream.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + + 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 +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include "cdio_assert.h" + +/* #define STREAM_DEBUG */ + +#include <cdio/logging.h> +#include <cdio/util.h> +#include "_cdio_stream.h" + +static const char _rcsid[] = "$Id: _cdio_stream.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $"; + +/* + * DataSource implementations + */ + +struct _CdioDataSource { + void* user_data; + cdio_stream_io_functions op; + int is_open; + long position; +}; + +/* + Open if not already open. + Return false if we hit an error. Errno should be set for that error. +*/ +static bool +_cdio_stream_open_if_necessary(CdioDataSource *obj) +{ + cdio_assert (obj != NULL); + + if (!obj->is_open) { + if (obj->op.open(obj->user_data)) { + cdio_warn ("could not open input stream..."); + return false; + } else { + cdio_debug ("opened source..."); + obj->is_open = 1; + obj->position = 0; + } + } + return true; +} + +/*! + Like 3 fseek and in fact may be the same. + + This function sets the file position indicator for the stream + pointed to by stream. The new position, measured in bytes, is obtained + by adding offset bytes to the position specified by whence. If whence + is set to SEEK_SET, SEEK_CUR, or SEEK_END, the offset is relative to + the start of the file, the current position indicator, or end-of-file, + respectively. A successful call to the fseek function clears the end- + of-file indicator for the stream and undoes any effects of the + ungetc(3) function on the same stream. + + RETURN VALUE + Upon successful completion, return 0, + Otherwise, -1 is returned and the global variable errno is set to indi- + cate the error. +*/ +long +cdio_stream_seek(CdioDataSource* obj, long offset, int whence) +{ + cdio_assert (obj != NULL); + + if (!_cdio_stream_open_if_necessary(obj)) + /* errno is set by _cdio_stream_open_if necessary. */ + return -1; + + if (obj->position != offset) { +#ifdef STREAM_DEBUG + cdio_warn("had to reposition DataSource from %ld to %ld!", obj->position, offset); +#endif + obj->position = offset; + return obj->op.seek(obj->user_data, offset, whence); + } + + return 0; +} + +CdioDataSource* +cdio_stream_new(void *user_data, const cdio_stream_io_functions *funcs) +{ + CdioDataSource *new_obj; + + new_obj = _cdio_malloc (sizeof (CdioDataSource)); + + new_obj->user_data = user_data; + memcpy(&(new_obj->op), funcs, sizeof(cdio_stream_io_functions)); + + return new_obj; +} + +/*! + Like fread(3) and in fact may be the same. + + DESCRIPTION: + The function fread reads nmemb elements of data, each size bytes long, + from the stream pointed to by stream, storing them at the location + given by ptr. + + RETURN VALUE: + return the number of items successfully read or written (i.e., + not the number of characters). If an error occurs, or the + end-of-file is reached, the return value is a short item count + (or zero). + + We do not distinguish between end-of-file and error, and callers + must use feof(3) and ferror(3) to determine which occurred. +*/ +long +cdio_stream_read(CdioDataSource* obj, void *ptr, long size, long nmemb) +{ + long read_bytes; + + cdio_assert (obj != NULL); + + if (!_cdio_stream_open_if_necessary(obj)) return 0; + + read_bytes = obj->op.read(obj->user_data, ptr, size*nmemb); + obj->position += read_bytes; + + return read_bytes; +} + +/*! + Return whatever size of stream reports, I guess unit size is bytes. + On error return -1; + */ +long int +cdio_stream_stat(CdioDataSource* obj) +{ + cdio_assert (obj != NULL); + + if (!_cdio_stream_open_if_necessary(obj)) return -1; + + return obj->op.stat(obj->user_data); +} + +void +cdio_stream_close(CdioDataSource* obj) +{ + cdio_assert (obj != NULL); + + if (obj->is_open) { + cdio_debug ("closed source..."); + obj->op.close(obj->user_data); + obj->is_open = 0; + obj->position = 0; + } +} + +void +cdio_stream_destroy(CdioDataSource* obj) +{ + cdio_assert (obj != NULL); + + cdio_stream_close(obj); + + obj->op.free(obj->user_data); +} + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/_cdio_stream.h b/src/input/vcd/libcdio/_cdio_stream.h new file mode 100644 index 000000000..562c18bf8 --- /dev/null +++ b/src/input/vcd/libcdio/_cdio_stream.h @@ -0,0 +1,124 @@ +/* + $Id: _cdio_stream.h,v 1.1 2003/10/13 11:47:11 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + + 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 +*/ + + +#ifndef __CDIO_STREAM_H__ +#define __CDIO_STREAM_H__ + +#include <cdio/types.h> +#include "cdio_private.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + /* typedef'ed IO functions prototypes */ + + typedef int(*cdio_data_open_t)(void *user_data); + + typedef long(*cdio_data_read_t)(void *user_data, void *buf, long count); + + typedef long(*cdio_data_seek_t)(void *user_data, long offset, int whence); + + typedef long(*cdio_data_stat_t)(void *user_data); + + typedef int(*cdio_data_close_t)(void *user_data); + + typedef void(*cdio_data_free_t)(void *user_data); + + + /* abstract data source */ + + typedef struct { + cdio_data_open_t open; + cdio_data_seek_t seek; + cdio_data_stat_t stat; + cdio_data_read_t read; + cdio_data_close_t close; + cdio_data_free_t free; + } cdio_stream_io_functions; + + CdioDataSource* + cdio_stream_new(void *user_data, const cdio_stream_io_functions *funcs); + + /*! + Like fread(3) and in fact may be the same. + + DESCRIPTION: + The function fread reads nmemb elements of data, each size bytes long, + from the stream pointed to by stream, storing them at the location + given by ptr. + + RETURN VALUE: + return the number of items successfully read or written (i.e., + not the number of characters). If an error occurs, or the + end-of-file is reached, the return value is a short item count + (or zero). + + We do not distinguish between end-of-file and error, and callers + must use feof(3) and ferror(3) to determine which occurred. + */ + long + cdio_stream_read(CdioDataSource* obj, void *ptr, long size, long nmemb); + + /*! + Like fseek(3) and in fact may be the same. + + This function sets the file position indicator for the stream + pointed to by stream. The new position, measured in bytes, is obtained + by adding offset bytes to the position specified by whence. If whence + is set to SEEK_SET, SEEK_CUR, or SEEK_END, the offset is relative to + the start of the file, the current position indicator, or end-of-file, + respectively. A successful call to the fseek function clears the end- + of-file indicator for the stream and undoes any effects of the + ungetc(3) function on the same stream. + + RETURN VALUE + Upon successful completion, return 0, + Otherwise, -1 is returned and the global variable errno is set to indi- + cate the error. + */ + long cdio_stream_seek(CdioDataSource* obj, long offset, int whence); + + /*! + Return whatever size of stream reports, I guess unit size is bytes. + On error return -1; + */ + long cdio_stream_stat(CdioDataSource* obj); + + void cdio_stream_destroy(CdioDataSource* obj); + + void cdio_stream_close(CdioDataSource* obj); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __CDIO_STREAM_H__ */ + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/_cdio_sunos.c b/src/input/vcd/libcdio/_cdio_sunos.c new file mode 100644 index 000000000..e7faf57cd --- /dev/null +++ b/src/input/vcd/libcdio/_cdio_sunos.c @@ -0,0 +1,734 @@ +/* + $Id: _cdio_sunos.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $ + + Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org> + Copyright (C) 2002,2003 Rocky Bernstein <rocky@panix.com> + + 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 +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_GLOB_H +#include <glob.h> +#endif + + +#include <cdio/logging.h> +#include <cdio/sector.h> +#include <cdio/util.h> +#include "cdio_assert.h" +#include "cdio_private.h" +#include "scsi_mmc.h" + +#define DEFAULT_CDIO_DEVICE "/vol/dev/aliases/cdrom0" + +#ifdef HAVE_SOLARIS_CDROM + +static const char _rcsid[] = "$Id: _cdio_sunos.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $"; + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> + +#ifdef HAVE_SYS_CDIO_H +# include <sys/cdio.h> /* CDIOCALLOW etc... */ +#else +#error "You need <sys/cdio.h> to have CDROM support" +#endif + +#include <sys/dkio.h> +#include <sys/scsi/generic/commands.h> +#include <sys/scsi/impl/uscsi.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/ioctl.h> + +#define TOTAL_TRACKS (_obj->tochdr.cdth_trk1) +#define FIRST_TRACK_NUM (_obj->tochdr.cdth_trk0) + +/* reader */ + +typedef struct { + /* Things common to all drivers like this. + This must be first. */ + generic_img_private_t gen; + + enum { + _AM_NONE, + _AM_SUN_CTRL_ATAPI, + _AM_SUN_CTRL_SCSI +#if FINISHED + _AM_READ_CD, + _AM_READ_10 +#endif + } access_mode; + + + /* Track information */ + struct cdrom_tochdr tochdr; + struct cdrom_tocentry tocent[100]; /* entry info for each track */ + +} _img_private_t; + +/*! + Initialize CD device. + */ +static bool +_cdio_init (_img_private_t *_obj) +{ + + struct dk_cinfo cinfo; + + if (!cdio_generic_init(_obj)) return false; + + /* + * CDROMCDXA/CDROMREADMODE2 are broken on IDE/ATAPI devices. + * Try to send MMC3 SCSI commands via the uscsi interface on + * ATAPI devices. + */ + if ( ioctl(_obj->gen.fd, DKIOCINFO, &cinfo) == 0 + && ((strcmp(cinfo.dki_cname, "ide") == 0) + || (strncmp(cinfo.dki_cname, "pci", 3) == 0)) ) { + _obj->access_mode = _AM_SUN_CTRL_ATAPI; + } else { + _obj->access_mode = _AM_SUN_CTRL_SCSI; + } + + return true; +} + +static int +_cdio_mmc_read_sectors (int fd, void *buf, lsn_t lsn, int sector_type, + unsigned int nblocks) +{ + struct uscsi_cmd sc; + union scsi_cdb cdb; + int sub_channel = 0; + + memset(&cdb, 0, sizeof(cdb)); + memset(&sc, 0, sizeof(sc)); + + cdb.scc_cmd = CDIO_MMC_GPCMD_READ_CD; + CDIO_MMC_SET_READ_TYPE(cdb.cdb_opaque, sector_type); + CDIO_MMC_SET_READ_LBA(cdb.cdb_opaque, lsn); + CDIO_MMC_SET_READ_LENGTH(cdb.cdb_opaque, nblocks); + CDIO_MMC_SET_MAIN_CHANNEL_SELECTION_BITS(cdb.cdb_opaque, + CDIO_MMC_MCSB_ALL_HEADERS); + cdb.cdb_opaque[10] = sub_channel; + + sc.uscsi_cdb = (caddr_t)&cdb; + sc.uscsi_cdblen = 12; + sc.uscsi_bufaddr = (caddr_t) buf; + sc.uscsi_buflen = CDIO_CD_FRAMESIZE_RAW; + sc.uscsi_flags = USCSI_ISOLATE | USCSI_READ; + sc.uscsi_timeout = 20; + if (ioctl(fd, USCSICMD, &sc)) { + perror("USCSICMD: READ CD"); + return 1; + } + if (sc.uscsi_status) { + cdio_error("SCSI command failed with status %d\n", + sc.uscsi_status); + } + + return sc.uscsi_status; +} + +/*! + Reads a single mode2 sector from cd device into data starting from lsn. + Returns 0 if no error. + */ +static int +_cdio_read_mode2_sector (void *env, void *data, lsn_t lsn, + bool mode2_form2) +{ + char buf[M2RAW_SECTOR_SIZE] = { 0, }; + struct cdrom_msf *msf = (struct cdrom_msf *) &buf; + msf_t _msf; + + _img_private_t *_obj = env; + + cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf); + msf->cdmsf_min0 = from_bcd8(_msf.m); + msf->cdmsf_sec0 = from_bcd8(_msf.s); + msf->cdmsf_frame0 = from_bcd8(_msf.f); + + if (_obj->gen.ioctls_debugged == 75) + cdio_debug ("only displaying every 75th ioctl from now on"); + + if (_obj->gen.ioctls_debugged == 30 * 75) + cdio_debug ("only displaying every 30*75th ioctl from now on"); + + if (_obj->gen.ioctls_debugged < 75 + || (_obj->gen.ioctls_debugged < (30 * 75) + && _obj->gen.ioctls_debugged % 75 == 0) + || _obj->gen.ioctls_debugged % (30 * 75) == 0) + cdio_debug ("reading %2.2d:%2.2d:%2.2d", + msf->cdmsf_min0, msf->cdmsf_sec0, msf->cdmsf_frame0); + + _obj->gen.ioctls_debugged++; + + switch (_obj->access_mode) + { + case _AM_NONE: + cdio_error ("No way to read CD mode2."); + return 1; + break; + + case _AM_SUN_CTRL_SCSI: + if (ioctl (_obj->gen.fd, CDROMREADMODE2, buf) == -1) { + perror ("ioctl(..,CDROMREADMODE2,..)"); + return 1; + /* exit (EXIT_FAILURE); */ + } + break; + + case _AM_SUN_CTRL_ATAPI: + { + if (_cdio_mmc_read_sectors(_obj->gen.fd, data, lsn, + CDIO_MMC_READ_TYPE_MODE2, 1)) { + return 1; + } + break; + } + } + + if (mode2_form2) + memcpy (data, buf, M2RAW_SECTOR_SIZE); + else + memcpy (((char *)data), buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE); + + return 0; +} + +/*! + Reads single audio sectors from CD device into data starting from lsn. + Returns 0 if no error. + + May have to check size of nblocks. There may be a limit that + can be read in one go, e.g. 25 blocks. +*/ + +static int +_cdio_read_audio_sectors (void *env, void *data, lsn_t lsn, + unsigned int nblocks) +{ + _img_private_t *_obj = env; + + if (_obj->gen.ioctls_debugged == 75) + cdio_debug ("only displaying every 75th ioctl from now on"); + + if (_obj->gen.ioctls_debugged == 30 * 75) + cdio_debug ("only displaying every 30*75th ioctl from now on"); + + if (_obj->gen.ioctls_debugged < 75 + || (_obj->gen.ioctls_debugged < (30 * 75) + && _obj->gen.ioctls_debugged % 75 == 0) + || _obj->gen.ioctls_debugged % (30 * 75) == 0) + cdio_debug ("reading %d", lsn); + + _obj->gen.ioctls_debugged++; + + switch (_obj->access_mode) + { + case _AM_NONE: + cdio_error ("No way to read CD audio"); + return 1; + break; + + case _AM_SUN_CTRL_SCSI: + { + struct cdrom_cdda cdda; + cdda.cdda_addr = lsn; + cdda.cdda_length = nblocks; + cdda.cdda_data = (caddr_t) data; + if (ioctl (_obj->gen.fd, CDROMCDDA, &cdda) == -1) { + perror ("ioctl(..,CDROMCDDA,..)"); + return 1; + /* exit (EXIT_FAILURE); */ + } + } + break; + + case _AM_SUN_CTRL_ATAPI: + { + if (_cdio_mmc_read_sectors(_obj->gen.fd, data, lsn, + CDIO_MMC_READ_TYPE_CDDA, nblocks)) { + return 1; + } + break; + } + } + + return 0; +} + +/*! + Reads nblocks of mode2 sectors from cd device into data starting + from lsn. + Returns 0 if no error. + */ +static int +_cdio_read_mode2_sectors (void *env, void *data, uint32_t lsn, + bool mode2_form2, unsigned int nblocks) +{ + _img_private_t *_obj = env; + unsigned int i; + int retval; + + for (i = 0; i < nblocks; i++) { + if (mode2_form2) { + if ( (retval = _cdio_read_mode2_sector (_obj, + ((char *)data) + (M2RAW_SECTOR_SIZE * i), + lsn + i, true)) ) + return retval; + } else { + char buf[M2RAW_SECTOR_SIZE] = { 0, }; + if ( (retval = _cdio_read_mode2_sector (_obj, buf, lsn + i, true)) ) + return retval; + + memcpy (((char *)data) + (CDIO_CD_FRAMESIZE * i), + buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE); + } + } + return 0; +} + +/*! + Return the size of the CD in logical block address (LBA) units. + */ +static uint32_t +_cdio_stat_size (void *env) +{ + _img_private_t *_obj = env; + + struct cdrom_tocentry tocent; + uint32_t size; + + tocent.cdte_track = CDIO_CDROM_LEADOUT_TRACK; + tocent.cdte_format = CDROM_LBA; + if (ioctl (_obj->gen.fd, CDROMREADTOCENTRY, &tocent) == -1) + { + perror ("ioctl(CDROMREADTOCENTRY)"); + exit (EXIT_FAILURE); + } + + size = tocent.cdte_addr.lba; + + return size; +} + +/*! + Set the arg "key" with "value" in the source device. + Currently "source" and "access-mode" are valid keys. + "source" sets the source device in I/O operations + "access-mode" sets the the method of CD access + + 0 is returned if no error was found, and nonzero if there as an error. +*/ +static int +_cdio_set_arg (void *env, const char key[], const char value[]) +{ + _img_private_t *_obj = env; + + if (!strcmp (key, "source")) + { + if (!value) + return -2; + + free (_obj->gen.source_name); + + _obj->gen.source_name = strdup (value); + } + else if (!strcmp (key, "access-mode")) + { + if (!strcmp(value, "ATAPI")) + _obj->access_mode = _AM_SUN_CTRL_ATAPI; + else if (!strcmp(value, "SCSI")) + _obj->access_mode = _AM_SUN_CTRL_SCSI; + else + cdio_warn ("unknown access type: %s. ignored.", value); + } + else + return -1; + + return 0; +} + +/*! + Read and cache the CD's Track Table of Contents and track info. + Return true if successful or false if an error. +*/ +static bool +_cdio_read_toc (_img_private_t *_obj) +{ + int i; + + /* read TOC header */ + if ( ioctl(_obj->gen.fd, CDROMREADTOCHDR, &_obj->tochdr) == -1 ) { + cdio_error("%s: %s\n", + "error in ioctl CDROMREADTOCHDR", strerror(errno)); + return false; + } + + /* read individual tracks */ + for (i=_obj->tochdr.cdth_trk0; i<=_obj->tochdr.cdth_trk1; i++) { + _obj->tocent[i-1].cdte_track = i; + _obj->tocent[i-1].cdte_format = CDROM_MSF; + if ( ioctl(_obj->gen.fd, CDROMREADTOCENTRY, &_obj->tocent[i-1]) == -1 ) { + cdio_error("%s %d: %s\n", + "error in ioctl CDROMREADTOCENTRY for track", + i, strerror(errno)); + return false; + } + } + + /* read the lead-out track */ + _obj->tocent[_obj->tochdr.cdth_trk1].cdte_track = CDIO_CDROM_LEADOUT_TRACK; + _obj->tocent[_obj->tochdr.cdth_trk1].cdte_format = CDROM_MSF; + + if (ioctl(_obj->gen.fd, CDROMREADTOCENTRY, + &_obj->tocent[_obj->tochdr.cdth_trk1]) == -1 ) { + cdio_error("%s: %s\n", + "error in ioctl CDROMREADTOCENTRY for lead-out", + strerror(errno)); + return false; + } + + _obj->gen.toc_init = true; + return true; +} + +/*! + Eject media in CD drive. If successful, as a side effect we + also free obj. + */ +static int +_cdio_eject_media (void *env) { + + _img_private_t *_obj = env; + int ret; + + close(_obj->gen.fd); + _obj->gen.fd = -1; + if (_obj->gen.fd > -1) { + if ((ret = ioctl(_obj->gen.fd, CDROMEJECT)) != 0) { + cdio_generic_free((void *) _obj); + cdio_error ("CDROMEJECT failed: %s\n", strerror(errno)); + return 1; + } else { + return 0; + } + } + return 2; +} + + +static void * +_cdio_malloc_and_zero(size_t size) { + void *ptr; + + if( !size ) size++; + + if((ptr = malloc(size)) == NULL) { + cdio_error("malloc() failed: %s", strerror(errno)); + return NULL; + } + + memset(ptr, 0, size); + return ptr; +} + +/*! + Return the value associated with the key "arg". +*/ +static const char * +_cdio_get_arg (void *env, const char key[]) +{ + _img_private_t *_obj = env; + + if (!strcmp (key, "source")) { + return _obj->gen.source_name; + } else if (!strcmp (key, "access-mode")) { + switch (_obj->access_mode) { + case _AM_SUN_CTRL_ATAPI: + return "ATAPI"; + case _AM_SUN_CTRL_SCSI: + return "SCSI"; + case _AM_NONE: + return "no access method"; + } + } + return NULL; +} + +/*! + Return a string containing the default CD device if none is specified. + */ +char * +cdio_get_default_device_solaris(void) +{ + char *volume_device; + char *volume_name; + char *volume_action; + char *device; + struct stat stb; + + if ((volume_device = getenv("VOLUME_DEVICE")) != NULL && + (volume_name = getenv("VOLUME_NAME")) != NULL && + (volume_action = getenv("VOLUME_ACTION")) != NULL && + strcmp(volume_action, "insert") == 0) { + + device = _cdio_malloc_and_zero(strlen(volume_device) + + strlen(volume_name) + 2); + if (device == NULL) + return strdup(DEFAULT_CDIO_DEVICE); + sprintf(device, "%s/%s", volume_device, volume_name); + if (stat(device, &stb) != 0 || !S_ISCHR(stb.st_mode)) { + free(device); + return strdup(DEFAULT_CDIO_DEVICE); + } + return device; + } + return strdup(DEFAULT_CDIO_DEVICE); +} + +/*! + Return the number of of the first track. + CDIO_INVALID_TRACK is returned on error. +*/ +static track_t +_cdio_get_first_track_num(void *env) +{ + _img_private_t *_obj = env; + + if (!_obj->gen.toc_init) _cdio_read_toc (_obj) ; + + return FIRST_TRACK_NUM; +} + +/*! + Return the number of tracks in the current medium. +*/ +static track_t +_cdio_get_num_tracks(void *env) +{ + _img_private_t *_obj = env; + + if (!_obj->gen.toc_init) _cdio_read_toc (_obj) ; + + return TOTAL_TRACKS; +} + +/*! + Get format of track. +*/ +static track_format_t +_cdio_get_track_format(void *env, track_t track_num) +{ + _img_private_t *_obj = env; + + if (!_obj->gen.init) _cdio_init(_obj); + if (!_obj->gen.toc_init) _cdio_read_toc (_obj) ; + + if (track_num > TOTAL_TRACKS || track_num == 0) + return TRACK_FORMAT_ERROR; + + /* This is pretty much copied from the "badly broken" cdrom_count_tracks + in linux/cdrom.c. + */ + if (_obj->tocent[track_num-1].cdte_ctrl & CDROM_DATA_TRACK) { + if (_obj->tocent[track_num-1].cdte_format == 0x10) + return TRACK_FORMAT_CDI; + else if (_obj->tocent[track_num-1].cdte_format == 0x20) + return TRACK_FORMAT_XA; + else + return TRACK_FORMAT_DATA; + } else + return TRACK_FORMAT_AUDIO; + +} + +/*! + 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 +_cdio_get_track_green(void *env, track_t track_num) +{ + _img_private_t *_obj = env; + + if (!_obj->gen.init) _cdio_init(_obj); + if (!_obj->gen.toc_init) _cdio_read_toc (_obj) ; + + if (track_num == CDIO_CDROM_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1; + + if (track_num > TOTAL_TRACKS+1 || track_num == 0) + return false; + + /* FIXME: Dunno if this is the right way, but it's what + I was using in cdinfo for a while. + */ + return ((_obj->tocent[track_num-1].cdte_ctrl & 2) != 0); +} + +/*! + Return the starting MSF (minutes/secs/frames) for track number + track_num in obj. Tracks 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 entry. +*/ +static bool +_cdio_get_track_msf(void *env, track_t track_num, msf_t *msf) +{ + _img_private_t *_obj = env; + + if (NULL == msf) return false; + + if (!_obj->gen.init) _cdio_init(_obj); + if (!_obj->gen.toc_init) _cdio_read_toc (_obj) ; + + if (track_num == CDIO_CDROM_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1; + + if (track_num > TOTAL_TRACKS+1 || track_num == 0) { + return false; + } else { + struct cdrom_tocentry *msf0 = &_obj->tocent[track_num-1]; + msf->m = to_bcd8(msf0->cdte_addr.msf.minute); + msf->s = to_bcd8(msf0->cdte_addr.msf.second); + msf->f = to_bcd8(msf0->cdte_addr.msf.frame); + return true; + } +} + +#else +/*! + Return a string containing the default VCD device if none is specified. + */ +char * +cdio_get_default_device_solaris(void) +{ + return strdup(DEFAULT_CDIO_DEVICE); +} +#endif /* HAVE_SOLARIS_CDROM */ + +/*! + Return an array of strings giving possible CD devices. + */ +char ** +cdio_get_devices_solaris (void) +{ +#ifndef HAVE_SOLARIS_CDROM + return NULL; +#else + char **drives = NULL; + unsigned int num_files=0; +#ifdef HAVE_GLOB_H + unsigned int i; + glob_t globbuf; + globbuf.gl_offs = 0; + glob("/vol/dev/aliases/cdrom*", GLOB_DOOFFS, NULL, &globbuf); + for (i=0; i<globbuf.gl_pathc; i++) { + cdio_add_device_list(&drives, globbuf.gl_pathv[i], &num_files); + } + globfree(&globbuf); +#else + cdio_add_device_list(&drives, DEFAULT_CDIO_DEVICE, &num_files); +#endif /*HAVE_GLOB_H*/ + cdio_add_device_list(&drives, NULL, &num_files); + return drives; +#endif /*HAVE_SOLARIS_CDROM*/ +} + +/*! + 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_solaris (const char *source_name) +{ + +#ifdef HAVE_SOLARIS_CDROM + CdIo *ret; + _img_private_t *_data; + + cdio_funcs _funcs = { + .eject_media = _cdio_eject_media, + .free = cdio_generic_free, + .get_arg = _cdio_get_arg, + .get_devices = cdio_get_devices_solaris, + .get_default_device = cdio_get_default_device_solaris, + .get_first_track_num= _cdio_get_first_track_num, + .get_num_tracks = _cdio_get_num_tracks, + .get_track_format = _cdio_get_track_format, + .get_track_green = _cdio_get_track_green, + .get_track_lba = NULL, /* This could be implemented if need be. */ + .get_track_msf = _cdio_get_track_msf, + .lseek = cdio_generic_lseek, + .read = cdio_generic_read, + .read_audio_sectors = _cdio_read_audio_sectors, + .read_mode2_sector = _cdio_read_mode2_sector, + .read_mode2_sectors = _cdio_read_mode2_sectors, + .stat_size = _cdio_stat_size, + .set_arg = _cdio_set_arg + }; + + _data = _cdio_malloc (sizeof (_img_private_t)); + _data->gen.fd = -1; + + _cdio_set_arg(_data, "source", (NULL == source_name) + ? DEFAULT_CDIO_DEVICE: source_name); + + ret = cdio_new (_data, &_funcs); + if (ret == NULL) return NULL; + + if (_cdio_init(_data)) + return ret; + else { + cdio_generic_free (_data); + return NULL; + } + +#else + return NULL; +#endif /* HAVE_SOLARIS_CDROM */ + +} + +bool +cdio_have_solaris (void) +{ +#ifdef HAVE_SOLARIS_CDROM + return true; +#else + return false; +#endif /* HAVE_SOLARIS_CDROM */ +} + diff --git a/src/input/vcd/libcdio/_cdio_win32.c b/src/input/vcd/libcdio/_cdio_win32.c new file mode 100644 index 000000000..418beb86c --- /dev/null +++ b/src/input/vcd/libcdio/_cdio_win32.c @@ -0,0 +1,1168 @@ +/* + $Id: _cdio_win32.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $ + + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + + 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 file contains Win32-specific code and implements low-level + control of the CD drive. Inspired by vlc's cdrom.h code +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +static const char _rcsid[] = "$Id: _cdio_win32.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $"; + +#include <cdio/cdio.h> +#include <cdio/sector.h> +#include <cdio/util.h> +#include "cdio_assert.h" +#include "cdio_private.h" +#include "scsi_mmc.h" + +/* LBA = msf.frame + 75 * ( msf.second - 2 + 60 * msf.minute ) */ +#define MSF_TO_LBA2(min, sec, frame) ((int)frame + 75 * (sec -2 + 60 * min)) + +#include <string.h> + +#ifdef HAVE_WIN32_CDROM + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> + +#include <windows.h> +#include <winioctl.h> + +#include <sys/stat.h> +#include <sys/types.h> + +/* Win32 DeviceIoControl specifics */ +#ifndef MAXIMUM_NUMBER_TRACKS +# define MAXIMUM_NUMBER_TRACKS 100 +#endif +typedef struct _TRACK_DATA { + UCHAR Reserved; + UCHAR Control : 4; + UCHAR Adr : 4; + UCHAR TrackNumber; + UCHAR Reserved1; + UCHAR Address[4]; +} TRACK_DATA, *PTRACK_DATA; +typedef struct _CDROM_TOC { + UCHAR Length[2]; + UCHAR FirstTrack; + UCHAR LastTrack; + TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS]; +} CDROM_TOC, *PCDROM_TOC; +typedef enum _TRACK_MODE_TYPE { + YellowMode2, + XAForm2, + CDDA +} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE; +typedef struct __RAW_READ_INFO { + LARGE_INTEGER DiskOffset; + ULONG SectorCount; + TRACK_MODE_TYPE TrackMode; +} RAW_READ_INFO, *PRAW_READ_INFO; + +#ifndef IOCTL_CDROM_BASE +# define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM +#endif +#ifndef IOCTL_CDROM_READ_TOC +# define IOCTL_CDROM_READ_TOC CTL_CODE(IOCTL_CDROM_BASE, 0x0000, \ + METHOD_BUFFERED, FILE_READ_ACCESS) +#endif +#ifndef IOCTL_CDROM_RAW_READ +#define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, \ + METHOD_OUT_DIRECT, FILE_READ_ACCESS) +#endif + +/* Win32 aspi specific */ +#define WIN_NT ( GetVersion() < 0x80000000 ) +#define ASPI_HAID 0 +#define ASPI_TARGET 0 +#define DTYPE_CDROM 0x05 + +#define SENSE_LEN 0x0E +#define SC_GET_DEV_TYPE 0x01 +#define SC_EXEC_SCSI_CMD 0x02 +#define SC_GET_DISK_INFO 0x06 +#define SS_COMP 0x01 +#define SS_PENDING 0x00 +#define SS_NO_ADAPTERS 0xE8 +#define SRB_DIR_IN 0x08 +#define SRB_DIR_OUT 0x10 +#define SRB_EVENT_NOTIFY 0x40 + +#define SECTOR_TYPE_MODE2 0x14 +#define READ_CD_USERDATA_MODE2 0x10 + +#define READ_TOC 0x43 +#define READ_TOC_FORMAT_TOC 0x0 + +#pragma pack(1) + +struct SRB_GetDiskInfo +{ + unsigned char SRB_Cmd; + unsigned char SRB_Status; + unsigned char SRB_HaId; + unsigned char SRB_Flags; + unsigned long SRB_Hdr_Rsvd; + unsigned char SRB_Target; + unsigned char SRB_Lun; + unsigned char SRB_DriveFlags; + unsigned char SRB_Int13HDriveInfo; + unsigned char SRB_Heads; + unsigned char SRB_Sectors; + unsigned char SRB_Rsvd1[22]; +}; + +struct SRB_GDEVBlock +{ + unsigned char SRB_Cmd; + unsigned char SRB_Status; + unsigned char SRB_HaId; + unsigned char SRB_Flags; + unsigned long SRB_Hdr_Rsvd; + unsigned char SRB_Target; + unsigned char SRB_Lun; + unsigned char SRB_DeviceType; + unsigned char SRB_Rsvd1; +}; + +struct SRB_ExecSCSICmd +{ + unsigned char SRB_Cmd; + unsigned char SRB_Status; + unsigned char SRB_HaId; + unsigned char SRB_Flags; + unsigned long SRB_Hdr_Rsvd; + unsigned char SRB_Target; + unsigned char SRB_Lun; + unsigned short SRB_Rsvd1; + unsigned long SRB_BufLen; + unsigned char *SRB_BufPointer; + unsigned char SRB_SenseLen; + unsigned char SRB_CDBLen; + unsigned char SRB_HaStat; + unsigned char SRB_TargStat; + unsigned long *SRB_PostProc; + unsigned char SRB_Rsvd2[20]; + unsigned char CDBByte[16]; + unsigned char SenseArea[SENSE_LEN+2]; +}; + +#pragma pack() + +typedef struct { + lsn_t start_lsn; +} track_info_t; + +typedef struct { + /* Things common to all drivers like this. + This must be first. */ + generic_img_private_t gen; + + HANDLE h_device_handle; /* device descriptor */ + long hASPI; + short i_sid; + long (*lpSendCommand)( void* ); + + /* Track information */ + bool toc_init; /* if true, info below is valid. */ + 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 */ + +} _img_private_t; + +/* General ioctl() CD-ROM command function */ +static bool +_cdio_mciSendCommand(int id, UINT msg, DWORD flags, void *arg) +{ + MCIERROR mci_error; + + mci_error = mciSendCommand(id, msg, flags, (DWORD)arg); + if ( mci_error ) { + char error[256]; + + mciGetErrorString(mci_error, error, 256); + cdio_error("mciSendCommand() error: %s", error); + } + return(mci_error == 0); +} + +static const char * +cdio_is_cdrom(const char drive_letter) { + static char psz_win32_drive[7]; + static char root_path_name[8]; + _img_private_t obj; + + /* Initializations */ + obj.h_device_handle = NULL; + obj.i_sid = 0; + obj.hASPI = 0; + obj.lpSendCommand = 0; + + if ( WIN_NT ) { + sprintf( psz_win32_drive, "\\\\.\\%c:", drive_letter ); + sprintf( root_path_name, "\\\\.\\%c:\\", drive_letter ); + + obj.h_device_handle = CreateFile( psz_win32_drive, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, + FILE_FLAG_NO_BUFFERING | + FILE_FLAG_RANDOM_ACCESS, NULL ); + if (obj.h_device_handle != NULL + && (DRIVE_CDROM == GetDriveType(root_path_name))) { + CloseHandle(obj.h_device_handle); + return strdup(psz_win32_drive); + } else { + CloseHandle(obj.h_device_handle); + return NULL; + } + } else { + HMODULE hASPI = NULL; + long (*lpGetSupport)( void ) = NULL; + long (*lpSendCommand)( void* ) = NULL; + DWORD dwSupportInfo; + int j, i_hostadapters; + char c_drive; + + hASPI = LoadLibrary( "wnaspi32.dll" ); + if( hASPI != NULL ) { + (FARPROC) lpGetSupport = GetProcAddress( hASPI, + "GetASPI32SupportInfo" ); + (FARPROC) lpSendCommand = GetProcAddress( hASPI, + "SendASPI32Command" ); + } + + if( hASPI == NULL || lpGetSupport == NULL || lpSendCommand == NULL ) { + cdio_debug("Unable to load ASPI or get ASPI function pointers"); + if( hASPI ) FreeLibrary( hASPI ); + return NULL; + } + + /* ASPI support seems to be there */ + + dwSupportInfo = lpGetSupport(); + + if( HIBYTE( LOWORD ( dwSupportInfo ) ) == SS_NO_ADAPTERS ) { + cdio_debug("no host adapters found (ASPI)"); + FreeLibrary( hASPI ); + return NULL; + } + + if( HIBYTE( LOWORD ( dwSupportInfo ) ) != SS_COMP ) { + cdio_debug("Unable to initalize ASPI layer"); + FreeLibrary( hASPI ); + return NULL; + } + + i_hostadapters = LOBYTE( LOWORD( dwSupportInfo ) ); + if( i_hostadapters == 0 ) { + FreeLibrary( hASPI ); + return NULL; + } + + c_drive = toupper(drive_letter) - 'A'; + + for( j = 0; j < 15; j++ ) { + struct SRB_GetDiskInfo srbDiskInfo; + + srbDiskInfo.SRB_Cmd = SC_GET_DISK_INFO; + srbDiskInfo.SRB_HaId = 0; + 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 = 0; + srbGDEVBlock.SRB_Target = j; + + lpSendCommand( (void*) &srbGDEVBlock ); + + if( ( srbGDEVBlock.SRB_Status == SS_COMP ) && + ( srbGDEVBlock.SRB_DeviceType == DTYPE_CDROM ) ) { + sprintf( psz_win32_drive, "%c:", drive_letter ); + FreeLibrary( hASPI ); + return(psz_win32_drive); + } + } + } + FreeLibrary( hASPI ); + } + return NULL; + +} + +/*! + Initialize CD device. + */ +static bool +_cdio_init_win32 (void *user_data) +{ + _img_private_t *_obj = user_data; + if (_obj->gen.init) { + cdio_error ("init called more than once"); + return false; + } + + _obj->gen.init = true; + _obj->toc_init = false; + + + /* Initializations */ + _obj->h_device_handle = NULL; + _obj->i_sid = 0; + _obj->hASPI = 0; + _obj->lpSendCommand = 0; + + if ( WIN_NT ) { + char psz_win32_drive[7]; + unsigned int len=strlen(_obj->gen.source_name); + + cdio_debug("using winNT/2K/XP ioctl layer"); + + if (cdio_is_device_win32(_obj->gen.source_name)) { + sprintf( psz_win32_drive, "\\\\.\\%c:", _obj->gen.source_name[len-2] ); + + _obj->h_device_handle = CreateFile( psz_win32_drive, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, + FILE_FLAG_NO_BUFFERING | + FILE_FLAG_RANDOM_ACCESS, NULL ); + return (_obj->h_device_handle == NULL) ? false : true; + } else + return false; + } else { + HMODULE hASPI = NULL; + long (*lpGetSupport)( void ) = NULL; + long (*lpSendCommand)( void* ) = NULL; + DWORD dwSupportInfo; + int i, j, i_hostadapters; + char c_drive = _obj->gen.source_name[0]; + + hASPI = LoadLibrary( "wnaspi32.dll" ); + if( hASPI != NULL ) { + (FARPROC) lpGetSupport = GetProcAddress( hASPI, + "GetASPI32SupportInfo" ); + (FARPROC) lpSendCommand = GetProcAddress( hASPI, + "SendASPI32Command" ); + } + + if( hASPI == NULL || lpGetSupport == NULL || lpSendCommand == NULL ) { + cdio_debug("Unable to load ASPI or get ASPI function pointers"); + if( hASPI ) FreeLibrary( hASPI ); + return false; + } + + /* ASPI support seems to be there */ + + dwSupportInfo = lpGetSupport(); + + if( HIBYTE( LOWORD ( dwSupportInfo ) ) == SS_NO_ADAPTERS ) { + cdio_debug("no host adapters found (ASPI)"); + FreeLibrary( hASPI ); + return -1; + } + + if( HIBYTE( LOWORD ( dwSupportInfo ) ) != SS_COMP ) { + cdio_debug("unable to initalize ASPI layer"); + FreeLibrary( hASPI ); + return -1; + } + + i_hostadapters = LOBYTE( LOWORD( dwSupportInfo ) ); + if( i_hostadapters == 0 ) { + FreeLibrary( hASPI ); + return -1; + } + + c_drive = toupper(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 ) ) { + _obj->i_sid = MAKEWORD( i, j ); + _obj->hASPI = (long)hASPI; + _obj->lpSendCommand = lpSendCommand; + cdio_debug("Using ASPI layer"); + + return true; + } else { + FreeLibrary( hASPI ); + cdio_debug( "%c: is not a CD-ROM drive", + _obj->gen.source_name[0] ); + return false; + } + } + } + } + + FreeLibrary( hASPI ); + cdio_debug( "Unable to get HaId and target (ASPI)" ); + + } + + return false; +} + +/*! + Release and free resources associated with cd. + */ +static void +_cdio_win32_free (void *user_data) +{ + _img_private_t *_obj = user_data; + + if (NULL == _obj) return; + free (_obj->gen.source_name); + + if( _obj->h_device_handle ) + CloseHandle( _obj->h_device_handle ); + if( _obj->hASPI ) + FreeLibrary( (HMODULE)_obj->hASPI ); + + free (_obj); +} + +/*! + Reads a single mode2 sector from cd device into data starting from lsn. + Returns 0 if no error. + */ +static int +_cdio_mmc_read_sectors (void *user_data, void *data, lsn_t lsn, + int sector_type, unsigned int nblocks) +{ + _img_private_t *_obj = user_data; + unsigned char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; + + if( _obj->hASPI ) { + HANDLE hEvent; + struct SRB_ExecSCSICmd ssc; + + /* Create the transfer completion event */ + hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); + if( hEvent == NULL ) { + return 1; + } + + /* Data selection */ + + memset( &ssc, 0, sizeof( ssc ) ); + + ssc.SRB_Cmd = SC_EXEC_SCSI_CMD; + ssc.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + ssc.SRB_HaId = LOBYTE( _obj->i_sid ); + ssc.SRB_Target = HIBYTE( _obj->i_sid ); + ssc.SRB_SenseLen = SENSE_LEN; + + ssc.SRB_PostProc = (LPVOID) hEvent; + ssc.SRB_CDBLen = 12; + + /* Operation code */ + ssc.CDBByte[ 0 ] = CDIO_MMC_GPCMD_READ_CD; + + CDIO_MMC_SET_READ_TYPE(ssc.CDBByte, sector_type); + CDIO_MMC_SET_READ_LBA(ssc.CDBByte, lsn); + CDIO_MMC_SET_READ_LENGTH(ssc.CDBByte, nblocks); + CDIO_MMC_SET_MAIN_CHANNEL_SELECTION_BITS(ssc.CDBByte, + CDIO_MMC_MCSB_ALL_HEADERS); + + /* Result buffer */ + ssc.SRB_BufPointer = buf; + ssc.SRB_BufLen = CDIO_CD_FRAMESIZE_RAW; + + /* Initiate transfer */ + ResetEvent( hEvent ); + _obj->lpSendCommand( (void*) &ssc ); + + /* If the command has still not been processed, wait until it's + * finished */ + if( ssc.SRB_Status == SS_PENDING ) { + WaitForSingleObject( hEvent, INFINITE ); + } + CloseHandle( hEvent ); + + /* check that the transfer went as planned */ + if( ssc.SRB_Status != SS_COMP ) { + return 1; + } + + } else { + DWORD dwBytesReturned; + RAW_READ_INFO cdrom_raw; + + /* Initialize CDROM_RAW_READ structure */ + cdrom_raw.DiskOffset.QuadPart = CDIO_CD_FRAMESIZE * lsn; + cdrom_raw.SectorCount = 1; + cdrom_raw.TrackMode = XAForm2; + + if( DeviceIoControl( _obj->h_device_handle, + IOCTL_CDROM_RAW_READ, &cdrom_raw, + sizeof(RAW_READ_INFO), buf, + sizeof(buf), &dwBytesReturned, NULL ) + == 0 ) { + return 1; + } + } + + /* FIXME! remove the 8 (SUBHEADER size) below... */ + memcpy (data, buf, CDIO_CD_FRAMESIZE_RAW); + + return 0; +} + +/*! + Reads an audio device into data starting from lsn. + Returns 0 if no error. + */ +static int +_cdio_read_audio_sectors (void *user_data, void *data, lsn_t lsn, + unsigned int nblocks) +{ + return _cdio_mmc_read_sectors( user_data, data, lsn, + CDIO_MMC_READ_TYPE_CDDA, nblocks ); +} + +/*! + Reads a single mode2 sector from cd device into data starting + from lsn. Returns 0 if no error. + */ +static int +_cdio_read_mode2_sector (void *user_data, void *data, lsn_t lsn, + bool mode2_form2) +{ + char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; + _img_private_t *_obj = user_data; + int ret; + + if (_obj->gen.ioctls_debugged == 75) + cdio_debug ("only displaying every 75th ioctl from now on"); + + if (_obj->gen.ioctls_debugged == 30 * 75) + cdio_debug ("only displaying every 30*75th ioctl from now on"); + + if (_obj->gen.ioctls_debugged < 75 + || (_obj->gen.ioctls_debugged < (30 * 75) + && _obj->gen.ioctls_debugged % 75 == 0) + || _obj->gen.ioctls_debugged % (30 * 75) == 0) + cdio_debug ("reading %lu", (unsigned long int) lsn); + + _obj->gen.ioctls_debugged++; + + ret = _cdio_mmc_read_sectors(user_data, buf, lsn, CDIO_MMC_READ_TYPE_ANY, 1); + + if( ret != 0 ) return ret; + + if (mode2_form2) + memcpy (data, buf, M2RAW_SECTOR_SIZE); + else + memcpy (((char *)data), buf + CDIO_CD_SUBHEADER_SIZE, 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 +_cdio_read_mode2_sectors (void *user_data, void *data, lsn_t lsn, + bool mode2_form2, unsigned int nblocks) +{ + _img_private_t *_obj = user_data; + int i; + int retval; + + for (i = 0; i < nblocks; i++) { + if (mode2_form2) { + if ( (retval = _cdio_read_mode2_sector (_obj, + ((char *)data) + (M2RAW_SECTOR_SIZE * i), + lsn + i, true)) ) + return retval; + } else { + char buf[M2RAW_SECTOR_SIZE] = { 0, }; + if ( (retval = _cdio_read_mode2_sector (_obj, buf, lsn + i, true)) ) + return retval; + + memcpy (((char *)data) + (CDIO_CD_FRAMESIZE * i), + buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE); + } + } + return 0; +} + +/*! + Return the size of the CD in logical block address (LBA) units. + */ +static uint32_t +_cdio_stat_size (void *user_data) +{ + _img_private_t *_obj = user_data; + + return _obj->tocent[_obj->total_tracks].start_lsn; +} + +/*! + Set the key "arg" to "value" in source device. +*/ +static int +_cdio_set_arg (void *user_data, const char key[], const char value[]) +{ + _img_private_t *_obj = user_data; + + if (!strcmp (key, "source")) + { + if (!value) + return -2; + + free (_obj->gen.source_name); + + _obj->gen.source_name = strdup (value); + } + else + return -1; + + return 0; +} + +/*! + Read and cache the CD's Track Table of Contents and track info. + Return true if successful or false if an error. +*/ +static bool +_cdio_read_toc (_img_private_t *_obj) +{ + + if( _obj->hASPI ) { + HANDLE hEvent; + struct SRB_ExecSCSICmd ssc; + unsigned char p_tocheader[ 4 ]; + + /* Create the transfer completion event */ + hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); + if( hEvent == NULL ) { + return false; + } + + memset( &ssc, 0, sizeof( ssc ) ); + + ssc.SRB_Cmd = SC_EXEC_SCSI_CMD; + ssc.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + ssc.SRB_HaId = LOBYTE( _obj->i_sid ); + ssc.SRB_Target = HIBYTE( _obj->i_sid ); + ssc.SRB_SenseLen = SENSE_LEN; + + ssc.SRB_PostProc = (LPVOID) hEvent; + ssc.SRB_CDBLen = 10; + + /* Operation code */ + ssc.CDBByte[ 0 ] = READ_TOC; + + /* Format */ + ssc.CDBByte[ 2 ] = READ_TOC_FORMAT_TOC; + + /* Starting track */ + ssc.CDBByte[ 6 ] = 0; + + /* Allocation length and buffer */ + ssc.SRB_BufLen = sizeof( p_tocheader ); + ssc.SRB_BufPointer = p_tocheader; + ssc.CDBByte[ 7 ] = ( ssc.SRB_BufLen >> 8 ) & 0xff; + ssc.CDBByte[ 8 ] = ( ssc.SRB_BufLen ) & 0xff; + + /* Initiate transfer */ + ResetEvent( hEvent ); + _obj->lpSendCommand( (void*) &ssc ); + + /* If the command has still not been processed, wait until it's + * finished */ + if( ssc.SRB_Status == SS_PENDING ) + WaitForSingleObject( hEvent, INFINITE ); + + /* check that the transfer went as planned */ + if( ssc.SRB_Status != SS_COMP ) { + CloseHandle( hEvent ); + return false; + } + + _obj->first_track_num = p_tocheader[2]; + _obj->total_tracks = p_tocheader[3] - p_tocheader[2] + 1; + + { + int i, i_toclength; + unsigned char *p_fulltoc; + + i_toclength = 4 /* header */ + p_tocheader[0] + + ((unsigned int)p_tocheader[1] << 8); + + p_fulltoc = malloc( i_toclength ); + + if( p_fulltoc == NULL ) { + cdio_error( "out of memory" ); + CloseHandle( hEvent ); + return false; + } + + /* Allocation length and buffer */ + ssc.SRB_BufLen = i_toclength; + ssc.SRB_BufPointer = p_fulltoc; + ssc.CDBByte[ 7 ] = ( ssc.SRB_BufLen >> 8 ) & 0xff; + ssc.CDBByte[ 8 ] = ( ssc.SRB_BufLen ) & 0xff; + + /* Initiate transfer */ + ResetEvent( hEvent ); + _obj->lpSendCommand( (void*) &ssc ); + + /* If the command has still not been processed, wait until it's + * finished */ + if( ssc.SRB_Status == SS_PENDING ) + WaitForSingleObject( hEvent, INFINITE ); + + /* check that the transfer went as planned */ + if( ssc.SRB_Status != SS_COMP ) + _obj->total_tracks = 0; + + for( i = 0 ; i <= _obj->total_tracks ; i++ ) { + int i_index = 8 + 8 * i; + _obj->tocent[ i ].start_lsn = ((int)p_fulltoc[ i_index ] << 24) + + ((int)p_fulltoc[ i_index+1 ] << 16) + + ((int)p_fulltoc[ i_index+2 ] << 8) + + (int)p_fulltoc[ i_index+3 ]; + + cdio_debug( "p_sectors: %i %lu", + i, (unsigned long int) _obj->tocent[i].start_lsn ); + } + + free( p_fulltoc ); + } + + CloseHandle( hEvent ); + return true; + + } else { + DWORD dwBytesReturned; + CDROM_TOC cdrom_toc; + int i; + + if( DeviceIoControl( _obj->h_device_handle, + IOCTL_CDROM_READ_TOC, + NULL, 0, &cdrom_toc, sizeof(CDROM_TOC), + &dwBytesReturned, NULL ) == 0 ) { + cdio_debug( "could not read TOCHDR" ); + return false; + } + + _obj->first_track_num = cdrom_toc.FirstTrack; + _obj->total_tracks = cdrom_toc.LastTrack - cdrom_toc.FirstTrack + 1; + + + for( i = 0 ; i <= _obj->total_tracks ; i++ ) { + _obj->tocent[ i ].start_lsn = MSF_TO_LBA2( + cdrom_toc.TrackData[i].Address[1], + cdrom_toc.TrackData[i].Address[2], + cdrom_toc.TrackData[i].Address[3] ); + cdio_debug("p_sectors: %i, %lu", i, + (unsigned long int) (_obj->tocent[i].start_lsn)); + } + } + return true; +} + +/*! + Eject media. Return 1 if successful, 0 otherwise. + */ +static int +_cdio_eject_media (void *user_data) { + + _img_private_t *_obj = user_data; + + + MCI_OPEN_PARMS op; + MCI_STATUS_PARMS st; + DWORD i_flags; + char psz_drive[4]; + int ret; + + memset( &op, 0, sizeof(MCI_OPEN_PARMS) ); + op.lpstrDeviceType = (LPCSTR)MCI_DEVTYPE_CD_AUDIO; + strcpy( psz_drive, "X:" ); + psz_drive[0] = _obj->gen.source_name[0]; + op.lpstrElementName = psz_drive; + + /* Set the flags for the device type */ + i_flags = MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | + MCI_OPEN_ELEMENT | MCI_OPEN_SHAREABLE; + + if( !mciSendCommand( 0, MCI_OPEN, i_flags, (unsigned long)&op ) ) { + st.dwItem = MCI_STATUS_READY; + /* Eject disc */ + ret = mciSendCommand( op.wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, 0 ) != 0; + /* Release access to the device */ + mciSendCommand( op.wDeviceID, MCI_CLOSE, MCI_WAIT, 0 ); + } else + ret = 0; + + return ret; +} + +/*! + Return the value associated with the key "arg". +*/ +static const char * +_cdio_get_arg (void *user_data, const char key[]) +{ + _img_private_t *_obj = user_data; + + if (!strcmp (key, "source")) { + return _obj->gen.source_name; + } else if (!strcmp (key, "access-mode")) { + if ( WIN_NT ) + return "winNT/2K/XP ioctl"; + else if (_obj->hASPI) + return "ASPI"; + else + return "undefined WIN32"; + } + return NULL; +} + +/*! + Return the number of of the first track. + CDIO_INVALID_TRACK is returned on error. +*/ +static track_t +_cdio_get_first_track_num(void *user_data) +{ + _img_private_t *_obj = user_data; + + if (!_obj->toc_init) _cdio_read_toc (_obj) ; + + return _obj->first_track_num; +} + +/*! + Return the number of tracks in the current medium. + CDIO_INVALID_TRACK is returned on error. +*/ +static track_t +_cdio_get_num_tracks(void *user_data) +{ + _img_private_t *_obj = user_data; + + if (!_obj->toc_init) _cdio_read_toc (_obj) ; + + return _obj->total_tracks; +} + +/*! + Get format of track. +*/ +static track_format_t +_cdio_get_track_format(void *user_data, track_t track_num) +{ + _img_private_t *_obj = user_data; + + MCI_OPEN_PARMS op; + MCI_STATUS_PARMS st; + DWORD i_flags; + int ret; + + memset( &op, 0, sizeof(MCI_OPEN_PARMS) ); + op.lpstrDeviceType = (LPCSTR)MCI_DEVTYPE_CD_AUDIO; + op.lpstrElementName = _obj->gen.source_name; + + /* Set the flags for the device type */ + i_flags = MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | + MCI_OPEN_ELEMENT | MCI_OPEN_SHAREABLE; + + if( !mciSendCommand( 0, MCI_OPEN, i_flags, (unsigned long)&op ) ) { + st.dwItem = MCI_CDA_STATUS_TYPE_TRACK; + st.dwTrack = track_num; + i_flags = MCI_TRACK | MCI_STATUS_ITEM ; + ret = mciSendCommand( op.wDeviceID, MCI_STATUS, i_flags, + (unsigned long) &st ); + + /* Release access to the device */ + mciSendCommand( op.wDeviceID, MCI_CLOSE, MCI_WAIT, 0 ); + + switch(st.dwReturn) { + case MCI_CDA_TRACK_AUDIO: + return TRACK_FORMAT_AUDIO; + case MCI_CDA_TRACK_OTHER: + return TRACK_FORMAT_DATA; + default: + return TRACK_FORMAT_XA; + } + } + + return TRACK_FORMAT_ERROR; + +} + +/*! + 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 +_cdio_get_track_green(void *user_data, track_t track_num) +{ + _img_private_t *_obj = user_data; + + if (!_obj->toc_init) _cdio_read_toc (_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 false; + + /* FIXME! */ + return true; +} + +/*! + Return the starting MSF (minutes/secs/frames) for 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 bool +_cdio_get_track_msf(void *user_data, track_t track_num, msf_t *msf) +{ + _img_private_t *_obj = user_data; + + if (NULL == msf) return false; + + if (!_obj->toc_init) _cdio_read_toc (_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 false; + } else { + cdio_lsn_to_msf(_obj->tocent[track_num-1].start_lsn, msf); + return true; + } +} + +#endif /* HAVE_WIN32_CDROM */ + +/*! + Return an array of strings giving possible CD devices. + */ +char ** +cdio_get_devices_win32 (void) +{ +#ifndef HAVE_WIN32_CDROM + return NULL; +#else + char **drives = NULL; + unsigned int num_drives=0; + char drive_letter; + + /* Scan the system for CD-ROM drives. + */ + +#if FINISHED + /* Now check the currently mounted CD drives */ + if (NULL != (ret_drive = cdio_check_mounts("/etc/mtab"))) { + cdio_add_device_list(&drives, drive, &num_drives); + } + + /* Finally check possible mountable drives in /etc/fstab */ + if (NULL != (ret_drive = cdio_check_mounts("/etc/fstab"))) { + cdio_add_device_list(&drives, drive, &num_drives); + } +#endif + + /* Scan the system for CD-ROM drives. + Not always 100% reliable, so use the USE_MNTENT code above first. + */ + for (drive_letter='A'; drive_letter <= 'Z'; drive_letter++) { + const char *drive_str=cdio_is_cdrom(drive_letter); + if (drive_str != NULL) { + cdio_add_device_list(&drives, drive_str, &num_drives); + } + } + cdio_add_device_list(&drives, NULL, &num_drives); + return drives; +#endif /*HAVE_WIN32_CDROM*/ +} + +/*! + Return a string containing the default CD device if none is specified. + if CdIo is NULL (we haven't initialized a specific device driver), + then find a suitable one and return the default device for that. + + NULL is returned if we couldn't get a default device. +*/ +char * +cdio_get_default_device_win32(void) +{ + +#ifdef HAVE_WIN32_CDROM + char drive_letter; + + for (drive_letter='A'; drive_letter <= 'Z'; drive_letter++) { + const char *drive_str=cdio_is_cdrom(drive_letter); + if (drive_str != NULL) { + return strdup(drive_str); + } + } +#endif + return NULL; +} + +/*! + Return true if source_name could be a device containing a CD-ROM. +*/ +bool +cdio_is_device_win32(const char *source_name) +{ + unsigned int len; + len = strlen(source_name); + + if (NULL == source_name) return false; + +#ifdef HAVE_WIN32_CDROM + if ( WIN_NT ) + /* Really should test to see if of form: \\.\x: */ + return ((len == 6) && isalpha(source_name[len-2]) + && (source_name[len-1] == ':')); + else + /* See if is of form: x: */ + return ((len == 2) && isalpha(source_name[0]) + && (source_name[len-1] == ':')); +#else + return false; +#endif +} + +/*! + 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_win32 (const char *source_name) +{ + +#ifdef HAVE_WIN32_CDROM + CdIo *ret; + _img_private_t *_data; + + cdio_funcs _funcs = { + .eject_media = _cdio_eject_media, + .free = _cdio_win32_free, + .get_arg = _cdio_get_arg, + .get_default_device = cdio_get_default_device_win32, + .get_devices = cdio_get_devices_win32, + .get_first_track_num= _cdio_get_first_track_num, + .get_mcn = NULL, + .get_num_tracks = _cdio_get_num_tracks, + .get_track_format = _cdio_get_track_format, + .get_track_green = _cdio_get_track_green, + .get_track_lba = NULL, /* This could be implemented if need be. */ + .get_track_msf = _cdio_get_track_msf, + .lseek = NULL, + .read = NULL, + .read_audio_sectors = _cdio_read_audio_sectors, + .read_mode2_sector = _cdio_read_mode2_sector, + .read_mode2_sectors = _cdio_read_mode2_sectors, + .set_arg = _cdio_set_arg, + .stat_size = _cdio_stat_size + }; + + _data = _cdio_malloc (sizeof (_img_private_t)); + _data->gen.init = false; + _data->gen.fd = -1; + + _cdio_set_arg(_data, "source", (NULL == source_name) + ? cdio_get_default_device_win32(): source_name); + + ret = cdio_new (_data, &_funcs); + if (ret == NULL) return NULL; + + if (_cdio_init_win32(_data)) + return ret; + else { + _cdio_win32_free (_data); + return NULL; + } + +#else + return NULL; +#endif /* HAVE_WIN32_CDROM */ + +} + +bool +cdio_have_win32 (void) +{ +#ifdef HAVE_WIN32_CDROM + return true; +#else + return false; +#endif /* HAVE_WIN32_CDROM */ +} diff --git a/src/input/vcd/libcdio/bytesex.h b/src/input/vcd/libcdio/bytesex.h new file mode 100644 index 000000000..431de9799 --- /dev/null +++ b/src/input/vcd/libcdio/bytesex.h @@ -0,0 +1,196 @@ +/* + $Id: bytesex.h,v 1.1 2003/10/13 11:47:11 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + + 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 +*/ + +#ifndef __CDIO_BYTESEX_H__ +#define __CDIO_BYTESEX_H__ + +#include <cdio/logging.h> +#include <cdio/types.h> +#include "bytesex_asm.h" + +/* generic byteswap routines */ + +#define UINT16_SWAP_LE_BE_C(val) ((uint16_t) ( \ + (((uint16_t) (val) & (uint16_t) 0x00ffU) << 8) | \ + (((uint16_t) (val) & (uint16_t) 0xff00U) >> 8))) + +#define UINT32_SWAP_LE_BE_C(val) ((uint32_t) ( \ + (((uint32_t) (val) & (uint32_t) 0x000000ffU) << 24) | \ + (((uint32_t) (val) & (uint32_t) 0x0000ff00U) << 8) | \ + (((uint32_t) (val) & (uint32_t) 0x00ff0000U) >> 8) | \ + (((uint32_t) (val) & (uint32_t) 0xff000000U) >> 24))) + +#define UINT64_SWAP_LE_BE_C(val) ((uint64_t) ( \ + (((uint64_t) (val) & (uint64_t) UINT64_C(0x00000000000000ff)) << 56) | \ + (((uint64_t) (val) & (uint64_t) UINT64_C(0x000000000000ff00)) << 40) | \ + (((uint64_t) (val) & (uint64_t) UINT64_C(0x0000000000ff0000)) << 24) | \ + (((uint64_t) (val) & (uint64_t) UINT64_C(0x00000000ff000000)) << 8) | \ + (((uint64_t) (val) & (uint64_t) UINT64_C(0x000000ff00000000)) >> 8) | \ + (((uint64_t) (val) & (uint64_t) UINT64_C(0x0000ff0000000000)) >> 24) | \ + (((uint64_t) (val) & (uint64_t) UINT64_C(0x00ff000000000000)) >> 40) | \ + (((uint64_t) (val) & (uint64_t) UINT64_C(0xff00000000000000)) >> 56))) + +#ifndef UINT16_SWAP_LE_BE +# define UINT16_SWAP_LE_BE UINT16_SWAP_LE_BE_C +#endif + +#ifndef UINT32_SWAP_LE_BE +# define UINT32_SWAP_LE_BE UINT32_SWAP_LE_BE_C +#endif + +#ifndef UINT64_SWAP_LE_BE +# define UINT64_SWAP_LE_BE UINT64_SWAP_LE_BE_C +#endif + +inline static +uint16_t uint16_swap_le_be (const uint16_t val) +{ + return UINT16_SWAP_LE_BE (val); +} + +inline static +uint32_t uint32_swap_le_be (const uint32_t val) +{ + return UINT32_SWAP_LE_BE (val); +} + +inline static +uint64_t uint64_swap_le_be (const uint64_t val) +{ + return UINT64_SWAP_LE_BE (val); +} + +# define UINT8_TO_BE(val) ((uint8_t) (val)) +# define UINT8_TO_LE(val) ((uint8_t) (val)) +#ifdef WORDS_BIGENDIAN +# define UINT16_TO_BE(val) ((uint16_t) (val)) +# define UINT16_TO_LE(val) ((uint16_t) UINT16_SWAP_LE_BE(val)) + +# define UINT32_TO_BE(val) ((uint32_t) (val)) +# define UINT32_TO_LE(val) ((uint32_t) UINT32_SWAP_LE_BE(val)) + +# define UINT64_TO_BE(val) ((uint64_t) (val)) +# define UINT64_TO_LE(val) ((uint64_t) UINT64_SWAP_LE_BE(val)) +#else +# define UINT16_TO_BE(val) ((uint16_t) UINT16_SWAP_LE_BE(val)) +# define UINT16_TO_LE(val) ((uint16_t) (val)) + +# define UINT32_TO_BE(val) ((uint32_t) UINT32_SWAP_LE_BE(val)) +# define UINT32_TO_LE(val) ((uint32_t) (val)) + +# define UINT64_TO_BE(val) ((uint64_t) UINT64_SWAP_LE_BE(val)) +# define UINT64_TO_LE(val) ((uint64_t) (val)) +#endif + +/* symmetric conversions */ +#define UINT8_FROM_BE(val) (UINT8_TO_BE (val)) +#define UINT8_FROM_LE(val) (UINT8_TO_LE (val)) +#define UINT16_FROM_BE(val) (UINT16_TO_BE (val)) +#define UINT16_FROM_LE(val) (UINT16_TO_LE (val)) +#define UINT32_FROM_BE(val) (UINT32_TO_BE (val)) +#define UINT32_FROM_LE(val) (UINT32_TO_LE (val)) +#define UINT64_FROM_BE(val) (UINT64_TO_BE (val)) +#define UINT64_FROM_LE(val) (UINT64_TO_LE (val)) + +/* converter function template */ +#define CVT_TO_FUNC(bits) \ + static inline uint ## bits ## _t \ + uint ## bits ## _to_be (uint ## bits ## _t val) \ + { return UINT ## bits ## _TO_BE (val); } \ + static inline uint ## bits ## _t \ + uint ## bits ## _to_le (uint ## bits ## _t val) \ + { return UINT ## bits ## _TO_LE (val); } \ + +CVT_TO_FUNC(8) +CVT_TO_FUNC(16) +CVT_TO_FUNC(32) +CVT_TO_FUNC(64) + +#undef CVT_TO_FUNC + +#define uint8_from_be(val) (uint8_to_be (val)) +#define uint8_from_le(val) (uint8_to_le (val)) +#define uint16_from_be(val) (uint16_to_be (val)) +#define uint16_from_le(val) (uint16_to_le (val)) +#define uint32_from_be(val) (uint32_to_be (val)) +#define uint32_from_le(val) (uint32_to_le (val)) +#define uint64_from_be(val) (uint64_to_be (val)) +#define uint64_from_le(val) (uint64_to_le (val)) + +/* ISO9660 related stuff */ + +#define to_711(i) uint8_to_le(i) +#define from_711(i) uint8_from_le(i) + +#define to_721(i) uint16_to_le(i) +#define from_721(i) uint16_from_le(i) + +#define to_721(i) uint16_to_le(i) +#define from_721(i) uint16_from_le(i) + +#define to_722(i) uint16_to_be(i) +#define from_722(i) uint16_from_be(i) + +static inline uint32_t +to_723(uint16_t i) +{ + return uint32_swap_le_be(i) | i; +} + +static inline uint16_t +from_723 (uint32_t p) +{ + if (uint32_swap_le_be (p) != p) + cdio_warn ("from_723: broken byte order"); + + return (0xFFFF & p); +} + +#define to_731(i) uint32_to_le(i) +#define from_731(i) uint32_from_le(i) + +#define to_732(i) uint32_to_be(i) +#define from_732(i) uint32_from_be(i) + +static inline uint64_t +to_733(uint32_t i) +{ + return uint64_swap_le_be(i) | i; +} + +static inline uint32_t +from_733 (uint64_t p) +{ + if (uint64_swap_le_be (p) != p) + cdio_warn ("from_733: broken byte order"); + + return (UINT32_C(0xFFFFFFFF) & p); +} + +#endif /* __CDIO_BYTESEX_H__ */ + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/bytesex_asm.h b/src/input/vcd/libcdio/bytesex_asm.h new file mode 100644 index 000000000..34ef5e605 --- /dev/null +++ b/src/input/vcd/libcdio/bytesex_asm.h @@ -0,0 +1,123 @@ +/* + $Id: bytesex_asm.h,v 1.1 2003/10/13 11:47:11 f1rmb Exp $ + + Copyright (C) 2001 Sven Ottemann <ac-logic@freenet.de> + 2001 Herbert Valerio Riedel <hvr@gnu.org> + + 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 +*/ + +#ifndef __CDIO_BYTESEX_ASM_H__ +#define __CDIO_BYTESEX_ASM_H__ +#if !defined(DISABLE_ASM_OPTIMIZE) + +#include <cdio/types.h> + +#if defined(__powerpc__) && defined(__GNUC__) + +inline static +uint32_t uint32_swap_le_be_asm(const uint32_t a) +{ + uint32_t b; + + __asm__ ("lwbrx %0,0,%1" + :"=r"(b) + :"r"(&a), "m"(a)); + + return b; +} + +inline static +uint16_t uint16_swap_le_be_asm(const uint16_t a) +{ + uint32_t b; + + __asm__ ("lhbrx %0,0,%1" + :"=r"(b) + :"r"(&a), "m"(a)); + + return b; +} + +#define UINT16_SWAP_LE_BE uint16_swap_le_be_asm +#define UINT32_SWAP_LE_BE uint32_swap_le_be_asm + +#elif defined(__mc68000__) && defined(__STORMGCC__) + +inline static +uint32_t uint32_swap_le_be_asm(uint32_t a __asm__("d0")) +{ + /* __asm__("rolw #8,%0; swap %0; rolw #8,%0" : "=d" (val) : "0" (val)); */ + + __asm__("move.l %1,d0;rol.w #8,d0;swap d0;rol.w #8,d0;move.l d0,%0" + :"=r"(a) + :"r"(a)); + + return(a); +} + +inline static +uint16_t uint16_swap_le_be_asm(uint16_t a __asm__("d0")) +{ + __asm__("move.l %1,d0;rol.w #8,d0;move.l d0,%0" + :"=r"(a) + :"r"(a)); + + return(a); +} + +#define UINT16_SWAP_LE_BE uint16_swap_le_be_asm +#define UINT32_SWAP_LE_BE uint32_swap_le_be_asm + +#elif 0 && defined(__i386__) && defined(__GNUC__) + +inline static +uint32_t uint32_swap_le_be_asm(uint32_t a) +{ + __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */ + "rorl $16,%0\n\t" /* swap words */ + "xchgb %b0,%h0" /* swap higher bytes */ + :"=q" (a) + : "0" (a)); + + return(a); +} + +inline static +uint16_t uint16_swap_le_be_asm(uint16_t a) +{ + __asm__("xchgb %b0,%h0" /* swap bytes */ + : "=q" (a) + : "0" (a)); + + return(a); +} + +#define UINT16_SWAP_LE_BE uint16_swap_le_be_asm +#define UINT32_SWAP_LE_BE uint32_swap_le_be_asm + +#endif + +#endif /* !defined(DISABLE_ASM_OPTIMIZE) */ +#endif /* __CDIO_BYTESEX_ASM_H__ */ + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/cd_types.c b/src/input/vcd/libcdio/cd_types.c new file mode 100644 index 000000000..0dd6c8410 --- /dev/null +++ b/src/input/vcd/libcdio/cd_types.c @@ -0,0 +1,294 @@ +/* + $Id: cd_types.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $ + + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + + 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 tries to determine what kind of CD-image or filesystems on a + track we've got. +*/ +#include "config.h" + +#ifdef HAVE_STDIO_H +#include <stdio.h> +#endif + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +#include <cdio/cdio.h> +#include <cdio/iso9660.h> +#include <cdio/logging.h> +#include <cdio/util.h> +#include <cdio/cd_types.h> + +/* +Subject: -65- How can I read an IRIX (EFS) CD-ROM on a machine which + doesn't use EFS? +Date: 18 Jun 1995 00:00:01 EST + + You want 'efslook', at + ftp://viz.tamu.edu/pub/sgi/software/efslook.tar.gz. + +and +! Robert E. Seastrom <rs@access4.digex.net>'s software (with source +! code) for using an SGI CD-ROM on a Macintosh is at +! ftp://bifrost.seastrom.com/pub/mac/CDROM-Jumpstart.sit151.hqx. + +*/ + +static char buffer[6][CDIO_CD_FRAMESIZE_RAW]; /* for CD-Data */ + +/* Some interesting sector numbers stored in the above buffer. */ +#define UFS_SUPERBLOCK_SECTOR 4 /* buffer[2] */ +#define BOOT_SECTOR 17 /* buffer[3] */ +#define VCD_INFO_SECTOR 150 /* buffer[4] */ + + +typedef struct signature +{ + unsigned int buf_num; + unsigned int offset; + const char *sig_str; + const char *description; +} signature_t; + +static signature_t sigs[] = + { +/*buffer[x] off look for description */ + {0, 1, ISO_STANDARD_ID, "ISO 9660"}, + {0, 1, "CD-I", "CD-I"}, + {0, 8, "CDTV", "CDTV"}, + {0, 8, "CD-RTOS", "CD-RTOS"}, + {0, 9, "CDROM", "HIGH SIERRA"}, + {0, 16, "CD-BRIDGE", "BRIDGE"}, + {0, ISO_XA_MARKER_OFFSET, ISO_XA_MARKER_STRING, "XA"}, + {1, 64, "PPPPHHHHOOOOTTTTOOOO____CCCCDDDD", "PHOTO CD"}, + {1, 0x438, "\x53\xef", "EXT2 FS"}, + {2, 1372, "\x54\x19\x01\x0", "UFS"}, + {3, 7, "EL TORITO", "BOOTABLE"}, + {4, 0, "VIDEO_CD", "VIDEO CD"}, + {4, 0, "SUPERVCD", "SVCD or Chaoji VCD"}, + { 0 } + }; + + +/* The below index into the above sigs array. Make sure things match. */ +#define INDEX_ISOFS 0 +#define INDEX_CD_I 1 +#define INDEX_CDTV 2 +#define INDEX_CD_RTOS 3 +#define INDEX_HS 4 +#define INDEX_BRIDGE 5 +#define INDEX_XA 6 +#define INDEX_PHOTO_CD 7 +#define INDEX_EXT2 8 +#define INDEX_UFS 9 +#define INDEX_BOOTABLE 10 +#define INDEX_VIDEO_CD 11 /* Video CD */ +#define INDEX_SVCD 12 /* CVD *or* SVCD */ + + +/* + Read a particular block into the global array to be used for further + analysis later. +*/ +static int +_cdio_read_block(const CdIo *cdio, int superblock, uint32_t offset, + uint8_t bufnum, track_t track_num) +{ + unsigned int track_sec_count = cdio_get_track_sec_count(cdio, track_num); + memset(buffer[bufnum], 0, CDIO_CD_FRAMESIZE); + + if ( track_sec_count < superblock) { + cdio_debug("reading block %u skipped track %d has only %u sectors\n", + superblock, track_num, track_sec_count); + return -1; + } + + cdio_debug("about to read sector %lu\n", + (long unsigned int) offset+superblock); + + if (cdio_get_track_green(cdio, track_num)) { + if (0 > cdio_read_mode2_sector(cdio, buffer[bufnum], + offset+superblock, false)) + return -1; + } else { + if (0 > cdio_read_mode1_sector(cdio, buffer[bufnum], + offset+superblock, false)) + return -1; + } + + return 0; +} + +/* + Return true if the previously read-in buffer contains a "signature" that + matches index "num". + */ +static bool +_cdio_is_it(int num) +{ + signature_t *sigp=&sigs[num]; + int len=strlen(sigp->sig_str); + + /* TODO: check that num < largest sig. */ + return 0 == memcmp(&buffer[sigp->buf_num][sigp->offset], sigp->sig_str, len); +} + +static int +_cdio_is_hfs(void) +{ + return (0 == memcmp(&buffer[1][512],"PM",2)) || + (0 == memcmp(&buffer[1][512],"TS",2)) || + (0 == memcmp(&buffer[1][1024], "BD",2)); +} + +static int +_cdio_is_3do(void) +{ + return (0 == memcmp(&buffer[1][0],"\x01\x5a\x5a\x5a\x5a\x5a\x01", 7)) && + (0 == memcmp(&buffer[1][40], "CD-ROM", 6)); +} + +static int +_cdio_is_joliet(void) +{ + return 2 == buffer[3][0] && buffer[3][88] == 0x25 && buffer[3][89] == 0x2f; +} + +/* ISO 9660 volume space in M2F1_SECTOR_SIZE byte units */ +static int +_cdio_get_iso9660_fs_sec_count(void) +{ + return ((buffer[0][80] & 0xff) | + ((buffer[0][81] & 0xff) << 8) | + ((buffer[0][82] & 0xff) << 16) | + ((buffer[0][83] & 0xff) << 24)); +} + +static int +_cdio_get_joliet_level( void ) +{ + switch (buffer[3][90]) { + case 0x40: return 1; + case 0x43: return 2; + case 0x45: return 3; + } + return 0; +} + +/* + Try to determine what kind of CD-image and/or filesystem we + have at track track_num. Return information about the CD image + is returned in cdio_analysis and the return value. +*/ +cdio_fs_anal_t +cdio_guess_cd_type(const CdIo *cdio, int start_session, track_t track_num, + /*out*/ cdio_analysis_t *cdio_analysis) +{ + int ret = 0; + bool sector0_read_ok; + + if (TRACK_FORMAT_AUDIO == cdio_get_track_format(cdio, track_num)) + return CDIO_FS_AUDIO; + + if ( _cdio_read_block(cdio, ISO_PVD_SECTOR, start_session, + 0, track_num) < 0 ) + return CDIO_FS_UNKNOWN; + + /* We have something that smells of a filesystem. */ + if (_cdio_is_it(INDEX_CD_I) && _cdio_is_it(INDEX_CD_RTOS) + && !_cdio_is_it(INDEX_BRIDGE) && !_cdio_is_it(INDEX_XA)) { + return CDIO_FS_INTERACTIVE; + } else { + /* read sector 0 ONLY, when NO greenbook CD-I !!!! */ + + sector0_read_ok = + _cdio_read_block(cdio, 0, start_session, 1, track_num) == 0; + + if (_cdio_is_it(INDEX_HS)) + ret |= CDIO_FS_HIGH_SIERRA; + else if (_cdio_is_it(INDEX_ISOFS)) { + if (_cdio_is_it(INDEX_CD_RTOS) && _cdio_is_it(INDEX_BRIDGE)) + ret = CDIO_FS_ISO_9660_INTERACTIVE; + else if (_cdio_is_hfs()) + ret = CDIO_FS_ISO_HFS; + else + ret = CDIO_FS_ISO_9660; + cdio_analysis->isofs_size = _cdio_get_iso9660_fs_sec_count(); + sprintf(cdio_analysis->iso_label, buffer[0]+40); + +#if 0 + if (_cdio_is_rockridge()) + ret |= CDIO_FS_ANAL_ROCKRIDGE; +#endif + + if (_cdio_read_block(cdio, BOOT_SECTOR, start_session, 3, track_num) < 0) + return ret; + + if (_cdio_is_joliet()) { + cdio_analysis->joliet_level = _cdio_get_joliet_level(); + ret |= CDIO_FS_ANAL_JOLIET; + } + if (_cdio_is_it(INDEX_BOOTABLE)) + ret |= CDIO_FS_ANAL_BOOTABLE; + + if ( _cdio_is_it(INDEX_XA) && _cdio_is_it(INDEX_ISOFS) + && !(sector0_read_ok && _cdio_is_it(INDEX_PHOTO_CD)) ) { + + if ( _cdio_read_block(cdio, VCD_INFO_SECTOR, start_session, 4, + track_num) < 0 ) + return ret; + + if (_cdio_is_it(INDEX_BRIDGE) && _cdio_is_it(INDEX_CD_RTOS)) { + if (_cdio_is_it(INDEX_VIDEO_CD)) ret |= CDIO_FS_ANAL_VIDEOCD; + else if (_cdio_is_it(INDEX_SVCD)) ret |= CDIO_FS_ANAL_SVCD; + } else if (_cdio_is_it(INDEX_SVCD)) ret |= CDIO_FS_ANAL_CVD; + + } + } + else if (_cdio_is_hfs()) ret |= CDIO_FS_HFS; + else if (sector0_read_ok && _cdio_is_it(INDEX_EXT2)) ret |= CDIO_FS_EXT2; + else if (_cdio_is_3do()) ret |= CDIO_FS_3DO; + else { + if ( _cdio_read_block(cdio, UFS_SUPERBLOCK_SECTOR, start_session, 2, + track_num) < 0 ) + return ret; + + if (sector0_read_ok && _cdio_is_it(INDEX_UFS)) + ret |= CDIO_FS_UFS; + else + ret |= CDIO_FS_UNKNOWN; + } + } + + /* other checks */ + if (_cdio_is_it(INDEX_XA)) ret |= CDIO_FS_ANAL_XA; + if (_cdio_is_it(INDEX_PHOTO_CD)) ret |= CDIO_FS_ANAL_PHOTO_CD; + if (_cdio_is_it(INDEX_CDTV)) ret |= CDIO_FS_ANAL_CDTV; + return ret; +} diff --git a/src/input/vcd/libcdio/cdio.c b/src/input/vcd/libcdio/cdio.c new file mode 100644 index 000000000..8d6c39bed --- /dev/null +++ b/src/input/vcd/libcdio/cdio.c @@ -0,0 +1,887 @@ +/* + $Id: cdio.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $ + + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org> + + 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 +*/ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> + +#include "cdio_assert.h" +#include <cdio/cdio.h> +#include <cdio/cd_types.h> +#include <cdio/util.h> +#include <cdio/logging.h> +#include "cdio_private.h" + +static const char _rcsid[] = "$Id: cdio.c,v 1.1 2003/10/13 11:47:11 f1rmb Exp $"; + + +const char *track_format2str[6] = + { + "audio", "CD-i", "XA", "data", "PSX", "error" + }; + +/* The below array gives of the drivers that are currently available for + on a particular host. */ + +CdIo_driver_t CdIo_driver[CDIO_MAX_DRIVER] = { {0} }; + +/* The last valid entry of Cdio_driver. + -1 or (CDIO_DRIVER_UNINIT) means uninitialzed. + -2 means some sort of error. +*/ + +#define CDIO_DRIVER_UNINIT -1 +int CdIo_last_driver = CDIO_DRIVER_UNINIT; + +static bool +cdio_have_false(void) +{ + return false; +} + + +/* The below array gives all drivers that can possibly appear. + on a particular host. */ + +CdIo_driver_t CdIo_all_drivers[CDIO_MAX_DRIVER+1] = { + {DRIVER_UNKNOWN, + 0, + "Unknown", + "No driver", + &cdio_have_false, + NULL, + NULL, + NULL, + NULL + }, + + {DRIVER_BSDI, + CDIO_SRC_IS_DEVICE_MASK|CDIO_SRC_IS_NATIVE_MASK|CDIO_SRC_IS_SCSI_MASK, + "BSDI", + "BSDI ATAPI and SCSI driver", + &cdio_have_bsdi, + &cdio_open_bsdi, + &cdio_get_default_device_bsdi, + &cdio_is_device_generic, + &cdio_get_devices_bsdi + }, + + {DRIVER_FREEBSD, + CDIO_SRC_IS_DEVICE_MASK|CDIO_SRC_IS_NATIVE_MASK|CDIO_SRC_IS_SCSI_MASK, + "FreeBSD", + "FreeBSD driver", + &cdio_have_freebsd, + &cdio_open_freebsd, + &cdio_get_default_device_freebsd, + &cdio_is_device_generic, + NULL + }, + + {DRIVER_LINUX, + CDIO_SRC_IS_DEVICE_MASK|CDIO_SRC_IS_NATIVE_MASK, + "GNU/Linux", + "GNU/Linux ioctl and MMC driver", + &cdio_have_linux, + &cdio_open_linux, + &cdio_get_default_device_linux, + &cdio_is_device_generic, + &cdio_get_devices_linux + }, + + {DRIVER_SOLARIS, + CDIO_SRC_IS_DEVICE_MASK|CDIO_SRC_IS_NATIVE_MASK|CDIO_SRC_IS_SCSI_MASK, + "Solaris", + "Solaris ATAPI and SCSI driver", + &cdio_have_solaris, + &cdio_open_solaris, + &cdio_get_default_device_solaris, + &cdio_is_device_generic, + &cdio_get_devices_solaris + }, + + {DRIVER_OSX, + CDIO_SRC_IS_DEVICE_MASK|CDIO_SRC_IS_NATIVE_MASK|CDIO_SRC_IS_SCSI_MASK, + "OS X", + "Apple Darwin OS X driver", + &cdio_have_osx, + &cdio_open_osx, + &cdio_get_default_device_osx, + &cdio_is_device_generic, + &cdio_get_devices_osx + }, + + {DRIVER_WIN32, + CDIO_SRC_IS_DEVICE_MASK|CDIO_SRC_IS_NATIVE_MASK|CDIO_SRC_IS_SCSI_MASK, + "WIN32", + "Windows 32-bit ASPI and winNT/2K/XP ioctl driver", + &cdio_have_win32, + &cdio_open_win32, + &cdio_get_default_device_win32, + &cdio_is_device_win32, + &cdio_get_devices_win32 + }, + + {DRIVER_BINCUE, + CDIO_SRC_IS_DISK_IMAGE_MASK, + "BIN/CUE", + "bin/cuesheet disk image driver", + &cdio_have_bincue, + &cdio_open_bincue, + &cdio_get_default_device_bincue, + NULL, + &cdio_get_devices_bincue + }, + + {DRIVER_NRG, + CDIO_SRC_IS_DISK_IMAGE_MASK, + "NRG", + "Nero NRG disk image driver", + &cdio_have_nrg, + &cdio_open_nrg, + &cdio_get_default_device_nrg, + NULL, + &cdio_get_devices_nrg + } + +}; + +static CdIo * +scan_for_driver(driver_id_t start, driver_id_t end, const char *source_name) +{ + driver_id_t driver_id; + + for (driver_id=start; driver_id<=end; driver_id++) { + if ((*CdIo_all_drivers[driver_id].have_driver)()) { + CdIo *ret=(*CdIo_all_drivers[driver_id].driver_open)(source_name); + if (ret != NULL) { + ret->driver_id = driver_id; + return ret; + } + } + } + return NULL; +} + +const char * +cdio_driver_describe(driver_id_t driver_id) +{ + return CdIo_all_drivers[driver_id].describe; +} + +/*! + Eject media in CD drive if there is a routine to do so. + Return 0 if success and 1 for failure, and 2 if no routine. + If the CD is ejected *obj is freed and obj set to NULL. + */ +int +cdio_eject_media (CdIo **obj) +{ + + if ((obj == NULL) || (*obj == NULL)) return 1; + + if ((*obj)->op.eject_media) { + int ret = (*obj)->op.eject_media ((*obj)->env); + if (0 == ret) { + cdio_destroy(*obj); + *obj = NULL; + } + return ret; + } else { + cdio_destroy(*obj); + *obj = NULL; + return 2; + } +} + +/*! + Free device list returned by cdio_get_devices or + cdio_get_devices_with_cap. +*/ +void cdio_free_device_list (char * device_list[]) +{ + if (NULL == device_list) return; + for ( ; *device_list != NULL ; device_list++ ) + free(*device_list); +} + + +/*! + Return the value associatied with key. NULL is returned if obj is NULL + or "key" does not exist. + */ +const char * +cdio_get_arg (const CdIo *obj, const char key[]) +{ + if (obj == NULL) return NULL; + + if (obj->op.get_arg) { + return obj->op.get_arg (obj->env, key); + } else { + return NULL; + } +} + +/*! + Return a string containing the default CD device if none is specified. + if CdIo is NULL (we haven't initialized a specific device driver), + then find a suitable one and return the default device for that. + + NULL is returned if we couldn't get a default device. + */ +char * +cdio_get_default_device (const CdIo *obj) +{ + if (obj == NULL) { + driver_id_t driver_id; + /* Scan for driver */ + for (driver_id=DRIVER_UNKNOWN; driver_id<=CDIO_MAX_DRIVER; driver_id++) { + if ( (*CdIo_all_drivers[driver_id].have_driver)() && + *CdIo_all_drivers[driver_id].get_default_device ) { + return (*CdIo_all_drivers[driver_id].get_default_device)(); + } + } + return NULL; + } + + if (obj->op.get_default_device) { + return obj->op.get_default_device (); + } else { + return NULL; + } +} + +/*!Return an array of device names. If you want a specific + devices, dor a driver give that device, if you want hardware + devices, give DRIVER_DEVICE and if you want all possible devices, + image drivers and hardware drivers give DRIVER_UNKNOWN. + + NULL is returned if we couldn't return a list of devices. +*/ +char ** +cdio_get_devices (driver_id_t driver_id) +{ + CdIo *cdio; + + switch (driver_id) { + /* FIXME: spit out unknown to give image drivers as well. */ + case DRIVER_UNKNOWN: + case DRIVER_DEVICE: + cdio = scan_for_driver(DRIVER_UNKNOWN, CDIO_MAX_DRIVER, NULL); + break; + default: + return (*CdIo_all_drivers[driver_id].get_devices)(); + } + + if (cdio == NULL) return NULL; + if (cdio->op.get_devices) { + return cdio->op.get_devices (); + } else { + return NULL; + } +} + +/*! + Return an array of device names in search_devices that have at + least the capabilities listed by cap. If search_devices is NULL, + then we'll search all possible CD drives. + + If "any" is set false then every capability listed in the extended + portion of capabilities (i.e. not the basic filesystem) must be + satisified. If "any" is set true, then if any of the capabilities + matches, we call that a success. + + To find a CD-drive of any type, use the mask CDIO_FS_MATCH_ALL. + + NULL is returned if we couldn't get a default device. +*/ +char ** +cdio_get_devices_with_cap (char* search_devices[], + cdio_fs_anal_t capabilities, bool any) +{ + char **drives=search_devices; + char **drives_ret=NULL; + int num_drives=0; + + if (NULL == drives) drives=cdio_get_devices(DRIVER_DEVICE); + if (NULL == drives) return NULL; + + if (capabilities == CDIO_FS_MATCH_ALL) { + /* Duplicate drives into drives_ret. */ + for( ; *drives != NULL; drives++ ) { + cdio_add_device_list(&drives_ret, *drives, &num_drives); + } + } else { + cdio_fs_anal_t got_fs=0; + cdio_fs_anal_t need_fs = CDIO_FSTYPE(capabilities); + cdio_fs_anal_t need_fs_ext; + need_fs_ext = capabilities & ~CDIO_FS_MASK; + + for( ; *drives != NULL; drives++ ) { + CdIo *cdio = cdio_open(*drives, DRIVER_UNKNOWN); + + if (NULL != cdio) { + track_t first_track = cdio_get_first_track_num(cdio); + cdio_analysis_t cdio_analysis; + got_fs = cdio_guess_cd_type(cdio, 0, first_track, + &cdio_analysis); + /* Match on fs and add */ + if ( (CDIO_FS_UNKNOWN == need_fs || CDIO_FSTYPE(got_fs) == need_fs) ) + { + bool doit = any + ? (got_fs & need_fs_ext) != 0 + : (got_fs | ~need_fs_ext) == -1; + if (doit) + cdio_add_device_list(&drives_ret, *drives, &num_drives); + } + + cdio_destroy(cdio); + } + } + cdio_add_device_list(&drives_ret, NULL, &num_drives); + } + return drives_ret; +} + +/*! + Return a string containing the name of the driver in use. + if CdIo is NULL (we haven't initialized a specific device driver), + then return NULL. +*/ +const char * +cdio_get_driver_name (const CdIo *cdio) +{ + return CdIo_all_drivers[cdio->driver_id].name; +} + + +/*! + Return the number of of the first track. + CDIO_INVALID_TRACK is returned on error. +*/ +track_t +cdio_get_first_track_num (const CdIo *cdio) +{ + cdio_assert (cdio != NULL); + + if (cdio->op.get_first_track_num) { + return cdio->op.get_first_track_num (cdio->env); + } else { + return CDIO_INVALID_TRACK; + } +} + +/*! + Return a string containing the name of the driver in use. + if CdIo is NULL (we haven't initialized a specific device driver), + then return NULL. +*/ +char * +cdio_get_mcn (const CdIo *cdio) +{ + if (cdio->op.get_mcn) { + return cdio->op.get_mcn (cdio->env); + } else { + return NULL; + } +} + +/*! + Return the number of tracks in the current medium. + CDIO_INVALID_TRACK is returned on error. +*/ +track_t +cdio_get_num_tracks (const CdIo *cdio) +{ + if (cdio == NULL) return CDIO_INVALID_TRACK; + + if (cdio->op.get_num_tracks) { + return cdio->op.get_num_tracks (cdio->env); + } else { + return CDIO_INVALID_TRACK; + } +} + +/*! + Get format of track. +*/ +track_format_t +cdio_get_track_format(const CdIo *cdio, track_t track_num) +{ + cdio_assert (cdio != NULL); + + if (cdio->op.get_track_format) { + return cdio->op.get_track_format (cdio->env, track_num); + } else { + return TRACK_FORMAT_ERROR; + } +} + +/*! + 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? +*/ +bool +cdio_get_track_green(const CdIo *cdio, track_t track_num) +{ + cdio_assert (cdio != NULL); + + if (cdio->op.get_track_green) { + return cdio->op.get_track_green (cdio->env, track_num); + } else { + return false; + } +} + +/*! + Return the starting LBA for track number + track_num in cdio. Tracks numbers start at 1. + The "leadout" track is specified either by + using track_num LEADOUT_TRACK or the total tracks+1. + CDIO_INVALID_LBA is returned on error. +*/ +lba_t +cdio_get_track_lba(const CdIo *cdio, track_t track_num) +{ + if (cdio == NULL) return CDIO_INVALID_LBA; + + if (cdio->op.get_track_lba) { + return cdio->op.get_track_lba (cdio->env, track_num); + } else { + msf_t msf; + if (cdio->op.get_track_msf) + if (cdio_get_track_msf(cdio, track_num, &msf)) + return cdio_msf_to_lba(&msf); + return CDIO_INVALID_LBA; + } +} + +/*! + Return the starting LSN for track number + track_num in cdio. Tracks numbers start at 1. + The "leadout" track is specified either by + using track_num LEADOUT_TRACK or the total tracks+1. + CDIO_INVALID_LBA is returned on error. +*/ +lsn_t +cdio_get_track_lsn(const CdIo *cdio, track_t track_num) +{ + if (cdio == NULL) return CDIO_INVALID_LBA; + + if (cdio->op.get_track_lba) { + return cdio_lba_to_lsn(cdio->op.get_track_lba (cdio->env, track_num)); + } else { + msf_t msf; + if (cdio_get_track_msf(cdio, track_num, &msf)) + return cdio_msf_to_lsn(&msf); + return CDIO_INVALID_LSN; + } +} + +/*! + Return the starting MSF (minutes/secs/frames) for track number + track_num in cdio. 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. +*/ +bool +cdio_get_track_msf(const CdIo *cdio, track_t track_num, /*out*/ msf_t *msf) +{ + cdio_assert (cdio != NULL); + + if (cdio->op.get_track_msf) { + return cdio->op.get_track_msf (cdio->env, track_num, msf); + } else if (cdio->op.get_track_lba) { + lba_t lba = cdio->op.get_track_lba (cdio->env, track_num); + if (lba == CDIO_INVALID_LBA) return false; + cdio_lba_to_msf(lba, msf); + return true; + } else { + return false; + } +} + +/*! + Return the number of sectors between this track an the next. This + includes any pregap sectors before the start of the next track. + Tracks start at 1. + 0 is returned if there is an error. +*/ +unsigned int +cdio_get_track_sec_count(const CdIo *cdio, track_t track_num) +{ + track_t num_tracks = cdio_get_num_tracks(cdio); + + if (track_num >=1 && track_num <= num_tracks) + return ( cdio_get_track_lba(cdio, track_num+1) + - cdio_get_track_lba(cdio, track_num) ); + return 0; +} + +bool +cdio_have_driver(driver_id_t driver_id) +{ + return (*CdIo_all_drivers[driver_id].have_driver)(); +} + +bool +cdio_is_device(const char *source_name, driver_id_t driver_id) +{ + if (CdIo_all_drivers[driver_id].is_device == NULL) return false; + return (*CdIo_all_drivers[driver_id].is_device)(source_name); +} + + +/*! + Initialize CD Reading and control routines. Should be called first. + May be implicitly called by other routines if not called first. +*/ +bool +cdio_init(void) +{ + + CdIo_driver_t *all_dp; + CdIo_driver_t *dp = CdIo_driver; + driver_id_t driver_id; + + if (CdIo_last_driver != CDIO_DRIVER_UNINIT) { + cdio_warn ("Init routine called more than once."); + return false; + } + + for (driver_id=DRIVER_UNKNOWN; driver_id<=CDIO_MAX_DRIVER; driver_id++) { + all_dp = &CdIo_all_drivers[driver_id]; + if ((*CdIo_all_drivers[driver_id].have_driver)()) { + *dp++ = *all_dp; + CdIo_last_driver++; + } + } + + return true; +} + +CdIo * +cdio_new (void *env, const cdio_funcs *funcs) +{ + CdIo *new_cdio; + + new_cdio = _cdio_malloc (sizeof (CdIo)); + + new_cdio->env = env; + new_cdio->op = *funcs; + + return new_cdio; +} + +/*! + Free any resources associated with cdio. +*/ +void +cdio_destroy (CdIo *cdio) +{ + CdIo_last_driver = CDIO_DRIVER_UNINIT; + if (cdio == NULL) return; + + if (cdio->op.free != NULL) + cdio->op.free (cdio->env); + free (cdio); +} + +/*! + lseek - reposition read/write file offset + Returns (off_t) -1 on error. + Similar to (if not the same as) libc's lseek() +*/ +off_t +cdio_lseek (const CdIo *cdio, off_t offset, int whence) +{ + if (cdio == NULL) return -1; + + if (cdio->op.lseek) + return cdio->op.lseek (cdio->env, offset, whence); + return -1; +} + +/*! + Reads into buf the next size bytes. + Returns -1 on error. + Similar to (if not the same as) libc's read() +*/ +ssize_t +cdio_read (const CdIo *cdio, void *buf, size_t size) +{ + if (cdio == NULL) return -1; + + if (cdio->op.read) + return cdio->op.read (cdio->env, buf, size); + return -1; +} + +int +cdio_read_audio_sector (const CdIo *cdio, void *buf, lsn_t lsn) +{ + cdio_assert (cdio != NULL); + cdio_assert (buf != NULL); + + if (cdio->op.read_audio_sectors != NULL) + return cdio->op.read_audio_sectors (cdio->env, buf, lsn, 1); + return -1; +} + +int +cdio_read_audio_sectors (const CdIo *cdio, void *buf, lsn_t lsn, + unsigned int nblocks) +{ + cdio_assert (cdio != NULL); + cdio_assert (buf != NULL); + + if (cdio->op.read_audio_sectors != NULL) + return cdio->op.read_audio_sectors (cdio->env, buf, lsn, nblocks); + return -1; +} + +/*! + Reads a single mode1 form1 or form2 sector from cd device + into data starting from lsn. Returns 0 if no error. + */ +int +cdio_read_mode1_sector (const CdIo *cdio, void *data, lsn_t lsn, bool is_form2) +{ + uint32_t size = is_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE ; + char buf[M2RAW_SECTOR_SIZE] = { 0, }; + int ret; + + cdio_assert (cdio != NULL); + cdio_assert (data != NULL); + + if (cdio->op.lseek && cdio->op.read) { + if (0 > cdio_lseek(cdio, CDIO_CD_FRAMESIZE*lsn, SEEK_SET)) + return -1; + if (0 > cdio_read(cdio, buf, CDIO_CD_FRAMESIZE)) + return -1; + memcpy (data, buf, size); + return 0; + } else { + ret = cdio_read_mode2_sector(cdio, data, lsn, is_form2); + if (ret == 0) + memcpy (data, buf+CDIO_CD_SUBHEADER_SIZE, size); + } + return ret; + +} + +int +cdio_read_mode1_sectors (const CdIo *cdio, void *data, lsn_t lsn, + bool is_form2, unsigned int num_sectors) +{ + uint32_t size = is_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE ; + int retval; + int i; + + cdio_assert (cdio != NULL); + + for (i = 0; i < num_sectors; i++) { + if ( (retval = cdio_read_mode1_sector (cdio, + ((char *)data) + (size * i), + lsn + i, is_form2)) ) + return retval; + } + return 0; +} + +/*! + Reads a single mode2 sector from cd device into data starting + from lsn. Returns 0 if no error. + */ +int +cdio_read_mode2_sector (const CdIo *cdio, void *buf, lsn_t lsn, + bool is_form2) +{ + cdio_assert (cdio != NULL); + cdio_assert (buf != NULL); + cdio_assert (cdio->op.read_mode2_sector != NULL + || cdio->op.read_mode2_sectors != NULL); + + if (cdio->op.read_mode2_sector) + return cdio->op.read_mode2_sector (cdio->env, buf, lsn, is_form2); + + /* fallback */ + if (cdio->op.read_mode2_sectors != NULL) + return cdio_read_mode2_sectors (cdio, buf, lsn, is_form2, 1); + return 1; +} + +int +cdio_read_mode2_sectors (const CdIo *cdio, void *buf, lsn_t lsn, bool mode2raw, + unsigned num_sectors) +{ + cdio_assert (cdio != NULL); + cdio_assert (buf != NULL); + cdio_assert (cdio->op.read_mode2_sectors != NULL); + + return cdio->op.read_mode2_sectors (cdio->env, buf, lsn, + mode2raw, num_sectors); +} + +uint32_t +cdio_stat_size (const CdIo *cdio) +{ + cdio_assert (cdio != NULL); + + return cdio->op.stat_size (cdio->env); +} + +/*! + Set the arg "key" with "value" in the source device. +*/ +int +cdio_set_arg (CdIo *cdio, const char key[], const char value[]) +{ + cdio_assert (cdio != NULL); + cdio_assert (cdio->op.set_arg != NULL); + cdio_assert (key != NULL); + + return cdio->op.set_arg (cdio->env, key, value); +} + +/*! Sets up to read from place specified by source_name and + driver_id. This should be called before using any other routine, + except cdio_init. This will call cdio_init, if that hasn't been + done previously. + + NULL is returned on error. +*/ +CdIo * +cdio_open (const char *orig_source_name, driver_id_t driver_id) +{ + char *source_name; + + if (CdIo_last_driver == -1) cdio_init(); + + if (NULL == orig_source_name || strlen(orig_source_name)==0) + source_name = cdio_get_default_device(NULL); + 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; + } + case DRIVER_DEVICE: + { + /* Scan for a driver. */ + CdIo *ret = cdio_open_cd(source_name); + free(source_name); + return ret; + } + break; + case DRIVER_BSDI: + case DRIVER_FREEBSD: + case DRIVER_LINUX: + case DRIVER_SOLARIS: + case DRIVER_WIN32: + case DRIVER_OSX: + case DRIVER_NRG: + case DRIVER_BINCUE: + 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; + return ret; + } + } + + free(source_name); + return NULL; +} + + +/* In the future we'll have more complicated code to allow selection + of an I/O routine as well as code to find an appropriate default + routine among the "registered" routines. Possibly classes too + disk-based, SCSI-based, native-based, vendor (e.g. Sony, or + Plextor) based + + For now though, we'll start more simply... +*/ +CdIo * +cdio_open_cd (const char *source_name) +{ + if (CdIo_last_driver == -1) cdio_init(); + + /* Scan for a driver. */ + return scan_for_driver(CDIO_MIN_DEVICE_DRIVER, CDIO_MAX_DEVICE_DRIVER, + source_name); +} + + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/cdio/Makefile.am b/src/input/vcd/libcdio/cdio/Makefile.am new file mode 100644 index 000000000..e2564e9bd --- /dev/null +++ b/src/input/vcd/libcdio/cdio/Makefile.am @@ -0,0 +1,12 @@ +noinst_HEADERS = cdio.h cd_types.h iso9660.h logging.h sector.h types.h util.h version.h xa.h + +debug: +install-debug: install + +mostlyclean-generic: + -rm -f *~ \#* .*~ .\#* + +maintainer-clean-generic: + -@echo "This command is intended for maintainers to use;" + -@echo "it deletes files that may require special tools to rebuild." + -rm -f Makefile.in diff --git a/src/input/vcd/libcdio/cdio/cd_types.h b/src/input/vcd/libcdio/cdio/cd_types.h new file mode 100644 index 000000000..91b36453c --- /dev/null +++ b/src/input/vcd/libcdio/cdio/cd_types.h @@ -0,0 +1,114 @@ +/* + $Id: cd_types.h,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + Copyright (C) 1996,1997,1998 Gerd Knorr <kraxel@bytesex.org> + and Heiko Eißfeldt <heiko@hexco.de> + + 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 +*/ + +/* + Filesystem types we understand. The highest-numbered fs type should + be less than CDIO_FS_MASK defined below. +*/ + +#ifndef __CDIO_CD_TYPES_H__ +#define __CDIO_CD_TYPES_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define CDIO_FS_AUDIO 1 /* audio only - not really a fs */ +#define CDIO_FS_HIGH_SIERRA 2 +#define CDIO_FS_ISO_9660 3 +#define CDIO_FS_INTERACTIVE 4 +#define CDIO_FS_HFS 5 +#define CDIO_FS_UFS 6 + +/* EXT2 was the GNU/Linux native filesystem for early kernels. Newer + GNU/Linux OS's may use EXT3 which EXT2 with a journal. */ +#define CDIO_FS_EXT2 7 + +#define CDIO_FS_ISO_HFS 8 /* both hfs & isofs filesystem */ +#define CDIO_FS_ISO_9660_INTERACTIVE 9 /* both CD-RTOS and isofs filesystem */ + + +/* The 3DO is, technically, a set of specifications created by the 3DO +company. These specs are for making a 3DO Interactive Multiplayer +which uses a CD-player. Panasonic in the early 90's was the first +company to manufacture and market a 3DO player. */ +#define CDIO_FS_3DO 10 + +#define CDIO_FS_MASK 15 /* Should be 2*n-1 and > above */ +#define CDIO_FS_UNKNOWN CDIO_FS_MASK + +/* Macro to extract just the FS type portion defined above */ +#define CDIO_FSTYPE(fs) (fs & CDIO_FS_MASK) + +/* + Bit masks for the classes of CD-images. These are generally + higher-level than the fs-type information above and may be determined + based of the fs type information. + */ +#define CDIO_FS_ANAL_XA 16 +#define CDIO_FS_ANAL_MULTISESSION 32 +#define CDIO_FS_ANAL_PHOTO_CD 64 +#define CDIO_FS_ANAL_HIDDEN_TRACK 128 +#define CDIO_FS_ANAL_CDTV 256 +#define CDIO_FS_ANAL_BOOTABLE 512 +#define CDIO_FS_ANAL_VIDEOCD 1024 /* VCD 1.1 */ +#define CDIO_FS_ANAL_ROCKRIDGE 2048 +#define CDIO_FS_ANAL_JOLIET 4096 +#define CDIO_FS_ANAL_SVCD 8192 /* Super VCD or Choiji Video CD */ +#define CDIO_FS_ANAL_CVD 16384 /* Choiji Video CD */ + +/* Pattern which can be used by cdio_get_devices to specify matching + any sort of CD. +*/ +#define CDIO_FS_MATCH_ALL (cdio_fs_anal_t) (~CDIO_FS_MASK) + + +typedef struct +{ + unsigned int joliet_level; + char iso_label[33]; /* 32 + 1 for null byte at the end in + formatting the string */ + unsigned int isofs_size; +} cdio_analysis_t; + +/* + Try to determine what kind of CD-image and/or filesystem we + have at track track_num. Return information about the CD image + is returned in cdio_analysis and the return value. +*/ +cdio_fs_anal_t cdio_guess_cd_type(const CdIo *cdio, int start_session, + track_t track_num, + /*out*/ cdio_analysis_t *cdio_analysis); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __CDIO_CD_TYPES_H__ */ + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/cdio/cdio.h b/src/input/vcd/libcdio/cdio/cdio.h new file mode 100644 index 000000000..d0b304b38 --- /dev/null +++ b/src/input/vcd/libcdio/cdio/cdio.h @@ -0,0 +1,445 @@ +/* -*- c -*- + $Id: cdio.h,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org> + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + + 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 +*/ + +/* Public CD Input and Control Interface . */ + + +#ifndef __CDIO_H__ +#define __CDIO_H__ + +/* Application Interface or Protocol version number. If the public + interface changes, we increase this number. + */ +#define CDIO_API_VERSION 1 + +#include <cdio/version.h> + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <cdio/types.h> +#include <cdio/sector.h> + +/* Flags specifying the category of device to open or is opened. */ +#define CDIO_SRC_IS_DISK_IMAGE_MASK 0x0001 +#define CDIO_SRC_IS_DEVICE_MASK 0x0002 +#define CDIO_SRC_IS_SCSI_MASK 0x0004 +#define CDIO_SRC_IS_NATIVE_MASK 0x0008 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + /* opaque structure */ + typedef struct _CdIo CdIo; + + /* The below enumerations may be used to tag a specific driver + that is opened or is desired to be opened. Note that this is + different than what is available on a given host. + + Order is a little significant since the order is used in scans. + We have to start with UNKNOWN and devices should come before + disk-image readers. By putting something towards the top (a lower + enumeration number), in an iterative scan we prefer that to something + with a higher enumeration number. + + NOTE: IF YOU MODIFY ENUM MAKE SURE INITIALIZATION IN CDIO.C AGREES. + + */ + typedef enum { + DRIVER_UNKNOWN, + DRIVER_BSDI, + DRIVER_FREEBSD, + DRIVER_LINUX, + DRIVER_SOLARIS, + DRIVER_OSX, + DRIVER_WIN32, + DRIVER_BINCUE, /* Prefer bincue over nrg when both exist */ + DRIVER_NRG, + DRIVER_DEVICE /* Is really a set of the above; should come last */ + } driver_id_t; + + /* Make sure what's listed below is the last one above. Since we have + a bogus (but useful) 0th entry above we don't have to add one below. + */ +#define CDIO_MIN_DRIVER DRIVER_BSDI +#define CDIO_MIN_DEVICE_DRIVER CDIO_MIN_DRIVER +#define CDIO_MAX_DRIVER DRIVER_NRG +#define CDIO_MAX_DEVICE_DRIVER DRIVER_WIN32 + + typedef enum { + TRACK_FORMAT_AUDIO, /* Audio track, e.g. CD-DA */ + TRACK_FORMAT_CDI, /* CD-i. How this is different from DATA below? */ + TRACK_FORMAT_XA, /* Mode2 of some sort */ + TRACK_FORMAT_DATA, /* Mode1 of some sort */ + TRACK_FORMAT_PSX, /* Playstation CD. Like audio but only 2336 bytes + of user data. + */ + TRACK_FORMAT_ERROR /* Dunno what is or some other error. */ + } track_format_t; + + /* Printable tags for above enumeration. */ + extern const char *track_format2str[6]; + + /*! + Eject media in CD drive if there is a routine to do so. + Return 0 if success and 1 for failure, and 2 if no routine. + If the CD is ejected *obj is freed and obj set to NULL. + */ + int cdio_eject_media (CdIo **obj); + + /*! + Free any resources associated with obj. + */ + void cdio_destroy (CdIo *obj); + + /*! + Free device list returned by cdio_get_devices or + cdio_get_devices_with_cap. + */ + void cdio_free_device_list (char * device_list[]); + + /*! + Return the value associatied with key. NULL is returned if obj is NULL + or "key" does not exist. + */ + const char * cdio_get_arg (const CdIo *obj, const char key[]); + + /*! + Return an array of device names in search_devices that have at + least the capabilities listed by cap. If search_devices is NULL, + then we'll search all possible CD drives. + + If "any" is set false then every capability listed in the extended + portion of capabilities (i.e. not the basic filesystem) must be + satisified. If "any" is set true, then if any of the capabilities + matches, we call that a success. + + To find a CD-drive of any type, use the mask CDIO_FS_MATCH_ALL. + + NULL is returned if we couldn't get a default device. + */ + char ** cdio_get_devices_with_cap (char* search_devices[], + cdio_fs_anal_t capabilities, bool any); + + /*!Return an array of device names. If you want a specific + devices, dor a driver give that device, if you want hardware + devices, give DRIVER_DEVICE and if you want all possible devices, + image drivers and hardware drivers give DRIVER_UNKNOWN. + + NULL is returned if we couldn't return a list of devices. + */ + char ** cdio_get_devices (driver_id_t driver); + + /*! + Return a string containing the default CD device. + if obj is NULL (we haven't initialized a specific device driver), + then find a suitable one and return the default device for that. + + NULL is returned if we couldn't get a default device. + */ + char * cdio_get_default_device (const CdIo *obj); + + /*! + Return the media catalog number (MCN) from the CD or NULL if there + is none or we don't have the ability to get it. + + Note: string is malloc'd so caller has to free() the returned + string when done with it. + */ + char *cdio_get_mcn (const CdIo *obj); + + /*! + Return a string containing the name of the driver in use. + if CdIo is NULL (we haven't initialized a specific device driver), + then return NULL. + */ + const char * cdio_get_driver_name (const CdIo *obj); + + /*! + Return the number of the first track. + CDIO_INVALID_TRACK is returned on error. + */ + track_t cdio_get_first_track_num(const CdIo *obj); + + /*! + Return a string containing the default CD device if none is specified. + */ + track_t cdio_get_num_tracks (const CdIo *obj); + + /*! + Get format of track. + */ + track_format_t cdio_get_track_format(const CdIo *obj, track_t track_num); + + /*! + 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? + */ + bool cdio_get_track_green(const CdIo *obj, track_t track_num); + + /*! + Return the starting LBA for track number + track_num in obj. Tracks numbers start at 1. + The "leadout" track is specified either by + using track_num LEADOUT_TRACK or the total tracks+1. + CDIO_INVALID_LBA is returned on error. + */ + lba_t cdio_get_track_lba(const CdIo *obj, track_t track_num); + + /*! + Return the starting LSN for track number + track_num in obj. Tracks numbers start at 1. + The "leadout" track is specified either by + using track_num LEADOUT_TRACK or the total tracks+1. + CDIO_INVALID_LBA is returned on error. + */ + lsn_t cdio_get_track_lsn(const CdIo *obj, track_t track_num); + + /*! + Return the starting MSF (minutes/secs/frames) for 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. + */ + bool cdio_get_track_msf(const CdIo *obj, track_t track_num, + /*out*/ msf_t *msf); + + /*! + Return the number of sectors between this track an the next. This + includes any pregap sectors before the start of the next track. + Tracks start at 1. + 0 is returned if there is an error. + */ + unsigned int cdio_get_track_sec_count(const CdIo *obj, track_t track_num); + + /*! + lseek - reposition read/write file offset + Returns (off_t) -1 on error. + Similar to (if not the same as) libc's lseek() + */ + off_t cdio_lseek(const CdIo *obj, off_t offset, int whence); + + /*! + Reads into buf the next size bytes. + Returns -1 on error. + Similar to (if not the same as) libc's read() + */ + ssize_t cdio_read(const CdIo *obj, void *buf, size_t size); + + /*! + Reads a audio sector from cd device into data starting + from lsn. Returns 0 if no error. + */ + int cdio_read_audio_sector (const CdIo *obj, void *buf, lsn_t lsn); + + /*! + Reads a audio sector from cd device into data starting + from lsn. Returns 0 if no error. + */ + int cdio_read_audio_sectors (const CdIo *obj, void *buf, lsn_t lsn, + unsigned int nblocks); + + /*! + Reads a single mode1 sector from cd device into data starting + from lsn. Returns 0 if no error. + */ + int cdio_read_mode1_sector (const CdIo *obj, void *buf, lsn_t lsn, + bool is_form2); + + /*! + Reads nblocks of mode1 sectors from cd device into data starting + from lsn. Returns 0 if no error. + */ + int cdio_read_mode1_sectors (const CdIo *obj, void *buf, lsn_t lsn, + bool is_form2, unsigned int num_sectors); + + /*! + Reads a single mode2 sector from cd device into data starting + from lsn. Returns 0 if no error. + */ + int cdio_read_mode2_sector (const CdIo *obj, void *buf, lsn_t lsn, + bool is_form2); + + /*! + Reads nblocks of mode2 sectors from cd device into data starting + from lsn. + Returns 0 if no error. + */ + int cdio_read_mode2_sectors (const CdIo *obj, void *buf, lsn_t lsn, + bool is_form2, unsigned int num_sectors); + + /*! + Set the arg "key" with "value" in the source device. + 0 is returned if no error was found, and nonzero if there as an error. + */ + int cdio_set_arg (CdIo *obj, const char key[], const char value[]); + + /*! + Return the size of the CD in logical block address (LBA) units. + */ + uint32_t cdio_stat_size (const CdIo *obj); + + /*! + Initialize CD Reading and control routines. Should be called first. + */ + bool cdio_init(void); + + /* True if xxx driver is available. where xxx=linux, solaris, nrg, ... + */ + bool cdio_have_bsdi (void); + bool cdio_have_freebsd (void); + bool cdio_have_linux (void); + bool cdio_have_solaris (void); + bool cdio_have_osx (void); + bool cdio_have_win32 (void); + bool cdio_have_nrg (void); + bool cdio_have_bincue (void); + + /* Like above but uses the enumeration instead. */ + bool cdio_have_driver (driver_id_t driver_id); + + /* Return a string decribing driver_id. */ + const char *cdio_driver_describe (driver_id_t driver_id); + + /*! Sets up to read from place specified by source_name and + driver_id This should be called before using any other routine, + except cdio_init. This will call cdio_init, if that hasn't been + done previously. to call one of the specific routines below. + + NULL is returned on error. + */ + CdIo * cdio_open (const char *source_name, driver_id_t driver_id); + + /*! cdrao BIN/CUE CD disk-image routines. Source is the .bin file + + NULL is returned on error. + */ + CdIo * cdio_open_bincue (const char *bin_name); + + char * cdio_get_default_device_bincue(void); + + char **cdio_get_devices_bincue(void); + + /*! CD routines. Source is the some sort of device. + + NULL is returned on error. + */ + CdIo * cdio_open_cd (const char *device_name); + + /*! cdrao BIN/CUE CD disk-image routines. Source is the .cue file + + NULL is returned on error. + */ + CdIo * cdio_open_cue (const char *cue_name); + + /*! BSDI CD-reading routines. + NULL is returned on error. + */ + CdIo * cdio_open_bsdi (const char *source_name); + + char * cdio_get_default_device_bsdi(void); + + char **cdio_get_devices_bsdi(void); + + /*! BSDI CD-reading routines. + NULL is returned on error. + */ + CdIo * cdio_open_freebsd (const char *source_name); + + char * cdio_get_default_device_freebsd(void); + + char **cdio_get_devices_freebsd(void); + + /*! Linux CD-reading routines. + NULL is returned on error. + */ + CdIo * cdio_open_linux (const char *source_name); + + char * cdio_get_default_device_linux(void); + + char **cdio_get_devices_linux(void); + + /*! Solaris CD-reading routines. + NULL is returned on error. + */ + CdIo * cdio_open_solaris (const char *source_name); + + char * cdio_get_default_device_solaris(void); + + char **cdio_get_devices_solaris(void); + + /*! Darwin OS X CD-reading routines. + NULL is returned on error. + */ + CdIo * cdio_open_osx (const char *source_name); + + char * cdio_get_default_device_osx(void); + + char **cdio_get_devices_osx(void); + + /*! Win32 CD-reading routines. + NULL is returned on error. + */ + CdIo * cdio_open_win32 (const char *source_name); + + char * cdio_get_default_device_win32(void); + + char **cdio_get_devices_win32(void); + + /*! Nero CD disk-image routines. + NULL is returned on error. + */ + CdIo * cdio_open_nrg (const char *source_name); + + char * cdio_get_default_device_nrg(void); + + char **cdio_get_devices_nrg(void); + + /*! Return corresponding BIN file if cue_name is a cue file or NULL + if not a CUE file. + */ + char *cdio_is_cuefile(const char *cue_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.... + */ + char *cdio_is_binfile(const char *bin_name); + + /*! Return true if source name is a device. + */ + bool cdio_is_device(const char *source_name, driver_id_t driver_id); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __CDIO_H__ */ diff --git a/src/input/vcd/libcdio/cdio/iso9660.h b/src/input/vcd/libcdio/cdio/iso9660.h new file mode 100644 index 000000000..c2cabe5fc --- /dev/null +++ b/src/input/vcd/libcdio/cdio/iso9660.h @@ -0,0 +1,428 @@ +/* + $Id: iso9660.h,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + + See also iso9660.h by Eric Youngdale (1993). + + Copyright 1993 Yggdrasil Computing, Incorporated + Copyright (c) 1999,2000 J. Schilling + + 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 +*/ +/* + * Header file iso9660.h - assorted structure definitions and typecasts. + specific to iso9660 filesystem. +*/ + + +#ifndef __CDIO_ISO9660_H__ +#define __CDIO_ISO9660_H__ + +#include <cdio/cdio.h> +#include <cdio/xa.h> + +#include <time.h> + +#define _delta(from, to) ((to) - (from) + 1) + +#define MIN_TRACK_SIZE 4*75 +#define MIN_ISO_SIZE MIN_TRACK_SIZE + +/* + A ISO filename is: "abcde.eee;1" -> <filename> '.' <ext> ';' <version #> + + The maximum needed string length is: + 30 chars (filename + ext) + + 2 chars ('.' + ';') + + strlen("32767") + + null byte + ================================ + = 38 chars +*/ +#define LEN_ISONAME 31 +#define MAX_ISONAME 37 + +#define MAX_ISOPATHNAME 255 + +/* + * ISO 9660 directory flags. + */ +#define ISO_FILE 0 /* Not really a flag... */ +#define ISO_EXISTENCE 1 /* Do not make existence known (hidden) */ +#define ISO_DIRECTORY 2 /* This file is a directory */ +#define ISO_ASSOCIATED 4 /* This file is an assiciated file */ +#define ISO_RECORD 8 /* Record format in extended attr. != 0 */ +#define ISO_PROTECTION 16 /* No read/execute perm. in ext. attr. */ +#define ISO_DRESERVED1 32 /* Reserved bit 5 */ +#define ISO_DRESERVED2 64 /* Reserved bit 6 */ +#define ISO_MULTIEXTENT 128 /* Not final entry of a mult. ext. file */ + +/* Volume descriptor types */ +#define ISO_VD_PRIMARY 1 +#define ISO_VD_SUPPLEMENTARY 2 /* Used by Joliet */ +#define ISO_VD_END 255 + +#define ISO_PVD_SECTOR 16 +#define ISO_EVD_SECTOR 17 + +#define ISO_STANDARD_ID "CD001" +#define ISO_BLOCKSIZE 2048 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +enum strncpy_pad_check { + ISO9660_NOCHECK = 0, + ISO9660_7BIT, + ISO9660_ACHARS, + ISO9660_DCHARS +}; + +PRAGMA_BEGIN_PACKED + +struct iso9660_dtime { + uint8_t dt_year; + uint8_t dt_month; /* 1..12. Note 1 origin not 0, like a tm struct. */ + uint8_t dt_day; + uint8_t dt_hour; + uint8_t dt_minute; + uint8_t dt_second; + int8_t dt_gmtoff; /* GMT values -48 .. + 52 in 15 min intervals */ +} GNUC_PACKED; + +typedef struct iso9660_dtime iso9660_dtime_t; + +struct iso9660_ltime { + char lt_year [_delta( 1, 4)]; /* Add 1900 for Julian year */ + char lt_month [_delta( 5, 6)]; /* 1..12. Note starts at 1. */ + char lt_day [_delta( 7, 8)]; + char lt_hour [_delta( 9, 10)]; + char lt_minute [_delta( 11, 12)]; + char lt_second [_delta( 13, 14)]; + char lt_hsecond [_delta( 15, 16)]; /* 1/100's of a second */ + int8_t lt_gmtoff [_delta( 17, 17)]; +} GNUC_PACKED; + +typedef struct iso9660_ltime iso9660_ltime_t; + +/* ISO-9660 Primary Volume Descriptor. + */ +struct iso9660_pvd { + uint8_t type; /* 711 */ + char id[5]; + uint8_t version; /* 711 */ + char unused1[1]; + char system_id[32]; /* achars */ + char volume_id[32]; /* dchars */ + char unused2[8]; + uint64_t volume_space_size; /* 733 */ + char escape_sequences[32]; + uint32_t volume_set_size; /* 723 */ + uint32_t volume_sequence_number; /* 723 */ + uint32_t logical_block_size; /* 723 */ + uint64_t path_table_size; /* 733 */ + uint32_t type_l_path_table; /* 731 */ + uint32_t opt_type_l_path_table; /* 731 */ + uint32_t type_m_path_table; /* 732 */ + uint32_t opt_type_m_path_table; /* 732 */ + char root_directory_record[34]; /* 9.1 */ + char volume_set_id[128]; /* dchars */ + char publisher_id[128]; /* achars */ + char preparer_id[128]; /* achars */ + char application_id[128]; /* achars */ + char copyright_file_id[37]; /* 7.5 dchars */ + char abstract_file_id[37]; /* 7.5 dchars */ + char bibliographic_file_id[37]; /* 7.5 dchars */ + iso9660_ltime_t creation_date; /* 8.4.26.1 */ + iso9660_ltime_t modification_date; /* 8.4.26.1 */ + iso9660_ltime_t expiration_date; /* 8.4.26.1 */ + iso9660_ltime_t effective_date; /* 8.4.26.1 */ + uint8_t file_structure_version; /* 711 */ + char unused4[1]; + char application_data[512]; + char unused5[653]; +} GNUC_PACKED; + +typedef struct iso9660_dir iso9660_dir_t; +typedef struct iso9660_pvd iso9660_pvd_t; +typedef struct iso9660_stat iso9660_stat_t; + +#ifndef EMPTY_ARRAY_SIZE +#define EMPTY_ARRAY_SIZE 0 +#endif + +/* + * XXX JS: The next structure may have an odd length! + * Some compilers (e.g. on Sun3/mc68020) padd the structures to even length. + * For this reason, we cannot use sizeof (struct iso_path_table) or + * sizeof (struct iso_directory_record) to compute on disk sizes. + * Instead, we use offsetof(..., name) and add the name size. + * See mkisofs.h + */ + +/* Format of an ISO-9660 directory record */ +struct iso9660_dir { + uint8_t length; /* 711 */ + uint8_t xa_length; /* 711 */ + uint64_t extent; /* 733 */ + uint64_t size; /* 733 */ + iso9660_dtime_t recording_time; /* 7 by 711 */ + uint8_t file_flags; + uint8_t file_unit_size; /* 711 */ + uint8_t interleave_gap; /* 711 */ + uint32_t volume_sequence_number; /* 723 */ + uint8_t filename_len; /* 711 */ + char filename[EMPTY_ARRAY_SIZE]; +} GNUC_PACKED; + + +/* The following structure is not part of ISO 9660. We just use it + for our own purposes for communicating info back that's pulled out. +*/ +struct iso9660_stat { /* big endian!! */ + enum { _STAT_FILE = 1, _STAT_DIR = 2 } type; + lsn_t lsn; /* start logical sector number */ + uint32_t size; /* total size in bytes */ + uint32_t secsize; /* number of sectors allocated */ + iso9660_xa_t xa; /* XA attributes */ + struct tm tm; /* time on entry */ +} ; + +PRAGMA_END_PACKED + +/*==================================== + Character file/dirname's +=====================================*/ + +/*! + Return true if c is a DCHAR - a character that can appear in an an + ISO-9600 level 1 directory name. These are the ASCII capital + letters A-Z, the digits 0-9 and an underscore. +*/ +bool iso9660_isdchar (int c); + +/*! + Return true if c is an ACHAR - + These are the DCHAR's plus some ASCII symbols including the space + symbol. +*/ +bool iso9660_isachar (int c); + +/*! + Convert ISO-9660 file name that stored in a directory entry into + what's usually listed as the file name in a listing. + Lowercase name, and drop deal with trailing ;1's or .;1's or + ; version numbers. + + The length of the translated string is returned. +*/ +int iso9660_name_translate(const char *old, char *new); + +/*! + Pad string src with spaces to size len and copy this to dst. If + len is less than the length of src, dst will be truncated to the + first len characters of src. + + src can also be scanned to see if it contains only ACHARs, DCHARs, + 7-bit ASCII chars depending on the enumeration _check. + + In addition to getting changed, dst is the return value. + Note: this string might not be NULL terminated. + */ +char *iso9660_strncpy_pad(char dst[], const char src[], size_t len, + enum strncpy_pad_check _check); + +/*! + Set time in format used in ISO 9660 directory index record + from a Unix time structure. */ + void iso9660_set_dtime (const struct tm *tm, + /*out*/ iso9660_dtime_t *idr_date); + + +/*! + Set "long" time in format used in ISO 9660 primary volume descriptor + from a Unix time structure. */ + void iso9660_set_ltime (const struct tm *_tm, + /*out*/ iso9660_ltime_t *pvd_date); + +/*! + Get Unix time structure from format use in an ISO 9660 directory index + record. Even though tm_wday and tm_yday fields are not explicitly in + idr_date, they are calculated from the other fields. + + If tm is to reflect the localtime, set "use_localtime" true, otherwise + tm will reported in GMT. +*/ + void iso9660_get_dtime (const iso9660_dtime_t *idr_date, bool use_localtime, + /*out*/ struct tm *tm); + + +/*===================================================================== + file/dirname's +======================================================================*/ + +/*! + Check that pathname is a valid ISO-9660 directory name. + + A valid directory name should not start out with a slash (/), + dot (.) or null byte, should be less than 37 characters long, + have no more than 8 characters in a directory component + which is separated by a /, and consist of only DCHARs. + + True is returned if pathname is valid. + */ +bool iso9660_dirname_valid_p (const char pathname[]); + +/*! + Take pathname and a version number and turn that into a ISO-9660 + pathname. (That's just the pathname followd by ";" and the version + number. For example, mydir/file.ext -> mydir/file.ext;1 for version + 1. The resulting ISO-9660 pathname is returned. +*/ +char *iso9660_pathname_isofy (const char pathname[], uint16_t version); + +/*! + Check that pathname is a valid ISO-9660 pathname. + + A valid pathname contains a valid directory name, if one appears and + the filename portion should be no more than 8 characters for the + file prefix and 3 characters in the extension (or portion after a + dot). There should be exactly one dot somewhere in the filename + portion and the filename should be composed of only DCHARs. + + True is returned if pathname is valid. + */ +bool iso9660_pathname_valid_p (const char pathname[]); + +/*===================================================================== + directory tree +======================================================================*/ + +void +iso9660_dir_init_new (void *dir, uint32_t self, uint32_t ssize, + uint32_t parent, uint32_t psize, + const time_t *dir_time); + +void +iso9660_dir_init_new_su (void *dir, uint32_t self, uint32_t ssize, + const void *ssu_data, unsigned int ssu_size, + uint32_t parent, uint32_t psize, + const void *psu_data, unsigned int psu_size, + const time_t *dir_time); + +void +iso9660_dir_add_entry_su (void *dir, const char filename[], uint32_t extent, + uint32_t size, uint8_t file_flags, + const void *su_data, + unsigned int su_size, const time_t *entry_time); + +unsigned int +iso9660_dir_calc_record_size (unsigned int namelen, unsigned int su_len); + +/*! + Given a directory pointer, find the filesystem entry that contains + lsn and return information about it in stat. + + Returns true if we found an entry with the lsn and false if not. + */ +bool iso9660_find_fs_lsn(const CdIo *cdio, lsn_t lsn, + /*out*/ iso9660_stat_t *stat); + +/*! + Get file status for pathname into stat. As with libc's stat, 0 is returned + if no error and -1 on error. + */ +int iso9660_fs_stat (const CdIo *obj, const char pathname[], + /*out*/ iso9660_stat_t *stat, bool is_mode2); + +void * /* list of char* -- caller must free it */ +iso9660_fs_readdir (const CdIo *obj, const char pathname[], bool mode2); + +uint8_t +iso9660_get_dir_len(const iso9660_dir_t *idr); + +#if FIXME +uint8_t +iso9660_get_dir_size(const iso9660_dir_t *idr); + +lsn_t +iso9660_get_dir_extent(const iso9660_dir_t *idr); +#endif + +uint8_t +iso9660_get_pvd_type(const iso9660_pvd_t *pvd); + +const char * +iso9660_get_pvd_id(const iso9660_pvd_t *pvd); + +int +iso9660_get_pvd_space_size(const iso9660_pvd_t *pvd); + +int +iso9660_get_pvd_block_size(const iso9660_pvd_t *pvd) ; + +/*! Return the primary volume id version number (of pvd). + If there is an error 0 is returned. + */ +int iso9660_get_pvd_version(const iso9660_pvd_t *pvd) ; + +/*! Return the LSN of the root directory for pvd. + If there is an error CDIO_INVALID_LSN is returned. + */ +lsn_t iso9660_get_root_lsn(const iso9660_pvd_t *pvd); + +/* pathtable */ + +/*! Zero's out pathable. Do this first. */ +void iso9660_pathtable_init (void *pt); + +unsigned int iso9660_pathtable_get_size (const void *pt); + +uint16_t +iso9660_pathtable_l_add_entry (void *pt, const char name[], uint32_t extent, + uint16_t parent); + +uint16_t +iso9660_pathtable_m_add_entry (void *pt, const char name[], uint32_t extent, + uint16_t parent); + +/* volume descriptors */ + +void +iso9660_set_pvd (void *pd, const char volume_id[], const char application_id[], + const char publisher_id[], const char preparer_id[], + uint32_t iso_size, const void *root_dir, + uint32_t path_table_l_extent, uint32_t path_table_m_extent, + uint32_t path_table_size, const time_t *pvd_time); + +void +iso9660_set_evd (void *pd); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __CDIO_ISO9660_H__ */ + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/cdio/logging.h b/src/input/vcd/libcdio/cdio/logging.h new file mode 100644 index 000000000..9a600b437 --- /dev/null +++ b/src/input/vcd/libcdio/cdio/logging.h @@ -0,0 +1,66 @@ +/* + $Id: logging.h,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + + 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 +*/ + +#ifndef __LOGGING_H__ +#define __LOGGING_H__ + +#include <cdio/types.h> + +typedef enum { + CDIO_LOG_DEBUG = 1, + CDIO_LOG_INFO, + CDIO_LOG_WARN, + CDIO_LOG_ERROR, + CDIO_LOG_ASSERT +} cdio_log_level_t; + +extern int cdio_loglevel_default; + +void +cdio_log (cdio_log_level_t level, const char format[], ...) GNUC_PRINTF(2, 3); + +typedef void (*cdio_log_handler_t) (cdio_log_level_t level, + const char message[]); + +cdio_log_handler_t +cdio_log_set_handler (cdio_log_handler_t new_handler); + +void +cdio_debug (const char format[], ...) GNUC_PRINTF(1,2); + +void +cdio_info (const char format[], ...) GNUC_PRINTF(1,2); + +void +cdio_warn (const char format[], ...) GNUC_PRINTF(1,2); + +void +cdio_error (const char format[], ...) GNUC_PRINTF(1,2); + +#endif /* __LOGGING_H__ */ + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/cdio/sector.h b/src/input/vcd/libcdio/cdio/sector.h new file mode 100644 index 000000000..39dd0fefb --- /dev/null +++ b/src/input/vcd/libcdio/cdio/sector.h @@ -0,0 +1,162 @@ +/* + $Id: sector.h,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + + 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 +*/ +/* + Things related to CDROM layout. Sector sizes, MSFs, LBAs, +*/ + +#ifndef _CDIO_SECTOR_H_ +#define _CDIO_SECTOR_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include <cdio/types.h> + +#define CDIO_PREGAP_SECTORS 150 +#define CDIO_POSTGAP_SECTORS 150 + +/* + * A CD-ROM physical sector size is 2048, 2052, 2056, 2324, 2332, 2336, + * 2340, or 2352 bytes long. + +* Sector types of the standard CD-ROM data formats: + * + * format sector type user data size (bytes) + * ----------------------------------------------------------------------------- + * 1 (Red Book) CD-DA 2352 (CDIO_CD_FRAMESIZE_RAW) + * 2 (Yellow Book) Mode1 Form1 2048 (CDIO_CD_FRAMESIZE) + * 3 (Yellow Book) Mode1 Form2 2336 (M2RAW_SECTOR_SIZE) + * 4 (Green Book) Mode2 Form1 2048 (CDIO_CD_FRAMESIZE) + * 5 (Green Book) Mode2 Form2 2328 (2324+4 spare bytes) + * + * + * The layout of the standard CD-ROM data formats: + * ----------------------------------------------------------------------------- + * - audio (red): | audio_sample_bytes | + * | 2352 | + * + * - data (yellow, mode1): | sync - head - data - EDC - zero - ECC | + * | 12 - 4 - 2048 - 4 - 8 - 276 | + * + * - data (yellow, mode2): | sync - head - data | + * | 12 - 4 - 2336 | + * + * - XA data (green, mode2 form1): | sync - head - sub - data - EDC - ECC | + * | 12 - 4 - 8 - 2048 - 4 - 276 | + * + * - XA data (green, mode2 form2): | sync - head - sub - data - Spare | + * | 12 - 4 - 8 - 2324 - 4 | + * + */ + +/* + Some generally useful CD-ROM information -- mostly based on the above. + This is from linux.h - not to slight other OS's. This was the first + place I came across such useful stuff. +*/ +#define CDIO_CD_MINS 74 /* max. minutes per CD, not really a limit */ +#define CDIO_CD_SECS_PER_MIN 60 /* seconds per minute */ +#define CDIO_CD_FRAMES_PER_SEC 75 /* frames per second */ +#define CDIO_CD_SYNC_SIZE 12 /* 12 sync bytes per raw data frame */ +#define CDIO_CD_CHUNK_SIZE 24 /* lowest-level "data bytes piece" */ +#define CDIO_CD_NUM_OF_CHUNKS 98 /* chunks per frame */ +#define CDIO_CD_FRAMESIZE_SUB 96 /* subchannel data "frame" size */ +#define CDIO_CD_HEADER_SIZE 4 /* header (address) bytes per raw data + frame */ +#define CDIO_CD_SUBHEADER_SIZE 8 /* subheader bytes per raw XA data frame */ +#define CDIO_CD_EDC_SIZE 4 /* bytes EDC per most raw data frame types */ +#define CDIO_CD_M1F1_ZERO_SIZE 8 /* bytes zero per yellow book mode 1 frame */ +#define CDIO_CD_ECC_SIZE 276 /* bytes ECC per most raw data frame types */ +#define CDIO_CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ +#define CDIO_CD_FRAMESIZE_RAW 2352/* bytes per frame, "raw" mode */ +#define CDIO_CD_FRAMESIZE_RAWER 2646 /* The maximum possible returned bytes */ +#define CDIO_CD_FRAMESIZE_RAW1 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE) /*2340*/ +#define CDIO_CD_FRAMESIZE_RAW0 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE) /*2336*/ + +/* "before data" part of raw XA (green, mode2) frame */ +#define CDIO_CD_XA_HEADER (CDIO_CD_HEADER_SIZE+CDIO_CD_SUBHEADER_SIZE) + +/* "after data" part of raw XA (green, mode2 form1) frame */ +#define CDIO_CD_XA_TAIL (CDIO_CD_EDC_SIZE+CDIO_CD_ECC_SIZE) + +/* "before data" sync bytes + header of XA (green, mode2) frame */ +#define CDIO_CD_XA_SYNC_HEADER (CDIO_CD_SYNC_SIZE+CDIO_CD_XA_HEADER) + +/* CD-ROM address types (Linux cdrom_tocentry.cdte_format) */ +#define CDIO_CDROM_LBA 0x01 /* "logical block": first frame is #0 */ +#define CDIO_CDROM_MSF 0x02 /* "minute-second-frame": binary, not bcd here! */ + +#define CDIO_CDROM_DATA_TRACK 0x04 + +/* The leadout track is always 0xAA, regardless of # of tracks on disc */ +#define CDIO_CDROM_LEADOUT_TRACK 0xAA + +#define M2F2_SECTOR_SIZE 2324 +#define M2SUB_SECTOR_SIZE 2332 +#define M2RAW_SECTOR_SIZE 2336 + +#define CDIO_CD_MAX_TRACKS 99 +#define CDIO_CD_MIN_TRACK_NO 1 + +#define CDIO_CD_FRAMES_PER_MIN \ + (CDIO_CD_FRAMES_PER_SEC*CDIO_CD_SECS_PER_MIN) + +#define CDIO_CD_74MIN_SECTORS (UINT32_C(74)*CDIO_CD_FRAMES_PER_MIN) +#define CDIO_CD_80MIN_SECTORS (UINT32_C(80)*CDIO_CD_FRAMES_PER_MIN) +#define CDIO_CD_90MIN_SECTORS (UINT32_C(90)*CDIO_CD_FRAMES_PER_MIN) + +#define CDIO_CD_MAX_SECTORS \ + (UINT32_C(100)*CDIO_CD_FRAMES_PER_MIN-CDIO_PREGAP_SECTORS) + +#define msf_t_SIZEOF 3 + +/* warning, returns new allocated string */ +char *cdio_lba_to_msf_str (lba_t lba); + +lba_t cdio_lba_to_lsn (lba_t lba); + +void cdio_lba_to_msf(lba_t lba, msf_t *msf); + +lba_t cdio_lsn_to_lba (lsn_t lsn); + +void cdio_lsn_to_msf (lsn_t lsn, msf_t *msf); + +lba_t +cdio_msf_to_lba (const msf_t *msf); + +lsn_t +cdio_msf_to_lsn (const msf_t *msf); + +#ifdef __cplusplus + } +#endif + +#endif /* _CDIO_SECTOR_H_ */ + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/cdio/types.h b/src/input/vcd/libcdio/cdio/types.h new file mode 100644 index 000000000..e3c3ff3e5 --- /dev/null +++ b/src/input/vcd/libcdio/cdio/types.h @@ -0,0 +1,236 @@ +/* + $Id: types.h,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + Copyright (C) 2002,2003 Rocky Bernstein <rocky@panix.com> + + 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 +*/ + +#ifndef __CDIO_TYPES_H__ +#define __CDIO_TYPES_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + /* provide some C99 definitions */ + +#if defined(HAVE_SYS_TYPES_H) +#include <sys/types.h> +#endif + +#if defined(HAVE_STDINT_H) +# include <stdint.h> +#elif defined(HAVE_INTTYPES_H) +# include <inttypes.h> +#elif defined(AMIGA) || defined(__linux__) + typedef u_int8_t uint8_t; + typedef u_int16_t uint16_t; + typedef u_int32_t uint32_t; + typedef u_int64_t uint64_t; +#else + /* warning ISO/IEC 9899:1999 <stdint.h> was missing and even <inttypes.h> */ + /* fixme */ +#endif /* HAVE_STDINT_H */ + + /* default HP/UX macros are broken */ +#if defined(__hpux__) +# undef UINT16_C +# undef UINT32_C +# undef UINT64_C +# undef INT64_C +#endif + +#if defined (MINGW32) + typedef int ssize_t; +#endif + + /* if it's still not defined, take a good guess... should work for + most 32bit and 64bit archs */ + +#ifndef UINT16_C +# define UINT16_C(c) c ## U +#endif + +#ifndef UINT32_C +# if defined (SIZEOF_INT) && SIZEOF_INT == 4 +# define UINT32_C(c) c ## U +# elif defined (SIZEOF_LONG) && SIZEOF_LONG == 4 +# define UINT32_C(c) c ## UL +# else +# define UINT32_C(c) c ## U +# endif +#endif + +#ifndef UINT64_C +# if defined (SIZEOF_LONG) && SIZEOF_LONG == 8 +# define UINT64_C(c) c ## UL +# elif defined (SIZEOF_INT) && SIZEOF_INT == 8 +# define UINT64_C(c) c ## U +# else +# define UINT64_C(c) c ## ULL +# endif +#endif + +#ifndef INT64_C +# if defined (SIZEOF_LONG) && SIZEOF_LONG == 8 +# define INT64_C(c) c ## L +# elif defined (SIZEOF_INT) && SIZEOF_INT == 8 +# define INT64_C(c) c +# else +# define INT64_C(c) c ## LL +# endif +#endif + +#if defined(HAVE_STDBOOL_H) +#include <stdbool.h> +#else + /* ISO/IEC 9899:1999 <stdbool.h> missing -- enabling workaround */ + +# ifndef __cplusplus + typedef enum + { + false = 0, + true = 1 + } _Bool; + +# define false false +# define true true +# define bool _Bool +# endif +#endif + + /* some GCC optimizations -- gcc 2.5+ */ + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) +#define GNUC_PRINTF( format_idx, arg_idx ) \ + __attribute__((format (printf, format_idx, arg_idx))) +#define GNUC_SCANF( format_idx, arg_idx ) \ + __attribute__((format (scanf, format_idx, arg_idx))) +#define GNUC_FORMAT( arg_idx ) \ + __attribute__((format_arg (arg_idx))) +#define GNUC_NORETURN \ + __attribute__((noreturn)) +#define GNUC_CONST \ + __attribute__((const)) +#define GNUC_UNUSED \ + __attribute__((unused)) +#define GNUC_PACKED \ + __attribute__((packed)) +#else /* !__GNUC__ */ +#define GNUC_PRINTF( format_idx, arg_idx ) +#define GNUC_SCANF( format_idx, arg_idx ) +#define GNUC_FORMAT( arg_idx ) +#define GNUC_NORETURN +#define GNUC_CONST +#define GNUC_UNUSED +#define GNUC_PACKED +#endif /* !__GNUC__ */ + +#if defined(__GNUC__) + /* for GCC we try to use GNUC_PACKED */ +# define PRAGMA_BEGIN_PACKED +# define PRAGMA_END_PACKED +#elif defined(HAVE_ISOC99_PRAGMA) + /* should work with most EDG-frontend based compilers */ +# define PRAGMA_BEGIN_PACKED _Pragma("pack(1)") +# define PRAGMA_END_PACKED _Pragma("pack()") +#else /* neither gcc nor _Pragma() available... */ + /* ...so let's be naive and hope the regression testsuite is run... */ +# define PRAGMA_BEGIN_PACKED +# define PRAGMA_END_PACKED +#endif + + /* + * user directed static branch prediction gcc 2.96+ + */ +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 95) +# define GNUC_LIKELY(x) __builtin_expect((x),true) +# define GNUC_UNLIKELY(x) __builtin_expect((x),false) +#else +# define GNUC_LIKELY(x) (x) +# define GNUC_UNLIKELY(x) (x) +#endif + +#ifndef NULL +# define NULL ((void*) 0) +#endif + + /* our own offsetof()-like macro */ +#define __cd_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + + /* In many structures on the disk a sector address is stored as a + BCD-encoded mmssff in three bytes. */ + PRAGMA_BEGIN_PACKED + typedef struct { + uint8_t m, s, f; + } GNUC_PACKED msf_t; + PRAGMA_END_PACKED + +#define msf_t_SIZEOF 3 + + /* type used for bit-fields in structs (1 <= bits <= 8) */ +#if defined(__GNUC__) + /* this is strict ISO C99 which allows only 'unsigned int', 'signed + int' and '_Bool' explicitly as bit-field type */ + typedef unsigned int bitfield_t; +#else + /* other compilers might increase alignment requirements to match the + 'unsigned int' type -- fixme: find out how unalignment accesses can + be pragma'ed on non-gcc compilers */ + typedef uint8_t bitfield_t; +#endif + + /* The type of a Logical Block Address. */ + typedef uint32_t lba_t; + + /* The type of an Logical Sector Number. */ + typedef uint32_t lsn_t; + + /* The type of an track number 0..99. */ + typedef uint8_t track_t; + + /*! + Constant for invalid track number + */ +#define CDIO_INVALID_TRACK 0xFF + + /*! + Constant for invalid LBA + */ +#define CDIO_INVALID_LBA 0xFFFFFFFF + + /*! + Constant for invalid LSN + */ +#define CDIO_INVALID_LSN 0xFFFFFFFF + +typedef int cdio_fs_anal_t; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __CDIO_TYPES_H__ */ + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/cdio/util.h b/src/input/vcd/libcdio/cdio/util.h new file mode 100644 index 000000000..147a32365 --- /dev/null +++ b/src/input/vcd/libcdio/cdio/util.h @@ -0,0 +1,109 @@ +/* + $Id: util.h,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + + 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 +*/ + +#ifndef __CDIO_UTIL_H__ +#define __CDIO_UTIL_H__ + +#include <stdlib.h> + +#undef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#undef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#undef IN +#define IN(x, low, high) ((x) >= (low) && (x) <= (high)) + +#undef CLAMP +#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) + +static inline unsigned +_cdio_len2blocks (unsigned len, int blocksize) +{ + unsigned blocks; + + blocks = len / blocksize; + if (len % blocksize) + blocks++; + + return blocks; +} + +/* round up to next block boundary */ +static inline unsigned +_cdio_ceil2block (unsigned offset, int blocksize) +{ + return _cdio_len2blocks (offset, blocksize) * blocksize; +} + +static inline unsigned +_cdio_ofs_add (unsigned offset, unsigned length, int blocksize) +{ + if (blocksize - (offset % blocksize) < length) + offset = _cdio_ceil2block (offset, blocksize); + + offset += length; + + return offset; +} + +void * +_cdio_malloc (size_t size); + +void * +_cdio_memdup (const void *mem, size_t count); + +char * +_cdio_strdup_upper (const char str[]); + +void +_cdio_strfreev(char **strv); + +char * +_cdio_strjoin (char *strv[], unsigned count, const char delim[]); + +size_t +_cdio_strlenv(char **str_array); + +char ** +_cdio_strsplit(const char str[], char delim); + +static inline const char * +_cdio_bool_str (bool b) +{ + return b ? "yes" : "no"; +} + +/* BCD */ + +uint8_t to_bcd8(uint8_t n); +uint8_t from_bcd8(uint8_t p); + +#endif /* __CDIO_UTIL_H__ */ + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/cdio/version.h b/src/input/vcd/libcdio/cdio/version.h new file mode 100644 index 000000000..c8bbce698 --- /dev/null +++ b/src/input/vcd/libcdio/cdio/version.h @@ -0,0 +1 @@ +#define CDIO_VERSION "0.64-cvs" diff --git a/src/input/vcd/libcdio/cdio/xa.h b/src/input/vcd/libcdio/cdio/xa.h new file mode 100644 index 000000000..06e5df250 --- /dev/null +++ b/src/input/vcd/libcdio/cdio/xa.h @@ -0,0 +1,121 @@ +/* + $Id: xa.h,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + + See also iso9660.h by Eric Youngdale (1993) and in cdrtools. These + are + + Copyright 1993 Yggdrasil Computing, Incorporated + Copyright (c) 1999,2000 J. Schilling + + 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 +*/ + +#ifndef __CDIO_XA_H__ +#define __CDIO_XA_H__ + +#include <cdio/types.h> + +#define ISO_XA_MARKER_STRING "CD-XA001" +#define ISO_XA_MARKER_OFFSET 1024 + +/* XA attribute definitions */ +#define XA_PERM_RSYS 0x0001 /* System Group Read */ +#define XA_PERM_XSYS 0x0004 /* System Group Execute */ + +#define XA_PERM_RUSR 0x0010 /* User (owner) Read */ +#define XA_PERM_XUSR 0x0040 /* User (owner) Execute */ + +#define XA_PERM_RGRP 0x0100 /* Group Read */ +#define XA_PERM_XGRP 0x0400 /* Group Execute */ + +#define XA_PERM_ROTH 0x1000 /* Other (world) Read */ +#define XA_PERM_XOTH 0x4000 /* Other (world) Execute */ + +#define XA_ATTR_MODE2FORM1 (1 << 11) +#define XA_ATTR_MODE2FORM2 (1 << 12) +#define XA_ATTR_INTERLEAVED (1 << 13) +#define XA_ATTR_CDDA (1 << 14) +#define XA_ATTR_DIRECTORY (1 << 15) + +/* some aggregations */ +#define XA_PERM_ALL_READ (XA_PERM_RUSR | XA_PERM_RSYS | XA_PERM_RGRP) +#define XA_PERM_ALL_EXEC (XA_PERM_XUSR | XA_PERM_XSYS | XA_PERM_XGRP) +#define XA_PERM_ALL_ALL (XA_PERM_ALL_READ | XA_PERM_ALL_EXEC) + +#define XA_FORM1_DIR (XA_ATTR_DIRECTORY | XA_ATTR_MODE2FORM1 | XA_PERM_ALL_ALL) +#define XA_FORM1_FILE (XA_ATTR_MODE2FORM1 | XA_PERM_ALL_ALL) +#define XA_FORM2_FILE (XA_ATTR_MODE2FORM2 | XA_PERM_ALL_ALL) + +/* + * Extended Attributes record according to Yellow Book. + */ +typedef struct iso9660_xa /* big endian!! */ +{ + uint16_t group_id; /* 0 */ + uint16_t user_id; /* 0 */ + uint16_t attributes; /* XA_ATTR_ */ + uint8_t signature[2]; /* { 'X', 'A' } */ + uint8_t filenum; /* file number, see also XA subheader */ + uint8_t reserved[5]; /* zero */ +} iso9660_xa_t GNUC_PACKED; + + +/*! + Returns a string which interpreting the extended attribute xa_attr. + For example: + \verbatim + d---1xrxrxr + ---2--r-r-r + -a--1xrxrxr + \endverbatim + + A description of the characters in the string follows + The 1st character is either "d" if the entry is a directory, or "-" if not + The 2nd character is either "a" if the entry is CDDA (audio), or "-" if not + The 3rd character is either "i" if the entry is interleaved, or "-" if not + The 4th character is either "2" if the entry is mode2 form2 or "-" if not + The 5th character is either "1" if the entry is mode2 form1 or "-" if not + Note that an entry will either be in mode2 form1 or mode form2. That + is you will either see "2-" or "-1" in the 4th & 5th positions. + + The 6th and 7th characters refer to permissions for a user while the + the 8th and 9th characters refer to permissions for a group while, and + the 10th and 11th characters refer to permissions for everyone. + + In each of these pairs the first character (6, 8, 10) is "x" if the + entry is executable. For a directory this means the directory is + allowed to be listed or "searched". + The second character of a pair (7, 9, 11) is "r" if the entry is allowed + to be read. +*/ +const char * +iso9660_get_xa_attr_str (uint16_t xa_attr); + +iso9660_xa_t * +iso9660_xa_init (iso9660_xa_t *_xa, uint16_t uid, uint16_t gid, uint16_t attr, + uint8_t filenum); + +#endif /* __CDIO_XA_H__ */ + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/cdio_assert.h b/src/input/vcd/libcdio/cdio_assert.h new file mode 100644 index 000000000..03ea16763 --- /dev/null +++ b/src/input/vcd/libcdio/cdio_assert.h @@ -0,0 +1,59 @@ +/* + $Id: cdio_assert.h,v 1.1 2003/10/13 11:47:11 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + + 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 +*/ + +#ifndef __CDIO_ASSERT_H__ +#define __CDIO_ASSERT_H__ + +#if defined(__GNUC__) + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <cdio/types.h> +#include <cdio/logging.h> + +#define cdio_assert(expr) \ + { \ + if (GNUC_UNLIKELY (!(expr))) cdio_log (CDIO_LOG_ASSERT, \ + "file %s: line %d (%s): assertion failed: (%s)", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, #expr); \ + } + +#define cdio_assert_not_reached() \ + { \ + cdio_log (CDIO_LOG_ASSERT, \ + "file %s: line %d (%s): should not be reached", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + } + +#else /* non GNU C */ + +#include <assert.h> + +#define cdio_assert(expr) \ + assert(expr) + +#define cdio_assert_not_reached() \ + assert(0) + +#endif + +#endif /* __CDIO_ASSERT_H__ */ diff --git a/src/input/vcd/libcdio/cdio_private.h b/src/input/vcd/libcdio/cdio_private.h new file mode 100644 index 000000000..85c92946d --- /dev/null +++ b/src/input/vcd/libcdio/cdio_private.h @@ -0,0 +1,304 @@ +/* + $Id: cdio_private.h,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + + 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 +*/ + +/* Internal routines for CD I/O drivers. */ + + +#ifndef __CDIO_PRIVATE_H__ +#define __CDIO_PRIVATE_H__ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <cdio/cdio.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + /* Opaque type */ + typedef struct _CdioDataSource CdioDataSource; + + typedef struct { + + /*! + Eject media in CD drive. If successful, as a side effect we + also free obj. Return 0 if success and 1 for failure. + */ + int (*eject_media) (void *env); + + /*! + Release and free resources associated with cd. + */ + void (*free) (void *env); + + /*! + Return the value associated with the key "arg". + */ + const char * (*get_arg) (void *env, const char key[]); + + /*! + Return an array of device names. if CdIo is NULL (we haven't + initialized a specific device driver), then find a suitable device + driver. + + NULL is returned if we couldn't return a list of devices. + */ + char ** (*get_devices) (void); + + /*! + Return a string containing the default CD device if none is specified. + */ + char * (*get_default_device)(void); + + /*! + Return the media catalog number MCN from the CD or NULL if + there is none or we don't have the ability to get it. + */ + char * (*get_mcn) (void *env); + + /*! + Return the number of of the first track. + CDIO_INVALID_TRACK is returned on error. + */ + track_t (*get_first_track_num) (void *env); + + /*! + Return the number of tracks in the current medium. + CDIO_INVALID_TRACK is returned on error. + */ + track_t (*get_num_tracks) (void *env); + + /*! + Return the starting LBA for track number + track_num in obj. Tracks numbers start at 1. + The "leadout" track is specified either by + using track_num LEADOUT_TRACK or the total tracks+1. + CDIO_INVALID_LBA is returned on error. + */ + lba_t (*get_track_lba) (void *env, track_t track_num); + + /*! + Get format of track. + */ + track_format_t (*get_track_format) (void *env, track_t track_num); + + /*! + 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? + */ + bool (*get_track_green) (void *env, track_t track_num); + + /*! + Return the starting MSF (minutes/secs/frames) for track number + track_num in obj. Tracks numbers start at 1. + The "leadout" track is specified either by + using track_num LEADOUT_TRACK or the total tracks+1. + False is returned on error. + */ + bool (*get_track_msf) (void *env, track_t track_num, msf_t *msf); + + /*! + lseek - reposition read/write file offset + Returns (off_t) -1 on error. + Similar to libc's lseek() + */ + off_t (*lseek) (void *env, off_t offset, int whence); + + /*! + Reads into buf the next size bytes. + Returns -1 on error. + Similar to libc's read() + */ + ssize_t (*read) (void *env, void *buf, size_t size); + + /*! + Reads a single mode2 sector from cd device into buf starting + from lsn. Returns 0 if no error. + */ + int (*read_audio_sectors) (void *env, void *buf, lsn_t lsn, + unsigned int nblocks); + + /*! + Reads a single mode2 sector from cd device into buf starting + from lsn. Returns 0 if no error. + */ + int (*read_mode2_sector) (void *env, void *buf, lsn_t lsn, + bool mode2raw); + + /*! + Reads nblocks of mode2 sectors from cd device into data starting + from lsn. + Returns 0 if no error. + */ + int (*read_mode2_sectors) (void *env, void *buf, lsn_t lsn, + bool mode2raw, unsigned int nblocks); + + /*! + Set the arg "key" with "value" in the source device. + */ + int (*set_arg) (void *env, const char key[], const char value[]); + + /*! + Return the size of the CD in logical block address (LBA) units. + */ + uint32_t (*stat_size) (void *env); + + } cdio_funcs; + + + /* Implementation of CdIo type */ + struct _CdIo { + driver_id_t driver_id; /* Particular driver opened. */ + cdio_funcs op; /* driver-specific routines handling implimentatin*/ + void *env; /* environment. Passed to routine above. */ + }; + + /*! + Things common to private device structures. Even though not all + devices may have some of these fields, by listing common ones + we facilitate writing generic routines and even cut-and-paste + code. + */ + typedef struct { + char *source_name; /* Name used in open. */ + bool init; /* True if structure has been initialized */ + bool toc_init; /* True TOC read in */ + int ioctls_debugged; /* for debugging */ + + /* Only one of the below is used. The first is for CD-ROM devices + and the second for stream reading (bincue, nrg, toc, network). + */ + int fd; /* File descriptor of device */ + CdioDataSource *data_source; + } generic_img_private_t; + + /* This is used in drivers that must keep their own internal + position pointer for doing seeks. Stream-based drivers (like bincue, + nrg, toc, network) would use this. + */ + typedef struct + { + off_t buff_offset; /* buffer offset in disk-image seeks. */ + track_t index; /* Current track index in tocent. */ + lba_t lba; /* Current LBA */ + } internal_position_t; + + CdIo * cdio_new (void *env, const cdio_funcs *funcs); + + /* The below structure describes a specific CD Input driver */ + typedef struct + { + driver_id_t id; + unsigned int flags; + const char *name; + const char *describe; + bool (*have_driver) (void); + CdIo *(*driver_open) (const char *source_name); + char *(*get_default_device) (void); + bool (*is_device) (const char *source_name); + char **(*get_devices) (void); + } CdIo_driver_t; + + /* The below array gives of the drivers that are currently available for + on a particular host. */ + extern CdIo_driver_t CdIo_driver[CDIO_MAX_DRIVER]; + + /* The last valid entry of Cdio_driver. -1 means uninitialzed. -2 + means some sort of error. + */ + extern int CdIo_last_driver; + + /* The below array gives all drivers that can possibly appear. + on a particular host. */ + extern CdIo_driver_t CdIo_all_drivers[CDIO_MAX_DRIVER+1]; + + /*! + Add/allocate a drive to the end of drives. + Use cdio_free_device_list() to free this device_list. + */ + void cdio_add_device_list(char **device_list[], const char *drive, + int *num_drives); + + /*! + Bogus eject media when there is no ejectable media, e.g. a disk image + We always return 2. Should we also free resources? + */ + int cdio_generic_bogus_eject_media (void *env); + + /*! + Release and free resources associated with cd. + */ + void cdio_generic_free (void *env); + + /*! + Initialize CD device. + */ + bool cdio_generic_init (void *env); + + /*! + Reads into buf the next size bytes. + Returns -1 on error. + Is in fact libc's read(). + */ + off_t cdio_generic_lseek (void *env, off_t offset, int whence); + + /*! + Reads into buf the next size bytes. + Returns -1 on error. + Is in fact libc's read(). + */ + ssize_t cdio_generic_read (void *env, void *buf, size_t size); + + /*! + Release and free resources associated with stream or disk image. + */ + void cdio_generic_stream_free (void *env); + + /*! + Return true if source_name could be a device containing a CD-ROM on + Win32 + */ + bool cdio_is_device_win32(const char *source_name); + + + /*! + Return true if source_name could be a device containing a CD-ROM on + most Unix servers with block and character devices. + */ + bool cdio_is_device_generic(const char *source_name); + + + /*! + Like above, but don't give a warning device doesn't exist. + */ + bool cdio_is_device_quiet_generic(const char *source_name); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __CDIO_PRIVATE_H__ */ diff --git a/src/input/vcd/libcdio/ds.c b/src/input/vcd/libcdio/ds.c new file mode 100644 index 000000000..7cc62a8f9 --- /dev/null +++ b/src/input/vcd/libcdio/ds.c @@ -0,0 +1,249 @@ +/* + $Id: ds.c,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + + 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 +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> + +#include "ds.h" +#include <cdio/util.h> +#include <cdio/types.h> +#include "cdio_assert.h" + +static const char _rcsid[] = "$Id: ds.c,v 1.1 2003/10/13 11:47:12 f1rmb Exp $"; + +struct _CdioList +{ + unsigned length; + + CdioListNode *begin; + CdioListNode *end; +}; + +struct _CdioListNode +{ + CdioList *list; + + CdioListNode *next; + + void *data; +}; + +/* impl */ + +CdioList * +_cdio_list_new (void) +{ + CdioList *new_obj = _cdio_malloc (sizeof (CdioList)); + + return new_obj; +} + +void +_cdio_list_free (CdioList *list, int free_data) +{ + while (_cdio_list_length (list)) + _cdio_list_node_free (_cdio_list_begin (list), free_data); + + free (list); +} + +unsigned +_cdio_list_length (const CdioList *list) +{ + cdio_assert (list != NULL); + + return list->length; +} + +void +_cdio_list_prepend (CdioList *list, void *data) +{ + CdioListNode *new_node; + + cdio_assert (list != NULL); + + new_node = _cdio_malloc (sizeof (CdioListNode)); + + new_node->list = list; + new_node->next = list->begin; + new_node->data = data; + + list->begin = new_node; + if (list->length == 0) + list->end = new_node; + + list->length++; +} + +void +_cdio_list_append (CdioList *list, void *data) +{ + cdio_assert (list != NULL); + + if (list->length == 0) + { + _cdio_list_prepend (list, data); + } + else + { + CdioListNode *new_node = _cdio_malloc (sizeof (CdioListNode)); + + new_node->list = list; + new_node->next = NULL; + new_node->data = data; + + list->end->next = new_node; + list->end = new_node; + + list->length++; + } +} + +void +_cdio_list_foreach (CdioList *list, _cdio_list_iterfunc func, void *user_data) +{ + CdioListNode *node; + + cdio_assert (list != NULL); + cdio_assert (func != 0); + + for (node = _cdio_list_begin (list); + node != NULL; + node = _cdio_list_node_next (node)) + func (_cdio_list_node_data (node), user_data); +} + +CdioListNode * +_cdio_list_find (CdioList *list, _cdio_list_iterfunc cmp_func, void *user_data) +{ + CdioListNode *node; + + cdio_assert (list != NULL); + cdio_assert (cmp_func != 0); + + for (node = _cdio_list_begin (list); + node != NULL; + node = _cdio_list_node_next (node)) + if (cmp_func (_cdio_list_node_data (node), user_data)) + break; + + return node; +} + +CdioListNode * +_cdio_list_begin (const CdioList *list) +{ + cdio_assert (list != NULL); + + return list->begin; +} + +CdioListNode * +_cdio_list_end (CdioList *list) +{ + cdio_assert (list != NULL); + + return list->end; +} + +CdioListNode * +_cdio_list_node_next (CdioListNode *node) +{ + if (node) + return node->next; + + return NULL; +} + +void +_cdio_list_node_free (CdioListNode *node, int free_data) +{ + CdioList *list; + CdioListNode *prev_node; + + cdio_assert (node != NULL); + + list = node->list; + + cdio_assert (_cdio_list_length (list) > 0); + + if (free_data) + free (_cdio_list_node_data (node)); + + if (_cdio_list_length (list) == 1) + { + cdio_assert (list->begin == list->end); + + list->end = list->begin = NULL; + list->length = 0; + free (node); + return; + } + + cdio_assert (list->begin != list->end); + + if (list->begin == node) + { + list->begin = node->next; + free (node); + list->length--; + return; + } + + for (prev_node = list->begin; prev_node->next; prev_node = prev_node->next) + if (prev_node->next == node) + break; + + cdio_assert (prev_node->next != NULL); + + if (list->end == node) + list->end = prev_node; + + prev_node->next = node->next; + + list->length--; + + free (node); +} + +void * +_cdio_list_node_data (CdioListNode *node) +{ + if (node) + return node->data; + + return NULL; +} + +/* eof */ + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ + diff --git a/src/input/vcd/libcdio/ds.h b/src/input/vcd/libcdio/ds.h new file mode 100644 index 000000000..046a5b0b0 --- /dev/null +++ b/src/input/vcd/libcdio/ds.h @@ -0,0 +1,73 @@ +/* + $Id: ds.h,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + + 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 +*/ + +#ifndef __CDIO_DS_H__ +#define __CDIO_DS_H__ + +#include <cdio/types.h> + +/* opaque... */ +typedef struct _CdioList CdioList; +typedef struct _CdioListNode CdioListNode; + +typedef int (*_cdio_list_cmp_func) (void *data1, void *data2); + +typedef int (*_cdio_list_iterfunc) (void *data, void *user_data); + +/* methods */ +CdioList *_cdio_list_new (void); + +void _cdio_list_free (CdioList *list, int free_data); + +unsigned _cdio_list_length (const CdioList *list); + +void _cdio_list_prepend (CdioList *list, void *data); + +void _cdio_list_append (CdioList *list, void *data); + +void _cdio_list_foreach (CdioList *list, _cdio_list_iterfunc func, void *user_data); + +CdioListNode *_cdio_list_find (CdioList *list, _cdio_list_iterfunc cmp_func, void *user_data); + +#define _CDIO_LIST_FOREACH(node, list) \ + for (node = _cdio_list_begin (list); node; node = _cdio_list_node_next (node)) + +/* node ops */ + +CdioListNode *_cdio_list_begin (const CdioList *list); + +CdioListNode *_cdio_list_end (CdioList *list); + +CdioListNode *_cdio_list_node_next (CdioListNode *node); + +void _cdio_list_node_free (CdioListNode *node, int free_data); + +void *_cdio_list_node_data (CdioListNode *node); + +#endif /* __CDIO_DS_H__ */ + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ + diff --git a/src/input/vcd/libcdio/iso9660.c b/src/input/vcd/libcdio/iso9660.c new file mode 100644 index 000000000..c7d6f8a54 --- /dev/null +++ b/src/input/vcd/libcdio/iso9660.c @@ -0,0 +1,885 @@ +/* + $Id: iso9660.c,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + + 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 +*/ + +/* Private headers */ +#include "iso9660_private.h" +#include "cdio_assert.h" +#include "bytesex.h" + +/* Public headers */ +#include <cdio/iso9660.h> +#include <cdio/util.h> + +#include <time.h> +#include <ctype.h> +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_STDIO_H +#include <stdio.h> +#endif + +static const char _rcsid[] = "$Id: iso9660.c,v 1.1 2003/10/13 11:47:12 f1rmb Exp $"; + +/* some parameters... */ +#define SYSTEM_ID "CD-RTOS CD-BRIDGE" +#define VOLUME_SET_ID "" + +static void +pathtable_get_size_and_entries(const void *pt, unsigned int *size, + unsigned int *entries); + +/*! + Get time structure from structure in an ISO 9660 directory index + record. Even though tm_wday and tm_yday fields are not explicitly in + idr_date, the are calculated from the other fields. + + If tm is to reflect the localtime set use_localtime true, otherwise + tm will reported in GMT. +*/ +void +iso9660_get_dtime (const iso9660_dtime_t *idr_date, bool use_localtime, + /*out*/ struct tm *tm) +{ + time_t t; + struct tm *temp_tm; + + if (!idr_date) return; + + tm->tm_year = idr_date->dt_year; + tm->tm_mon = idr_date->dt_month - 1; + tm->tm_mday = idr_date->dt_day; + tm->tm_hour = idr_date->dt_hour; + tm->tm_min = idr_date->dt_minute; + tm->tm_sec = idr_date->dt_second; + + /* Recompute tm_wday and tm_yday via mktime. */ + t = mktime(tm); + + if (use_localtime) + temp_tm = localtime(&t); + else + temp_tm = gmtime(&t); + + memcpy(tm, temp_tm, sizeof(struct tm)); +} + +/*! + Set time in format used in ISO 9660 directory index record + from a Unix time structure. */ +void +iso9660_set_dtime (const struct tm *tm, /*out*/ iso9660_dtime_t *idr_date) +{ + memset (idr_date, 0, 7); + + if (!tm) return; + + idr_date->dt_year = tm->tm_year; + idr_date->dt_month = tm->tm_mon + 1; + idr_date->dt_day = tm->tm_mday; + idr_date->dt_hour = tm->tm_hour; + idr_date->dt_minute = tm->tm_min; + idr_date->dt_second = tm->tm_sec; + +#ifdef HAVE_TM_GMTOFF + /* The ISO 9660 timezone is in the range -48..+52 and each unit + represents a 15-minute interval. */ + idr_date->dt_gmtoff = tm->tm_gmtoff / (15 * 60); + + if (tm->tm_isdst) idr_date->dt_gmtoff -= 4; + + if (idr_date->dt_gmtoff < -48 ) { + + cdio_warn ("Converted ISO 9660 timezone %d is less than -48. Adjusted", + idr_date->dt_gmtoff); + idr_date->dt_gmtoff = -48; + } else if (idr_date->dt_gmtoff > 52) { + cdio_warn ("Converted ISO 9660 timezone %d is over 52. Adjusted", + idr_date->dt_gmtoff); + idr_date->dt_gmtoff = 52; + } +#else + idr_date->dt_gmtoff = 0; +#endif +} + +/*! + Set "long" time in format used in ISO 9660 primary volume descriptor + from a Unix time structure. */ +void +iso9660_set_ltime (const struct tm *_tm, /*out*/ iso9660_ltime_t *pvd_date) +{ + char *_pvd_date = (char *) pvd_date; + + memset (_pvd_date, '0', 16); + _pvd_date[16] = (int8_t) 0; /* tz */ + + if (!_tm) return; + + snprintf(_pvd_date, 17, + "%4.4d%2.2d%2.2d" "%2.2d%2.2d%2.2d" "%2.2d", + _tm->tm_year + 1900, _tm->tm_mon + 1, _tm->tm_mday, + _tm->tm_hour, _tm->tm_min, _tm->tm_sec, + 0 /* 1/100 secs */ ); + + _pvd_date[16] = (int8_t) 0; /* tz */ +} + +/*! + Convert ISO-9660 file name that stored in a directory entry into + what's usually listed as the file name in a listing. + Lowercase name, and trailing ;1's or .;1's and turn the + other ;'s into version numbers. + + The length of the translated string is returned. +*/ +int +iso9660_name_translate(const char *old, char *new) +{ + int len = strlen(old); + int i; + + for (i = 0; i < len; i++) { + unsigned char c = old[i]; + if (!c) + break; + + /* lower case */ + if (isupper(c)) c = tolower(c); + + /* Drop trailing '.;1' (ISO 9660:1988 7.5.1 requires period) */ + if (c == '.' && i == len - 3 && old[i + 1] == ';' && old[i + 2] == '1') + break; + + /* Drop trailing ';1' */ + if (c == ';' && i == len - 2 && old[i + 1] == '1') + break; + + /* Convert remaining ';' to '.' */ + if (c == ';') + c = '.'; + + new[i] = c; + } + new[i] = '\0'; + return i; +} + +/*! + Pad string src with spaces to size len and copy this to dst. If + len is less than the length of src, dst will be truncated to the + first len characters of src. + + src can also be scanned to see if it contains only ACHARs, DCHARs, + 7-bit ASCII chars depending on the enumeration _check. + + In addition to getting changed, dst is the return value. + Note: this string might not be NULL terminated. + */ +char * +iso9660_strncpy_pad(char dst[], const char src[], size_t len, + enum strncpy_pad_check _check) +{ + size_t rlen; + + cdio_assert (dst != NULL); + cdio_assert (src != NULL); + cdio_assert (len > 0); + + switch (_check) + { + int idx; + case ISO9660_NOCHECK: + break; + + case ISO9660_7BIT: + for (idx = 0; src[idx]; idx++) + if ((int8_t) src[idx] < 0) + { + cdio_warn ("string '%s' fails 7bit constraint (pos = %d)", + src, idx); + break; + } + break; + + case ISO9660_ACHARS: + for (idx = 0; src[idx]; idx++) + if (!iso9660_isachar (src[idx])) + { + cdio_warn ("string '%s' fails a-character constraint (pos = %d)", + src, idx); + break; + } + break; + + case ISO9660_DCHARS: + for (idx = 0; src[idx]; idx++) + if (!iso9660_isdchar (src[idx])) + { + cdio_warn ("string '%s' fails d-character constraint (pos = %d)", + src, idx); + break; + } + break; + + default: + cdio_assert_not_reached (); + break; + } + + rlen = strlen (src); + + if (rlen > len) + cdio_warn ("string '%s' is getting truncated to %d characters", + src, (unsigned int) len); + + strncpy (dst, src, len); + if (rlen < len) + memset(dst+rlen, ' ', len-rlen); + return dst; +} + +/*! + Return true if c is a DCHAR - a valid ISO-9660 level 1 character. + These are the ASCSII capital letters A-Z, the digits 0-9 and an + underscore. +*/ +bool +iso9660_isdchar (int c) +{ + if (!IN (c, 0x30, 0x5f) + || IN (c, 0x3a, 0x40) + || IN (c, 0x5b, 0x5e)) + return false; + + return true; +} + + +/*! + Return true if c is an ACHAR - + These are the DCHAR's plus some ASCII symbols including the space + symbol. +*/ +bool +iso9660_isachar (int c) +{ + if (!IN (c, 0x20, 0x5f) + || IN (c, 0x23, 0x24) + || c == 0x40 + || IN (c, 0x5b, 0x5e)) + return false; + + return true; +} + +void +iso9660_set_evd(void *pd) +{ + struct iso_volume_descriptor ied; + + cdio_assert (sizeof(struct iso_volume_descriptor) == ISO_BLOCKSIZE); + + cdio_assert (pd != NULL); + + memset(&ied, 0, sizeof(ied)); + + ied.type = to_711(ISO_VD_END); + iso9660_strncpy_pad (ied.id, ISO_STANDARD_ID, sizeof(ied.id), ISO9660_DCHARS); + ied.version = to_711(ISO_VERSION); + + memcpy(pd, &ied, sizeof(ied)); +} + +void +iso9660_set_pvd(void *pd, + const char volume_id[], + const char publisher_id[], + const char preparer_id[], + const char application_id[], + uint32_t iso_size, + const void *root_dir, + uint32_t path_table_l_extent, + uint32_t path_table_m_extent, + uint32_t path_table_size, + const time_t *pvd_time + ) +{ + iso9660_pvd_t ipd; + + cdio_assert (sizeof(iso9660_pvd_t) == ISO_BLOCKSIZE); + + cdio_assert (pd != NULL); + cdio_assert (volume_id != NULL); + cdio_assert (application_id != NULL); + + memset(&ipd,0,sizeof(ipd)); /* paranoia? */ + + /* magic stuff ... thatis CD XA marker... */ + strcpy(((char*)&ipd)+ISO_XA_MARKER_OFFSET, ISO_XA_MARKER_STRING); + + ipd.type = to_711(ISO_VD_PRIMARY); + iso9660_strncpy_pad (ipd.id, ISO_STANDARD_ID, 5, ISO9660_DCHARS); + ipd.version = to_711(ISO_VERSION); + + iso9660_strncpy_pad (ipd.system_id, SYSTEM_ID, 32, ISO9660_ACHARS); + iso9660_strncpy_pad (ipd.volume_id, volume_id, 32, ISO9660_DCHARS); + + ipd.volume_space_size = to_733(iso_size); + + ipd.volume_set_size = to_723(1); + ipd.volume_sequence_number = to_723(1); + ipd.logical_block_size = to_723(ISO_BLOCKSIZE); + + ipd.path_table_size = to_733(path_table_size); + ipd.type_l_path_table = to_731(path_table_l_extent); + ipd.type_m_path_table = to_732(path_table_m_extent); + + cdio_assert (sizeof(ipd.root_directory_record) == 34); + memcpy(ipd.root_directory_record, root_dir, sizeof(ipd.root_directory_record)); + ipd.root_directory_record[0] = 34; + + iso9660_strncpy_pad (ipd.volume_set_id, VOLUME_SET_ID, 128, ISO9660_DCHARS); + + iso9660_strncpy_pad (ipd.publisher_id, publisher_id, 128, ISO9660_ACHARS); + iso9660_strncpy_pad (ipd.preparer_id, preparer_id, 128, ISO9660_ACHARS); + iso9660_strncpy_pad (ipd.application_id, application_id, 128, ISO9660_ACHARS); + + iso9660_strncpy_pad (ipd.copyright_file_id , "", 37, ISO9660_DCHARS); + iso9660_strncpy_pad (ipd.abstract_file_id , "", 37, ISO9660_DCHARS); + iso9660_strncpy_pad (ipd.bibliographic_file_id, "", 37, ISO9660_DCHARS); + + iso9660_set_ltime (gmtime (pvd_time), &(ipd.creation_date)); + iso9660_set_ltime (gmtime (pvd_time), &(ipd.modification_date)); + iso9660_set_ltime (NULL, &(ipd.expiration_date)); + iso9660_set_ltime (NULL, &(ipd.effective_date)); + + ipd.file_structure_version = to_711(1); + + /* we leave ipd.application_data = 0 */ + + memcpy(pd, &ipd, sizeof(ipd)); /* copy stuff to arg ptr */ +} + +unsigned int +iso9660_dir_calc_record_size(unsigned int namelen, unsigned int su_len) +{ + unsigned int length; + + length = sizeof(iso9660_dir_t); + length += namelen; + if (length % 2) /* pad to word boundary */ + length++; + length += su_len; + if (length % 2) /* pad to word boundary again */ + length++; + + return length; +} + +void +iso9660_dir_add_entry_su(void *dir, + const char filename[], + uint32_t extent, + uint32_t size, + uint8_t file_flags, + const void *su_data, + unsigned int su_size, + const time_t *entry_time) +{ + iso9660_dir_t *idr = dir; + uint8_t *dir8 = dir; + unsigned int offset = 0; + uint32_t dsize = from_733(idr->size); + int length, su_offset; + cdio_assert (sizeof(iso9660_dir_t) == 33); + + if (!dsize && !idr->length) + dsize = ISO_BLOCKSIZE; /* for when dir lacks '.' entry */ + + cdio_assert (dsize > 0 && !(dsize % ISO_BLOCKSIZE)); + cdio_assert (dir != NULL); + cdio_assert (extent > 17); + cdio_assert (filename != NULL); + cdio_assert (strlen(filename) <= MAX_ISOPATHNAME); + + length = sizeof(iso9660_dir_t); + length += strlen(filename); + length = _cdio_ceil2block (length, 2); /* pad to word boundary */ + su_offset = length; + length += su_size; + length = _cdio_ceil2block (length, 2); /* pad to word boundary again */ + + /* find the last entry's end */ + { + unsigned int ofs_last_rec = 0; + + offset = 0; + while (offset < dsize) + { + if (!dir8[offset]) + { + offset++; + continue; + } + + offset += dir8[offset]; + ofs_last_rec = offset; + } + + cdio_assert (offset == dsize); + + offset = ofs_last_rec; + } + + /* be sure we don't cross sectors boundaries */ + offset = _cdio_ofs_add (offset, length, ISO_BLOCKSIZE); + offset -= length; + + cdio_assert (offset + length <= dsize); + + idr = (iso9660_dir_t *) &dir8[offset]; + + cdio_assert (offset+length < dsize); + + memset(idr, 0, length); + + idr->length = to_711(length); + idr->extent = to_733(extent); + idr->size = to_733(size); + + iso9660_set_dtime (gmtime(entry_time), &(idr->recording_time)); + + idr->file_flags = to_711(file_flags); + + idr->volume_sequence_number = to_723(1); + + idr->filename_len = to_711(strlen(filename) + ? strlen(filename) : 1); /* working hack! */ + + memcpy(idr->filename, filename, from_711(idr->filename_len)); + memcpy(&dir8[offset] + su_offset, su_data, su_size); +} + +void +iso9660_dir_init_new (void *dir, + uint32_t self, + uint32_t ssize, + uint32_t parent, + uint32_t psize, + const time_t *dir_time) +{ + iso9660_dir_init_new_su (dir, self, ssize, NULL, 0, parent, psize, NULL, + 0, dir_time); +} + +void +iso9660_dir_init_new_su (void *dir, + uint32_t self, + uint32_t ssize, + const void *ssu_data, + unsigned int ssu_size, + uint32_t parent, + uint32_t psize, + const void *psu_data, + unsigned int psu_size, + const time_t *dir_time) +{ + cdio_assert (ssize > 0 && !(ssize % ISO_BLOCKSIZE)); + cdio_assert (psize > 0 && !(psize % ISO_BLOCKSIZE)); + cdio_assert (dir != NULL); + + memset (dir, 0, ssize); + + /* "\0" -- working hack due to padding */ + iso9660_dir_add_entry_su (dir, "\0", self, ssize, ISO_DIRECTORY, ssu_data, + ssu_size, dir_time); + + iso9660_dir_add_entry_su (dir, "\1", parent, psize, ISO_DIRECTORY, psu_data, + psu_size, dir_time); +} + +/* Zero's out pathable. Do this first. */ +void +iso9660_pathtable_init (void *pt) +{ + cdio_assert (sizeof (struct iso_path_table) == 8); + + cdio_assert (pt != NULL); + + memset (pt, 0, ISO_BLOCKSIZE); /* fixme */ +} + +static const struct iso_path_table* +pathtable_get_entry (const void *pt, unsigned int entrynum) +{ + const uint8_t *tmp = pt; + unsigned int offset = 0; + unsigned int count = 0; + + cdio_assert (pt != NULL); + + while (from_711 (*tmp)) + { + if (count == entrynum) + break; + + cdio_assert (count < entrynum); + + offset += sizeof (struct iso_path_table); + offset += from_711 (*tmp); + if (offset % 2) + offset++; + tmp = (uint8_t *)pt + offset; + count++; + } + + if (!from_711 (*tmp)) + return NULL; + + return (const void *) tmp; +} + +void +pathtable_get_size_and_entries (const void *pt, + unsigned int *size, + unsigned int *entries) +{ + const uint8_t *tmp = pt; + unsigned int offset = 0; + unsigned int count = 0; + + cdio_assert (pt != NULL); + + while (from_711 (*tmp)) + { + offset += sizeof (struct iso_path_table); + offset += from_711 (*tmp); + if (offset % 2) + offset++; + tmp = (uint8_t *)pt + offset; + count++; + } + + if (size) + *size = offset; + + if (entries) + *entries = count; +} + +unsigned int +iso9660_pathtable_get_size (const void *pt) +{ + unsigned int size = 0; + pathtable_get_size_and_entries (pt, &size, NULL); + return size; +} + +uint16_t +iso9660_pathtable_l_add_entry (void *pt, + const char name[], + uint32_t extent, + uint16_t parent) +{ + struct iso_path_table *ipt = + (struct iso_path_table*)((char *)pt + iso9660_pathtable_get_size (pt)); + size_t name_len = strlen (name) ? strlen (name) : 1; + unsigned int entrynum = 0; + + cdio_assert (iso9660_pathtable_get_size (pt) < ISO_BLOCKSIZE); /*fixme */ + + memset (ipt, 0, sizeof (struct iso_path_table) + name_len); /* paranoia */ + + ipt->name_len = to_711 (name_len); + ipt->extent = to_731 (extent); + ipt->parent = to_721 (parent); + memcpy (ipt->name, name, name_len); + + pathtable_get_size_and_entries (pt, NULL, &entrynum); + + if (entrynum > 1) + { + const struct iso_path_table *ipt2 + = pathtable_get_entry (pt, entrynum - 2); + + cdio_assert (ipt2 != NULL); + + cdio_assert (from_721 (ipt2->parent) <= parent); + } + + return entrynum; +} + +uint16_t +iso9660_pathtable_m_add_entry (void *pt, + const char name[], + uint32_t extent, + uint16_t parent) +{ + struct iso_path_table *ipt = + (struct iso_path_table*)((char *)pt + iso9660_pathtable_get_size (pt)); + size_t name_len = strlen (name) ? strlen (name) : 1; + unsigned int entrynum = 0; + + cdio_assert (iso9660_pathtable_get_size(pt) < ISO_BLOCKSIZE); /* fixme */ + + memset(ipt, 0, sizeof (struct iso_path_table) + name_len); /* paranoia */ + + ipt->name_len = to_711 (name_len); + ipt->extent = to_732 (extent); + ipt->parent = to_722 (parent); + memcpy (ipt->name, name, name_len); + + pathtable_get_size_and_entries (pt, NULL, &entrynum); + + if (entrynum > 1) + { + const struct iso_path_table *ipt2 + = pathtable_get_entry (pt, entrynum - 2); + + cdio_assert (ipt2 != NULL); + + cdio_assert (from_722 (ipt2->parent) <= parent); + } + + return entrynum; +} + +/*! + Check that pathname is a valid ISO-9660 directory name. + + A valid directory name should not start out with a slash (/), + dot (.) or null byte, should be less than 37 characters long, + have no more than 8 characters in a directory component + which is separated by a /, and consist of only DCHARs. + */ +bool +iso9660_dirname_valid_p (const char pathname[]) +{ + const char *p = pathname; + int len; + + cdio_assert (pathname != NULL); + + if (*p == '/' || *p == '.' || *p == '\0') + return false; + + if (strlen (pathname) > MAX_ISOPATHNAME) + return false; + + len = 0; + for (; *p; p++) + if (iso9660_isdchar (*p)) + { + len++; + if (len > 8) + return false; + } + else if (*p == '/') + { + if (!len) + return false; + len = 0; + } + else + return false; /* unexpected char */ + + if (!len) + return false; /* last char may not be '/' */ + + return true; +} + +/*! + Check that pathname is a valid ISO-9660 pathname. + + A valid pathname contains a valid directory name, if one appears and + the filename portion should be no more than 8 characters for the + file prefix and 3 characters in the extension (or portion after a + dot). There should be exactly one dot somewhere in the filename + portion and the filename should be composed of only DCHARs. + + True is returned if pathname is valid. + */ +bool +iso9660_pathname_valid_p (const char pathname[]) +{ + const char *p = NULL; + + cdio_assert (pathname != NULL); + + if ((p = strrchr (pathname, '/'))) + { + bool rc; + char *_tmp = strdup (pathname); + + *strrchr (_tmp, '/') = '\0'; + + rc = iso9660_dirname_valid_p (_tmp); + + free (_tmp); + + if (!rc) + return false; + + p++; + } + else + p = pathname; + + if (strlen (pathname) > (MAX_ISOPATHNAME - 6)) + return false; + + { + int len = 0; + int dots = 0; + + for (; *p; p++) + if (iso9660_isdchar (*p)) + { + len++; + if (dots == 0 ? len > 8 : len > 3) + return false; + } + else if (*p == '.') + { + dots++; + if (dots > 1) + return false; + if (!len) + return false; + len = 0; + } + else + return false; + + if (dots != 1) + return false; + } + + return true; +} + +/*! + Take pathname and a version number and turn that into a ISO-9660 + pathname. (That's just the pathname followd by ";" and the version + number. For example, mydir/file.ext -> mydir/file.ext;1 for version + 1. The resulting ISO-9660 pathname is returned. +*/ +char * +iso9660_pathname_isofy (const char pathname[], uint16_t version) +{ + char tmpbuf[1024] = { 0, }; + + cdio_assert (strlen (pathname) < (sizeof (tmpbuf) - sizeof (";65535"))); + + snprintf (tmpbuf, sizeof(tmpbuf), "%s;%d", pathname, version); + + return strdup (tmpbuf); +} + +#if FIXME +lsn_t +iso9660_get_dir_extent(const iso9660_dir_t *idr) +{ + if (NULL == idr) return 0; + return from_733(idr->extent); +} +#endif + +uint8_t +iso9660_get_dir_len(const iso9660_dir_t *idr) +{ + if (NULL == idr) return 0; + return idr->length; +} + +#if FIXME +uint8_t +iso9660_get_dir_size(const iso9660_dir_t *idr) +{ + if (NULL == idr) return 0; + return from_733(idr->size); +} +#endif + +uint8_t +iso9660_get_pvd_type(const iso9660_pvd_t *pvd) +{ + if (NULL == pvd) return 255; + return(pvd->type); +} + +const char * +iso9660_get_pvd_id(const iso9660_pvd_t *pvd) +{ + if (NULL == pvd) return "ERR"; + return(pvd->id); +} + +int +iso9660_get_pvd_space_size(const iso9660_pvd_t *pvd) +{ + if (NULL == pvd) return 0; + return from_733(pvd->volume_space_size); +} + +int +iso9660_get_pvd_block_size(const iso9660_pvd_t *pvd) +{ + if (NULL == pvd) return 0; + return from_723(pvd->logical_block_size); +} + +/*! Return the primary volume id version number (of pvd). + If there is an error 0 is returned. + */ +int +iso9660_get_pvd_version(const iso9660_pvd_t *pvd) +{ + if (NULL == pvd) return 0; + return pvd->version; +} + +/*! Return the LSN of the root directory for pvd. + If there is an error CDIO_INVALID_LSN is returned. + */ +lsn_t +iso9660_get_root_lsn(const iso9660_pvd_t *pvd) +{ + if (NULL == pvd) + return CDIO_INVALID_LSN; + else { + iso9660_dir_t *idr = (void *) pvd->root_directory_record; + if (NULL == idr) return CDIO_INVALID_LSN; + return(from_733 (idr->extent)); + } +} + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/iso9660_fs.c b/src/input/vcd/libcdio/iso9660_fs.c new file mode 100644 index 000000000..b54cf2c0f --- /dev/null +++ b/src/input/vcd/libcdio/iso9660_fs.c @@ -0,0 +1,357 @@ +/* + $Id: iso9660_fs.c,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org> + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + + 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 +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +#include <cdio/cdio.h> +#include <cdio/iso9660.h> +#include <cdio/util.h> + +/* Private headers */ +#include "cdio_assert.h" +#include "bytesex.h" +#include "ds.h" + +#include <stdio.h> + +static const char _rcsid[] = "$Id: iso9660_fs.c,v 1.1 2003/10/13 11:47:12 f1rmb Exp $"; + +static void +_idr2statbuf (const iso9660_dir_t *idr, iso9660_stat_t *stat, bool is_mode2) +{ + iso9660_xa_t *xa_data = NULL; + uint8_t dir_len= iso9660_get_dir_len(idr); + + memset ((void *) stat, 0, sizeof (iso9660_stat_t)); + + if (!dir_len) return; + + stat->type = (idr->file_flags & ISO_DIRECTORY) ? _STAT_DIR : _STAT_FILE; + stat->lsn = from_733 (idr->extent); + stat->size = from_733 (idr->size); + stat->secsize = _cdio_len2blocks (stat->size, ISO_BLOCKSIZE); + + iso9660_get_dtime(&(idr->recording_time), true, &(stat->tm)); + + cdio_assert (dir_len >= sizeof (iso9660_dir_t)); + + if (is_mode2) { + int su_length = iso9660_get_dir_len(idr) - sizeof (iso9660_dir_t); + su_length -= idr->filename_len; + + if (su_length % 2) + su_length--; + + if (su_length < 0 || su_length < sizeof (iso9660_xa_t)) + return; + + xa_data = (void *) (((char *) idr) + (iso9660_get_dir_len(idr) - su_length)); + + if (xa_data->signature[0] != 'X' + || xa_data->signature[1] != 'A') + { + cdio_warn ("XA signature not found in ISO9660's system use area;" + " ignoring XA attributes for this file entry."); + cdio_debug ("%d %d %d, '%c%c' (%d, %d)", iso9660_get_dir_len(idr), + idr->filename_len, + su_length, + xa_data->signature[0], xa_data->signature[1], + xa_data->signature[0], xa_data->signature[1]); + return; + } + stat->xa = *xa_data; + } + +} + +static char * +_idr2name (const iso9660_dir_t *idr) +{ + char namebuf[256] = { 0, }; + uint8_t len=iso9660_get_dir_len(idr); + + if (!len) return NULL; + + cdio_assert (len >= sizeof (iso9660_dir_t)); + + /* (idr->file_flags & ISO_DIRECTORY) */ + + if (idr->filename[0] == '\0') + strcpy (namebuf, "."); + else if (idr->filename[0] == '\1') + strcpy (namebuf, ".."); + else + strncpy (namebuf, idr->filename, idr->filename_len); + + return strdup (namebuf); +} + + +static void +_fs_stat_root (const CdIo *cdio, iso9660_stat_t *stat, bool is_mode2) +{ + char block[ISO_BLOCKSIZE] = { 0, }; + const iso9660_pvd_t *pvd = (void *) █ + const iso9660_dir_t *idr = (void *) pvd->root_directory_record; + + if (is_mode2) { + if (cdio_read_mode2_sector (cdio, &block, ISO_PVD_SECTOR, false)) + cdio_assert_not_reached (); + } else { + if (cdio_read_mode1_sector (cdio, &block, ISO_PVD_SECTOR, false)) + cdio_assert_not_reached (); + } + + _idr2statbuf (idr, stat, is_mode2); +} + +static int +_fs_stat_traverse (const CdIo *cdio, const iso9660_stat_t *_root, + char **splitpath, /*out*/ iso9660_stat_t *buf, + bool is_mode2) +{ + unsigned offset = 0; + uint8_t *_dirbuf = NULL; + + if (!splitpath[0]) + { + *buf = *_root; + return 0; + } + + if (_root->type == _STAT_FILE) + return -1; + + cdio_assert (_root->type == _STAT_DIR); + + if (_root->size != ISO_BLOCKSIZE * _root->secsize) + { + cdio_warn ("bad size for ISO9660 directory (%ud) should be (%lu)!", + (unsigned) _root->size, + (unsigned long int) ISO_BLOCKSIZE * _root->secsize); + } + + _dirbuf = _cdio_malloc (_root->secsize * ISO_BLOCKSIZE); + + if (is_mode2) { + if (cdio_read_mode2_sectors (cdio, _dirbuf, _root->lsn, false, + _root->secsize)) + cdio_assert_not_reached (); + } else { + if (cdio_read_mode1_sectors (cdio, _dirbuf, _root->lsn, false, + _root->secsize)) + cdio_assert_not_reached (); + } + + while (offset < (_root->secsize * ISO_BLOCKSIZE)) + { + const iso9660_dir_t *idr = (void *) &_dirbuf[offset]; + iso9660_stat_t stat; + char *name; + + if (!iso9660_get_dir_len(idr)) + { + offset++; + continue; + } + + name = _idr2name (idr); + _idr2statbuf (idr, &stat, is_mode2); + + if (!strcmp (splitpath[0], name)) + { + int retval = _fs_stat_traverse (cdio, &stat, &splitpath[1], buf, + is_mode2); + free (name); + free (_dirbuf); + return retval; + } + + free (name); + + offset += iso9660_get_dir_len(idr); + } + + cdio_assert (offset == (_root->secsize * ISO_BLOCKSIZE)); + + /* not found */ + free (_dirbuf); + return -1; +} + +/*! + Get file status for pathname into stat. As with libc's stat, 0 is returned + if no error and -1 on error. + */ +int +iso9660_fs_stat (const CdIo *cdio, const char pathname[], + /*out*/ iso9660_stat_t *stat, bool is_mode2) +{ + iso9660_stat_t _root; + int retval; + char **splitpath; + + cdio_assert (cdio != NULL); + cdio_assert (pathname != NULL); + cdio_assert (stat != NULL); + + _fs_stat_root (cdio, &_root, is_mode2); + + splitpath = _cdio_strsplit (pathname, '/'); + retval = _fs_stat_traverse (cdio, &_root, splitpath, stat, is_mode2); + _cdio_strfreev (splitpath); + + return retval; +} + +void * /* list of char* -- caller must free it */ +iso9660_fs_readdir (const CdIo *cdio, const char pathname[], bool is_mode2) +{ + iso9660_stat_t stat; + + cdio_assert (cdio != NULL); + cdio_assert (pathname != NULL); + + if (iso9660_fs_stat (cdio, pathname, &stat, is_mode2)) + return NULL; + + if (stat.type != _STAT_DIR) + return NULL; + + { + unsigned offset = 0; + uint8_t *_dirbuf = NULL; + CdioList *retval = _cdio_list_new (); + + if (stat.size != ISO_BLOCKSIZE * stat.secsize) + { + cdio_warn ("bad size for ISO9660 directory (%ud) should be (%lu)!", + (unsigned) stat.size, + (unsigned long int) ISO_BLOCKSIZE * stat.secsize); + } + + _dirbuf = _cdio_malloc (stat.secsize * ISO_BLOCKSIZE); + + if (is_mode2) { + if (cdio_read_mode2_sectors (cdio, _dirbuf, stat.lsn, false, + stat.secsize)) + cdio_assert_not_reached (); + } else { + if (cdio_read_mode1_sectors (cdio, _dirbuf, stat.lsn, false, + stat.secsize)) + cdio_assert_not_reached (); + } + + while (offset < (stat.secsize * ISO_BLOCKSIZE)) + { + const iso9660_dir_t *idr = (void *) &_dirbuf[offset]; + + if (!iso9660_get_dir_len(idr)) + { + offset++; + continue; + } + + _cdio_list_append (retval, _idr2name (idr)); + + offset += iso9660_get_dir_len(idr); + } + + cdio_assert (offset == (stat.secsize * ISO_BLOCKSIZE)); + + free (_dirbuf); + return retval; + } +} + +static bool +find_fs_lsn_recurse (const CdIo *cdio, const char pathname[], + /*out*/ iso9660_stat_t *statbuf, lsn_t lsn) +{ + CdioList *entlist = iso9660_fs_readdir (cdio, pathname, true); + CdioList *dirlist = _cdio_list_new (); + CdioListNode *entnode; + + cdio_assert (entlist != NULL); + + /* iterate over each entry in the directory */ + + _CDIO_LIST_FOREACH (entnode, entlist) + { + char *name = _cdio_list_node_data (entnode); + char _fullname[4096] = { 0, }; + + snprintf (_fullname, sizeof (_fullname), "%s%s", pathname, name); + + if (iso9660_fs_stat (cdio, _fullname, statbuf, true)) + cdio_assert_not_reached (); + + strncat (_fullname, "/", sizeof (_fullname)); + + if (statbuf->type == _STAT_DIR + && strcmp (name, ".") + && strcmp (name, "..")) + _cdio_list_append (dirlist, strdup (_fullname)); + + if (statbuf->lsn == lsn) { + _cdio_list_free (entlist, true); + _cdio_list_free (dirlist, true); + return true; + } + + } + + _cdio_list_free (entlist, true); + + /* now recurse/descend over directories encountered */ + + _CDIO_LIST_FOREACH (entnode, dirlist) + { + char *_fullname = _cdio_list_node_data (entnode); + + if (find_fs_lsn_recurse (cdio, _fullname, statbuf, lsn)) { + _cdio_list_free (dirlist, true); + return true; + } + } + + _cdio_list_free (dirlist, true); + return false; +} + +/*! + Given a directory pointer, find the filesystem entry that contains + lsn and return information about it in stat. + + Returns true if we found an entry with the lsn and false if not. + */ +bool +iso9660_find_fs_lsn(const CdIo *cdio, lsn_t lsn, /*out*/ iso9660_stat_t *stat) +{ + return find_fs_lsn_recurse (cdio, "/", stat, lsn); +} + diff --git a/src/input/vcd/libcdio/iso9660_private.h b/src/input/vcd/libcdio/iso9660_private.h new file mode 100644 index 000000000..411664c38 --- /dev/null +++ b/src/input/vcd/libcdio/iso9660_private.h @@ -0,0 +1,85 @@ +/* + $Id: iso9660_private.h,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + + See also iso9660.h by Eric Youngdale (1993). + + Copyright 1993 Yggdrasil Computing, Incorporated + Copyright (c) 1999,2000 J. Schilling + + 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 +*/ + +#ifndef __CDIO_ISO9660_PRIVATE_H__ +#define __CDIO_ISO9660_PRIVATE_H__ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <cdio/types.h> + +#define ISO_VERSION 1 + +PRAGMA_BEGIN_PACKED + +struct iso_volume_descriptor { + uint8_t type; /* 711 */ + char id[5]; + uint8_t version; /* 711 */ + char data[2041]; +} GNUC_PACKED; + +#define struct_iso_volume_descriptor_SIZEOF ISO_BLOCKSIZE + +#define struct_iso9660_pvd_SIZEOF ISO_BLOCKSIZE + +/* + * XXX JS: The next structure has an odd length! + * Some compilers (e.g. on Sun3/mc68020) padd the structures to even length. + * For this reason, we cannot use sizeof (struct iso_path_table) or + * sizeof (struct iso_directory_record) to compute on disk sizes. + * Instead, we use offsetof(..., name) and add the name size. + * See mkisofs.h + */ + +/* We use this to help us look up the parent inode numbers. */ + +struct iso_path_table { + uint8_t name_len; /* 711 */ + uint8_t xa_len; /* 711 */ + uint32_t extent; /* 731/732 */ + uint16_t parent; /* 721/722 */ + char name[EMPTY_ARRAY_SIZE]; +} GNUC_PACKED; + +#define struct_iso_path_table_SIZEOF 8 + +#define struct_iso9660_dir_SIZEOF 33 + +PRAGMA_END_PACKED + +#endif /* __CDIO_ISO9660_PRIVATE_H__ */ + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/logging.c b/src/input/vcd/libcdio/logging.c new file mode 100644 index 000000000..522d98d9a --- /dev/null +++ b/src/input/vcd/libcdio/logging.c @@ -0,0 +1,142 @@ +/* + $Id: logging.c,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + + 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 +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> + +#include <cdio/logging.h> +#include "cdio_assert.h" + + +static const char _rcsid[] = "$Id: logging.c,v 1.1 2003/10/13 11:47:12 f1rmb Exp $"; + +int cdio_loglevel_default = CDIO_LOG_WARN; + +static void +default_cdio_log_handler (cdio_log_level_t level, const char message[]) +{ + switch (level) + { + case CDIO_LOG_ERROR: + if (level >= cdio_loglevel_default) { + fprintf (stderr, "**ERROR: %s\n", message); + fflush (stderr); + } + exit (EXIT_FAILURE); + break; + case CDIO_LOG_DEBUG: + if (level >= cdio_loglevel_default) { + fprintf (stdout, "--DEBUG: %s\n", message); + } + break; + case CDIO_LOG_WARN: + if (level >= cdio_loglevel_default) { + fprintf (stdout, "++ WARN: %s\n", message); + } + break; + case CDIO_LOG_INFO: + if (level >= cdio_loglevel_default) { + fprintf (stdout, " INFO: %s\n", message); + } + break; + case CDIO_LOG_ASSERT: + if (level >= cdio_loglevel_default) { + fprintf (stderr, "!ASSERT: %s\n", message); + fflush (stderr); + } + abort (); + break; + default: + cdio_assert_not_reached (); + break; + } + + fflush (stdout); +} + +static cdio_log_handler_t _handler = default_cdio_log_handler; + +cdio_log_handler_t +cdio_log_set_handler (cdio_log_handler_t new_handler) +{ + cdio_log_handler_t old_handler = _handler; + + _handler = new_handler; + + return old_handler; +} + +static void +cdio_logv (cdio_log_level_t level, const char format[], va_list args) +{ + char buf[1024] = { 0, }; + static int in_recursion = 0; + + if (in_recursion) + cdio_assert_not_reached (); + + in_recursion = 1; + + vsnprintf(buf, sizeof(buf)-1, format, args); + + _handler(level, buf); + + in_recursion = 0; +} + +void +cdio_log (cdio_log_level_t level, const char format[], ...) +{ + va_list args; + va_start (args, format); + cdio_logv (level, format, args); + va_end (args); +} + +#define CDIO_LOG_TEMPLATE(level, LEVEL) \ +void \ +cdio_ ## level (const char format[], ...) \ +{ \ + va_list args; \ + va_start (args, format); \ + cdio_logv (CDIO_LOG_ ## LEVEL, format, args); \ + va_end (args); \ +} + +CDIO_LOG_TEMPLATE(debug, DEBUG) +CDIO_LOG_TEMPLATE(info, INFO) +CDIO_LOG_TEMPLATE(warn, WARN) +CDIO_LOG_TEMPLATE(error, ERROR) + +#undef CDIO_LOG_TEMPLATE + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/scsi_mmc.h b/src/input/vcd/libcdio/scsi_mmc.h new file mode 100644 index 000000000..a0c22a86f --- /dev/null +++ b/src/input/vcd/libcdio/scsi_mmc.h @@ -0,0 +1,63 @@ +/* + $Id: scsi_mmc.h,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + + 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 file contains common definitions/routines for SCSI MMC + (Multimedia commands). +*/ + +#ifndef __SCSI_MMC_H__ +#define __SCSI_MMC_H__ + +/* Leval values that can go into READ_CD */ +#define CDIO_MMC_READ_TYPE_ANY 0 /* All types */ +#define CDIO_MMC_READ_TYPE_CDDA 1 /* Only CD-DA sectors */ +#define CDIO_MMC_READ_TYPE_MODE1 2 /* Only mode1 sectors (user data = 2048) */ +#define CDIO_MMC_READ_TYPE_MODE2 3 /* mode2 sectors form1 or form2 */ +#define CDIO_MMC_READ_TYPE_M2F1 4 /* mode2 sectors form1 */ +#define CDIO_MMC_READ_TYPE_M2F2 5 /* mode2 sectors form2 */ + +/* The generic packet command opcodes for CD/DVD Logical Units, + * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ +#define CDIO_MMC_GPCMD_READ_CD 0xbe +#define CDIO_MMC_GPCMD_READ_10 0x28 +#define CDIO_MMC_GPCMD_READ_12 0xa8 + +#define CDIO_MMC_SET_READ_TYPE(rec, sector_type) \ + rec[1] = (sector_type << 2) + + +#define CDIO_MMC_SET_READ_LBA(rec, lba) \ + rec[2] = (lba >> 24) & 0xff; \ + rec[3] = (lba >> 16) & 0xff; \ + rec[4] = (lba >> 8) & 0xff; \ + rec[5] = (lba ) & 0xff + +#define CDIO_MMC_SET_READ_LENGTH(rec, len) \ + rec[6] = (len >> 16) & 0xff; \ + rec[7] = (len >> 8) & 0xff; \ + rec[8] = (len ) & 0xff + +#define CDIO_MMC_MCSB_ALL_HEADERS 0x78 + +#define CDIO_MMC_SET_MAIN_CHANNEL_SELECTION_BITS(rec, val) \ + rec[9] = val; + +#endif /* __SCSI_MMC_H__ */ diff --git a/src/input/vcd/libcdio/sector.c b/src/input/vcd/libcdio/sector.c new file mode 100644 index 000000000..24082bc2d --- /dev/null +++ b/src/input/vcd/libcdio/sector.c @@ -0,0 +1,111 @@ +/* + $Id: sector.c,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + + 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 +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <cdio/sector.h> +#include <cdio/util.h> +#include "cdio_assert.h" + +#include <stdio.h> +#ifdef HAVE_STRING_H +#include <string.h> +#endif + + +static const char _rcsid[] = "$Id: sector.c,v 1.1 2003/10/13 11:47:12 f1rmb Exp $"; + +lba_t +cdio_lba_to_lsn (lba_t lba) +{ + return lba - CDIO_PREGAP_SECTORS; +} + +void +cdio_lba_to_msf (lba_t lba, msf_t *msf) +{ + cdio_assert (msf != 0); + + msf->m = to_bcd8 (lba / (60 * 75)); + msf->s = to_bcd8 ((lba / 75) % 60); + msf->f = to_bcd8 (lba % 75); +} + +/* warning, returns new allocated string */ +char * +cdio_lba_to_msf_str (lba_t lba) +{ + char buf[16]; + msf_t _msf = { .m = 0, .s = 0, .f = 0 }; + + cdio_lba_to_msf (lba, &_msf); + + snprintf (buf, sizeof (buf), "%.2x:%.2x.%.2x", _msf.m, _msf.s, _msf.f); + + return strdup (buf); +} + +lba_t +cdio_lsn_to_lba (lsn_t lsn) +{ + return lsn + CDIO_PREGAP_SECTORS; +} + +void +cdio_lsn_to_msf (lsn_t lsn, msf_t *msf) +{ + cdio_assert (msf != 0); + cdio_lba_to_msf(cdio_lsn_to_lba(lsn), msf); +} + +uint32_t +cdio_msf_to_lba (const msf_t *msf) +{ + uint32_t lba = 0; + + cdio_assert (msf != 0); + + lba = from_bcd8 (msf->m); + lba *= 60; + + lba += from_bcd8 (msf->s); + lba *= 75; + + lba += from_bcd8 (msf->f); + + return lba; +} + +uint32_t +cdio_msf_to_lsn (const msf_t *msf) +{ + return cdio_lba_to_lsn(cdio_msf_to_lba (msf)); +} + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/util.c b/src/input/vcd/libcdio/util.c new file mode 100644 index 000000000..3b5b832cc --- /dev/null +++ b/src/input/vcd/libcdio/util.c @@ -0,0 +1,192 @@ +/* + $Id: util.c,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + + 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 +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "cdio_assert.h" +#include <cdio/util.h> + +static const char _rcsid[] = "$Id: util.c,v 1.1 2003/10/13 11:47:12 f1rmb Exp $"; + +size_t +_cdio_strlenv(char **str_array) +{ + size_t n = 0; + + cdio_assert (str_array != NULL); + + while(str_array[n]) + n++; + + return n; +} + +void +_cdio_strfreev(char **strv) +{ + int n; + + cdio_assert (strv != NULL); + + for(n = 0; strv[n]; n++) + free(strv[n]); + + free(strv); +} + +char * +_cdio_strjoin (char *strv[], unsigned count, const char delim[]) +{ + size_t len; + char *new_str; + unsigned n; + + cdio_assert (strv != NULL); + cdio_assert (delim != NULL); + + len = (count-1) * strlen (delim); + + for (n = 0;n < count;n++) + len += strlen (strv[n]); + + len++; + + new_str = _cdio_malloc (len); + new_str[0] = '\0'; + + for (n = 0;n < count;n++) + { + if (n) + strcat (new_str, delim); + strcat (new_str, strv[n]); + } + + return new_str; +} + +char ** +_cdio_strsplit(const char str[], char delim) /* fixme -- non-reentrant */ +{ + int n; + char **strv = NULL; + char *_str, *p; + char _delim[2] = { 0, 0 }; + + cdio_assert (str != NULL); + + _str = strdup(str); + _delim[0] = delim; + + cdio_assert (_str != NULL); + + n = 1; + p = _str; + while(*p) + if (*(p++) == delim) + n++; + + strv = _cdio_malloc (sizeof (char *) * (n+1)); + + n = 0; + while((p = strtok(n ? NULL : _str, _delim)) != NULL) + strv[n++] = strdup(p); + + free(_str); + + return strv; +} + +void * +_cdio_malloc (size_t size) +{ + void *new_mem = malloc (size); + + cdio_assert (new_mem != NULL); + + memset (new_mem, 0, size); + + return new_mem; +} + +void * +_cdio_memdup (const void *mem, size_t count) +{ + void *new_mem = NULL; + + if (mem) + { + new_mem = _cdio_malloc (count); + memcpy (new_mem, mem, count); + } + + return new_mem; +} + +char * +_cdio_strdup_upper (const char str[]) +{ + char *new_str = NULL; + + if (str) + { + char *p; + + p = new_str = strdup (str); + + while (*p) + { + *p = toupper (*p); + p++; + } + } + + return new_str; +} + +uint8_t +to_bcd8 (uint8_t n) +{ + cdio_assert (n < 100); + + return ((n/10)<<4) | (n%10); +} + +uint8_t +from_bcd8(uint8_t p) +{ + return (0xf & p)+(10*(p >> 4)); +} + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/input/vcd/libcdio/xa.c b/src/input/vcd/libcdio/xa.c new file mode 100644 index 000000000..31c5e110a --- /dev/null +++ b/src/input/vcd/libcdio/xa.c @@ -0,0 +1,136 @@ +/* + $Id: xa.c,v 1.1 2003/10/13 11:47:12 f1rmb Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> + Copyright (C) 2003 Rocky Bernstein <rocky@panix.com> + + 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 +*/ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +/* Public headers */ +#include <cdio/iso9660.h> +#include <cdio/util.h> + +/* Private headers */ +#include "cdio_assert.h" +#include "bytesex.h" + +#define BUF_COUNT 16 +#define BUF_SIZE 80 + +/* Return a pointer to a internal free buffer */ +static char * +_getbuf (void) +{ + static char _buf[BUF_COUNT][BUF_SIZE]; + static int _num = -1; + + _num++; + _num %= BUF_COUNT; + + memset (_buf[_num], 0, BUF_SIZE); + + return _buf[_num]; +} + +/*! + Returns a string which interpreting the extended attribute xa_attr. + For example: + \verbatim + d---1xrxrxr + ---2--r-r-r + -a--1xrxrxr + \endverbatim + + A description of the characters in the string follows + The 1st character is either "d" if the entry is a directory, or "-" if not. + The 2nd character is either "a" if the entry is CDDA (audio), or "-" if not. + The 3rd character is either "i" if the entry is interleaved, or "-" if not. + The 4th character is either "2" if the entry is mode2 form2 or "-" if not. + The 5th character is either "1" if the entry is mode2 form1 or "-" if not. + Note that an entry will either be in mode2 form1 or mode form2. That + is you will either see "2-" or "-1" in the 4th & 5th positions. + + The 6th and 7th characters refer to permissions for a user while the + the 8th and 9th characters refer to permissions for a group while, and + the 10th and 11th characters refer to permissions for a others. + + In each of these pairs the first character (6, 8, 10) is "x" if the + entry is executable. For a directory this means the directory is + allowed to be listed or "searched". + The second character of a pair (7, 9, 11) is "r" if the entry is allowed + to be read. +*/ + +const char * +iso9660_get_xa_attr_str (uint16_t xa_attr) +{ + char *result = _getbuf(); + + xa_attr = uint16_from_be (xa_attr); + + result[ 0] = (xa_attr & XA_ATTR_DIRECTORY) ? 'd' : '-'; + result[ 1] = (xa_attr & XA_ATTR_CDDA) ? 'a' : '-'; + result[ 2] = (xa_attr & XA_ATTR_INTERLEAVED) ? 'i' : '-'; + result[ 3] = (xa_attr & XA_ATTR_MODE2FORM2) ? '2' : '-'; + result[ 4] = (xa_attr & XA_ATTR_MODE2FORM1) ? '1' : '-'; + + result[ 5] = (xa_attr & XA_PERM_XUSR) ? 'x' : '-'; + result[ 6] = (xa_attr & XA_PERM_RUSR) ? 'r' : '-'; + + result[ 7] = (xa_attr & XA_PERM_XGRP) ? 'x' : '-'; + result[ 8] = (xa_attr & XA_PERM_RGRP) ? 'r' : '-'; + + /* Hack alert: wonder if this should be ROTH and XOTH? */ + result[ 9] = (xa_attr & XA_PERM_XSYS) ? 'x' : '-'; + result[10] = (xa_attr & XA_PERM_RSYS) ? 'r' : '-'; + + result[11] = '\0'; + + return result; +} + +iso9660_xa_t * +iso9660_xa_init (iso9660_xa_t *_xa, uint16_t uid, uint16_t gid, uint16_t attr, + uint8_t filenum) +{ + cdio_assert (_xa != NULL); + + _xa->user_id = uint16_to_be (uid); + _xa->group_id = uint16_to_be (gid); + _xa->attributes = uint16_to_be (attr); + + _xa->signature[0] = 'X'; + _xa->signature[1] = 'A'; + + _xa->filenum = filenum; + + _xa->reserved[0] + = _xa->reserved[1] + = _xa->reserved[2] + = _xa->reserved[3] + = _xa->reserved[4] = 0x00; + + return _xa; +} |