First commit after CVS conversion. Should be just administrative changes.

This commit is contained in:
R. Bernstein
2008-11-29 00:56:26 -05:00
parent 4ea407f746
commit 95f087cdc3
413 changed files with 86786 additions and 86 deletions

2
lib/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/Makefile
/Makefile.in

30
lib/Makefile.am Normal file
View File

@@ -0,0 +1,30 @@
# $Id: Makefile.am,v 1.70 2008/03/20 19:02:38 karl Exp $
#
# Copyright (C) 2003, 2004, 2006, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
#
########################################################
# make all libraries
########################################################
if BUILD_CD_PARANOIA
paranoiadirs = cdda_interface paranoia
endif
if ENABLE_CXX_BINDINGS
cxxdirs = cdio++
endif
SUBDIRS = driver iso9660 udf $(paranoiadirs) $(cxxdirs)

View File

@@ -0,0 +1,8 @@
.deps
.libs
Makefile
Makefile.in
*.o
*.lo
*.la
*.la.ver

3
lib/cdda_interface/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/.deps
/Makefile
/Makefile.in

View File

@@ -0,0 +1,152 @@
# $Id: Makefile.am,v 1.16 2008/10/20 01:25:10 rocky Exp $
#
# Copyright (C) 2004, 2005, 2006, 2007, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
########################################################
# Things to make the cdda_interface library
########################################################
#
# From libtool documentation amended with guidance from N. Boullis:
#
# 1. Start with version information of `0:0:0' for each libtool library.
#
# 2. It is probably not a good idea to update the version information
# several times between public releases, but rather once per public
# release. (This seems to be more an aesthetic consideration than
# a hard technical one.)
#
# 3. If the library source code has changed at all since the last
# update, then increment REVISION (`C:R:A' becomes `C:R+1:A').
#
# 4. If any interfaces have been added, removed, or changed since the
# last update, increment CURRENT, and set REVISION to 0.
#
# 5. If any interfaces have been added since the last public release,
# then increment AGE.
#
# 6. If any interfaces have been removed or changed since the last
# public release, then set AGE to 0. A changed interface means an
# incompatibility with previous versions.
EXTRA_DIST = libcdio_cdda.sym
libcdio_cdda_la_CURRENT = 0
libcdio_cdda_la_REVISION = 5
libcdio_cdda_la_AGE = 0
noinst_HEADERS = common_interface.h drive_exceptions.h low_interface.h \
smallft.h utils.h
libcdio_cdda_sources = common_interface.c cddap_interface.c interface.c \
scan_devices.c smallft.c toc.c utils.c drive_exceptions.c
lib_LTLIBRARIES = libcdio_cdda.la
libcdio_cdda_la_SOURCES = $(libcdio_cdda_sources)
libcdio_cdda_la_ldflags = -version-info $(libcdio_cdda_la_CURRENT):$(libcdio_cdda_la_REVISION):$(libcdio_cdda_la_AGE) @LT_NO_UNDEFINED@
INCLUDES = $(LIBCDIO_CFLAGS)
FLAGS=@LIBCDIO_CFLAGS@ @UCDROM_H@ @TYPESIZES@ @CFLAGS@
OPT=$(FLAGS)
DEBUG=$(FLAGS) -DCDDA_TEST
## test:
## $(MAKE) libcdio_cdda.a CFLAGS="$(DEBUG)"
## $(CC) $(DEBUG) -c test_interface.c
## $(LD) $(DEBUG) test_interface.o $(LDFLAGS) -o cdda_test $(LIBS) libcdio_cdda.a
LIBS = $(LIBCDIO_LIBS) @COS_LIB@
########################################################
# Things to version the symbols in the libraries
########################################################
# An explanation of the versioning problem from Nicolas Boullis and
# the versioned symbol solution he uses below...
#
# Currently, libvcdinfo uses the cdio_open function from libcdio.
# Let's imagine a program foobar that uses both the vcdinfo_open
# function from libvcdinfo and the cdio_open function from libcdio.
# Currently, libcdio has SONAME libcdio.so.0, libvcdinfo has SONAME
# libvcdinfo.so.0 and requires libcdio.so.0, and foobar requires both
# libvcdinfo.so.0 and libcdio.so.0. Everything looks fine.
#
# Now, for some reason, you decide to change the cdio_open function.
# That's your right, but you have to bump the CURRENT version and (if I
# understand it correctly, athough this is not that clear in libtool's
# documentation) set the AGE to 0. Anyway, this bumps the SONAME, which is
# sane since the interface changes incompatibly.
# Now, you have a new libcdio with SONAME libcdio.so.1. But libvcdinfo and
# foobar still require libcdio.so.0. Everything is still fine.
# Now, after some minor changes, the author of foobar recompiles foobar.
# Then, foobar now requires libvcdinfo.so.0 and libcdio.so.1. And foobar
# now segfaults...
# What is happening? When you run foobar, if brings both libvcdinfo.so.0
# and libcdio.so.1, but libvcdinfo.so.0 also brings libcdio.so.0. So you
# have both libcdio.so.0 and libcdio.so.1 that bring their symbols to the
# global namespace. Hence, you have to incompatible versions of the
# cdio_open function in the name space. When foobar calls cdio_open, it
# may choose the wrong function, and segfaults...
# With versioned symbols, the cdio_open function from libcdio.so.0 may be
# known as (something that looks like) cdio_open@@CDIO_0. An the cdio_open
# function from libcdio.so.1 as cdio_open@@CDIO_1. Both versions of
# libcdio would still be brought in by the most recent foobar, but foobar
# (and libvcdinfo) know which versioned function to use and then use the
# good one.
# This is some simple versioning where every symbol is versioned with
# something that looks like the SONAME of the library. More complex (and
# better) versioning is possible; it is for example what is used by glibc.
# But good complex versioning is something that requires much more
# work...
# The below is a impliments symbol versioning. First of all, I
# compute MAJOR as CURENT - AGE; that is what is used within libtool
# (at least on GNU/Linux systems) for the number in the SONAME. The
# nm command gives the list of symbols known in each of the object
# files that will be part of the shared library. And the sed command
# extracts from this list those symbols that will be shared. (This sed
# command comes from libtool.)
libcdio_cdda_la_MAJOR = $(shell expr $(libcdio_cdda_la_CURRENT) - $(libcdio_cdda_la_AGE))
if BUILD_VERSIONED_LIBS
libcdio_cdda_la_LDFLAGS = $(libcdio_cdda_la_ldflags) -Wl,--version-script=libcdio_cdda.la.ver
libcdio_cdda_la_DEPENDENCIES = libcdio_cdda.la.ver
libcdio_cdda.la.ver: $(libcdio_cdda_la_OBJECTS) $(srcdir)/libcdio_cdda.sym
echo 'CDIO_CDDA_$(libcdio_cdda_la_MAJOR) { ' > $@
objs=`for obj in $(libcdio_cdda_la_OBJECTS); do sed -ne "s/^pic_object='\(.*\)'$$/\1/p" $$obj; done`; \
if test -n "$$objs" ; then \
nm $${objs} | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | { first=true; while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio_cdda.sym; then if test $$first = true; then echo " global:"; first=false; fi; echo " $${symbol};"; fi; done; } >> $@; \
nm $${objs} | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | { first=true; while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio_cdda.sym; then :; else if test $$first = true; then echo " local:"; first=false; fi; echo " $${symbol};"; fi; done; } >> $@; \
fi
echo '};' >> $@
else
libcdio_cdda_la_LDFLAGS = $(libcdio_cdda_la_ldflags)
endif
MOSTLYCLEANFILES = libcdio_cdda.la.ver

View File

@@ -0,0 +1,401 @@
/*
$Id: cddap_interface.c,v 1.8 2008/06/13 19:26:22 flameeyes Exp $
Copyright (C) 2004, 2005, 2007, 2008 Rocky Bernstein <rocky@gnu.org>
Original interface.c Copyright (C) 1994-1997
Eissfeldt heiko@colossus.escape.de
Current blenderization Copyright (C) 1998-1999 Monty xiphmont@mit.edu
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
/**
CD-ROM code which interfaces between user-level visible CD paranoia
routines and libddio routines. (There is some GNU/Linux-specific
code here too that should probably be removed.
**/
#include "config.h"
#include "common_interface.h"
#include "low_interface.h"
#include "utils.h"
/** The below variables are trickery to force the above enum symbol
values to be recorded in debug symbol tables. They are used to
allow one to refer to the enumeration value names in the typedefs
above in a debugger and debugger expressions
*/
paranoia_jitter_t debug_paranoia_jitter;
paranoia_cdda_enums_t debug_paranoia_cdda_enums;
/*! reads TOC via libcdio and returns the number of tracks in the disc.
0 is returned if there was an error.
*/
static int
cddap_readtoc (cdrom_drive_t *d)
{
int i;
track_t i_track;
/* Save TOC Entries */
d->tracks = cdio_get_num_tracks(d->p_cdio) ;
if (CDIO_INVALID_TRACK == d->tracks) return 0;
i_track = cdio_get_first_track_num(d->p_cdio);
for ( i=0; i < d->tracks; i++) {
d->disc_toc[i].bTrack = i_track;
d->disc_toc[i].dwStartSector = cdio_get_track_lsn(d->p_cdio, i_track);
i_track++;
}
d->disc_toc[i].bTrack = i_track;
d->disc_toc[i].dwStartSector = cdio_get_track_lsn(d->p_cdio,
CDIO_CDROM_LEADOUT_TRACK);
d->cd_extra=FixupTOC(d, i_track);
return --i_track; /* without lead-out */
}
/* Set operating speed */
static int
cddap_setspeed(cdrom_drive_t *d, int i_speed)
{
return cdio_set_speed(d->p_cdio, i_speed);
}
/* read 'i_sector' adjacent audio sectors
* into buffer '*p' beginning at sector 'begin'
*/
static long int
read_blocks (cdrom_drive_t *d, void *p, lsn_t begin, long i_sectors)
{
int retry_count = 0;
int err;
char *buffer=(char *)p;
do {
err = cdio_read_audio_sectors( d->p_cdio, buffer, begin, i_sectors);
if ( DRIVER_OP_SUCCESS != err ) {
if (!d->error_retry) return -7;
if (i_sectors==1) {
/* *Could* be I/O or media error. I think. If we're at
30 retries, we better skip this unhappy little
sector. */
if (retry_count>MAX_RETRIES-1) {
char b[256];
snprintf(b, sizeof(b),
"010: Unable to access sector %ld: skipping...\n",
(long int) begin);
cderror(d, b);
return -10;
}
}
if(retry_count>4)
if(i_sectors>1)
i_sectors=i_sectors*3/4;
retry_count++;
if (retry_count>MAX_RETRIES) {
cderror(d,"007: Unknown, unrecoverable error reading data\n");
return(-7);
}
} else
break;
} while (err);
return(i_sectors);
}
typedef enum {
JITTER_NONE = 0,
JITTER_SMALL= 1,
JITTER_LARGE= 2,
JITTER_MASSIVE=3
} jitter_baddness_t;
/* read 'i_sector' adjacent audio sectors
* into buffer '*p' beginning at sector 'begin'
*/
static long int
jitter_read (cdrom_drive_t *d, void *p, lsn_t begin, long i_sectors,
jitter_baddness_t jitter_badness)
{
static int i_jitter=0;
int jitter_flag;
long i_sectors_orig = i_sectors;
long i_jitter_offset = 0;
char *p_buf=malloc(CDIO_CD_FRAMESIZE_RAW*(i_sectors+1));
if (d->i_test_flags & CDDA_TEST_ALWAYS_JITTER)
jitter_flag = 1;
else
#ifdef HAVE_DRAND48
jitter_flag = (drand48() > .9) ? 1 : 0;
#else
jitter_flag = (rand() > .9) ? 1 : 0;
#endif
if (jitter_flag) {
int i_coeff = 0;
int i_jitter_sectors = 0;
switch(jitter_badness) {
case JITTER_SMALL : i_coeff = 4; break;
case JITTER_LARGE : i_coeff = 32; break;
case JITTER_MASSIVE: i_coeff = 128; break;
case JITTER_NONE :
default : ;
}
#ifdef HAVE_DRAND48
i_jitter = i_coeff * (int)((drand48()-.5)*CDIO_CD_FRAMESIZE_RAW/8);
#else
i_jitter = i_coeff * (int)((rand()-.5)*CDIO_CD_FRAMESIZE_RAW/8);
#endif
/* We may need to add another sector to compensate for the bytes that
will be dropped off when jittering, and the begin location may
be a little different.
*/
i_jitter_sectors = i_jitter / CDIO_CD_FRAMESIZE_RAW;
if (i_jitter >= 0)
i_jitter_offset = i_jitter % CDIO_CD_FRAMESIZE_RAW;
else {
i_jitter_offset = CDIO_CD_FRAMESIZE_RAW -
(-i_jitter % CDIO_CD_FRAMESIZE_RAW);
i_jitter_sectors--;
}
if (begin + i_jitter_sectors > 0) {
#if !TRACE_PARANOIA
char buffer[256];
sprintf(buffer, "jittering by %d, offset %ld\n", i_jitter,
i_jitter_offset);
cdmessage(d,buffer);
#endif
begin += i_jitter_sectors;
i_sectors ++;
} else
i_jitter_offset = 0;
}
i_sectors = read_blocks(d, p_buf, begin, i_sectors);
if (i_sectors < 0) return i_sectors;
if (i_sectors < i_sectors_orig)
/* Had to reduce # of sectors due to read errors. So give full amount,
with no jittering. */
memcpy(p, p_buf, i_sectors*CDIO_CD_FRAMESIZE_RAW);
else {
/* Got full amount, but now adjust size for jittering. */
memcpy(p, p_buf+i_jitter_offset, i_sectors_orig*CDIO_CD_FRAMESIZE_RAW);
i_sectors = i_sectors_orig;
}
free(p_buf);
return(i_sectors);
}
/* read 'i_sector' adjacent audio sectors
* into buffer '*p' beginning at sector 'begin'
*/
static long int
cddap_read (cdrom_drive_t *d, void *p, lsn_t begin, long i_sectors)
{
jitter_baddness_t jitter_badness = d->i_test_flags & 0x3;
/* read d->nsectors at a time, max. */
i_sectors = ( i_sectors > d->nsectors && d->nsectors > 0 )
? d->nsectors : i_sectors;
/* If we are testing under-run correction, we will deliberately set
what we read a frame short. */
if (d->i_test_flags & CDDA_TEST_UNDERRUN )
i_sectors--;
if (jitter_badness) {
return jitter_read(d, p, begin, i_sectors, jitter_badness);
} else
return read_blocks(d, p, begin, i_sectors);
}
static int
verify_read_command(cdrom_drive_t *d)
{
int i;
int16_t *buff=malloc(CDIO_CD_FRAMESIZE_RAW);
int audioflag=0;
int i_test_flags = d->i_test_flags;
d->i_test_flags = 0;
cdmessage(d,"Verifying drive can read CDDA...\n");
d->enable_cdda(d,1);
for(i=1;i<=d->tracks;i++){
if(cdda_track_audiop(d,i)==1){
long firstsector=cdda_track_firstsector(d,i);
long lastsector=cdda_track_lastsector(d,i);
long sector=(firstsector+lastsector)>>1;
audioflag=1;
if(d->read_audio(d,buff,sector,1)>0){
cdmessage(d,"\tExpected command set reads OK.\n");
d->enable_cdda(d,0);
free(buff);
d->i_test_flags = i_test_flags;
return(0);
}
}
}
d->enable_cdda(d,0);
if(!audioflag){
cdmessage(d,"\tCould not find any audio tracks on this disk.\n");
return(-403);
}
cdmessage(d,"\n\tUnable to read any data; "
"drive probably not CDDA capable.\n");
cderror(d,"006: Could not read any data from drive\n");
free(buff);
return(-6);
}
#include "drive_exceptions.h"
#ifdef HAVE_LINUX_MAJOR_H
static void
check_exceptions(cdrom_drive_t *d, const exception_t *list)
{
int i=0;
while(list[i].model){
if(!strncmp(list[i].model,d->drive_model,strlen(list[i].model))){
if(list[i].bigendianp!=-1)d->bigendianp=list[i].bigendianp;
return;
}
i++;
}
}
#endif /* HAVE_LINUX_MAJOR_H */
/* set function pointers to use the ioctl routines */
int
cddap_init_drive (cdrom_drive_t *d)
{
int ret;
#if HAVE_LINUX_MAJOR_H
switch(d->drive_type){
case MATSUSHITA_CDROM_MAJOR: /* sbpcd 1 */
case MATSUSHITA_CDROM2_MAJOR: /* sbpcd 2 */
case MATSUSHITA_CDROM3_MAJOR: /* sbpcd 3 */
case MATSUSHITA_CDROM4_MAJOR: /* sbpcd 4 */
/* don't make the buffer too big; this sucker don't preempt */
cdmessage(d,"Attempting to set sbpcd buffer size...\n");
d->nsectors=8;
#if BUFSIZE_DETERMINATION_FIXED
while(1){
/* this ioctl returns zero on error; exactly wrong, but that's
what it does. */
if (ioctl(d->ioctl_fd, CDROMAUDIOBUFSIZ, d->nsectors)==0) {
d->nsectors>>=1;
if(d->nsectors==0){
char buffer[256];
d->nsectors=8;
sprintf(buffer,"\tTrouble setting buffer size. Defaulting to %d sectors.\n",
d->nsectors);
cdmessage(d,buffer);
break; /* Oh, well. Try to read anyway.*/
}
} else {
char buffer[256];
sprintf(buffer,"\tSetting read block size at %d sectors (%ld bytes).\n",
d->nsectors,(long)d->nsectors*CDIO_CD_FRAMESIZE_RAW);
cdmessage(d,buffer);
break;
}
}
#endif /* BUFSIZE_DETERMINATION_FIXED */
break;
case IDE0_MAJOR:
case IDE1_MAJOR:
case IDE2_MAJOR:
case IDE3_MAJOR:
d->nsectors=8; /* it's a define in the linux kernel; we have no
way of determining other than this guess tho */
d->bigendianp=0;
d->is_atapi=1;
check_exceptions(d, atapi_list);
break;
default:
d->nsectors=25; /* The max for SCSI MMC2 */
}
#else
{
char buffer[256];
d->nsectors = 8;
sprintf(buffer,"\tSetting read block size at %d sectors (%ld bytes).\n",
d->nsectors,(long)d->nsectors*CDIO_CD_FRAMESIZE_RAW);
cdmessage(d,buffer);
}
#endif /*HAVE_LINUX_MAJOR_H*/
d->enable_cdda = dummy_exception;
d->set_speed = cddap_setspeed;
d->read_toc = cddap_readtoc;
d->read_audio = cddap_read;
ret = d->tracks = d->read_toc(d);
if(d->tracks<1)
return(ret);
d->opened=1;
if( (ret=verify_read_command(d)) ) return(ret);
d->error_retry=1;
return(0);
}

View File

@@ -0,0 +1,271 @@
/*
$Id: common_interface.c,v 1.17 2008/04/16 17:00:40 karl Exp $
Copyright (C) 2004, 2005, 2007, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998, 2002 Monty monty@xiph.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 3 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, see <http://www.gnu.org/licenses/>.
*/
/******************************************************************
*
* CDROM communication common to all interface methods is done here
* (mostly ioctl stuff, but not ioctls specific to the 'cooked'
* interface)
*
******************************************************************/
#include <math.h>
#include "common_interface.h"
#include "utils.h"
#include "smallft.h"
/* Variables to hold debugger-helping enumerations */
enum paranoia_cdda_enums;
enum paranoia_jitter_enums;
/*! Determine Endian-ness of the CD-drive based on reading data from
it. Some drives return audio data Big Endian while some (most)
return data Little Endian. Drives known to return data bigendian are
SCSI drives from Kodak, Ricoh, HP, Philips, Plasmon, Grundig
CDR100IPW, and Mitsumi CD-R. ATAPI and MMC drives are little endian.
rocky: As someone who didn't write the code, I have to say this is
nothing less than brilliant. An FFT is done both ways and the the
transform is looked at to see which has data in the FFT (or audible)
portion. (Or so that's how I understand it.)
@return 1 if big-endian, 0 if little-endian, -1 if we couldn't
figure things out or some error.
*/
int
data_bigendianp(cdrom_drive_t *d)
{
float lsb_votes=0;
float msb_votes=0;
int i,checked;
int endiancache=d->bigendianp;
float *a=calloc(1024,sizeof(float));
float *b=calloc(1024,sizeof(float));
long readsectors=5;
int16_t *buff=malloc(readsectors*CDIO_CD_FRAMESIZE_RAW);
memset(buff, 0, readsectors*CDIO_CD_FRAMESIZE_RAW);
/* look at the starts of the audio tracks */
/* if real silence, tool in until some static is found */
/* Force no swap for now */
d->bigendianp=-1;
cdmessage(d,"\nAttempting to determine drive endianness from data...");
d->enable_cdda(d,1);
for(i=0,checked=0;i<d->tracks;i++){
float lsb_energy=0;
float msb_energy=0;
if(cdda_track_audiop(d,i+1)==1){
long firstsector=cdda_track_firstsector(d,i+1);
long lastsector=cdda_track_lastsector(d,i+1);
int zeroflag=-1;
long beginsec=0;
/* find a block with nonzero data */
while(firstsector+readsectors<=lastsector){
int j;
if(d->read_audio(d,buff,firstsector,readsectors)>0){
/* Avoid scanning through jitter at the edges */
for(beginsec=0;beginsec<readsectors;beginsec++){
int offset=beginsec*CDIO_CD_FRAMESIZE_RAW/2;
/* Search *half* */
for(j=460;j<128+460;j++)
if(buff[offset+j]!=0){
zeroflag=0;
break;
}
if(!zeroflag)break;
}
if(!zeroflag)break;
firstsector+=readsectors;
}else{
d->enable_cdda(d,0);
free(a);
free(b);
free(buff);
return(-1);
}
}
beginsec*=CDIO_CD_FRAMESIZE_RAW/2;
/* un-interleave for an FFT */
if(!zeroflag){
int j;
for(j=0;j<128;j++)
a[j] = le16_to_cpu(buff[j*2+beginsec+460]);
for(j=0;j<128;j++)
b[j] = le16_to_cpu(buff[j*2+beginsec+461]);
fft_forward(128,a,NULL,NULL);
fft_forward(128,b,NULL,NULL);
for(j=0;j<128;j++)
lsb_energy+=fabs(a[j])+fabs(b[j]);
for(j=0;j<128;j++)
a[j] = be16_to_cpu(buff[j*2+beginsec+460]);
for(j=0;j<128;j++)
b[j] = be16_to_cpu(buff[j*2+beginsec+461]);
fft_forward(128,a,NULL,NULL);
fft_forward(128,b,NULL,NULL);
for(j=0;j<128;j++)
msb_energy+=fabs(a[j])+fabs(b[j]);
}
}
if(lsb_energy<msb_energy){
lsb_votes+=msb_energy/lsb_energy;
checked++;
}else
if(lsb_energy>msb_energy){
msb_votes+=lsb_energy/msb_energy;
checked++;
}
if(checked==5 && (lsb_votes==0 || msb_votes==0))break;
cdmessage(d,".");
}
free(buff);
free(a);
free(b);
d->bigendianp=endiancache;
d->enable_cdda(d,0);
/* How did we vote? Be potentially noisy */
if (lsb_votes>msb_votes) {
char buffer[256];
cdmessage(d,"\n\tData appears to be coming back Little Endian.\n");
sprintf(buffer,"\tcertainty: %d%%\n",(int)
(100.*lsb_votes/(lsb_votes+msb_votes)+.5));
cdmessage(d,buffer);
return(0);
} else {
if(msb_votes>lsb_votes){
char buffer[256];
cdmessage(d,"\n\tData appears to be coming back Big Endian.\n");
sprintf(buffer,"\tcertainty: %d%%\n",(int)
(100.*msb_votes/(lsb_votes+msb_votes)+.5));
cdmessage(d,buffer);
return(1);
}
cdmessage(d,"\n\tCannot determine CDROM drive endianness.\n");
return(bigendianp());
return(-1);
}
}
/************************************************************************/
/*! Here we fix up a couple of things that will never happen. yeah,
right.
The multisession stuff is from Hannu code; it assumes it knows the
leadout/leadin size. [I think Hannu refers to Hannu Savolainen
from GNU/Linux Kernel code.]
@return -1 if we can't get multisession info, 0 if there is one
session only or the last session LBA is the same as the first audio
track and 1 if the multi-session lba is higher than first audio track
*/
int
FixupTOC(cdrom_drive_t *d, track_t i_tracks)
{
int j;
/* First off, make sure the 'starting sector' is >=0 */
for( j=0; j<i_tracks; j++){
if (d->disc_toc[j].dwStartSector<0 ) {
cdmessage(d,"\n\tTOC entry claims a negative start offset: massaging"
".\n");
d->disc_toc[j].dwStartSector=0;
}
if( j<i_tracks-1 && d->disc_toc[j].dwStartSector>
d->disc_toc[j+1].dwStartSector ) {
cdmessage(d,"\n\tTOC entry claims an overly large start offset: massaging"
".\n");
d->disc_toc[j].dwStartSector=0;
}
}
/* Make sure the listed 'starting sectors' are actually increasing.
Flag things that are blatant/stupid/wrong */
{
lsn_t last=d->disc_toc[0].dwStartSector;
for ( j=1; j<i_tracks; j++){
if ( d->disc_toc[j].dwStartSector<last ) {
cdmessage(d,"\n\tTOC entries claim non-increasing offsets: massaging"
".\n");
d->disc_toc[j].dwStartSector=last;
}
last=d->disc_toc[j].dwStartSector;
}
}
d->audio_last_sector = CDIO_INVALID_LSN;
{
lsn_t last_ses_lsn;
if (cdio_get_last_session (d->p_cdio, &last_ses_lsn) < 0)
return -1;
/* A Red Book Disc must have only one session, otherwise this is a
* CD Extra */
if (last_ses_lsn > d->disc_toc[0].dwStartSector) {
/* CD Extra discs have two session, the first one ending after
* the last audio track
* Thus the need to fix the length of the the audio data portion to
* not cross the lead-out of this session */
for (j = i_tracks-1; j > 1; j--) {
if (cdio_get_track_format(d->p_cdio, j+1) != TRACK_FORMAT_AUDIO &&
cdio_get_track_format(d->p_cdio, j) == TRACK_FORMAT_AUDIO) {
/* First session lead-out is 1:30
* Lead-ins are 1:00
* Every session's first track have a 0:02 pregap
*
* That makes a control data section of (90+60+2)*75 sectors in the
* last audio track */
const int gap = ((90+60+2) * CDIO_CD_FRAMES_PER_SEC);
if ((last_ses_lsn - gap >= d->disc_toc[j-1].dwStartSector) &&
(last_ses_lsn - gap < d->disc_toc[j].dwStartSector)) {
d->audio_last_sector = last_ses_lsn - gap - 1;
break;
}
}
}
return 1;
}
}
return 0;
}

View File

@@ -0,0 +1,54 @@
/*
$Id: common_interface.h,v 1.7 2008/04/16 17:00:40 karl Exp $
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CDDA_COMMON_INTERFACE_H_
#define _CDDA_COMMON_INTERFACE_H_
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cdio/types.h>
#include "low_interface.h"
#if defined(HAVE_LSTAT) && !defined(HAVE_WIN32_CDROM)
/* Define this if the CD-ROM device is a file in the filesystem
that can be lstat'd
*/
#define DEVICE_IN_FILESYSTEM 1
#else
#undef DEVICE_IN_FILESYSTEM
#endif
/** Test for presence of a cdrom by pinging with the 'CDROMVOLREAD' ioctl() */
extern int ioctl_ping_cdrom(int fd);
extern char *atapi_drive_info(int fd);
/*! Here we fix up a couple of things that will never happen. yeah,
right.
rocky OMITTED FOR NOW:
The multisession stuff is from Hannu's code; it assumes it knows
the leadout/leadin size.
*/
extern int FixupTOC(cdrom_drive_t *d, track_t tracks);
#endif /*_CDDA_COMMON_INTERFACE_H_*/

View File

@@ -0,0 +1,84 @@
/*
$Id: drive_exceptions.c,v 1.1 2008/06/14 10:36:49 flameeyes Exp $
Copyright (C) 2004, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "common_interface.h"
#include "drive_exceptions.h"
int dummy_exception (cdrom_drive_t *d,int Switch)
{
return(0);
}
#if HAVE_LINUX_MAJOR_H
/* list of drives that affect autosensing in ATAPI specific portions of code
(force drives to detect as ATAPI or SCSI, force ATAPI read command */
const exception_t atapi_list[]={
{"SAMSUNG SCR-830 REV 2.09 2.09 ", 1, 0, dummy_exception,scsi_read_mmc2,0},
{"Memorex CR-622", 1, 0, dummy_exception, NULL,0},
{"SONY CD-ROM CDU-561", 0, 0, dummy_exception, NULL,0},
{"Chinon CD-ROM CDS-525", 0, 0, dummy_exception, NULL,0},
{NULL,0,0,NULL,NULL,0}};
#endif /*HAVE_LINUX_MAJOR_H*/
/* list of drives that affect MMC default settings */
#ifdef NEED_MMC_LIST
static exception_t mmc_list[]={
{"SAMSUNG SCR-830 REV 2.09 2.09 ", 1, 0, dummy_exception,scsi_read_mmc2,0},
{"Memorex CR-622", 1, 0, dummy_exception, NULL,0},
{"SONY CD-ROM CDU-561", 0, 0, dummy_exception, NULL,0},
{"Chinon CD-ROM CDS-525", 0, 0, dummy_exception, NULL,0},
{"KENWOOD CD-ROM UCR", -1, 0, NULL,scsi_read_D8, 0},
{NULL,0,0,NULL,NULL,0}};
#endif /*NEED_MMC_LIST*/
/* list of drives that affect SCSI default settings */
#ifdef NEED_SCSI_LIST
static exception_t scsi_list[]={
{"TOSHIBA", -1,0x82,scsi_enable_cdda,scsi_read_28, 0},
{"IBM", -1,0x82,scsi_enable_cdda,scsi_read_28, 0},
{"DEC", -1,0x82,scsi_enable_cdda,scsi_read_28, 0},
{"IMS", -1, 0,scsi_enable_cdda,scsi_read_28, 1},
{"KODAK", -1, 0,scsi_enable_cdda,scsi_read_28, 1},
{"RICOH", -1, 0,scsi_enable_cdda,scsi_read_28, 1},
{"HP", -1, 0,scsi_enable_cdda,scsi_read_28, 1},
{"PHILIPS", -1, 0,scsi_enable_cdda,scsi_read_28, 1},
{"PLASMON", -1, 0,scsi_enable_cdda,scsi_read_28, 1},
{"GRUNDIG CDR100IPW", -1, 0,scsi_enable_cdda,scsi_read_28, 1},
{"MITSUMI CD-R ", -1, 0,scsi_enable_cdda,scsi_read_28, 1},
{"KENWOOD CD-ROM UCR", -1, 0, NULL,scsi_read_D8, 0},
{"YAMAHA", -1, 0,scsi_enable_cdda, NULL, 0},
{"PLEXTOR", -1, 0, NULL, NULL, 0},
{"SONY", -1, 0, NULL, NULL, 0},
{"NEC", -1, 0, NULL,scsi_read_D4_10,0},
/* the 7501 locks up if hit with the 10 byte version from the
autoprobe first */
{"MATSHITA CD-R CW-7501", -1, 0, NULL,scsi_read_D4_12,-1},
{NULL,0,0,NULL,NULL,0}};
#endif /* NEED_SCSI_LIST*/

View File

@@ -0,0 +1,58 @@
/*
$Id: drive_exceptions.h,v 1.6 2008/06/13 19:26:23 flameeyes Exp $
Copyright (C) 2004, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
extern int scsi_enable_cdda(cdrom_drive_t *d, int);
extern long scsi_read_mmc(cdrom_drive_t *d, void *,long,long);
extern long scsi_read_D4_10(cdrom_drive_t *, void *,long,long);
extern long scsi_read_D4_12(cdrom_drive_t *, void *,long,long);
extern long scsi_read_D8(cdrom_drive_t *, void *,long,long);
extern long scsi_read_28(cdrom_drive_t *, void *,long,long);
extern long scsi_read_A8(cdrom_drive_t *, void *,long,long);
typedef struct exception {
const char *model;
int atapi; /* If the ioctl doesn't work */
unsigned char density;
int (*enable)(cdrom_drive_t *,int);
long (*read)(cdrom_drive_t *,void *, long, long);
int bigendianp;
} exception_t;
/* specific to general */
#ifdef FINISHED_DRIVE_EXCEPTIONS
extern long scsi_read_mmc2(cdrom_drive_t *d, void *,long,long);
#else
#define scsi_read_mmc2 NULL
#endif
int dummy_exception (cdrom_drive_t *d,int Switch);
#if HAVE_LINUX_MAJOR_H
extern const exception_t atapi_list[];
#endif
#ifdef NEED_MMC_LIST
extern const exception_t mmc_list[];
#endif
#ifdef NEED_SCSI_LIST
extern const exception_t scsi_list[];
#endif

View File

@@ -0,0 +1,188 @@
/*
$Id: interface.c,v 1.26 2008/04/16 17:00:40 karl Exp $
Copyright (C) 2005, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
/******************************************************************
* Top-level interface module for cdrom drive access. SCSI, ATAPI, etc
* specific stuff are in other modules. Note that SCSI does use
* specialized ioctls; these appear in common_interface.c where the
* generic_scsi stuff is in scsi_interface.c.
*
******************************************************************/
#include "common_interface.h"
#include "low_interface.h"
#include "utils.h"
#include <cdio/bytesex.h>
#include <cdio/mmc.h>
static void _clean_messages(cdrom_drive_t *d)
{
if(d){
if(d->messagebuf)free(d->messagebuf);
if(d->errorbuf)free(d->errorbuf);
d->messagebuf=NULL;
d->errorbuf=NULL;
}
}
/*!
Closes d and releases all storage associated with it except
the internal p_cdio pointer.
@param d cdrom_drive_t object to be closed.
@return 0 if passed a null pointer and 1 if not in which case
some work was probably done.
@see cdio_cddap_close
*/
bool
cdio_cddap_close_no_free_cdio(cdrom_drive_t *d)
{
if(d){
if(d->opened)
d->enable_cdda(d,0);
_clean_messages(d);
if (d->cdda_device_name) free(d->cdda_device_name);
if (d->drive_model) free(d->drive_model);
d->cdda_device_name = d->drive_model = NULL;
free(d);
return true;
}
return false;
}
/*!
Closes d and releases all storage associated with it.
Doubles as "cdrom_drive_free()".
@param d cdrom_drive_t object to be closed.
@return 0 if passed a null pointer and 1 if not in which case
some work was probably done.
@see cdio_cddap_close_no_free_cdio
*/
int
cdio_cddap_close(cdrom_drive_t *d)
{
if (d) {
CdIo_t *p_cdio = d->p_cdio;
cdio_cddap_close_no_free_cdio(d);
cdio_destroy (p_cdio);
return 1;
}
return 0;
}
/* finish initializing the drive! */
int
cdio_cddap_open(cdrom_drive_t *d)
{
int ret;
if(d->opened)return(0);
if ( (ret=cddap_init_drive(d)) )
return(ret);
/* Check TOC, enable for CDDA */
/* Some drives happily return a TOC even if there is no disc... */
{
int i;
for(i=0; i<d->tracks; i++)
if(d->disc_toc[i].dwStartSector<0 ||
d->disc_toc[i+1].dwStartSector==0){
d->opened=0;
cderror(d,"009: CDROM reporting illegal table of contents\n");
return(-9);
}
}
if((ret=d->enable_cdda(d,1)))
return(ret);
/* d->select_speed(d,d->maxspeed); most drives are full speed by default */
if ( -1 == d->bigendianp ) {
d->bigendianp = data_bigendianp(d);
}
return(0);
}
int
cdio_cddap_speed_set(cdrom_drive_t *d, int speed)
{
return d->set_speed ? d->set_speed(d, speed) : 0;
}
long
cdio_cddap_read(cdrom_drive_t *d, void *buffer, lsn_t beginsector,
long sectors)
{
if (d->opened) {
if (sectors>0) {
sectors=d->read_audio(d, buffer, beginsector, sectors);
if (sectors > 0) {
/* byteswap? */
if ( d->bigendianp == -1 ) /* not determined yet */
d->bigendianp = data_bigendianp(d);
if ( d->b_swap_bytes && d->bigendianp != bigendianp() ) {
int i;
uint16_t *p=(uint16_t *)buffer;
long els=sectors*CDIO_CD_FRAMESIZE_RAW/2;
for(i=0;i<els;i++)
p[i]=UINT16_SWAP_LE_BE_C(p[i]);
}
}
}
return(sectors);
}
cderror(d,"400: Device not open\n");
return(-400);
}
void
cdio_cddap_verbose_set(cdrom_drive_t *d,int err_action, int mes_action)
{
d->messagedest=mes_action;
d->errordest=err_action;
}
extern char *
cdio_cddap_messages(cdrom_drive_t *d)
{
char *ret=d->messagebuf;
d->messagebuf=NULL;
return(ret);
}
extern char *
cdio_cddap_errors(cdrom_drive_t *d)
{
char *ret=d->errorbuf;
d->errorbuf=NULL;
return(ret);
}

View File

@@ -0,0 +1,22 @@
cdio_cddap_find_a_cdrom
cdio_cddap_identify
cdio_cddap_identify_cdio
cdio_cddap_speed_set
cdio_cddap_verbose_set
cdio_cddap_messages
cdio_cddap_errors
cdio_cddap_close_no_free_cdio
cdio_cddap_close
cdio_cddap_open
cdio_cddap_read
cdio_cddap_track_firstsector
cdio_cddap_track_lastsector
cdio_cddap_tracks
cdio_cddap_sector_gettrack
cdio_cddap_track_channels
cdio_cddap_track_audiop
cdio_cddap_track_copyp
cdio_cddap_track_preemp
cdio_cddap_disc_firstsector
cdio_cddap_disc_lastsector
data_bigendianp

View File

@@ -0,0 +1,66 @@
/*
$Id: low_interface.h,v 1.9 2008/04/16 17:00:40 karl Exp $
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
/** internal include file for cdda interface kit for Linux */
#ifndef _CDDA_LOW_INTERFACE_
#define _CDDA_LOW_INTERFACE_
#ifdef HAVE_STDIO_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_LINUX_VERSION_H
#include <linux/version.h>
#endif
#include <cdio/paranoia.h>
#include <cdio/cdda.h>
/* some include file locations have changed with newer kernels */
#ifndef CDROMAUDIOBUFSIZ
#define CDROMAUDIOBUFSIZ 0x5382 /* set the audio buffer size */
#endif
#ifdef HAVE_LINUX_CDROM_H
#include <linux/cdrom.h>
#endif
#ifdef HAVE_LINUX_MAJOR_H
#include <linux/major.h>
#endif
#define MAX_RETRIES 8
#define MAX_BIG_BUFF_SIZE 65536
#define MIN_BIG_BUFF_SIZE 4096
#define SG_OFF sizeof(struct sg_header)
extern int cddap_init_drive (cdrom_drive_t *d);
#endif /*_CDDA_LOW_INTERFACE_*/

View File

@@ -0,0 +1,335 @@
/*
$Id: scan_devices.c,v 1.33 2008/06/16 19:45:44 flameeyes Exp $
Copyright (C) 2004, 2005, 2007, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
/******************************************************************
*
* Autoscan for or verify presence of a CD-ROM device
*
******************************************************************/
#include "common_interface.h"
#include "low_interface.h"
#include "utils.h"
#include "cdio/mmc.h"
#include <limits.h>
#include <ctype.h>
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#define MAX_DEV_LEN 20 /* Safe because strings only come from below */
/* must be absolute paths! */
static const char scsi_cdrom_prefixes[][16]={
"/dev/scd",
"/dev/sr",
""};
static const char scsi_generic_prefixes[][16]={
"/dev/sg",
""};
static const char devfs_scsi_test[]="/dev/scsi/";
static const char devfs_scsi_cd[]="cd";
static const char devfs_scsi_generic[]="generic";
static const char cdrom_devices[][32]={
"/dev/cdrom",
"/dev/cdroms/cdrom?",
"/dev/hd?",
"/dev/sg?",
"/dev/cdu31a",
"/dev/cdu535",
"/dev/sbpcd",
"/dev/sbpcd?",
"/dev/sonycd",
"/dev/mcd",
"/dev/sjcd",
/* "/dev/aztcd", timeout is too long */
"/dev/cm206cd",
"/dev/gscd",
"/dev/optcd",
""};
static cdrom_drive_t *
cdda_identify_device_cdio(CdIo_t *p_cdio, const char *psz_device,
int messagedest, char **ppsz_messages);
/* Functions here look for a cdrom drive; full init of a drive type
happens in interface.c */
cdrom_drive_t *
cdio_cddap_find_a_cdrom(int messagedest, char **ppsz_messages){
/* Brute force... */
int i=0;
cdrom_drive_t *d;
while(*cdrom_devices[i]!='\0'){
/* is it a name or a pattern? */
char *pos;
if((pos=strchr(cdrom_devices[i],'?'))){
int j;
/* try first eight of each device */
for(j=0;j<4;j++){
char *buffer=strdup(cdrom_devices[i]);
/* number, then letter */
buffer[pos-(cdrom_devices[i])]=j+48;
if((d=cdda_identify(buffer, messagedest, ppsz_messages)))
return(d);
idmessage(messagedest, ppsz_messages, "", NULL);
buffer[pos-(cdrom_devices[i])]=j+97;
if((d=cdda_identify(buffer, messagedest, ppsz_messages)))
return(d);
idmessage(messagedest, ppsz_messages, "", NULL);
}
}else{
/* Name. Go for it. */
if((d=cdda_identify(cdrom_devices[i], messagedest, ppsz_messages)))
return(d);
idmessage(messagedest, ppsz_messages, "", NULL);
}
i++;
}
{
#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
struct passwd *temp;
temp=getpwuid(geteuid());
idmessage(messagedest, ppsz_messages,
"\n\nNo cdrom drives accessible to %s found.\n",
temp->pw_name);
#else
idmessage(messagedest, ppsz_messages,
"\n\nNo cdrom drives accessible found.\n", NULL);
#endif
}
return(NULL);
}
#ifdef DEVICE_IN_FILESYSTEM
static char *
test_resolve_symlink(const char *file, int messagedest, char **ppsz_messages)
{
char resolved[PATH_MAX];
struct stat st;
if (lstat(file,&st)){
idperror(messagedest, ppsz_messages, "\t\tCould not stat %s",file);
return(NULL);
}
if (realpath(file,resolved))
return(strdup(resolved));
idperror(messagedest, ppsz_messages, "\t\tCould not resolve symlink %s",
file);
return(NULL);
}
#endif
/** Returns a paranoia CD-ROM drive object with a CD-DA in it or NULL
if there was an error.
@see cdio_cddap_identify_cdio
*/
cdrom_drive_t *
cdio_cddap_identify(const char *psz_dev, int messagedest,
char **ppsz_messages)
{
CdIo_t *p_cdio = NULL;
if (psz_dev)
idmessage(messagedest, ppsz_messages, "Checking %s for cdrom...",
psz_dev);
else
idmessage(messagedest, ppsz_messages, "Checking for cdrom...", NULL);
#ifdef DEVICE_IN_FILESYSTEM
if (psz_dev) {
char *psz_device = test_resolve_symlink(psz_dev, messagedest,
ppsz_messages);
if ( psz_device ) {
cdrom_drive_t *d=NULL;
p_cdio = cdio_open(psz_device, DRIVER_UNKNOWN);
d = cdda_identify_device_cdio(p_cdio, psz_device, messagedest,
ppsz_messages);
free(psz_device);
return d;
}
}
#endif
p_cdio = cdio_open(psz_dev, DRIVER_UNKNOWN);
if (p_cdio) {
if (!psz_dev) {
psz_dev = cdio_get_arg(p_cdio, "source");
}
return cdda_identify_device_cdio(p_cdio, psz_dev, messagedest,
ppsz_messages);
}
return NULL;
}
/** Returns a paranoia CD-ROM drive object with a CD-DA in it or NULL
if there was an error. In contrast to cdio_cddap_identify, we
start out with an initialized p_cdio object. For example you may
have used that for other purposes such as to get CDDB/CD-Text
information. @see cdio_cddap_identify
*/
cdrom_drive_t *
cdio_cddap_identify_cdio(CdIo_t *p_cdio, int messagedest, char **ppsz_messages)
{
if (!p_cdio) return NULL;
{
const char *psz_device = cdio_get_arg(p_cdio, "source");
idmessage(messagedest, ppsz_messages, "Checking %s for cdrom...",
psz_device);
return cdda_identify_device_cdio(p_cdio, psz_device, messagedest,
ppsz_messages);
}
}
static cdrom_drive_t *
cdda_identify_device_cdio(CdIo_t *p_cdio, const char *psz_device,
int messagedest, char **ppsz_messages)
{
cdrom_drive_t *d=NULL;
int drive_type = 0;
char *description=NULL;
#ifdef HAVE_LINUX_MAJOR_H
struct stat st;
#endif
if (!p_cdio) {
idperror(messagedest, ppsz_messages, "\t\tUnable to open %s", psz_device);
return NULL;
}
#ifdef HAVE_LINUX_MAJOR_H
if ( 0 == stat(psz_device, &st) ) {
if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
drive_type=(int)(st.st_rdev>>8);
switch (drive_type) {
case IDE0_MAJOR:
case IDE1_MAJOR:
case IDE2_MAJOR:
case IDE3_MAJOR:
/* Yay, ATAPI... */
description=strdup("ATAPI compatible ");
break;
case CDU31A_CDROM_MAJOR:
/* major indicates this is a cdrom; no ping necessary. */
description=strdup("Sony CDU31A or compatible");
break;
case CDU535_CDROM_MAJOR:
/* major indicates this is a cdrom; no ping necessary. */
description=strdup("Sony CDU535 or compatible");
break;
case MATSUSHITA_CDROM_MAJOR:
case MATSUSHITA_CDROM2_MAJOR:
case MATSUSHITA_CDROM3_MAJOR:
case MATSUSHITA_CDROM4_MAJOR:
/* major indicates this is a cdrom; no ping necessary. */
description=strdup("non-ATAPI IDE-style Matsushita/Panasonic CR-5xx or compatible");
break;
case SANYO_CDROM_MAJOR:
description=strdup("Sanyo proprietary or compatible: NOT CDDA CAPABLE");
break;
case MITSUMI_CDROM_MAJOR:
case MITSUMI_X_CDROM_MAJOR:
description=strdup("Mitsumi proprietary or compatible: NOT CDDA CAPABLE");
break;
case OPTICS_CDROM_MAJOR:
description=strdup("Optics Dolphin or compatible: NOT CDDA CAPABLE");
break;
case AZTECH_CDROM_MAJOR:
description=strdup("Aztech proprietary or compatible: NOT CDDA CAPABLE");
break;
case GOLDSTAR_CDROM_MAJOR:
description=strdup("Goldstar proprietary: NOT CDDA CAPABLE");
break;
case CM206_CDROM_MAJOR:
description=strdup("Philips/LMS CM206 proprietary: NOT CDDA CAPABLE");
break;
case SCSI_CDROM_MAJOR:
case SCSI_GENERIC_MAJOR:
/* Nope nope nope */
description=strdup("SCSI CD-ROM");
break;
default:
/* What the hell is this? */
idmessage(messagedest, ppsz_messages,
"\t\t%s is not a cooked ioctl CDROM.",
psz_device);
return(NULL);
}
}
}
#endif /*HAVE_LINUX_MAJOR_H*/
/* Minimum init */
d=calloc(1, sizeof(cdrom_drive_t));
d->p_cdio = p_cdio;
d->cdda_device_name = strdup(psz_device);
d->drive_type = drive_type;
d->bigendianp = -1; /* We don't know yet... */
d->nsectors = -1; /* We don't know yet... */
d->messagedest = messagedest;
d->b_swap_bytes = true;
{
cdio_hwinfo_t hw_info = {
"UNKNOWN", "Unknown model", "????"
};
if ( mmc_get_hwinfo( p_cdio, &hw_info ) ) {
unsigned int i_len = strlen(hw_info.psz_vendor)
+ strlen(hw_info.psz_model)
+ strlen(hw_info.psz_revision) + 5;
if (description) {
i_len += strlen(description);
d->drive_model=malloc( i_len );
snprintf( d->drive_model, i_len, "%s %s %s %s",
hw_info.psz_vendor, hw_info.psz_model, hw_info.psz_revision,
description );
free(description);
} else {
d->drive_model=malloc( i_len );
snprintf( d->drive_model, i_len, "%s %s %s",
hw_info.psz_vendor, hw_info.psz_model, hw_info.psz_revision
);
}
idmessage(messagedest, ppsz_messages, "\t\tCDROM sensed: %s\n",
d->drive_model);
}
}
return(d);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,563 @@
/*
$Id: smallft.c,v 1.2 2008/04/16 17:00:40 karl Exp $
Copyright (C) 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
/******************************************************************
* FFT implementation from OggSquish, minus cosine transforms,
* minus all but radix 2/4 case
*
* See OggSquish or NetLib for the version that can do other than just
* power-of-two sized vectors.
******************************************************************/
#include <stdlib.h>
#include <math.h>
#include "smallft.h"
static void drfti1(int n, float *wa, int *ifac){
static int ntryh[4] = { 4,2,3,5 };
static float tpi = 6.28318530717958647692528676655900577;
float arg,argh,argld,fi;
int ntry=0,i,j=-1;
int k1, l1, l2, ib;
int ld, ii, ip, is, nq, nr;
int ido, ipm, nfm1;
int nl=n;
int nf=0;
L101:
j++;
if (j < 4)
ntry=ntryh[j];
else
ntry+=2;
L104:
nq=nl/ntry;
nr=nl-ntry*nq;
if (nr!=0) goto L101;
nf++;
ifac[nf+1]=ntry;
nl=nq;
if(ntry!=2)goto L107;
if(nf==1)goto L107;
for (i=1;i<nf;i++){
ib=nf-i+1;
ifac[ib+1]=ifac[ib];
}
ifac[2] = 2;
L107:
if(nl!=1)goto L104;
ifac[0]=n;
ifac[1]=nf;
argh=tpi/n;
is=0;
nfm1=nf-1;
l1=1;
if(nfm1==0)return;
for (k1=0;k1<nfm1;k1++){
ip=ifac[k1+2];
ld=0;
l2=l1*ip;
ido=n/l2;
ipm=ip-1;
for (j=0;j<ipm;j++){
ld+=l1;
i=is;
argld=(float)ld*argh;
fi=0.;
for (ii=2;ii<ido;ii+=2){
fi+=1.;
arg=fi*argld;
wa[i++]=cos(arg);
wa[i++]=sin(arg);
}
is+=ido;
}
l1=l2;
}
}
static void fdrffti(int n, float *wsave, int *ifac){
if (n == 1) return;
drfti1(n, wsave+n, ifac);
}
static void dradf2(int ido,int l1,float *cc,float *ch,float *wa1){
int i,k;
float ti2,tr2;
int t0,t1,t2,t3,t4,t5,t6;
t1=0;
t0=(t2=l1*ido);
t3=ido<<1;
for(k=0;k<l1;k++){
ch[t1<<1]=cc[t1]+cc[t2];
ch[(t1<<1)+t3-1]=cc[t1]-cc[t2];
t1+=ido;
t2+=ido;
}
if(ido<2)return;
if(ido==2)goto L105;
t1=0;
t2=t0;
for(k=0;k<l1;k++){
t3=t2;
t4=(t1<<1)+(ido<<1);
t5=t1;
t6=t1+t1;
for(i=2;i<ido;i+=2){
t3+=2;
t4-=2;
t5+=2;
t6+=2;
tr2=wa1[i-2]*cc[t3-1]+wa1[i-1]*cc[t3];
ti2=wa1[i-2]*cc[t3]-wa1[i-1]*cc[t3-1];
ch[t6]=cc[t5]+ti2;
ch[t4]=ti2-cc[t5];
ch[t6-1]=cc[t5-1]+tr2;
ch[t4-1]=cc[t5-1]-tr2;
}
t1+=ido;
t2+=ido;
}
if(ido%2==1)return;
L105:
t3=(t2=(t1=ido)-1);
t2+=t0;
for(k=0;k<l1;k++){
ch[t1]=-cc[t2];
ch[t1-1]=cc[t3];
t1+=ido<<1;
t2+=ido;
t3+=ido;
}
}
static void dradf4(int ido,int l1,float *cc,float *ch,float *wa1,
float *wa2,float *wa3){
static float hsqt2 = .70710678118654752440084436210485;
int i,k,t0,t1,t2,t3,t4,t5,t6;
float ci2,ci3,ci4,cr2,cr3,cr4,ti1,ti2,ti3,ti4,tr1,tr2,tr3,tr4;
t0=l1*ido;
t1=t0;
t4=t1<<1;
t2=t1+(t1<<1);
t3=0;
for(k=0;k<l1;k++){
tr1=cc[t1]+cc[t2];
tr2=cc[t3]+cc[t4];
ch[t5=t3<<2]=tr1+tr2;
ch[(ido<<2)+t5-1]=tr2-tr1;
ch[(t5+=(ido<<1))-1]=cc[t3]-cc[t4];
ch[t5]=cc[t2]-cc[t1];
t1+=ido;
t2+=ido;
t3+=ido;
t4+=ido;
}
if(ido<2)return;
if(ido==2)goto L105;
t1=0;
for(k=0;k<l1;k++){
t2=t1;
t4=t1<<2;
t5=(t6=ido<<1)+t4;
for(i=2;i<ido;i+=2){
t3=(t2+=2);
t4+=2;
t5-=2;
t3+=t0;
cr2=wa1[i-2]*cc[t3-1]+wa1[i-1]*cc[t3];
ci2=wa1[i-2]*cc[t3]-wa1[i-1]*cc[t3-1];
t3+=t0;
cr3=wa2[i-2]*cc[t3-1]+wa2[i-1]*cc[t3];
ci3=wa2[i-2]*cc[t3]-wa2[i-1]*cc[t3-1];
t3+=t0;
cr4=wa3[i-2]*cc[t3-1]+wa3[i-1]*cc[t3];
ci4=wa3[i-2]*cc[t3]-wa3[i-1]*cc[t3-1];
tr1=cr2+cr4;
tr4=cr4-cr2;
ti1=ci2+ci4;
ti4=ci2-ci4;
ti2=cc[t2]+ci3;
ti3=cc[t2]-ci3;
tr2=cc[t2-1]+cr3;
tr3=cc[t2-1]-cr3;
ch[t4-1]=tr1+tr2;
ch[t4]=ti1+ti2;
ch[t5-1]=tr3-ti4;
ch[t5]=tr4-ti3;
ch[t4+t6-1]=ti4+tr3;
ch[t4+t6]=tr4+ti3;
ch[t5+t6-1]=tr2-tr1;
ch[t5+t6]=ti1-ti2;
}
t1+=ido;
}
if(ido&1)return;
L105:
t2=(t1=t0+ido-1)+(t0<<1);
t3=ido<<2;
t4=ido;
t5=ido<<1;
t6=ido;
for(k=0;k<l1;k++){
ti1=-hsqt2*(cc[t1]+cc[t2]);
tr1=hsqt2*(cc[t1]-cc[t2]);
ch[t4-1]=tr1+cc[t6-1];
ch[t4+t5-1]=cc[t6-1]-tr1;
ch[t4]=ti1-cc[t1+t0];
ch[t4+t5]=ti1+cc[t1+t0];
t1+=ido;
t2+=ido;
t4+=t3;
t6+=ido;
}
}
static void drftf1(int n,float *c,float *ch,float *wa,int *ifac){
int i,k1,l1,l2;
int na,kh,nf;
int ip,iw,ido,idl1,ix2,ix3;
nf=ifac[1];
na=1;
l2=n;
iw=n;
for(k1=0;k1<nf;k1++){
kh=nf-k1;
ip=ifac[kh+1];
l1=l2/ip;
ido=n/l2;
idl1=ido*l1;
iw-=(ip-1)*ido;
na=1-na;
if(ip!=4)goto L102;
ix2=iw+ido;
ix3=ix2+ido;
if(na!=0)
dradf4(ido,l1,ch,c,wa+iw-1,wa+ix2-1,wa+ix3-1);
else
dradf4(ido,l1,c,ch,wa+iw-1,wa+ix2-1,wa+ix3-1);
goto L110;
L102:
if(ip!=2)goto L104;
if(na!=0)goto L103;
dradf2(ido,l1,c,ch,wa+iw-1);
goto L110;
L103:
dradf2(ido,l1,ch,c,wa+iw-1);
goto L110;
L104:
return; /* We're restricted to powers of two. just fail */
L110:
l2=l1;
}
if(na==1)return;
for(i=0;i<n;i++)c[i]=ch[i];
}
static void fdrfftf(int n,float *r,float *wsave,int *ifac){
if(n==1)return;
drftf1(n,r,wsave,wsave+n,ifac);
}
static void dradb2(int ido,int l1,float *cc,float *ch,float *wa1){
int i,k,t0,t1,t2,t3,t4,t5,t6;
float ti2,tr2;
t0=l1*ido;
t1=0;
t2=0;
t3=(ido<<1)-1;
for(k=0;k<l1;k++){
ch[t1]=cc[t2]+cc[t3+t2];
ch[t1+t0]=cc[t2]-cc[t3+t2];
t2=(t1+=ido)<<1;
}
if(ido<2)return;
if(ido==2)goto L105;
t1=0;
t2=0;
for(k=0;k<l1;k++){
t3=t1;
t5=(t4=t2)+(ido<<1);
t6=t0+t1;
for(i=2;i<ido;i+=2){
t3+=2;
t4+=2;
t5-=2;
t6+=2;
ch[t3-1]=cc[t4-1]+cc[t5-1];
tr2=cc[t4-1]-cc[t5-1];
ch[t3]=cc[t4]-cc[t5];
ti2=cc[t4]+cc[t5];
ch[t6-1]=wa1[i-2]*tr2-wa1[i-1]*ti2;
ch[t6]=wa1[i-2]*ti2+wa1[i-1]*tr2;
}
t2=(t1+=ido)<<1;
}
if(ido%2==1)return;
L105:
t1=ido-1;
t2=ido-1;
for(k=0;k<l1;k++){
ch[t1]=cc[t2]+cc[t2];
ch[t1+t0]=-(cc[t2+1]+cc[t2+1]);
t1+=ido;
t2+=ido<<1;
}
}
static void dradb4(int ido,int l1,float *cc,float *ch,float *wa1,
float *wa2,float *wa3){
static float sqrt2=1.4142135623730950488016887242097;
int i,k,t0,t1,t2,t3,t4,t5,t6,t7,t8;
float ci2,ci3,ci4,cr2,cr3,cr4,ti1,ti2,ti3,ti4,tr1,tr2,tr3,tr4;
t0=l1*ido;
t1=0;
t2=ido<<2;
t3=0;
t6=ido<<1;
for(k=0;k<l1;k++){
t4=t3+t6;
t5=t1;
tr3=cc[t4-1]+cc[t4-1];
tr4=cc[t4]+cc[t4];
tr1=cc[t3]-cc[(t4+=t6)-1];
tr2=cc[t3]+cc[t4-1];
ch[t5]=tr2+tr3;
ch[t5+=t0]=tr1-tr4;
ch[t5+=t0]=tr2-tr3;
ch[t5+=t0]=tr1+tr4;
t1+=ido;
t3+=t2;
}
if(ido<2)return;
if(ido==2)goto L105;
t1=0;
for(k=0;k<l1;k++){
t5=(t4=(t3=(t2=t1<<2)+t6))+t6;
t7=t1;
for(i=2;i<ido;i+=2){
t2+=2;
t3+=2;
t4-=2;
t5-=2;
t7+=2;
ti1=cc[t2]+cc[t5];
ti2=cc[t2]-cc[t5];
ti3=cc[t3]-cc[t4];
tr4=cc[t3]+cc[t4];
tr1=cc[t2-1]-cc[t5-1];
tr2=cc[t2-1]+cc[t5-1];
ti4=cc[t3-1]-cc[t4-1];
tr3=cc[t3-1]+cc[t4-1];
ch[t7-1]=tr2+tr3;
cr3=tr2-tr3;
ch[t7]=ti2+ti3;
ci3=ti2-ti3;
cr2=tr1-tr4;
cr4=tr1+tr4;
ci2=ti1+ti4;
ci4=ti1-ti4;
ch[(t8=t7+t0)-1]=wa1[i-2]*cr2-wa1[i-1]*ci2;
ch[t8]=wa1[i-2]*ci2+wa1[i-1]*cr2;
ch[(t8+=t0)-1]=wa2[i-2]*cr3-wa2[i-1]*ci3;
ch[t8]=wa2[i-2]*ci3+wa2[i-1]*cr3;
ch[(t8+=t0)-1]=wa3[i-2]*cr4-wa3[i-1]*ci4;
ch[t8]=wa3[i-2]*ci4+wa3[i-1]*cr4;
}
t1+=ido;
}
if(ido%2 == 1)return;
L105:
t1=ido;
t2=ido<<2;
t3=ido-1;
t4=ido+(ido<<1);
for(k=0;k<l1;k++){
t5=t3;
ti1=cc[t1]+cc[t4];
ti2=cc[t4]-cc[t1];
tr1=cc[t1-1]-cc[t4-1];
tr2=cc[t1-1]+cc[t4-1];
ch[t5]=tr2+tr2;
ch[t5+=t0]=sqrt2*(tr1-ti1);
ch[t5+=t0]=ti2+ti2;
ch[t5+=t0]=-sqrt2*(tr1+ti1);
t3+=ido;
t1+=t2;
t4+=t2;
}
}
static void drftb1(int n, float *c, float *ch, float *wa, int *ifac){
int i,k1,l1,l2;
int na;
int nf,ip,iw,ix2,ix3,ido,idl1;
nf=ifac[1];
na=0;
l1=1;
iw=1;
for(k1=0;k1<nf;k1++){
ip=ifac[k1 + 2];
l2=ip*l1;
ido=n/l2;
idl1=ido*l1;
if(ip!=4)goto L103;
ix2=iw+ido;
ix3=ix2+ido;
if(na!=0)
dradb4(ido,l1,ch,c,wa+iw-1,wa+ix2-1,wa+ix3-1);
else
dradb4(ido,l1,c,ch,wa+iw-1,wa+ix2-1,wa+ix3-1);
na=1-na;
goto L115;
L103:
if(ip!=2)goto L106;
if(na!=0)
dradb2(ido,l1,ch,c,wa+iw-1);
else
dradb2(ido,l1,c,ch,wa+iw-1);
na=1-na;
goto L115;
L106:
return; /* silently fail. we only do powers of two in this version */
L115:
l1=l2;
iw+=(ip-1)*ido;
}
if(na==0)return;
for(i=0;i<n;i++)c[i]=ch[i];
}
static void fdrfftb(int n, float *r, float *wsave, int *ifac){
if (n == 1)return;
drftb1(n, r, wsave, wsave+n, ifac);
}
void fft_forward(int n, float *buf,float *trigcache,int *splitcache){
int flag=0;
if(!trigcache || !splitcache){
trigcache=calloc(3*n,sizeof(float));
splitcache=calloc(32,sizeof(int));
fdrffti(n, trigcache, splitcache);
flag=1;
}
fdrfftf(n, buf, trigcache, splitcache);
if(flag){
free(trigcache);
free(splitcache);
}
}
void fft_backward(int n, float *buf, float *trigcache,int *splitcache){
int i;
int flag=0;
if(!trigcache || !splitcache){
trigcache=calloc(3*n,sizeof(float));
splitcache=calloc(32,sizeof(int));
fdrffti(n, trigcache, splitcache);
flag=1;
}
fdrfftb(n, buf, trigcache, splitcache);
for(i=0;i<n;i++)buf[i]/=n;
if(flag){
free(trigcache);
free(splitcache);
}
}
void fft_i(int n, float **trigcache, int **splitcache){
*trigcache=calloc(3*n,sizeof(float));
*splitcache=calloc(32,sizeof(int));
fdrffti(n, *trigcache, *splitcache);
}

View File

@@ -0,0 +1,28 @@
/*
$Id: smallft.h,v 1.2 2008/04/16 17:00:40 karl Exp $
Copyright (C) 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
/******************************************************************
* FFT implementation from OggSquish, minus cosine transforms.
* Only convenience functions exposed
******************************************************************/
extern void fft_forward(int n, float *buf, float *trigcache, int *sp);
extern void fft_backward(int n, float *buf, float *trigcache, int *sp);
extern void fft_i(int n, float **trigcache, int **splitcache);

View File

@@ -0,0 +1,235 @@
/*
$Id: test_interface.c,v 1.4 2008/06/13 19:26:23 flameeyes Exp $
Copyright (C) 2004, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
/******************************************************************
*
* Fake interface backend for testing paranoia layer
* NOTE: THIS CODE HAVE BEEN FOLDED INTO THE MAINLINE CODE SO IT IS
* NOT USED ANYMORE. (It's not clear that it had been used
* for a while in the non-libcdio cdparaonoia either.)
*
******************************************************************/
#ifdef CDDA_TEST
#include "low_interface.h"
#include "utils.h"
/* Build which test model? */
#define CDDA_TEST_OK
#undef CDDA_TEST_JITTER_SMALL
#undef CDDA_TEST_JITTER_LARGE
#undef CDDA_TEST_JITTER_MASSIVE
#undef CDDA_TEST_FRAG_SMALL
#undef CDDA_TEST_FRAG_LARGE
#undef CDDA_TEST_FRAG_MASSIVE
#undef CDDA_TEST_BOGUS_BYTES
#undef CDDA_TEST_DROPDUPE_BYTES
#undef CDDA_TEST_SCRATCH
#undef CDDA_TEST_UNDERRUN
#undef CDDA_TEST_ALLJITTER
#undef CDDA_TEST_SOMEJITTER
#undef CDDA_TEST_SEEKJITTER
static int test_readtoc (cdrom_drive *d){
int tracks=0;
long bytes;
long sectors;
/* only one track, as many sectors as the file */
bytes=lseek(d->cdda_fd,0,SEEK_END);
lseek(d->cdda_fd,0,SEEK_SET);
sectors=bytes/CDIO_CD_FRAMESIZE_RAW;
d->disc_toc[0].bFlags = 0;
d->disc_toc[0].bTrack = 1;
d->disc_toc[0].dwStartSector = 37;
d->disc_toc[1].bFlags = 0x4;
d->disc_toc[1].bTrack = CDROM_LEADOUT;
d->disc_toc[1].dwStartSector = sectors+37;
tracks=2;
d->cd_extra=0;
return(--tracks); /* without lead-out */
}
/* we emulate jitter, scratches, atomic jitter and bogus bytes on
boundaries, etc */
static long
test_read(cdrom_drive *d, void *p, long begin, long sectors)
{
#if defined(CDDA_TEST_SEEKJITTER) \
|| defined(CDDA_TEST_ALLJITTER) \
|| defined(CDDA_TEST_SOMEJITTER)
int jitter_flag=0;
#endif
int los_flag=0;
static int jitter=0;
int bytes_so_far=0;
long bytestotal;
static FILE *fd=NULL;
static long lastread=0;
if(!fd)fd=fdopen(d->cdda_fd,"r");
#ifdef CDDA_TEST_UNDERRUN
sectors-=1;
#endif
#ifdef CDDA_TEST_SEEKJITTER
if(lastread!=begin)jitter_flag=1;
#else
#ifdef CDDA_TEST_ALLJITTER
jitter_flag=1;
#else
#ifdef CDDA_TEST_SOMEJITTER
jitter_flag=(drand48()>.9?1:0);
los_flag=(drand48()>.9?1:0);
#else
los_flag=1;
#endif
#endif
#endif
lastread=begin+sectors;
bytestotal=sectors*CDIO_CD_FRAMESIZE_RAW;
begin*=CDIO_CD_FRAMESIZE_RAW;
while(bytes_so_far<bytestotal){
int inner_bytes=bytestotal-bytes_so_far;
char *inner_buf=(char *)p + bytes_so_far;
long seeki;
long rbytes;
long this_bytes=inner_bytes;
#ifdef CDDA_TEST_OK
#else
#ifdef CDDA_TEST_JITTER_SMALL
if(jitter_flag)jitter=4*(int)((drand48()-.5)*CDIO_CD_FRAMESIZE_RAW/8);
#else
#ifdef CDDA_TEST_JITTER_LARGE
if(jitter_flag)jitter=32*(int)((drand48()-.5)*CDIO_CD_FRAMESIZE_RAW/8);
#else
#ifdef CDDA_TEST_JITTER_MASSIVE
if(jitter_flag)jitter=128*(int)((drand48()-.5)*CDIO_CD_FRAMESIZE_RAW/8);
#else
#ifdef CDDA_TEST_FRAG_SMALL
if(los_flag)this_bytes=256*(int)(drand48()*CDIO_CD_FRAMESIZE_RAW/8);
if(jitter_flag)jitter=4*(int)((drand48()-.5)*CDIO_CD_FRAMESIZE_RAW/8);
#else
#ifdef CDDA_TEST_FRAG_LARGE
if(los_flag)this_bytes=16*(int)(drand48()*CDIO_CD_FRAMESIZE_RAW/8);
if(jitter_flag)jitter=4*(int)((drand48()-.5)*CDIO_CD_FRAMESIZE_RAW/8);
#else
#ifdef CDDA_TEST_FRAG_MASSIVE
if(los_flag)this_bytes=8*(int)(drand48()*CDIO_CD_FRAMESIZE_RAW/8);
if(jitter_flag)jitter=32*(int)((drand48()-.5)*CDIO_CD_FRAMESIZE_RAW/8);
#else
#ifdef CDDA_TEST_DROPDUPE_BYTES
if(los_flag)this_bytes=CDIO_CD_FRAMESIZE_RAW;
if(jitter_flag)
if (drand48()>.8)
this_jitter=32;
else
this_jitter=0;
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
if(this_bytes>inner_bytes)this_bytes=inner_bytes;
if(begin+jitter+bytes_so_far<0)jitter=0;
seeki=begin+bytes_so_far+jitter;
if(fseek(fd,seeki,SEEK_SET)<0){
return(0);
}
rbytes=fread(inner_buf,1,this_bytes,fd);
bytes_so_far+=rbytes;
if(rbytes==0)break;
#ifdef CDDA_TEST_SEEKJITTER
jitter_flag=0;
los_flag=0;
#else
#ifdef CDDA_TEST_ALLJITTER
jitter_flag=1;
los_flag=0;
#else
#ifdef CDDA_TEST_SOMEJITTER
jitter_flag=(drand48()>.9?1:0);
los_flag=(drand48()>.9?1:0);
#else
los_flag=1;
#endif
#endif
#endif
}
#ifdef CDDA_TEST_SCRATCH
{
long location=300*CDIO_CD_FRAMESIZE_RAW+(drand48()*56)+512;
if(begin<=location && begin+bytestotal>location){
memset(p+location-begin,(int)(drand48()*256),1100);
}
}
#endif
return(sectors);
}
/* set function pointers to use the ioctl routines */
int test_init_drive (cdrom_drive *d){
d->nsectors=13;
d->enable_cdda = dummy_exception;
d->read_audio = test_read;
d->read_toc = test_readtoc;
d->set_speed = dummy_exception;
d->tracks=d->read_toc(d);
if(d->tracks==-1)
return(d->tracks);
d->opened=1;
srand48(0);
return(0);
}
#endif

210
lib/cdda_interface/toc.c Normal file
View File

@@ -0,0 +1,210 @@
/*
$Id: toc.c,v 1.7 2008/04/16 17:00:40 karl Exp $
Copyright (C) 2005, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
derived from code (C) 1994-1996 Heiko Eissfeldt
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 3 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, see <http://www.gnu.org/licenses/>.
*/
/******************************************************************
* Table of contents convenience functions
******************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "low_interface.h"
#include "utils.h"
/*! Return the lsn for the start of track i_track */
lsn_t
cdda_track_firstsector(cdrom_drive_t *d, track_t i_track)
{
if(!d->opened){
cderror(d,"400: Device not open\n");
return(-1);
}
if (i_track == 0) {
if (d->disc_toc[0].dwStartSector == 0) {
/* first track starts at lsn 0 -> no pre-gap */
cderror(d,"401: Invalid track number\n");
return(-1);
}
else {
return 0; /* pre-gap of first track always starts at lba 0 */
}
}
if( i_track>d->tracks) {
cderror(d,"401: Invalid track number\n");
return(-1);
}
{
const track_t i_first_track = cdio_get_first_track_num(d->p_cdio);
return(d->disc_toc[i_track-i_first_track].dwStartSector);
}
}
/*! Get first lsn of the first audio track. -1 is returned on error. */
lsn_t
cdda_disc_firstsector(cdrom_drive_t *d)
{
int i;
if(!d->opened){
cderror(d,"400: Device not open\n");
return(-1);
}
/* look for an audio track */
for ( i=0; i<d->tracks; i++ )
if( cdda_track_audiop(d, i+1)==1 ) {
if (i == 0) /* disc starts at lba 0 if first track is an audio track */
return 0;
else
return cdda_track_firstsector(d, i+1);
}
cderror(d,"403: No audio tracks on disc\n");
return(-1);
}
/*! Get last lsn of the track. The lsn is generally one less than the
start of the next track. -1 is returned on error. */
lsn_t
cdda_track_lastsector(cdrom_drive_t *d, track_t i_track)
{
if (!d->opened) {
cderror(d,"400: Device not open\n");
return -1;
}
if (i_track == 0) {
if (d->disc_toc[0].dwStartSector == 0) {
/* first track starts at lba 0 -> no pre-gap */
cderror(d,"401: Invalid track number\n");
return(-1);
}
else {
return d->disc_toc[0].dwStartSector-1;
}
}
if ( i_track<1 || i_track>d->tracks ) {
cderror(d,"401: Invalid track number\n");
return -1;
}
/* CD Extra have their first session ending at the last audio track */
if (d->cd_extra > 0 && i_track+1 <= d->tracks) {
if (d->audio_last_sector >= d->disc_toc[i_track-1].dwStartSector &&
d->audio_last_sector < d->disc_toc[i_track].dwStartSector) {
return d->audio_last_sector;
}
}
/* Safe, we've always the leadout at disc_toc[tracks] */
return(d->disc_toc[i_track].dwStartSector-1);
}
/*! Get last lsn of the last audio track. The last lssn generally one
less than the start of the next track after the audio track. -1 is
returned on error. */
lsn_t
cdda_disc_lastsector(cdrom_drive_t *d)
{
if (!d->opened) {
cderror(d,"400: Device not open\n");
return -1;
} else {
/* look for an audio track */
const track_t i_first_track = cdio_get_first_track_num(d->p_cdio);
track_t i = cdio_get_last_track_num(d->p_cdio);
for ( ; i >= i_first_track; i-- )
if ( cdda_track_audiop(d,i) )
return (cdda_track_lastsector(d,i));
}
cderror(d,"403: No audio tracks on disc\n");
return -1;
}
/*! Return the number of tracks on the CD. */
track_t
cdda_tracks(cdrom_drive_t *d)
{
if (!d->opened){
cderror(d,"400: Device not open\n");
return -1;
}
return(d->tracks);
}
/*! Return the track containing the given LSN. If the LSN is before
the first track (in the pregap), 0 is returned. If there was an
error or the LSN after the LEADOUT (beyond the end of the CD), then
CDIO_INVALID_TRACK is returned.
*/
int
cdda_sector_gettrack(cdrom_drive_t *d, lsn_t lsn)
{
if (!d->opened) {
cderror(d,"400: Device not open\n");
return -1;
} else {
if (lsn < d->disc_toc[0].dwStartSector)
return 0; /* We're in the pre-gap of first track */
return cdio_get_track(d->p_cdio, lsn);
}
}
/*! Return the number of channels in track: 2 or 4; -2 if not
implemented or -1 for error.
Not meaningful if track is not an audio track.
*/
int
cdda_track_channels(cdrom_drive_t *d, track_t i_track)
{
return(cdio_get_track_channels(d->p_cdio, i_track));
}
/*! Return 1 is track is an audio track, 0 otherwise. */
int
cdda_track_audiop(cdrom_drive_t *d, track_t i_track)
{
track_format_t track_format = cdio_get_track_format(d->p_cdio, i_track);
return TRACK_FORMAT_AUDIO == track_format ? 1 : 0;
}
/*! Return 1 is track is an audio track, 0 otherwise. */
int
cdda_track_copyp(cdrom_drive_t *d, track_t i_track)
{
track_flag_t track_flag = cdio_get_track_copy_permit(d->p_cdio, i_track);
return CDIO_TRACK_FLAG_TRUE == track_flag ? 1 : 0;
}
/*! Return 1 is audio track has linear preemphasis set, 0 otherwise.
Only makes sense for audio tracks.
*/
int
cdda_track_preemp(cdrom_drive_t *d, track_t i_track)
{
track_flag_t track_flag = cdio_get_track_preemphasis(d->p_cdio, i_track);
return CDIO_TRACK_FLAG_TRUE == track_flag ? 1 : 0;
}

152
lib/cdda_interface/utils.c Normal file
View File

@@ -0,0 +1,152 @@
/*
$Id: utils.c,v 1.4 2008/04/16 17:00:41 karl Exp $
Copyright (C) 2004, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "common_interface.h"
#include "utils.h"
void
cderror(cdrom_drive_t *d,const char *s)
{
if(s && d){
switch(d->errordest){
case CDDA_MESSAGE_PRINTIT:
write(STDERR_FILENO,s,strlen(s));
break;
case CDDA_MESSAGE_LOGIT:
d->errorbuf=catstring(d->errorbuf,s);
break;
case CDDA_MESSAGE_FORGETIT:
default: ;
}
}
}
void
cdmessage(cdrom_drive_t *d, const char *s)
{
if(s && d){
switch(d->messagedest){
case CDDA_MESSAGE_PRINTIT:
write(STDERR_FILENO,s,strlen(s));
break;
case CDDA_MESSAGE_LOGIT:
d->messagebuf=catstring(d->messagebuf,s);
break;
case CDDA_MESSAGE_FORGETIT:
default: ;
}
}
}
void
idperror(int messagedest,char **messages,const char *f,
const char *s)
{
char *buffer;
int malloced=0;
if(!f)
buffer=(char *)s;
else
if(!s)
buffer=(char *)f;
else{
buffer=malloc(strlen(f)+strlen(s)+9);
sprintf(buffer,f,s);
malloced=1;
}
if(buffer){
switch(messagedest){
case CDDA_MESSAGE_PRINTIT:
write(STDERR_FILENO,buffer,strlen(buffer));
if(errno){
write(STDERR_FILENO,": ",2);
write(STDERR_FILENO,strerror(errno),strlen(strerror(errno)));
write(STDERR_FILENO,"\n",1);
}
break;
case CDDA_MESSAGE_LOGIT:
if(messages){
*messages=catstring(*messages,buffer);
if(errno){
*messages=catstring(*messages,": ");
*messages=catstring(*messages,strerror(errno));
*messages=catstring(*messages,"\n");
}
}
break;
case CDDA_MESSAGE_FORGETIT:
default: ;
}
}
if(malloced)free(buffer);
}
void
idmessage(int messagedest,char **messages,const char *f,
const char *s)
{
char *buffer;
int malloced=0;
if(!f)
buffer=(char *)s;
else
if(!s)
buffer=(char *)f;
else{
const unsigned int i_buffer=strlen(f)+strlen(s)+10;
buffer=malloc(i_buffer);
sprintf(buffer,f,s);
strncat(buffer,"\n", i_buffer);
malloced=1;
}
if(buffer){
switch(messagedest){
case CDDA_MESSAGE_PRINTIT:
write(STDERR_FILENO,buffer,strlen(buffer));
if(!malloced)write(STDERR_FILENO,"\n",1);
break;
case CDDA_MESSAGE_LOGIT:
if(messages){
*messages=catstring(*messages,buffer);
if(!malloced)*messages=catstring(*messages,"\n");
}
break;
case CDDA_MESSAGE_FORGETIT:
default: ;
}
}
if(malloced)free(buffer);
}
char *
catstring(char *buff, const char *s) {
if (s) {
const unsigned int add_len = strlen(s) + 9;
if(buff) {
buff = realloc(buff, strlen(buff) + add_len);
} else {
buff=calloc(add_len, 1);
}
strncat(buff, s, add_len);
}
return(buff);
}

View File

@@ -0,0 +1,79 @@
/*
$Id: utils.h,v 1.8 2008/04/16 17:00:41 karl Exp $
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <cdio/bytesex.h>
#include <stdio.h>
/* I wonder how many alignment issues this is gonna trip in the
future... it shouldn't trip any... I guess we'll find out :) */
static inline int
bigendianp(void)
{
int test=1;
char *hack=(char *)(&test);
if(hack[0])return(0);
return(1);
}
extern char *catstring(char *buff, const char *s);
/*#if BYTE_ORDER == LITTLE_ENDIAN*/
#ifndef WORDS_BIGENDIAN
static inline int16_t be16_to_cpu(int16_t x){
return(UINT16_SWAP_LE_BE_C(x));
}
static inline int16_t le16_to_cpu(int16_t x){
return(x);
}
#else
static inline int16_t be16_to_cpu(int16_t x){
return(x);
}
static inline int16_t le16_to_cpu(int16_t x){
return(UINT16_SWAP_LE_BE_C(x));
}
#endif
static inline int16_t cpu_to_be16(int16_t x){
return(be16_to_cpu(x));
}
static inline int16_t cpu_to_le16(int16_t x){
return(le16_to_cpu(x));
}
void cderror(cdrom_drive_t *d, const char *s);
void cdmessage(cdrom_drive_t *d,const char *s);
void idperror(int messagedest, char **messages, const char *f, const char *s);
void idmessage(int messagedest, char **messages, const char *f, const char *s);

3
lib/cdio++/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/.deps
/Makefile
/Makefile.in

65
lib/cdio++/Makefile.am Normal file
View File

@@ -0,0 +1,65 @@
# $Id: Makefile.am,v 1.11 2008/10/29 09:53:00 rocky Exp $
#
# Copyright (C) 2005, 2006, 2007, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
########################################################
# Things to make the libcdio++ library
########################################################
#
# From libtool documentation amended with guidance from N. Boullis:
#
# 1. Start with version information of `0:0:0' for each libtool library.
#
# 2. It is probably not a good idea to update the version information
# several times between public releases, but rather once per public
# release. (This seems to be more an aesthetic consideration than
# a hard technical one.)
#
# 3. If the library source code has changed at all since the last
# update, then increment REVISION (`C:R:A' becomes `C:R+1:A').
#
# 4. If any interfaces have been added, removed, or changed since the
# last update, increment CURRENT, and set REVISION to 0.
#
# 5. If any interfaces have been added since the last public release,
# then increment AGE.
#
# 6. If any interfaces have been removed or changed since the last
# public release, then set AGE to 0. A changed interface means an
# incompatibility with previous versions.
lib_LTLIBRARIES = libiso9660++.la libcdio++.la
libcdiopp_la_CURRENT = 0
libcdiopp_la_REVISION = 2
libcdiopp_la_AGE = 0
libcdiopp_sources = cdio.cpp devices.cpp
libcdio___la_SOURCES = $(libcdiopp_sources)
libcdio___la_ldflags = -version-info $(libcdiopp_la_CURRENT):$(libcdiopp_la_REVISION):$(libcdiopp_la_AGE) @LT_NO_UNDEFINED@
libiso9660pp_la_CURRENT = 0
libiso9660pp_la_REVISION = 0
libiso9660pp_la_AGE = 0
libiso9660pp_sources = iso9660.cpp
libiso9660___la_SOURCES = $(libiso9660pp_sources)
libiso9660___la_LIBADD = $(LIBISO9660_LIBS) $(LIBCDIO_LIBS)
libiso9660___la_ldflags = -version-info $(libiso9660pp_la_CURRENT):$(libiso9660pp_la_REVISION):$(libiso9660pp_la_AGE) @LT_NO_UNDEFINED@
INCLUDES = -I$(top_srcdir)/include/ -I$(top_builddir)/include

44
lib/cdio++/cdio.cpp Normal file
View File

@@ -0,0 +1,44 @@
/* -*- C++ -*-
$Id: cdio.cpp,v 1.2 2008/04/20 13:44:31 karl Exp $
Copyright (C) 2006, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <sys/types.h>
#include <cdio++/cdio.hpp>
void possible_throw_device_exception(driver_return_code_t drc)
{
switch (drc) {
case DRIVER_OP_SUCCESS:
return;
case DRIVER_OP_ERROR:
throw DriverOpError();
case DRIVER_OP_UNSUPPORTED:
throw DriverOpUnsupported();
case DRIVER_OP_UNINIT:
throw DriverOpUninit();
case DRIVER_OP_NOT_PERMITTED:
throw DriverOpNotPermitted();
case DRIVER_OP_BAD_PARAMETER:
throw DriverOpBadParameter();
case DRIVER_OP_BAD_POINTER:
throw DriverOpBadPointer();
case DRIVER_OP_NO_DRIVER:
throw DriverOpNoDriver();
default:
throw DriverOpException(drc);
}
}

244
lib/cdio++/devices.cpp Normal file
View File

@@ -0,0 +1,244 @@
/* -*- C++ -*-
$Id: devices.cpp,v 1.3 2008/04/20 13:44:31 karl Exp $
Copyright (C) 2006, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <cdio/cdio.h>
#include <cdio++/cdio.hpp>
/*!
Close media tray in CD drive if there is a routine to do so.
@param psz_drive the name of CD-ROM to be closed.
@param driver_id is the driver to be used or that got used if
it was DRIVER_UNKNOWN or DRIVER_DEVICE; If this is NULL, we won't
report back the driver used.
*/
void closeTray (const char *psz_drive, /*in/out*/ driver_id_t &driver_id)
{
driver_return_code_t drc = cdio_close_tray (psz_drive, &driver_id);
possible_throw_device_exception(drc);
}
/*!
Close media tray in CD drive if there is a routine to do so.
@param psz_drive the name of CD-ROM to be closed. If omitted or
NULL, we'll scan for a suitable CD-ROM.
*/
void closeTray (const char *psz_drive)
{
driver_id_t driver_id = DRIVER_UNKNOWN;
closeTray(psz_drive, driver_id);
}
/*!
Get a string decribing driver_id.
@param driver_id the driver you want the description for
@return a sring of driver description
*/
const char *
driverDescribe (driver_id_t driver_id)
{
return cdio_driver_describe(driver_id);
}
/*!
Eject media in CD drive if there is a routine to do so.
If the CD is ejected, object is destroyed.
*/
void
ejectMedia (const char *psz_drive)
{
driver_return_code_t drc = cdio_eject_media_drive(psz_drive);
possible_throw_device_exception(drc);
}
/*!
Free device list returned by GetDevices
@param device_list list returned by GetDevices
@see GetDevices
*/
void
freeDeviceList (char * device_list[])
{
cdio_free_device_list(device_list);
}
/*!
Return a string containing the default CD device if none is specified.
if p_driver_id is DRIVER_UNKNOWN or DRIVER_DEVICE
then find a suitable one set the default device for that.
NULL is returned if we couldn't get a default device.
*/
char *
getDefaultDevice(/*in/out*/ driver_id_t &driver_id)
{
return cdio_get_default_device_driver(&driver_id);
}
/*! Return an array of device names. If you want a specific
devices for 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.
In some situations of drivers or OS's we can't find a CD device if
there is no media in it and it is possible for this routine to return
NULL even though there may be a hardware CD-ROM.
*/
char **
getDevices(driver_id_t driver_id)
{
return cdio_get_devices(driver_id);
}
/*! Like GetDevices above, but we may change the p_driver_id if we
were given DRIVER_DEVICE or DRIVER_UNKNOWN. This is because
often one wants to get a drive name and then *open* it
afterwards. Giving the driver back facilitates this, and speeds
things up for libcdio as well.
*/
char **
getDevices (driver_id_t &driver_id)
{
return cdio_get_devices_ret(&driver_id);
}
/*!
Get an array of device names in search_devices that have at least
the capabilities listed by the capabities parameter. If
search_devices is NULL, then we'll search all possible CD drives.
If "b_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.
@return the array of device names or NULL if we couldn't get a
default device. It is also possible to return a non NULL but
after dereferencing the the value is NULL. This also means nothing
was found.
*/
char **
getDevices(/*in*/ char *ppsz_search_devices[],
cdio_fs_anal_t capabilities, bool b_any)
{
return cdio_get_devices_with_cap(ppsz_search_devices, capabilities, b_any);
}
/*!
Like GetDevices above but we return the driver we found
as well. This is because often one wants to search for kind of drive
and then *open* it afterwards. Giving the driver back facilitates this,
and speeds things up for libcdio as well.
*/
char **
getDevices(/*in*/ char* ppsz_search_devices[],
cdio_fs_anal_t capabilities, /*out*/ driver_id_t &driver_id,
bool b_any)
{
return cdio_get_devices_with_cap_ret(ppsz_search_devices, capabilities,
b_any, &driver_id);
}
/*! Return true if we Have driver for driver_id */
bool
haveDriver (driver_id_t driver_id)
{
return cdio_have_driver(driver_id);
}
/*!
Determine if bin_name is the bin file part of a CDRWIN CD disk image.
@param bin_name location of presumed CDRWIN bin image file.
@return the corresponding CUE file if bin_name is a BIN file or
NULL if not a BIN file.
*/
char *isBinFile(const char *psz_bin_name)
{
return cdio_is_binfile(psz_bin_name);
}
/*!
Determine if cue_name is the cue sheet for a CDRWIN CD disk image.
@return corresponding BIN file if cue_name is a CDRWIN cue file or
NULL if not a CUE file.
*/
char *
isCueFile(const char *psz_cue_name)
{
return cdio_is_cuefile(psz_cue_name);
}
/*!
Determine if psz_source refers to a real hardware CD-ROM.
@param psz_source location name of object
@param driver_id driver for reading object. Use DRIVER_UNKNOWN if you
don't know what driver to use.
@return true if psz_source is a device; If false is returned we
could have a CD disk image.
*/
bool
isDevice(const char *psz_source, driver_id_t driver_id)
{
return cdio_is_device(psz_source, driver_id);
}
/*!
Determine if psz_nrg is a Nero CD disk image.
@param psz_nrg location of presumed NRG image file.
@return true if psz_nrg is a Nero NRG image or false
if not a NRG image.
*/
bool
isNero(const char *psz_nrg)
{
return cdio_is_nrg(psz_nrg);
}
/*!
Determine if psz_toc is a TOC file for a cdrdao CD disk image.
@param psz_toc location of presumed TOC image file.
@return true if toc_name is a cdrdao TOC file or false
if not a TOC file.
*/
bool
isTocFile(const char *psz_toc)
{
return cdio_is_tocfile(psz_toc);
}

295
lib/cdio++/iso9660.cpp Normal file
View File

@@ -0,0 +1,295 @@
/* -*- C++ -*-
$Id: iso9660.cpp,v 1.5 2008/04/20 13:44:31 karl Exp $
Copyright (C) 2006, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <cdio++/iso9660.hpp>
/*!
Given a directory pointer, find the filesystem entry that contains
lsn and return information about it.
@return Stat * of entry if we found lsn, or NULL otherwise.
Caller must free return value.
*/
ISO9660::Stat *
ISO9660::FS::find_lsn(lsn_t i_lsn)
{
return new Stat(iso9660_find_fs_lsn(p_cdio, i_lsn));
}
/*!
Read the Primary Volume Descriptor for a CD.
True is returned if read, and false if there was an error.
*/
ISO9660::PVD *
ISO9660::FS::read_pvd ()
{
iso9660_pvd_t pvd;
bool b_okay = iso9660_fs_read_pvd (p_cdio, &pvd);
if (b_okay) {
return new PVD(&pvd);
}
return (PVD *) NULL;
}
/*!
Read the Super block of an ISO 9660 image. This is the
Primary Volume Descriptor (PVD) and perhaps a Supplemental Volume
Descriptor if (Joliet) extensions are acceptable.
*/
bool
ISO9660::FS::read_superblock (iso_extension_mask_t iso_extension_mask)
{
return iso9660_fs_read_superblock (p_cdio, iso_extension_mask);
}
/*! Read psz_path (a directory) and return a list of iso9660_stat_t
pointers for the files inside that directory. The caller must free the
returned result.
*/
bool
ISO9660::FS::readdir (const char psz_path[], stat_vector_t& stat_vector,
bool b_mode2)
{
CdioList_t * p_stat_list = iso9660_fs_readdir (p_cdio, psz_path,
b_mode2);
if (p_stat_list) {
CdioListNode_t *p_entnode;
_CDIO_LIST_FOREACH (p_entnode, p_stat_list) {
iso9660_stat_t *p_statbuf =
(iso9660_stat_t *) _cdio_list_node_data (p_entnode);
stat_vector.push_back(new ISO9660::Stat(p_statbuf));
}
_cdio_list_free (p_stat_list, false);
return true;
} else {
return false;
}
}
/*! Close previously opened ISO 9660 image and free resources
associated with the image. Call this when done using using an ISO
9660 image.
@return true is unconditionally returned. If there was an error
false would be returned.
*/
bool
ISO9660::IFS::close()
{
iso9660_close(p_iso9660);
p_iso9660 = (iso9660_t *) NULL;
return true;
}
/*!
Given a directory pointer, find the filesystem entry that contains
lsn and return information about it.
Returns Stat* of entry if we found lsn, or NULL otherwise.
*/
ISO9660::Stat *
ISO9660::IFS::find_lsn(lsn_t i_lsn)
{
return new Stat(iso9660_ifs_find_lsn(p_iso9660, i_lsn));
}
/*!
Return the Joliet level recognized.
*/
uint8_t
ISO9660::IFS::get_joliet_level()
{
return iso9660_ifs_get_joliet_level(p_iso9660);
}
/*!
Return true if ISO 9660 image has extended attrributes (XA).
*/
bool
ISO9660::IFS::is_xa ()
{
return iso9660_ifs_is_xa (p_iso9660);
}
/*! Open an ISO 9660 image for "fuzzy" reading. This means that we
will try to guess various internal offset based on internal
checks. This may be useful when trying to read an ISO 9660 image
contained in a file format that libiso9660 doesn't know natively
(or knows imperfectly.)
Maybe in the future we will have a mode. NULL is returned on
error.
@see open
*/
bool
ISO9660::IFS::open_fuzzy (const char *psz_path,
iso_extension_mask_t iso_extension_mask,
uint16_t i_fuzz)
{
p_iso9660 = iso9660_open_fuzzy_ext(psz_path, iso_extension_mask, i_fuzz);
//return p_iso9660 != (iso9660_t *) NULL;
return true;
}
/*! Read the Primary Volume Descriptor for an ISO 9660 image. A
PVD object is returned if read, and NULL if there was an error.
*/
ISO9660::PVD *
ISO9660::IFS::read_pvd ()
{
iso9660_pvd_t pvd;
bool b_okay = iso9660_ifs_read_pvd (p_iso9660, &pvd);
if (b_okay) {
return new PVD(&pvd);
}
return (PVD *) NULL;
}
/*!
Read the Super block of an ISO 9660 image but determine framesize
and datastart and a possible additional offset. Generally here we are
not reading an ISO 9660 image but a CD-Image which contains an ISO 9660
filesystem.
@see read_superblock
*/
bool
ISO9660::IFS::read_superblock (iso_extension_mask_t iso_extension_mask,
uint16_t i_fuzz)
{
return iso9660_ifs_read_superblock (p_iso9660, iso_extension_mask);
}
/*!
Read the Super block of an ISO 9660 image but determine framesize
and datastart and a possible additional offset. Generally here we are
not reading an ISO 9660 image but a CD-Image which contains an ISO 9660
filesystem.
@see read_superblock
*/
bool
ISO9660::IFS::read_superblock_fuzzy (iso_extension_mask_t iso_extension_mask,
uint16_t i_fuzz)
{
return iso9660_ifs_fuzzy_read_superblock (p_iso9660, iso_extension_mask,
i_fuzz);
}
char *
ISO9660::PVD::get_application_id()
{
return iso9660_get_application_id(&pvd);
}
int
ISO9660::PVD::get_pvd_block_size()
{
return iso9660_get_pvd_block_size(&pvd);
}
/*!
Return the PVD's preparer ID.
NULL is returned if there is some problem in getting this.
*/
char *
ISO9660::PVD::get_preparer_id()
{
return iso9660_get_preparer_id(&pvd);
}
/*!
Return the PVD's publisher ID.
NULL is returned if there is some problem in getting this.
*/
char *
ISO9660::PVD::get_publisher_id()
{
return iso9660_get_publisher_id(&pvd);
}
const char *
ISO9660::PVD::get_pvd_id()
{
return iso9660_get_pvd_id(&pvd);
}
int
ISO9660::PVD::get_pvd_space_size()
{
return iso9660_get_pvd_space_size(&pvd);
}
uint8_t
ISO9660::PVD::get_pvd_type() {
return iso9660_get_pvd_type(&pvd);
}
/*! Return the primary volume id version number (of pvd).
If there is an error 0 is returned.
*/
int
ISO9660::PVD::get_pvd_version()
{
return iso9660_get_pvd_version(&pvd);
}
/*! Return the LSN of the root directory for pvd.
If there is an error CDIO_INVALID_LSN is returned.
*/
lsn_t
ISO9660::PVD::get_root_lsn()
{
return iso9660_get_root_lsn(&pvd);
}
/*!
Return the PVD's system ID.
NULL is returned if there is some problem in getting this.
*/
char *
ISO9660::PVD::get_system_id()
{
return iso9660_get_system_id(&pvd);
}
/*!
Return the PVD's volume ID.
NULL is returned if there is some problem in getting this.
*/
char *
ISO9660::PVD::get_volume_id()
{
return iso9660_get_volume_id(&pvd);
}
/*!
Return the PVD's volumeset ID.
NULL is returned if there is some problem in getting this.
*/
char *
ISO9660::PVD::get_volumeset_id()
{
return iso9660_get_volumeset_id(&pvd);
}

3
lib/driver/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/.deps
/Makefile
/Makefile.in

View File

@@ -0,0 +1,22 @@
# $Id: Makefile,v 1.2 2008/04/21 18:30:19 karl Exp $
#
# Copyright (C) 2004, 2008 Rocky Bernstein
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
#
# The make is done above. This boilerplate Makefile just transfers the call
all install check clean:
cd .. && $(MAKE) $@

View File

@@ -0,0 +1,893 @@
/*
$Id: freebsd.c,v 1.38 2008/04/21 18:30:20 karl Exp $
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
/* This file contains FreeBSD-specific code and implements low-level
control of the CD drive. Culled initially I think from xine's or
mplayer's FreeBSD code with lots of modifications.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static const char _rcsid[] = "$Id: freebsd.c,v 1.38 2008/04/21 18:30:20 karl Exp $";
#include "freebsd.h"
#ifdef HAVE_FREEBSD_CDROM
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#include <netinet/in.h>
#include <cdio/sector.h>
static lba_t get_track_lba_freebsd(void *p_user_data, track_t i_track);
static access_mode_t
str_to_access_mode_freebsd(const char *psz_access_mode)
{
const access_mode_t default_access_mode = DEFAULT_FREEBSD_AM;
if (NULL==psz_access_mode) return default_access_mode;
if (!strcmp(psz_access_mode, "ioctl"))
return _AM_IOCTL;
else if (!strcmp(psz_access_mode, "CAM"))
return _AM_CAM;
else {
cdio_warn ("unknown access type: %s. Default ioctl used.",
psz_access_mode);
return default_access_mode;
}
}
static void
free_freebsd (void *p_obj)
{
_img_private_t *p_env = p_obj;
if (NULL == p_env) return;
if (NULL != p_env->device) free(p_env->device);
if (_AM_CAM == p_env->access_mode)
return free_freebsd_cam(p_env);
else
return cdio_generic_free(p_obj);
}
/* 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)
{
return cdio_is_cdrom_freebsd_ioctl(drive, mnttype);
}
/*!
Reads i_blocks of audio sectors from cd device into data starting from lsn.
Returns 0 if no error.
*/
static driver_return_code_t
read_audio_sectors_freebsd (void *p_user_data, void *p_buf, lsn_t i_lsn,
unsigned int i_blocks)
{
_img_private_t *p_env = p_user_data;
if ( p_env->access_mode == _AM_CAM ) {
return mmc_read_sectors( p_env->gen.cdio, p_buf, i_lsn,
CDIO_MMC_READ_TYPE_CDDA, i_blocks);
} else
return read_audio_sectors_freebsd_ioctl(p_user_data, p_buf, i_lsn,
i_blocks);
}
/*!
Reads a single mode2 sector from cd device into data starting
from i_lsn. Returns 0 if no error.
*/
static driver_return_code_t
read_mode2_sector_freebsd (void *p_user_data, void *data, lsn_t i_lsn,
bool b_form2)
{
_img_private_t *p_env = p_user_data;
if ( p_env->access_mode == _AM_CAM )
return read_mode2_sector_freebsd_cam(p_env, data, i_lsn, b_form2);
else
return read_mode2_sector_freebsd_ioctl(p_env, data, i_lsn, b_form2);
}
/*!
Reads i_blocks of mode2 sectors from cd device into data starting
from lsn.
*/
static driver_return_code_t
read_mode2_sectors_freebsd (void *p_user_data, void *p_data, lsn_t i_lsn,
bool b_form2, unsigned int i_blocks)
{
_img_private_t *p_env = p_user_data;
if ( p_env->access_mode == _AM_CAM && b_form2 ) {
/* We have a routine that covers this case without looping. */
return read_mode2_sectors_freebsd_cam(p_env, p_data, i_lsn, i_blocks);
} else {
unsigned int i;
uint16_t i_blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE;
/* For each frame, pick out the data part we need */
for (i = 0; i < i_blocks; i++) {
int retval = read_mode2_sector_freebsd (p_env,
((char *)p_data) +
(i_blocksize * i),
i_lsn + i, b_form2);
if (retval) return retval;
}
}
return DRIVER_OP_SUCCESS;
}
/*!
Return the size of the CD in logical block address (LBA) units.
@return the lsn. On error return CDIO_INVALID_LSN.
*/
static lsn_t
get_disc_last_lsn_freebsd (void *p_obj)
{
_img_private_t *p_env = p_obj;
if (!p_env) return CDIO_INVALID_LSN;
if (_AM_CAM == p_env->access_mode)
return get_disc_last_lsn_mmc(p_env);
else
return get_disc_last_lsn_freebsd_ioctl(p_env);
}
/*!
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
DRIVER_OP_SUCCESS is returned if no error was found,
and nonzero if there as an error.
*/
static driver_return_code_t
set_arg_freebsd (void *p_user_data, const char key[], const char value[])
{
_img_private_t *p_env = p_user_data;
if (!strcmp (key, "source"))
{
if (!value) return DRIVER_OP_ERROR;
free (p_env->gen.source_name);
p_env->gen.source_name = strdup (value);
}
else if (!strcmp (key, "access-mode"))
{
p_env->access_mode = str_to_access_mode_freebsd(value);
if (p_env->access_mode == _AM_CAM && !p_env->b_cam_init)
return init_freebsd_cam(p_env)
? DRIVER_OP_SUCCESS : DRIVER_OP_ERROR;
}
else return DRIVER_OP_ERROR;
return DRIVER_OP_SUCCESS;
}
/* Set CD-ROM drive speed */
static int
set_speed_freebsd (void *p_user_data, int i_speed)
{
const _img_private_t *p_env = p_user_data;
if (!p_env) return -1;
#ifdef CDRIOCREADSPEED
i_speed *= 177;
return ioctl(p_env->gen.fd, CDRIOCREADSPEED, &i_speed);
#else
return -2;
#endif
}
/*!
Read and cache the CD's Track Table of Contents and track info.
Return false if unsuccessful;
*/
static bool
read_toc_freebsd (void *p_user_data)
{
_img_private_t *p_env = p_user_data;
track_t i, j;
/* read TOC header */
if ( ioctl(p_env->gen.fd, CDIOREADTOCHEADER, &p_env->tochdr) == -1 ) {
cdio_warn("error in ioctl(CDIOREADTOCHEADER): %s\n", strerror(errno));
return false;
}
p_env->gen.i_first_track = p_env->tochdr.starting_track;
p_env->gen.i_tracks = p_env->tochdr.ending_track -
p_env->gen.i_first_track + 1;
j=0;
for (i=p_env->gen.i_first_track; i<=p_env->gen.i_tracks; i++, j++) {
struct ioc_read_toc_single_entry *p_toc =
&(p_env->tocent[i-p_env->gen.i_first_track]);
p_toc->track = i;
p_toc->address_format = CD_LBA_FORMAT;
if ( ioctl(p_env->gen.fd, CDIOREADTOCENTRY, p_toc) ) {
cdio_warn("%s %d: %s\n",
"error in ioctl CDROMREADTOCENTRY for track",
i, strerror(errno));
return false;
}
set_track_flags(&(p_env->gen.track_flags[i]), p_toc->entry.control);
}
p_env->tocent[j].track = CDIO_CDROM_LEADOUT_TRACK;
p_env->tocent[j].address_format = CD_LBA_FORMAT;
if ( ioctl(p_env->gen.fd, CDIOREADTOCENTRY, &(p_env->tocent[j]) ) ){
cdio_warn("%s: %s\n",
"error in ioctl CDROMREADTOCENTRY for leadout track",
strerror(errno));
return false;
}
p_env->gen.toc_init = true;
return true;
}
/*!
Get the volume of an audio CD.
@param p_cdio the CD object to be acted upon.
*/
static driver_return_code_t
audio_get_volume_freebsd (void *p_user_data,
/*out*/ cdio_audio_volume_t *p_volume)
{
const _img_private_t *p_env = p_user_data;
return ioctl(p_env->gen.fd, CDIOCGETVOL, p_volume);
}
/*!
Pause playing CD through analog output
@param p_cdio the CD object to be acted upon.
*/
static driver_return_code_t
audio_pause_freebsd (void *p_user_data)
{
const _img_private_t *p_env = p_user_data;
return ioctl(p_env->gen.fd, CDIOCPAUSE);
}
/*!
Playing starting at given MSF through analog output
@param p_cdio the CD object to be acted upon.
*/
static driver_return_code_t
audio_play_msf_freebsd (void *p_user_data, msf_t *p_start_msf,
msf_t *p_end_msf)
{
const _img_private_t *p_env = p_user_data;
struct ioc_play_msf freebsd_play_msf;
freebsd_play_msf.start_m = cdio_from_bcd8(p_start_msf->m);
freebsd_play_msf.start_s = cdio_from_bcd8(p_start_msf->s);
freebsd_play_msf.start_f = cdio_from_bcd8(p_start_msf->f);
freebsd_play_msf.end_m = cdio_from_bcd8(p_end_msf->m);
freebsd_play_msf.end_s = cdio_from_bcd8(p_end_msf->s);
freebsd_play_msf.end_f = cdio_from_bcd8(p_end_msf->f);
return ioctl(p_env->gen.fd, CDIOCPLAYMSF, &freebsd_play_msf);
}
/*!
Playing CD through analog output at the desired track and index
@param p_user_data the CD object to be acted upon.
@param p_track_index location to start/end.
*/
static driver_return_code_t
audio_play_track_index_freebsd (void *p_user_data,
cdio_track_index_t *p_track_index)
{
const _img_private_t *p_env = p_user_data;
msf_t start_msf;
msf_t end_msf;
struct ioc_play_msf freebsd_play_msf;
lsn_t i_lsn = get_track_lba_freebsd(p_user_data,
p_track_index->i_start_track);
cdio_lsn_to_msf(i_lsn, &start_msf);
i_lsn = get_track_lba_freebsd(p_user_data, p_track_index->i_end_track);
cdio_lsn_to_msf(i_lsn, &end_msf);
freebsd_play_msf.start_m = start_msf.m;
freebsd_play_msf.start_s = start_msf.s;
freebsd_play_msf.start_f = start_msf.f;
freebsd_play_msf.end_m = end_msf.m;
freebsd_play_msf.end_s = end_msf.s;
freebsd_play_msf.end_f = end_msf.f;
return ioctl(p_env->gen.fd, CDIOCPLAYMSF, &freebsd_play_msf);
}
/*!
Read Audio Subchannel information
@param p_user_data the CD object to be acted upon.
@param p_subchannel returned information
*/
#if 1
static driver_return_code_t
audio_read_subchannel_freebsd (void *p_user_data,
/*out*/ cdio_subchannel_t *p_subchannel)
{
const _img_private_t *p_env = p_user_data;
int i_rc;
struct cd_sub_channel_info bsdinfo;
struct ioc_read_subchannel read_subchannel;
memset(& bsdinfo, 0, sizeof(struct cd_sub_channel_info));
read_subchannel.address_format = CD_MSF_FORMAT;
read_subchannel.data_format = CD_CURRENT_POSITION;
read_subchannel.track = 0;
read_subchannel.data_len = sizeof(struct cd_sub_channel_info);
read_subchannel.data = & bsdinfo;
i_rc = ioctl(p_env->gen.fd, CDIOCREADSUBCHANNEL, &read_subchannel);
if (0 == i_rc) {
p_subchannel->audio_status = bsdinfo.header.audio_status;
p_subchannel->address = bsdinfo.what.position.addr_type;
p_subchannel->control = bsdinfo.what.position.control;
p_subchannel->track = bsdinfo.what.position.track_number;
p_subchannel->index = bsdinfo.what.position.index_number;
p_subchannel->abs_addr.m = cdio_to_bcd8 (bsdinfo.what.position.absaddr.msf.minute);
p_subchannel->abs_addr.s = cdio_to_bcd8 (bsdinfo.what.position.absaddr.msf.second);
p_subchannel->abs_addr.f = cdio_to_bcd8 (bsdinfo.what.position.absaddr.msf.frame);
p_subchannel->rel_addr.m = cdio_to_bcd8 (bsdinfo.what.position.reladdr.msf.minute);
p_subchannel->rel_addr.s = cdio_to_bcd8 (bsdinfo.what.position.reladdr.msf.second);
p_subchannel->rel_addr.f = cdio_to_bcd8 (bsdinfo.what.position.reladdr.msf.frame);
}
return i_rc;
}
#endif
/*!
Resume playing an audio CD.
@param p_cdio the CD object to be acted upon.
*/
static driver_return_code_t
audio_resume_freebsd (void *p_user_data)
{
const _img_private_t *p_env = p_user_data;
return ioctl(p_env->gen.fd, CDIOCRESUME, 0);
}
/*!
Set the volume of an audio CD.
@param p_cdio the CD object to be acted upon.
*/
static driver_return_code_t
audio_set_volume_freebsd (void *p_user_data,
cdio_audio_volume_t *p_volume)
{
const _img_private_t *p_env = p_user_data;
return ioctl(p_env->gen.fd, CDIOCSETVOL, p_volume);
}
/*!
Eject media. Return 1 if successful, 0 otherwise.
*/
static int
eject_media_freebsd (void *p_user_data)
{
_img_private_t *p_env = p_user_data;
return (p_env->access_mode == _AM_IOCTL)
? eject_media_freebsd_ioctl(p_env)
: eject_media_freebsd_cam(p_env);
}
/*!
Stop playing an audio CD.
@param p_user_data the CD object to be acted upon.
*/
static driver_return_code_t
audio_stop_freebsd (void *p_user_data)
{
const _img_private_t *p_env = p_user_data;
return ioctl(p_env->gen.fd, CDIOCSTOP);
}
/*!
Return the value associated with the key "arg".
*/
static const char *
get_arg_freebsd (void *user_data, const char key[])
{
_img_private_t *env = user_data;
if (!strcmp (key, "source")) {
return env->gen.source_name;
} else if (!strcmp (key, "access-mode")) {
switch (env->access_mode) {
case _AM_IOCTL:
return "ioctl";
case _AM_CAM:
return "CAM";
case _AM_NONE:
return "no access method";
}
}
return NULL;
}
/*!
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 *
get_mcn_freebsd (const void *p_user_data) {
const _img_private_t *p_env = p_user_data;
return (p_env->access_mode == _AM_IOCTL)
? get_mcn_freebsd_ioctl(p_env)
: mmc_get_mcn(p_env->gen.cdio);
}
static void
get_drive_cap_freebsd (const void *p_user_data,
cdio_drive_read_cap_t *p_read_cap,
cdio_drive_write_cap_t *p_write_cap,
cdio_drive_misc_cap_t *p_misc_cap)
{
const _img_private_t *p_env = p_user_data;
if (p_env->access_mode == _AM_CAM)
get_drive_cap_mmc (p_user_data, p_read_cap, p_write_cap, p_misc_cap);
}
/*!
Run a SCSI MMC command.
p_user_data internal CD structure.
i_timeout_ms time in milliseconds we will wait for the command
to complete. If this value is -1, use the default
time-out value.
i_cdb Size of p_cdb
p_cdb CDB bytes.
e_direction direction the transfer is to go.
i_buf Size of buffer
p_buf Buffer for data, both sending and receiving
*/
static driver_return_code_t
run_mmc_cmd_freebsd( void *p_user_data, unsigned int i_timeout_ms,
unsigned int i_cdb, const mmc_cdb_t *p_cdb,
cdio_mmc_direction_t e_direction,
unsigned int i_buf, /*in/out*/ void *p_buf )
{
const _img_private_t *p_env = p_user_data;
if (p_env->access_mode == _AM_CAM)
return run_mmc_cmd_freebsd_cam( p_user_data, i_timeout_ms, i_cdb, p_cdb,
e_direction, i_buf, p_buf );
else
return DRIVER_OP_UNSUPPORTED;
}
/*!
Get format of track.
FIXME: We're just guessing this from the GNU/Linux code.
*/
static track_format_t
get_track_format_freebsd(void *p_user_data, track_t i_track)
{
_img_private_t *p_env = p_user_data;
if (!p_env->gen.toc_init) read_toc_freebsd (p_user_data) ;
if (i_track > TOTAL_TRACKS || i_track == 0)
return TRACK_FORMAT_ERROR;
i_track -= FIRST_TRACK_NUM;
/* This is pretty much copied from the "badly broken" cdrom_count_tracks
in linux/cdrom.c.
*/
if (p_env->tocent[i_track].entry.control & CDIO_CDROM_DATA_TRACK) {
if (p_env->tocent[i_track].address_format == CDIO_CDROM_CDI_TRACK)
return TRACK_FORMAT_CDI;
else if (p_env->tocent[i_track].address_format == CDIO_CDROM_XA_TRACK)
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
get_track_green_freebsd(void *user_data, track_t i_track)
{
_img_private_t *p_env = user_data;
if (i_track == CDIO_CDROM_LEADOUT_TRACK) i_track = TOTAL_TRACKS+1;
if (i_track > TOTAL_TRACKS+1 || i_track == 0)
return false;
/* FIXME: Dunno if this is the right way, but it's what
I was using in cdinfo for a while.
*/
return ((p_env->tocent[i_track-FIRST_TRACK_NUM].entry.control & 2) != 0);
}
/*!
Return the starting LSN track number
i_track in obj. Track numbers start at 1.
The "leadout" track is specified either by
using i_track LEADOUT_TRACK or the total tracks+1.
CDIO_INVALID_LBA is returned if there is no track entry.
*/
static lba_t
get_track_lba_freebsd(void *user_data, track_t i_track)
{
_img_private_t *p_env = user_data;
if (!p_env->gen.toc_init) read_toc_freebsd (p_env) ;
if (i_track == CDIO_CDROM_LEADOUT_TRACK) i_track = TOTAL_TRACKS+1;
if (i_track > TOTAL_TRACKS+1 || i_track == 0 || !p_env->gen.toc_init) {
return CDIO_INVALID_LBA;
} else {
return cdio_lsn_to_lba(ntohl(p_env->tocent[i_track-FIRST_TRACK_NUM].entry.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.
*/
/* Scan SCSI and CAM devices */
for ( c='0'; exists && c <='9'; c++ ) {
sprintf(drive, "/dev/cd%c%s", c, DEVICE_POSTFIX);
exists = cdio_is_cdrom(drive, NULL);
if ( exists ) {
cdio_add_device_list(&drives, drive, &num_drives);
}
}
/* Scan are ATAPI devices */
for ( c='0'; exists && c <='9'; c++ ) {
sprintf(drive, "/dev/acd%c%s", c, DEVICE_POSTFIX);
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()
{
#ifndef HAVE_FREEBSD_CDROM
return NULL;
#else
char drive[40];
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))
return strdup(fs->fs_spec);
}
#endif
/* Scan the system for CD-ROM drives.
Not always 100% reliable, so use the USE_MNTENT code above first.
*/
/* Scan SCSI and CAM devices */
for ( c='0'; exists && c <='9'; c++ ) {
sprintf(drive, "/dev/cd%c%s", c, DEVICE_POSTFIX);
exists = cdio_is_cdrom(drive, NULL);
if ( exists ) {
return strdup(drive);
}
}
/* Scan are ATAPI devices */
for ( c='0'; exists && c <='9'; c++ ) {
sprintf(drive, "/dev/acd%c%s", c, DEVICE_POSTFIX);
exists = cdio_is_cdrom(drive, NULL);
if ( exists ) {
return strdup(drive);
}
}
return NULL;
#endif /*HAVE_FREEBSD_CDROM*/
}
/*!
Close tray on CD-ROM.
@param psz_device the CD-ROM drive to be closed.
*/
driver_return_code_t
close_tray_freebsd (const char *psz_device)
{
#ifdef HAVE_FREEBSD_CDROM
int fd = open (psz_device, O_RDONLY|O_NONBLOCK, 0);
int i_rc;
if((i_rc = ioctl(fd, CDIOCCLOSE)) != 0) {
cdio_warn ("ioctl CDIOCCLOSE failed: %s\n", strerror(errno));
return DRIVER_OP_ERROR;
}
close(fd);
return DRIVER_OP_SUCCESS;
#else
return DRIVER_OP_NO_DRIVER;
#endif /*HAVE_FREEBSD_CDROM*/
}
#ifdef HAVE_FREEBSD_CDROM
/*! Find out if media has changed since the last call. @param
p_user_data the environment of the CD object to be acted upon.
@return 1 if media has changed since last call, 0 if not. Error
return codes are the same as driver_return_code_t
*/
static int
get_media_changed_freebsd (const void *p_user_data)
{
const _img_private_t *p_env = p_user_data;
if ( p_env->access_mode == _AM_CAM ) {
return mmc_get_media_changed( p_env->gen.cdio );
}
else
return DRIVER_OP_UNSUPPORTED;
}
#endif /*HAVE_FREEBSD_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_freebsd (const char *psz_source_name)
{
return cdio_open_am_freebsd(psz_source_name, NULL);
}
/*!
Initialization routine. This is the only thing that doesn't
get called via a function pointer. In fact *we* are the
ones to set that up.
*/
CdIo *
cdio_open_am_freebsd (const char *psz_orig_source_name,
const char *psz_access_mode)
{
#ifdef HAVE_FREEBSD_CDROM
CdIo *ret;
_img_private_t *_data;
char *psz_source_name;
cdio_funcs_t _funcs = {
.audio_get_volume = audio_get_volume_freebsd,
.audio_pause = audio_pause_freebsd,
.audio_play_msf = audio_play_msf_freebsd,
.audio_play_track_index = audio_play_track_index_freebsd,
.audio_read_subchannel = audio_read_subchannel_freebsd,
.audio_resume = audio_resume_freebsd,
.audio_set_volume = audio_set_volume_freebsd,
.audio_stop = audio_stop_freebsd,
.eject_media = eject_media_freebsd,
.free = free_freebsd,
.get_arg = get_arg_freebsd,
.get_blocksize = get_blocksize_mmc,
.get_cdtext = get_cdtext_generic,
.get_default_device = cdio_get_default_device_freebsd,
.get_devices = cdio_get_devices_freebsd,
.get_disc_last_lsn = get_disc_last_lsn_freebsd,
.get_discmode = get_discmode_generic,
.get_drive_cap = get_drive_cap_freebsd,
.get_first_track_num = get_first_track_num_generic,
.get_media_changed = get_media_changed_freebsd,
.get_mcn = get_mcn_freebsd,
.get_num_tracks = get_num_tracks_generic,
.get_track_channels = get_track_channels_generic,
.get_track_copy_permit = get_track_copy_permit_generic,
.get_track_format = get_track_format_freebsd,
.get_track_green = get_track_green_freebsd,
.get_track_lba = get_track_lba_freebsd,
.get_track_preemphasis = get_track_preemphasis_generic,
.get_track_msf = NULL,
.lseek = cdio_generic_lseek,
.read = cdio_generic_read,
.read_audio_sectors = read_audio_sectors_freebsd,
.read_data_sectors = read_data_sectors_mmc,
.read_mode2_sector = read_mode2_sector_freebsd,
.read_mode2_sectors = read_mode2_sectors_freebsd,
.read_toc = read_toc_freebsd,
.run_mmc_cmd = run_mmc_cmd_freebsd,
.set_arg = set_arg_freebsd,
.set_blocksize = set_blocksize_mmc,
.set_speed = set_speed_freebsd,
};
_data = calloc(1, sizeof (_img_private_t));
_data->access_mode = str_to_access_mode_freebsd(psz_access_mode);
_data->gen.init = false;
_data->gen.fd = -1;
_data->gen.toc_init = false;
_data->gen.b_cdtext_init = false;
_data->gen.b_cdtext_error = false;
if (NULL == psz_orig_source_name) {
psz_source_name=cdio_get_default_device_freebsd();
if (NULL == psz_source_name) return NULL;
_data->device = psz_source_name;
set_arg_freebsd(_data, "source", psz_source_name);
} else {
if (cdio_is_device_generic(psz_orig_source_name)) {
set_arg_freebsd(_data, "source", psz_orig_source_name);
_data->device = strdup(psz_orig_source_name);
} else {
/* The below would be okay if all device drivers worked this way. */
#if 0
cdio_info ("source %s is a not a device", psz_orig_source_name);
#endif
free(_data);
return NULL;
}
}
ret = cdio_new ((void *)_data, &_funcs);
if (ret == NULL) return NULL;
if (cdio_generic_init(_data, O_RDONLY))
if ( _data->access_mode == _AM_IOCTL ) {
return ret;
} else {
if (init_freebsd_cam(_data))
return ret;
else {
cdio_generic_free (_data);
return NULL;
}
}
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 */
}

View File

@@ -0,0 +1,232 @@
/*
$Id: freebsd.h,v 1.10 2008/05/11 09:50:54 rocky Exp $
Copyright (C) 2003, 2004, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
/* This file contains FreeBSD-specific code and implements low-level
control of the CD drive. Culled initially I think from xine's or
mplayer's FreeBSD code with lots of modifications.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cdio/sector.h>
#include "cdio_assert.h"
#include "cdio_private.h"
/*!
For ioctl access /dev/acd0c is preferred over /dev/cd0c.
For cam access /dev/cd0c is preferred. DEFAULT_CDIO_DEVICE and
DEFAULT_FREEBSD_AM should be consistent.
*/
#ifndef DEFAULT_CDIO_DEVICE
#define DEFAULT_CDIO_DEVICE "/dev/cd0c"
#endif
#ifndef DEFAULT_FREEBSD_AM
#define DEFAULT_FREEBSD_AM _AM_CAM
#endif
#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
#ifndef CDIOCREADAUDIO
struct ioc_read_audio
{
u_char address_format;
union msf_lba address;
int nframes;
u_char* buffer;
};
#define CDIOCREADAUDIO _IOWR('c',31,struct ioc_read_audio)
#endif
#include <sys/cdrio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/param.h> /* for __FreeBSD_version */
#if (__FreeBSD_version < 500000) && (__FreeBSD_kernel_version < 500000)
#define DEVICE_POSTFIX "c"
#else
#define DEVICE_POSTFIX ""
#endif
#define HAVE_FREEBSD_CAM
#ifdef HAVE_FREEBSD_CAM
#include <camlib.h>
#include <cam/scsi/scsi_message.h>
#include <cam/scsi/scsi_pass.h>
#include <errno.h>
#define ERRCODE(s) ((((s)[2]&0x0F)<<16)|((s)[12]<<8)|((s)[13]))
#define EMEDIUMTYPE EINVAL
#define ENOMEDIUM ENODEV
#define CREAM_ON_ERRNO(s) do { \
switch ((s)[12]) \
{ case 0x04: errno=EAGAIN; break; \
case 0x20: errno=ENODEV; break; \
case 0x21: if ((s)[13]==0) errno=ENOSPC; \
else errno=EINVAL; \
break; \
case 0x30: errno=EMEDIUMTYPE; break; \
case 0x3A: errno=ENOMEDIUM; break; \
} \
} while(0)
#endif /*HAVE_FREEBSD_CAM*/
#include <cdio/util.h>
#define TOTAL_TRACKS ( p_env->tochdr.ending_track \
- p_env->tochdr.starting_track + 1)
#define FIRST_TRACK_NUM (p_env->tochdr.starting_track)
typedef enum {
_AM_NONE,
_AM_IOCTL,
_AM_CAM
} access_mode_t;
typedef struct {
/* Things common to all drivers like this.
This must be first. */
generic_img_private_t gen;
#ifdef HAVE_FREEBSD_CAM
char *device;
struct cam_device *cam;
union ccb ccb;
#endif
access_mode_t access_mode;
bool b_ioctl_init;
bool b_cam_init;
/* Track information */
struct ioc_toc_header tochdr;
/* Entry info for each track. Add 1 for leadout. */
struct ioc_read_toc_single_entry tocent[CDIO_CD_MAX_TRACKS+1];
} _img_private_t;
bool cdio_is_cdrom_freebsd_ioctl(char *drive, char *mnttype);
track_format_t get_track_format_freebsd_ioctl(const _img_private_t *env,
track_t i_track);
bool get_track_green_freebsd_ioctl(const _img_private_t *env,
track_t i_track);
driver_return_code_t eject_media_freebsd_ioctl (_img_private_t *p_env);
driver_return_code_t eject_media_freebsd_cam (_img_private_t *p_env);
void get_drive_cap_freebsd_cam (const _img_private_t *p_env,
cdio_drive_read_cap_t *p_read_cap,
cdio_drive_write_cap_t *p_write_cap,
cdio_drive_misc_cap_t *p_misc_cap);
static int get_media_changed_freebsd (const void *p_user_data);
char *get_mcn_freebsd_ioctl (const _img_private_t *p_env);
void free_freebsd_cam (void *obj);
/*!
Using the ioctl method, r nblocks of audio sectors from cd device
into data starting from lsn. Returns 0 if no error.
*/
int read_audio_sectors_freebsd_ioctl (_img_private_t *env, void *data,
lsn_t lsn, unsigned int nblocks);
/*!
Using the CAM method, reads nblocks of mode2 sectors from
cd device using into data starting from lsn. Returns 0 if no
error.
*/
int read_mode2_sector_freebsd_cam (_img_private_t *env, void *data,
lsn_t lsn, bool b_form2);
/*!
Using the ioctl method, reads nblocks of mode2 sectors from
cd device using into data starting from lsn. Returns 0 if no
error.
*/
int read_mode2_sector_freebsd_ioctl (_img_private_t *env, void *data,
lsn_t lsn, bool b_form2);
/*!
Using the CAM method, reads nblocks of mode2 form2 sectors from
cd device using into data starting from lsn. Returns 0 if no
error.
Note: if you want form1 sectors, the caller has to pick out the
appropriate piece.
*/
int read_mode2_sectors_freebsd_cam (_img_private_t *env, void *buf,
lsn_t lsn, unsigned int nblocks);
bool read_toc_freebsd_ioctl (_img_private_t *env);
/*!
Run a SCSI MMC command.
p_user_data internal CD structure.
i_timeout time in milliseconds we will wait for the command
to complete. If this value is -1, use the default
time-out value.
i_cdb Size of p_cdb
p_cdb CDB bytes.
e_direction direction the transfer is to go.
i_buf Size of buffer
p_buf Buffer for data, both sending and receiving
Return 0 if no error.
*/
int run_mmc_cmd_freebsd_cam( const void *p_user_data,
unsigned int i_timeout_ms,
unsigned int i_cdb,
const mmc_cdb_t *p_cdb,
cdio_mmc_direction_t e_direction,
unsigned int i_buf,
/*in/out*/ void *p_buf );
/*!
Return the size of the CD in logical block address (LBA) units.
*/
lsn_t get_disc_last_lsn_freebsd_ioctl (_img_private_t *_obj);
bool init_freebsd_cam (_img_private_t *env);
void free_freebsd_cam (void *user_data);
#endif /*HAVE_FREEBSD_CDROM*/

View File

@@ -0,0 +1,257 @@
/*
$Id: freebsd_cam.c,v 1.12 2008/04/21 18:30:20 karl Exp $
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
/* This file contains FreeBSD-specific code and implements low-level
control of the CD drive via SCSI emulation.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static const char _rcsid[] = "$Id: freebsd_cam.c,v 1.12 2008/04/21 18:30:20 karl Exp $";
#ifdef HAVE_FREEBSD_CDROM
#include "freebsd.h"
#include <cdio/mmc.h>
/* Default value in seconds we will wait for a command to
complete. */
#define DEFAULT_TIMEOUT_MSECS 10000
/*!
Run a SCSI MMC command.
p_user_data internal CD structure.
i_timeout_ms time in milliseconds we will wait for the command
to complete. If this value is -1, use the default
time-out value.
i_cdb Size of p_cdb
p_cdb CDB bytes.
e_direction direction the transfer is to go.
i_buf Size of buffer
p_buf Buffer for data, both sending and receiving
Return 0 if no error.
*/
int
run_mmc_cmd_freebsd_cam( const void *p_user_data, unsigned int i_timeout_ms,
unsigned int i_cdb, const mmc_cdb_t *p_cdb,
cdio_mmc_direction_t e_direction,
unsigned int i_buf, /*in/out*/ void *p_buf )
{
const _img_private_t *p_env = p_user_data;
int i_status;
int direction = CAM_DEV_QFRZDIS;
union ccb ccb;
if (!p_env || !p_env->cam) return -2;
memset(&ccb, 0, sizeof(ccb));
ccb.ccb_h.path_id = p_env->cam->path_id;
ccb.ccb_h.target_id = p_env->cam->target_id;
ccb.ccb_h.target_lun = p_env->cam->target_lun;
ccb.ccb_h.timeout = i_timeout_ms;
if (!i_buf)
direction |= CAM_DIR_NONE;
else
direction |= (e_direction == SCSI_MMC_DATA_READ)?CAM_DIR_IN : CAM_DIR_OUT;
memcpy(ccb.csio.cdb_io.cdb_bytes, p_cdb->field, i_cdb);
ccb.csio.cdb_len =
mmc_get_cmd_len(ccb.csio.cdb_io.cdb_bytes[0]);
cam_fill_csio (&(ccb.csio), 1, NULL,
direction | CAM_DEV_QFRZDIS, MSG_SIMPLE_Q_TAG, p_buf, i_buf,
sizeof(ccb.csio.sense_data), ccb.csio.cdb_len, 30*1000);
if (cam_send_ccb(p_env->cam, &ccb) < 0)
{
cdio_warn ("transport failed: %s", strerror(errno));
return -1;
}
if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
{
return 0;
}
errno = EIO;
i_status = ERRCODE(((unsigned char *)&ccb.csio.sense_data));
if (i_status == 0)
i_status = -1;
else
CREAM_ON_ERRNO(((unsigned char *)&ccb.csio.sense_data));
cdio_warn ("transport failed: %d", i_status);
return i_status;
}
bool
init_freebsd_cam (_img_private_t *p_env)
{
char pass[100];
p_env->cam=NULL;
memset (&p_env->ccb, 0, sizeof(p_env->ccb));
p_env->ccb.ccb_h.func_code = XPT_GDEVLIST;
if (-1 == p_env->gen.fd)
p_env->gen.fd = open (p_env->device, O_RDONLY, 0);
if (p_env->gen.fd < 0)
{
cdio_warn ("open (%s): %s", p_env->device, strerror (errno));
return false;
}
if (ioctl (p_env->gen.fd, CAMGETPASSTHRU, &p_env->ccb) < 0)
{
cdio_warn ("open: %s", strerror (errno));
return false;
}
sprintf (pass,"/dev/%.15s%u",
p_env->ccb.cgdl.periph_name,
p_env->ccb.cgdl.unit_number);
p_env->cam = cam_open_pass (pass,O_RDWR,NULL);
if (!p_env->cam) return false;
p_env->gen.init = true;
p_env->b_cam_init = true;
return true;
}
void
free_freebsd_cam (void *user_data)
{
_img_private_t *p_env = user_data;
if (NULL == p_env) return;
if (p_env->gen.fd > 0)
close (p_env->gen.fd);
p_env->gen.fd = -1;
if(p_env->cam)
cam_close_device(p_env->cam);
free (p_env);
}
driver_return_code_t
read_mode2_sector_freebsd_cam (_img_private_t *p_env, void *data, lsn_t lsn,
bool b_form2)
{
if ( b_form2 )
return read_mode2_sectors_freebsd_cam(p_env, data, lsn, 1);
else {
/* Need to pick out the data portion from a mode2 form2 frame */
char buf[M2RAW_SECTOR_SIZE] = { 0, };
int retval = read_mode2_sectors_freebsd_cam(p_env, buf, lsn, 1);
if ( retval ) return retval;
memcpy (((char *)data), buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE);
return DRIVER_OP_SUCCESS;
}
}
/*!
Reads nblocks of mode2 sectors from cd device into data starting
from lsn.
Returns 0 if no error.
*/
int
read_mode2_sectors_freebsd_cam (_img_private_t *p_env, void *p_buf,
lsn_t lsn, unsigned int nblocks)
{
mmc_cdb_t cdb = {{0, }};
bool b_read_10 = false;
CDIO_MMC_SET_READ_LBA(cdb.field, lsn);
if (b_read_10) {
int retval;
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_10);
CDIO_MMC_SET_READ_LENGTH16(cdb.field, nblocks);
if ((retval = mmc_set_blocksize (p_env->gen.cdio, M2RAW_SECTOR_SIZE)))
return retval;
if ((retval = run_mmc_cmd_freebsd_cam (p_env, 0,
mmc_get_cmd_len(cdb.field[0]),
&cdb,
SCSI_MMC_DATA_READ,
M2RAW_SECTOR_SIZE * nblocks,
p_buf)))
{
mmc_set_blocksize (p_env->gen.cdio, CDIO_CD_FRAMESIZE);
return retval;
}
return mmc_set_blocksize (p_env->gen.cdio, CDIO_CD_FRAMESIZE);
} else {
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_CD);
CDIO_MMC_SET_READ_LENGTH24(cdb.field, nblocks);
cdb.field[1] = 0; /* sector size mode2 */
cdb.field[9] = 0x58; /* 2336 mode2 */
return run_mmc_cmd_freebsd_cam (p_env, 0,
mmc_get_cmd_len(cdb.field[0]),
&cdb,
SCSI_MMC_DATA_READ,
M2RAW_SECTOR_SIZE * nblocks, p_buf);
}
}
/*!
Eject media in CD-ROM drive. Return DRIVER_OP_SUCCESS if successful,
DRIVER_OP_ERROR on error.
*/
driver_return_code_t
eject_media_freebsd_cam (_img_private_t *p_env)
{
int i_status;
mmc_cdb_t cdb = {{0, }};
uint8_t buf[1];
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_ALLOW_MEDIUM_REMOVAL);
i_status = run_mmc_cmd_freebsd_cam (p_env, DEFAULT_TIMEOUT_MSECS,
mmc_get_cmd_len(cdb.field[0]),
&cdb, SCSI_MMC_DATA_WRITE, 0, &buf);
if (i_status) return i_status;
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_START_STOP);
cdb.field[4] = 1;
i_status = run_mmc_cmd_freebsd_cam (p_env, DEFAULT_TIMEOUT_MSECS,
mmc_get_cmd_len(cdb.field[0]), &cdb,
SCSI_MMC_DATA_WRITE, 0, &buf);
if (i_status) return i_status;
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_START_STOP);
cdb.field[4] = 2; /* eject */
return run_mmc_cmd_freebsd_cam (p_env, DEFAULT_TIMEOUT_MSECS,
mmc_get_cmd_len(cdb.field[0]),
&cdb,
SCSI_MMC_DATA_WRITE, 0, &buf);
}
#endif /* HAVE_FREEBSD_CDROM */

View File

@@ -0,0 +1,262 @@
/*
$Id: freebsd_ioctl.c,v 1.7 2008/04/21 18:30:20 karl Exp $
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
/* This file contains FreeBSD-specific code and implements low-level
control of the CD drive. Culled initially I think from xine's or
mplayer's FreeBSD code with lots of modifications.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static const char _rcsid[] = "$Id: freebsd_ioctl.c,v 1.7 2008/04/21 18:30:20 karl Exp $";
#ifdef HAVE_FREEBSD_CDROM
#include "freebsd.h"
/* 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 .
*/
bool
cdio_is_cdrom_freebsd_ioctl(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);
}
/*!
Reads a single mode2 sector from cd device into data starting from lsn.
Returns 0 if no error.
*/
int
read_audio_sectors_freebsd_ioctl (_img_private_t *_obj, void *data, lsn_t lsn,
unsigned int nblocks)
{
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 = CDIO_CDROM_LBA;
/* 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.
*/
int
read_mode2_sector_freebsd_ioctl (_img_private_t *p_env, void *data, lsn_t lsn,
bool b_form2)
{
char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
int retval;
if ( !b_form2 )
return cdio_generic_read_form1_sector (p_env, buf, lsn);
if ( (retval = read_audio_sectors_freebsd_ioctl (p_env, buf, lsn, 1)) )
return retval;
memcpy (data, buf + CDIO_CD_XA_SYNC_HEADER, M2RAW_SECTOR_SIZE);
return 0;
}
/*!
Return the size of the CD in logical block address (LBA) units.
*/
lsn_t
get_disc_last_lsn_freebsd_ioctl (_img_private_t *p_obj)
{
struct ioc_read_toc_single_entry tocent;
uint32_t size;
tocent.track = CDIO_CDROM_LEADOUT_TRACK;
tocent.address_format = CDIO_CDROM_LBA;
if (ioctl (p_obj->gen.fd, CDIOREADTOCENTRY, &tocent) == -1)
{
perror ("ioctl(CDROMREADTOCENTRY)");
exit (EXIT_FAILURE);
}
size = tocent.entry.addr.lba;
return size;
}
/*!
Eject media in CD-ROM drive. Return DRIVER_OP_SUCCESS if successful,
DRIVER_OP_ERROR on error.
*/
driver_return_code_t
eject_media_freebsd_ioctl (_img_private_t *p_env)
{
_img_private_t *p_obj = p_env;
int ret=DRIVER_OP_ERROR;
if (ioctl(p_obj->gen.fd, CDIOCALLOW) == -1) {
cdio_warn("ioctl(fd, CDIOCALLOW) failed: %s\n", strerror(errno));
} else if (ioctl(p_obj->gen.fd, CDIOCEJECT) == -1) {
cdio_warn("ioctl(CDIOCEJECT) failed: %s\n", strerror(errno));
} else {
ret=DRIVER_OP_SUCCESS;;
}
return ret;
}
/*!
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.
*/
char *
get_mcn_freebsd_ioctl (const _img_private_t *p_env) {
struct ioc_read_subchannel subchannel;
struct cd_sub_channel_info subchannel_info;
subchannel.address_format = CDIO_CDROM_MSF;
subchannel.data_format = CDIO_SUBCHANNEL_MEDIA_CATALOG;
subchannel.track = 0;
subchannel.data_len = sizeof(subchannel_info);
subchannel.data = &subchannel_info;
if(ioctl(p_env->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;
}
/*!
Get format of track.
FIXME: We're just guessing this from the GNU/Linux code.
*/
track_format_t
get_track_format_freebsd_ioctl(const _img_private_t *p_env, track_t i_track)
{
struct ioc_read_subchannel subchannel;
struct cd_sub_channel_info subchannel_info;
subchannel.address_format = CDIO_CDROM_LBA;
subchannel.data_format = CDIO_SUBCHANNEL_CURRENT_POSITION;
subchannel.track = i_track;
subchannel.data_len = 1;
subchannel.data = &subchannel_info;
if(ioctl(p_env->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?
*/
bool
get_track_green_freebsd_ioctl(const _img_private_t *p_env, track_t i_track)
{
struct ioc_read_subchannel subchannel;
struct cd_sub_channel_info subchannel_info;
subchannel.address_format = CDIO_CDROM_LBA;
subchannel.data_format = CDIO_SUBCHANNEL_CURRENT_POSITION;
subchannel.track = i_track;
subchannel.data_len = 1;
subchannel.data = &subchannel_info;
if(ioctl(p_env->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;
}
#endif /* HAVE_FREEBSD_CDROM */

View File

@@ -0,0 +1,22 @@
# $Id: Makefile,v 1.2 2008/04/21 18:30:21 karl Exp $
#
# Copyright (C) 2004, 2008 Rocky Bernstein
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
#
# The make is done above. This boilerplate Makefile just transfers the call
all install check clean:
cd .. && $(MAKE) $@

View File

@@ -0,0 +1,808 @@
/*
$Id: aspi32.c,v 1.11 2008/04/21 18:30:21 karl Exp $
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
/* This file contains Win32-specific code and implements low-level
control of the CD drive via the ASPI API.
Inspired by vlc's cdrom.h code
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static const char _rcsid[] = "$Id: aspi32.c,v 1.11 2008/04/21 18:30:21 karl Exp $";
#include <cdio/cdio.h>
#include <cdio/sector.h>
#include <cdio/util.h>
#include <cdio/mmc.h>
#include "cdio_assert.h"
#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 "win32.h"
#include <sys/stat.h>
#include <sys/types.h>
#include "aspi32.h"
#include "cdtext_private.h"
/* Amount of time we are willing to wait for an operation to complete.
10 seconds?
*/
#define OP_TIMEOUT_MS 10000
static const
char *aspierror(int nErrorCode)
{
switch (nErrorCode)
{
case SS_PENDING:
return "SRB being processed";
break;
case SS_COMP:
return "SRB completed without error";
break;
case SS_ABORTED:
return "SRB aborted";
break;
case SS_ABORT_FAIL:
return "Unable to abort SRB";
break;
case SS_ERR:
return "SRB completed with error";
break;
case SS_INVALID_CMD:
return "Invalid ASPI command";
break;
case SS_INVALID_HA:
return "Invalid host adapter number";
break;
case SS_NO_DEVICE:
return "SCSI device not installed";
break;
case SS_INVALID_SRB:
return "Invalid parameter set in SRB";
break;
case SS_OLD_MANAGER:
return "ASPI manager doesn't support";
break;
case SS_ILLEGAL_MODE:
return "Unsupported MS Windows mode";
break;
case SS_NO_ASPI:
return "No ASPI managers";
break;
case SS_FAILED_INIT:
return "ASPI for windows failed init";
break;
case SS_ASPI_IS_BUSY:
return "No resources available to execute command.";
break;
case SS_BUFFER_TOO_BIG:
return "Buffer size is too big to handle.";
break;
case SS_MISMATCHED_COMPONENTS:
return "The DLLs/EXEs of ASPI don't version check";
break;
case SS_NO_ADAPTERS:
return "No host adapters found";
break;
case SS_INSUFFICIENT_RESOURCES:
return "Couldn't allocate resources needed to init";
break;
case SS_ASPI_IS_SHUTDOWN:
return "Call came to ASPI after PROCESS_DETACH";
break;
case SS_BAD_INSTALL:
return "The DLL or other components are installed wrong.";
break;
default:
return "Unknown ASPI error.";
}
}
/* General ioctl() CD-ROM command function */
static bool
mciSendCommand_aspi(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_warn("mciSendCommand() error: %s", error);
}
return(mci_error == 0);
}
/*
See if the ASPI DLL is loadable. If so pointers are returned
and we return true. Return false if there was a problem.
*/
static bool
have_aspi( HMODULE *hASPI,
long (**lpGetSupport)( void ),
long (**lpSendCommand)( void* ) )
{
/* check if aspi is available */
*hASPI = LoadLibrary( "wnaspi32.dll" );
if( *hASPI == NULL ) {
cdio_debug("Unable to load ASPI DLL");
return false;
}
*lpGetSupport = (void *) GetProcAddress( *hASPI,
"GetASPI32SupportInfo" );
*lpSendCommand = (void *) GetProcAddress( *hASPI,
"SendASPI32Command" );
/* make sure that we've got both function addresses */
if( *lpGetSupport == NULL || *lpSendCommand == NULL ) {
cdio_debug("Unable to get ASPI function pointers");
FreeLibrary( *hASPI );
return false;
}
return true;
}
/*!
Get disc type associated with cd object.
*/
discmode_t
get_discmode_aspi (_img_private_t *p_env)
{
track_t i_track;
discmode_t discmode=CDIO_DISC_MODE_NO_INFO;
/* See if this is a DVD. */
cdio_dvd_struct_t dvd; /* DVD READ STRUCT for layer 0. */
dvd.physical.type = CDIO_DVD_STRUCT_PHYSICAL;
dvd.physical.layer_num = 0;
if (0 == mmc_get_dvd_struct_physical_private (p_env, &run_mmc_cmd_aspi,
&dvd)) {
switch(dvd.physical.layer[0].book_type) {
case CDIO_DVD_BOOK_DVD_ROM: return CDIO_DISC_MODE_DVD_ROM;
case CDIO_DVD_BOOK_DVD_RAM: return CDIO_DISC_MODE_DVD_RAM;
case CDIO_DVD_BOOK_DVD_R: return CDIO_DISC_MODE_DVD_R;
case CDIO_DVD_BOOK_DVD_RW: return CDIO_DISC_MODE_DVD_RW;
case CDIO_DVD_BOOK_DVD_PR: return CDIO_DISC_MODE_DVD_PR;
case CDIO_DVD_BOOK_DVD_PRW: return CDIO_DISC_MODE_DVD_PRW;
default: return CDIO_DISC_MODE_DVD_OTHER;
}
}
if (!p_env->gen.toc_init)
read_toc_aspi (p_env);
if (!p_env->gen.toc_init)
return CDIO_DISC_MODE_NO_INFO;
for (i_track = p_env->gen.i_first_track;
i_track < p_env->gen.i_first_track + p_env->gen.i_tracks ;
i_track ++) {
track_format_t track_fmt=get_track_format_aspi(p_env, i_track);
switch(track_fmt) {
case TRACK_FORMAT_AUDIO:
switch(discmode) {
case CDIO_DISC_MODE_NO_INFO:
discmode = CDIO_DISC_MODE_CD_DA;
break;
case CDIO_DISC_MODE_CD_DA:
case CDIO_DISC_MODE_CD_MIXED:
case CDIO_DISC_MODE_ERROR:
/* No change*/
break;
default:
discmode = CDIO_DISC_MODE_CD_MIXED;
}
break;
case TRACK_FORMAT_XA:
switch(discmode) {
case CDIO_DISC_MODE_NO_INFO:
discmode = CDIO_DISC_MODE_CD_XA;
break;
case CDIO_DISC_MODE_CD_XA:
case CDIO_DISC_MODE_CD_MIXED:
case CDIO_DISC_MODE_ERROR:
/* No change*/
break;
default:
discmode = CDIO_DISC_MODE_CD_MIXED;
}
break;
case TRACK_FORMAT_DATA:
switch(discmode) {
case CDIO_DISC_MODE_NO_INFO:
discmode = CDIO_DISC_MODE_CD_DATA;
break;
case CDIO_DISC_MODE_CD_DATA:
case CDIO_DISC_MODE_CD_MIXED:
case CDIO_DISC_MODE_ERROR:
/* No change*/
break;
default:
discmode = CDIO_DISC_MODE_CD_MIXED;
}
break;
case TRACK_FORMAT_ERROR:
default:
discmode = CDIO_DISC_MODE_ERROR;
}
}
return discmode;
}
const char *
is_cdrom_aspi(const char drive_letter)
{
static char psz_win32_drive[7];
HMODULE hASPI = NULL;
long (*lpGetSupport)( void ) = NULL;
long (*lpSendCommand)( void* ) = NULL;
DWORD dwSupportInfo;
int i_adapter, i_hostadapters;
char c_drive;
int i_rc;
if ( !have_aspi(&hASPI, &lpGetSupport, &lpSendCommand) )
return NULL;
/* ASPI support seems to be there. */
dwSupportInfo = lpGetSupport();
i_rc = HIBYTE( LOWORD ( dwSupportInfo ) );
if( SS_COMP != i_rc ) {
cdio_debug("ASPI: %s", aspierror(i_rc));
FreeLibrary( hASPI );
return NULL;
}
i_hostadapters = LOBYTE( LOWORD( dwSupportInfo ) );
if( i_hostadapters == 0 ) {
FreeLibrary( hASPI );
return NULL;
}
c_drive = toupper(drive_letter) - 'A';
for( i_adapter = 0; i_adapter < i_hostadapters; i_adapter++ ) {
struct SRB_GetDiskInfo srbDiskInfo;
int i_target;
SRB_HAInquiry srbInquiry;
srbInquiry.SRB_Cmd = SC_HA_INQUIRY;
srbInquiry.SRB_HaId = i_adapter;
lpSendCommand( (void*) &srbInquiry );
if( srbInquiry.SRB_Status != SS_COMP ) continue;
if( !srbInquiry.HA_Unique[3]) srbInquiry.HA_Unique[3]=8;
for(i_target=0; i_target < srbInquiry.HA_Unique[3]; i_target++)
{
int i_lun;
for( i_lun=0; i_lun<8; i_lun++)
{
srbDiskInfo.SRB_Cmd = SC_GET_DISK_INFO;
srbDiskInfo.SRB_Flags = 0;
srbDiskInfo.SRB_Hdr_Rsvd = 0;
srbDiskInfo.SRB_HaId = i_adapter;
srbDiskInfo.SRB_Target = i_target;
srbDiskInfo.SRB_Lun = i_lun;
lpSendCommand( (void*) &srbDiskInfo );
if( (srbDiskInfo.SRB_Status == SS_COMP) &&
(srbDiskInfo.SRB_Int13HDriveInfo == c_drive) ) {
/* Make sure this is a CD-ROM device. */
struct SRB_GDEVBlock srbGDEVBlock;
memset( &srbGDEVBlock, 0, sizeof(struct SRB_GDEVBlock) );
srbGDEVBlock.SRB_Cmd = SC_GET_DEV_TYPE;
srbDiskInfo.SRB_HaId = i_adapter;
srbGDEVBlock.SRB_Target = i_target;
srbGDEVBlock.SRB_Lun = i_lun;
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.
*/
bool
init_aspi (_img_private_t *env)
{
HMODULE hASPI = NULL;
long (*lpGetSupport)( void ) = NULL;
long (*lpSendCommand)( void* ) = NULL;
DWORD dwSupportInfo;
int i_adapter, i_hostadapters;
char c_drive;
int i_rc;
if (2 == strlen(env->gen.source_name) && isalpha(env->gen.source_name[0]) )
{
c_drive = env->gen.source_name[0];
} else if ( 6 == strlen(env->gen.source_name)
&& isalpha(env->gen.source_name[4] )) {
c_drive = env->gen.source_name[4];
} else {
c_drive = 'C';
}
if ( !have_aspi(&hASPI, &lpGetSupport, &lpSendCommand) )
return false;
/* ASPI support seems to be there. */
dwSupportInfo = lpGetSupport();
i_rc = HIBYTE( LOWORD ( dwSupportInfo ) );
if( SS_COMP != i_rc ) {
cdio_info("ASPI: %s", aspierror(i_rc));
FreeLibrary( hASPI );
return false;
}
i_hostadapters = LOBYTE( LOWORD( dwSupportInfo ) );
if( i_hostadapters == 0 ) {
FreeLibrary( hASPI );
return false;
}
c_drive = toupper(c_drive) - 'A';
for( i_adapter = 0; i_adapter < i_hostadapters; i_adapter++ ) {
struct SRB_GetDiskInfo srbDiskInfo;
int i_target;
SRB_HAInquiry srbInquiry;
srbInquiry.SRB_Cmd = SC_HA_INQUIRY;
srbInquiry.SRB_HaId = i_adapter;
lpSendCommand( (void*) &srbInquiry );
if( srbInquiry.SRB_Status != SS_COMP ) continue;
if( !srbInquiry.HA_Unique[3]) srbInquiry.HA_Unique[3]=8;
for(i_target=0; i_target < srbInquiry.HA_Unique[3]; i_target++)
{
int i_lun;
for (i_lun = 0; i_lun < 8; i_lun++ ) {
srbDiskInfo.SRB_Cmd = SC_GET_DISK_INFO;
srbDiskInfo.SRB_Flags = 0;
srbDiskInfo.SRB_Hdr_Rsvd = 0;
srbDiskInfo.SRB_HaId = i_adapter;
srbDiskInfo.SRB_Target = i_target;
srbDiskInfo.SRB_Lun = i_lun;
lpSendCommand( (void*) &srbDiskInfo );
if( (srbDiskInfo.SRB_Status == SS_COMP) ) {
if (srbDiskInfo.SRB_Int13HDriveInfo != c_drive)
{
continue;
} else {
/* Make sure this is a CD-ROM device. */
struct SRB_GDEVBlock srbGDEVBlock;
memset( &srbGDEVBlock, 0, sizeof(struct SRB_GDEVBlock) );
srbGDEVBlock.SRB_Cmd = SC_GET_DEV_TYPE;
srbGDEVBlock.SRB_HaId = i_adapter;
srbGDEVBlock.SRB_Target = i_target;
lpSendCommand( (void*) &srbGDEVBlock );
if( ( srbGDEVBlock.SRB_Status == SS_COMP ) &&
( srbGDEVBlock.SRB_DeviceType == DTYPE_CDROM ) ) {
env->i_sid = MAKEWORD( i_adapter, i_target );
env->hASPI = (long)hASPI;
env->lpSendCommand = lpSendCommand;
env->b_aspi_init = true;
env->i_lun = i_lun;
cdio_debug("Using ASPI layer");
return true;
} else {
FreeLibrary( hASPI );
cdio_debug( "%c: is not a CD-ROM drive",
env->gen.source_name[0] );
return false;
}
}
}
}
}
}
FreeLibrary( hASPI );
cdio_debug( "Unable to get HaId and target (ASPI)" );
return false;
}
/*!
Run a SCSI MMC command.
env private CD structure
i_timeout_ms time in milliseconds we will wait for the command
to complete. If this value is -1, use the default
time-out value.
p_buf Buffer for data, both sending and receiving
i_buf Size of buffer
e_direction direction the transfer is to go.
cdb CDB bytes. All values that are needed should be set on
input. We'll figure out what the right CDB length should be.
We return 0 if command completed successfully.
*/
int
run_mmc_cmd_aspi( void *p_user_data, unsigned int i_timeout_ms,
unsigned int i_cdb, const mmc_cdb_t * p_cdb,
cdio_mmc_direction_t e_direction,
unsigned int i_buf, /*in/out*/ void *p_buf )
{
const _img_private_t *p_env = p_user_data;
HANDLE hEvent;
struct SRB_ExecSCSICmd ssc;
/* Create the transfer completion event */
hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
if( hEvent == NULL ) {
cdio_info("CreateEvent failed");
return 1;
}
memset( &ssc, 0, sizeof( ssc ) );
ssc.SRB_Cmd = SC_EXEC_SCSI_CMD;
ssc.SRB_Flags = SCSI_MMC_DATA_READ == e_direction ?
SRB_DIR_IN | SRB_EVENT_NOTIFY : SRB_DIR_OUT | SRB_EVENT_NOTIFY;
ssc.SRB_HaId = LOBYTE( p_env->i_sid );
ssc.SRB_Target = HIBYTE( p_env->i_sid );
ssc.SRB_Lun = p_env->i_lun;
ssc.SRB_SenseLen = SENSE_LEN;
ssc.SRB_PostProc = (LPVOID) hEvent;
ssc.SRB_CDBLen = i_cdb;
/* Result buffer */
ssc.SRB_BufPointer = p_buf;
ssc.SRB_BufLen = i_buf;
memcpy( ssc.CDBByte, p_cdb, i_cdb );
ResetEvent( hEvent );
p_env->lpSendCommand( (void*) &ssc );
/* If the command has still not been processed, wait until it's
* finished */
if( ssc.SRB_Status == SS_PENDING ) {
WaitForSingleObject( hEvent, msecs2secs(i_timeout_ms) );
}
CloseHandle( hEvent );
/* check that the transfer went as planned */
if( ssc.SRB_Status != SS_COMP ) {
cdio_info("ASPI: %s", aspierror(ssc.SRB_Status));
return 2;
}
return 0;
}
/*!
Reads nblocks sectors from cd device into data starting from lsn.
Returns 0 if no error.
*/
static int
read_sectors_aspi (_img_private_t *p_env, void *data, lsn_t lsn,
int sector_type, unsigned int nblocks)
{
mmc_cdb_t cdb = {{0, }};
unsigned int i_buf;
int sync = 0;
int header_code = 2;
int i_user_data = 1;
int edc_ecc = 0;
int error_field = 0;
#if 0
sector_type = 0; /*all types */
#endif
/* Set up passthrough command */
CDIO_MMC_SET_COMMAND (cdb.field, CDIO_MMC_GPCMD_READ_CD);
CDIO_MMC_SET_READ_TYPE (cdb.field, sector_type);
CDIO_MMC_SET_READ_LBA (cdb.field, lsn);
CDIO_MMC_SET_READ_LENGTH24(cdb.field, nblocks);
#if 1
cdb.field[ 9 ] = (sync << 7) |
(header_code << 5) |
(i_user_data << 4) |
(edc_ecc << 3) |
(error_field << 1);
/* ssc.CDBByte[ 9 ] = READ_CD_USERDATA_MODE2; */
#else
CDIO_MMC_SET_MAIN_CHANNEL_SELECTION_BITS(cmd,
CDIO_MMC_MCSB_ALL_HEADERS);
#endif
switch (sector_type) {
case CDIO_MMC_READ_TYPE_ANY:
case CDIO_MMC_READ_TYPE_CDDA:
i_buf = CDIO_CD_FRAMESIZE_RAW;
break;
case CDIO_MMC_READ_TYPE_M2F1:
i_buf = CDIO_CD_FRAMESIZE;
break;
case CDIO_MMC_READ_TYPE_M2F2:
i_buf = 2324;
break;
case CDIO_MMC_READ_TYPE_MODE1:
i_buf = CDIO_CD_FRAMESIZE;
break;
default:
i_buf = CDIO_CD_FRAMESIZE_RAW;
}
return run_mmc_cmd_aspi(p_env, OP_TIMEOUT_MS,
mmc_get_cmd_len(cdb.field[0]),
&cdb, SCSI_MMC_DATA_READ, i_buf*nblocks, data);
}
/*!
Reads an audio device into data starting from lsn.
Returns 0 if no error.
*/
int
read_audio_sectors_aspi (_img_private_t *p_env, void *data, lsn_t lsn,
unsigned int i_blocks)
{
if (read_sectors_aspi(p_env, data, lsn, CDIO_MMC_READ_TYPE_CDDA, i_blocks)) {
return read_sectors_aspi(p_env, data, lsn,
CDIO_MMC_READ_TYPE_ANY, i_blocks);
}
return 0;
}
/*!
Reads a single mode2 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
int
read_mode2_sector_aspi (_img_private_t *p_env, void *data, lsn_t lsn,
bool b_form2)
{
return read_sectors_aspi(p_env, data, lsn, b_form2
? CDIO_MMC_READ_TYPE_M2F2
: CDIO_MMC_READ_TYPE_M2F1,
1);
}
/*!
Reads a single mode2 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
int
read_mode1_sector_aspi (_img_private_t *p_env, void *data, lsn_t lsn,
bool b_form2)
{
return read_sectors_aspi(p_env, data, lsn, CDIO_MMC_READ_TYPE_MODE1, 1);
}
/*!
Read and cache the CD's Track Table of Contents and track info.
Return true if successful or false if an error.
*/
bool
read_toc_aspi (_img_private_t *p_env)
{
mmc_cdb_t cdb = {{0, }};
unsigned char tocheader[ 4 ];
int i_status;
/* Operation code */
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_TOC);
/* Format */
cdb.field[ 2 ] = CDIO_MMC_READTOC_FMT_TOC;
/* Starting track */
CDIO_MMC_SET_START_TRACK(cdb.field, 0);
CDIO_MMC_SET_READ_LENGTH16(cdb.field, sizeof(tocheader));
i_status = run_mmc_cmd_aspi (p_env, OP_TIMEOUT_MS,
mmc_get_cmd_len(cdb.field[0]),
&cdb, SCSI_MMC_DATA_READ,
sizeof(tocheader), &tocheader);
if (0 != i_status) return false;
p_env->gen.i_first_track = tocheader[2];
p_env->gen.i_tracks = tocheader[3] - tocheader[2] + 1;
{
int i, j, i_toclength;
unsigned char *p_fulltoc;
i_toclength = 4 /* header */ + tocheader[0] +
((unsigned int) tocheader[1] << 8);
p_fulltoc = malloc( i_toclength );
if( p_fulltoc == NULL ) {
cdio_error( "out of memory" );
return false;
}
CDIO_MMC_SET_READ_LENGTH16(cdb.field, i_toclength);
i_status = run_mmc_cmd_aspi (p_env, OP_TIMEOUT_MS,
mmc_get_cmd_len(cdb.field[0]),
&cdb, SCSI_MMC_DATA_READ,
i_toclength, p_fulltoc);
if( 0 != i_status ) {
p_env->gen.i_tracks = 0;
}
j = p_env->gen.i_first_track;
for( i = 0 ; i <= p_env->gen.i_tracks ; i++, j++ ) {
int i_index = 8 + 8 * i;
p_env->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 ];
p_env->tocent[i].Control = (UCHAR)p_fulltoc[ 1 + 8 * i ];
set_track_flags(&(p_env->gen.track_flags[j]), p_env->tocent[i].Control);
cdio_debug( "p_sectors: %i %lu",
i, (unsigned long int) p_env->tocent[i].start_lsn );
}
free( p_fulltoc );
}
p_env->gen.toc_init = true;
return true;
}
/* Eject media will eventually get removed from _cdio_win32.c */
#if 0
/*!
Eject media. Return 1 if successful, 0 otherwise.
*/
int
wnaspi32_eject_media (void *user_data) {
_img_private_t *env = 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] = env->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_aspi( 0, MCI_OPEN, i_flags, &op ) ) {
st.dwItem = MCI_STATUS_READY;
/* Eject disc */
ret = mciSendCommand_aspi( op.wDeviceID, MCI_SET,
MCI_SET_DOOR_OPEN, 0 ) != 0;
/* Release access to the device */
mciSendCommand_aspi( op.wDeviceID, MCI_CLOSE, MCI_WAIT, 0 );
} else
ret = 0;
return ret;
}
#endif
/*!
Get format of track.
*/
track_format_t
get_track_format_aspi(const _img_private_t *p_env, track_t track_num)
{
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 = p_env->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_aspi( 0, MCI_OPEN, i_flags, &op ) ) {
st.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
st.dwTrack = track_num;
i_flags = MCI_TRACK | MCI_STATUS_ITEM ;
ret = mciSendCommand_aspi( op.wDeviceID, MCI_STATUS, i_flags, &st );
/* Release access to the device */
mciSendCommand_aspi( 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;
}
#endif /* HAVE_WIN32_CDROM */

View File

@@ -0,0 +1,248 @@
/* Win32 aspi specific */
/*
$Id: aspi32.h,v 1.6 2008/04/21 18:30:21 karl Exp $
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
#define ASPI_HAID 0
#define ASPI_TARGET 0
#define DTYPE_CDROM 0x05
#define SENSE_LEN 0x0E
#define SC_HA_INQUIRY 0x00
#define SC_GET_DEV_TYPE 0x01
#define SC_EXEC_SCSI_CMD 0x02
#define SC_GET_DISK_INFO 0x06
//*****************************************************************************
// %%% SRB Status %%%
//*****************************************************************************
#define SS_PENDING 0x00 // SRB being processed
#define SS_COMP 0x01 // SRB completed without error
#define SS_ABORTED 0x02 // SRB aborted
#define SS_ABORT_FAIL 0x03 // Unable to abort SRB
#define SS_ERR 0x04 // SRB completed with error
#define SS_INVALID_CMD 0x80 // Invalid ASPI command
#define SS_INVALID_HA 0x81 // Invalid host adapter number
#define SS_NO_DEVICE 0x82 // SCSI device not installed
#define SS_INVALID_SRB 0xE0 // Invalid parameter set in SRB
#define SS_OLD_MANAGER 0xE1 // ASPI manager doesn't support Windows
#define SS_BUFFER_ALIGN 0xE1 // Buffer not aligned (replaces
// OLD_MANAGER in Win32)
#define SS_ILLEGAL_MODE 0xE2 // Unsupported Windows mode
#define SS_NO_ASPI 0xE3 // No ASPI managers resident
#define SS_FAILED_INIT 0xE4 // ASPI for windows failed init
#define SS_ASPI_IS_BUSY 0xE5 // No resources available to execute
// cmd
#define SS_BUFFER_TOO_BIG 0xE6 // Buffer size to big to handle!
#define SS_MISMATCHED_COMPONENTS 0xE7 // The DLLs/EXEs of ASPI don't version
// check
#define SS_NO_ADAPTERS 0xE8 // No host adapters to manage
#define SS_INSUFFICIENT_RESOURCES 0xE9 // Couldn't allocate resources needed
// to init
#define SS_ASPI_IS_SHUTDOWN 0xEA // Call came to ASPI after
// PROCESS_DETACH
#define SS_BAD_INSTALL 0xEB // The DLL or other components are installed wrong
//*****************************************************************************
// %%% Host Adapter Status %%%
//*****************************************************************************
#define HASTAT_OK 0x00 // Host adapter did not detect an
// error
#define HASTAT_SEL_TO 0x11 // Selection Timeout
#define HASTAT_DO_DU 0x12 // Data overrun data underrun
#define HASTAT_BUS_FREE 0x13 // Unexpected bus free
#define HASTAT_PHASE_ERR 0x14 // Target bus phase sequence
// failure
#define HASTAT_TIMEOUT 0x09 // Timed out while SRB was
// waiting to beprocessed.
#define HASTAT_COMMAND_TIMEOUT 0x0B // Adapter timed out processing SRB.
#define HASTAT_MESSAGE_REJECT 0x0D // While processing SRB, the
// adapter received a MESSAGE
#define HASTAT_BUS_RESET 0x0E // A bus reset was detected.
#define HASTAT_PARITY_ERROR 0x0F // A parity error was detected.
#define HASTAT_REQUEST_SENSE_FAILED 0x10 // The adapter failed in issuing
#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];
};
/*****************************************************************************
%%% SRB - HOST ADAPTER INQUIRY - SC_HA_INQUIRY (0) %%%
*****************************************************************************/
typedef struct // Offset
{ // HX/DEC
BYTE SRB_Cmd; // 00/000 ASPI command code = SC_HA_INQUIRY
BYTE SRB_Status; // 01/001 ASPI command status byte
BYTE SRB_HaId; // 02/002 ASPI host adapter number
BYTE SRB_Flags; // 03/003 ASPI request flags
DWORD SRB_Hdr_Rsvd; // 04/004 Reserved, MUST = 0
BYTE HA_Count; // 08/008 Number of host adapters present
BYTE HA_SCSI_ID; // 09/009 SCSI ID of host adapter
BYTE HA_ManagerId[16]; // 0A/010 String describing the manager
BYTE HA_Identifier[16]; // 1A/026 String describing the host adapter
BYTE HA_Unique[16]; // 2A/042 Host Adapter Unique parameters
WORD HA_Rsvd1; // 3A/058 Reserved, MUST = 0
}
SRB_HAInquiry;
/*!
Get disc type associated with cd object.
*/
discmode_t get_discmode_aspi (_img_private_t *p_env);
/*!
Return the the kind of drive capabilities of device.
Note: string is malloc'd so caller should free() then returned
string when done with it.
*/
char * get_mcn_aspi (const _img_private_t *env);
/*!
Get the format (XA, DATA, AUDIO) of a track.
*/
track_format_t get_track_format_aspi(const _img_private_t *env,
track_t i_track);
/*!
Initialize internal structures for CD device.
*/
bool init_aspi (_img_private_t *env);
/*
Read cdtext information for a CdIo object .
return true on success, false on error or CD-TEXT information does
not exist.
*/
bool init_cdtext_aspi (_img_private_t *env);
const char *is_cdrom_aspi(const char drive_letter);
/*!
Reads an audio device using the DeviceIoControl method into data
starting from lsn. Returns 0 if no error.
*/
int read_audio_sectors_aspi (_img_private_t *obj, void *data, lsn_t lsn,
unsigned int nblocks);
/*!
Reads a single mode1 sector using the DeviceIoControl method into
data starting from lsn. Returns 0 if no error.
*/
int read_mode1_sector_aspi (_img_private_t *env, void *data,
lsn_t lsn, bool b_form2);
/*!
Reads a single mode2 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
int read_mode2_sector_aspi (_img_private_t *env, void *data, lsn_t lsn,
bool b_form2);
/*!
Read and cache the CD's Track Table of Contents and track info.
Return true if successful or false if an error.
*/
bool read_toc_aspi (_img_private_t *env);
/*!
Run a SCSI MMC command.
env private CD structure
i_timeout time in milliseconds we will wait for the command
to complete. If this value is -1, use the default
time-out value.
p_buf Buffer for data, both sending and receiving
i_buf Size of buffer
e_direction direction the transfer is to go.
cdb CDB bytes. All values that are needed should be set on
input. We'll figure out what the right CDB length should be.
Return 0 if command completed successfully.
*/
int run_mmc_cmd_aspi( void *p_user_data,
unsigned int i_timeout,
unsigned int i_cdb,
const mmc_cdb_t * p_cdb,
cdio_mmc_direction_t e_direction,
unsigned int i_buf, /*in/out*/ void *p_buf );

1003
lib/driver/MSWindows/win32.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,239 @@
/*
$Id: win32.h,v 1.11 2008/04/21 18:30:21 karl Exp $
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "cdio_private.h"
#pragma pack()
typedef struct {
lsn_t start_lsn;
UCHAR Control : 4;
UCHAR Format;
cdtext_t cdtext; /* CD-TEXT */
} track_info_t;
typedef enum {
_AM_NONE,
_AM_IOCTL,
_AM_ASPI,
} access_mode_t;
typedef struct {
/* Things common to all drivers like this.
This must be first. */
generic_img_private_t gen;
access_mode_t access_mode;
/* Some of the more OS specific things. */
/* Entry info for each track, add 1 for leadout. */
track_info_t tocent[CDIO_CD_MAX_TRACKS+1];
HANDLE h_device_handle; /* device descriptor */
long hASPI;
short i_sid;
short i_lun;
long (*lpSendCommand)( void* );
bool b_ioctl_init;
bool b_aspi_init;
} _img_private_t;
/*!
Pause playing CD through analog output
@param p_cdio the CD object to be acted upon.
*/
driver_return_code_t audio_pause_win32ioctl (void *p_user_data);
/*!
Playing starting at given MSF through analog output
@param p_cdio the CD object to be acted upon.
*/
driver_return_code_t audio_play_msf_win32ioctl (void *p_user_data,
msf_t *p_start_msf,
msf_t *p_end_msf);
/*!
Resume playing an audio CD.
@param p_cdio the CD object to be acted upon.
*/
driver_return_code_t audio_resume_win32ioctl (void *p_user_data);
/*!
Get disc type associated with cd object.
*/
discmode_t get_discmode_win32ioctl (_img_private_t *p_env);
/*!
Get the volume settings of an audio CD.
@param p_cdio the CD object to be acted upon.
*/
driver_return_code_t
audio_get_volume_win32ioctl ( void *p_user_data,
/*out*/ cdio_audio_volume_t *p_volume);
/*!
Read Audio Subchannel information
@param p_cdio the CD object to be acted upon.
*/
driver_return_code_t
audio_read_subchannel_win32ioctl (void *p_user_data,
cdio_subchannel_t *p_subchannel);
/*!
Set the volume of an audio CD.
@param p_cdio the CD object to be acted upon.
*/
driver_return_code_t
audio_stop_win32ioctl ( void *p_user_data );
/*!
Set the volume of an audio CD.
@param p_cdio the CD object to be acted upon.
*/
driver_return_code_t
audio_set_volume_win32ioctl ( void *p_user_data,
cdio_audio_volume_t *p_volume);
/*!
Close the tray of a CD-ROM
@param p_user_data the CD object to be acted upon.
*/
driver_return_code_t close_tray_win32ioctl (const char *psz_win32_drive);
/*!
Reads an audio device using the DeviceIoControl method into data
starting from lsn. Returns 0 if no error.
*/
int read_audio_sectors_win32ioctl (_img_private_t *p_obj, void *p_data, lsn_t lsn,
unsigned int nblocks);
/*!
Reads a single mode2 sector using the DeviceIoControl method into
data starting from lsn. Returns 0 if no error.
*/
int read_mode2_sector_win32ioctl (_img_private_t *p_env, void *p_data,
lsn_t lsn, bool b_form2);
/*!
Reads a single mode1 sector using the DeviceIoControl method into
data starting from lsn. Returns 0 if no error.
*/
int read_mode1_sector_win32ioctl (_img_private_t *p_env, void *p_data,
lsn_t lsn, bool b_form2);
const char *is_cdrom_win32ioctl (const char drive_letter);
/*!
Run a SCSI MMC command.
env private CD structure
i_timeout_ms time in milliseconds we will wait for the command
to complete. If this value is -1, use the default
time-out value.
p_buf Buffer for data, both sending and receiving
i_buf Size of buffer
e_direction direction the transfer is to go.
cdb CDB bytes. All values that are needed should be set on
input. We'll figure out what the right CDB length should be.
Return 0 if command completed successfully.
*/
int run_mmc_cmd_win32ioctl( void *p_user_data,
unsigned int i_timeout,
unsigned int i_cdb,
const mmc_cdb_t * p_cdb,
cdio_mmc_direction_t e_direction,
unsigned int i_buf, /*in/out*/ void *p_buf );
/*!
Initialize internal structures for CD device.
*/
bool init_win32ioctl (_img_private_t *p_env);
/*!
Read and cache the CD's Track Table of Contents and track info.
Return true if successful or false if an error.
*/
bool read_toc_win32ioctl (_img_private_t *p_env);
/*!
Return the media catalog number MCN.
Note: string is malloc'd so caller should free() then returned
string when done with it.
*/
char *get_mcn_win32ioctl (const _img_private_t *p_env);
/*
Read cdtext information for a CdIo object .
return true on success, false on error or CD-TEXT information does
not exist.
*/
bool init_cdtext_win32ioctl (_img_private_t *p_env);
/*!
Return the the kind of drive capabilities of device.
Note: string is malloc'd so caller should free() then returned
string when done with it.
*/
void get_drive_cap_aspi (const _img_private_t *p_env,
cdio_drive_read_cap_t *p_read_cap,
cdio_drive_write_cap_t *p_write_cap,
cdio_drive_misc_cap_t *p_misc_cap);
/*!
Return the the kind of drive capabilities of device.
Note: string is malloc'd so caller should free() then returned
string when done with it.
*/
void get_drive_cap_win32ioctl (const _img_private_t *p_env,
cdio_drive_read_cap_t *p_read_cap,
cdio_drive_write_cap_t *p_write_cap,
cdio_drive_misc_cap_t *p_misc_cap);
/*!
Get the format (XA, DATA, AUDIO) of a track.
*/
track_format_t get_track_format_win32ioctl(const _img_private_t *p_env,
track_t i_track);
void set_cdtext_field_win32(void *user_data, track_t i_track,
track_t i_first_track,
cdtext_field_t e_field, const char *psz_value);

File diff suppressed because it is too large Load Diff

183
lib/driver/Makefile.am Normal file
View File

@@ -0,0 +1,183 @@
# $Id: Makefile.am,v 1.28 2008/10/20 01:25:15 rocky Exp $
#
# Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
# Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
########################################################
# Things to make the libcdio library
########################################################
#
# From libtool documentation amended with guidance from N. Boullis:
#
# 1. Start with version information of `0:0:0' for each libtool library.
#
# 2. It is probably not a good idea to update the version information
# several times between public releases, but rather once per public
# release. (This seems to be more an aesthetic consideration than
# a hard technical one.)
#
# 3. If the library source code has changed at all since the last
# update, then increment REVISION (`C:R:A' becomes `C:R+1:A').
#
# 4. If any interfaces have been added, removed, or changed since the
# last update, increment CURRENT, and set REVISION to 0.
#
# 5. If any interfaces have been added since the last public release,
# then increment AGE.
#
# 6. If any interfaces have been removed or changed since the last
# public release, then set AGE to 0. A changed interface means an
# incompatibility with previous versions.
libcdio_la_CURRENT = 10
libcdio_la_REVISION = 0
libcdio_la_AGE = 0
EXTRA_DIST = image/Makefile FreeBSD/Makefile MSWindows/Makefile \
libcdio.sym
noinst_HEADERS = cdio_assert.h cdio_private.h portable.h
libcdio_sources = \
_cdio_generic.c \
_cdio_stdio.c \
_cdio_stdio.h \
_cdio_stream.c \
_cdio_stream.h \
aix.c \
bsdi.c \
audio.c \
cd_types.c \
cdio.c \
cdtext.c \
cdtext_private.h \
device.c \
disc.c \
ds.c \
FreeBSD/freebsd.c \
FreeBSD/freebsd.h \
FreeBSD/freebsd_cam.c \
FreeBSD/freebsd_ioctl.c \
generic.h \
gnu_linux.c \
image.h \
image/bincue.c \
image/cdrdao.c \
image_common.c \
image_common.h \
image/nrg.c \
image/nrg.h \
logging.c \
mmc.c \
mmc_private.h \
MSWindows/aspi32.c \
MSWindows/aspi32.h \
MSWindows/win32_ioctl.c \
MSWindows/win32.c \
MSWindows/win32.h \
netbsd.c \
osx.c \
read.c \
sector.c \
solaris.c \
track.c \
utf8.c \
util.c
lib_LTLIBRARIES = libcdio.la
libcdio_la_LIBADD = $(LTLIBICONV)
libcdio_la_SOURCES = $(libcdio_sources)
libcdio_la_ldflags = -version-info $(libcdio_la_CURRENT):$(libcdio_la_REVISION):$(libcdio_la_AGE) @LT_NO_UNDEFINED@
INCLUDES = $(LIBCDIO_CFLAGS)
########################################################
# Things to version the symbols in the libraries
########################################################
# An explanation of the versioning problem from Nicolas Boullis and
# the versioned symbol solution he uses below...
#
# Currently, libvcdinfo uses the cdio_open function from libcdio.
# Let's imagine a program foobar that uses both the vcdinfo_open
# function from libvcdinfo and the cdio_open function from libcdio.
# Currently, libcdio has SONAME libcdio.so.0, libvcdinfo has SONAME
# libvcdinfo.so.0 and requires libcdio.so.0, and foobar requires both
# libvcdinfo.so.0 and libcdio.so.0. Everything looks fine.
#
# Now, for some reason, you decide to change the cdio_open function.
# That's your right, but you have to bump the CURRENT version and (if I
# understand it correctly, athough this is not that clear in libtool's
# documentation) set the AGE to 0. Anyway, this bumps the SONAME, which is
# sane since the interface changes incompatibly.
# Now, you have a new libcdio with SONAME libcdio.so.1. But libvcdinfo and
# foobar still require libcdio.so.0. Everything is still fine.
# Now, after some minor changes, the author of foobar recompiles foobar.
# Then, foobar now requires libvcdinfo.so.0 and libcdio.so.1. And foobar
# now segfaults...
# What is happening? When you run foobar, if brings both libvcdinfo.so.0
# and libcdio.so.1, but libvcdinfo.so.0 also brings libcdio.so.0. So you
# have both libcdio.so.0 and libcdio.so.1 that bring their symbols to the
# global namespace. Hence, you have to incompatible versions of the
# cdio_open function in the name space. When foobar calls cdio_open, it
# may choose the wrong function, and segfaults...
# With versioned symbols, the cdio_open function from libcdio.so.0 may be
# known as (something that looks like) cdio_open@@CDIO_0. An the cdio_open
# function from libcdio.so.1 as cdio_open@@CDIO_1. Both versions of
# libcdio would still be brought in by the most recent foobar, but foobar
# (and libvcdinfo) know which versioned function to use and then use the
# good one.
# This is some simple versioning where every symbol is versioned with
# something that looks like the SONAME of the library. More complex (and
# better) versioning is possible; it is for example what is used by glibc.
# But good complex versioning is something that requires much more
# work...
# The below is a impliments symbol versioning. First of all, I
# compute MAJOR as CURENT - AGE; that is what is used within libtool
# (at least on GNU/Linux systems) for the number in the SONAME. The
# nm command gives the list of symbols known in each of the object
# files that will be part of the shared library. And the sed command
# extracts from this list those symbols that will be shared. (This sed
# command comes from libtool.)
libcdio_la_MAJOR = $(shell expr $(libcdio_la_CURRENT) - $(libcdio_la_AGE))
if BUILD_VERSIONED_LIBS
libcdio_la_LDFLAGS = $(libcdio_la_ldflags) -Wl,--version-script=libcdio.la.ver
libcdio_la_DEPENDENCIES = libcdio.la.ver
libcdio.la.ver: $(libcdio_la_OBJECTS) $(srcdir)/libcdio.sym
echo 'CDIO_$(libcdio_la_MAJOR) { ' > $@
objs=`for obj in $(libcdio_la_OBJECTS); do sed -ne "s/^pic_object='\(.*\)'$$/\1/p" $$obj; done`; \
if test -n "$${objs}" ; then \
nm $${objs} | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | { first=true; while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio.sym; then if test $$first = true; then echo " global:"; first=false; fi; echo " $${symbol};"; fi; done; } >> $@; \
nm $${objs} | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | { first=true; while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio.sym; then :; else if test $$first = true; then echo " local:"; first=false; fi; echo " $${symbol};"; fi; done; } >> $@; \
fi
echo '};' >> $@
else
libcdio_la_LDFLAGS = $(libcdio_la_ldflags)
endif
MOSTLYCLEANFILES = libcdio.la.ver

513
lib/driver/_cdio_generic.c Normal file
View File

@@ -0,0 +1,513 @@
/*
$Id: _cdio_generic.c,v 1.27 2008/04/22 15:29:11 karl Exp $
Copyright (C) 2004, 2005, 2006, 2007, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
/* This file contains generic implementations of device-driver routines.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static const char _rcsid[] = "$Id: _cdio_generic.c,v 1.27 2008/04/22 15:29:11 karl Exp $";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /*HAVE_UNISTD_H*/
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <cdio/sector.h>
#include <cdio/util.h>
#include <cdio/logging.h>
#include "cdio_assert.h"
#include "cdio_private.h"
#include "_cdio_stdio.h"
#include "portable.h"
/*!
Eject media -- there's nothing to do here. We always return -2.
Should we also free resources?
*/
int
cdio_generic_unimplemented_eject_media (void *p_user_data) {
/* Sort of a stub here. Perhaps log a message? */
return DRIVER_OP_UNSUPPORTED;
}
/*!
Set the blocksize for subsequent reads.
*/
int
cdio_generic_unimplemented_set_blocksize (void *p_user_data,
uint16_t i_blocksize) {
/* Sort of a stub here. Perhaps log a message? */
return DRIVER_OP_UNSUPPORTED;
}
/*!
Set the drive speed.
*/
int
cdio_generic_unimplemented_set_speed (void *p_user_data, int i_speed) {
/* Sort of a stub here. Perhaps log a message? */
return DRIVER_OP_UNSUPPORTED;
}
/*!
Release and free resources associated with cd.
*/
void
cdio_generic_free (void *p_user_data)
{
generic_img_private_t *p_env = p_user_data;
track_t i_track;
if (NULL == p_env) return;
if (p_env->source_name) free (p_env->source_name);
if (p_env->b_cdtext_init) {
for (i_track=0; i_track < p_env->i_tracks; i_track++) {
cdtext_destroy(&(p_env->cdtext_track[i_track]));
}
}
if (p_env->fd >= 0)
close (p_env->fd);
free (p_env);
}
/*!
Initialize CD device.
*/
bool
cdio_generic_init (void *user_data, int open_flags)
{
generic_img_private_t *p_env = user_data;
if (p_env->init) {
cdio_warn ("init called more than once");
return false;
}
p_env->fd = open (p_env->source_name, open_flags, 0);
if (p_env->fd < 0)
{
cdio_warn ("open (%s): %s", p_env->source_name, strerror (errno));
return false;
}
p_env->init = true;
p_env->toc_init = false;
p_env->b_cdtext_init = false;
p_env->b_cdtext_error = false;
p_env->i_joliet_level = 0; /* Assume no Joliet extensions initally */
return true;
}
/*!
Reads a single form1 sector from cd device into data starting
from lsn.
*/
driver_return_code_t
cdio_generic_read_form1_sector (void * user_data, void *data, lsn_t lsn)
{
if (0 > cdio_generic_lseek(user_data, CDIO_CD_FRAMESIZE*lsn, SEEK_SET))
return DRIVER_OP_ERROR;
return cdio_generic_read(user_data, data, CDIO_CD_FRAMESIZE);
}
/*!
Reads into buf the next size bytes.
Returns -1 on error.
Is in fact libc's lseek().
*/
off_t
cdio_generic_lseek (void *user_data, off_t offset, int whence)
{
generic_img_private_t *p_env = user_data;
return lseek(p_env->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 *p_env = user_data;
return read(p_env->fd, buf, size);
}
/*!
Release and free resources associated with stream or disk image.
*/
void
cdio_generic_stdio_free (void *p_user_data)
{
generic_img_private_t *p_env = p_user_data;
if (NULL == p_env) return;
if (NULL != p_env->source_name)
free (p_env->source_name);
if (p_env->data_source)
cdio_stdio_destroy (p_env->data_source);
}
/*!
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,
unsigned int *num_drives)
{
if (NULL != drive) {
unsigned int j;
char real_device_1[PATH_MAX];
char real_device_2[PATH_MAX];
cdio_follow_symlink(drive, real_device_1);
/* Check if drive is already in list. */
for (j=0; j<*num_drives; j++) {
cdio_follow_symlink((*device_list)[j], real_device_2);
if (strcmp(real_device_1, real_device_2) == 0) break;
}
if (j==*num_drives) {
/* Drive not in list. Add it. */
(*num_drives)++;
*device_list = realloc(*device_list, (*num_drives) * sizeof(char *));
(*device_list)[*num_drives-1] = strdup(drive);
}
} else {
(*num_drives)++;
if (*device_list) {
*device_list = realloc(*device_list, (*num_drives) * sizeof(char *));
} else {
*device_list = malloc((*num_drives) * sizeof(char *));
}
(*device_list)[*num_drives-1] = NULL;
}
}
/*
Get cdtext information in p_user_data for track i_track.
For disc information i_track is 0.
Return the CD-TEXT or NULL if obj is NULL, CD-TEXT information does
not exist, or we don't know how to get this implemented.
*/
cdtext_t *
get_cdtext_generic (void *p_user_data, track_t i_track)
{
generic_img_private_t *p_env = p_user_data;
if (!p_env) return NULL;
if (!p_env->toc_init)
p_env->cdio->op.read_toc (p_user_data);
if ( (0 != i_track
&& i_track >= p_env->i_tracks+p_env->i_first_track ) )
return NULL;
if (!p_env->b_cdtext_init)
init_cdtext_generic(p_env);
if (!p_env->b_cdtext_init) return NULL;
if (0 == i_track)
return &(p_env->cdtext);
else
return &(p_env->cdtext_track[i_track-p_env->i_first_track]);
}
/*!
Get disc type associated with cd object.
*/
discmode_t
get_discmode_generic (void *p_user_data )
{
generic_img_private_t *p_env = p_user_data;
/* See if this is a DVD. */
cdio_dvd_struct_t dvd; /* DVD READ STRUCT for layer 0. */
dvd.physical.type = CDIO_DVD_STRUCT_PHYSICAL;
dvd.physical.layer_num = 0;
if (0 == mmc_get_dvd_struct_physical (p_env->cdio, &dvd)) {
switch(dvd.physical.layer[0].book_type) {
case CDIO_DVD_BOOK_DVD_ROM: return CDIO_DISC_MODE_DVD_ROM;
case CDIO_DVD_BOOK_DVD_RAM: return CDIO_DISC_MODE_DVD_RAM;
case CDIO_DVD_BOOK_DVD_R: return CDIO_DISC_MODE_DVD_R;
case CDIO_DVD_BOOK_DVD_RW: return CDIO_DISC_MODE_DVD_RW;
case CDIO_DVD_BOOK_DVD_PR: return CDIO_DISC_MODE_DVD_PR;
case CDIO_DVD_BOOK_DVD_PRW: return CDIO_DISC_MODE_DVD_PRW;
default: return CDIO_DISC_MODE_DVD_OTHER;
}
}
return get_discmode_cd_generic(p_user_data);
}
/*!
Get disc type associated with cd object.
*/
discmode_t
get_discmode_cd_generic (void *p_user_data )
{
generic_img_private_t *p_env = p_user_data;
track_t i_track;
discmode_t discmode=CDIO_DISC_MODE_NO_INFO;
if (!p_env->toc_init)
p_env->cdio->op.read_toc (p_user_data);
if (!p_env->toc_init)
return CDIO_DISC_MODE_NO_INFO;
for (i_track = p_env->i_first_track;
i_track < p_env->i_first_track + p_env->i_tracks ;
i_track ++) {
track_format_t track_fmt =
p_env->cdio->op.get_track_format(p_env, i_track);
switch(track_fmt) {
case TRACK_FORMAT_AUDIO:
switch(discmode) {
case CDIO_DISC_MODE_NO_INFO:
discmode = CDIO_DISC_MODE_CD_DA;
break;
case CDIO_DISC_MODE_CD_DA:
case CDIO_DISC_MODE_CD_MIXED:
case CDIO_DISC_MODE_ERROR:
/* No change*/
break;
default:
discmode = CDIO_DISC_MODE_CD_MIXED;
}
break;
case TRACK_FORMAT_XA:
switch(discmode) {
case CDIO_DISC_MODE_NO_INFO:
discmode = CDIO_DISC_MODE_CD_XA;
break;
case CDIO_DISC_MODE_CD_XA:
case CDIO_DISC_MODE_CD_MIXED:
case CDIO_DISC_MODE_ERROR:
/* No change*/
break;
default:
discmode = CDIO_DISC_MODE_CD_MIXED;
}
break;
case TRACK_FORMAT_CDI:
case TRACK_FORMAT_DATA:
switch(discmode) {
case CDIO_DISC_MODE_NO_INFO:
discmode = CDIO_DISC_MODE_CD_DATA;
break;
case CDIO_DISC_MODE_CD_DATA:
case CDIO_DISC_MODE_CD_MIXED:
case CDIO_DISC_MODE_ERROR:
/* No change*/
break;
default:
discmode = CDIO_DISC_MODE_CD_MIXED;
}
break;
case TRACK_FORMAT_ERROR:
default:
discmode = CDIO_DISC_MODE_ERROR;
}
}
return discmode;
}
/*!
Return the number of of the first track.
CDIO_INVALID_TRACK is returned on error.
*/
track_t
get_first_track_num_generic(void *p_user_data)
{
const generic_img_private_t *p_env = p_user_data;
if (!p_env->toc_init)
p_env->cdio->op.read_toc (p_user_data);
return p_env->toc_init ? p_env->i_first_track : CDIO_INVALID_TRACK;
}
/*!
Return the number of tracks in the current medium.
*/
track_t
get_num_tracks_generic(void *p_user_data)
{
generic_img_private_t *p_env = p_user_data;
if (!p_env->toc_init)
p_env->cdio->op.read_toc (p_user_data);
return p_env->toc_init ? p_env->i_tracks : CDIO_INVALID_TRACK;
}
void
set_cdtext_field_generic(void *p_user_data, track_t i_track,
track_t i_first_track,
cdtext_field_t e_field, const char *psz_value)
{
char **pp_field;
generic_img_private_t *p_env = p_user_data;
if( i_track == 0 )
pp_field = &(p_env->cdtext.field[e_field]);
else
pp_field = &(p_env->cdtext_track[i_track-i_first_track].field[e_field]);
if (*pp_field) free(*pp_field);
*pp_field = (psz_value) ? strdup(psz_value) : NULL;
}
/*!
Read CD-Text information for a CdIo_t object .
return true on success, false on error or CD-Text information does
not exist.
*/
bool
init_cdtext_generic (generic_img_private_t *p_env)
{
return mmc_init_cdtext_private( p_env,
p_env->cdio->op.run_mmc_cmd,
set_cdtext_field_generic
);
}
/*! Return number of channels in track: 2 or 4; -2 if not
implemented or -1 for error.
Not meaningful if track is not an audio track.
*/
int
get_track_channels_generic(const void *p_user_data, track_t i_track)
{
const generic_img_private_t *p_env = p_user_data;
return p_env->track_flags[i_track].channels;
}
/*! Return 1 if copy is permitted on the track, 0 if not, or -1 for error.
Is this meaningful if not an audio track?
*/
track_flag_t
get_track_copy_permit_generic(void *p_user_data, track_t i_track)
{
const generic_img_private_t *p_env = p_user_data;
return p_env->track_flags[i_track].copy_permit;
}
/*! Return 1 if track has pre-emphasis, 0 if not, or -1 for error.
Is this meaningful if not an audio track?
pre-emphasis is a non linear frequency response.
*/
track_flag_t
get_track_preemphasis_generic(const void *p_user_data, track_t i_track)
{
const generic_img_private_t *p_env = p_user_data;
return p_env->track_flags[i_track].preemphasis;
}
void
set_track_flags(track_flags_t *p_track_flag, uint8_t i_flag)
{
p_track_flag->preemphasis = ( i_flag & CDIO_TRACK_FLAG_PRE_EMPHASIS )
? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE;
p_track_flag->copy_permit = ( i_flag & CDIO_TRACK_FLAG_COPY_PERMITTED )
? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE;
p_track_flag->channels = ( i_flag & CDIO_TRACK_FLAG_FOUR_CHANNEL_AUDIO )
? 4 : 2;
}
driver_return_code_t
read_data_sectors_generic (void *p_user_data, void *p_buf, lsn_t i_lsn,
uint16_t i_blocksize, uint32_t i_blocks)
{
int rc;
if (0 > cdio_generic_lseek(p_user_data, i_blocksize*i_lsn, SEEK_SET))
return DRIVER_OP_ERROR;
rc = cdio_generic_read(p_user_data, p_buf, i_blocksize*i_blocks);
if (rc > 0) return DRIVER_OP_SUCCESS;
return DRIVER_OP_ERROR;
}
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

224
lib/driver/_cdio_stdio.c Normal file
View File

@@ -0,0 +1,224 @@
/*
$Id: _cdio_stdio.c,v 1.6 2008/04/22 15:29:11 karl Exp $
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /*HAVE_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.6 2008/04/22 15:29:11 karl 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 = calloc (1, 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 upon successful completion, DRIVER_OP_SUCCESS, else,
DRIVER_OP_ERROR is returned and the global variable errno is set to
indicate the error.
*/
static driver_return_code_t
_stdio_seek(void *p_user_data, long i_offset, int whence)
{
_UserData *const ud = p_user_data;
if ( (i_offset=fseek (ud->fd, i_offset, whence)) ) {
cdio_error ("fseek (): %s", strerror (errno));
}
return i_offset;
}
static long int
_stdio_stat(void *p_user_data)
{
const _UserData *const ud = p_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 int 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;
}
/*!
Deallocate resources assocaited with obj. After this obj is unusable.
*/
void
cdio_stdio_destroy(CdioDataSource_t *p_obj)
{
cdio_stream_destroy(p_obj);
}
CdioDataSource_t *
cdio_stdio_new(const char pathname[])
{
CdioDataSource_t *new_obj = NULL;
cdio_stream_io_functions funcs = { NULL, NULL, NULL, NULL, NULL, NULL };
_UserData *ud = NULL;
struct stat statbuf;
if (stat (pathname, &statbuf) == -1)
{
cdio_warn ("could not retrieve file info for `%s': %s",
pathname, strerror (errno));
return NULL;
}
ud = calloc (1, 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:
*/

51
lib/driver/_cdio_stdio.h Normal file
View File

@@ -0,0 +1,51 @@
/*
$Id: _cdio_stdio.h,v 1.3 2008/04/22 15:29:11 karl Exp $
Copyright (C) 2003, 2008 Rocky Bernstein <rocky@gnu.org>
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CDIO_STDIO_H__
#define __CDIO_STDIO_H__
#include "_cdio_stream.h"
/*!
Initialize a new stdio stream reading from pathname.
A pointer to the stream is returned or NULL if there was an error.
cdio_stream_free should be called on the returned value when you
don't need the stream any more. No other finalization is needed.
*/
CdioDataSource_t * cdio_stdio_new(const char psz_path[]);
/*!
Deallocate resources assocaited with obj. After this obj is unusable.
*/
void cdio_stdio_destroy(CdioDataSource_t *p_obj);
#endif /* __CDIO_STREAM_STDIO_H__ */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

214
lib/driver/_cdio_stream.c Normal file
View File

@@ -0,0 +1,214 @@
/*
$Id: _cdio_stream.c,v 1.9 2008/04/22 15:29:11 karl Exp $
Copyright (C) 2005, 2006, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 2000, 2004, 2005 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#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.9 2008/04/22 15:29:11 karl Exp $";
/*
* DataSource implementations
*/
struct _CdioDataSource {
void* user_data;
cdio_stream_io_functions op;
int is_open;
long position;
};
void
cdio_stream_close(CdioDataSource_t *p_obj)
{
if (!p_obj) return;
if (p_obj->is_open) {
cdio_debug ("closed source...");
p_obj->op.close(p_obj->user_data);
p_obj->is_open = 0;
p_obj->position = 0;
}
}
void
cdio_stream_destroy(CdioDataSource_t *p_obj)
{
if (!p_obj) return;
cdio_stream_close(p_obj);
p_obj->op.free(p_obj->user_data);
free(p_obj);
}
/**
Like 3 fgetpos.
This function gets the current file position indicator for the stream
pointed to by stream.
@return unpon successful completion, return value is positive, else,
the global variable errno is set to indicate the error.
*/
ssize_t
cdio_stream_getpos(CdioDataSource_t* p_obj, /*out*/ ssize_t *i_offset)
{
if (!p_obj || !p_obj->is_open) return DRIVER_OP_UNINIT;
return *i_offset = p_obj->position;
}
CdioDataSource_t *
cdio_stream_new(void *user_data, const cdio_stream_io_functions *funcs)
{
CdioDataSource_t *new_obj;
new_obj = calloc (1, sizeof (CdioDataSource_t));
new_obj->user_data = user_data;
memcpy(&(new_obj->op), funcs, sizeof(cdio_stream_io_functions));
return new_obj;
}
/*
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_t *p_obj)
{
if (!p_obj) return false;
if (!p_obj->is_open) {
if (p_obj->op.open(p_obj->user_data)) {
cdio_warn ("could not open input stream...");
return false;
} else {
cdio_debug ("opened source...");
p_obj->is_open = 1;
p_obj->position = 0;
}
}
return true;
}
/**
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.
*/
ssize_t
cdio_stream_read(CdioDataSource_t* p_obj, void *ptr, long size, long nmemb)
{
long read_bytes;
if (!p_obj) return 0;
if (!_cdio_stream_open_if_necessary(p_obj)) return 0;
read_bytes = (p_obj->op.read)(p_obj->user_data, ptr, size*nmemb);
p_obj->position += read_bytes;
return read_bytes;
}
/**
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 unpon successful completion, return value is positive, else,
the global variable errno is set to indicate the error.
*/
ssize_t
cdio_stream_seek(CdioDataSource_t* p_obj, ssize_t offset, int whence)
{
if (!p_obj) return DRIVER_OP_UNINIT;
if (!_cdio_stream_open_if_necessary(p_obj))
/* errno is set by _cdio_stream_open_if necessary. */
return DRIVER_OP_ERROR;
if (offset < 0) return DRIVER_OP_ERROR;
if (p_obj->position != offset) {
#ifdef STREAM_DEBUG
cdio_warn("had to reposition DataSource from %ld to %ld!", obj->position, offset);
#endif
p_obj->position = offset;
return p_obj->op.seek(p_obj->user_data, offset, whence);
}
return 0;
}
/**
Return whatever size of stream reports, I guess unit size is bytes.
On error return -1;
*/
ssize_t
cdio_stream_stat(CdioDataSource_t *p_obj)
{
if (!p_obj) return -1;
if (!_cdio_stream_open_if_necessary(p_obj)) return -1;
return p_obj->op.stat(p_obj->user_data);
}
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

139
lib/driver/_cdio_stream.h Normal file
View File

@@ -0,0 +1,139 @@
/*
$Id: _cdio_stream.h,v 1.5 2008/04/22 15:29:11 karl Exp $
Copyright (C) 2003, 2004, 2005, 2006, 2008 Rocky Bernstein <rocky@gnu.org>
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#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 driver_return_code_t(*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;
/**
Like 3 fgetpos.
This function gets the current file position indicator for the stream
pointed to by stream.
@return unpon successful completion, return value is positive, else,
the global variable errno is set to indicate the error.
*/
ssize_t cdio_stream_getpos(CdioDataSource_t* p_obj,
/*out*/ ssize_t *i_offset);
CdioDataSource_t *
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.
*/
ssize_t cdio_stream_read(CdioDataSource_t* p_obj, void *ptr, long i_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 upon successful completion, DRIVER_OP_SUCCESS, else,
DRIVER_OP_ERROR is returned and the global variable errno is set to
indicate the error.
*/
ssize_t cdio_stream_seek(CdioDataSource_t *p_obj, ssize_t i_offset,
int whence);
/**
Return whatever size of stream reports, I guess unit size is bytes.
On error return -1;
*/
ssize_t cdio_stream_stat(CdioDataSource_t *p_obj);
/**
Deallocate resources associated with p_obj. After this p_obj is unusable.
*/
void cdio_stream_destroy(CdioDataSource_t *p_obj);
void cdio_stream_close(CdioDataSource_t *p_obj);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __CDIO_STREAM_H__ */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

1026
lib/driver/aix.c Normal file

File diff suppressed because it is too large Load Diff

188
lib/driver/audio.c Normal file
View File

@@ -0,0 +1,188 @@
/*
$Id: audio.c,v 1.9 2008/04/22 15:29:11 karl Exp $
Copyright (C) 2005, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
/*! Audio (via line output) related routines. */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cdio/cdio.h>
#include <cdio/util.h>
#include <cdio/audio.h>
#include "cdio_private.h"
/* Return the number of seconds (discarding frame portion) of an MSF */
uint32_t
cdio_audio_get_msf_seconds(msf_t *p_msf)
{
return
cdio_from_bcd8(p_msf->m)*CDIO_CD_SECS_PER_MIN + cdio_from_bcd8(p_msf->s);
}
/*!
Get volume of an audio CD.
@param p_cdio the CD object to be acted upon.
*/
driver_return_code_t
cdio_audio_get_volume (CdIo_t *p_cdio, /*out*/ cdio_audio_volume_t *p_volume)
{
cdio_audio_volume_t temp_audio_volume;
if (!p_cdio) return DRIVER_OP_UNINIT;
if (!p_volume) p_volume = &temp_audio_volume;
if (p_cdio->op.audio_get_volume) {
return p_cdio->op.audio_get_volume (p_cdio->env, p_volume);
} else {
return DRIVER_OP_UNSUPPORTED;
}
}
/*!
Playing CD through analog output
@param p_cdio the CD object to be acted upon.
*/
driver_return_code_t
cdio_audio_pause (CdIo_t *p_cdio)
{
if (!p_cdio) return DRIVER_OP_UNINIT;
if (p_cdio->op.audio_pause) {
return p_cdio->op.audio_pause (p_cdio->env);
} else {
return DRIVER_OP_UNSUPPORTED;
}
}
/*!
Playing CD through analog output at the given MSF.
@param p_cdio the CD object to be acted upon.
*/
driver_return_code_t
cdio_audio_play_msf (CdIo_t *p_cdio, msf_t *p_start_msf, msf_t *p_end_msf)
{
if (!p_cdio) return DRIVER_OP_UNINIT;
if (p_cdio->op.audio_play_msf) {
return p_cdio->op.audio_play_msf (p_cdio->env, p_start_msf, p_end_msf);
} else {
return DRIVER_OP_UNSUPPORTED;
}
}
/*!
Playing CD through analog output
@param p_cdio the CD object to be acted upon.
*/
driver_return_code_t
cdio_audio_play_track_index (CdIo_t *p_cdio, cdio_track_index_t *p_track_index)
{
if (!p_cdio) return DRIVER_OP_UNINIT;
if (p_cdio->op.audio_play_track_index) {
return p_cdio->op.audio_play_track_index (p_cdio->env, p_track_index);
} else {
return DRIVER_OP_UNSUPPORTED;
}
}
/*!
Get subchannel information.
@param p_cdio the CD object to be acted upon.
*/
driver_return_code_t
cdio_audio_read_subchannel (CdIo_t *p_cdio, cdio_subchannel_t *p_subchannel)
{
if (!p_cdio) return DRIVER_OP_UNINIT;
if (p_cdio->op.audio_read_subchannel) {
return p_cdio->op.audio_read_subchannel(p_cdio->env, p_subchannel);
} else {
return DRIVER_OP_UNSUPPORTED;
}
}
/*!
Resume playing an audio CD.
@param p_cdio the CD object to be acted upon.
*/
driver_return_code_t
cdio_audio_resume (CdIo_t *p_cdio)
{
if (!p_cdio) return DRIVER_OP_UNINIT;
if (p_cdio->op.audio_resume) {
return p_cdio->op.audio_resume(p_cdio->env);
} else {
return DRIVER_OP_UNSUPPORTED;
}
}
/*!
Set volume of an audio CD.
@param p_cdio the CD object to be acted upon.
*/
driver_return_code_t
cdio_audio_set_volume (CdIo_t *p_cdio, cdio_audio_volume_t *p_volume)
{
if (!p_cdio) return DRIVER_OP_UNINIT;
if (p_cdio->op.audio_set_volume) {
return p_cdio->op.audio_set_volume(p_cdio->env, p_volume);
} else {
return DRIVER_OP_UNSUPPORTED;
}
}
/*!
Resume playing an audio CD.
@param p_cdio the CD object to be acted upon.
*/
driver_return_code_t
cdio_audio_stop (CdIo_t *p_cdio)
{
if (!p_cdio) return DRIVER_OP_UNINIT;
if (p_cdio->op.audio_stop) {
return p_cdio->op.audio_stop(p_cdio->env);
} else {
return DRIVER_OP_UNSUPPORTED;
}
}
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

1079
lib/driver/bsdi.c Normal file

File diff suppressed because it is too large Load Diff

360
lib/driver/cd_types.c Normal file
View File

@@ -0,0 +1,360 @@
/*
$Id: cd_types.c,v 1.9 2008/06/16 19:39:30 flameeyes Exp $
Copyright (C) 2003, 2004, 2005, 2006, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
/*
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.
*/
/** The below variables are trickery to force enum symbol values to be
recorded in debug symbol tables. They are used to allow one to refer
to the enumeration value names in the typedefs above in a debugger
and debugger expressions.
*/
cdio_fs_cap_t debug_cdio_fs_cap;
cdio_fs_t debug_cdio_fs;
static char buffer[6][CDIO_CD_FRAMESIZE_RAW]; /* for CD-Data */
/* Some interesting sector numbers stored in the above buffer. */
#define ISO_SUPERBLOCK_SECTOR 16 /* buffer[0] */
#define UFS_SUPERBLOCK_SECTOR 4 /* buffer[2] */
#define BOOT_SECTOR 17 /* buffer[3] */
#define VCD_INFO_SECTOR 150 /* buffer[4] */
#define XISO_SECTOR 32 /* buffer[4] */
#define UDFX_SECTOR 32 /* buffer[4] */
#define UDF_ANCHOR_SECTOR 256 /* buffer[5] */
typedef struct signature
{
unsigned int buf_num;
unsigned int offset;
char sig_str[60];
char description[60];
} signature_t;
static const signature_t sigs[] =
{
/*buffer[x] off look for description */
{0, 0, "MICROSOFT*XBOX*MEDIA", "XBOX CD"},
{0, 1, "BEA01", "UDF"},
{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"}
};
/* The below index into the above sigs array. Make sure things match. */
#define INDEX_XISO 0 /* Microsoft X-BOX filesystem */
#define INDEX_UDF 1
#define INDEX_ISOFS 2
#define INDEX_CD_I 3
#define INDEX_CDTV 4
#define INDEX_CD_RTOS 5
#define INDEX_HS 6
#define INDEX_BRIDGE 7
#define INDEX_XA 8
#define INDEX_PHOTO_CD 9
#define INDEX_EXT2 10
#define INDEX_UFS 11
#define INDEX_BOOTABLE 12
#define INDEX_VIDEO_CD 13 /* Video CD */
#define INDEX_SVCD 14 /* CVD *or* SVCD */
/*
Read a particular block into the global array to be used for further
analysis later.
*/
static driver_return_code_t
_cdio_read_block(const CdIo_t *p_cdio, int superblock, uint32_t offset,
uint8_t bufnum, track_t i_track)
{
unsigned int track_sec_count = cdio_get_track_sec_count(p_cdio, i_track);
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, i_track, track_sec_count);
return DRIVER_OP_ERROR;
}
cdio_debug("about to read sector %lu\n",
(long unsigned int) offset+superblock);
return cdio_read_data_sectors (p_cdio, buffer[bufnum], offset+superblock,
ISO_BLOCKSIZE, 1);
}
/*
Return true if the previously read-in buffer contains a "signature" that
matches index "num".
*/
static bool
_cdio_is_it(int num)
{
const 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;
}
static int
_cdio_is_UDF(void)
{
return 2 == ((uint16_t)buffer[5][0] | ((uint16_t)buffer[5][1] << 8));
}
/* 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 i_track. 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_t *p_cdio, int start_session, track_t i_track,
/*out*/ cdio_iso_analysis_t *iso_analysis)
{
int ret = CDIO_FS_UNKNOWN;
bool sector0_read_ok;
if (TRACK_FORMAT_AUDIO == cdio_get_track_format(p_cdio, i_track))
return CDIO_FS_AUDIO;
if ( DRIVER_OP_SUCCESS !=
_cdio_read_block(p_cdio, ISO_PVD_SECTOR, start_session, 0, i_track) )
return CDIO_FS_UNKNOWN;
if ( _cdio_is_it(INDEX_XISO) )
return CDIO_FS_ANAL_XISO;
if ( DRIVER_OP_SUCCESS != _cdio_read_block(p_cdio, ISO_SUPERBLOCK_SECTOR,
start_session, 0, i_track) )
return ret;
if ( _cdio_is_it(INDEX_UDF) ) {
/* Detect UDF version
Test if we have a valid version of UDF the xbox can read natively */
if (_cdio_read_block(p_cdio, 35, start_session, 5, i_track) < 0)
return CDIO_FS_UNKNOWN;
iso_analysis->UDFVerMinor=(unsigned int)buffer[5][240];
iso_analysis->UDFVerMajor=(unsigned int)buffer[5][241];
/* Read disc label */
if (_cdio_read_block(p_cdio, 32, start_session, 5, i_track) < 0)
return CDIO_FS_UDF;
strncpy(iso_analysis->iso_label, buffer[5]+25, 33);
iso_analysis->iso_label[32] = '\0';
return CDIO_FS_UDF;
}
/* 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 | CDIO_FS_ANAL_ISO9660_ANY);
} else {
/* read sector 0 ONLY, when NO greenbook CD-I !!!! */
sector0_read_ok =
_cdio_read_block(p_cdio, 0, start_session, 1, i_track) == 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 | CDIO_FS_ANAL_ISO9660_ANY);
else if (_cdio_is_hfs())
ret = CDIO_FS_ISO_HFS;
else
ret = (CDIO_FS_ISO_9660 | CDIO_FS_ANAL_ISO9660_ANY);
iso_analysis->isofs_size = _cdio_get_iso9660_fs_sec_count();
strncpy(iso_analysis->iso_label, buffer[0]+40,33);
iso_analysis->iso_label[32] = '\0';
if ( _cdio_read_block(p_cdio, UDF_ANCHOR_SECTOR, start_session, 5,
i_track) < 0)
return ret;
/* Maybe there is an UDF anchor in IOS session
so its ISO/UDF session and we prefere UDF */
if ( _cdio_is_UDF() ) {
/* Detect UDF version.
Test if we have a valid version of UDF the xbox can read natively */
if ( _cdio_read_block(p_cdio, 35, start_session, 5, i_track) < 0)
return ret;
iso_analysis->UDFVerMinor=(unsigned int)buffer[5][240];
iso_analysis->UDFVerMajor=(unsigned int)buffer[5][241];
#if 0
/* We are using ISO/UDF cd's as iso,
no need to get UDF disc label */
if (_cdio_read_block(p_cdio, 32, start_session, 5, i_track) < 0)
return ret;
stnrcpy(iso_analysis->iso_label, buffer[5]+25, 33);
iso_analysis->iso_label[32] = '\0';
#endif
ret=CDIO_FS_ISO_UDF;
}
#if 0
if (_cdio_is_rockridge())
ret |= CDIO_FS_ANAL_ROCKRIDGE;
#endif
if (_cdio_read_block(p_cdio, BOOT_SECTOR, start_session, 3, i_track) < 0)
return ret;
if (_cdio_is_joliet()) {
iso_analysis->joliet_level = _cdio_get_joliet_level();
ret |= (CDIO_FS_ANAL_JOLIET | CDIO_FS_ANAL_ISO9660_ANY);
}
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(p_cdio, VCD_INFO_SECTOR, start_session, 4,
i_track) < 0 )
return ret;
if (_cdio_is_it(INDEX_BRIDGE) && _cdio_is_it(INDEX_CD_RTOS)) {
ret |= CDIO_FS_ANAL_ISO9660_ANY;
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 | CDIO_FS_ANAL_ISO9660_ANY);
else if (_cdio_is_3do()) ret |= CDIO_FS_3DO;
else {
if ( _cdio_read_block(p_cdio, UFS_SUPERBLOCK_SECTOR, start_session, 2,
i_track) < 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 | CDIO_FS_ANAL_ISO9660_ANY);
if (_cdio_is_it(INDEX_PHOTO_CD))
ret |= (CDIO_FS_ANAL_PHOTO_CD | CDIO_FS_ANAL_ISO9660_ANY);
if (_cdio_is_it(INDEX_CDTV))
ret |= CDIO_FS_ANAL_CDTV;
return ret;
}

112
lib/driver/cdio.c Normal file
View File

@@ -0,0 +1,112 @@
/*
$Id: cdio.c,v 1.14 2008/04/22 15:29:11 karl Exp $
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "cdio_assert.h"
#include <cdio/cdio.h>
#include <cdio/util.h>
#include "cdio_private.h"
static const char _rcsid[] = "$Id: cdio.c,v 1.14 2008/04/22 15:29:11 karl Exp $";
/*!
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;
}
}
/*!
Get cdtext information for a CdIo object .
@param obj the CD object that may contain CD-TEXT information.
@return the CD-TEXT object or NULL if obj is NULL
or CD-TEXT information does not exist.
*/
cdtext_t *
cdio_get_cdtext (CdIo *obj, track_t i_track)
{
if (obj == NULL) return NULL;
if (obj->op.get_cdtext) {
return obj->op.get_cdtext (obj->env, i_track);
} else {
return NULL;
}
}
CdIo_t *
cdio_new (generic_img_private_t *p_env, cdio_funcs_t *p_funcs)
{
CdIo_t *p_new_cdio = calloc(1, sizeof (CdIo_t));
if (NULL == p_new_cdio) return NULL;
p_new_cdio->env = p_env; /* This is the private "environment" that
driver-dependent routines use. */
p_new_cdio->op = *p_funcs;
p_env->cdio = p_new_cdio; /* A way for the driver-dependent routines
to access the higher-level general cdio
object. */
return p_new_cdio;
}
/*!
Set the arg "key" with "value" in the source device.
*/
driver_return_code_t
cdio_set_arg (CdIo_t *p_cdio, const char key[], const char value[])
{
if (!p_cdio) return DRIVER_OP_UNINIT;
if (!p_cdio->op.set_arg) return DRIVER_OP_UNSUPPORTED;
if (!key) return DRIVER_OP_ERROR;
return p_cdio->op.set_arg (p_cdio->env, key, value);
}
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

59
lib/driver/cdio_assert.h Normal file
View File

@@ -0,0 +1,59 @@
/*
$Id: cdio_assert.h,v 1.2 2008/04/22 15:29:11 karl Exp $
Copyright (C) 2008 Rocky Bernstein <rocky@gnu.org>
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#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__ */

547
lib/driver/cdio_private.h Normal file
View File

@@ -0,0 +1,547 @@
/*
$Id: cdio_private.h,v 1.37 2008/04/22 15:29:11 karl Exp $
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
/* Internal routines for CD I/O drivers. */
#ifndef __CDIO_PRIVATE_H__
#define __CDIO_PRIVATE_H__
#if defined(HAVE_CONFIG_H) && !defined(LIBCDIO_CONFIG_H)
# include "config.h"
#endif
#include <cdio/cdio.h>
#include <cdio/audio.h>
#include <cdio/cdtext.h>
#include "mmc_private.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Opaque type */
typedef struct _CdioDataSource CdioDataSource_t;
#ifdef __cplusplus
}
#endif /* __cplusplus */
#include "generic.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct {
/*!
Get volume of an audio CD.
@param p_env the CD object to be acted upon.
*/
driver_return_code_t (*audio_get_volume)
(void *p_env, /*out*/ cdio_audio_volume_t *p_volume);
/*!
Pause playing CD through analog output
@param p_env the CD object to be acted upon.
*/
driver_return_code_t (*audio_pause) (void *p_env);
/*!
Playing CD through analog output
@param p_env the CD object to be acted upon.
*/
driver_return_code_t (*audio_play_msf) ( void *p_env,
msf_t *p_start_msf,
msf_t *p_end_msf );
/*!
Playing CD through analog output
@param p_env the CD object to be acted upon.
*/
driver_return_code_t (*audio_play_track_index)
( void *p_env, cdio_track_index_t *p_track_index );
/*!
Get subchannel information.
@param p_env the CD object to be acted upon.
*/
driver_return_code_t (*audio_read_subchannel)
( void *p_env, cdio_subchannel_t *subchannel );
/*!
Resume playing an audio CD.
@param p_env the CD object to be acted upon.
*/
driver_return_code_t (*audio_resume) ( void *p_env );
/*!
Set volume of an audio CD.
@param p_env the CD object to be acted upon.
*/
driver_return_code_t (*audio_set_volume)
( void *p_env, cdio_audio_volume_t *p_volume );
/*!
Stop playing an audio CD.
@param p_env the CD object to be acted upon.
*/
driver_return_code_t (*audio_stop) ( void *p_env );
/*!
Eject media in CD drive. If successful, as a side effect we
also free p_env.
@param p_env the CD object to be acted upon.
If the CD is ejected *p_env is freed and p_env set to NULL.
*/
driver_return_code_t (*eject_media) ( void *p_env );
/*!
Release and free resources associated with cd.
*/
void (*free) (void *p_env);
/*!
Return the value associated with the key "arg".
*/
const char * (*get_arg) (void *p_env, const char key[]);
/*!
Get the block size for subsequest read requests, via a SCSI MMC
MODE_SENSE 6 command.
*/
int (*get_blocksize) ( void *p_env );
/*!
Get cdtext information for a CdIo object.
@param obj the CD object that may contain CD-TEXT information.
@return the CD-TEXT object or NULL if obj is NULL
or CD-TEXT information does not exist.
If i_track is 0 or CDIO_CDROM_LEADOUT_TRACK the track returned
is the information assocated with the CD.
*/
cdtext_t * (*get_cdtext) ( void *p_env, track_t i_track );
/*!
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 );
/*!
Get the default CD device.
@return a string containing the default CD device or NULL is
if we couldn't get a default device.
In some situations of drivers or OS's we can't find a CD device if
there is no media in it and it is possible for this routine to return
NULL even though there may be a hardware CD-ROM.
*/
char * (*get_default_device) ( void );
/*!
Return the size of the CD in logical block address (LBA) units.
@return the lsn. On error 0 or CDIO_INVALD_LSN.
*/
lsn_t (*get_disc_last_lsn) ( void *p_env );
/*!
Get disc mode associated with cd_obj.
*/
discmode_t (*get_discmode) ( void *p_env );
/*!
Return the what kind of device we've got.
See cd_types.h for a list of bitmasks for the drive type;
*/
void (*get_drive_cap) (const void *p_env,
cdio_drive_read_cap_t *p_read_cap,
cdio_drive_write_cap_t *p_write_cap,
cdio_drive_misc_cap_t *p_misc_cap);
/*!
Return the number of of the first track.
CDIO_INVALID_TRACK is returned on error.
*/
track_t (*get_first_track_num) ( void *p_env );
/*!
Get the CD-ROM hardware info via a SCSI MMC INQUIRY command.
False is returned if we had an error getting the information.
*/
bool (*get_hwinfo)
( const CdIo_t *p_cdio, /* out*/ cdio_hwinfo_t *p_hw_info );
/*! Get the LSN of the first track of the last session of
on the CD.
@param p_cdio the CD object to be acted upon.
@param i_last_session pointer to the session number to be returned.
*/
driver_return_code_t (*get_last_session)
( void *p_env, /*out*/ lsn_t *i_last_session );
/*!
Find out if media has changed since the last call.
@param p_env the CD object to be acted upon.
@return 1 if media has changed since last call, 0 if not. Error
return codes are the same as driver_return_code_t
*/
int (*get_media_changed) ( const void *p_env );
/*!
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) ( const void *p_env );
/*!
Return the number of tracks in the current medium.
CDIO_INVALID_TRACK is returned on error.
*/
track_t (*get_num_tracks) ( void *p_env );
/*! Return number of channels in track: 2 or 4; -2 if not
implemented or -1 for error.
Not meaningful if track is not an audio track.
*/
int (*get_track_channels) ( const void *p_env, track_t i_track );
/*! Return 0 if track is copy protected, 1 if not, or -1 for error
or -2 if not implimented (yet). Is this meaningful if not an
audio track?
*/
track_flag_t (*get_track_copy_permit) ( void *p_env, track_t i_track );
/*!
Return the starting LBA for track number
i_track in p_env. 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 *p_env, track_t i_track );
/*!
Return the starting LBA for the pregap for track number
i_track in p_env. Tracks numbers start at 1.
CDIO_INVALID_LBA is returned on error.
*/
lba_t (*get_track_pregap_lba) ( const void *p_env, track_t i_track );
/*!
Return the International Standard Recording Code (ISRC) for track number
i_track in p_cdio. Track numbers start at 1.
Note: string is malloc'd so caller has to free() the returned
string when done with it.
*/
char * (*get_track_isrc) ( const void *p_env, track_t i_track );
/*!
Get format of track.
*/
track_format_t (*get_track_format) ( void *p_env, track_t i_track );
/*!
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 *p_env, track_t i_track );
/*!
Return the starting MSF (minutes/secs/frames) for track number
i_track in p_env. Tracks numbers start at 1.
The "leadout" track is specified either by
using i_track LEADOUT_TRACK or the total tracks+1.
False is returned on error.
*/
bool (*get_track_msf) ( void *p_env, track_t i_track, msf_t *p_msf );
/*! Return 1 if track has pre-emphasis, 0 if not, or -1 for error
or -2 if not implimented (yet). Is this meaningful if not an
audio track?
*/
track_flag_t (*get_track_preemphasis)
( const void *p_env, track_t i_track );
/*!
lseek - reposition read/write file offset
Returns (off_t) -1 on error.
Similar to libc's lseek()
*/
off_t (*lseek) ( void *p_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 *p_env, void *p_buf, size_t i_size );
/*!
Reads a single mode2 sector from cd device into buf starting
from lsn. Returns 0 if no error.
*/
int (*read_audio_sectors) ( void *p_env, void *p_buf, lsn_t i_lsn,
unsigned int i_blocks );
/*!
Read a data sector
@param p_env environment to read from
@param p_buf place to read data into. The caller should make sure
this location can store at least CDIO_CD_FRAMESIZE,
M2RAW_SECTOR_SIZE, or M2F2_SECTOR_SIZE depending
on the kind of sector getting read. If you don't
know whether you have a Mode 1/2, Form 1/ Form 2/Formless
sector best to reserve space for the maximum,
M2RAW_SECTOR_SIZE.
@param i_lsn sector to read
@param i_blocksize size of block. Should be either CDIO_CD_FRAMESIZE,
M2RAW_SECTOR_SIZE, or M2F2_SECTOR_SIZE. See comment above under p_buf.
*/
driver_return_code_t (*read_data_sectors)
( void *p_env, void *p_buf, lsn_t i_lsn, uint16_t i_blocksize,
uint32_t i_blocks );
/*!
Reads a single mode2 sector from cd device into buf starting
from lsn. Returns 0 if no error.
*/
int (*read_mode2_sector)
( void *p_env, void *p_buf, lsn_t i_lsn, bool b_mode2_form2 );
/*!
Reads i_blocks of mode2 sectors from cd device into data starting
from lsn.
Returns 0 if no error.
*/
int (*read_mode2_sectors)
( void *p_env, void *p_buf, lsn_t i_lsn, bool b_mode2_form2,
unsigned int i_blocks );
/*!
Reads a single mode1 sector from cd device into buf starting
from lsn. Returns 0 if no error.
*/
int (*read_mode1_sector)
( void *p_env, void *p_buf, lsn_t i_lsn, bool mode1_form2 );
/*!
Reads i_blocks of mode1 sectors from cd device into data starting
from lsn.
Returns 0 if no error.
*/
int (*read_mode1_sectors)
( void *p_env, void *p_buf, lsn_t i_lsn, bool mode1_form2,
unsigned int i_blocks );
bool (*read_toc) ( void *p_env ) ;
/*!
Run a SCSI MMC command.
cdio CD structure set by cdio_open().
i_timeout_ms time in milliseconds we will wait for the command
to complete.
cdb_len number of bytes in cdb (6, 10, or 12).
cdb CDB bytes. All values that are needed should be set on
input.
b_return_data TRUE if the command expects data to be returned in
the buffer
len Size of buffer
buf Buffer for data, both sending and receiving
Returns 0 if command completed successfully.
*/
mmc_run_cmd_fn_t run_mmc_cmd;
/*!
Set the arg "key" with "value" in the source device.
*/
int (*set_arg) ( void *p_env, const char key[], const char value[] );
/*!
Set the blocksize for subsequent reads.
*/
driver_return_code_t (*set_blocksize) ( void *p_env,
uint16_t i_blocksize );
/*!
Set the drive speed.
@return 0 if everything went okay, -1 if we had an error. is -2
returned if this is not implemented for the current driver.
*/
int (*set_speed) ( void *p_env, int i_speed );
} cdio_funcs_t;
/*! Implementation of CdIo type */
struct _CdIo {
driver_id_t driver_id; /**< Particular driver opened. */
cdio_funcs_t op; /**< driver-specific routines handling
implementation*/
void *env; /**< environment. Passed to routine above. */
};
/* 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_t * cdio_new (generic_img_private_t *p_env, cdio_funcs_t *p_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_t *(*driver_open) (const char *psz_source_name);
CdIo_t *(*driver_open_am) (const char *psz_source_name,
const char *psz_access_mode);
char *(*get_default_device) (void);
bool (*is_device) (const char *psz_source_name);
char **(*get_devices) (void);
driver_return_code_t (*close_tray) (const char *psz_device);
} 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 *psz_drive,
unsigned int *i_drives);
driver_return_code_t close_tray_bsdi (const char *psz_drive);
driver_return_code_t close_tray_freebsd (const char *psz_drive);
driver_return_code_t close_tray_linux (const char *psz_drive);
driver_return_code_t close_tray_netbsd (const char *psz_drive);
driver_return_code_t close_tray_osx (const char *psz_drive);
driver_return_code_t close_tray_solaris (const char *psz_drive);
driver_return_code_t close_tray_win32 (const char *psz_drive);
bool cdio_have_netbsd(void);
CdIo_t * cdio_open_netbsd (const char *psz_source);
char * cdio_get_default_device_netbsd(void);
char **cdio_get_devices_netbsd(void);
/*! Set up CD-ROM for reading using the NetBSD driver. The device_name is
the some sort of device name.
NULL is returned on error or there is no FreeBSD driver.
@see cdio_open_cd, cdio_open
*/
CdIo_t * cdio_open_am_netbsd (const char *psz_source,
const char *psz_access_mode);
/*! DEPRICATED: use cdio_have_driver().
True if AIX driver is available. */
bool cdio_have_aix (void);
/*! DEPRICATED: use cdio_have_driver().
True if BSDI driver is available. */
bool cdio_have_bsdi (void);
/*! DEPRICATED: use cdio_have_driver().
True if FreeBSD driver is available. */
bool cdio_have_freebsd (void);
/*! DEPRICATED: use cdio_have_driver().
True if GNU/Linux driver is available. */
bool cdio_have_linux (void);
/*! DEPRICATED: use cdio_have_driver().
True if Sun Solaris driver is available. */
bool cdio_have_solaris (void);
/*! DEPRICATED: use cdio_have_driver().
True if Apple OSX driver is available. */
bool cdio_have_osx (void);
/*! DEPRICATED: use cdio_have_driver().
True if Microsoft Windows driver is available. */
bool cdio_have_win32 (void);
/*! True if Nero driver is available. */
bool cdio_have_nrg (void);
/*! True if BIN/CUE driver is available. */
bool cdio_have_bincue (void);
/*! True if cdrdao CDRDAO driver is available. */
bool cdio_have_cdrdao (void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __CDIO_PRIVATE_H__ */

253
lib/driver/cdtext.c Normal file
View File

@@ -0,0 +1,253 @@
/*
$Id: cdtext.c,v 1.7 2008/06/16 22:41:44 flameeyes Exp $
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
toc reading routine adapted from cuetools
Copyright (C) 2003 Svend Sanjay Sorensen <ssorensen@fastmail.fm>
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cdio/cdtext.h>
#include <cdio/logging.h>
#include "cdtext_private.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
/*! Note: the order and number items (except CDTEXT_INVALID) should
match the cdtext_field_t enumeration. */
static const char cdtext_keywords[][16] =
{
"ARRANGER",
"COMPOSER",
"DISC_ID",
"GENRE",
"ISRC",
"MESSAGE",
"PERFORMER",
"SIZE_INFO",
"SONGWRITER",
"TITLE",
"TOC_INFO",
"TOC_INFO2",
"UPC_EAN",
};
/*! Return string representation of the enum values above */
const char *
cdtext_field2str (cdtext_field_t i)
{
if (i >= MAX_CDTEXT_FIELDS)
return "Invalid CDTEXT field index";
else
return cdtext_keywords[i];
}
/*! Free memory assocated with cdtext*/
void
cdtext_destroy (cdtext_t *p_cdtext)
{
cdtext_field_t i;
if (!p_cdtext) return;
for (i=0; i < MAX_CDTEXT_FIELDS; i++) {
if (p_cdtext->field[i]) {
free(p_cdtext->field[i]);
p_cdtext->field[i] = NULL;
}
}
}
/*!
returns the CDTEXT value associated with key. NULL is returned
if key is CDTEXT_INVALID or the field is not set.
*/
char *
cdtext_get (cdtext_field_t key, const cdtext_t *p_cdtext)
{
if ((key == CDTEXT_INVALID) || (!p_cdtext->field[key])) return NULL;
return strdup(p_cdtext->field[key]);
}
const char *
cdtext_get_const (cdtext_field_t key, const cdtext_t *p_cdtext)
{
if (key == CDTEXT_INVALID) return NULL;
return p_cdtext->field[key];
}
/*! Initialize a new cdtext structure.
When the structure is no longer needed, release the
resources using cdtext_delete.
*/
void
cdtext_init (cdtext_t *p_cdtext)
{
cdtext_field_t i;
for (i=0; i < MAX_CDTEXT_FIELDS; i++) {
p_cdtext->field[i] = NULL;
}
}
/*!
returns 0 if field is a CD-TEXT keyword, returns non-zero otherwise
*/
cdtext_field_t
cdtext_is_keyword (const char *key)
{
#if 0
char *item;
item = bsearch(key,
cdtext_keywords, 12,
sizeof (char *),
(int (*)(const void *, const void *))
strcmp);
return (NULL != item) ? 0 : 1;
#else
unsigned int i;
for (i = 0; i < 13 ; i++)
if (0 == strcmp (cdtext_keywords[i], key)) {
return i;
}
return CDTEXT_INVALID;
#endif
}
/*! sets cdtext's keyword entry to field.
*/
void
cdtext_set (cdtext_field_t key, const char *p_value, cdtext_t *p_cdtext)
{
if (NULL == p_value || key == CDTEXT_INVALID) return;
if (p_cdtext->field[key]) free (p_cdtext->field[key]);
p_cdtext->field[key] = strdup (p_value);
}
#define SET_CDTEXT_FIELD(FIELD) \
(*set_cdtext_field_fn)(p_user_data, i_track, i_first_track, FIELD, buffer);
/*
parse all CD-TEXT data retrieved.
*/
bool
cdtext_data_init(void *p_user_data, track_t i_first_track,
unsigned char *wdata, int i_data,
set_cdtext_field_fn_t set_cdtext_field_fn)
{
CDText_data_t *p_data;
int i = -1;
int j;
char buffer[256];
int idx;
int i_track;
bool b_ret = false;
memset( buffer, 0x00, sizeof(buffer) );
idx = 0;
p_data = (CDText_data_t *) (&wdata[4]);
/* For reasons I don't understand - incorrect CDROM TOC reading?
we are off sometimes by 4.
*/
if( (p_data->type < 0x80) || (p_data->type > 0x85)
|| (p_data->block == 0) ) {
CDText_data_t *p_data_test = (CDText_data_t *) (&wdata[8]);
if( (p_data_test->type >= 0x80)
&& (p_data_test->type <= 0x85) && (p_data_test->block == 0) ) {
p_data = p_data_test;
i_data -= 4;
}
}
for( ; i_data > 0;
i_data -= sizeof(CDText_data_t), p_data++ ) {
#if TESTED
if ( p_data->bDBC ) {
cdio_warn("Double-byte characters not supported");
return false;
}
#endif
if( (p_data->type >= 0x80)
&& (p_data->type <= 0x85) && (p_data->block == 0) ) {
i_track = p_data->i_track;
i++;
if( p_data->seq != i ) break;
for( j=0; j < CDIO_CDTEXT_MAX_TEXT_DATA; j++ ) {
if( p_data->text[j] == 0x00 ) {
bool b_field_set=true;
switch( p_data->type) {
case CDIO_CDTEXT_TITLE:
SET_CDTEXT_FIELD(CDTEXT_TITLE);
break;
case CDIO_CDTEXT_PERFORMER:
SET_CDTEXT_FIELD(CDTEXT_PERFORMER);
break;
case CDIO_CDTEXT_SONGWRITER:
SET_CDTEXT_FIELD(CDTEXT_SONGWRITER);
break;
case CDIO_CDTEXT_COMPOSER:
SET_CDTEXT_FIELD(CDTEXT_COMPOSER);
break;
case CDIO_CDTEXT_ARRANGER:
SET_CDTEXT_FIELD(CDTEXT_ARRANGER);
break;
case CDIO_CDTEXT_MESSAGE:
SET_CDTEXT_FIELD(CDTEXT_MESSAGE);
break;
case CDIO_CDTEXT_DISCID:
SET_CDTEXT_FIELD(CDTEXT_DISCID);
break;
case CDIO_CDTEXT_GENRE:
SET_CDTEXT_FIELD(CDTEXT_GENRE);
break;
default : b_field_set = false;
}
if (b_field_set) {
b_ret = true;
i_track++;
idx = 0;
}
} else {
buffer[idx++] = p_data->text[j];
}
buffer[idx] = 0x00;
}
}
}
return b_ret;
}

139
lib/driver/cdtext_private.h Normal file
View File

@@ -0,0 +1,139 @@
/*
$Id: cdtext_private.h,v 1.3 2008/04/22 15:29:11 karl Exp $
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CDIO_CDTEXT_PRIVATE_H__
#define __CDIO_CDTEXT_PRIVATE_H__
#include <cdio/cdio.h>
#include <cdio/cdtext.h>
/*! An enumeration for some of the CDIO_CDTEXT_* #defines below. This isn't
really an enumeration one would really use in a program it is here
to be helpful in debuggers where wants just to refer to the
ISO_*_ names and get something.
*/
extern enum cdtext_enum1_s {
CDIO_CDTEXT_MAX_PACK_DATA = 255,
CDIO_CDTEXT_MAX_TEXT_DATA = 12,
CDIO_CDTEXT_TITLE = 0x80,
CDIO_CDTEXT_PERFORMER = 0x81,
CDIO_CDTEXT_SONGWRITER = 0x82,
CDIO_CDTEXT_COMPOSER = 0x83,
CDIO_CDTEXT_ARRANGER = 0x84,
CDIO_CDTEXT_MESSAGE = 0x85,
CDIO_CDTEXT_DISCID = 0x86,
CDIO_CDTEXT_GENRE = 0x87,
CDIO_CDTEXT_TOC = 0x88,
CDIO_CDTEXT_TOC2 = 0x89,
CDIO_CDTEXT_UPC = 0x8E,
CDIO_CDTEXT_BLOCKSIZE = 0x8F
} cdtext_enums1;
#define CDIO_CDTEXT_MAX_PACK_DATA 255
#define CDIO_CDTEXT_MAX_TEXT_DATA 12
/* From table J.2 - Pack Type Indicator Definitions from
Working Draft NCITS XXX T10/1364-D Revision 10G. November 12, 2001.
*/
/* Title of Alubm name (ID=0) or Track Titles (ID != 0) */
#define CDIO_CDTEXT_TITLE 0x80
/* Name(s) of the performer(s) in ASCII */
#define CDIO_CDTEXT_PERFORMER 0x81
/* Name(s) of the songwriter(s) in ASCII */
#define CDIO_CDTEXT_SONGWRITER 0x82
/* Name(s) of the Composers in ASCII */
#define CDIO_CDTEXT_COMPOSER 0x83
/* Name(s) of the Arrangers in ASCII */
#define CDIO_CDTEXT_ARRANGER 0x84
/* Message(s) from content provider and/or artist in ASCII */
#define CDIO_CDTEXT_MESSAGE 0x85
/* Disc Identificatin information */
#define CDIO_CDTEXT_DISCID 0x86
/* Genre Identification and Genre Information */
#define CDIO_CDTEXT_GENRE 0x87
/* Table of Content Information */
#define CDIO_CDTEXT_TOC 0x88
/* Second Table of Content Information */
#define CDIO_CDTEXT_TOC2 0x89
/* 0x8A, 0x8B, 0x8C are reserved
0x8D Reserved for content provider only.
*/
/* UPC/EAN code of the album and ISRC code of each track */
#define CDIO_CDTEXT_UPC 0x8E
/* Size information of the Block */
#define CDIO_CDTEXT_BLOCKSIZE 0x8F
PRAGMA_BEGIN_PACKED
struct CDText_data
{
uint8_t type;
track_t i_track;
uint8_t seq;
#ifdef WORDS_BIGENDIAN
uint8_t bDBC: 1; /* double byte character */
uint8_t block: 3; /* block number 0..7 */
uint8_t characterPosition:4; /* character position */
#else
uint8_t characterPosition:4; /* character position */
uint8_t block :3; /* block number 0..7 */
uint8_t bDBC :1; /* double byte character */
#endif
char text[CDIO_CDTEXT_MAX_TEXT_DATA];
uint8_t crc[2];
} GNUC_PACKED;
PRAGMA_END_PACKED
typedef struct CDText_data CDText_data_t;
typedef void (*set_cdtext_field_fn_t) (void *user_data, track_t i_track,
track_t i_first_track,
cdtext_field_t field,
const char *buffer);
/*
Internal routine to parse all CD-TEXT data retrieved.
*/
bool cdtext_data_init(void *user_data, track_t i_first_track,
unsigned char *wdata, int i_data,
set_cdtext_field_fn_t set_cdtext_field_fn);
#endif /* __CDIO_CDTEXT_PRIVATE_H__ */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

1038
lib/driver/device.c Normal file

File diff suppressed because it is too large Load Diff

119
lib/driver/disc.c Normal file
View File

@@ -0,0 +1,119 @@
/*
$Id: disc.c,v 1.6 2008/04/22 15:29:12 karl Exp $
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cdio/cdio.h>
#include "cdio_private.h"
/* Must match discmode enumeration */
const char *discmode2str[] = {
"CD-DA",
"CD-DATA (Mode 1)",
"CD DATA (Mode 2)",
"CD-ROM Mixed",
"DVD-ROM",
"DVD-RAM",
"DVD-R",
"DVD-RW",
"DVD+R",
"DVD+RW",
"Unknown/unclassified DVD",
"No information",
"Error in getting information",
"CD-i"
};
/*!
Get the size of the CD in logical block address (LBA) units.
@param p_cdio the CD object queried
@return the lsn. On error 0 or CDIO_INVALD_LSN.
*/
lsn_t
cdio_get_disc_last_lsn(const CdIo_t *p_cdio)
{
if (!p_cdio) return CDIO_INVALID_LSN;
return p_cdio->op.get_disc_last_lsn (p_cdio->env);
}
/*!
Get medium associated with cd_obj.
*/
discmode_t
cdio_get_discmode (CdIo_t *cd_obj)
{
if (!cd_obj) return CDIO_DISC_MODE_ERROR;
if (cd_obj->op.get_discmode) {
return cd_obj->op.get_discmode (cd_obj->env);
} else {
return CDIO_DISC_MODE_NO_INFO;
}
}
/*!
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_t *p_cdio)
{
if (p_cdio->op.get_mcn) {
return p_cdio->op.get_mcn (p_cdio->env);
} else {
return NULL;
}
}
bool
cdio_is_discmode_cdrom(discmode_t discmode)
{
switch (discmode) {
case CDIO_DISC_MODE_CD_DA:
case CDIO_DISC_MODE_CD_DATA:
case CDIO_DISC_MODE_CD_XA:
case CDIO_DISC_MODE_CD_MIXED:
case CDIO_DISC_MODE_NO_INFO:
return true;
default:
return false;
}
}
bool
cdio_is_discmode_dvd(discmode_t discmode)
{
switch (discmode) {
case CDIO_DISC_MODE_DVD_ROM:
case CDIO_DISC_MODE_DVD_RAM:
case CDIO_DISC_MODE_DVD_R:
case CDIO_DISC_MODE_DVD_RW:
case CDIO_DISC_MODE_DVD_PR:
case CDIO_DISC_MODE_DVD_PRW:
return true;
default:
return false;
}
}

251
lib/driver/ds.c Normal file
View File

@@ -0,0 +1,251 @@
/*
$Id: ds.c,v 1.4 2008/04/22 15:29:12 karl Exp $
Copyright (C) 2005, 2008 Rocky Bernstein <rocky@gnu.org>
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <cdio/ds.h>
#include <cdio/util.h>
#include <cdio/types.h>
#include "cdio_assert.h"
static const char _rcsid[] = "$Id: ds.c,v 1.4 2008/04/22 15:29:12 karl Exp $";
struct _CdioList
{
unsigned length;
CdioListNode_t *begin;
CdioListNode_t *end;
};
struct _CdioListNode
{
CdioList_t *list;
CdioListNode_t *next;
void *data;
};
/* impl */
CdioList_t *
_cdio_list_new (void)
{
CdioList_t *p_new_obj = calloc (1, sizeof (CdioList_t));
return p_new_obj;
}
void
_cdio_list_free (CdioList_t *p_list, int free_data)
{
while (_cdio_list_length (p_list))
_cdio_list_node_free (_cdio_list_begin (p_list), free_data);
free (p_list);
}
unsigned
_cdio_list_length (const CdioList_t *p_list)
{
cdio_assert (p_list != NULL);
return p_list->length;
}
void
_cdio_list_prepend (CdioList_t *p_list, void *p_data)
{
CdioListNode_t *p_new_node;
cdio_assert (p_list != NULL);
p_new_node = calloc (1, sizeof (CdioListNode_t));
p_new_node->list = p_list;
p_new_node->next = p_list->begin;
p_new_node->data = p_data;
p_list->begin = p_new_node;
if (p_list->length == 0)
p_list->end = p_new_node;
p_list->length++;
}
void
_cdio_list_append (CdioList_t *p_list, void *p_data)
{
cdio_assert (p_list != NULL);
if (p_list->length == 0)
{
_cdio_list_prepend (p_list, p_data);
}
else
{
CdioListNode_t *p_new_node = calloc (1, sizeof (CdioListNode_t));
p_new_node->list = p_list;
p_new_node->next = NULL;
p_new_node->data = p_data;
p_list->end->next = p_new_node;
p_list->end = p_new_node;
p_list->length++;
}
}
void
_cdio_list_foreach (CdioList_t *p_list, _cdio_list_iterfunc_t func,
void *p_user_data)
{
CdioListNode_t *node;
cdio_assert (p_list != NULL);
cdio_assert (func != 0);
for (node = _cdio_list_begin (p_list);
node != NULL;
node = _cdio_list_node_next (node))
func (_cdio_list_node_data (node), p_user_data);
}
CdioListNode_t *
_cdio_list_find (CdioList_t *p_list, _cdio_list_iterfunc_t cmp_func,
void *p_user_data)
{
CdioListNode_t *p_node;
cdio_assert (p_list != NULL);
cdio_assert (cmp_func != 0);
for (p_node = _cdio_list_begin (p_list);
p_node != NULL;
p_node = _cdio_list_node_next (p_node))
if (cmp_func (_cdio_list_node_data (p_node), p_user_data))
break;
return p_node;
}
CdioListNode_t *
_cdio_list_begin (const CdioList_t *p_list)
{
cdio_assert (p_list != NULL);
return p_list->begin;
}
CdioListNode_t *
_cdio_list_end (CdioList_t *p_list)
{
cdio_assert (p_list != NULL);
return p_list->end;
}
CdioListNode_t *
_cdio_list_node_next (CdioListNode_t *p_node)
{
if (p_node)
return p_node->next;
return NULL;
}
void
_cdio_list_node_free (CdioListNode_t *p_node, int free_data)
{
CdioList_t *p_list;
CdioListNode_t *prev_node;
cdio_assert (p_node != NULL);
p_list = p_node->list;
cdio_assert (_cdio_list_length (p_list) > 0);
if (free_data)
free (_cdio_list_node_data (p_node));
if (_cdio_list_length (p_list) == 1)
{
cdio_assert (p_list->begin == p_list->end);
p_list->end = p_list->begin = NULL;
p_list->length = 0;
free (p_node);
return;
}
cdio_assert (p_list->begin != p_list->end);
if (p_list->begin == p_node)
{
p_list->begin = p_node->next;
free (p_node);
p_list->length--;
return;
}
for (prev_node = p_list->begin; prev_node->next; prev_node = prev_node->next)
if (prev_node->next == p_node)
break;
cdio_assert (prev_node->next != NULL);
if (p_list->end == p_node)
p_list->end = prev_node;
prev_node->next = p_node->next;
p_list->length--;
free (p_node);
}
void *
_cdio_list_node_data (CdioListNode_t *p_node)
{
if (p_node)
return p_node->data;
return NULL;
}
/* eof */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

222
lib/driver/generic.h Normal file
View File

@@ -0,0 +1,222 @@
/*
$Id: generic.h,v 1.16 2008/04/22 15:29:12 karl Exp $
Copyright (C) 2004, 2005, 2006, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
/* Internal routines for CD I/O drivers. */
#ifndef __CDIO_GENERIC_H__
#define __CDIO_GENERIC_H__
#if defined(HAVE_CONFIG_H) && !defined(LIBCDIO_CONFIG_H)
# include "config.h"
#endif
#include <cdio/cdio.h>
#include <cdio/cdtext.h>
#include <cdio/iso9660.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/*!
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 if TOC read in */
bool b_cdtext_init; /**< True if CD-Text read in */
bool b_cdtext_error; /**< True if trouble reading CD-Text */
int ioctls_debugged; /**< for debugging */
/* Only one of data_source or fd is used; fd is for CD-ROM
devices and the data_source for stream reading (bincue, nrg, toc,
network).
*/
CdioDataSource_t *data_source;
int fd; /**< File descriptor of device */
track_t i_first_track; /**< The starting track number. */
track_t i_tracks; /**< The number of tracks. */
uint8_t i_joliet_level; /**< 0 = no Joliet extensions.
1-3: Joliet level. */
iso9660_pvd_t pvd;
iso9660_svd_t svd;
CdIo_t *cdio; /**< a way to call general cdio routines. */
cdtext_t cdtext; /**< CD-Text for disc. */
cdtext_t cdtext_track[CDIO_CD_MAX_TRACKS+1]; /**< CD-TEXT for each track*/
track_flags_t track_flags[CDIO_CD_MAX_TRACKS+1];
} generic_img_private_t;
/*!
Bogus eject media when there is no ejectable media, e.g. a disk image
We always return 2. Should we also free resources?
*/
driver_return_code_t cdio_generic_unimplemented_eject_media (void *p_env);
/*!
Set the blocksize for subsequent reads.
@return -2 since it's not implemented.
*/
driver_return_code_t
cdio_generic_unimplemented_set_blocksize (void *p_user_data,
uint16_t i_blocksize);
/*!
Set the drive speed.
@return -2 since it's not implemented.
*/
driver_return_code_t cdio_generic_unimplemented_set_speed (void *p_user_data,
int i_speed);
/*!
Release and free resources associated with cd.
*/
void cdio_generic_free (void *p_env);
/*!
Initialize CD device.
*/
bool cdio_generic_init (void *p_env, int open_mode);
/*!
Reads into buf the next size bytes.
Returns -1 on error.
Is in fact libc's read().
*/
off_t cdio_generic_lseek (void *p_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 *p_env, void *p_buf, size_t size);
/*!
Reads a single form1 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
int cdio_generic_read_form1_sector (void * user_data, void *data,
lsn_t lsn);
/*!
Release and free resources associated with stream or disk image.
*/
void cdio_generic_stdio_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);
/*!
Get cdtext information for a CdIo object .
@param obj the CD object that may contain CD-TEXT information.
@return the CD-TEXT object or NULL if obj is NULL
or CD-TEXT information does not exist.
*/
cdtext_t *get_cdtext_generic (void *p_user_data, track_t i_track);
/*!
Return the number of of the first track.
CDIO_INVALID_TRACK is returned on error.
*/
track_t get_first_track_num_generic(void *p_user_data);
/*!
Return the number of tracks in the current medium.
*/
track_t get_num_tracks_generic(void *p_user_data);
/*!
Get disc type associated with cd object.
*/
discmode_t get_discmode_generic (void *p_user_data );
/*!
Same as above but only handles CD cases
*/
discmode_t get_discmode_cd_generic (void *p_user_data );
/*! Return number of channels in track: 2 or 4; -2 if not
implemented or -1 for error.
Not meaningful if track is not an audio track.
*/
int get_track_channels_generic(const void *p_user_data, track_t i_track);
/*! Return 1 if copy is permitted on the track, 0 if not, or -1 for error.
Is this meaningful if not an audio track?
*/
track_flag_t get_track_copy_permit_generic(void *p_user_data,
track_t i_track);
/*! Return 1 if track has pre-emphasis, 0 if not, or -1 for error.
Is this meaningful if not an audio track?
pre-emphasis is a non linear frequency response.
*/
track_flag_t get_track_preemphasis_generic(const void *p_user_data,
track_t i_track);
void set_cdtext_field_generic(void *user_data, track_t i_track,
track_t i_first_track,
cdtext_field_t e_field, const char *psz_value);
/*!
Read cdtext information for a CdIo object .
return true on success, false on error or CD-Text information does
not exist.
*/
bool init_cdtext_generic (generic_img_private_t *p_env);
void set_track_flags(track_flags_t *p_track_flag, uint8_t flag);
/*! Read mode 1 or mode2 sectors (using cooked mode). */
driver_return_code_t read_data_sectors_generic (void *p_user_data,
void *p_buf, lsn_t i_lsn,
uint16_t i_blocksize,
uint32_t i_blocks);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __CDIO_GENERIC_H__ */

1671
lib/driver/gnu_linux.c Normal file

File diff suppressed because it is too large Load Diff

81
lib/driver/image.h Normal file
View File

@@ -0,0 +1,81 @@
/*
$Id: image.h,v 1.9 2008/04/22 15:29:12 karl Exp $
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
/*!
Header for image drivers. In contrast to image_common.h which contains
routines, this header like most C headers does not depend on anything
defined before it is included.
*/
#ifndef __CDIO_IMAGE_H__
#define __CDIO_IMAGE_H__
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cdio/types.h>
#include <cdio/cdtext.h>
#include "cdio_private.h"
#include <cdio/sector.h>
/*!
The universal format for information about a track for CD image readers
It may be that some fields can be derived from other fields.
Over time this structure may get cleaned up. Possibly this can be
expanded/reused for real CD formats.
*/
typedef struct {
track_t track_num; /**< Probably is index+1 */
msf_t start_msf;
lba_t start_lba;
int start_index;
lba_t pregap; /**< pre-gap */
lba_t silence; /**< pre-gap with zero audio data */
int sec_count; /**< Number of sectors in this track. Does not
include pregap */
int num_indices;
flag_t flags; /**< "[NO] COPY", "4CH", "[NO] PREMPAHSIS" */
char *isrc; /**< IRSC Code (5.22.4) exactly 12 bytes */
char *filename;
CdioDataSource_t *data_source;
off_t offset; /**< byte offset into data_start of track
beginning. In cdrdao for example, one
filename may cover many tracks and
each track would then have a different
offset.
*/
track_format_t track_format;
bool track_green;
cdtext_t cdtext; /**< CD-TEXT */
trackmode_t mode;
uint16_t datasize; /**< How much is in the portion we return
back? */
uint16_t datastart; /**< Offset from begining of frame
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;
#endif /* __CDIO_IMAGE_H__ */

21
lib/driver/image/Makefile Normal file
View File

@@ -0,0 +1,21 @@
# $Id: Makefile,v 1.2 2008/04/21 18:30:22 karl Exp $
#
# Copyright (C) 2004, 2008 Rocky Bernstein
# 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 3 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, see <http://www.gnu.org/licenses/>.
#
# The make is done above. This boilerplate Makefile just transfers the call
all install check clean:
cd .. && $(MAKE) $@

1217
lib/driver/image/bincue.c Normal file

File diff suppressed because it is too large Load Diff

1341
lib/driver/image/cdrdao.c Normal file

File diff suppressed because it is too large Load Diff

1352
lib/driver/image/nrg.c Normal file

File diff suppressed because it is too large Load Diff

155
lib/driver/image/nrg.h Normal file
View File

@@ -0,0 +1,155 @@
/*
$Id: nrg.h,v 1.7 2008/06/10 00:45:08 pjcreath Exp $
Copyright (C) 2004, 2006, 2008 Rocky Bernstein <rocky@gnu.org>
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 3 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, see <http://www.gnu.org/licenses/>.
*/
/* NERO (NRG) file format structures. */
/* 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 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;
} _footer_t;
typedef struct {
uint32_t start GNUC_PACKED;
uint32_t length GNUC_PACKED;
uint32_t type GNUC_PACKED; /* 0x0 -> MODE1, 0x2 -> MODE2 form1,
0x3 -> 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 32-bit 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; /* 0x0 -> MODE1, 0x2 -> MODE2 form1,
0x3 -> MIXED_MODE2 2336 blocksize
*/
uint32_t start_lsn GNUC_PACKED;
uint64_t _unknown GNUC_PACKED; /* wtf is this for? -- always zero... */
} _etn2_array_t;
typedef struct {
uint8_t type; /* has track copy bit and whether audiofile
or datafile. Is often 0x41 == 'A' */
uint8_t track; /* binary or BCD?? */
uint8_t addr_ctrl; /* addresstype: MSF or LBA in lower 4 bits
control in upper 4 bits.
makes 0->1 transitions */
uint8_t res; /* ?? */
uint32_t lsn GNUC_PACKED;
} _cuex_array_t;
/* New DAO[XI] Information from http://en.wikipedia.org/wiki/NRG_(file_format)
*/
typedef struct {
char psz_isrc[CDIO_ISRC_SIZE];
uint8_t unknown[6];
} _dao_array_common_t;
typedef struct {
_dao_array_common_t common;
uint64_t index0 GNUC_PACKED;
uint64_t index1 GNUC_PACKED;
uint64_t end_of_track GNUC_PACKED;
} _daox_array_t;
typedef struct {
_dao_array_common_t common;
uint32_t index0 GNUC_PACKED;
uint32_t index1 GNUC_PACKED;
uint32_t end_of_track GNUC_PACKED;
} _daoi_array_t;
typedef struct GNUC_PACKED {
uint32_t chunk_size_le GNUC_PACKED;
char psz_mcn[CDIO_MCN_SIZE];
uint8_t unknown[3];
uint8_t first_track;
uint8_t last_track;
} _dao_common_t;
typedef struct {
_dao_common_t common;
_daox_array_t track_info[EMPTY_ARRAY_SIZE];
} _daox_t;
typedef struct {
_dao_common_t common;
_daoi_array_t track_info[EMPTY_ARRAY_SIZE];
} _daoi_t;
typedef struct {
uint32_t id GNUC_PACKED;
uint32_t len GNUC_PACKED;
char data[EMPTY_ARRAY_SIZE];
} _chunk_t;
PRAGMA_END_PACKED
/* Nero images are Big Endian. */
typedef enum {
CDTX_ID = 0x43445458, /* CD TEXT */
CUEX_ID = 0x43554558, /* Nero version 5.5.x-6.x */
CUES_ID = 0x43554553, /* Nero pre version 5.5.x-6.x */
DAOX_ID = 0x44414f58, /* Nero version 5.5.x-6.x */
DAOI_ID = 0x44414f49,
END1_ID = 0x454e4421,
ETN2_ID = 0x45544e32,
ETNF_ID = 0x45544e46,
NER5_ID = 0x4e455235, /* Nero version 5.5.x */
NERO_ID = 0x4e45524f, /* Nero pre 5.5.x */
SINF_ID = 0x53494e46, /* Session information */
MTYP_ID = 0x4d545950, /* Disc Media type? */
} nero_id_t;
#define MTYP_AUDIO_CD 1 /* This isn't correct. But I don't know the
the right thing is and it sometimes works (and
sometimes is wrong). */
/* Disk track type Values gleaned from DAOX */
typedef enum {
DTYP_MODE1 = 0,
DTYP_MODE2_XA = 2,
DTYP_INVALID = 255
} nero_dtype_t;
/** The below variables are trickery to force the above enum symbol
values to be recorded in debug symbol tables. They are used to
allow one to refer to the enumeration value names in the typedefs
above in a debugger and debugger expressions.
*/
extern nero_id_t nero_id;
extern nero_dtype_t nero_dtype;

373
lib/driver/image_common.c Normal file
View File

@@ -0,0 +1,373 @@
/*
$Id: image_common.c,v 1.15 2008/04/22 15:29:12 karl Exp $
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
/*! Common image routines.
Because _img_private_t may vary over image formats, the routines are
included into the image drivers after _img_private_t is defined. In
order for the below routines to work, there is a large part of
_img_private_t that is common among image drivers. For example, see
image.h
*/
#include "image.h"
#include "image_common.h"
#include "_cdio_stdio.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
/*!
Eject media -- there's nothing to do here except free resources.
We always return DRIVER_OP_UNSUPPORTED.
*/
driver_return_code_t
_eject_media_image(void *p_user_data)
{
_free_image (p_user_data);
return DRIVER_OP_UNSUPPORTED;
}
/*!
We don't need the image any more. Free all memory associated with
it.
*/
void
_free_image (void *p_user_data)
{
_img_private_t *p_env = p_user_data;
track_t i_track;
if (NULL == p_env) return;
for (i_track=0; i_track < p_env->gen.i_tracks; i_track++) {
track_info_t *p_tocent = &(p_env->tocent[i_track]);
free_if_notnull(p_tocent->filename);
free_if_notnull(p_tocent->isrc);
cdtext_destroy(&(p_tocent->cdtext));
if (p_tocent->data_source) cdio_stdio_destroy(p_tocent->data_source);
}
free_if_notnull(p_env->psz_mcn);
free_if_notnull(p_env->psz_cue_name);
free_if_notnull(p_env->psz_access_mode);
cdtext_destroy(&(p_env->gen.cdtext));
cdio_generic_stdio_free(p_env);
free(p_env);
}
/*!
Return the value associated with the key "arg".
*/
const char *
_get_arg_image (void *user_data, const char key[])
{
_img_private_t *p_env = user_data;
if (!strcmp (key, "source")) {
return p_env->gen.source_name;
} else if (!strcmp (key, "cue")) {
return p_env->psz_cue_name;
} else if (!strcmp(key, "access-mode")) {
return "image";
}
return NULL;
}
/*!
Get disc type associated with cd_obj.
*/
discmode_t
_get_discmode_image (void *p_user_data)
{
_img_private_t *p_env = p_user_data;
return p_env->disc_mode;
}
/*!
Return the the kind of drive capabilities of device.
*/
void
_get_drive_cap_image (const void *user_data,
cdio_drive_read_cap_t *p_read_cap,
cdio_drive_write_cap_t *p_write_cap,
cdio_drive_misc_cap_t *p_misc_cap)
{
*p_read_cap = CDIO_DRIVE_CAP_READ_CD_DA
| CDIO_DRIVE_CAP_READ_CD_G
| CDIO_DRIVE_CAP_READ_CD_R
| CDIO_DRIVE_CAP_READ_CD_RW
| CDIO_DRIVE_CAP_READ_MODE2_FORM1
| CDIO_DRIVE_CAP_READ_MODE2_FORM2
| CDIO_DRIVE_CAP_READ_MCN
;
*p_write_cap = 0;
/* In the future we may want to simulate
LOCK, OPEN_TRAY, CLOSE_TRAY, SELECT_SPEED, etc.
*/
*p_misc_cap = CDIO_DRIVE_CAP_MISC_FILE;
}
/*!
Return the number of of the first track.
CDIO_INVALID_TRACK is returned on error.
*/
track_t
_get_first_track_num_image(void *p_user_data)
{
_img_private_t *p_env = p_user_data;
return p_env->gen.i_first_track;
}
/*!
Find out if media has changed since the last call.
@param p_user_data the CD object to be acted upon.
@return 1 if media has changed since last call, 0 if not. Error
return codes are the same as driver_return_code_t
There is no such thing as changing a media image so we will
always return 0 - no change.
*/
int
get_media_changed_image(const void *p_user_data)
{
return 0;
}
/*!
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 *
_get_mcn_image(const void *p_user_data)
{
const _img_private_t *p_env = p_user_data;
if (!p_env || !p_env->psz_mcn) return NULL;
return strdup(p_env->psz_mcn);
}
/*!
Return the number of tracks.
*/
track_t
_get_num_tracks_image(void *p_user_data)
{
_img_private_t *p_env = p_user_data;
return p_env->gen.i_tracks;
}
/*!
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.
*/
bool
_get_track_msf_image(void *p_user_data, track_t i_track, msf_t *msf)
{
const _img_private_t *p_env = p_user_data;
if (NULL == msf) return false;
if (i_track == CDIO_CDROM_LEADOUT_TRACK) i_track = p_env->gen.i_tracks+1;
if (i_track <= p_env->gen.i_tracks+1 && i_track != 0) {
*msf = p_env->tocent[i_track-p_env->gen.i_first_track].start_msf;
return true;
} else
return false;
}
/*! Return number of channels in track: 2 or 4; -2 if not
implemented or -1 for error.
Not meaningful if track is not an audio track.
*/
int
get_track_channels_image(const void *p_user_data, track_t i_track)
{
const _img_private_t *p_env = p_user_data;
return ( p_env->tocent[i_track-p_env->gen.i_first_track].flags
& FOUR_CHANNEL_AUDIO ) ? 4 : 2;
}
/*! Return 1 if copy is permitted on the track, 0 if not, or -1 for error.
Is this meaningful if not an audio track?
*/
track_flag_t
get_track_copy_permit_image(void *p_user_data, track_t i_track)
{
const _img_private_t *p_env = p_user_data;
return ( p_env->tocent[i_track-p_env->gen.i_first_track].flags
& COPY_PERMITTED ) ? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE;
}
/*! Return 1 if track has pre-emphasis, 0 if not, or -1 for error.
Is this meaningful if not an audio track?
pre-emphasis is a non linear frequency response.
*/
track_flag_t
get_track_preemphasis_image(const void *p_user_data, track_t i_track)
{
const _img_private_t *p_env = p_user_data;
return ( p_env->tocent[i_track-p_env->gen.i_first_track].flags
& PRE_EMPHASIS ) ? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE;
}
/*! Return the starting LBA for the pregap for track number i_track.
Track numbers start at 1.
CDIO_INVALID_LBA is returned on error.
*/
lba_t
get_track_pregap_lba_image(const void *p_user_data, track_t i_track)
{
const _img_private_t *p_env = p_user_data;
lba_t pregap, start_lba;
pregap = p_env->tocent[i_track-p_env->gen.i_first_track].pregap;
start_lba = p_env->tocent[i_track-p_env->gen.i_first_track].start_lba;
/* avoid initializing pregap to CDIO_INVALID_LBA by letting calloc
do the work. also, nero files have the pregap set equal
to the start of the track when there is no pregap
*/
if (!pregap || pregap == start_lba) {
pregap = CDIO_INVALID_LBA;
}
return pregap;
}
/*!
Return the International Standard Recording Code (ISRC) for track number
i_track in p_cdio. Track numbers start at 1.
Note: string is malloc'd so caller has to free() the returned
string when done with it.
*/
char *
get_track_isrc_image(const void *p_user_data, track_t i_track)
{
const _img_private_t *p_env = p_user_data;
char *isrc = p_env->tocent[i_track-p_env->gen.i_first_track].isrc;
if (isrc && isrc[0]) {
return strdup(isrc);
} else {
return NULL;
}
}
/*!
Read a data sector
@param p_cdio object to read from
@param p_buf place to read data into. The caller should make sure
this location can store at least ISO_BLOCKSIZE, M2RAW_SECTOR_SIZE,
or M2F2_SECTOR_SIZE depending on the kind of sector getting read. If
you don't know whether you have a Mode 1/2, Form 1/ Form 2/Formless
sector best to reserve space for the maximum, M2RAW_SECTOR_SIZE.
@param i_lsn sector to read
@param i_blocksize size of block. Should be either ISO_BLOCKSIZE
M2RAW_SECTOR_SIZE, or M2F2_SECTOR_SIZE. See comment above under
p_buf.
*/
driver_return_code_t
read_data_sectors_image ( void *p_user_data, void *p_buf,
lsn_t i_lsn, uint16_t i_blocksize,
uint32_t i_blocks )
{
const _img_private_t *p_env = p_user_data;
if (!p_env || !p_env->gen.cdio) return DRIVER_OP_UNINIT;
{
CdIo_t *p_cdio = p_env->gen.cdio;
track_t i_track = cdio_get_track(p_cdio, i_lsn);
track_format_t e_track_format = cdio_get_track_format(p_cdio, i_track);
switch(e_track_format) {
case TRACK_FORMAT_PSX:
case TRACK_FORMAT_AUDIO:
case TRACK_FORMAT_ERROR:
return DRIVER_OP_ERROR;
case TRACK_FORMAT_DATA:
return cdio_read_mode1_sectors (p_cdio, p_buf, i_lsn, false, i_blocks);
case TRACK_FORMAT_CDI:
case TRACK_FORMAT_XA:
return cdio_read_mode2_sectors (p_cdio, p_buf, i_lsn, false, i_blocks);
}
}
return DRIVER_OP_ERROR;
}
/*!
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.
*/
driver_return_code_t
_set_arg_image (void *p_user_data, const char key[], const char value[])
{
_img_private_t *p_env = p_user_data;
if (!strcmp (key, "source"))
{
free_if_notnull (p_env->gen.source_name);
if (!value) return DRIVER_OP_ERROR;
p_env->gen.source_name = strdup (value);
}
else if (!strcmp (key, "cue"))
{
free_if_notnull (p_env->psz_cue_name);
if (!value) return DRIVER_OP_ERROR;
p_env->psz_cue_name = strdup (value);
}
else if (!strcmp (key, "access-mode"))
{
free_if_notnull (p_env->psz_access_mode);
if (!value) return DRIVER_OP_ERROR;
p_env->psz_access_mode = strdup (value);
}
else
return DRIVER_OP_ERROR;
return DRIVER_OP_SUCCESS;
}

202
lib/driver/image_common.h Normal file
View File

@@ -0,0 +1,202 @@
/*
$Id: image_common.h,v 1.13 2008/04/22 15:29:12 karl Exp $
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
/*! Common image routines.
Because _img_private_t may vary over image formats, the routines are
included into the image drivers after _img_private_t is defined. In
order for the below routines to work, there is a large part of
_img_private_t that is common among image drivers. For example, see
image.h
*/
#ifndef __CDIO_IMAGE_COMMON_H__
#define __CDIO_IMAGE_COMMON_H__
typedef struct {
/* Things common to all drivers like this.
This must be first. */
generic_img_private_t gen;
internal_position_t pos;
char *psz_cue_name;
char *psz_access_mode; /* Just the name of the driver.
We add this for regularity with other
real CD drivers which has an access mode.
*/
char *psz_mcn; /* Media Catalog Number (5.22.3)
exactly 13 bytes */
track_info_t tocent[CDIO_CD_MAX_TRACKS+1]; /* entry info for each track
add 1 for leadout. */
discmode_t disc_mode;
#ifdef NEED_NERO_STRUCT
/* Nero Specific stuff. Note: for the image_free to work, this *must*
be last. */
bool is_dao; /* True if some of disk at once. False
if some sort of track at once. */
uint32_t mtyp; /* Value of MTYP (media type?) tag */
uint8_t dtyp; /* Value of DAOX media type tag */
/* This is a hack because I don't really understnad NERO better. */
bool is_cues;
CdioList_t *mapping; /* List of track information */
uint32_t size;
#endif
} _img_private_t;
#define free_if_notnull(p_obj) \
if (NULL != p_obj) { free(p_obj); p_obj=NULL; };
/*!
We don't need the image any more. Free all memory associated with
it.
*/
void _free_image (void *p_user_data);
int _eject_media_image(void *p_user_data);
/*!
Return the value associated with the key "arg".
*/
const char * _get_arg_image (void *user_data, const char key[]);
/*!
Get disc type associated with cd_obj.
*/
discmode_t _get_discmode_image (void *p_user_data);
/*!
Return the the kind of drive capabilities of device.
*/
void _get_drive_cap_image (const void *user_data,
cdio_drive_read_cap_t *p_read_cap,
cdio_drive_write_cap_t *p_write_cap,
cdio_drive_misc_cap_t *p_misc_cap);
/*!
Return the number of of the first track.
CDIO_INVALID_TRACK is returned on error.
*/
track_t _get_first_track_num_image(void *p_user_data);
/*!
Find out if media has changed since the last call.
@param p_user_data the CD object to be acted upon.
@return 1 if media has changed since last call, 0 if not. Error
return codes are the same as driver_return_code_t
We always return DRIVER_OP_UNSUPPORTED.
*/
int get_media_changed_image(const void *p_user_data);
/*!
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 * _get_mcn_image(const void *p_user_data);
/*!
Return the number of tracks.
*/
track_t _get_num_tracks_image(void *p_user_data);
/*!
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.
*/
bool _get_track_msf_image(void *p_user_data, track_t i_track, msf_t *msf);
/*! Return number of channels in track: 2 or 4; -2 if not
implemented or -1 for error.
Not meaningful if track is not an audio track.
*/
int get_track_channels_image(const void *p_user_data, track_t i_track);
/*! Return 1 if copy is permitted on the track, 0 if not, or -1 for error.
Is this meaningful if not an audio track?
*/
track_flag_t get_track_copy_permit_image(void *p_user_data, track_t i_track);
/*! Return 1 if track has pre-emphasis, 0 if not, or -1 for error.
Is this meaningful if not an audio track?
pre-emphasis is a non linear frequency response.
*/
track_flag_t get_track_preemphasis_image(const void *p_user_data,
track_t i_track);
/*! Return the starting LBA for the pregap for track number i_track.
Track numbers start at 1.
CDIO_INVALID_LBA is returned on error.
*/
lba_t get_track_pregap_lba_image(const void *p_user_data, track_t i_track);
/*!
Return the International Standard Recording Code (ISRC) for track number
i_track in p_cdio. Track numbers start at 1.
Note: string is malloc'd so caller has to free() the returned
string when done with it.
*/
char *get_track_isrc_image(const void *p_user_data, track_t i_track);
/*!
Read a data sector
@param p_cdio object to read from
@param p_buf place to read data into. The caller should make sure
this location can store at least ISO_BLOCKSIZE, M2RAW_SECTOR_SIZE,
or M2F2_SECTOR_SIZE depending on the kind of sector getting read. If
you don't know whether you have a Mode 1/2, Form 1/ Form 2/Formless
sector best to reserve space for the maximum, M2RAW_SECTOR_SIZE.
@param i_lsn sector to read
@param i_blocksize size of block. Should be either ISO_BLOCKSIZE
M2RAW_SECTOR_SIZE, or M2F2_SECTOR_SIZE. See comment above under
p_buf.
@param i_blocks number of blocks to read.
*/
driver_return_code_t
read_data_sectors_image ( void *p_user_data, void *p_buf,
lsn_t i_lsn, uint16_t i_blocksize,
uint32_t i_blocks );
/*!
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.
*/
int _set_arg_image (void *user_data, const char key[], const char value[]);
#endif /* __CDIO_IMAGE_COMMON_H__ */

220
lib/driver/libcdio.sym Normal file
View File

@@ -0,0 +1,220 @@
CDIO_SECTOR_SYNC_HEADER
_cdio_list_append
_cdio_list_begin
_cdio_list_end
_cdio_list_find
_cdio_list_foreach
_cdio_list_free
_cdio_list_length
_cdio_list_new
_cdio_list_node_data
_cdio_list_node_free
_cdio_list_node_next
_cdio_list_prepend
_cdio_malloc
_cdio_strfreev
_cdio_strsplit
cdio_audio_get_msf_seconds
cdio_audio_get_volume
cdio_audio_pause
cdio_audio_play_msf
cdio_audio_play_track_index
cdio_audio_read_subchannel
cdio_audio_resume
cdio_audio_set_volume
cdio_audio_stop
cdio_close_tray
cdio_debug
cdio_destroy
cdio_driver_describe
cdio_driver_errmsg
cdio_eject_media
cdio_eject_media_drive
cdio_error
cdio_free_device_list
cdio_from_bcd8
cdio_get_arg
cdio_get_cdtext
cdio_get_default_device
cdio_get_default_device_bincue
cdio_get_default_device_bsdi
cdio_get_default_device_cdrdao
cdio_get_default_device_driver
cdio_get_default_device_freebsd
cdio_get_default_device_linux
cdio_get_default_device_nrg
cdio_get_default_device_osx
cdio_get_default_device_solaris
cdio_get_default_device_win32
cdio_get_devices
cdio_get_devices_bincue
cdio_get_devices_bsdi
cdio_get_devices_cdrdao
cdio_get_devices_freebsd
cdio_get_devices_linux
cdio_get_devices_nrg
cdio_get_devices_osx
cdio_get_devices_ret
cdio_get_devices_solaris
cdio_get_devices_win32
cdio_get_devices_with_cap
cdio_get_devices_with_cap_ret
cdio_get_disc_last_lsn
cdio_get_discmode
cdio_get_drive_cap
cdio_get_drive_cap_dev
cdio_get_driver_id
cdio_get_driver_name
cdio_get_first_track_num
cdio_get_hwinfo
cdio_get_joliet_level
cdio_get_last_session
cdio_get_last_track_num
cdio_get_mcn
cdio_get_media_changed
cdio_get_num_tracks
cdio_get_track
cdio_get_track_channels
cdio_get_track_copy_permit
cdio_get_track_format
cdio_get_track_green
cdio_get_track_last_lsn
cdio_get_track_lba
cdio_get_track_pregap_lba
cdio_get_track_pregap_lsn
cdio_get_track_isrc
cdio_get_track_lsn
cdio_get_track_msf
cdio_get_track_preemphasis
cdio_get_track_sec_count
cdio_guess_cd_type
cdio_have_atapi
cdio_have_bincue
cdio_have_bsdi
cdio_have_cdrdao
cdio_have_driver
cdio_have_freebsd
cdio_have_linux
cdio_have_netbsd
cdio_have_nrg
cdio_have_osx
cdio_have_solaris
cdio_have_win32
cdio_info
cdio_init
cdio_is_binfile
cdio_is_cuefile
cdio_is_device
cdio_is_discmode_cdrom
cdio_is_discmode_dvd
cdio_is_nrg
cdio_is_tocfile
cdio_lba_to_lsn
cdio_lba_to_msf
cdio_lba_to_msf_str
cdio_log
cdio_log_set_handler
cdio_loglevel_default
cdio_lseek
cdio_lsn_to_lba
cdio_lsn_to_msf
cdio_msf_to_lba
cdio_msf_to_lsn
cdio_msf_to_str
cdio_open
cdio_open_am
cdio_open_am_bincue
cdio_open_am_bsdi
cdio_open_am_cd
cdio_open_am_cdrdao
cdio_open_am_freebsd
cdio_open_am_linux
cdio_open_am_netbsd
cdio_open_am_nrg
cdio_open_am_osx
cdio_open_am_solaris
cdio_open_am_win32
cdio_open_bincue
cdio_open_bsdi
cdio_open_cd
cdio_open_cdrdao
cdio_open_cue
cdio_open_freebsd
cdio_open_linux
cdio_open_netbsd
cdio_open_nrg
cdio_open_osx
cdio_open_solaris
cdio_open_win32
cdio_os_driver
cdio_read
cdio_read_audio_sector
cdio_read_audio_sectors
cdio_read_data_sectors
cdio_read_mode1_sector
cdio_read_mode1_sectors
cdio_read_mode2_sector
cdio_read_mode2_sectors
cdio_read_sector
cdio_read_sectors
cdio_set_arg
cdio_set_blocksize
cdio_set_drive_speed
cdio_set_speed
cdio_stdio_destroy
cdio_stdio_new
cdio_stream_getpos
cdio_stream_read
cdio_stream_seek
cdio_to_bcd8
cdio_warn
cdtext_destroy
cdtext_field2str
cdtext_get
cdtext_get_const
cdtext_init
cdtext_is_keyword
cdtext_set
debug_cdio_mmc_feature
debug_cdio_mmc_feature_interface
debug_cdio_mmc_feature_profile
debug_cdio_mmc_get_conf
debug_cdio_mmc_gpcmd
debug_cdio_mmc_read_sub_state
discmode2str
mmc_audio_read_subchannel
mmc_audio_state2str
mmc_close_tray
mmc_eject_media
mmc_feature2str
mmc_feature_profile2str
mmc_get_blocksize
mmc_get_cmd_len
mmc_get_discmode
mmc_get_drive_mmc_cap
mmc_get_dvd_struct_physical
mmc_get_hwinfo
mmc_get_last_lsn
mmc_get_mcn
mmc_get_media_changed
mmc_get_tray_status
mmc_have_interface
mmc_mode_sense
mmc_mode_sense_10
mmc_mode_sense_6
mmc_read_cd
mmc_read_data_sectors
mmc_read_sectors
mmc_read_timeout_ms
mmc_run_cmd
mmc_run_cmd_len
mmc_set_blocksize
mmc_set_speed
mmc_start_stop_media
mmc_timeout_ms
track_format2str
cdio_charset_converter_create
cdio_charset_converter_destroy
cdio_charset_convert
cdio_charset_from_utf8
cdio_charset_to_utf8

142
lib/driver/logging.c Normal file
View File

@@ -0,0 +1,142 @@
/*
$Id: logging.c,v 1.2 2008/04/22 15:29:12 karl Exp $
Copyright (C) 2003, 2004, 2008 Rocky Bernstein <rocky@gnu.org>
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#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"
#include "portable.h"
static const char _rcsid[] = "$Id: logging.c,v 1.2 2008/04/22 15:29:12 karl Exp $";
cdio_log_level_t 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:
*/

1468
lib/driver/mmc.c Normal file

File diff suppressed because it is too large Load Diff

155
lib/driver/mmc_private.h Normal file
View File

@@ -0,0 +1,155 @@
/* private MMC helper routines.
$Id: mmc_private.h,v 1.12 2008/04/22 15:29:12 karl Exp $
Copyright (C) 2004, 2005, 2006, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <cdio/mmc.h>
#include "cdtext_private.h"
/*! Convert milliseconds to seconds taking the ceiling value, i.e.
1002 milliseconds gets rounded to 2 seconds.
*/
#define SECS2MSECS 1000
static inline unsigned int
msecs2secs(unsigned int msecs)
{
return (msecs+(SECS2MSECS-1)) / SECS2MSECS;
}
#undef SECS2MSECS
/***********************************************************
MMC CdIo Operations which a driver may use.
These are not directly user-accessible.
************************************************************/
/*!
Read Audio Subchannel information
@param p_user_data the CD object to be acted upon.
*/
driver_return_code_t
audio_read_subchannel_mmc ( void *p_user_data,
cdio_subchannel_t *p_subchannel);
/*!
Get the block size for subsequest read requests, via a SCSI MMC
MODE_SENSE 6 command.
*/
int get_blocksize_mmc (void *p_user_data);
/*!
Get the lsn of the end of the CD
@return the lsn. On error return CDIO_INVALID_LSN.
*/
lsn_t get_disc_last_lsn_mmc( void *p_user_data );
void get_drive_cap_mmc (const void *p_user_data,
/*out*/ cdio_drive_read_cap_t *p_read_cap,
/*out*/ cdio_drive_write_cap_t *p_write_cap,
/*out*/ cdio_drive_misc_cap_t *p_misc_cap);
int get_media_changed_mmc (const void *p_user_data);
char *get_mcn_mmc (const void *p_user_data);
driver_return_code_t get_tray_status (const void *p_user_data);
/*! Read just the user data part of some sort of data sector (via
mmc_read_cd).
@param p_user_data object to read from
@param p_buf place to read data into. The caller should make sure
this location can store at least CDIO_CD_FRAMESIZE,
M2RAW_SECTOR_SIZE, or M2F2_SECTOR_SIZE depending on
the kind of sector getting read. If you don't know
whether you have a Mode 1/2, Form 1/ Form 2/Formless
sector best to reserve space for the maximum,
M2RAW_SECTOR_SIZE.
@param i_lsn sector to read
@param i_blocksize size of block. Should be either CDIO_CD_FRAMESIZE,
M2RAW_SECTOR_SIZE, or M2F2_SECTOR_SIZE. See comment above under p_buf.
*/
driver_return_code_t read_data_sectors_mmc ( void *p_user_data,
void *p_buf, lsn_t i_lsn,
uint16_t i_blocksize,
uint32_t i_blocks );
char *get_mcn_mmc (const void *p_user_data);
/* Set read blocksize (via MMC) */
driver_return_code_t set_blocksize_mmc (void *p_user_data,
uint16_t i_blocksize);
/* Set the drive speed in CD-ROM speed units (via MMC). */
driver_return_code_t set_drive_speed_mmc (void *p_user_data, int i_speed);
/* Set CD-ROM drive speed in K bytes per second. (via MMC) */
driver_return_code_t set_speed_mmc (void *p_user_data, int i_Kbs_speed);
/***********************************************************
Miscellaenous other "private" routines. Probably need
to better classify these.
************************************************************/
typedef driver_return_code_t (*mmc_run_cmd_fn_t)
( void *p_user_data,
unsigned int i_timeout_ms,
unsigned int i_cdb,
const mmc_cdb_t *p_cdb,
cdio_mmc_direction_t e_direction,
unsigned int i_buf, /*in/out*/ void *p_buf );
int mmc_set_blocksize_mmc_private ( const void *p_env, const
mmc_run_cmd_fn_t run_mmc_cmd,
uint16_t i_blocksize );
/*!
Get the DVD type associated with cd object.
*/
discmode_t
mmc_get_dvd_struct_physical_private ( void *p_env,
mmc_run_cmd_fn_t run_mmc_cmd,
cdio_dvd_struct_t *s );
char *mmc_get_mcn_private ( void *p_env,
mmc_run_cmd_fn_t run_mmc_cmd
);
bool mmc_init_cdtext_private ( void *p_user_data,
mmc_run_cmd_fn_t run_mmc_cmd,
set_cdtext_field_fn_t set_cdtext_field_fn
);
/*!
On input a MODE_SENSE command was issued and we have the results
in p. We interpret this and return a bit mask set according to the
capabilities.
*/
void mmc_get_drive_cap_buf(const uint8_t *p,
/*out*/ cdio_drive_read_cap_t *p_read_cap,
/*out*/ cdio_drive_write_cap_t *p_write_cap,
/*out*/ cdio_drive_misc_cap_t *p_misc_cap);
driver_return_code_t
mmc_set_blocksize_private ( void *p_env,
const mmc_run_cmd_fn_t run_mmc_cmd,
uint16_t i_blocksize);

656
lib/driver/netbsd.c Normal file
View File

@@ -0,0 +1,656 @@
/*
$Id: netbsd.c,v 1.4 2008/04/22 15:29:12 karl Exp $
Copyright (C) 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
/* Changes up to version 0.76 */
/*
* Copyright (c) 2003
* Matthias Drochner. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <cdio/sector.h>
#include <cdio/util.h>
#include "cdio_assert.h"
#include "cdio_private.h"
#ifdef __i386__
#define DEFAULT_CDIO_DEVICE "/dev/rcd0d"
#else
#define DEFAULT_CDIO_DEVICE "/dev/rcd0c"
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_NETBSD_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 <sys/cdio.h>
#include <sys/scsiio.h>
#define TOTAL_TRACKS (_obj->tochdr.ending_track \
- _obj->tochdr.starting_track + 1)
#define FIRST_TRACK_NUM (_obj->tochdr.starting_track)
typedef struct {
generic_img_private_t gen;
bool toc_valid;
struct ioc_toc_header tochdr;
struct cd_toc_entry tocent[100];
bool sessionformat_valid;
int sessionformat[100]; /* format of the session the track is in */
} _img_private_t;
static driver_return_code_t
run_scsi_cmd_netbsd(void *p_user_data, unsigned int i_timeout_ms,
unsigned int i_cdb, const mmc_cdb_t *p_cdb,
cdio_mmc_direction_t e_direction,
unsigned int i_buf, void *p_buf )
{
const _img_private_t *_obj = p_user_data;
scsireq_t req;
memset(&req, 0, sizeof(req));
memcpy(&req.cmd[0], p_cdb, i_cdb);
req.cmdlen = i_cdb;
req.datalen = i_buf;
req.databuf = p_buf;
req.timeout = i_timeout_ms;
req.flags = e_direction == SCSI_MMC_DATA_READ ? SCCMD_READ : SCCMD_WRITE;
if (ioctl(_obj->gen.fd, SCIOCCOMMAND, &req) < 0) {
perror("SCIOCCOMMAND");
return -1;
}
if (req.retsts != SCCMD_OK) {
fprintf(stderr, "SCIOCCOMMAND cmd 0x%02x sts %d\n", req.cmd[0], req.retsts);
return -1;
}
return 0;
}
static int
read_audio_sectors_netbsd(void *user_data, void *data, lsn_t lsn,
unsigned int nblocks)
{
scsireq_t req;
_img_private_t *_obj = user_data;
memset(&req, 0, sizeof(req));
req.cmd[0] = 0xbe;
req.cmd[1] = 0;
req.cmd[2] = (lsn >> 24) & 0xff;
req.cmd[3] = (lsn >> 16) & 0xff;
req.cmd[4] = (lsn >> 8) & 0xff;
req.cmd[5] = (lsn >> 0) & 0xff;
req.cmd[6] = (nblocks >> 16) & 0xff;
req.cmd[7] = (nblocks >> 8) & 0xff;
req.cmd[8] = (nblocks >> 0) & 0xff;
req.cmd[9] = 0x78;
req.cmdlen = 10;
req.datalen = nblocks * CDIO_CD_FRAMESIZE_RAW;
req.databuf = data;
req.timeout = 10000;
req.flags = SCCMD_READ;
if (ioctl(_obj->gen.fd, SCIOCCOMMAND, &req) < 0) {
perror("SCIOCCOMMAND");
return 1;
}
if (req.retsts != SCCMD_OK) {
fprintf(stderr, "SCIOCCOMMAND cmd 0xbe sts %d\n", req.retsts);
return 1;
}
return 0;
}
static int
read_mode2_sector_netbsd(void *user_data, void *data, lsn_t lsn,
bool mode2_form2)
{
scsireq_t req;
_img_private_t *_obj = user_data;
char buf[M2RAW_SECTOR_SIZE] = { 0, };
memset(&req, 0, sizeof(req));
req.cmd[0] = 0xbe;
req.cmd[1] = 0;
req.cmd[2] = (lsn >> 24) & 0xff;
req.cmd[3] = (lsn >> 16) & 0xff;
req.cmd[4] = (lsn >> 8) & 0xff;
req.cmd[5] = (lsn >> 0) & 0xff;
req.cmd[6] = 0;
req.cmd[7] = 0;
req.cmd[8] = 1;
req.cmd[9] = 0x58; /* subheader + userdata + ECC */
req.cmdlen = 10;
req.datalen = M2RAW_SECTOR_SIZE;
req.databuf = buf;
req.timeout = 10000;
req.flags = SCCMD_READ;
if (ioctl(_obj->gen.fd, SCIOCCOMMAND, &req) < 0) {
perror("SCIOCCOMMAND");
return 1;
}
if (req.retsts != SCCMD_OK) {
fprintf(stderr, "SCIOCCOMMAND cmd 0xbe sts %d\n", req.retsts);
return 1;
}
if (mode2_form2)
memcpy(data, buf, M2RAW_SECTOR_SIZE);
else
memcpy(data, buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE);
return 0;
}
static int
read_mode2_sectors_netbsd(void *user_data, void *data, lsn_t lsn,
bool mode2_form2, unsigned int nblocks)
{
int i, res;
char *buf = data;
for (i = 0; i < nblocks; i++) {
res = read_mode2_sector_netbsd(user_data, buf, lsn, mode2_form2);
if (res)
return res;
buf += (mode2_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE);
lsn++;
}
return 0;
}
static int
set_arg_netbsd(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 if (!strcmp(key, "access-mode")) {
if (strcmp(value, "READ_CD"))
cdio_error("unknown access type: %s ignored.", value);
} else
return -1;
return 0;
}
static bool
_cdio_read_toc(_img_private_t *_obj)
{
int res;
struct ioc_read_toc_entry req;
res = ioctl(_obj->gen.fd, CDIOREADTOCHEADER, &_obj->tochdr);
if (res < 0) {
cdio_error("error in ioctl(CDIOREADTOCHEADER): %s\n",
strerror(errno));
return false;
}
req.address_format = CD_MSF_FORMAT;
req.starting_track = FIRST_TRACK_NUM;
req.data_len = (TOTAL_TRACKS + 1) /* leadout! */
* sizeof(struct cd_toc_entry);
req.data = _obj->tocent;
res = ioctl(_obj->gen.fd, CDIOREADTOCENTRIES, &req);
if (res < 0) {
cdio_error("error in ioctl(CDROMREADTOCENTRIES): %s\n",
strerror(errno));
return false;
}
_obj->toc_valid = 1;
return true;
}
static bool
read_toc_netbsd (void *p_user_data)
{
return _cdio_read_toc(p_user_data);
}
static int
_cdio_read_discinfo(_img_private_t *_obj)
{
scsireq_t req;
#define FULLTOCBUF (4 + 1000*11)
unsigned char buf[FULLTOCBUF] = { 0, };
int i, j;
memset(&req, 0, sizeof(req));
req.cmd[0] = 0x43; /* READ TOC/PMA/ATIP */
req.cmd[1] = 0x02;
req.cmd[2] = 0x02; /* full TOC */
req.cmd[3] = 0;
req.cmd[4] = 0;
req.cmd[5] = 0;
req.cmd[6] = 0;
req.cmd[7] = FULLTOCBUF / 256;
req.cmd[8] = FULLTOCBUF % 256;
req.cmd[9] = 0;
req.cmdlen = 10;
req.datalen = FULLTOCBUF;
req.databuf = buf;
req.timeout = 10000;
req.flags = SCCMD_READ;
if (ioctl(_obj->gen.fd, SCIOCCOMMAND, &req) < 0) {
perror("SCIOCCOMMAND");
return 1;
}
if (req.retsts != SCCMD_OK) {
fprintf(stderr, "SCIOCCOMMAND cmd 0x43 sts %d\n", req.retsts);
return 1;
}
#if 1
printf("discinfo:");
for (i = 0; i < 4; i++)
printf(" %02x", buf[i]);
printf("\n");
for (i = 0; i < buf[1] - 2; i++) {
printf(" %02x", buf[i + 4]);
if (!((i + 1) % 11))
printf("\n");
}
#endif
for (i = 4; i < req.datalen_used; i += 11) {
if (buf[i + 3] == 0xa0) { /* POINT */
/* XXX: assume entry 0xa1 follows */
for (j = buf[i + 8] - 1; j <= buf[i + 11 + 8] - 1; j++)
_obj->sessionformat[j] = buf[i + 9];
}
}
_obj->sessionformat_valid = true;
return 0;
}
static int
eject_media_netbsd(void *user_data) {
_img_private_t *_obj = user_data;
int fd, res, ret = 0;
fd = open(_obj->gen.source_name, O_RDONLY|O_NONBLOCK);
if (fd < 0)
return 2;
res = ioctl(fd, CDIOCALLOW);
if (res < 0) {
cdio_error("ioctl(fd, CDIOCALLOW) failed: %s\n",
strerror(errno));
/* go on... */
}
res = ioctl(fd, CDIOCEJECT);
if (res < 0) {
cdio_error("ioctl(CDIOCEJECT) failed: %s\n",
strerror(errno));
ret = 1;
}
return ret;
}
/*!
Return the value associated with the key "arg".
*/
static const char *
get_arg_netbsd(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")) {
return "READ_CD";
}
return NULL;
}
static track_t
get_first_track_num_netbsd(void *user_data)
{
_img_private_t *_obj = user_data;
int res;
if (!_obj->toc_valid) {
res = _cdio_read_toc(_obj);
if (!res)
return CDIO_INVALID_TRACK;
}
return FIRST_TRACK_NUM;
}
static track_t
get_num_tracks_netbsd(void *user_data)
{
_img_private_t *_obj = user_data;
int res;
if (!_obj->toc_valid) {
res = _cdio_read_toc(_obj);
if (!res)
return CDIO_INVALID_TRACK;
}
return TOTAL_TRACKS;
}
/*!
Get format of track.
*/
static track_format_t
get_track_format_netbsd(void *user_data, track_t track_num)
{
_img_private_t *_obj = user_data;
int res;
if (!_obj->toc_valid) {
res = _cdio_read_toc(_obj);
if (!res)
return CDIO_INVALID_TRACK;
}
if (track_num > TOTAL_TRACKS || track_num == 0)
return TRACK_FORMAT_ERROR;
if (_obj->tocent[track_num - 1].control & 0x04) {
if (!_obj->sessionformat_valid) {
res = _cdio_read_discinfo(_obj);
if (res)
return CDIO_INVALID_TRACK;
}
if (_obj->sessionformat[track_num - 1] == 0x10)
return TRACK_FORMAT_CDI;
else if (_obj->sessionformat[track_num - 1] == 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
get_track_green_netbsd(void *user_data, track_t track_num)
{
return (get_track_format_netbsd(user_data, track_num)
== TRACK_FORMAT_XA);
}
/*!
Return the starting MSF (minutes/secs/frames) for track number
track_num in obj. Track numbers usually start at something
greater than 0, usually 1.
The "leadout" track is specified either by
using i_track LEADOUT_TRACK or the total tracks+1.
False is returned if there is no track entry.
*/
static bool
get_track_msf_netbsd(void *user_data, track_t track_num, msf_t *msf)
{
_img_private_t *_obj = user_data;
int res;
if (!msf)
return false;
if (!_obj->toc_valid) {
res = _cdio_read_toc(_obj);
if (!res)
return CDIO_INVALID_TRACK;
}
if (track_num == CDIO_CDROM_LEADOUT_TRACK)
track_num = TOTAL_TRACKS + 1;
if (track_num > TOTAL_TRACKS + 1 || track_num == 0)
return false;
msf->m = cdio_to_bcd8(_obj->tocent[track_num - 1].addr.msf.minute);
msf->s = cdio_to_bcd8(_obj->tocent[track_num - 1].addr.msf.second);
msf->f = cdio_to_bcd8(_obj->tocent[track_num - 1].addr.msf.frame);
return true;
}
/*!
Return the size of the CD in logical block address (LBA) units.
@return the lsn. On error return CDIO_INVALID_LSN.
Also note that in one at least one test the corresponding MMC gives
a different answer, so there may be some disagreement about what is in
fact the last lsn.
*/
static lsn_t
get_disc_last_lsn_netbsd(void *user_data)
{
msf_t msf;
get_track_msf_netbsd(user_data, CDIO_CDROM_LEADOUT_TRACK, &msf);
return (((msf.m * 60) + msf.s) * CDIO_CD_FRAMES_PER_SEC + msf.f);
}
#endif /* HAVE_NETBSD_CDROM */
char **
cdio_get_devices_netbsd (void)
{
#ifndef HAVE_NETBSD_CDROM
return NULL;
#else
return NULL;
#endif /* HAVE_NETBSD_CDROM */
}
/*!
Return a string containing the default CD device.
*/
char *
cdio_get_default_device_netbsd()
{
return strdup(DEFAULT_CDIO_DEVICE);
}
/*!
Close tray on CD-ROM.
@param psz_device the CD-ROM drive to be closed.
*/
driver_return_code_t
close_tray_netbsd (const char *psz_device)
{
#ifdef HAVE_NETBSD_CDROM
return DRIVER_OP_UNSUPPORTED;
#else
return DRIVER_OP_NO_DRIVER;
#endif
}
#ifdef HAVE_NETBSD_CDROM
static cdio_funcs_t _funcs = {
.audio_read_subchannel = audio_read_subchannel_mmc,
.eject_media = eject_media_netbsd,
.free = cdio_generic_free,
.get_arg = get_arg_netbsd,
.get_blocksize = get_blocksize_mmc,
.get_cdtext = get_cdtext_generic,
.get_default_device = cdio_get_default_device_netbsd,
.get_devices = cdio_get_devices_netbsd,
.get_disc_last_lsn = get_disc_last_lsn_netbsd,
.get_discmode = get_discmode_generic,
.get_drive_cap = get_drive_cap_mmc,
.get_first_track_num = get_first_track_num_netbsd,
.get_hwinfo = NULL,
.get_mcn = get_mcn_mmc,
.get_num_tracks = get_num_tracks_netbsd,
.get_track_channels = get_track_channels_generic,
.get_track_copy_permit = get_track_copy_permit_generic,
.get_track_format = get_track_format_netbsd,
.get_track_green = get_track_green_netbsd,
.get_track_lba = NULL, /* This could be implemented if need be. */
.get_track_preemphasis = get_track_preemphasis_generic,
.get_track_msf = get_track_msf_netbsd,
.lseek = cdio_generic_lseek,
.read = cdio_generic_read,
.read_audio_sectors = read_audio_sectors_netbsd,
.read_data_sectors = read_data_sectors_generic,
.read_mode2_sector = read_mode2_sector_netbsd,
.read_mode2_sectors = read_mode2_sectors_netbsd,
.read_toc = read_toc_netbsd,
#if 1
.run_mmc_cmd = run_scsi_cmd_netbsd,
#endif
.set_arg = set_arg_netbsd,
};
#endif /*HAVE_NETBSD_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_t *
cdio_open_netbsd(const char *source_name)
{
#ifdef HAVE_NETBSD_CDROM
CdIo_t *ret;
_img_private_t *_data;
_data = calloc(1, sizeof(_img_private_t));
_data->gen.init = false;
_data->gen.fd = -1;
_data->toc_valid = false;
_data->sessionformat_valid = false;
set_arg_netbsd(_data, "source",
(source_name ? source_name : DEFAULT_CDIO_DEVICE));
if (source_name && !cdio_is_device_generic(source_name))
return (NULL);
ret = cdio_new(&_data->gen, &_funcs);
if (!ret)
return NULL;
if (cdio_generic_init(_data, O_RDONLY)) {
return ret;
} else {
cdio_generic_free(_data);
return NULL;
}
#else
return NULL;
#endif /* HAVE_BSDI_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_t *
cdio_open_am_netbsd(const char *source_name, const char *am)
{
return (cdio_open_netbsd(source_name));
}
bool
cdio_have_netbsd (void)
{
#ifdef HAVE_NETBSD_CDROM
return true;
#else
return false;
#endif /* HAVE_NETBSD_CDROM */
}
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

1979
lib/driver/osx.c Normal file

File diff suppressed because it is too large Load Diff

77
lib/driver/portable.h Normal file
View File

@@ -0,0 +1,77 @@
/*
$Id: portable.h,v 1.4 2008/04/22 15:29:12 karl Exp $
Copyright (C) 2006, 2008 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 3 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, see <http://www.gnu.org/licenses/>.
*/
/*
This file contains definitions to fill in for differences or
deficiencies to OS or compiler irregularities. If this file is
included other routines can be more portable.
*/
#ifndef __CDIO_PORTABLE_H__
#define __CDIO_PORTABLE_H__
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#if !defined(HAVE_FTRUNCATE)
# if defined ( WIN32 )
# define ftruncate chsize
# endif
#endif /*HAVE_FTRUNCATE*/
#if !defined(HAVE_SNPRINTF)
# if defined ( MSVC )
# define snprintf _snprintf
# endif
#endif /*HAVE_SNPRINTF*/
#if !defined(HAVE_VSNPRINTF)
# if defined ( MSVC )
# define snprintf _vsnprintf
# endif
#endif /*HAVE_SNPRINTF*/
#if !defined(HAVE_DRAND48) && defined(HAVE_RAND)
# define drand48() (rand() / (double)RAND_MAX)
#endif
#ifdef MSVC
# include <io.h>
# ifndef S_ISBLK
# define _S_IFBLK 0060000 /* Block Special */
# define S_ISBLK(x) (x & _S_IFBLK)
# endif
# ifndef S_ISCHR
# define _S_IFCHR 0020000 /* character special */
# define S_ISCHR(x) (x & _S_IFCHR)
# endif
#endif /*MSVC*/
#ifdef HAVE_MEMSET
# define BZERO(ptr, size) memset(ptr, 0, size)
#elif HAVE_BZERO
# define BZERO(ptr, size) bzero(ptr, size)
#else
#error You need either memset or bzero
#endif
#endif /* __CDIO_PORTABLE_H__ */

329
lib/driver/read.c Normal file
View File

@@ -0,0 +1,329 @@
/*
$Id: read.c,v 1.12 2008/04/22 15:29:12 karl Exp $
Copyright (C) 2005, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
*/
/** \file read.h
*
* \brief sector (block, frame)-related libcdio routines.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cdio/cdio.h>
#include <cdio/logging.h>
#include "cdio_private.h"
#include "cdio_assert.h"
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#define check_read_parms(p_cdio, p_buf, i_lsn) \
if (!p_cdio) return DRIVER_OP_UNINIT; \
if (!p_buf || CDIO_INVALID_LSN == i_lsn) \
return DRIVER_OP_ERROR;
#define check_lsn(i_lsn) \
check_read_parms(p_cdio, p_buf, i_lsn); \
{ \
lsn_t end_lsn = \
cdio_get_track_lsn(p_cdio, CDIO_CDROM_LEADOUT_TRACK); \
if ( i_lsn > end_lsn ) { \
cdio_info("Trying to access past end of disk lsn: %ld, end lsn: %ld", \
(long int) i_lsn, (long int) end_lsn); \
return DRIVER_OP_ERROR; \
} \
}
#define check_lsn_blocks(i_lsn, i_blocks) \
check_read_parms(p_cdio, p_buf, i_lsn); \
{ \
lsn_t end_lsn = \
cdio_get_track_lsn(p_cdio, CDIO_CDROM_LEADOUT_TRACK); \
if ( i_lsn > end_lsn ) { \
cdio_info("Trying to access past end of disk lsn: %ld, end lsn: %ld", \
(long int) i_lsn, (long int) end_lsn); \
return DRIVER_OP_ERROR; \
} \
/* Care is used in the expression below to be correct with */ \
/* respect to unsigned integers. */ \
if ( i_lsn + i_blocks > end_lsn + 1 ) { \
cdio_info("Request truncated to end disk; lsn: %ld, end lsn: %ld", \
(long int) i_lsn, (long int) end_lsn); \
i_blocks = end_lsn - i_lsn + 1; \
} \
}
/*!
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_t *p_cdio, off_t offset, int whence)
{
if (!p_cdio) return DRIVER_OP_UNINIT;
if (p_cdio->op.lseek)
return (p_cdio->op.lseek) (p_cdio->env, offset, whence);
return DRIVER_OP_UNSUPPORTED;
}
/*! Reads into buf the next size bytes. Similar to (if not the
same as) libc's read(). This is a "cooked" read, or one handled by
the OS. It probably won't work on audio data. For that use
cdio_read_audio_sector(s).
@param p_cdio object to read from
@param p_buf place to read data into. The caller should make sure
this location can store at least i_size bytes.
@param i_size number of bytes to read
@return (ssize_t) -1 on error.
*/
ssize_t
cdio_read (const CdIo_t *p_cdio, void *p_buf, size_t i_size)
{
if (!p_cdio) return DRIVER_OP_UNINIT;
if (p_cdio->op.read)
return (p_cdio->op.read) (p_cdio->env, p_buf, i_size);
return DRIVER_OP_UNSUPPORTED;
}
/*!
Reads an audio sector from cd device into data starting
from lsn. Returns DRIVER_OP_SUCCESS if no error.
*/
driver_return_code_t
cdio_read_audio_sector (const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn)
{
check_lsn(i_lsn);
if (p_cdio->op.read_audio_sectors)
return p_cdio->op.read_audio_sectors (p_cdio->env, p_buf, i_lsn, 1);
return DRIVER_OP_UNSUPPORTED;
}
/*!
Reads audio sectors from cd device into data starting
from lsn. Returns DRIVER_OP_SUCCESS if no error.
*/
driver_return_code_t
cdio_read_audio_sectors (const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn,
uint32_t i_blocks)
{
check_lsn_blocks(i_lsn, i_blocks);
if (0 == i_blocks) return DRIVER_OP_SUCCESS;
if (p_cdio->op.read_audio_sectors)
return (p_cdio->op.read_audio_sectors) (p_cdio->env, p_buf, i_lsn,
i_blocks);
return DRIVER_OP_UNSUPPORTED;
}
/*!
Reads an audio sector from cd device into data starting
from lsn. Returns DRIVER_OP_SUCCESS if no error.
*/
driver_return_code_t
cdio_read_data_sectors (const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn,
uint16_t i_blocksize, uint32_t i_blocks)
{
check_lsn(i_lsn);
if (0 == i_blocks) return DRIVER_OP_SUCCESS;
if (p_cdio->op.read_data_sectors)
return p_cdio->op.read_data_sectors (p_cdio->env, p_buf, i_lsn,
i_blocksize, i_blocks);
return DRIVER_OP_UNSUPPORTED;
}
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
/*!
Reads a single mode1 form1 or form2 sector from cd device
into data starting from lsn. Returns DRIVER_OP_SUCCESS if no error.
*/
driver_return_code_t
cdio_read_mode1_sector (const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn,
bool b_form2)
{
uint32_t size = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE ;
check_lsn(i_lsn);
if (p_cdio->op.read_mode1_sector) {
return p_cdio->op.read_mode1_sector(p_cdio->env, p_buf, i_lsn, b_form2);
} else if (p_cdio->op.lseek && p_cdio->op.read) {
char buf[CDIO_CD_FRAMESIZE] = { 0, };
if (0 > cdio_lseek(p_cdio, CDIO_CD_FRAMESIZE*i_lsn, SEEK_SET))
return -1;
if (0 > cdio_read(p_cdio, buf, CDIO_CD_FRAMESIZE))
return -1;
memcpy (p_buf, buf, size);
return DRIVER_OP_SUCCESS;
}
return DRIVER_OP_UNSUPPORTED;
}
/*!
Reads mode 1 sectors
@param p_cdio object to read from
@param buf place to read data into
@param lsn sector to read
@param b_form2 true for reading mode 1 form 2 sectors or false for
mode 1 form 1 sectors.
@param i_blocks number of sectors to read
*/
driver_return_code_t
cdio_read_mode1_sectors (const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn,
bool b_form2, uint32_t i_blocks)
{
check_lsn_blocks(i_lsn, i_blocks);
if (0 == i_blocks) return DRIVER_OP_SUCCESS;
if (p_cdio->op.read_mode1_sectors)
return (p_cdio->op.read_mode1_sectors) (p_cdio->env, p_buf, i_lsn, b_form2,
i_blocks);
return DRIVER_OP_UNSUPPORTED;
}
/*!
Reads a mode 2 sector
@param p_cdio object to read from
@param buf place to read data into
@param lsn sector to read
@param b_form2 true for reading mode 2 form 2 sectors or false for
mode 2 form 1 sectors.
*/
driver_return_code_t
cdio_read_mode2_sector (const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn,
bool b_form2)
{
check_lsn(i_lsn);
if (p_cdio->op.read_mode2_sector)
return p_cdio->op.read_mode2_sector (p_cdio->env, p_buf, i_lsn, b_form2);
/* fallback */
if (p_cdio->op.read_mode2_sectors != NULL)
return cdio_read_mode2_sectors (p_cdio, p_buf, i_lsn, b_form2, 1);
return DRIVER_OP_UNSUPPORTED;
}
/*!
Reads mode 2 sectors
@param p_cdio object to read from
@param buf place to read data into
@param lsn sector to read
@param b_form2 true for reading mode2 form 2 sectors or false for
mode 2 form 1 sectors.
@param i_blocks number of sectors to read
*/
driver_return_code_t
cdio_read_mode2_sectors (const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn,
bool b_form2, uint32_t i_blocks)
{
check_lsn_blocks(i_lsn, i_blocks);
if (0 == i_blocks) return DRIVER_OP_SUCCESS;
if (p_cdio->op.read_mode2_sectors)
return (p_cdio->op.read_mode2_sectors) (p_cdio->env, p_buf, i_lsn,
b_form2, i_blocks);
return DRIVER_OP_UNSUPPORTED;
}
/** The special case of reading a single block is a common one so we
provide a routine for that as a convenience.
*/
driver_return_code_t
cdio_read_sector(const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn,
cdio_read_mode_t read_mode)
{
return cdio_read_sectors(p_cdio, p_buf, i_lsn, read_mode, 1);
}
/*!
Reads a number of sectors (AKA blocks).
@param p_buf place to read data into. The caller should make sure
this location is large enough. See below for size information.
@param read_mode the kind of "mode" to use in reading.
@param i_lsn sector to read
@param i_blocks number of sectors to read
@return DRIVER_OP_SUCCESS (0) if no error, other (negative) enumerations
are returned on error.
If read_mode is CDIO_MODE_AUDIO,
*p_buf should hold at least CDIO_FRAMESIZE_RAW * i_blocks bytes.
If read_mode is CDIO_MODE_DATA,
*p_buf should hold at least i_blocks times either ISO_BLOCKSIZE,
M1RAW_SECTOR_SIZE or M2F2_SECTOR_SIZE depending on the kind of
sector getting read. If you don't know whether you have a Mode 1/2,
Form 1/ Form 2/Formless sector best to reserve space for the maximum
which is M2RAW_SECTOR_SIZE.
If read_mode is CDIO_MODE_M2F1,
*p_buf should hold at least M2RAW_SECTOR_SIZE * i_blocks bytes.
If read_mode is CDIO_MODE_M2F2,
*p_buf should hold at least CDIO_CD_FRAMESIZE * i_blocks bytes.
*/
driver_return_code_t
cdio_read_sectors(const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn,
cdio_read_mode_t read_mode, uint32_t i_blocks)
{
switch(read_mode) {
case CDIO_READ_MODE_AUDIO:
return cdio_read_audio_sectors (p_cdio, p_buf, i_lsn, i_blocks);
case CDIO_READ_MODE_M1F1:
return cdio_read_mode1_sectors (p_cdio, p_buf, i_lsn, false, i_blocks);
case CDIO_READ_MODE_M1F2:
return cdio_read_mode1_sectors (p_cdio, p_buf, i_lsn, true, i_blocks);
case CDIO_READ_MODE_M2F1:
return cdio_read_mode2_sectors (p_cdio, p_buf, i_lsn, false, i_blocks);
case CDIO_READ_MODE_M2F2:
return cdio_read_mode2_sectors (p_cdio, p_buf, i_lsn, true, i_blocks);
}
/* Can't happen. Just to shut up gcc. */
return DRIVER_OP_ERROR;
}
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

268
lib/driver/sector.c Normal file
View File

@@ -0,0 +1,268 @@
/*
$Id: sector.c,v 1.5 2005/02/06 04:20:25 rocky Exp $
Copyright (C) 2004, 2005 Rocky Bernstein <rocky@panix.com>
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/logging.h>
#include "cdio_assert.h"
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <ctype.h>
static const char _rcsid[] = "$Id: sector.c,v 1.5 2005/02/06 04:20:25 rocky Exp $";
/*! String of bytes used to identify the beginning of a Mode 1 or
Mode 2 sector. */
const uint8_t CDIO_SECTOR_SYNC_HEADER[CDIO_CD_SYNC_SIZE] =
{0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0};
/* Variables to hold debugger-helping enumerations */
enum cdio_cd_enums;
enum m2_sector_enums;
lba_t
cdio_lba_to_lsn (lba_t lba)
{
if (CDIO_INVALID_LBA == lba) return CDIO_INVALID_LSN;
return lba - CDIO_PREGAP_SECTORS;
}
/*
The below is adapted from cdparanoia code which claims it is
straight from the MMC3 spec.
*/
void
cdio_lsn_to_msf (lsn_t lsn, msf_t *msf)
{
int m, s, f;
cdio_assert (msf != 0);
if ( lsn >= -CDIO_PREGAP_SECTORS ){
m = (lsn + CDIO_PREGAP_SECTORS) / CDIO_CD_FRAMES_PER_MIN;
lsn -= m * CDIO_CD_FRAMES_PER_MIN;
s = (lsn + CDIO_PREGAP_SECTORS) / CDIO_CD_FRAMES_PER_SEC;
lsn -= s * CDIO_CD_FRAMES_PER_SEC;
f = lsn + CDIO_PREGAP_SECTORS;
} else {
m = (lsn + CDIO_CD_MAX_LSN) / CDIO_CD_FRAMES_PER_MIN;
lsn -= m * (CDIO_CD_FRAMES_PER_MIN);
s = (lsn+CDIO_CD_MAX_LSN) / CDIO_CD_FRAMES_PER_SEC;
lsn -= s * CDIO_CD_FRAMES_PER_SEC;
f = lsn + CDIO_CD_MAX_LSN;
}
if (m > 99) {
cdio_warn ("number of minutes (%d) truncated to 99.", m);
m = 99;
}
msf->m = cdio_to_bcd8 (m);
msf->s = cdio_to_bcd8 (s);
msf->f = cdio_to_bcd8 (f);
}
/*!
Convert an LBA into a string representation of the MSF.
\warning cdio_lba_to_msf_str returns new allocated string */
char *
cdio_lba_to_msf_str (lba_t lba)
{
if (CDIO_INVALID_LBA == lba) {
return strdup("*INVALID");
} else {
msf_t msf;
msf.m = msf.s = msf.f = 0;
cdio_lba_to_msf (lba, &msf);
return cdio_msf_to_str(&msf);
}
}
/*!
Convert an LSN into the corresponding LBA.
CDIO_INVALID_LBA is returned if there is an error.
*/
lba_t
cdio_lsn_to_lba (lsn_t lsn)
{
if (CDIO_INVALID_LSN == lsn) return CDIO_INVALID_LBA;
return lsn + CDIO_PREGAP_SECTORS;
}
/*!
Convert an LBA into the corresponding MSF.
*/
void
cdio_lba_to_msf (lba_t lba, msf_t *msf)
{
cdio_assert (msf != 0);
cdio_lsn_to_msf(cdio_lba_to_lsn(lba), msf);
}
/*!
Convert a MSF into the corresponding LBA.
CDIO_INVALID_LBA is returned if there is an error.
*/
lba_t
cdio_msf_to_lba (const msf_t *msf)
{
uint32_t lba = 0;
cdio_assert (msf != 0);
lba = cdio_from_bcd8 (msf->m);
lba *= CDIO_CD_SECS_PER_MIN;
lba += cdio_from_bcd8 (msf->s);
lba *= CDIO_CD_FRAMES_PER_SEC;
lba += cdio_from_bcd8 (msf->f);
return lba;
}
/*!
Convert a MSF into the corresponding LSN.
CDIO_INVALID_LSN is returned if there is an error.
*/
lba_t
cdio_msf_to_lsn (const msf_t *msf)
{
return cdio_lba_to_lsn(cdio_msf_to_lba (msf));
}
/*!
Convert an LBA into a string representation of the MSF.
\warning cdio_lba_to_msf_str returns new allocated string */
char *
cdio_msf_to_str (const msf_t *msf)
{
char buf[16];
snprintf (buf, sizeof (buf), "%2.2x:%2.2x:%2.2x", msf->m, msf->s, msf->f);
return strdup (buf);
}
/*!
Convert a MSF - broken out as 3 integer components into the
corresponding LBA.
CDIO_INVALID_LBA is returned if there is an error.
*/
lba_t
cdio_msf3_to_lba (unsigned int minutes, unsigned int seconds,
unsigned int frames)
{
return ((minutes * CDIO_CD_SECS_PER_MIN + seconds) * CDIO_CD_FRAMES_PER_SEC
+ frames);
}
/*!
Convert a string of the form MM:SS:FF into the corresponding LBA.
CDIO_INVALID_LBA is returned if there is an error.
*/
lba_t
cdio_mmssff_to_lba (const char *psz_mmssff)
{
int psz_field;
lba_t ret;
char c;
if (0 == strcmp (psz_mmssff, "0"))
return 0;
c = *psz_mmssff++;
if(c >= '0' && c <= '9')
psz_field = (c - '0');
else
return CDIO_INVALID_LBA;
while(':' != (c = *psz_mmssff++)) {
if(c >= '0' && c <= '9')
psz_field = psz_field * 10 + (c - '0');
else
return CDIO_INVALID_LBA;
}
ret = cdio_msf3_to_lba (psz_field, 0, 0);
c = *psz_mmssff++;
if(c >= '0' && c <= '9')
psz_field = (c - '0');
else
return CDIO_INVALID_LBA;
if(':' != (c = *psz_mmssff++)) {
if(c >= '0' && c <= '9') {
psz_field = psz_field * 10 + (c - '0');
c = *psz_mmssff++;
if(c != ':')
return CDIO_INVALID_LBA;
}
else
return CDIO_INVALID_LBA;
}
if(psz_field >= CDIO_CD_SECS_PER_MIN)
return CDIO_INVALID_LBA;
ret += cdio_msf3_to_lba (0, psz_field, 0);
c = *psz_mmssff++;
if (isdigit(c))
psz_field = (c - '0');
else
return -1;
if('\0' != (c = *psz_mmssff++)) {
if (isdigit(c)) {
psz_field = psz_field * 10 + (c - '0');
c = *psz_mmssff++;
}
else
return CDIO_INVALID_LBA;
}
if('\0' != c)
return CDIO_INVALID_LBA;
if(psz_field >= CDIO_CD_FRAMES_PER_SEC)
return CDIO_INVALID_LBA;
ret += psz_field;
return ret;
}
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

1174
lib/driver/solaris.c Normal file

File diff suppressed because it is too large Load Diff

361
lib/driver/track.c Normal file
View File

@@ -0,0 +1,361 @@
/*
$Id: track.c,v 1.7 2008/04/22 15:29:12 karl Exp $
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
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 3 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, see <http://www.gnu.org/licenses/>.
*/
/*! Track-related routines. */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cdio/cdio.h>
#include "cdio_private.h"
const char *track_format2str[6] =
{
"audio", "CD-i", "XA", "data", "PSX", "error"
};
/* Variables to hold debugger-helping enumerations */
enum cdio_track_enums;
/*!
Return the number of the first track.
CDIO_INVALID_TRACK is returned on error.
*/
track_t
cdio_get_first_track_num (const CdIo_t *p_cdio)
{
if (NULL == p_cdio) return CDIO_INVALID_TRACK;
if (p_cdio->op.get_first_track_num) {
return p_cdio->op.get_first_track_num (p_cdio->env);
} else {
return CDIO_INVALID_TRACK;
}
}
/*!
Return the last track number.
CDIO_INVALID_TRACK is returned on error.
*/
track_t
cdio_get_last_track_num (const CdIo_t *p_cdio)
{
if (NULL == p_cdio) return CDIO_INVALID_TRACK;
{
const track_t i_first_track = cdio_get_first_track_num(p_cdio);
if ( CDIO_INVALID_TRACK != i_first_track ) {
const track_t i_tracks = cdio_get_num_tracks(p_cdio);
if ( CDIO_INVALID_TRACK != i_tracks )
return i_first_track + i_tracks - 1;
}
return CDIO_INVALID_TRACK;
}
}
/*! Return number of channels in track: 2 or 4; -2 if not
implemented or -1 for error.
Not meaningful if track is not an audio track.
*/
int
cdio_get_track_channels(const CdIo_t *p_cdio, track_t i_track)
{
if (p_cdio->op.get_track_channels) {
return p_cdio->op.get_track_channels (p_cdio->env, i_track);
} else {
return -2;
}
}
/*! Return copy protection status on a track. Is this meaningful
if not an audio track?
*/
track_flag_t
cdio_get_track_copy_permit(const CdIo_t *p_cdio, track_t i_track)
{
if (p_cdio->op.get_track_copy_permit) {
return p_cdio->op.get_track_copy_permit (p_cdio->env, i_track);
} else {
return CDIO_TRACK_FLAG_UNKNOWN;
}
}
/*!
Get format of track.
*/
track_format_t
cdio_get_track_format(const CdIo_t *p_cdio, track_t i_track)
{
if (!p_cdio) return TRACK_FORMAT_ERROR;
if (p_cdio->op.get_track_format) {
return p_cdio->op.get_track_format (p_cdio->env, i_track);
} else {
return TRACK_FORMAT_ERROR;
}
}
/*!
Return the Joliet level recognized for p_cdio.
*/
uint8_t
cdio_get_joliet_level(const CdIo_t *p_cdio)
{
if (!p_cdio) return 0;
{
const generic_img_private_t *p_env
= (generic_img_private_t *) (p_cdio->env);
return p_env->i_joliet_level;
}
}
/*!
Return the number of tracks in the current medium.
CDIO_INVALID_TRACK is returned on error.
*/
track_t
cdio_get_num_tracks (const CdIo_t *p_cdio)
{
if (p_cdio == NULL) return CDIO_INVALID_TRACK;
if (p_cdio->op.get_num_tracks) {
return p_cdio->op.get_num_tracks (p_cdio->env);
} else {
return CDIO_INVALID_TRACK;
}
}
/*! Find the track which contans lsn.
CDIO_INVALID_TRACK is returned if the lsn outside of the CD or
if there was some error.
If the lsn is before the pregap of the first track 0 is returned.
Otherwise we return the track that spans the lsn.
*/
track_t
cdio_get_track(const CdIo_t *p_cdio, lsn_t lsn)
{
if (!p_cdio) return CDIO_INVALID_TRACK;
{
track_t i_low_track = cdio_get_first_track_num(p_cdio);
track_t i_high_track = cdio_get_last_track_num(p_cdio)+1; /* LEADOUT */
if (CDIO_INVALID_TRACK == i_low_track
|| CDIO_INVALID_TRACK == i_high_track ) return CDIO_INVALID_TRACK;
if (lsn < cdio_get_track_lsn(p_cdio, i_low_track))
return 0; /* We're in the pre-gap of first track */
if (lsn > cdio_get_track_lsn(p_cdio, i_high_track))
return CDIO_INVALID_TRACK; /* We're beyond the end. */
do {
const track_t i_mid = (i_low_track + i_high_track) / 2;
const lsn_t i_mid_lsn = cdio_get_track_lsn(p_cdio, i_mid);
if (lsn <= i_mid_lsn) i_high_track = i_mid - 1;
if (lsn >= i_mid_lsn) i_low_track = i_mid + 1;
} while ( i_low_track <= i_high_track );
return (i_low_track > i_high_track + 1)
? i_high_track + 1 : i_high_track;
}
}
/*!
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_t *p_cdio, track_t i_track)
{
if (p_cdio == NULL) {
return false;
}
if (p_cdio->op.get_track_green) {
return p_cdio->op.get_track_green (p_cdio->env, i_track);
} 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_t *p_cdio, track_t i_track)
{
if (!p_cdio) return CDIO_INVALID_LBA;
if (p_cdio->op.get_track_lba) {
return p_cdio->op.get_track_lba (p_cdio->env, i_track);
} else {
msf_t msf;
if (p_cdio->op.get_track_msf)
if (cdio_get_track_msf(p_cdio, i_track, &msf))
return cdio_msf_to_lba(&msf);
return CDIO_INVALID_LBA;
}
}
/*!
Return the starting LSN for track number
i_track in cdio. Tracks numbers start at 1.
The "leadout" track is specified either by
using i_track LEADOUT_TRACK or the total tracks+1.
CDIO_INVALID_LSN is returned on error.
*/
lsn_t
cdio_get_track_lsn(const CdIo_t *p_cdio, track_t i_track)
{
if (p_cdio == NULL) return CDIO_INVALID_LSN;
if (p_cdio->op.get_track_lba) {
return cdio_lba_to_lsn(p_cdio->op.get_track_lba (p_cdio->env, i_track));
} else {
msf_t msf;
if (cdio_get_track_msf(p_cdio, i_track, &msf))
return cdio_msf_to_lsn(&msf);
return CDIO_INVALID_LSN;
}
}
/*!
Return the International Standard Recording Code (ISRC) for track number
i_track in p_cdio. Track numbers start at 1.
Note: string is malloc'd so caller has to free() the returned
string when done with it.
*/
char *
cdio_get_track_isrc (const CdIo_t *p_cdio, track_t i_track)
{
if (p_cdio == NULL) return NULL;
if (p_cdio->op.get_track_isrc) {
return p_cdio->op.get_track_isrc (p_cdio->env, i_track);
} else {
return NULL;
}
}
/*!
Return the starting LBA for the pregap for track number
i_track in cdio. Track numbers start at 1.
CDIO_INVALID_LBA is returned on error.
*/
lba_t
cdio_get_track_pregap_lba(const CdIo_t *p_cdio, track_t i_track)
{
if (p_cdio == NULL) return CDIO_INVALID_LBA;
if (p_cdio->op.get_track_pregap_lba) {
return p_cdio->op.get_track_pregap_lba (p_cdio->env, i_track);
} else {
return CDIO_INVALID_LBA;
}
}
/*!
Return the starting LSN for the pregap for track number
i_track in cdio. Track numbers start at 1.
CDIO_INVALID_LSN is returned on error.
*/
lsn_t
cdio_get_track_pregap_lsn(const CdIo_t *p_cdio, track_t i_track)
{
return cdio_lba_to_lsn(cdio_get_track_pregap_lba(p_cdio, i_track));
}
/*!
Return the ending LSN for track number
i_track in cdio. CDIO_INVALID_LSN is returned on error.
*/
lsn_t
cdio_get_track_last_lsn(const CdIo_t *p_cdio, track_t i_track)
{
lsn_t lsn = cdio_get_track_lsn(p_cdio, i_track+1);
if (CDIO_INVALID_LSN == lsn) return CDIO_INVALID_LSN;
/* Safe, we've always the leadout. */
return lsn - 1;
}
/*!
Return the starting MSF (minutes/secs/frames) for track number
i_track in cdio. Track numbers start at 1.
The "leadout" track is specified either by
using i_track LEADOUT_TRACK or the total tracks+1.
False is returned if there is no track entry.
*/
bool
cdio_get_track_msf(const CdIo_t *p_cdio, track_t i_track, /*out*/ msf_t *msf)
{
if (!p_cdio) return false;
if (p_cdio->op.get_track_msf) {
return p_cdio->op.get_track_msf (p_cdio->env, i_track, msf);
} else if (p_cdio->op.get_track_lba) {
lba_t lba = p_cdio->op.get_track_lba (p_cdio->env, i_track);
if (lba == CDIO_INVALID_LBA) return false;
cdio_lba_to_msf(lba, msf);
return true;
} else {
return false;
}
}
/*! Return copy protection status on a track. Is this meaningful
if not an audio track?
*/
track_flag_t
cdio_get_track_preemphasis(const CdIo *p_cdio, track_t i_track)
{
if (p_cdio->op.get_track_preemphasis) {
return p_cdio->op.get_track_preemphasis (p_cdio->env, i_track);
} else {
return CDIO_TRACK_FLAG_UNKNOWN;
}
}
/*!
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_t *p_cdio, track_t i_track)
{
const track_t i_tracks = cdio_get_num_tracks(p_cdio);
if (i_track >=1 && i_track <= i_tracks)
return ( cdio_get_track_lba(p_cdio, i_track+1)
- cdio_get_track_lba(p_cdio, i_track) );
return 0;
}

210
lib/driver/utf8.c Normal file
View File

@@ -0,0 +1,210 @@
/*
$Id: utf8.c,v 1.5 2008/04/22 15:29:12 karl Exp $
Copyright (C) 2006, 2008 Burkhard Plaum <plaum@ipf.uni-stuttgart.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 3 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, see <http://www.gnu.org/licenses/>.
*/
/* UTF-8 support */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_JOLIET
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_ICONV
# include <iconv.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#include <cdio/utf8.h>
#include <stdio.h>
struct cdio_charset_coverter_s
{
iconv_t ic;
};
cdio_charset_coverter_t *
cdio_charset_converter_create(const char * src_charset,
const char * dst_charset)
{
cdio_charset_coverter_t * ret;
ret = calloc(1, sizeof(*ret));
ret->ic = iconv_open(dst_charset, src_charset);
return ret;
}
#if 0
static void bgav_hexdump(uint8_t * data, int len, int linebreak)
{
int i;
int bytes_written = 0;
int imax;
while(bytes_written < len)
{
imax = (bytes_written + linebreak > len) ? len - bytes_written : linebreak;
for(i = 0; i < imax; i++)
fprintf(stderr, "%02x ", data[bytes_written + i]);
for(i = imax; i < linebreak; i++)
fprintf(stderr, " ");
for(i = 0; i < imax; i++)
{
if(!(data[bytes_written + i] & 0x80) && (data[bytes_written + i] >= 32))
fprintf(stderr, "%c", data[bytes_written + i]);
else
fprintf(stderr, ".");
}
bytes_written += imax;
fprintf(stderr, "\n");
}
}
#endif
void cdio_charset_converter_destroy(cdio_charset_coverter_t*cnv)
{
iconv_close(cnv->ic);
free(cnv);
}
#define BYTES_INCREMENT 16
static bool
do_convert(iconv_t cd, char * src, int src_len,
char ** dst, int *dst_len)
{
char * ret;
char *inbuf;
char *outbuf;
int alloc_size;
int output_pos;
size_t inbytesleft;
size_t outbytesleft;
if(src_len < 0)
src_len = strlen(src);
#if 0
fprintf(stderr, "Converting:\n");
bgav_hexdump(src, src_len, 16);
#endif
alloc_size = src_len + BYTES_INCREMENT;
inbytesleft = src_len;
/* We reserve space here to add a final '\0' */
outbytesleft = alloc_size-1;
ret = malloc(alloc_size);
inbuf = src;
outbuf = ret;
while(1)
{
if(iconv(cd, &inbuf, &inbytesleft,
&outbuf, &outbytesleft) == (size_t)-1)
{
switch(errno)
{
case E2BIG:
output_pos = (int)(outbuf - ret);
alloc_size += BYTES_INCREMENT;
outbytesleft += BYTES_INCREMENT;
ret = realloc(ret, alloc_size);
if (ret == NULL)
{
fprintf(stderr, "Can't realloc(%d).\n", alloc_size);
return false;
}
outbuf = ret + output_pos;
break;
default:
fprintf(stderr, "Iconv failed: %s\n", strerror(errno));
if (ret != NULL)
free(ret);
return false;
break;
}
}
if(!inbytesleft)
break;
}
/* Zero terminate */
*outbuf = '\0';
/* Set return values */
*dst = ret;
if(dst_len)
*dst_len = (int)(outbuf - ret);
#if 0
fprintf(stderr, "Conversion done, src:\n");
bgav_hexdump(src, src_len, 16);
fprintf(stderr, "dst:\n");
bgav_hexdump((uint8_t*)(ret), (int)(outbuf - ret), 16);
#endif
return true;
}
bool cdio_charset_convert(cdio_charset_coverter_t*cnv,
char * src, int src_len,
char ** dst, int * dst_len)
{
return do_convert(cnv->ic, src, src_len, dst, dst_len);
}
bool cdio_charset_from_utf8(cdio_utf8_t * src, char ** dst,
int * dst_len, const char * dst_charset)
{
iconv_t ic;
bool result;
ic = iconv_open(dst_charset, "UTF-8");
result = do_convert(ic, src, -1, dst, dst_len);
iconv_close(ic);
return result;
}
bool cdio_charset_to_utf8(char *src, size_t src_len, cdio_utf8_t **dst,
const char * src_charset)
{
iconv_t ic;
bool result;
ic = iconv_open("UTF-8", src_charset);
result = do_convert(ic, src, src_len, dst, NULL);
iconv_close(ic);
return result;
}
#endif /* HAVE_JOLIET */

189
lib/driver/util.c Normal file
View File

@@ -0,0 +1,189 @@
/*
$Id: util.c,v 1.6 2008/04/22 15:29:12 karl Exp $
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#ifdef HAVE_UNISTD_H // readlink
#include <unistd.h>
#endif
#ifdef HAVE_INTTYPES_H
#include "inttypes.h"
#endif
#include "cdio_assert.h"
#include <cdio/types.h>
#include <cdio/util.h>
static const char _rcsid[] = "$Id: util.c,v 1.6 2008/04/22 15:29:12 karl 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_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 = calloc (1, sizeof (char *) * (n+1));
n = 0;
while((p = strtok(n ? NULL : _str, _delim)) != NULL)
strv[n++] = strdup(p);
free(_str);
return strv;
}
void *
_cdio_memdup (const void *mem, size_t count)
{
void *new_mem = NULL;
if (mem)
{
new_mem = calloc (1, 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
cdio_to_bcd8 (uint8_t n)
{
/*cdio_assert (n < 100);*/
return ((n/10)<<4) | (n%10);
}
uint8_t
cdio_from_bcd8(uint8_t p)
{
return (0xf & p)+(10*(p >> 4));
}
/*!
Follow symlinks until we have the real device file
(idea taken from libunieject).
*/
void cdio_follow_symlink (const char * src, char * dst) {
#ifdef HAVE_READLINK
char tmp_src[PATH_MAX+1];
char tmp_dst[PATH_MAX+1];
int len;
strcpy(tmp_src, src);
while(1) {
len = readlink(tmp_src, tmp_dst, PATH_MAX);
if(len < 0) {
strncpy(dst, tmp_src, PATH_MAX);
return;
}
else {
tmp_dst[len] = '\0';
strncpy(tmp_src, tmp_dst, PATH_MAX);
}
}
#else
strncpy(dst, src, PATH_MAX);
#endif
}
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

9
lib/iso9660/.cvsignore Normal file
View File

@@ -0,0 +1,9 @@
.deps
.libs
Makefile
Makefile.in
*.o
*.lo
*.la
*.la.ver

3
lib/iso9660/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/.deps
/Makefile
/Makefile.in

150
lib/iso9660/Makefile.am Normal file
View File

@@ -0,0 +1,150 @@
# $Id: Makefile.am,v 1.18 2008/10/20 01:25:15 rocky Exp $
#
# Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
# Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
########################################################
# Things to make the libiso9660 library
########################################################
#
# From libtool documentation amended with guidance from N. Boullis:
#
# 1. Start with version information of `0:0:0' for each libtool library.
#
# 2. It is probably not a good idea to update the version information
# several times between public releases, but rather once per public
# release. (This seems to be more an aesthetic consideration than
# a hard technical one.)
#
# 3. If the library source code has changed at all since the last
# update, then increment REVISION (`C:R:A' becomes `C:R+1:A').
#
# 4. If any interfaces have been added, removed, or changed since the
# last update, increment CURRENT, and set REVISION to 0.
#
# 5. If any interfaces have been added since the last public release,
# then increment AGE.
#
# 6. If any interfaces have been removed or changed since the last
# public release, then set AGE to 0. A changed interface means an
# incompatibility with previous versions.
libiso9660_la_CURRENT = 7
libiso9660_la_REVISION = 0
libiso9660_la_AGE = 0
EXTRA_DIST = libiso9660.sym
noinst_HEADERS = iso9660_private.h
lib_LTLIBRARIES = libiso9660.la
if ENABLE_ROCK
rock_src = rock.c
else
rock_src =
endif
libiso9660_la_SOURCES = \
iso9660.c \
iso9660_private.h \
iso9660_fs.c \
$(rock_src) \
xa.c
libiso9660_la_LIBADD = @LIBCDIO_LIBS@
libiso9660_la_ldflags = -version-info $(libiso9660_la_CURRENT):$(libiso9660_la_REVISION):$(libiso9660_la_AGE) @LT_NO_UNDEFINED@
libiso9660_la_dependencies = libcdio.la
INCLUDES = $(LIBCDIO_CFLAGS)
########################################################
# Things to version the symbols in the libraries
########################################################
# An explanation of the versioning problem from Nicolas Boullis and
# the versioned symbol solution he uses below...
#
# Currently, libvcdinfo uses the cdio_open function from libcdio.
# Let's imagine a program foobar that uses both the vcdinfo_open
# function from libvcdinfo and the cdio_open function from libcdio.
# Currently, libcdio has SONAME libcdio.so.0, libvcdinfo has SONAME
# libvcdinfo.so.0 and requires libcdio.so.0, and foobar requires both
# libvcdinfo.so.0 and libcdio.so.0. Everything looks fine.
#
# Now, for some reason, you decide to change the cdio_open function.
# That's your right, but you have to bump the CURRENT version and (if I
# understand it correctly, athough this is not that clear in libtool's
# documentation) set the AGE to 0. Anyway, this bumps the SONAME, which is
# sane since the interface changes incompatibly.
# Now, you have a new libcdio with SONAME libcdio.so.1. But libvcdinfo and
# foobar still require libcdio.so.0. Everything is still fine.
# Now, after some minor changes, the author of foobar recompiles foobar.
# Then, foobar now requires libvcdinfo.so.0 and libcdio.so.1. And foobar
# now segfaults...
# What is happening? When you run foobar, if brings both libvcdinfo.so.0
# and libcdio.so.1, but libvcdinfo.so.0 also brings libcdio.so.0. So you
# have both libcdio.so.0 and libcdio.so.1 that bring their symbols to the
# global namespace. Hence, you have to incompatible versions of the
# cdio_open function in the name space. When foobar calls cdio_open, it
# may choose the wrong function, and segfaults...
# With versioned symbols, the cdio_open function from libcdio.so.0 may be
# known as (something that looks like) cdio_open@@CDIO_0. An the cdio_open
# function from libcdio.so.1 as cdio_open@@CDIO_1. Both versions of
# libcdio would still be brought in by the most recent foobar, but foobar
# (and libvcdinfo) know which versioned function to use and then use the
# good one.
# This is some simple versioning where every symbol is versioned with
# something that looks like the SONAME of the library. More complex (and
# better) versioning is possible; it is for example what is used by glibc.
# But good complex versioning is something that requires much more
# work...
# The below is a impliments symbol versioning. First of all, I
# compute MAJOR as CURENT - AGE; that is what is used within libtool
# (at least on GNU/Linux systems) for the number in the SONAME. The
# nm command gives the list of symbols known in each of the object
# files that will be part of the shared library. And the sed command
# extracts from this list those symbols that will be shared. (This sed
# command comes from libtool.)
libiso9660_la_MAJOR = $(shell expr $(libiso9660_la_CURRENT) - $(libiso9660_la_AGE))
if BUILD_VERSIONED_LIBS
libiso9660_la_LDFLAGS = $(libiso9660_la_ldflags) -Wl,--version-script=libiso9660.la.ver
libiso9660_la_DEPENDENCIES = $(libcdio9660_la_dependencies) libiso9660.la.ver
libiso9660.la.ver: $(libiso9660_la_OBJECTS) $(srcdir)/libiso9660.sym
echo 'ISO9660_$(libiso9660_la_MAJOR) {' > $@
objs=`for obj in $(libiso9660_la_OBJECTS); do sed -ne "s/^pic_object='\(.*\)'$$/\1/p" $$obj; done`;
if test -n "$$objs" ; then \
nm $${objs} | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | { first=true; while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libiso9660.sym; then if test $$first = true; then echo " global:"; first=false; fi; echo " $${symbol};"; fi; done; } >> $@; \
nm $${objs} | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | { first=true; while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libiso9660.sym; then :; else if test $$first = true; then echo " local:"; first=false; fi; echo " $${symbol};"; fi; done; } >> $@; \
fi
echo '};' >> $@
MOSTLYCLEANFILES = libiso9660.la.ver
else
libiso9660_la_LDFLAGS = $(libiso9660_la_ldflags)
libiso9660_la_DEPENDENCIES = $(libcdio9660_la_dependencies)
endif

1241
lib/iso9660/iso9660.c Normal file

File diff suppressed because it is too large Load Diff

1567
lib/iso9660/iso9660_fs.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,83 @@
/*
$Id: iso9660_private.h,v 1.5 2008/04/18 16:02:09 karl Exp $
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#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
typedef struct iso_volume_descriptor_s {
uint8_t type; /**< 7.1.1 */
char id[5]; /**< "CD001" (ISO_STANDARD_ID) */
uint8_t version; /**< 7.1.1 */
char data[2041];
} GNUC_PACKED iso_volume_descriptor_t;
#define iso_volume_descriptor_t_SIZEOF ISO_BLOCKSIZE
#define iso9660_pvd_t_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. */
typedef struct iso_path_table_s {
uint8_t name_len; /**< 7.1.1 */
uint8_t xa_len; /**< 7.1.1 */
uint32_t extent; /**< 7.3.1/7.3.2 */
uint16_t parent; /**< 7.2.1/7.2.2 */
char name[EMPTY_ARRAY_SIZE];
} GNUC_PACKED iso_path_table_t;
#define iso_path_table_t_SIZEOF 8
#define iso9660_dir_t_SIZEOF 33
PRAGMA_END_PACKED
#endif /* __CDIO_ISO9660_PRIVATE_H__ */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,81 @@
iso_enums1
iso_extension_enums
iso_flag_enums
iso_vd_enums
iso_rock_enums
iso_rock_nm_flag
iso_rock_sl_flag
iso_rock_tf_flag
iso9660_close
iso9660_dir_add_entry_su
iso9660_dir_calc_record_size
iso9660_dir_init_new
iso9660_dir_init_new_su
iso9660_dir_to_name
iso9660_dirname_valid_p
iso9660_find_fs_lsn
iso9660_fs_find_lsn
iso9660_fs_find_lsn_with_path
iso9660_fs_read_pvd
iso9660_fs_read_superblock
iso9660_fs_readdir
iso9660_fs_stat
iso9660_fs_stat_translate
iso9660_get_application_id
iso9660_get_dir_len
iso9660_get_dtime
iso9660_get_ltime
iso9660_get_posix_filemode
iso9660_get_posix_filemode_from_rock
iso9660_get_posix_filemode_from_xa
iso9660_get_preparer_id
iso9660_get_publisher_id
iso9660_get_pvd_block_size
iso9660_get_pvd_id
iso9660_get_pvd_space_size
iso9660_get_pvd_type
iso9660_get_pvd_version
iso9660_get_rock_attr_str
iso9660_get_root_lsn
iso9660_get_system_id
iso9660_get_volume_id
iso9660_get_volumeset_id
iso9660_get_xa_attr_str
iso9660_ifs_find_lsn
iso9660_ifs_find_lsn_with_path
iso9660_ifs_fuzzy_read_superblock
iso9660_ifs_get_application_id
iso9660_ifs_get_joliet_level
iso9660_ifs_get_preparer_id
iso9660_ifs_get_publisher_id
iso9660_ifs_get_system_id
iso9660_ifs_get_volume_id
iso9660_ifs_get_volumeset_id
iso9660_ifs_is_xa
iso9660_ifs_read_pvd
iso9660_ifs_read_superblock
iso9660_ifs_readdir
iso9660_ifs_stat
iso9660_ifs_stat_translate
iso9660_is_achar
iso9660_is_dchar
iso9660_iso_seek_read
iso9660_name_translate
iso9660_name_translate_ext
iso9660_open
iso9660_open_ext
iso9660_open_fuzzy
iso9660_open_fuzzy_ext
iso9660_pathname_isofy
iso9660_pathname_valid_p
iso9660_pathtable_get_size
iso9660_pathtable_init
iso9660_pathtable_l_add_entry
iso9660_pathtable_m_add_entry
iso9660_set_dtime
iso9660_set_evd
iso9660_set_ltime
iso9660_set_pvd
iso9660_strncpy_pad
iso9660_xa_init
ISO_STANDARD_ID

619
lib/iso9660/rock.c Normal file
View File

@@ -0,0 +1,619 @@
/*
$Id: rock.c,v 1.18 2008/04/18 16:02:09 karl Exp $
Copyright (C) 2005, 2008 Rocky Bernstein <rocky@gnu.org>
Adapted from GNU/Linux fs/isofs/rock.c (C) 1992, 1993 Eric Youngdale
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 3 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, see <http://www.gnu.org/licenses/>.
*/
/* Rock Ridge Extensions to iso9660 */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <cdio/iso9660.h>
#include <cdio/logging.h>
#include <cdio/bytesex.h>
#define CDIO_MKDEV(ma,mi) ((ma)<<16 | (mi))
enum iso_rock_enums iso_rock_enums;
iso_rock_nm_flag_t iso_rock_nm_flag;
iso_rock_sl_flag_t iso_rock_sl_flag;
iso_rock_tf_flag_t iso_rock_tf_flag;
/* Our own realloc routine tailored for the iso9660_stat_t symlink
field. I can't figure out how to make realloc() work without
valgrind complaint.
*/
static bool
realloc_symlink(/*in/out*/ iso9660_stat_t *p_stat, uint8_t i_grow)
{
if (!p_stat->rr.i_symlink) {
const uint16_t i_max = 2*i_grow+1;
p_stat->rr.psz_symlink = (char *) calloc(1, i_max);
p_stat->rr.i_symlink_max = i_max;
return (NULL != p_stat->rr.psz_symlink);
} else {
unsigned int i_needed = p_stat->rr.i_symlink + i_grow ;
if ( i_needed <= p_stat->rr.i_symlink_max)
return true;
else {
char * psz_newsymlink = (char *) calloc(1, 2*i_needed);
if (!psz_newsymlink) return false;
p_stat->rr.i_symlink_max = 2*i_needed;
memcpy(psz_newsymlink, p_stat->rr.psz_symlink, p_stat->rr.i_symlink);
free(p_stat->rr.psz_symlink);
p_stat->rr.psz_symlink = psz_newsymlink;
return true;
}
}
}
/* These functions are designed to read the system areas of a directory record
* and extract relevant information. There are different functions provided
* depending upon what information we need at the time. One function fills
* out an inode structure, a second one extracts a filename, a third one
* returns a symbolic link name, and a fourth one returns the extent number
* for the file. */
#define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */
/* This is a way of ensuring that we have something in the system
use fields that is compatible with Rock Ridge */
#define CHECK_SP(FAIL) \
if(rr->u.SP.magic[0] != 0xbe) FAIL; \
if(rr->u.SP.magic[1] != 0xef) FAIL; \
p_stat->rr.s_rock_offset = rr->u.SP.skip;
/* We define a series of macros because each function must do exactly the
same thing in certain places. We use the macros to ensure that everything
is done correctly */
#define CONTINUE_DECLS \
int cont_extent = 0, cont_offset = 0, cont_size = 0; \
void *buffer = NULL
#define CHECK_CE \
{ cont_extent = from_733(*rr->u.CE.extent); \
cont_offset = from_733(*rr->u.CE.offset); \
cont_size = from_733(*rr->u.CE.size); }
#define SETUP_ROCK_RIDGE(DE,CHR,LEN) \
{ \
LEN= sizeof(iso9660_dir_t) + DE->filename_len; \
if(LEN & 1) LEN++; \
CHR = ((unsigned char *) DE) + LEN; \
LEN = *((unsigned char *) DE) - LEN; \
if (0xff != p_stat->rr.s_rock_offset) \
{ \
LEN -= p_stat->rr.s_rock_offset; \
CHR += p_stat->rr.s_rock_offset; \
if (LEN<0) LEN=0; \
} \
}
/* Copy a long or short time from the iso_rock_tf_t into
the specified field of a iso_rock_statbuf_t.
non-paramater variables are p_stat, rr, and cnt.
*/
#define add_time(FLAG, TIME_FIELD) \
if (rr->u.TF.flags & FLAG) { \
p_stat->rr.TIME_FIELD.b_used = true; \
p_stat->rr.TIME_FIELD.b_longdate = \
(0 != (rr->u.TF.flags & ISO_ROCK_TF_LONG_FORM)); \
if (p_stat->rr.TIME_FIELD.b_longdate) { \
memcpy(&(p_stat->rr.TIME_FIELD.t.ltime), \
&(rr->u.TF.time_bytes[cnt]), \
sizeof(iso9660_ltime_t)); \
cnt += sizeof(iso9660_ltime_t); \
} else { \
memcpy(&(p_stat->rr.TIME_FIELD.t.dtime), \
&(rr->u.TF.time_bytes[cnt]), \
sizeof(iso9660_dtime_t)); \
cnt += sizeof(iso9660_dtime_t); \
} \
}
/*!
Get
@return length of name field; 0: not found, -1: to be ignored
*/
int
get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir,
/*out*/ char * psz_name,
/*in/out*/ iso9660_stat_t *p_stat)
{
int len;
unsigned char *chr;
int symlink_len = 0;
CONTINUE_DECLS;
int i_namelen = 0;
int truncate=0;
if (!p_stat || nope == p_stat->rr.b3_rock) return 0;
*psz_name = 0;
SETUP_ROCK_RIDGE(p_iso9660_dir, chr, len);
/*repeat:*/
{
iso_extension_record_t * rr;
int sig;
int rootflag;
while (len > 1){ /* There may be one byte for padding somewhere */
rr = (iso_extension_record_t *) chr;
if (rr->len == 0) goto out; /* Something got screwed up here */
sig = *chr+(*(chr+1) << 8);
chr += rr->len;
len -= rr->len;
switch(sig){
case SIG('S','P'):
CHECK_SP(goto out);
break;
case SIG('C','E'):
{
iso711_t i_fname = from_711(p_iso9660_dir->filename_len);
if ('\0' == p_iso9660_dir->filename[0] && 1 == i_fname)
break;
if ('\1' == p_iso9660_dir->filename[0] && 1 == i_fname)
break;
}
CHECK_CE;
break;
case SIG('E','R'):
p_stat->rr.b3_rock = yep;
cdio_debug("ISO 9660 Extensions: ");
{
int p;
for(p=0;p<rr->u.ER.len_id;p++) cdio_debug("%c",rr->u.ER.data[p]);
}
break;
case SIG('N','M'):
/* Alternate name */
p_stat->rr.b3_rock = yep;
if (truncate) break;
if (rr->u.NM.flags & ISO_ROCK_NM_PARENT) {
i_namelen = sizeof("..");
strncat(psz_name, "..", i_namelen);
} else if (rr->u.NM.flags & ISO_ROCK_NM_CURRENT) {
i_namelen = sizeof(".");
strncat(psz_name, ".", i_namelen);
break;
}
if (rr->u.NM.flags & ~1) {
cdio_info("Unsupported NM flag settings (%d)",rr->u.NM.flags);
break;
}
if((strlen(psz_name) + rr->len - 5) >= 254) {
truncate = 1;
break;
}
strncat(psz_name, rr->u.NM.name, rr->len - 5);
i_namelen += rr->len - 5;
break;
case SIG('P','X'):
/* POSIX file attributes */
p_stat->rr.st_mode = from_733(rr->u.PX.st_mode);
p_stat->rr.st_nlinks = from_733(rr->u.PX.st_nlinks);
p_stat->rr.st_uid = from_733(rr->u.PX.st_uid);
p_stat->rr.st_gid = from_733(rr->u.PX.st_gid);
p_stat->rr.b3_rock = yep;
break;
case SIG('S','L'):
{
/* Symbolic link */
uint8_t slen;
iso_rock_sl_part_t * p_sl;
iso_rock_sl_part_t * p_oldsl;
slen = rr->len - 5;
p_sl = &rr->u.SL.link;
p_stat->rr.i_symlink = symlink_len;
while (slen > 1){
rootflag = 0;
switch(p_sl->flags &~1){
case 0:
realloc_symlink(p_stat, p_sl->len);
memcpy(&(p_stat->rr.psz_symlink[p_stat->rr.i_symlink]),
p_sl->text, p_sl->len);
p_stat->rr.i_symlink += p_sl->len;
break;
case 4:
realloc_symlink(p_stat, 1);
p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '.';
/* continue into next case. */
case 2:
realloc_symlink(p_stat, 1);
p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '.';
break;
case 8:
rootflag = 1;
realloc_symlink(p_stat, 1);
p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '/';
break;
default:
cdio_warn("Symlink component flag not implemented");
}
slen -= p_sl->len + 2;
p_oldsl = p_sl;
p_sl = (iso_rock_sl_part_t *) (((char *) p_sl) + p_sl->len + 2);
if (slen < 2) {
if (((rr->u.SL.flags & 1) != 0) && ((p_oldsl->flags & 1) == 0))
p_stat->rr.i_symlink += 1;
break;
}
/*
* If this component record isn't continued, then append a '/'.
*/
if (!rootflag && (p_oldsl->flags & 1) == 0) {
realloc_symlink(p_stat, 1);
p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '/';
}
}
}
symlink_len = p_stat->rr.i_symlink;
realloc_symlink(p_stat, 1);
p_stat->rr.psz_symlink[symlink_len]='\0';
break;
case SIG('R','E'):
free(buffer);
return -1;
case SIG('T','F'):
/* Time stamp(s) for a file */
{
int cnt = 0;
add_time(ISO_ROCK_TF_CREATE, create);
add_time(ISO_ROCK_TF_MODIFY, modify);
add_time(ISO_ROCK_TF_ACCESS, access);
add_time(ISO_ROCK_TF_ATTRIBUTES, attributes);
add_time(ISO_ROCK_TF_BACKUP, backup);
add_time(ISO_ROCK_TF_EXPIRATION, expiration);
add_time(ISO_ROCK_TF_EFFECTIVE, effective);
p_stat->rr.b3_rock = yep;
break;
}
default:
break;
}
}
}
free(buffer);
return i_namelen; /* If 0, this file did not have a NM field */
out:
free(buffer);
return 0;
}
static int
parse_rock_ridge_stat_internal(iso9660_dir_t *p_iso9660_dir,
iso9660_stat_t *p_stat, int regard_xa)
{
int len;
unsigned char * chr;
int symlink_len = 0;
CONTINUE_DECLS;
if (nope == p_stat->rr.b3_rock) return 0;
SETUP_ROCK_RIDGE(p_iso9660_dir, chr, len);
if (regard_xa)
{
chr+=14;
len-=14;
if (len<0) len=0;
}
/* repeat:*/
{
int sig;
iso_extension_record_t * rr;
int rootflag;
while (len > 1){ /* There may be one byte for padding somewhere */
rr = (iso_extension_record_t *) chr;
if (rr->len == 0) goto out; /* Something got screwed up here */
sig = from_721(*chr);
chr += rr->len;
len -= rr->len;
switch(sig){
case SIG('S','P'):
CHECK_SP(goto out);
break;
case SIG('C','E'):
CHECK_CE;
break;
case SIG('E','R'):
p_stat->rr.b3_rock = yep;
cdio_debug("ISO 9660 Extensions: ");
{ int p;
for(p=0;p<rr->u.ER.len_id;p++) cdio_debug("%c",rr->u.ER.data[p]);
}
break;
case SIG('P','X'):
p_stat->rr.st_mode = from_733(rr->u.PX.st_mode);
p_stat->rr.st_nlinks = from_733(rr->u.PX.st_nlinks);
p_stat->rr.st_uid = from_733(rr->u.PX.st_uid);
p_stat->rr.st_gid = from_733(rr->u.PX.st_gid);
break;
case SIG('P','N'):
/* Device major,minor number */
{ int32_t high, low;
high = from_733(rr->u.PN.dev_high);
low = from_733(rr->u.PN.dev_low);
/*
* The Rock Ridge standard specifies that if sizeof(dev_t) <= 4,
* then the high field is unused, and the device number is completely
* stored in the low field. Some writers may ignore this subtlety,
* and as a result we test to see if the entire device number is
* stored in the low field, and use that.
*/
if((low & ~0xff) && high == 0) {
p_stat->rr.i_rdev = CDIO_MKDEV(low >> 8, low & 0xff);
} else {
p_stat->rr.i_rdev = CDIO_MKDEV(high, low);
}
}
break;
case SIG('T','F'):
/* Time stamp(s) for a file */
{
int cnt = 0;
add_time(ISO_ROCK_TF_CREATE, create);
add_time(ISO_ROCK_TF_MODIFY, modify);
add_time(ISO_ROCK_TF_ACCESS, access);
add_time(ISO_ROCK_TF_ATTRIBUTES, attributes);
add_time(ISO_ROCK_TF_BACKUP, backup);
add_time(ISO_ROCK_TF_EXPIRATION, expiration);
add_time(ISO_ROCK_TF_EFFECTIVE, effective);
p_stat->rr.b3_rock = yep;
break;
}
case SIG('S','L'):
{
/* Symbolic link */
uint8_t slen;
iso_rock_sl_part_t * p_sl;
iso_rock_sl_part_t * p_oldsl;
slen = rr->len - 5;
p_sl = &rr->u.SL.link;
p_stat->rr.i_symlink = symlink_len;
while (slen > 1){
rootflag = 0;
switch(p_sl->flags &~1){
case 0:
realloc_symlink(p_stat, p_sl->len);
memcpy(&(p_stat->rr.psz_symlink[p_stat->rr.i_symlink]),
p_sl->text, p_sl->len);
p_stat->rr.i_symlink += p_sl->len;
break;
case 4:
realloc_symlink(p_stat, 1);
p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '.';
/* continue into next case. */
case 2:
realloc_symlink(p_stat, 1);
p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '.';
break;
case 8:
rootflag = 1;
realloc_symlink(p_stat, 1);
p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '/';
p_stat->rr.i_symlink++;
break;
default:
cdio_warn("Symlink component flag not implemented");
}
slen -= p_sl->len + 2;
p_oldsl = p_sl;
p_sl = (iso_rock_sl_part_t *) (((char *) p_sl) + p_sl->len + 2);
if (slen < 2) {
if (((rr->u.SL.flags & 1) != 0) && ((p_oldsl->flags & 1) == 0))
p_stat->rr.i_symlink += 1;
break;
}
/*
* If this component record isn't continued, then append a '/'.
*/
if (!rootflag && (p_oldsl->flags & 1) == 0) {
realloc_symlink(p_stat, 1);
p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '/';
}
}
}
symlink_len = p_stat->rr.i_symlink;
realloc_symlink(p_stat, 1);
p_stat->rr.psz_symlink[symlink_len]='\0';
break;
case SIG('R','E'):
cdio_warn("Attempt to read p_stat for relocated directory");
goto out;
#if FINISHED
case SIG('C','L'):
{
iso9660_stat_t * reloc;
ISOFS_I(p_stat)->i_first_extent = from_733(rr->u.CL.location);
reloc = isofs_iget(p_stat->rr.i_sb, p_stat->rr.i_first_extent, 0);
if (!reloc)
goto out;
p_stat->rr.st_mode = reloc->st_mode;
p_stat->rr.st_nlinks = reloc->st_nlinks;
p_stat->rr.st_uid = reloc->st_uid;
p_stat->rr.st_gid = reloc->st_gid;
p_stat->rr.i_rdev = reloc->i_rdev;
p_stat->rr.i_symlink = reloc->i_symlink;
p_stat->rr.i_blocks = reloc->i_blocks;
p_stat->rr.i_atime = reloc->i_atime;
p_stat->rr.i_ctime = reloc->i_ctime;
p_stat->rr.i_mtime = reloc->i_mtime;
iput(reloc);
}
break;
#endif
default:
break;
}
}
}
out:
free(buffer);
return 0;
}
int
parse_rock_ridge_stat(iso9660_dir_t *p_iso9660_dir,
/*out*/ iso9660_stat_t *p_stat)
{
int result;
if (!p_stat) return 0;
result = parse_rock_ridge_stat_internal(p_iso9660_dir, p_stat, 0);
/* if Rock-Ridge flag was reset and we didn't look for attributes
* behind eventual XA attributes, have a look there */
if (0xFF == p_stat->rr.s_rock_offset && nope != p_stat->rr.b3_rock) {
result = parse_rock_ridge_stat_internal(p_iso9660_dir, p_stat, 14);
}
return result;
}
#define BUF_COUNT 16
#define BUF_SIZE sizeof("drwxrwxrwx")
/* Return a pointer to a internal free buffer */
static char *
_getbuf (void)
{
static char _buf[BUF_COUNT][BUF_SIZE];
static int _i = -1;
_i++;
_i %= BUF_COUNT;
memset (_buf[_i], 0, BUF_SIZE);
return _buf[_i];
}
/*!
Returns a string which interpreting the POSIX mode st_mode.
For example:
\verbatim
drwxrws---
-rw-rw-r--
lrwxrwxrwx
\endverbatim
A description of the characters in the string follows
The 1st character is either "b" for a block device,
"c" for a character device, "d" if the entry is a directory, "l" for
a symbolic link, "p" for a pipe or FIFO, "s" for a "socket",
or "-" if none of the these.
The 2nd to 4th characters refer to permissions for a user while the
the 5th to 7th characters refer to permissions for a group while, and
the 8th to 10h characters refer to permissions for everyone.
In each of these triplets the first character (2, 5, 8) is "r" if
the entry is allowed to be read.
The second character of a triplet (3, 6, 9) is "w" if the entry is
allowed to be written.
The third character of a triplet (4, 7, 10) is "x" if the entry is
executable but not user (for character 4) or group (for characters
6) settable and "s" if the item has the corresponding user/group set.
For a directory having an executable property on ("x" or "s") means
the directory is allowed to be listed or "searched". If the execute
property is not allowed for a group or user but the corresponding
group/user is set "S" indicates this. If none of these properties
holds the "-" indicates this.
*/
const char *
iso9660_get_rock_attr_str(posix_mode_t st_mode)
{
char *result = _getbuf();
if (S_ISBLK(st_mode))
result[ 0] = 'b';
else if (S_ISDIR(st_mode))
result[ 0] = 'd';
else if (S_ISCHR(st_mode))
result[ 0] = 'c';
else if (S_ISLNK(st_mode))
result[ 0] = 'l';
else if (S_ISFIFO(st_mode))
result[ 0] = 'p';
else if (S_ISSOCK(st_mode))
result[ 0] = 's';
/* May eventually fill in others.. */
else
result[ 0] = '-';
result[ 1] = (st_mode & ISO_ROCK_IRUSR) ? 'r' : '-';
result[ 2] = (st_mode & ISO_ROCK_IWUSR) ? 'w' : '-';
if (st_mode & ISO_ROCK_ISUID)
result[ 3] = (st_mode & ISO_ROCK_IXUSR) ? 's' : 'S';
else
result[ 3] = (st_mode & ISO_ROCK_IXUSR) ? 'x' : '-';
result[ 4] = (st_mode & ISO_ROCK_IRGRP) ? 'r' : '-';
result[ 5] = (st_mode & ISO_ROCK_IWGRP) ? 'w' : '-';
if (st_mode & ISO_ROCK_ISGID)
result[ 6] = (st_mode & ISO_ROCK_IXGRP) ? 's' : 'S';
else
result[ 6] = (st_mode & ISO_ROCK_IXGRP) ? 'x' : '-';
result[ 7] = (st_mode & ISO_ROCK_IROTH) ? 'r' : '-';
result[ 8] = (st_mode & ISO_ROCK_IWOTH) ? 'w' : '-';
result[ 9] = (st_mode & ISO_ROCK_IXOTH) ? 'x' : '-';
result[11] = '\0';
return result;
}
/*!
Returns POSIX mode bitstring for a given file.
*/
mode_t
iso9660_get_posix_filemode_from_rock(const iso_rock_statbuf_t *rr)
{
return (mode_t) rr->st_mode;
}

183
lib/iso9660/xa.c Normal file
View File

@@ -0,0 +1,183 @@
/*
$Id: xa.c,v 1.8 2008/04/24 07:28:00 rocky Exp $
Copyright (C) 2003, 2005, 2008 Rocky Bernstein <rocky@panix.com>
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
/*! String inside frame which identifies XA attributes. Note should
come *before* public headers which does a #define of
this name.
*/
const char ISO_XA_MARKER_STRING[] = {'C', 'D', '-', 'X', 'A', '0', '0', '1'};
/* Public headers */
#include <cdio/iso9660.h>
#include <cdio/util.h>
#include <cdio/bytesex.h>
/* Private headers */
#include "cdio_assert.h"
/** The below variable is trickery to force enum symbol values to be
recorded in debug symbol tables. It is used to allow one to refer
to the enumeration value names in the typedefs above in a debugger
and debugger expressions.
*/
xa_misc_enum_t debugger_xa_misc_enum;
#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;
}
/*!
Returns POSIX mode bitstring for a given file.
*/
posix_mode_t
iso9660_get_posix_filemode_from_xa(uint16_t i_perms)
{
posix_mode_t mode = 0;
if (i_perms & XA_PERM_RUSR) mode |= S_IRUSR;
if (i_perms & XA_PERM_XUSR) mode |= S_IXUSR;
#ifdef S_IRGRP
if (i_perms & XA_PERM_RGRP) mode |= S_IRGRP;
#endif
#ifdef S_IXGRP
if (i_perms & XA_PERM_XGRP) mode |= S_IXGRP;
#endif
#ifdef S_IROTH
if (i_perms & XA_PERM_ROTH) mode |= S_IROTH;
#endif
#ifdef S_IXOTH
if (i_perms & XA_PERM_XOTH) mode |= S_IXOTH;
#endif
if (i_perms & XA_ATTR_DIRECTORY) mode |= S_IFDIR;
return mode;
}

8
lib/paranoia/.cvsignore Normal file
View File

@@ -0,0 +1,8 @@
.deps
.libs
Makefile
Makefile.in
*.o
*.lo
*.la
*.la.ver

3
lib/paranoia/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/.deps
/Makefile
/Makefile.in

154
lib/paranoia/Makefile.am Normal file
View File

@@ -0,0 +1,154 @@
# $Id: Makefile.am,v 1.10 2008/10/20 01:25:15 rocky Exp $
#
# Copyright (C) 2004, 2006, 2008 Rocky Bernstein <rocky@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 3 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, see <http://www.gnu.org/licenses/>.
########################################################
# Things to make the libcdio_paranoia library
########################################################
#
# From libtool documentation amended with guidance from N. Boullis:
#
# 1. Start with version information of `0:0:0' for each libtool library.
#
# 2. It is probably not a good idea to update the version information
# several times between public releases, but rather once per public
# release. (This seems to be more an aesthetic consideration than
# a hard technical one.)
#
# 3. If the library source code has changed at all since the last
# update, then increment REVISION (`C:R:A' becomes `C:R+1:A').
#
# 4. If any interfaces have been added, removed, or changed since the
# last update, increment CURRENT, and set REVISION to 0.
#
# 5. If any interfaces have been added since the last public release,
# then increment AGE.
#
# 6. If any interfaces have been removed or changed since the last
# public release, then set AGE to 0. A changed interface means an
# incompatibility with previous versions.
EXTRA_DIST = libcdio_paranoia.sym
libcdio_paranoia_la_CURRENT = 0
libcdio_paranoia_la_REVISION = 3
libcdio_paranoia_la_AGE = 0
noinst_HEADERS = gap.h isort.h overlap.h p_block.h
libcdio_paranoia_sources = gap.c isort.c overlap.c overlap.h \
p_block.c paranoia.c
lib_LTLIBRARIES = libcdio_paranoia.la
libcdio_paranoia_la_SOURCES = $(libcdio_paranoia_sources)
libcdio_paranoia_la_ldflags = -version-info $(libcdio_paranoia_la_CURRENT):$(libcdio_paranoia_la_REVISION):$(libcdio_paranoia_la_AGE) @LT_NO_UNDEFINED@
INCLUDES = $(LIBCDIO_CFLAGS)
FLAGS=@LIBCDIO_CFLAGS@ @TYPESIZES@ @CFLAGS@ -I.. -I../..
OPT=$(FLAGS)
DEBUG=$(FLAGS)
## SUFFIXES = .t
## TFILES = isort.t gap.t p_block.t paranoia.t
##test: $(TFILES)
##.c.t:
## $(CC) -g -DTEST $(DEBUG) -o $@ $< $(LIBS)
## $@
##debug:
## $(MAKE) libcdio_paranoia.a CFLAGS="$(DEBUG)"
LIBS = $(LIBCDIO_LIBS) $(LIBCDIO_CDDA_LIBS)
########################################################
# Things to version the symbols in the libraries
########################################################
# An explanation of the versioning problem from Nicolas Boullis and
# the versioned symbol solution he uses below...
#
# Currently, libvcdinfo uses the cdio_open function from libcdio.
# Let's imagine a program foobar that uses both the vcdinfo_open
# function from libvcdinfo and the cdio_open function from libcdio.
# Currently, libcdio has SONAME libcdio.so.0, libvcdinfo has SONAME
# libvcdinfo.so.0 and requires libcdio.so.0, and foobar requires both
# libvcdinfo.so.0 and libcdio.so.0. Everything looks fine.
#
# Now, for some reason, you decide to change the cdio_open function.
# That's your right, but you have to bump the CURRENT version and (if I
# understand it correctly, athough this is not that clear in libtool's
# documentation) set the AGE to 0. Anyway, this bumps the SONAME, which is
# sane since the interface changes incompatibly.
# Now, you have a new libcdio with SONAME libcdio.so.1. But libvcdinfo and
# foobar still require libcdio.so.0. Everything is still fine.
# Now, after some minor changes, the author of foobar recompiles foobar.
# Then, foobar now requires libvcdinfo.so.0 and libcdio.so.1. And foobar
# now segfaults...
# What is happening? When you run foobar, if brings both libvcdinfo.so.0
# and libcdio.so.1, but libvcdinfo.so.0 also brings libcdio.so.0. So you
# have both libcdio.so.0 and libcdio.so.1 that bring their symbols to the
# global namespace. Hence, you have to incompatible versions of the
# cdio_open function in the name space. When foobar calls cdio_open, it
# may choose the wrong function, and segfaults...
# With versioned symbols, the cdio_open function from libcdio.so.0 may be
# known as (something that looks like) cdio_open@@CDIO_0. An the cdio_open
# function from libcdio.so.1 as cdio_open@@CDIO_1. Both versions of
# libcdio would still be brought in by the most recent foobar, but foobar
# (and libvcdinfo) know which versioned function to use and then use the
# good one.
# This is some simple versioning where every symbol is versioned with
# something that looks like the SONAME of the library. More complex (and
# better) versioning is possible; it is for example what is used by glibc.
# But good complex versioning is something that requires much more
# work...
# The below is a impliments symbol versioning. First of all, I
# compute MAJOR as CURENT - AGE; that is what is used within libtool
# (at least on GNU/Linux systems) for the number in the SONAME. The
# nm command gives the list of symbols known in each of the object
# files that will be part of the shared library. And the sed command
# extracts from this list those symbols that will be shared. (This sed
# command comes from libtool.)
libcdio_paranoia_la_MAJOR = $(shell expr $(libcdio_paranoia_la_CURRENT) - $(libcdio_paranoia_la_AGE))
if BUILD_VERSIONED_LIBS
libcdio_paranoia_la_LDFLAGS = $(libcdio_paranoia_la_ldflags) -Wl,--version-script=libcdio_paranoia.la.ver
libcdio_paranoia_la_DEPENDENCIES = libcdio_paranoia.la.ver
libcdio_paranoia.la.ver: $(libcdio_paranoia_la_OBJECTS) $(srcdir)/libcdio_paranoia.sym
echo 'CDIO_PARANOIA_$(libcdio_paranoia_la_MAJOR) { ' > $@
objs=`for obj in $(libcdio_paranoia_la_OBJECTS); do sed -ne "s/^pic_object='\(.*\)'$$/\1/p" $$obj; done`; \
if test -n "$$objs" ; then \
nm $${objs} | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | { first=true; while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio_paranoia.sym; then if test $$first = true; then echo " global:"; first=false; fi; echo " $${symbol};"; fi; done; } >> $@; \
nm $${objs} | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | { first=true; while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio_paranoia.sym; then :; else if test $$first = true; then echo " local:"; first=false; fi; echo " $${symbol};"; fi; done; } >> $@; \
fi
echo '};' >> $@
else
libcdio_paranoia_la_LDFLAGS = $(libcdio_paranoia_la_ldflags)
endif
MOSTLYCLEANFILES = libcdio_paranoia.la.ver

550
lib/paranoia/gap.c Normal file
View File

@@ -0,0 +1,550 @@
/*
$Id: gap.c,v 1.4 2008/04/17 17:39:48 karl Exp $
Copyright (C) 2004, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
/***
* Gap analysis support code for paranoia
*
***/
#include "config.h"
#include "p_block.h"
#include <cdio/paranoia.h>
#include "gap.h"
#include <string.h>
/**** Gap analysis code ***************************************************/
/* ===========================================================================
* i_paranoia_overlap_r (internal)
*
* This function seeks backward through two vectors (starting at the given
* offsets) to determine how many consecutive samples agree. It returns
* the number of matching samples, which may be 0.
*
* Unlike its sibling, i_paranoia_overlap_f, this function doesn't need to
* be given the size of the vectors (all vectors stop at offset 0).
*
* This function is used by i_analyze_rift_r() below to find where a
* leading rift ends.
*/
long int
i_paranoia_overlap_r(int16_t *buffA,int16_t *buffB,
long offsetA, long offsetB)
{
long beginA=offsetA;
long beginB=offsetB;
/* Start at the given offsets and work our way backwards until we hit
* the beginning of one of the vectors.
*/
for( ; beginA>=0 && beginB>=0; beginA--,beginB-- )
if (buffA[beginA] != buffB[beginB]) break;
/* These values will either point to the first mismatching sample, or
* -1 if we hit the beginning of a vector. So increment to point to the
* last matching sample.
*
* ??? Why? This would appear to return one less sample than actually
* matched. E.g., no matching samples returns -1! Is this a bug?
*/
beginA++;
beginB++;
return(offsetA-beginA);
}
/* ===========================================================================
* i_paranoia_overlap_f (internal)
*
* This function seeks forward through two vectors (starting at the given
* offsets) to determine how many consecutive samples agree. It returns
* the number of matching samples, which may be 0.
*
* Unlike its sibling, i_paranoia_overlap_r, this function needs to given
* the size of the vectors.
*
* This function is used by i_analyze_rift_f() below to find where a
* trailing rift ends.
*/
long int
i_paranoia_overlap_f(int16_t *buffA,int16_t *buffB,
long offsetA, long offsetB,
long sizeA,long sizeB)
{
long endA=offsetA;
long endB=offsetB;
/* Start at the given offsets and work our way forward until we hit
* the end of one of the vectors.
*/
for(;endA<sizeA && endB<sizeB;endA++,endB++)
if(buffA[endA]!=buffB[endB])break;
/* ??? Note that we don't do any post-loop tweaking of endA. Why the
* asymmetry with i_paranoia_overlap_r?
*/
return(endA-offsetA);
}
/* ===========================================================================
* i_stutter_or_gap (internal)
*
* This function compares (gap) samples of two vectors at the given offsets.
* It returns 0 if all the samples are identical, or nonzero if they differ.
*
* This is used by i_analyze_rift_[rf] below to determine whether a rift
* contains samples dropped by the other vector (that should be inserted),
* or whether the rift contains a stutter (that should be dropped). See
* i_analyze_rift_[rf] for more details.
*/
int
i_stutter_or_gap(int16_t *A, int16_t *B,long offA, long offB, long int gap)
{
long a1=offA;
long b1=offB;
/* If the rift was so big that there aren't enough samples in the other
* vector to compare against the full gap, then just compare what we
* have available. E.g.:
*
* (5678)|(newly matching run ...)
* (... 12345678)| (345678) |(newly matching run ...)
*
* In this case, a1 would be -2, since we'd want to compare 6 samples
* against a vector that had only 4. So we start 2 samples later, and
* compare the 4 available samples.
*
* Again, this approach to identifying stutters is simply a heuristic,
* so this may not produce correct results in all cases.
*/
if(a1<0){
/* Note that a1 is negative, so we're increasing b1 and decreasing (gap).
*/
b1-=a1;
gap+=a1;
a1=0;
}
/* Note that we don't have an equivalent adjustment for leading rifts.
* Thus, it's possible for the following memcmp() to run off the end
* of A. See the bug note in i_analyze_rift_r().
*/
/* Multiply gap by 2 because samples are 2 bytes long and memcmp compares
* at the byte level.
*/
return(memcmp(A+a1,B+b1,gap*2));
}
/* riftv is the first value into the rift -> or <- */
/* ===========================================================================
* i_analyze_rift_f (internal)
*
* This function examines a trailing rift to see how far forward the rift goes
* and to determine what kind of rift it is. This function is called by
* i_stage2_each() when a trailing rift is detected. (aoffset,boffset) are
* the offsets into (A,B) of the first mismatching sample.
*
* This function returns:
* matchA > 0 if there are (matchA) samples missing from A
* matchA < 0 if there are (-matchA) duplicate samples (stuttering) in A
* matchB > 0 if there are (matchB) samples missing from B
* matchB < 0 if there are (-matchB) duplicate samples in B
* matchC != 0 if there are (matchC) samples of garbage, after which
* both A and B are in sync again
*/
void
i_analyze_rift_f(int16_t *A,int16_t *B,
long sizeA, long sizeB,
long aoffset, long boffset,
long *matchA,long *matchB,long *matchC)
{
long apast=sizeA-aoffset;
long bpast=sizeB-boffset;
long i;
*matchA=0, *matchB=0, *matchC=0;
/* Look forward to see where we regain agreement between vectors
* A and B (of at least MIN_WORDS_RIFT samples). We look for one of
* the following possible matches:
*
* edge
* v
* (1) (... A matching run)|(aoffset matches ...)
* (... B matching run)| (rift) |(boffset+i matches ...)
*
* (2) (... A matching run)| (rift) |(aoffset+i matches ...)
* (... B matching run)|(boffset matches ...)
*
* (3) (... A matching run)| (rift) |(aoffset+i matches ...)
* (... B matching run)| (rift) |(boffset+i matches ...)
*
* Anything that doesn't match one of these three is too corrupt to
* for us to recover from. E.g.:
*
* (... A matching run)| (rift) |(eventual match ...)
* (... B matching run)| (big rift) |(eventual match ...)
*
* We won't find the eventual match, since we wouldn't be sure how
* to fix the rift.
*/
for(i=0;;i++){
/* Search for whatever case we hit first, so as to end up with the
* smallest rift.
*
* ??? Why do we start at 0? It should never match.
*/
/* Don't search for (1) past the end of B */
if (i<bpast)
/* See if we match case (1) above, which either means that A dropped
* samples at the rift, or that B stuttered.
*/
if(i_paranoia_overlap_f(A,B,aoffset,boffset+i,sizeA,sizeB)>=MIN_WORDS_RIFT){
*matchA=i;
break;
}
/* Don't search for (2) or (3) past the end of A */
if (i<apast) {
/* See if we match case (2) above, which either means that B dropped
* samples at the rift, or that A stuttered.
*/
if(i_paranoia_overlap_f(A,B,aoffset+i,boffset,sizeA,sizeB)>=MIN_WORDS_RIFT){
*matchB=i;
break;
}
/* Don't search for (3) past the end of B */
if (i<bpast)
/* See if we match case (3) above, which means that a fixed-length
* rift of samples is getting read unreliably.
*/
if(i_paranoia_overlap_f(A,B,aoffset+i,boffset+i,sizeA,sizeB)>=MIN_WORDS_RIFT){
*matchC=i;
break;
}
}else
/* Stop searching when we've reached the end of both vectors.
* In theory we could stop when there aren't MIN_WORDS_RIFT samples
* left in both vectors, but this case should happen fairly rarely.
*/
if(i>=bpast)break;
/* Try the search again with a larger tentative rift. */
}
if(*matchA==0 && *matchB==0 && *matchC==0)return;
if(*matchC)return;
/* For case (1) or (2), we need to determine whether the rift contains
* samples dropped by the other vector (that should be inserted), or
* whether the rift contains a stutter (that should be dropped). To
* distinguish, we check the contents of the rift against the good samples
* just before the rift. If the contents match, then the rift contains
* a stutter.
*
* A stutter in the second vector:
* (...good samples... 1234)|(567 ...newly matched run...)
* (...good samples... 1234)| (1234) | (567 ...newly matched run)
*
* Samples missing from the first vector:
* (...good samples... 1234)|(901 ...newly matched run...)
* (...good samples... 1234)| (5678) |(901 ...newly matched run...)
*
* Of course, there's no theoretical guarantee that a non-stutter
* truly represents missing samples, but given that we're dealing with
* verified fragments in stage 2, we can have some confidence that this
* is the case.
*/
if(*matchA){
/* For case (1), we need to determine whether A dropped samples at the
* rift or whether B stuttered.
*
* If the rift doesn't match the good samples in A (and hence in B),
* it's not a stutter, and the rift should be inserted into A.
*/
if(i_stutter_or_gap(A,B,aoffset-*matchA,boffset,*matchA))
return;
/* It is a stutter, so we need to signal that we need to remove
* (matchA) bytes from B.
*/
*matchB = -*matchA;
*matchA=0;
return;
}else{
/* Case (2) is the inverse of case (1) above. */
if(i_stutter_or_gap(B,A,boffset-*matchB,aoffset,*matchB))
return;
*matchA = -*matchB;
*matchB=0;
return;
}
}
/* riftv must be first even val of rift moving back */
/* ===========================================================================
* i_analyze_rift_r (internal)
*
* This function examines a leading rift to see how far back the rift goes
* and to determine what kind of rift it is. This function is called by
* i_stage2_each() when a leading rift is detected. (aoffset,boffset) are
* the offsets into (A,B) of the first mismatching sample.
*
* This function returns:
* matchA > 0 if there are (matchA) samples missing from A
* matchA < 0 if there are (-matchA) duplicate samples (stuttering) in A
* matchB > 0 if there are (matchB) samples missing from B
* matchB < 0 if there are (-matchB) duplicate samples in B
* matchC != 0 if there are (matchC) samples of garbage, after which
* both A and B are in sync again
*/
void
i_analyze_rift_r(int16_t *A,int16_t *B,
long sizeA, long sizeB,
long aoffset, long boffset,
long *matchA,long *matchB,long *matchC)
{
long apast=aoffset+1;
long bpast=boffset+1;
long i;
*matchA=0, *matchB=0, *matchC=0;
/* Look backward to see where we regain agreement between vectors
* A and B (of at least MIN_WORDS_RIFT samples). We look for one of
* the following possible matches:
*
* edge
* v
* (1) (... aoffset matches)|(A matching run ...)
* (... boffset-i matches)| (rift) |(B matching run ...)
*
* (2) (... aoffset-i matches)| (rift) |(A matching run ...)
* (... boffset matches)|(B matching run ...)
*
* (3) (... aoffset-i matches)| (rift) |(A matching run ...)
* (... boffset-i matches)| (rift) |(B matching run ...)
*
* Anything that doesn't match one of these three is too corrupt to
* for us to recover from. E.g.:
*
* (... eventual match)| (rift) |(A matching run ...)
* (... eventual match) | (big rift) |(B matching run ...)
*
* We won't find the eventual match, since we wouldn't be sure how
* to fix the rift.
*/
for(i=0;;i++){
/* Search for whatever case we hit first, so as to end up with the
* smallest rift.
*
* ??? Why do we start at 0? It should never match.
*/
/* Don't search for (1) past the beginning of B */
if (i<bpast)
/* See if we match case (1) above, which either means that A dropped
* samples at the rift, or that B stuttered.
*/
if(i_paranoia_overlap_r(A,B,aoffset,boffset-i)>=MIN_WORDS_RIFT){
*matchA=i;
break;
}
/* Don't search for (2) or (3) past the beginning of A */
if (i<apast) {
/* See if we match case (2) above, which either means that B dropped
* samples at the rift, or that A stuttered.
*/
if(i_paranoia_overlap_r(A,B,aoffset-i,boffset)>=MIN_WORDS_RIFT){
*matchB=i;
break;
}
/* Don't search for (3) past the beginning of B */
if (i<bpast)
/* See if we match case (3) above, which means that a fixed-length
* rift of samples is getting read unreliably.
*/
if(i_paranoia_overlap_r(A,B,aoffset-i,boffset-i)>=MIN_WORDS_RIFT){
*matchC=i;
break;
}
}else
/* Stop searching when we've reached the end of both vectors.
* In theory we could stop when there aren't MIN_WORDS_RIFT samples
* left in both vectors, but this case should happen fairly rarely.
*/
if(i>=bpast)break;
/* Try the search again with a larger tentative rift. */
}
if(*matchA==0 && *matchB==0 && *matchC==0)return;
if(*matchC)return;
/* For case (1) or (2), we need to determine whether the rift contains
* samples dropped by the other vector (that should be inserted), or
* whether the rift contains a stutter (that should be dropped). To
* distinguish, we check the contents of the rift against the good samples
* just after the rift. If the contents match, then the rift contains
* a stutter.
*
* A stutter in the second vector:
* (...newly matched run... 234)|(5678 ...good samples...)
* (...newly matched run... 234)| (5678) |(5678 ...good samples...)
*
* Samples missing from the first vector:
* (...newly matched run... 890)|(5678 ...good samples...)
* (...newly matched run... 890)| (1234) |(5678 ...good samples...)
*
* Of course, there's no theoretical guarantee that a non-stutter
* truly represents missing samples, but given that we're dealing with
* verified fragments in stage 2, we can have some confidence that this
* is the case.
*/
if(*matchA){
/* For case (1), we need to determine whether A dropped samples at the
* rift or whether B stuttered.
*
* If the rift doesn't match the good samples in A (and hence in B),
* it's not a stutter, and the rift should be inserted into A.
*
* ???BUG??? It's possible for aoffset+1+*matchA to be > sizeA, in
* which case the comparison in i_stutter_or_gap() will extend beyond
* the bounds of A. Thankfully, this isn't writing data and thus
* trampling memory, but it's still a memory access error that should
* be fixed.
*
* This bug is not fixed yet.
*/
if(i_stutter_or_gap(A,B,aoffset+1,boffset-*matchA+1,*matchA))
return;
/* It is a stutter, so we need to signal that we need to remove
* (matchA) bytes from B.
*/
*matchB = -*matchA;
*matchA=0;
return;
}else{
/* Case (2) is the inverse of case (1) above. */
if(i_stutter_or_gap(B,A,boffset+1,aoffset-*matchB+1,*matchB))
return;
*matchA = -*matchB;
*matchB=0;
return;
}
}
/* ===========================================================================
* analyze_rift_silence_f (internal)
*
* This function examines the fragment and root from the rift onward to
* see if they have a rift's worth of silence (or if they end with silence).
* It sets (*matchA) to -1 if A's rift is silence, (*matchB) to -1 if B's
* rift is silence, and sets them to 0 otherwise.
*
* Note that, unlike every other function in cdparanoia, this function
* considers any repeated value to be silence (which, in effect, it is).
* All other functions only consider repeated zeroes to be silence.
*
* ??? Is this function name just a misnomer, as it's really looking for
* repeated garbage?
*
* This function is called by i_stage2_each() if it runs into a trailing rift
* that i_analyze_rift_f couldn't diagnose. This checks for another variant:
* where one vector has silence and the other doesn't. We then assume
* that the silence (and anything following it) is garbage.
*
* Note that while this function checks both A and B for silence, the caller
* assumes that only one or the other has silence.
*/
void
analyze_rift_silence_f(int16_t *A,int16_t *B,long sizeA,long sizeB,
long aoffset, long boffset,
long *matchA, long *matchB)
{
*matchA=-1;
*matchB=-1;
/* Search for MIN_WORDS_RIFT samples, or to the end of the vector,
* whichever comes first.
*/
sizeA=min(sizeA,aoffset+MIN_WORDS_RIFT);
sizeB=min(sizeB,boffset+MIN_WORDS_RIFT);
aoffset++;
boffset++;
/* Check whether A has only "silence" within the search range. Note
* that "silence" here is a single, repeated value (zero or not).
*/
while(aoffset<sizeA){
if(A[aoffset]!=A[aoffset-1]){
*matchA=0;
break;
}
aoffset++;
}
/* Check whether B has only "silence" within the search range. Note
* that "silence" here is a single, repeated value (zero or not).
*
* Also note that while the caller assumes that only matchA or matchB
* is set, we check both vectors here.
*/
while(boffset<sizeB){
if(B[boffset]!=B[boffset-1]){
*matchB=0;
break;
}
boffset++;
}
}

43
lib/paranoia/gap.h Normal file
View File

@@ -0,0 +1,43 @@
/*
$Id: gap.h,v 1.2 2008/04/17 17:39:48 karl Exp $
Copyright (C) 2004, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _GAP_H_
#define _GAP_H_
extern long i_paranoia_overlap_r(int16_t *buffA,int16_t *buffB,
long offsetA, long offsetB);
extern long i_paranoia_overlap_f(int16_t *buffA,int16_t *buffB,
long offsetA, long offsetB,
long sizeA,long sizeB);
extern int i_stutter_or_gap(int16_t *A, int16_t *B,long offA, long offB,
long gap);
extern void i_analyze_rift_f(int16_t *A,int16_t *B,
long sizeA, long sizeB,
long aoffset, long boffset,
long *matchA,long *matchB,long *matchC);
extern void i_analyze_rift_r(int16_t *A,int16_t *B,
long sizeA, long sizeB,
long aoffset, long boffset,
long *matchA,long *matchB,long *matchC);
extern void analyze_rift_silence_f(int16_t *A,int16_t *B,long sizeA,long sizeB,
long aoffset, long boffset,
long *matchA, long *matchB);
#endif /*_GAP_H*/

302
lib/paranoia/isort.c Normal file
View File

@@ -0,0 +1,302 @@
/*
$Id: isort.c,v 1.7 2008/04/17 17:39:48 karl Exp $
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
/* sorted vector abstraction for paranoia */
/* Old isort got a bit complex. This re-constrains complexity to
give a go at speed through a more alpha-6-like mechanism. */
/* "Sort" is a bit of a misnomer in this implementation. It's actually
* basically a hash table of sample values (with a linked-list collision
* resolution), which lets you quickly determine where in a vector a
* particular sample value occurs.
*
* Collisions aren't due to hash collisions, as the table has one bucket
* for each possible sample value. Instead, the "collisions" represent
* multiple occurrences of a given value.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "p_block.h"
#include "isort.h"
/* ===========================================================================
* sort_alloc()
*
* Allocates and initializes a new, empty sort_info object, which can be
* used to index up to (size) samples from a vector.
*/
sort_info_t *
sort_alloc(long size)
{
sort_info_t *ret=calloc(1, sizeof(sort_info_t));
ret->vector=NULL;
ret->sortbegin=-1;
ret->size=-1;
ret->maxsize=size;
ret->head=calloc(65536,sizeof(sort_link_t *));
ret->bucketusage=calloc(1, 65536*sizeof(long));
ret->revindex=calloc(size,sizeof(sort_link_t));
ret->lastbucket=0;
return(ret);
}
/* ===========================================================================
* sort_unsortall() (internal)
*
* This function resets the index for further use with a different vector
* or range, without the overhead of an unnecessary free/alloc.
*/
void
sort_unsortall(sort_info_t *i)
{
/* If there were few enough different samples encountered (and hence few
* enough buckets used), we can just zero out those buckets. If there
* were many (2000 is picked somewhat arbitrarily), it's faster simply to
* zero out all buckets with a memset() rather than walking the data
* structure and zeroing them out one by one.
*/
if (i->lastbucket>2000) { /* a guess */
memset(i->head,0,65536*sizeof(sort_link_t *));
} else {
long b;
for (b=0; b<i->lastbucket; b++)
i->head[i->bucketusage[b]]=NULL;
}
i->lastbucket=0;
i->sortbegin=-1;
/* Curiously, this function preserves the vector association created
* by sort_setup(), but it is used only internally by sort_setup, so
* preserving this association is unnecessary.
*/
}
/* ===========================================================================
* sort_free()
*
* Releases all memory consumed by a sort_info object.
*/
void
sort_free(sort_info_t *i)
{
free(i->revindex);
free(i->head);
free(i->bucketusage);
free(i);
}
/* ===========================================================================
* sort_sort() (internal)
*
* This function builds the index to allow for fast searching for sample
* values within a portion (sortlo - sorthi) of the object's associated
* vector. It is called internally and only when needed.
*/
static void
sort_sort(sort_info_t *i,long sortlo,long sorthi)
{
long j;
/* We walk backward through the range to index because we insert new
* samples at the head of each bucket's list. At the end, they'll be
* sorted from first to last occurrence.
*/
for (j=sorthi-1; j>=sortlo; j--) {
/* i->vector[j] = the signed 16-bit sample to index.
* hv = pointer to the head of the sorted list of occurences
* of this sample
* l = the node to associate with this sample
*
* We add 32768 to convert the signed 16-bit integer to an unsigned
* range from 0 to 65535.
*
* Note that l is located within i->revindex at a position
* corresponding to the sample's position in the vector. This allows
* ipos() to determine the sample position from a returned sort_link.
*/
sort_link_t **hv = i->head+i->vector[j]+32768;
sort_link_t *l = i->revindex+j;
/* If this is the first time we've encountered this sample, add its
* bucket to the list of buckets used. This list is used only for
* resetting the index quickly.
*/
if(*hv==NULL){
i->bucketusage[i->lastbucket] = i->vector[j]+32768;
i->lastbucket++;
}
/* Point the new node at the old head, then assign the new node as
* the new head.
*/
l->next=*hv;
*hv=l;
}
/* Mark the index as initialized.
*/
i->sortbegin=0;
}
/* ===========================================================================
* sort_setup()
*
* This function initializes a previously allocated sort_info_t. The
* sort_info_t is associated with a vector of samples of length
* (size), whose position begins at (*abspos) within the CD's stream
* of samples. Only the range of samples between (sortlo, sorthi)
* will eventually be indexed for fast searching. (sortlo, sorthi)
* are absolute sample positions.
*
* ???: Why is abspos a pointer? Why not just store a copy?
*
* Note: size *must* be <= the size given to the preceding sort_alloc(),
* but no error checking is done here.
*/
void
sort_setup(sort_info_t *i, int16_t *vector, long int *abspos,
long int size, long int sortlo, long int sorthi)
{
/* Reset the index if it has already been built.
*/
if (i->sortbegin!=-1)
sort_unsortall(i);
i->vector=vector;
i->size=size;
i->abspos=abspos;
/* Convert the absolute (sortlo, sorthi) to offsets within the vector.
* Note that the index will not be built until sort_getmatch() is called.
* Here we're simply hanging on to the range to index until then.
*/
i->lo = min(size, max(sortlo - *abspos, 0));
i->hi = max(0, min(sorthi - *abspos, size));
}
/* ===========================================================================
* sort_getmatch()
*
* This function returns a sort_link_t pointer which refers to the
* first sample equal to (value) in the vector. It only searches for
* hits within (overlap) samples of (post), where (post) is an offset
* within the vector. The caller can determine the position of the
* matched sample using ipos(sort_info *, sort_link *).
*
* This function returns NULL if no matches were found.
*/
sort_link_t *
sort_getmatch(sort_info_t *i, long post, long overlap, int value)
{
sort_link_t *ret;
/* If the vector hasn't been indexed yet, index it now.
*/
if (i->sortbegin==-1)
sort_sort(i,i->lo,i->hi);
/* Now we reuse lo and hi */
/* We'll only return samples within (overlap) samples of (post).
* Clamp the boundaries to search to the boundaries of the array,
* convert the signed sample to an unsigned offset, and store the
* state so that future calls to sort_nextmatch do the right thing.
*
* Reusing lo and hi this way is awful.
*/
post=max(0,min(i->size,post));
i->val=value+32768;
i->lo=max(0,post-overlap); /* absolute position */
i->hi=min(i->size,post+overlap); /* absolute position */
/* Walk through the linked list of samples with this value, until
* we find the first one within the bounds specified. If there
* aren't any, return NULL.
*/
ret=i->head[i->val];
while (ret) {
/* ipos() calculates the offset (in terms of the original vector)
* of this hit.
*/
if (ipos(i,ret)<i->lo) {
ret=ret->next;
} else {
if (ipos(i,ret)>=i->hi)
ret=NULL;
break;
}
}
/*i->head[i->val]=ret;*/
return(ret);
}
/* ===========================================================================
* sort_nextmatch()
*
* This function returns a sort_link_t pointer which refers to the next sample
* matching the criteria previously passed to sort_getmatch(). See
* sort_getmatch() for details.
*
* This function returns NULL if no further matches were found.
*/
sort_link_t *
sort_nextmatch(sort_info_t *i, sort_link_t *prev)
{
sort_link_t *ret=prev->next;
/* If there aren't any more hits, or we've passed the boundary requested
* of sort_getmatch(), we're done.
*/
if (!ret || ipos(i,ret)>=i->hi)
return(NULL);
return(ret);
}

161
lib/paranoia/isort.h Normal file
View File

@@ -0,0 +1,161 @@
/*
$Id: isort.h,v 1.6 2008/04/17 17:39:48 karl Exp $
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _ISORT_H_
#define _ISORT_H_
typedef struct sort_link{
struct sort_link *next;
} sort_link_t;
typedef struct sort_info {
int16_t *vector; /* vector (storage doesn't belong to us) */
long *abspos; /* pointer for side effects */
long size; /* vector size */
long maxsize; /* maximum vector size */
long sortbegin; /* range of contiguous sorted area */
long lo,hi; /* current post, overlap range */
int val; /* ...and val */
/* sort structs */
sort_link_t **head; /* sort buckets (65536) */
long *bucketusage; /* of used buckets (65536) */
long lastbucket;
sort_link_t *revindex;
} sort_info_t;
/*! ========================================================================
* sort_alloc()
*
* Allocates and initializes a new, empty sort_info object, which can
* be used to index up to (size) samples from a vector.
*/
extern sort_info_t *sort_alloc(long int size);
/*! ========================================================================
* sort_unsortall() (internal)
*
* This function resets the index for further use with a different
* vector or range, without the overhead of an unnecessary free/alloc.
*/
extern void sort_unsortall(sort_info_t *i);
/*! ========================================================================
* sort_setup()
*
* This function initializes a previously allocated sort_info_t. The
* sort_info_t is associated with a vector of samples of length
* (size), whose position begins at (*abspos) within the CD's stream
* of samples. Only the range of samples between (sortlo, sorthi)
* will eventually be indexed for fast searching. (sortlo, sorthi)
* are absolute sample positions.
*
* ???: Why is abspos a pointer? Why not just store a copy?
*
* Note: size *must* be <= the size given to the preceding sort_alloc(),
* but no error checking is done here.
*/
extern void sort_setup(sort_info_t *i, int16_t *vector, long int *abspos,
long int size, long int sortlo, long int sorthi);
/* =========================================================================
* sort_free()
*
* Releases all memory consumed by a sort_info object.
*/
extern void sort_free(sort_info_t *i);
/*! ========================================================================
* sort_getmatch()
*
* This function returns a sort_link_t pointer which refers to the
* first sample equal to (value) in the vector. It only searches for
* hits within (overlap) samples of (post), where (post) is an offset
* within the vector. The caller can determine the position of the
* matched sample using ipos(sort_info *, sort_link *).
*
* This function returns NULL if no matches were found.
*/
extern sort_link_t *sort_getmatch(sort_info_t *i, long post, long overlap,
int value);
/*! ========================================================================
* sort_nextmatch()
*
* This function returns a sort_link_t pointer which refers to the
* next sample matching the criteria previously passed to
* sort_getmatch(). See sort_getmatch() for details.
*
* This function returns NULL if no further matches were found.
*/
extern sort_link_t *sort_nextmatch(sort_info_t *i, sort_link_t *prev);
/* ===========================================================================
* is()
*
* This macro returns the size of the vector indexed by the given sort_info_t.
*/
#define is(i) (i->size)
/* ===========================================================================
* ib()
*
* This macro returns the absolute position of the first sample in the vector
* indexed by the given sort_info_t.
*/
#define ib(i) (*i->abspos)
/* ===========================================================================
* ie()
*
* This macro returns the absolute position of the sample after the last
* sample in the vector indexed by the given sort_info_t.
*/
#define ie(i) (i->size+*i->abspos)
/* ===========================================================================
* iv()
*
* This macro returns the vector indexed by the given sort_info_t.
*/
#define iv(i) (i->vector)
/* ===========================================================================
* ipos()
*
* This macro returns the relative position (offset) within the indexed vector
* at which the given match was found.
*
* It uses a little-known and frightening aspect of C pointer arithmetic:
* subtracting a pointer is not an arithmetic subtraction, but rather the
* additive inverse. In other words, since
* q = p + n returns a pointer to the nth object in p,
* q - p = p + n - p, and
* q - p = n, not the difference of the two addresses.
*/
#define ipos(i,l) (l-i->revindex)
#endif /* _ISORT_H_ */

View File

@@ -0,0 +1,9 @@
cdio_paranoia_init
cdio_paranoia_free
cdio_paranoia_modeset
cdio_paranoia_seek
cdio_paranoia_read
cdio_paranoia_read_limited
cdio_paranoia_overlapset
cdio_paranoia_set_range
paranoia_cb_mode2str

256
lib/paranoia/overlap.c Normal file
View File

@@ -0,0 +1,256 @@
/*
$Id: overlap.c,v 1.6 2008/04/17 17:39:48 karl Exp $
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
/***
*
* Statistic code and cache management for overlap settings
*
***/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <cdio/paranoia.h>
#include "p_block.h"
#include "overlap.h"
#include "isort.h"
/**** Internal cache management *****************************************/
void
paranoia_resetcache(cdrom_paranoia_t *p)
{
c_block_t *c=c_first(p);
v_fragment_t *v;
while(c){
free_c_block(c);
c=c_first(p);
}
v=v_first(p);
while(v){
free_v_fragment(v);
v=v_first(p);
}
}
void
paranoia_resetall(cdrom_paranoia_t *p)
{
p->root.returnedlimit=0;
p->dyndrift=0;
p->root.lastsector=0;
if(p->root.vector){
i_cblock_destructor(p->root.vector);
p->root.vector=NULL;
}
paranoia_resetcache(p);
}
void
i_paranoia_trim(cdrom_paranoia_t *p, long int beginword, long int endword)
{
root_block *root=&(p->root);
if(root->vector!=NULL){
long target=beginword-MAX_SECTOR_OVERLAP*CD_FRAMEWORDS;
long rbegin=cb(root->vector);
long rend=ce(root->vector);
if(rbegin>beginword)
goto rootfree;
if(rbegin+MAX_SECTOR_OVERLAP*CD_FRAMEWORDS<beginword){
if(target+MIN_WORDS_OVERLAP>rend)
goto rootfree;
{
long int offset=target-rbegin;
c_removef(root->vector,offset);
}
}
{
c_block_t *c=c_first(p);
while(c){
c_block_t *next=c_next(c);
if(ce(c)<beginword-MAX_SECTOR_OVERLAP*CD_FRAMEWORDS)
free_c_block(c);
c=next;
}
}
}
return;
rootfree:
i_cblock_destructor(root->vector);
root->vector=NULL;
root->returnedlimit=-1;
root->lastsector=0;
}
/**** Statistical and heuristic[al? :-] management ************************/
/* ===========================================================================
* offset_adjust_settings (internal)
*
* This function is called by offset_add_value() every time 10 samples have
* been accumulated. This function updates the internal statistics for
* paranoia (dynoverlap, dyndrift) that compensate for jitter and drift.
*
* (dynoverlap) influences how far stage 1 and stage 2 search for matching
* runs. In low-jitter conditions, it will be very small (or even 0),
* narrowing our search. In high-jitter conditions, it will be much larger,
* widening our search at the cost of speed.
*
* ???: To be studied further.
*/
void
offset_adjust_settings(cdrom_paranoia_t *p,
void(*callback)(long int, paranoia_cb_mode_t))
{
if(p->stage2.offpoints>=10){
/* drift: look at the average offset value. If it's over one
sector, frob it. We just want a little hysteresis [sp?]*/
long av=(p->stage2.offpoints?p->stage2.offaccum/p->stage2.offpoints:0);
if(abs(av)>p->dynoverlap/4){
av=(av/MIN_SECTOR_EPSILON)*MIN_SECTOR_EPSILON;
if(callback)(*callback)(ce(p->root.vector),PARANOIA_CB_DRIFT);
p->dyndrift+=av;
/* Adjust all the values in the cache otherwise we get a
(potentially unstable) feedback loop */
{
c_block_t *c=c_first(p);
v_fragment_t *v=v_first(p);
while(v && v->one){
/* safeguard beginning bounds case with a hammer */
if(fb(v)<av || cb(v->one)<av){
v->one=NULL;
}else{
fb(v)-=av;
}
v=v_next(v);
}
while(c){
long adj=min(av,cb(c));
c_set(c,cb(c)-adj);
c=c_next(c);
}
}
p->stage2.offaccum=0;
p->stage2.offmin=0;
p->stage2.offmax=0;
p->stage2.offpoints=0;
p->stage2.newpoints=0;
p->stage2.offdiff=0;
}
}
if(p->stage1.offpoints>=10){
/* dynoverlap: we arbitrarily set it to 4x the running difference
value, unless min/max are more */
p->dynoverlap=(p->stage1.offpoints?p->stage1.offdiff/
p->stage1.offpoints*3:CD_FRAMEWORDS);
if(p->dynoverlap<-p->stage1.offmin*1.5)
p->dynoverlap=-p->stage1.offmin*1.5;
if(p->dynoverlap<p->stage1.offmax*1.5)
p->dynoverlap=p->stage1.offmax*1.5;
if(p->dynoverlap<MIN_SECTOR_EPSILON)p->dynoverlap=MIN_SECTOR_EPSILON;
if(p->dynoverlap>MAX_SECTOR_OVERLAP*CD_FRAMEWORDS)
p->dynoverlap=MAX_SECTOR_OVERLAP*CD_FRAMEWORDS;
if(callback)(*callback)(p->dynoverlap,PARANOIA_CB_OVERLAP);
if(p->stage1.offpoints>600){ /* bit of a bug; this routine is
called too often due to the overlap
mesh alg we use in stage 1 */
p->stage1.offpoints/=1.2;
p->stage1.offaccum/=1.2;
p->stage1.offdiff/=1.2;
}
p->stage1.offmin=0;
p->stage1.offmax=0;
p->stage1.newpoints=0;
}
}
/* ===========================================================================
* offset_add_value (internal)
*
* This function adds the given jitter detected (value) to the statistics
* for the given stage (o). It is called whenever jitter has been identified
* by stage 1 or 2. After every 10 samples, we update the overall jitter-
* compensation settings (e.g. dynoverlap). This allows us to narrow our
* search for matching runs (in both stages) in low-jitter conditions
* and also widen our search appropriately when there is jitter.
*
* ???BUG???:
* Note that there is a bug in the way that this is called by try_sort_sync().
* Silence looks like zero jitter, and dynoverlap may be incorrectly reduced
* when there's lots of silence but also jitter.
*
* See the bug notes in try_sort_sync() for details.
*/
void
offset_add_value(cdrom_paranoia_t *p,offsets *o,long value,
void(*callback)(long int, paranoia_cb_mode_t))
{
if(o->offpoints!=-1){
/* Track the average magnitude of jitter (in either direction) */
o->offdiff+=abs(value);
o->offpoints++;
o->newpoints++;
/* Track the net value of the jitter (to track drift) */
o->offaccum+=value;
/* Track the largest jitter we've encountered in each direction */
if(value<o->offmin)o->offmin=value;
if(value>o->offmax)o->offmax=value;
/* After 10 samples, update dynoverlap, etc. */
if(o->newpoints>=10)offset_adjust_settings(p,callback);
}
}

33
lib/paranoia/overlap.h Normal file
View File

@@ -0,0 +1,33 @@
/*
$Id: overlap.h,v 1.2 2008/04/17 17:39:48 karl Exp $
Copyright (C) 2004, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _OVERLAP_H_
#define _OVERLAP_H_
extern void offset_add_value(cdrom_paranoia_t *p,offsets *o,long value,
void(*callback)(long int, paranoia_cb_mode_t));
extern void offset_clear_settings(offsets *o);
extern void offset_adjust_settings(cdrom_paranoia_t *p,
void(*callback)(long, paranoia_cb_mode_t));
extern void i_paranoia_trim(cdrom_paranoia_t *p,long beginword,long endword);
extern void paranoia_resetall(cdrom_paranoia_t *p);
extern void paranoia_resetcache(cdrom_paranoia_t *p);
#endif /*_OVERLAP_H_*/

459
lib/paranoia/p_block.c Normal file
View File

@@ -0,0 +1,459 @@
/*
$Id: p_block.c,v 1.13 2008/04/17 17:39:48 karl Exp $
Copyright (C) 2004, 2005, 2007, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 1998 Monty xiphmont@mit.edu
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <limits.h>
#include "p_block.h"
#include <cdio/cdda.h>
#include <cdio/paranoia.h>
linked_list_t *new_list(void *(*newp)(void),void (*freep)(void *))
{
linked_list_t *ret=calloc(1,sizeof(linked_list_t));
ret->new_poly=newp;
ret->free_poly=freep;
return(ret);
}
linked_element *add_elem(linked_list_t *l,void *elem)
{
linked_element *ret=calloc(1,sizeof(linked_element));
ret->stamp=l->current++;
ret->ptr=elem;
ret->list=l;
if(l->head)
l->head->prev=ret;
else
l->tail=ret;
ret->next=l->head;
ret->prev=NULL;
l->head=ret;
l->active++;
return(ret);
}
linked_element *
new_elem(linked_list_t *p_list)
{
void *p_new=p_list->new_poly();
return(add_elem(p_list,p_new));
}
void
free_elem(linked_element *e,int free_ptr)
{
linked_list_t *l=e->list;
if(free_ptr)l->free_poly(e->ptr);
if(e==l->head)
l->head=e->next;
if(e==l->tail)
l->tail=e->prev;
if(e->prev)
e->prev->next=e->next;
if(e->next)
e->next->prev=e->prev;
l->active--;
free(e);
}
void
free_list(linked_list_t *list,int free_ptr)
{
while(list->head)
free_elem(list->head,free_ptr);
free(list);
}
void *get_elem(linked_element *e)
{
return(e->ptr);
}
linked_list_t *copy_list(linked_list_t *list)
{
linked_list_t *new=new_list(list->new_poly,list->free_poly);
linked_element *i=list->tail;
while(i){
add_elem(new,i->ptr);
i=i->prev;
}
return(new);
}
/**** C_block stuff ******************************************************/
static c_block_t *
i_cblock_constructor(cdrom_paranoia_t *p)
{
c_block_t *ret=calloc(1,sizeof(c_block_t));
return(ret);
}
void
i_cblock_destructor(c_block_t *c)
{
if(c){
if(c->vector)free(c->vector);
if(c->flags)free(c->flags);
c->e=NULL;
free(c);
}
}
c_block_t *
new_c_block(cdrom_paranoia_t *p)
{
linked_element *e=new_elem(p->cache);
c_block_t *c=e->ptr;
c->e=e;
c->p=p;
return(c);
}
void free_c_block(c_block_t *c)
{
/* also rid ourselves of v_fragments that reference this block */
v_fragment_t *v=v_first(c->p);
while(v){
v_fragment_t *next=v_next(v);
if(v->one==c)free_v_fragment(v);
v=next;
}
free_elem(c->e,1);
}
static v_fragment_t *
i_vfragment_constructor(void)
{
v_fragment_t *ret=calloc(1,sizeof(v_fragment_t));
return(ret);
}
static void
i_v_fragment_destructor(v_fragment_t *v)
{
free(v);
}
v_fragment_t *
new_v_fragment(cdrom_paranoia_t *p, c_block_t *one,
long int begin, long int end, int last)
{
linked_element *e=new_elem(p->fragments);
v_fragment_t *b=e->ptr;
b->e=e;
b->p=p;
b->one=one;
b->begin=begin;
b->vector=one->vector+begin-one->begin;
b->size=end-begin;
b->lastsector=last;
#if TRACE_PARANOIA
fprintf(stderr, "- Verified [%ld-%ld] (0x%04X...0x%04X)%s\n",
begin, end,
b->vector[0]&0xFFFF, b->vector[b->size-1]&0xFFFF,
last ? " *" : "");
#endif
return(b);
}
void free_v_fragment(v_fragment_t *v)
{
free_elem(v->e,1);
}
c_block_t *
c_first(cdrom_paranoia_t *p)
{
if(p->cache->head)
return(p->cache->head->ptr);
return(NULL);
}
c_block_t *
c_last(cdrom_paranoia_t *p)
{
if(p->cache->tail)
return(p->cache->tail->ptr);
return(NULL);
}
c_block_t *
c_next(c_block_t *c)
{
if(c->e->next)
return(c->e->next->ptr);
return(NULL);
}
c_block_t *
c_prev(c_block_t *c)
{
if(c->e->prev)
return(c->e->prev->ptr);
return(NULL);
}
v_fragment_t *
v_first(cdrom_paranoia_t *p)
{
if(p->fragments->head){
return(p->fragments->head->ptr);
}
return(NULL);
}
v_fragment_t *
v_last(cdrom_paranoia_t *p)
{
if(p->fragments->tail)
return(p->fragments->tail->ptr);
return(NULL);
}
v_fragment_t *
v_next(v_fragment_t *v)
{
if(v->e->next)
return(v->e->next->ptr);
return(NULL);
}
v_fragment_t *
v_prev(v_fragment_t *v)
{
if(v->e->prev)
return(v->e->prev->ptr);
return(NULL);
}
void
recover_cache(cdrom_paranoia_t *p)
{
linked_list_t *l=p->cache;
/* Are we at/over our allowed cache size? */
while(l->active>p->cache_limit)
/* cull from the tail of the list */
free_c_block(c_last(p));
}
int16_t *
v_buffer(v_fragment_t *v)
{
if(!v->one)return(NULL);
if(!cv(v->one))return(NULL);
return(v->vector);
}
/* alloc a c_block not on a cache list */
c_block_t *
c_alloc(int16_t *vector, long begin, long size)
{
c_block_t *c=calloc(1,sizeof(c_block_t));
c->vector=vector;
c->begin=begin;
c->size=size;
return(c);
}
void c_set(c_block_t *v,long begin){
v->begin=begin;
}
/* pos here is vector position from zero */
void
c_insert(c_block_t *v,long pos,int16_t *b,long size)
{
int vs=cs(v);
if(pos<0 || pos>vs)return;
if(v->vector) {
v->vector = realloc(v->vector,sizeof(int16_t)*(size+vs));
} else {
v->vector = calloc(1, sizeof(int16_t)*size);
}
if(pos<vs)memmove(v->vector+pos+size,v->vector+pos,
(vs-pos)*sizeof(int16_t));
memcpy(v->vector+pos,b,size*sizeof(int16_t));
v->size+=size;
}
void
c_remove(c_block_t *v, long cutpos, long cutsize)
{
int vs=cs(v);
if(cutpos<0 || cutpos>vs)return;
if(cutpos+cutsize>vs)cutsize=vs-cutpos;
if(cutsize<0)cutsize=vs-cutpos;
if(cutsize<1)return;
memmove(v->vector+cutpos,v->vector+cutpos+cutsize,
(vs-cutpos-cutsize)*sizeof(int16_t));
v->size-=cutsize;
}
void
c_overwrite(c_block_t *v,long pos,int16_t *b,long size)
{
int vs=cs(v);
if(pos<0)return;
if(pos+size>vs)size=vs-pos;
memcpy(v->vector+pos,b,size*sizeof(int16_t));
}
void
c_append(c_block_t *v, int16_t *vector, long size)
{
int vs=cs(v);
/* update the vector */
if(v->vector)
v->vector=realloc(v->vector,sizeof(int16_t)*(size+vs));
else {
v->vector=calloc(1, sizeof(int16_t)*size);
}
memcpy(v->vector+vs,vector,sizeof(int16_t)*size);
v->size+=size;
}
void
c_removef(c_block_t *v, long cut)
{
c_remove(v,0,cut);
v->begin+=cut;
}
/**** Initialization *************************************************/
/*! Get the beginning and ending sector bounds given cursor position.
There are a couple of subtle differences between this and the
cdda_firsttrack_sector and cdda_lasttrack_sector. If the cursor is
an a sector later than cdda_firsttrack_sector, that sectur will be
used. As for the difference between cdda_lasttrack_sector, if the CD
is mixed and there is a data track after the cursor but before the
last audio track, the end of the audio sector before that is used.
*/
void
i_paranoia_firstlast(cdrom_paranoia_t *p)
{
track_t i, j;
cdrom_drive_t *d=p->d;
const track_t i_first_track = cdio_get_first_track_num(d->p_cdio);
const track_t i_last_track = cdio_get_last_track_num(d->p_cdio);
p->current_lastsector = p->current_firstsector = -1;
i = cdda_sector_gettrack(d, p->cursor);
if ( CDIO_INVALID_TRACK != i ) {
if ( 0 == i ) i++;
j = i;
/* In the below loops, We assume the cursor already is on an audio
sector. Not sure if this is correct if p->cursor is in the pregap
before the first track.
*/
for ( ; i < i_last_track; i++)
if( !cdda_track_audiop(d,i) ) {
p->current_lastsector=cdda_track_lastsector(d,i-1);
break;
}
i = j;
for ( ; i >= i_first_track; i-- )
if( !cdda_track_audiop(d,i) ) {
p->current_firstsector = cdda_track_firstsector(d,i+1);
break;
}
}
if (p->current_lastsector == -1)
p->current_lastsector = cdda_disc_lastsector(d);
if(p->current_firstsector == -1)
p->current_firstsector = cdda_disc_firstsector(d);
}
cdrom_paranoia_t *
paranoia_init(cdrom_drive_t *d)
{
cdrom_paranoia_t *p=calloc(1,sizeof(cdrom_paranoia_t));
p->cache=new_list((void *)&i_cblock_constructor,
(void *)&i_cblock_destructor);
p->fragments=new_list((void *)&i_vfragment_constructor,
(void *)&i_v_fragment_destructor);
p->readahead=150;
p->sortcache=sort_alloc(p->readahead*CD_FRAMEWORDS);
p->d=d;
p->dynoverlap=MAX_SECTOR_OVERLAP*CD_FRAMEWORDS;
p->cache_limit=JIGGLE_MODULO;
p->enable=PARANOIA_MODE_FULL;
p->cursor=cdda_disc_firstsector(d);
p->lastread=LONG_MAX;
/* One last one... in case data and audio tracks are mixed... */
i_paranoia_firstlast(p);
return(p);
}
void paranoia_set_range(cdrom_paranoia_t *p, long start, long end)
{
p->cursor = start;
p->current_firstsector = start;
p->current_lastsector = end;
}

213
lib/paranoia/p_block.h Normal file
View File

@@ -0,0 +1,213 @@
/*
$Id: p_block.h,v 1.6 2008/04/17 17:39:48 karl Exp $
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
Copyright (C) by Monty (xiphmont@mit.edu)
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _P_BLOCK_H_
#define _P_BLOCK_H_
#include <cdio/paranoia.h>
#include <cdio/cdda.h>
#define MIN_WORDS_OVERLAP 64 /* 16 bit words */
#define MIN_WORDS_SEARCH 64 /* 16 bit words */
#define MIN_WORDS_RIFT 16 /* 16 bit words */
#define MAX_SECTOR_OVERLAP 32 /* sectors */
#define MIN_SECTOR_EPSILON 128 /* words */
#define MIN_SECTOR_BACKUP 16 /* sectors */
#define JIGGLE_MODULO 15 /* sectors */
#define MIN_SILENCE_BOUNDARY 1024 /* 16 bit words */
#define min(x,y) ((x)>(y)?(y):(x))
#define max(x,y) ((x)<(y)?(y):(x))
#include "isort.h"
typedef struct {
/* linked list */
struct linked_element *head;
struct linked_element *tail;
void *(*new_poly)();
void (*free_poly)(void *poly);
long current;
long active;
} linked_list_t;
typedef struct linked_element{
void *ptr;
struct linked_element *prev;
struct linked_element *next;
linked_list_t *list;
int stamp;
} linked_element;
extern linked_list_t *new_list(void *(*new_fn)(void),void (*free)(void *));
extern linked_element *new_elem(linked_list_t *list);
extern linked_element *add_elem(linked_list_t *list,void *elem);
extern void free_list(linked_list_t *list,int free_ptr); /* unlink or free */
extern void free_elem(linked_element *e,int free_ptr); /* unlink or free */
extern void *get_elem(linked_element *e);
/* This is a shallow copy; it doesn't copy contained structures */
extern linked_list_t *copy_list(linked_list_t *p_list);
typedef struct c_block {
/* The buffer */
int16_t *vector;
long begin;
long size;
/* auxiliary support structures */
unsigned char *flags; /* 1 known boundaries in read data
2 known blanked data
4 matched sample
8 reserved
16 reserved
32 reserved
64 reserved
128 reserved
*/
/* end of session cases */
long lastsector;
cdrom_paranoia_t *p;
struct linked_element *e;
} c_block_t;
extern void free_c_block(c_block_t *c);
extern void i_cblock_destructor(c_block_t *c);
extern c_block_t *new_c_block(cdrom_paranoia_t *p);
typedef struct v_fragment_s {
c_block_t *one;
long begin;
long size;
int16_t *vector;
/* end of session cases */
long lastsector;
/* linked list */
cdrom_paranoia_t *p;
struct linked_element *e;
} v_fragment_t;
extern void free_v_fragment(v_fragment_t *c);
extern v_fragment_t *new_v_fragment(cdrom_paranoia_t *p, c_block_t *one,
long int begin, long int end,
int lastsector);
extern int16_t *v_buffer(v_fragment_t *v);
extern c_block_t *c_first(cdrom_paranoia_t *p);
extern c_block_t *c_last(cdrom_paranoia_t *p);
extern c_block_t *c_next(c_block_t *c);
extern c_block_t *c_prev(c_block_t *c);
extern v_fragment_t *v_first(cdrom_paranoia_t *p);
extern v_fragment_t *v_last(cdrom_paranoia_t *p);
extern v_fragment_t *v_next(v_fragment_t *v);
extern v_fragment_t *v_prev(v_fragment_t *v);
typedef struct root_block{
long returnedlimit;
long lastsector;
cdrom_paranoia_t *p;
c_block_t *vector; /* doesn't use any sorting */
int silenceflag;
long silencebegin;
} root_block;
typedef struct offsets{
long offpoints;
long newpoints;
long offaccum;
long offdiff;
long offmin;
long offmax;
} offsets;
struct cdrom_paranoia_s {
cdrom_drive_t *d;
root_block root; /* verified/reconstructed cached data */
linked_list_t *cache; /* our data as read from the cdrom */
long int cache_limit;
linked_list_t *fragments; /* fragments of blocks that have been 'verified' */
sort_info_t *sortcache;
int readahead; /* sectors of readahead in each readop */
int jitter;
long lastread;
paranoia_cb_mode_t enable;
long int cursor;
long int current_lastsector;
long int current_firstsector;
/* statistics for drift/overlap */
struct offsets stage1;
struct offsets stage2;
long dynoverlap;
long dyndrift;
/* statistics for verification */
};
extern c_block_t *c_alloc(int16_t *vector,long begin,long size);
extern void c_set(c_block_t *v,long begin);
extern void c_insert(c_block_t *v,long pos,int16_t *b,long size);
extern void c_remove(c_block_t *v,long cutpos,long cutsize);
extern void c_overwrite(c_block_t *v,long pos,int16_t *b,long size);
extern void c_append(c_block_t *v, int16_t *vector, long size);
extern void c_removef(c_block_t *v, long cut);
#define ce(v) (v->begin+v->size)
#define cb(v) (v->begin)
#define cs(v) (v->size)
/* pos here is vector position from zero */
extern void recover_cache(cdrom_paranoia_t *p);
extern void i_paranoia_firstlast(cdrom_paranoia_t *p);
#define cv(c) (c->vector)
#define fe(f) (f->begin+f->size)
#define fb(f) (f->begin)
#define fs(f) (f->size)
#define fv(f) (v_buffer(f))
#ifndef DO_NOT_WANT_PARANOIA_COMPATIBILITY
/** For compatibility with good ol' paranoia */
#define linked_list linked_list_t
#endif /*DO_NOT_WANT_PARANOIA_COMPATIBILITY*/
#define CDP_COMPILE
#endif /*_P_BLOCK_H_*/

Some files were not shown because too many files have changed in this diff Show More