First commit after CVS conversion. Should be just administrative changes.
This commit is contained in:
2
lib/.gitignore
vendored
Normal file
2
lib/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
30
lib/Makefile.am
Normal file
30
lib/Makefile.am
Normal 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)
|
||||
8
lib/cdda_interface/.cvsignore
Normal file
8
lib/cdda_interface/.cvsignore
Normal file
@@ -0,0 +1,8 @@
|
||||
.deps
|
||||
.libs
|
||||
Makefile
|
||||
Makefile.in
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
*.la.ver
|
||||
3
lib/cdda_interface/.gitignore
vendored
Normal file
3
lib/cdda_interface/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/.deps
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
152
lib/cdda_interface/Makefile.am
Normal file
152
lib/cdda_interface/Makefile.am
Normal 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
|
||||
401
lib/cdda_interface/cddap_interface.c
Normal file
401
lib/cdda_interface/cddap_interface.c
Normal 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);
|
||||
}
|
||||
|
||||
271
lib/cdda_interface/common_interface.c
Normal file
271
lib/cdda_interface/common_interface.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
54
lib/cdda_interface/common_interface.h
Normal file
54
lib/cdda_interface/common_interface.h
Normal 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_*/
|
||||
84
lib/cdda_interface/drive_exceptions.c
Normal file
84
lib/cdda_interface/drive_exceptions.c
Normal 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*/
|
||||
58
lib/cdda_interface/drive_exceptions.h
Normal file
58
lib/cdda_interface/drive_exceptions.h
Normal 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
|
||||
188
lib/cdda_interface/interface.c
Normal file
188
lib/cdda_interface/interface.c
Normal 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);
|
||||
}
|
||||
|
||||
22
lib/cdda_interface/libcdio_cdda.sym
Normal file
22
lib/cdda_interface/libcdio_cdda.sym
Normal 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
|
||||
66
lib/cdda_interface/low_interface.h
Normal file
66
lib/cdda_interface/low_interface.h
Normal 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_*/
|
||||
|
||||
335
lib/cdda_interface/scan_devices.c
Normal file
335
lib/cdda_interface/scan_devices.c
Normal 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);
|
||||
}
|
||||
1574
lib/cdda_interface/scsi_interface.c
Normal file
1574
lib/cdda_interface/scsi_interface.c
Normal file
File diff suppressed because it is too large
Load Diff
563
lib/cdda_interface/smallft.c
Normal file
563
lib/cdda_interface/smallft.c
Normal 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);
|
||||
}
|
||||
28
lib/cdda_interface/smallft.h
Normal file
28
lib/cdda_interface/smallft.h
Normal 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);
|
||||
235
lib/cdda_interface/test_interface.c
Normal file
235
lib/cdda_interface/test_interface.c
Normal 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
210
lib/cdda_interface/toc.c
Normal 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
152
lib/cdda_interface/utils.c
Normal 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);
|
||||
}
|
||||
79
lib/cdda_interface/utils.h
Normal file
79
lib/cdda_interface/utils.h
Normal 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
3
lib/cdio++/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/.deps
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
65
lib/cdio++/Makefile.am
Normal file
65
lib/cdio++/Makefile.am
Normal 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
44
lib/cdio++/cdio.cpp
Normal 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
244
lib/cdio++/devices.cpp
Normal 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
295
lib/cdio++/iso9660.cpp
Normal 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
3
lib/driver/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/.deps
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
22
lib/driver/FreeBSD/Makefile
Normal file
22
lib/driver/FreeBSD/Makefile
Normal 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) $@
|
||||
893
lib/driver/FreeBSD/freebsd.c
Normal file
893
lib/driver/FreeBSD/freebsd.c
Normal 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 */
|
||||
}
|
||||
232
lib/driver/FreeBSD/freebsd.h
Normal file
232
lib/driver/FreeBSD/freebsd.h
Normal 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*/
|
||||
257
lib/driver/FreeBSD/freebsd_cam.c
Normal file
257
lib/driver/FreeBSD/freebsd_cam.c
Normal 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 */
|
||||
262
lib/driver/FreeBSD/freebsd_ioctl.c
Normal file
262
lib/driver/FreeBSD/freebsd_ioctl.c
Normal 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 */
|
||||
22
lib/driver/MSWindows/Makefile
Normal file
22
lib/driver/MSWindows/Makefile
Normal 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) $@
|
||||
808
lib/driver/MSWindows/aspi32.c
Normal file
808
lib/driver/MSWindows/aspi32.c
Normal 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 */
|
||||
248
lib/driver/MSWindows/aspi32.h
Normal file
248
lib/driver/MSWindows/aspi32.h
Normal 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
1003
lib/driver/MSWindows/win32.c
Normal file
File diff suppressed because it is too large
Load Diff
239
lib/driver/MSWindows/win32.h
Normal file
239
lib/driver/MSWindows/win32.h
Normal 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);
|
||||
|
||||
1067
lib/driver/MSWindows/win32_ioctl.c
Normal file
1067
lib/driver/MSWindows/win32_ioctl.c
Normal file
File diff suppressed because it is too large
Load Diff
183
lib/driver/Makefile.am
Normal file
183
lib/driver/Makefile.am
Normal 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
513
lib/driver/_cdio_generic.c
Normal 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
224
lib/driver/_cdio_stdio.c
Normal 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
51
lib/driver/_cdio_stdio.h
Normal 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
214
lib/driver/_cdio_stream.c
Normal 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
139
lib/driver/_cdio_stream.h
Normal 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
1026
lib/driver/aix.c
Normal file
File diff suppressed because it is too large
Load Diff
188
lib/driver/audio.c
Normal file
188
lib/driver/audio.c
Normal 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
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
360
lib/driver/cd_types.c
Normal 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
112
lib/driver/cdio.c
Normal 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
59
lib/driver/cdio_assert.h
Normal 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
547
lib/driver/cdio_private.h
Normal 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
253
lib/driver/cdtext.c
Normal 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
139
lib/driver/cdtext_private.h
Normal 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
1038
lib/driver/device.c
Normal file
File diff suppressed because it is too large
Load Diff
119
lib/driver/disc.c
Normal file
119
lib/driver/disc.c
Normal 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
251
lib/driver/ds.c
Normal 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
222
lib/driver/generic.h
Normal 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
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
81
lib/driver/image.h
Normal 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
21
lib/driver/image/Makefile
Normal 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
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
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
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
155
lib/driver/image/nrg.h
Normal 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
373
lib/driver/image_common.c
Normal 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
202
lib/driver/image_common.h
Normal 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
220
lib/driver/libcdio.sym
Normal 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
142
lib/driver/logging.c
Normal 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
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
155
lib/driver/mmc_private.h
Normal 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
656
lib/driver/netbsd.c
Normal 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
1979
lib/driver/osx.c
Normal file
File diff suppressed because it is too large
Load Diff
77
lib/driver/portable.h
Normal file
77
lib/driver/portable.h
Normal 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
329
lib/driver/read.c
Normal 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
268
lib/driver/sector.c
Normal 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
1174
lib/driver/solaris.c
Normal file
File diff suppressed because it is too large
Load Diff
361
lib/driver/track.c
Normal file
361
lib/driver/track.c
Normal 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
210
lib/driver/utf8.c
Normal 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
189
lib/driver/util.c
Normal 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
9
lib/iso9660/.cvsignore
Normal file
@@ -0,0 +1,9 @@
|
||||
.deps
|
||||
.libs
|
||||
Makefile
|
||||
Makefile.in
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
*.la.ver
|
||||
|
||||
3
lib/iso9660/.gitignore
vendored
Normal file
3
lib/iso9660/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/.deps
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
150
lib/iso9660/Makefile.am
Normal file
150
lib/iso9660/Makefile.am
Normal 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
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
1567
lib/iso9660/iso9660_fs.c
Normal file
File diff suppressed because it is too large
Load Diff
83
lib/iso9660/iso9660_private.h
Normal file
83
lib/iso9660/iso9660_private.h
Normal 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:
|
||||
*/
|
||||
81
lib/iso9660/libiso9660.sym
Normal file
81
lib/iso9660/libiso9660.sym
Normal 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
619
lib/iso9660/rock.c
Normal 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
183
lib/iso9660/xa.c
Normal 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
8
lib/paranoia/.cvsignore
Normal file
@@ -0,0 +1,8 @@
|
||||
.deps
|
||||
.libs
|
||||
Makefile
|
||||
Makefile.in
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
*.la.ver
|
||||
3
lib/paranoia/.gitignore
vendored
Normal file
3
lib/paranoia/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/.deps
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
154
lib/paranoia/Makefile.am
Normal file
154
lib/paranoia/Makefile.am
Normal 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
550
lib/paranoia/gap.c
Normal 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
43
lib/paranoia/gap.h
Normal 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
302
lib/paranoia/isort.c
Normal 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
161
lib/paranoia/isort.h
Normal 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_ */
|
||||
|
||||
9
lib/paranoia/libcdio_paranoia.sym
Normal file
9
lib/paranoia/libcdio_paranoia.sym
Normal 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
256
lib/paranoia/overlap.c
Normal 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
33
lib/paranoia/overlap.h
Normal 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
459
lib/paranoia/p_block.c
Normal 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
213
lib/paranoia/p_block.h
Normal 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
Reference in New Issue
Block a user