Initial revision

This commit is contained in:
rocky
2003-03-24 19:01:09 +00:00
commit d4d82912da
48 changed files with 8779 additions and 0 deletions

15
.cvsignore Normal file
View File

@@ -0,0 +1,15 @@
Makefile
Makefile.in
aclocal.m4
autom4te.cache
config.guess
config.h
config.h.in
config.log
config.status
config.sub
configure
libcdio*.tar.gz
libtool
ltmain.sh
stamp-h1

2
AUTHORS Normal file
View File

@@ -0,0 +1,2 @@
Herbert Valerio Riedel <hvr@gnu.org>
Rocky Bernstein <rocky@panix.com>

0
ChangeLog Normal file
View File

30
Makefile.am Normal file
View File

@@ -0,0 +1,30 @@
# $Id: Makefile.am,v 1.1 2003/03/24 19:01:09 rocky Exp $
#
# Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
## Process this file with automake to produce Makefile.in
## which configure then turns into a Makefile ...
## which make can then use to produce stuff. Isn't configuration simple?
EXTRA_DIST = libpopt.m4
# SUBDIRS = doc lib src tests
SUBDIRS = lib src tests

2
NEWS Normal file
View File

@@ -0,0 +1,2 @@
0.1
Routines split off from VCDImager.

3
README Normal file
View File

@@ -0,0 +1,3 @@
This library is to encapsulate CD-ROM reading and control.
Applications wishing to be oblivious of the OS- and device-dependant
properties of a CD-ROM can use this library.

128
autogen.sh Executable file
View File

@@ -0,0 +1,128 @@
#!/bin/sh
# Run this to generate all the initial makefiles, etc.
srcdir=`dirname $0`
PKG_NAME="libcdio"
DIE=0
(autoconf --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: You must have \`autoconf' installed to."
echo "Download the appropriate package for your distribution,"
echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
DIE=1
}
(grep "^AM_PROG_LIBTOOL" $srcdir/configure.ac >/dev/null) && {
(libtool --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: You must have \`libtool' installed."
echo "Get ftp://ftp.gnu.org/pub/gnu/libtool-1.2d.tar.gz"
echo "(or a newer version if it is available)"
DIE=1
}
}
grep "^AM_GNU_GETTEXT" $srcdir/configure.ac >/dev/null && {
grep "sed.*POTFILES" $srcdir/configure.ac >/dev/null || \
(gettext --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: You must have \`gettext' installed."
echo "Get ftp://alpha.gnu.org/gnu/gettext-0.10.35.tar.gz"
echo "(or a newer version if it is available)"
DIE=1
}
}
(automake --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: You must have \`automake' installed."
echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz"
echo "(or a newer version if it is available)"
DIE=1
NO_AUTOMAKE=yes
}
# if no automake, don't bother testing for aclocal
test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: Missing \`aclocal'. The version of \`automake'"
echo "installed doesn't appear recent enough."
echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz"
echo "(or a newer version if it is available)"
DIE=1
}
if test "$DIE" -eq 1; then
exit 1
fi
if test -z "$*"; then
echo "**Warning**: I am going to run \`configure' with no arguments."
echo "If you wish to pass any to it, please specify them on the"
echo \`$0\'" command line."
echo
fi
case $CC in
xlc )
am_opt=--include-deps;;
esac
for coin in `find $srcdir -name configure.ac -print`
do
dr=`dirname $coin`
if test -f $dr/NO-AUTO-GEN; then
echo skipping $dr -- flagged as no auto-gen
else
echo processing $dr
macrodirs=`sed -n -e 's,AM_ACLOCAL_INCLUDE(\(.*\)),\1,gp' < $coin`
( cd $dr
aclocalinclude="$ACLOCAL_FLAGS"
for k in $macrodirs; do
if test -d $k; then
aclocalinclude="$aclocalinclude -I $k"
##else
## echo "**Warning**: No such directory \`$k'. Ignored."
fi
done
if grep "^AM_GNU_GETTEXT" configure.ac >/dev/null; then
if grep "sed.*POTFILES" configure.ac >/dev/null; then
: do nothing -- we still have an old unmodified configure.ac
else
echo "Creating $dr/aclocal.m4 ..."
test -r $dr/aclocal.m4 || touch $dr/aclocal.m4
echo "Running gettextize... Ignore non-fatal messages."
echo "no" | gettextize --force --copy
echo "Making $dr/aclocal.m4 writable ..."
test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4
fi
fi
if grep "^AM_PROG_LIBTOOL" configure.ac >/dev/null; then
echo "Running libtoolize..."
libtoolize --force --copy
fi
echo "Running aclocal $aclocalinclude ..."
aclocal $aclocalinclude
if grep "^AM_CONFIG_HEADER" configure.ac >/dev/null; then
echo "Running autoheader..."
autoheader
fi
echo "Running automake --gnu $am_opt ..."
automake --add-missing --gnu $am_opt
echo "Running autoconf ..."
autoconf
)
fi
done
conf_flags="--enable-maintainer-mode" # --enable-compile-warnings #--enable-iso-c
if test x$NOCONFIGURE = x; then
echo Running $srcdir/configure $conf_flags "$@" ...
$srcdir/configure $conf_flags "$@" \
&& echo Now type \`make\' to compile $PKG_NAME
else
echo Skipping configure process.
fi

174
configure.ac Normal file
View File

@@ -0,0 +1,174 @@
AC_REVISION([$Id: configure.ac,v 1.1 2003/03/24 19:01:09 rocky Exp $])dnl
AC_INIT(lib/cdio.c)
AM_CONFIG_HEADER(config.h)
AM_INIT_AUTOMAKE(libcdio, 0.1)
AM_SANITY_CHECK
dnl Checks for programs.
AC_PROG_CC
if test "x$GCC" != "xyes"
then
echo "*** non GNU CC compiler detected."
echo "*** This package has not been tested very well with non GNU compilers"
echo "*** you should try to use 'gcc' for compiling this package."
else
WARN_CFLAGS="-Wall -Wchar-subscripts -Wmissing-prototypes -Wmissing-declarations -Wunused -Wpointer-arith -Wwrite-strings -Wnested-externs -Wsign-promo -Wno-sign-compare"
for WOPT in $WARN_CFLAGS; do
SAVE_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $WOPT"
AC_MSG_CHECKING([whether $CC understands $WOPT])
AC_TRY_COMPILE([], [], has_option=yes, has_option=no,)
CFLAGS="$SAVE_CFLAGS"
AC_MSG_RESULT($has_option)
if test $has_option = yes; then
warning_flags="$warning_flags $option"
fi
unset has_option
unset SAVE_CFLAGS
done
WARNING_FLAGS="$warning_flags"
unset warning_flags
fi
dnl We use a perl for documentation and regression tests
AC_PATH_PROG(PERL, perl, no)
AC_SUBST(PERL)dnl
dnl AM_PATH_LIBPOPT(, [enable_cli_fe=no; enable_xml_fe=no])
dnl headers
AC_STDC_HEADERS
AC_CHECK_HEADERS(stdint.h inttypes.h stdbool.h)
dnl compiler
AC_C_BIGENDIAN
AC_C_CONST
AC_C_INLINE
dnl ISOC99_PRAGMA
AC_MSG_CHECKING([whether $CC supports ISOC99 _Pragma()])
AC_TRY_COMPILE([],[_Pragma("pack(1)")], [
ISOC99_PRAGMA=yes
AC_DEFINE(HAVE_ISOC99_PRAGMA, [], [Supports ISO _Pragma() macro])
],ISOC99_PRAGMA=no)
AC_MSG_RESULT($ISOC99_PRAGMA)
dnl empty_array_size
AC_MSG_CHECKING([how to create empty arrays])
empty_array_size="xxx"
AC_TRY_COMPILE([],[struct { int foo; int bar[]; } doo;], empty_array_size="")
if test "x$empty_array_size" = "xxxx";then
AC_TRY_COMPILE([],[struct { int foo; int bar[0]; } doo;], empty_array_size="0")
fi
if test "x$empty_array_size" = "xxxx"
then
AC_MSG_ERROR([compiler is unable to creaty empty arrays])
else
AC_DEFINE_UNQUOTED(EMPTY_ARRAY_SIZE, $empty_array_size,
[what to put between the brackets for empty arrays])
changequote(`,')
msg="[${empty_array_size}]"
changequote([,])
AC_MSG_RESULT($msg)
fi
dnl empty_array_size
dnl bitfield order
AC_MSG_CHECKING(bitfield ordering in structs)
AC_TRY_RUN([
int
main() {
struct { char bit_0:1, bit_12:2, bit_345:3, bit_67:2; }
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
__attribute__((packed))
#endif
bf = { 1,1,1,1 };
if (sizeof (bf) != 1) return 1;
return *((unsigned char*) &bf) != 0x4b; }
], bf_lsbf=1, AC_TRY_RUN([
int
main() {
struct { char bit_0:1, bit_12:2, bit_345:3, bit_67:2; }
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
__attribute__((packed))
#endif
bf = { 1,1,1,1 };
if (sizeof (bf) != 1) return 1;
return *((unsigned char*) &bf) != 0xa5; }
], bf_lsbf=0, AC_MSG_ERROR([unsupported bitfield ordering])))
if test "x$bf_lsbf" = "x1"; then
AC_MSG_RESULT(LSBF)
AC_DEFINE(BITFIELD_LSBF, [], [compiler does lsbf in struct bitfields])
else
AC_MSG_RESULT(MSBF)
fi
dnl
dnl system
AC_CYGWIN
LIBS="$LIBS -lm"
CFLAGS="$CFLAGS $WARN_CFLAGS"
AM_CONDITIONAL(CYGWIN, test "x$CYGWIN" = "xyes")
AM_CONDITIONAL(BUILD_CDINFO_LINUX, test "x$enable_cli_fe" = "xyes")
AM_PROG_LIBTOOL
dnl Checks for header files.
AC_STDC_HEADERS
AC_HAVE_HEADERS( stdbool.h stdlib.h stdint.h stdio.h string.h strings.h linux/version.h sys/cdio.h sys/stat.h sys/types.h )
LIBCDIO_CFLAGS='-I$(top_srcdir)/lib/ -I$(top_srcdir)/include/'
LIBCDIO_LIBS='$(top_builddir)/lib/libcdio.la'
AC_SUBST(LIBCDIO_CFLAGS)
AC_SUBST(LIBCDIO_LIBS)
case $host_os in
linux*)
AC_CHECK_HEADERS(linux/version.h)
AC_CHECK_HEADERS(linux/cdrom.h, [have_linux_cdrom_h="yes"])
if test "x$have_linux_cdrom_h" = "xyes" ; then
AC_TRY_COMPILE(,[
#include <linux/cdrom.h>
struct cdrom_generic_command test;
int has_timeout=sizeof(test.timeout);],
[AC_DEFINE([HAVE_LINUX_CDROM_TIMEOUT], [1],
[Define 1 if timeout is in cdrom_generic_command struct])])
AC_DEFINE([HAVE_LINUX_CDROM], [1],
[Define 1 if you have Linux-type CD-ROM support])
fi
;;
bsdi*)
AC_DEFINE([HAVE_BSDI_CDROM], [1],
[Define 1 if you have BSDI-type CD-ROM support])
;;
sunos*|sun*|solaris*)
AC_CHECK_HEADERS(sys/cdio.h)
AC_DEFINE([HAVE_SOLARIS_CDROM], [1],
[Define 1 if you have Solaris CD-ROM support])
;;
*)
AC_MSG_WARN(Don't have OS CD-reading support for ${host_os}...)
AC_MSG_WARN(Will use generic support.)
;;
esac
AC_SUBST(LINUX_CDROM_TIMEOUT)
AC_SUBST(HAVE_LINUX_CDROM)
AC_SUBST(HAVE_BSDI_CDROM)
AC_SUBST(HAVE_SOLARIS_CDROM)
AC_OUTPUT([ \
Makefile \
lib/Makefile \
src/Makefile \
tests/Makefile \
])

7
lib/.cvsignore Normal file
View File

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

77
lib/Makefile.am Normal file
View File

@@ -0,0 +1,77 @@
# $Id: Makefile.am,v 1.1 2003/03/24 19:01:09 rocky Exp $
#
# Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
####################################################
# Things to make the libcdio library
####################################################
#
noinst_HEADERS = cdio_assert.h bytesex.h bytesex_asm.h \
cdio_private.h ds.h
include_HEADERS = cdio.h logging.h sector.h cdio_types.h util.h
libcdio_sources = \
_cdio_bincue.c \
_cdio_bsdi.c \
_cdio_linux.c \
_cdio_nrg.c \
_cdio_stdio.c \
_cdio_stdio.h \
_cdio_stream.c \
_cdio_stream.h \
_cdio_sunos.c \
bytesex.h \
bytesex_asm.h \
cdio.c \
cdio.h \
ds.c \
ds.h \
cdio_types.h \
logging.c \
logging.h \
sector.c \
sector.h \
util.c \
util.h
lib_LTLIBRARIES = libcdio.la
libcdio_la_SOURCES = $(libcdio_sources)
###
# Install header files (default=$includedir/cdio)
#
install-includeHEADERS: $(include_HEADERS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(includedir)/cdio
@list='$(include_HEADERS)'; for p in $$list; do \
if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \
echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/cdio/"; \
$(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/cdio/; \
done
###
# Remove them
#
uninstall-includeHEADERS:
@$(NORMAL_UNINSTALL)
list='$(include_HEADERS)'; for p in $$list; do \
rm -f $(DESTDIR)$(includedir)/cdio/$$p; \
done

581
lib/_cdio_bincue.c Normal file
View File

@@ -0,0 +1,581 @@
/*
$Id: _cdio_bincue.c,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2002,2003 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* This code implements low-level access functions for a CD images
residing inside a disk file (*.bin) and its associated cue sheet.
(*.cue).
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static const char _rcsid[] = "$Id: _cdio_bincue.c,v 1.1 2003/03/24 19:01:09 rocky Exp $";
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "cdio_assert.h"
#include "cdio_private.h"
#include "logging.h"
#include "sector.h"
#include "util.h"
#include "_cdio_stdio.h"
/* reader */
#define DEFAULT_CDIO_DEVICE "videocd.bin"
#define DEFAULT_CDIO_CUE "videocd.cue"
typedef struct {
int blocksize;
int track_num; /* Probably is index+1 */
msf_t start_msf;
int start_index;
int num_indices;
int flags; /* "DCP", "4CH", "PRE" */
track_format_t track_format;
bool track_green;
} track_info_t;
typedef struct {
bool sector_2336_flag;
CdioDataSource *bin_src;
char *source_name;
char *cue_name;
track_info_t tocent[100]; /* entry info for each track */
track_t total_tracks; /* number of tracks in image */
track_t first_track_num; /* track number of first track */
bool have_cue;
bool init;
} _img_private_t;
static bool _cdio_image_read_cue (_img_private_t *_obj);
static uint32_t _cdio_stat_size (void *user_data);
/*!
Initialize image structures.
*/
static bool
_cdio_init (_img_private_t *_obj)
{
if (_obj->init)
return false;
/* Read in CUE sheet. */
if ((_obj->cue_name != NULL)) {
_obj->have_cue == _cdio_image_read_cue(_obj);
}
if (!_obj->have_cue ) {
/* Time to fake things...
Make one big track, track 0 and 1 are the same.
We are guessing stuff atarts a msf 00:04:00 - 2 for the 150
sector pregap and 2 for the cue information.
*/
int blocksize = _obj->sector_2336_flag
? M2RAW_SECTOR_SIZE : CD_RAW_SECTOR_SIZE;
_obj->total_tracks = 2;
_obj->first_track_num = 1;
_obj->tocent[0].start_msf.m = to_bcd8(0);
_obj->tocent[0].start_msf.s = to_bcd8(4);
_obj->tocent[0].start_msf.f = to_bcd8(0);
_obj->tocent[0].blocksize = blocksize;
_obj->tocent[0].track_format= TRACK_FORMAT_XA;
_obj->tocent[0].track_green = true;
_obj->tocent[1] = _obj->tocent[0];
}
if (!(_obj->bin_src = cdio_stdio_new (_obj->source_name))) {
cdio_error ("init failed");
return false;
}
/* Have to set init before calling _cdio_stat_size() or we will
get into infinite recursion calling passing right here.
*/
_obj->init = true;
/* Fake out leadout track. */
cdio_lsn_to_msf ( _cdio_stat_size( (_img_private_t *) _obj),
&_obj->tocent[_obj->total_tracks].start_msf);
return true;
}
/*!
Return the size of the CD in logical block address (LBA) units.
*/
static uint32_t
_cdio_stat_size (void *user_data)
{
_img_private_t *_obj = user_data;
long size;
int blocksize = _obj->sector_2336_flag
? M2RAW_SECTOR_SIZE : CD_RAW_SECTOR_SIZE;
_cdio_init (_obj);
size = cdio_stream_stat (_obj->bin_src);
if (size % blocksize)
{
cdio_warn ("image file not multiple of blocksize (%d)",
blocksize);
if (size % M2RAW_SECTOR_SIZE == 0)
cdio_warn ("this may be a 2336-type disc image");
else if (size % CD_RAW_SECTOR_SIZE == 0)
cdio_warn ("this may be a 2352-type disc image");
/* exit (EXIT_FAILURE); */
}
size /= blocksize;
return size;
}
#define MAXLINE 512
static bool
_cdio_image_read_cue (_img_private_t *_obj)
{
FILE *fp;
char line[MAXLINE];
int track_num;
int min,sec,frame;
int blocksize;
int start_index;
bool seen_first_index_for_track=false;
if ( _obj == NULL || _obj->cue_name == NULL ) return false;
fp = fopen (_obj->cue_name, "r");
if (fp == NULL) return false;
_obj->total_tracks=0;
_obj->first_track_num=1;
while ((fgets(line, MAXLINE, fp)) != NULL) {
char *s=NULL;
char *p;
/*printf("Retrieved line of length %zu :\n", read);
printf("%s", line); */
for (p=line; isspace(*p); p++) ;
if (1==sscanf(p, "FILE \"%a[^\"]", &s)) {
/* Should expand file name based on cue file basename.
free(_obj->bin_file);
_obj->bin_file = s;
*/
/* printf("Found file name %s\n", s); */
} else if (2==sscanf(p, "TRACK %d MODE2/%d", &track_num, &blocksize)) {
_obj->tocent[_obj->total_tracks].blocksize = blocksize;
_obj->tocent[_obj->total_tracks].track_num = track_num;
_obj->tocent[_obj->total_tracks].num_indices = 0;
_obj->tocent[_obj->total_tracks].track_format= TRACK_FORMAT_XA;
_obj->tocent[_obj->total_tracks].track_green = true;
_obj->total_tracks++;
seen_first_index_for_track=false;
/*printf("Added track %d with blocksize %d\n", track_num, blocksize);*/
} else if (2==sscanf(p, "TRACK %d MODE1/%d", &track_num, &blocksize)) {
_obj->tocent[_obj->total_tracks].blocksize = blocksize;
_obj->tocent[_obj->total_tracks].track_num = track_num;
_obj->tocent[_obj->total_tracks].num_indices = 0;
_obj->tocent[_obj->total_tracks].track_format= TRACK_FORMAT_CDI;
_obj->tocent[_obj->total_tracks].track_green = false;
_obj->total_tracks++;
seen_first_index_for_track=false;
/*printf("Added track %d with blocksize %d\n", track_num, blocksize);*/
} else if (1==sscanf(p, "TRACK %d AUDIO", &track_num)) {
_obj->tocent[_obj->total_tracks].blocksize = blocksize;
_obj->tocent[_obj->total_tracks].track_num = track_num;
_obj->tocent[_obj->total_tracks].num_indices = 0;
_obj->tocent[_obj->total_tracks].track_format= TRACK_FORMAT_AUDIO;
_obj->tocent[_obj->total_tracks].track_green = false;
_obj->total_tracks++;
seen_first_index_for_track=false;
} else if (4==sscanf(p, "INDEX %d %d:%d:%d",
&start_index, &min, &sec, &frame)) {
/* FIXME! all of this is a big hack.
If start_index == 0, then this is the "last_cue" information.
The +2 below seconds is to adjust for the 150 pregap.
*/
if (!seen_first_index_for_track && start_index != 0) {
_obj->tocent[_obj->total_tracks-1].start_index = start_index;
_obj->tocent[_obj->total_tracks-1].start_msf.m = to_bcd8 (min);
_obj->tocent[_obj->total_tracks-1].start_msf.s = to_bcd8 (sec)+2;
_obj->tocent[_obj->total_tracks-1].start_msf.f = to_bcd8 (frame);
seen_first_index_for_track=true;
}
_obj->tocent[_obj->total_tracks-1].num_indices++;
}
}
_obj->have_cue = _obj->total_tracks != 0;
fclose (fp);
return true;
}
/*!
Release and free resources used here.
*/
static void
_cdio_free (void *user_data)
{
_img_private_t *_obj = user_data;
free (_obj->source_name);
if (_obj->bin_src)
cdio_stream_destroy (_obj->bin_src);
free (_obj);
}
static int
_read_mode2_sector (void *user_data, void *data, uint32_t lsn,
bool mode2_form2)
{
_img_private_t *_obj = user_data;
char buf[CD_RAW_SECTOR_SIZE] = { 0, };
int blocksize = _obj->sector_2336_flag
? M2RAW_SECTOR_SIZE : CD_RAW_SECTOR_SIZE;
_cdio_init (_obj);
cdio_stream_seek (_obj->bin_src, lsn * blocksize);
cdio_stream_read (_obj->bin_src,
_obj->sector_2336_flag ? (buf + 12 + 4) : buf,
blocksize, 1);
if (mode2_form2)
memcpy (data, buf + 12 + 4, M2RAW_SECTOR_SIZE);
else
memcpy (data, buf + 12 + 4 + 8, M2F1_SECTOR_SIZE);
return 0;
}
/*!
Reads nblocks of mode2 sectors from cd device into data starting
from lsn.
Returns 0 if no error.
*/
static int
_read_mode2_sectors (void *user_data, void *data, uint32_t lsn,
bool mode2_form2, unsigned nblocks)
{
_img_private_t *_obj = user_data;
int i;
int retval;
for (i = 0; i < nblocks; i++) {
if (mode2_form2) {
if ( (retval = _read_mode2_sector (_obj,
((char *)data) + (M2RAW_SECTOR_SIZE * i),
lsn + i, true)) )
return retval;
} else {
char buf[M2RAW_SECTOR_SIZE] = { 0, };
if ( (retval = _read_mode2_sector (_obj, buf, lsn + i, true)) )
return retval;
memcpy (((char *)data) + (M2F1_SECTOR_SIZE * i), buf + 8,
M2F1_SECTOR_SIZE);
}
}
return 0;
}
/*!
Set the device to use in I/O operations.
*/
static int
_cdio_set_arg (void *user_data, const char key[], const char value[])
{
_img_private_t *_obj = user_data;
if (!strcmp (key, "source"))
{
free (_obj->source_name);
if (!value)
return -2;
_obj->source_name = strdup (value);
}
else if (!strcmp (key, "sector"))
{
if (!strcmp (value, "2336"))
_obj->sector_2336_flag = true;
else if (!strcmp (value, "2352"))
_obj->sector_2336_flag = false;
else
return -2;
}
else if (!strcmp (key, "cue"))
{
free (_obj->cue_name);
if (!value)
return -2;
_obj->cue_name = strdup (value);
}
else
return -1;
return 0;
}
/*!
Eject media -- there's nothing to do here. We always return 2.
also free obj.
*/
static int
_cdio_eject_media (void *user_data) {
/* Sort of a stub here. Perhaps log a message? */
return 2;
}
/*!
Return the value associated with the key "arg".
*/
static const char *
_cdio_get_arg (void *user_data, const char key[])
{
_img_private_t *_obj = user_data;
if (!strcmp (key, "source")) {
return _obj->source_name;
} else if (!strcmp (key, "cue")) {
return _obj->cue_name;
}
return NULL;
}
/*!
Return a string containing the default VCD device if none is specified.
*/
static char *
_cdio_get_default_device()
{
return strdup(DEFAULT_CDIO_DEVICE);
}
/*!
Return the number of of the first track.
CDIO_INVALID_TRACK is returned on error.
*/
static track_t
_cdio_get_first_track_num(void *user_data)
{
_img_private_t *_obj = user_data;
_cdio_init (_obj);
return _obj->first_track_num;
}
/*!
Return the number of tracks in the current medium.
If no cuesheet is available, We fake it an just say there's
one big track.
CDIO_INVALID_TRACK is returned on error.
*/
static track_t
_cdio_get_num_tracks(void *user_data)
{
_img_private_t *_obj = user_data;
_cdio_init (_obj);
return _obj->have_cue && _obj->total_tracks > 0 ? _obj->total_tracks : 1;
}
/*!
Return the number of tracks in the current medium.
CDIO_INVALID_TRACK is returned on error.
*/
static track_format_t
_cdio_get_track_format(void *user_data, track_t track_num)
{
_img_private_t *_obj = user_data;
if (!_obj->init) _cdio_init(_obj);
if (track_num > _obj->total_tracks || track_num == 0)
return TRACK_FORMAT_ERROR;
return _obj->tocent[track_num-1].track_format;
}
/*!
Return true if we have XA data (green, mode2 form1) or
XA data (green, mode2 form2). That is track begins:
sync - header - subheader
12 4 - 8
FIXME: there's gotta be a better design for this and get_track_format?
*/
static bool
_cdio_get_track_green(void *user_data, track_t track_num)
{
_img_private_t *_obj = user_data;
if (!_obj->init) _cdio_init(_obj);
if (track_num > _obj->total_tracks || track_num == 0)
return false;
return _obj->tocent[track_num-1].track_green;
}
/*!
Return the starting MSF (minutes/secs/frames) for the track number
track_num in obj. Tracks numbers start at 1.
Since there are no tracks, unless the track number is is 1 we return
falure. If the track number is 1, we return 00:00:00.
*/
static bool
_cdio_get_track_msf(void *user_data, track_t track_num, msf_t *msf)
{
_img_private_t *_obj = user_data;
_cdio_init (_obj);
if (NULL == msf) return false;
if (track_num == CDIO_LEADOUT_TRACK) track_num = _obj->total_tracks+1;
if (track_num <= _obj->total_tracks+1 && track_num != 0) {
*msf = _obj->tocent[track_num-1].start_msf;
return true;
} else
return false;
}
CdIo *
cdio_open_bincue (const char *source_name)
{
CdIo *ret;
_img_private_t *_data;
cdio_funcs _funcs = {
.eject_media = _cdio_eject_media,
.free = _cdio_free,
.get_arg = _cdio_get_arg,
.get_default_device = _cdio_get_default_device,
.get_first_track_num= _cdio_get_first_track_num,
.get_num_tracks = _cdio_get_num_tracks,
.get_track_format = _cdio_get_track_format,
.get_track_green = _cdio_get_track_green,
.get_track_lba = NULL, /* This could be implemented if need be. */
.get_track_msf = _cdio_get_track_msf,
.read_mode2_sector = _read_mode2_sector,
.read_mode2_sectors = _read_mode2_sectors,
.set_arg = _cdio_set_arg,
.stat_size = _cdio_stat_size
};
_data = _cdio_malloc (sizeof (_img_private_t));
_data->init = false;
/* FIXME: should set cue initially. */
_data->cue_name = NULL;
ret = cdio_new (_data, &_funcs);
if (ret == NULL) return NULL;
_cdio_set_arg(_data, "source", (NULL == source_name)
? DEFAULT_CDIO_DEVICE: source_name);
return ret;
}
CdIo *
cdio_open_cue (const char *cue_name)
{
CdIo *ret;
_img_private_t *_data;
cdio_funcs _funcs = {
.eject_media = _cdio_eject_media,
.free = _cdio_free,
.get_arg = _cdio_get_arg,
.get_default_device = _cdio_get_default_device,
.get_first_track_num= _cdio_get_first_track_num,
.get_num_tracks = _cdio_get_num_tracks,
.get_track_format = _cdio_get_track_format,
.get_track_green = _cdio_get_track_green,
.get_track_lba = NULL, /* This could be implemented if need be. */
.get_track_msf = _cdio_get_track_msf,
.read_mode2_sector = _read_mode2_sector,
.read_mode2_sectors = _read_mode2_sectors,
.set_arg = _cdio_set_arg,
.stat_size = _cdio_stat_size
};
_data = _cdio_malloc (sizeof (_img_private_t));
_data->init = false;
if (cue_name != NULL) {
char *source_name=strdup(cue_name);
int i=strlen(source_name)-strlen("cue");
if (i>0) {
if (cue_name[i]=='c' && cue_name[i+1]=='u' && cue_name[i+2]=='e') {
source_name[i++]='b'; source_name[i++]='i'; source_name[i++]='n';
}
else if (cue_name[i]=='C' && cue_name[i+1]=='U' && cue_name[i+2]=='E') {
source_name[i++]='B'; source_name[i++]='I'; source_name[i++]='N';
}
}
_cdio_set_arg (_data, "cue", cue_name);
_cdio_set_arg (_data, "source", source_name);
free(source_name);
}
ret = cdio_new (_data, &_funcs);
if (ret == NULL) return NULL;
if (_cdio_init(_data))
return ret;
else {
_cdio_free (_data);
return NULL;
}
}
bool
cdio_have_bincue (void)
{
return true;
}

441
lib/_cdio_bsdi.c Normal file
View File

@@ -0,0 +1,441 @@
/*
$Id: _cdio_bsdi.c,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "cdio_assert.h"
#include "cdio_private.h"
#include "util.h"
#include "sector.h"
#include "logging.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static const char _rcsid[] = "$Id: _cdio_bsdi.c,v 1.1 2003/03/24 19:01:09 rocky Exp $";
#if HAVE_BSDI_CDROM
#include </sys/dev/scsi/scsi.h>
#include </sys/dev/scsi/scsi_ioctl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
/* reader */
typedef struct {
int fd;
enum {
_AM_NONE,
_AM_READ_CD,
_AM_READ_10
} access_mode;
char *source_name;
bool init;
} _img_private_t;
static int
_scsi_cmd (int fd, struct scsi_user_cdb *sucp, const char *tag)
{
u_char *cp;
if (ioctl (fd, SCSIRAWCDB, sucp))
{
vcd_error ("%s: ioctl (SCSIRAWCDB): %s", tag, strerror (errno));
return 1;
}
if (sucp->suc_sus.sus_status)
{
cp = sucp->suc_sus.sus_sense;
vcd_info("%s: cmd: %x sus_status %d ", tag, sucp->suc_cdb[0],
sucp->suc_sus.sus_status);
vcd_info(" sense: %x %x %x %x %x %x %x %x", cp[0], cp[1], cp[2],
cp[3], cp[4], cp[5], cp[6], cp[7]);
return 1;
}
return 0;
}
/*!
Initialize CD device.
*/
static bool
_cdio_init (_img_private_t *_obj)
{
if (_obj->init)
return;
_obj->fd = open (_obj->source_name, O_RDONLY, 0);
_obj->access_mode = _AM_READ_CD;
if (_obj->fd < 0)
{
cdio_error ("open (%s): %s", _obj->source_name, strerror (errno));
return false;
}
_obj->init = true;
_obj->toc_init = false;
return true;
}
/*!
Release and free resources associated with cd.
*/
static void
_cdio_free (void *user_data)
{
_img_private_t *_obj = user_data;
free (_obj->source_name);
if (_obj->fd)
close (_obj->fd);
free (_obj);
}
static int
_set_bsize (int fd, unsigned bsize)
{
struct
{
uint8_t reserved1;
uint8_t medium;
uint8_t reserved2;
uint8_t block_desc_length;
uint8_t density;
uint8_t number_of_blocks_hi;
uint8_t number_of_blocks_med;
uint8_t number_of_blocks_lo;
uint8_t reserved3;
uint8_t block_length_hi;
uint8_t block_length_med;
uint8_t block_length_lo;
} mh;
struct scsi_user_cdb suc;
memset (&mh, 0, sizeof (mh));
memset (&suc, 0, sizeof (struct scsi_user_cdb));
suc.suc_cdb[0] = 0x15;
suc.suc_cdb[1] = 1 << 4;
suc.suc_cdb[4] = 12;
suc.suc_cdblen = 6;;
suc.suc_data = (u_char *)&mh;
suc.suc_datalen = sizeof (mh);
suc.suc_timeout = 500;
suc.suc_flags = SUC_WRITE;
mh.block_desc_length = 0x08;
mh.block_length_hi = (bsize >> 16) & 0xff;
mh.block_length_med = (bsize >> 8) & 0xff;
mh.block_length_lo = (bsize >> 0) & 0xff;
return _scsi_cmd (fd, &suc, "_set_bsize");
}
static int
_read_mode2 (int fd, void *buf, uint32_t lba, unsigned nblocks,
bool _workaround)
{
struct scsi_user_cdb suc;
int retval = 0;
memset (&suc, 0, sizeof (struct scsi_user_cdb));
suc.suc_cdb[0] = (_workaround
? 0x28 /* CMD_READ_10 */
: 0xbe /* CMD_READ_CD */);
if (!_workaround)
suc.suc_cdb[1] = 0; /* sector size mode2 */
suc.suc_cdb[2] = (lba >> 24) & 0xff;
suc.suc_cdb[3] = (lba >> 16) & 0xff;
suc.suc_cdb[4] = (lba >> 8) & 0xff;
suc.suc_cdb[5] = (lba >> 0) & 0xff;
suc.suc_cdb[6] = (nblocks >> 16) & 0xff;
suc.suc_cdb[7] = (nblocks >> 8) & 0xff;
suc.suc_cdb[8] = (nblocks >> 0) & 0xff;
if (!_workaround)
suc.suc_cdb[9] = 0x58; /* 2336 mode2 mixed form */
suc.suc_cdblen = _workaround ? 10 : 12;
suc.suc_data = buf;
suc.suc_datalen = 2336 * nblocks;
suc.suc_timeout = 500;
suc.suc_flags = SUC_READ;
if (_workaround)
{
if ((retval = _set_bsize (fd, 2336)))
goto out;
if ((retval = _scsi_cmd(fd, &suc, "_read_mode2_workaround")))
{
_set_bsize (fd, 2048);
goto out;
}
retval = _set_bsize (fd, 2048);
}
else
retval = _scsi_cmd(fd, &suc, "_read_mode2");
out:
return retval;
}
static int
_read_mode2_sector (void *user_data, void *data, uint32_t lsn, bool form2)
{
_img_private_t *_obj = user_data;
_cdio_init (_obj);
if (form2)
{
retry:
switch (_obj->access_mode)
{
case _AM_NONE:
vcd_error ("no way to read mode2");
return 1;
break;
case _AM_READ_CD:
case _AM_READ_10:
if (_read_mode2 (_obj->fd, data, lsn, 1,
(_obj->access_mode == _AM_READ_10)))
{
if (_obj->access_mode == _AM_READ_CD)
{
vcd_info ("READ_CD failed; switching to READ_10 mode...");
_obj->access_mode = _AM_READ_10;
goto retry;
}
else
{
vcd_info ("READ_10 failed; no way to read mode2 left.");
_obj->access_mode = _AM_NONE;
goto retry;
}
return 1;
}
break;
}
}
else
{
char buf[M2RAW_SIZE] = { 0, };
int retval;
if ((retval = _read_mode2_sector (_obj, buf, lsn, true)))
return retval;
memcpy (data, buf + 8, M2F1_SECTOR_SIZE);
}
return 0;
}
static const u_char scsi_cdblen[8] = {6, 10, 10, 12, 12, 12, 10, 10};
static uint32_t
_cdio_stat_size (void *user_data)
{
_img_private_t *_obj = user_data;
struct scsi_user_cdb suc;
uint8_t buf[12] = { 0, };
uint32_t retval;
_cdio_init(_obj);
memset (&suc, 0, sizeof (struct scsi_user_cdb));
suc.suc_cdb[0] = 0x43; /* CMD_READ_TOC_PMA_ATIP */
suc.suc_cdb[1] = 0; /* lba; msf: 0x2 */
suc.suc_cdb[6] = 0xaa; /* CDROM_LEADOUT */
suc.suc_cdb[8] = 12; /* ? */
suc.suc_cdblen = 10;
suc.suc_data = buf;
suc.suc_datalen = sizeof (buf);
suc.suc_timeout = 500;
suc.suc_flags = SUC_READ;
if (_scsi_cmd(_obj->fd, &suc, "_cdio_stat_size"))
return 0;
{
int i;
retval = 0;
for (i = 8; i < 12; i++)
{
retval <<= 8;
retval += buf[i];
}
}
return retval;
}
/*!
Return the value associated with the key "arg".
*/
static const char *
_cdio_get_arg (void *user_data, const char key[])
{
_img_private_t *_obj = user_data;
if (!strcmp (key, "source")) {
return _obj->source_name;
} else if (!strcmp (key, "access-mode")) {
switch (_obj->access_mode) {
case _AM_READ_CD:
return "READ_CD";
case _AM_READ_10:
return "READ_10";
case _AM_NONE:
return "no access method";
}
}
return NULL;
}
/*!
Return a string containing the default VCD device if none is specified.
*/
static char *
_cdio_get_default_device()
{
return strdup(DEFAULT_CDIO_DEVICE);
}
/*!
Set the key "arg" to "value" in source device.
*/
static int
_cdio_set_arg (void *user_data, const char key[], const char value[])
{
_img_private_t *_obj = user_data;
if (!strcmp (key, "source"))
{
if (!value)
return -2;
free (_obj->source_name);
_obj->source_name = strdup (value);
}
else if (!strcmp (key, "access-mode"))
{
if (!strcmp(value, "READ_CD"))
_obj->access_mode = _AM_READ_CD;
else if (!strcmp(value, "READ_10"))
_obj->access_mode = _AM_READ_10;
else
cdio_error ("unknown access type: %s. ignored.", value);
}
else
return -1;
return 0;
}
#endif /* HAVE_BSDI_CDROM */
CdIo *
cdio_open_bsdi (const char *source_name)
{
#ifdef HAVE_BSDI_CDROM
_img_private_t *_data;
cdio_funcs _funcs = {
.eject_media = _cdio_eject_media,
.free = _cdio_free,
.get_arg = _cdio_get_arg,
.get_default_device = _cdio_get_default_device,
.read_mode2_sector = _read_mode2_sector,
.set_arg = _cdio_set_arg,
.stat_size = _cdio_stat_size
};
_data = _cdio_malloc (sizeof (_img_private_t));
_data->access_mode = _AM_READ_CD;
_data->init = false;
_data->fd = -1;
_cdio_set_arg(_data, "source", (NULL == source_name)
? DEFAULT_CDIO_DEVICE: source_name);
ret = cdio_new (_data, &_funcs);
if (ret == NULL) return NULL;
if (_cdio_init(_data))
return ret;
else {
_cdio_free (_data);
return NULL;
}
#else
return NULL;
#endif /* HAVE_BSDI_CDROM */
}
bool
cdio_have_bsdi (void)
{
#ifdef HAVE_BSDI_CDROM
return true;
#else
return false;
#endif /* HAVE_BSDI_CDROM */
}

29
lib/_cdio_bsdi.h Normal file
View File

@@ -0,0 +1,29 @@
/*
$Id: _cdio_bsdi.h,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __VCD_IMAGE_BSDICD_H__
#define __VCD_IMAGE_BSDICD_H__
#include <libvcd/vcd_image.h>
VcdImageSource *
vcd_image_source_new_bsdicd (void);
#endif /* __VCD_IMAGE_BSDICD_H__ */

725
lib/_cdio_linux.c Normal file
View File

@@ -0,0 +1,725 @@
/*
$Id: _cdio_linux.c,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2002,2003 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* This file contains Linux-specific code and implements low-level
control of the CD drive.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static const char _rcsid[] = "$Id: _cdio_linux.c,v 1.1 2003/03/24 19:01:09 rocky Exp $";
#include "cdio_assert.h"
#include "cdio_private.h"
#include "sector.h"
#include "util.h"
#ifdef HAVE_LINUX_CDROM
#if defined(HAVE_LINUX_VERSION_H)
# include <linux/version.h>
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16)
# define __CDIO_LINUXCD_BUILD
# else
# error "You need a kernel greater than 2.2.16 to have CDROM support"
# endif
#else
# error "You need <linux/version.h> to have CDROM support"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/cdrom.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#define DEFAULT_CDIO_DEVICE "/dev/cdrom"
#define TOTAL_TRACKS (_obj->tochdr.cdth_trk1)
#define FIRST_TRACK_NUM (_obj->tochdr.cdth_trk0)
typedef struct {
int fd;
int ioctls_debugged; /* for debugging */
enum {
_AM_NONE,
_AM_IOCTL,
_AM_READ_CD,
_AM_READ_10
} access_mode;
char *source_name;
bool init;
/* Track information */
bool toc_init; /* if true, info below is valid. */
struct cdrom_tochdr tochdr;
struct cdrom_tocentry tocent[100]; /* entry info for each track */
} _img_private_t;
/*!
Initialize CD device.
*/
static bool
_cdio_init (_img_private_t *_obj)
{
if (_obj->init) {
cdio_error ("init called more than once");
return false;
}
_obj->fd = open (_obj->source_name, O_RDONLY, 0);
if (_obj->fd < 0)
{
cdio_error ("open (%s): %s", _obj->source_name, strerror (errno));
return false;
}
_obj->init = true;
_obj->toc_init = false;
return true;
}
/*!
Release and free resources associated with cd.
*/
static void
_cdio_free (void *user_data)
{
_img_private_t *_obj = user_data;
if (NULL == _obj) return;
free (_obj->source_name);
if (_obj->fd >= 0)
close (_obj->fd);
free (_obj);
}
static int
_set_bsize (int fd, unsigned bsize)
{
struct cdrom_generic_command cgc;
struct
{
uint8_t reserved1;
uint8_t medium;
uint8_t reserved2;
uint8_t block_desc_length;
uint8_t density;
uint8_t number_of_blocks_hi;
uint8_t number_of_blocks_med;
uint8_t number_of_blocks_lo;
uint8_t reserved3;
uint8_t block_length_hi;
uint8_t block_length_med;
uint8_t block_length_lo;
} mh;
memset (&mh, 0, sizeof (mh));
memset (&cgc, 0, sizeof (struct cdrom_generic_command));
cgc.cmd[0] = 0x15;
cgc.cmd[1] = 1 << 4;
cgc.cmd[4] = 12;
cgc.buflen = sizeof (mh);
cgc.buffer = (void *) &mh;
cgc.data_direction = CGC_DATA_WRITE;
mh.block_desc_length = 0x08;
mh.block_length_hi = (bsize >> 16) & 0xff;
mh.block_length_med = (bsize >> 8) & 0xff;
mh.block_length_lo = (bsize >> 0) & 0xff;
return ioctl (fd, CDROM_SEND_PACKET, &cgc);
}
static int
__read_mode2 (int fd, void *buf, lba_t lba, unsigned nblocks,
bool _workaround)
{
struct cdrom_generic_command cgc;
memset (&cgc, 0, sizeof (struct cdrom_generic_command));
cgc.cmd[0] = _workaround ? GPCMD_READ_10 : GPCMD_READ_CD;
cgc.cmd[2] = (lba >> 24) & 0xff;
cgc.cmd[3] = (lba >> 16) & 0xff;
cgc.cmd[4] = (lba >> 8) & 0xff;
cgc.cmd[5] = (lba >> 0) & 0xff;
cgc.cmd[6] = (nblocks >> 16) & 0xff;
cgc.cmd[7] = (nblocks >> 8) & 0xff;
cgc.cmd[8] = (nblocks >> 0) & 0xff;
if (!_workaround)
{
cgc.cmd[1] = 0; /* sector size mode2 */
cgc.cmd[9] = 0x58; /* 2336 mode2 */
}
cgc.buflen = 2336 * nblocks;
cgc.buffer = buf;
#ifdef HAVE_LINUX_CDROM_TIMEOUT
cgc.timeout = 500;
#endif
cgc.data_direction = CGC_DATA_READ;
if (_workaround)
{
int retval;
if ((retval = _set_bsize (fd, 2336)))
return retval;
if ((retval = ioctl (fd, CDROM_SEND_PACKET, &cgc)))
{
_set_bsize (fd, 2048);
return retval;
}
if ((retval = _set_bsize (fd, 2048)))
return retval;
}
else
return ioctl (fd, CDROM_SEND_PACKET, &cgc);
return 0;
}
static int
_read_mode2 (int fd, void *buf, lba_t lba, unsigned nblocks,
bool _workaround)
{
unsigned l = 0;
int retval = 0;
while (nblocks > 0)
{
const unsigned nblocks2 = (nblocks > 25) ? 25 : nblocks;
void *buf2 = ((char *)buf ) + (l * 2336);
retval |= __read_mode2 (fd, buf2, lba + l, nblocks2, _workaround);
if (retval)
break;
nblocks -= nblocks2;
l += nblocks2;
}
return retval;
}
/*!
Reads a single mode2 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
static int
_read_mode2_sector (void *user_data, void *data, lsn_t lsn,
bool mode2_form2)
{
char buf[M2RAW_SECTOR_SIZE] = { 0, };
struct cdrom_msf *msf = (struct cdrom_msf *) &buf;
msf_t _msf;
_img_private_t *_obj = user_data;
cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf);
msf->cdmsf_min0 = from_bcd8(_msf.m);
msf->cdmsf_sec0 = from_bcd8(_msf.s);
msf->cdmsf_frame0 = from_bcd8(_msf.f);
if (_obj->ioctls_debugged == 75)
cdio_debug ("only displaying every 75th ioctl from now on");
if (_obj->ioctls_debugged == 30 * 75)
cdio_debug ("only displaying every 30*75th ioctl from now on");
if (_obj->ioctls_debugged < 75
|| (_obj->ioctls_debugged < (30 * 75)
&& _obj->ioctls_debugged % 75 == 0)
|| _obj->ioctls_debugged % (30 * 75) == 0)
cdio_debug ("reading %2.2d:%2.2d:%2.2d",
msf->cdmsf_min0, msf->cdmsf_sec0, msf->cdmsf_frame0);
_obj->ioctls_debugged++;
retry:
switch (_obj->access_mode)
{
case _AM_NONE:
cdio_error ("no way to read mode2");
return 1;
break;
case _AM_IOCTL:
if (ioctl (_obj->fd, CDROMREADMODE2, &buf) == -1)
{
perror ("ioctl()");
return 1;
/* exit (EXIT_FAILURE); */
}
break;
case _AM_READ_CD:
case _AM_READ_10:
if (_read_mode2 (_obj->fd, buf, lsn, 1,
(_obj->access_mode == _AM_READ_10)))
{
perror ("ioctl()");
if (_obj->access_mode == _AM_READ_CD)
{
cdio_info ("READ_CD failed; switching to READ_10 mode...");
_obj->access_mode = _AM_READ_10;
goto retry;
}
else
{
cdio_info ("READ_10 failed; switching to ioctl(CDROMREADMODE2) mode...");
_obj->access_mode = _AM_IOCTL;
goto retry;
}
return 1;
}
break;
}
if (mode2_form2)
memcpy (data, buf, M2RAW_SECTOR_SIZE);
else
memcpy (((char *)data), buf + 8, M2F1_SECTOR_SIZE);
return 0;
}
/*!
Reads nblocks of mode2 sectors from cd device into data starting
from lsn.
Returns 0 if no error.
*/
static int
_read_mode2_sectors (void *user_data, void *data, lsn_t lsn,
bool mode2_form2, unsigned nblocks)
{
_img_private_t *_obj = user_data;
int i;
int retval;
for (i = 0; i < nblocks; i++) {
if (mode2_form2) {
if ( (retval = _read_mode2_sector (_obj,
((char *)data) + (M2RAW_SECTOR_SIZE * i),
lsn + i, true)) )
return retval;
} else {
char buf[M2RAW_SECTOR_SIZE] = { 0, };
if ( (retval = _read_mode2_sector (_obj, buf, lsn + i, true)) )
return retval;
memcpy (((char *)data) + (M2F1_SECTOR_SIZE * i), buf + 8,
M2F1_SECTOR_SIZE);
}
}
return 0;
}
/*!
Return the size of the CD in logical block address (LBA) units.
*/
static uint32_t
_cdio_stat_size (void *user_data)
{
_img_private_t *_obj = user_data;
struct cdrom_tocentry tocent;
uint32_t size;
tocent.cdte_track = CDROM_LEADOUT;
tocent.cdte_format = CDROM_LBA;
if (ioctl (_obj->fd, CDROMREADTOCENTRY, &tocent) == -1)
{
perror ("ioctl(CDROMREADTOCENTRY)");
exit (EXIT_FAILURE);
}
size = tocent.cdte_addr.lba;
return size;
}
/*!
Set the key "arg" to "value" in source device.
*/
static int
_cdio_set_arg (void *user_data, const char key[], const char value[])
{
_img_private_t *_obj = user_data;
if (!strcmp (key, "source"))
{
if (!value)
return -2;
free (_obj->source_name);
_obj->source_name = strdup (value);
}
else if (!strcmp (key, "access-mode"))
{
if (!strcmp(value, "IOCTL"))
_obj->access_mode = _AM_IOCTL;
else if (!strcmp(value, "READ_CD"))
_obj->access_mode = _AM_READ_CD;
else if (!strcmp(value, "READ_10"))
_obj->access_mode = _AM_READ_10;
else
cdio_error ("unknown access type: %s. ignored.", value);
}
else
return -1;
return 0;
}
/*!
Read and cache the CD's Track Table of Contents and track info.
Return false if successful or true if an error.
*/
static bool
_cdio_read_toc (_img_private_t *_obj)
{
int i;
/* read TOC header */
if ( ioctl(_obj->fd, CDROMREADTOCHDR, &_obj->tochdr) == -1 ) {
cdio_error("%s: %s\n",
"error in ioctl CDROMREADTOCHDR", strerror(errno));
return false;
}
/* read individual tracks */
for (i= FIRST_TRACK_NUM; i<=TOTAL_TRACKS; i++) {
_obj->tocent[i-1].cdte_track = i;
_obj->tocent[i-1].cdte_format = CDROM_MSF;
if ( ioctl(_obj->fd, CDROMREADTOCENTRY, &_obj->tocent[i-1]) == -1 ) {
cdio_error("%s %d: %s\n",
"error in ioctl CDROMREADTOCENTRY for track",
i, strerror(errno));
return false;
}
/****
struct cdrom_msf0 *msf= &_obj->tocent[i-1].cdte_addr.msf;
fprintf (stdout, "--- track# %d (msf %2.2x:%2.2x:%2.2x)\n",
i, msf->minute, msf->second, msf->frame);
****/
}
/* read the lead-out track */
_obj->tocent[TOTAL_TRACKS].cdte_track = CDROM_LEADOUT;
_obj->tocent[TOTAL_TRACKS].cdte_format = CDROM_MSF;
if (ioctl(_obj->fd, CDROMREADTOCENTRY,
&_obj->tocent[TOTAL_TRACKS]) == -1 ) {
cdio_error("%s: %s\n",
"error in ioctl CDROMREADTOCENTRY for lead-out",
strerror(errno));
return false;
}
/*
struct cdrom_msf0 *msf= &_obj->tocent[TOTAL_TRACKS].cdte_addr.msf;
fprintf (stdout, "--- track# %d (msf %2.2x:%2.2x:%2.2x)\n",
i, msf->minute, msf->second, msf->frame);
*/
return true;
}
/*!
Eject media in CD drive. If successful, as a side effect we
also free obj.
*/
static int
_cdio_eject_media (void *user_data) {
_img_private_t *_obj = user_data;
int ret, status;
if (_obj->fd > -1) {
if((status = ioctl(_obj->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT)) > 0) {
switch(status) {
case CDS_TRAY_OPEN:
if((ret = ioctl(_obj->fd, CDROMCLOSETRAY)) != 0) {
cdio_error ("CDROMCLOSETRAY failed: %s\n", strerror(errno));
}
break;
case CDS_DISC_OK:
if((ret = ioctl(_obj->fd, CDROMEJECT)) != 0) {
cdio_error("CDROMEJECT failed: %s\n", strerror(errno));
}
break;
}
_cdio_free((void *) _obj);
return 0;
} else {
cdio_error ("CDROM_DRIVE_STATUS failed: %s\n", strerror(errno));
_cdio_free((void *) _obj);
return 1;
}
}
return 2;
}
/*!
Return the value associated with the key "arg".
*/
static const char *
_cdio_get_arg (void *user_data, const char key[])
{
_img_private_t *_obj = user_data;
if (!strcmp (key, "source")) {
return _obj->source_name;
} else if (!strcmp (key, "access-mode")) {
switch (_obj->access_mode) {
case _AM_IOCTL:
return "ioctl";
case _AM_READ_CD:
return "READ_CD";
case _AM_READ_10:
return "READ_10";
case _AM_NONE:
return "no access method";
}
}
return NULL;
}
/*!
Return a string containing the default VCD device if none is specified.
*/
static char *
_cdio_get_default_device()
{
return strdup(DEFAULT_CDIO_DEVICE);
}
/*!
Return the number of of the first track.
CDIO_INVALID_TRACK is returned on error.
*/
static track_t
_cdio_get_first_track_num(void *user_data)
{
_img_private_t *_obj = user_data;
if (!_obj->toc_init) _cdio_read_toc (_obj) ;
return FIRST_TRACK_NUM;
}
/*!
Return the number of tracks in the current medium.
CDIO_INVALID_TRACK is returned on error.
*/
static track_t
_cdio_get_num_tracks(void *user_data)
{
_img_private_t *_obj = user_data;
if (!_obj->toc_init) _cdio_read_toc (_obj) ;
return TOTAL_TRACKS;
}
/*!
Get format of track.
*/
static track_format_t
_cdio_get_track_format(void *user_data, track_t track_num)
{
_img_private_t *_obj = user_data;
if (!_obj->toc_init) _cdio_read_toc (_obj) ;
if (track_num > TOTAL_TRACKS || track_num == 0)
return TRACK_FORMAT_ERROR;
/* This is pretty much copied from the "badly broken" cdrom_count_tracks
in linux/cdrom.c.
*/
if (_obj->tocent[track_num-1].cdte_ctrl & CDROM_DATA_TRACK) {
if (_obj->tocent[track_num-1].cdte_format == 0x10)
return TRACK_FORMAT_CDI;
else if (_obj->tocent[track_num-1].cdte_format == 0x20)
return TRACK_FORMAT_XA;
else
return TRACK_FORMAT_DATA;
} else
return TRACK_FORMAT_AUDIO;
}
/*!
Return true if we have XA data (green, mode2 form1) or
XA data (green, mode2 form2). That is track begins:
sync - header - subheader
12 4 - 8
FIXME: there's gotta be a better design for this and get_track_format?
*/
static bool
_cdio_get_track_green(void *user_data, track_t track_num)
{
_img_private_t *_obj = user_data;
if (!_obj->toc_init) _cdio_read_toc (_obj) ;
if (track_num == CDIO_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1;
if (track_num > TOTAL_TRACKS+1 || track_num == 0)
return false;
/* FIXME: Dunno if this is the right way, but it's what
I was using in cdinfo for a while.
*/
return ((_obj->tocent[track_num-1].cdte_ctrl & 2) != 0);
}
/*!
Return the starting MSF (minutes/secs/frames) for track number
track_num in obj. Track numbers start at 1.
The "leadout" track is specified either by
using track_num LEADOUT_TRACK or the total tracks+1.
False is returned if there is no track entry.
*/
static bool
_cdio_get_track_msf(void *user_data, track_t track_num, msf_t *msf)
{
_img_private_t *_obj = user_data;
if (NULL == msf) return false;
if (!_obj->toc_init) _cdio_read_toc (_obj) ;
if (track_num == CDIO_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1;
if (track_num > TOTAL_TRACKS+1 || track_num == 0) {
return false;
} else {
struct cdrom_msf0 *msf0= &_obj->tocent[track_num-1].cdte_addr.msf;
msf->m = to_bcd8(msf0->minute);
msf->s = to_bcd8(msf0->second);
msf->f = to_bcd8(msf0->frame);
return true;
}
}
#endif /* HAVE_LINUX_CDROM */
/*!
Initialization routine. This is the only thing that doesn't
get called via a function pointer. In fact *we* are the
ones to set that up.
*/
CdIo *
cdio_open_linux (const char *source_name)
{
#ifdef HAVE_LINUX_CDROM
CdIo *ret;
_img_private_t *_data;
cdio_funcs _funcs = {
.eject_media = _cdio_eject_media,
.free = _cdio_free,
.get_arg = _cdio_get_arg,
.get_default_device = _cdio_get_default_device,
.get_first_track_num= _cdio_get_first_track_num,
.get_num_tracks = _cdio_get_num_tracks,
.get_track_format = _cdio_get_track_format,
.get_track_green = _cdio_get_track_green,
.get_track_lba = NULL, /* This could be implemented if need be. */
.get_track_msf = _cdio_get_track_msf,
.read_mode2_sector = _read_mode2_sector,
.read_mode2_sectors = _read_mode2_sectors,
.set_arg = _cdio_set_arg,
.stat_size = _cdio_stat_size
};
_data = _cdio_malloc (sizeof (_img_private_t));
_data->access_mode = _AM_READ_CD;
_data->init = false;
_data->fd = -1;
_cdio_set_arg(_data, "source", (NULL == source_name)
? DEFAULT_CDIO_DEVICE: source_name);
ret = cdio_new (_data, &_funcs);
if (ret == NULL) return NULL;
if (_cdio_init(_data))
return ret;
else {
_cdio_free (_data);
return NULL;
}
#else
return NULL;
#endif /* HAVE_LINUX_CDROM */
}
bool
cdio_have_linux (void)
{
#ifdef HAVE_LINUX_CDROM
return true;
#else
return false;
#endif /* HAVE_LINUX_CDROM */
}

770
lib/_cdio_nrg.c Normal file
View File

@@ -0,0 +1,770 @@
/*
$Id: _cdio_nrg.c,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2001,2003 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*! This code implements low-level access functions for the Nero native
CD-image format residing inside a disk file (*.nrg).
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cdio_assert.h"
#include "bytesex.h"
#include "ds.h"
#include "cdio_private.h"
#include "logging.h"
#include "sector.h"
#include "util.h"
#include "_cdio_stdio.h"
static const char _rcsid[] = "$Id: _cdio_nrg.c,v 1.1 2003/03/24 19:01:09 rocky Exp $";
/* structures used */
/* this ugly image format is typical for lazy win32 programmers... at
least structure were set big endian, so at reverse
engineering wasn't such a big headache... */
PRAGMA_BEGIN_PACKED
typedef struct {
uint32_t start GNUC_PACKED;
uint32_t length GNUC_PACKED;
uint32_t type GNUC_PACKED; /* only 0x3 seen so far...
-> MIXED_MODE2 2336 blocksize */
uint32_t start_lsn GNUC_PACKED; /* does not include any pre-gaps! */
uint32_t _unknown GNUC_PACKED; /* wtf is this for? -- always zero... */
} _etnf_array_t;
/* finally they realized that 32bit offsets are a bit outdated for IA64 *eg* */
typedef struct {
uint64_t start GNUC_PACKED;
uint64_t length GNUC_PACKED;
uint32_t type GNUC_PACKED;
uint32_t start_lsn GNUC_PACKED;
uint64_t _unknown GNUC_PACKED; /* wtf is this for? -- always zero... */
} _etn2_array_t;
typedef struct {
uint8_t _unknown1 GNUC_PACKED; /* 0x41 == 'A' */
uint8_t track GNUC_PACKED; /* binary or BCD?? */
uint8_t index GNUC_PACKED; /* makes 0->1 transitions */
uint8_t _unknown2 GNUC_PACKED; /* ?? */
uint32_t lsn GNUC_PACKED;
} _cuex_array_t;
typedef struct {
uint32_t id GNUC_PACKED;
uint32_t len GNUC_PACKED;
char data[EMPTY_ARRAY_SIZE] GNUC_PACKED;
} _chunk_t;
PRAGMA_END_PACKED
/* to be converted into BE */
#define CUEX_ID 0x43554558
#define CUES_ID 0x43554553
#define DAOX_ID 0x44414f58
#define DAOI_ID 0x44414f49
#define END1_ID 0x454e4421
#define ETN2_ID 0x45544e32
#define ETNF_ID 0x45544e46
#define NER5_ID 0x4e455235
#define NERO_ID 0x4e45524f
#define SINF_ID 0x53494e46
/* reader */
#define DEFAULT_CDIO_DEVICE "image.nrg"
typedef struct {
int blocksize;
int track_num; /* Probably is index+1 */
msf_t start_msf;
int start_index;
int secsize; /* Number of sectors in track. Does not
include pregap before next entry. */
int flags; /* "DCP", "4CH", "PRE" */
track_format_t track_format;
bool track_green;
} track_info_t;
/*
Link element of track structure as a linked list.
Possibly redundant with above track_info_t */
typedef struct {
uint32_t start_lsn;
uint32_t secsize; /* Number of sectors in track. Does not
include pregap before next entry. */
uint64_t img_offset; /* Bytes offset from beginning of disk image file.*/
} _mapping_t;
typedef struct {
bool sector_2336_flag;
CdioDataSource *nrg_src;
char *source_name;
track_info_t tocent[100]; /* entry info for each track */
track_t total_tracks; /* number of tracks in image */
track_t first_track_num; /* track number of first track */
CdioList *mapping; /* List of track information */
uint32_t size;
bool init;
} _img_private_t;
static bool _cdio_parse_nero_footer (_img_private_t *_obj);
static uint32_t _cdio_stat_size (void *user_data);
/*!
Release and free resources used here.
*/
static void
_cdio_free (void *user_data)
{
_img_private_t *_obj = user_data;
free(_obj->source_name);
if (_obj->nrg_src)
cdio_stream_destroy (_obj->nrg_src);
_cdio_list_free (_obj->mapping, true);
free (_obj);
}
/* Updates internal track TOC, so we can later
simulate ioctl(CDROMREADTOCENTRY).
*/
static void
_register_mapping (_img_private_t *_obj, lsn_t start_lsn, uint32_t secsize,
uint64_t img_offset, uint32_t blocksize)
{
const int track_num=_obj->total_tracks;
_mapping_t *_map = _cdio_malloc (sizeof (_mapping_t));
if (!_obj->mapping)
_obj->mapping = _cdio_list_new ();
_cdio_list_append (_obj->mapping, _map);
_map->start_lsn = start_lsn;
_map->secsize = secsize;
_map->img_offset = img_offset;
_obj->size = MAX (_obj->size, (start_lsn + secsize));
/* Update _obj->tocent[track_num] and track_num These structures are
in a sense redundant witht the obj->mapping list. Perhaps one
or the other can be eliminated.
*/
cdio_lba_to_msf (cdio_lsn_to_lba(start_lsn),
&_obj->tocent[track_num].start_msf);
_obj->tocent[track_num].track_num = track_num+1;
_obj->tocent[track_num].blocksize = blocksize;
_obj->tocent[track_num].secsize = secsize;
_obj->tocent[track_num].secsize = secsize;
_obj->total_tracks++;
/* FIXME: These are probably not right. Probably we need to look at
"type." But this hasn't been reverse engineered yet.
*/
_obj->tocent[track_num].track_format= TRACK_FORMAT_XA;
_obj->tocent[track_num].track_green = true;
/* cdio_debug ("map: %d +%d -> %ld", start_lsn, secsize, img_offset); */
}
/*
Disk and track information for a Nero file are located at the end
of the file. This routine extracts that information.
*/
static bool
_cdio_parse_nero_footer (_img_private_t *_obj)
{
long unsigned int footer_start;
long unsigned int size;
char *footer_buf = NULL;
if (_obj->size)
return 0;
size = cdio_stream_stat (_obj->nrg_src);
{
PRAGMA_BEGIN_PACKED
union {
struct {
uint32_t __x GNUC_PACKED;
uint32_t ID GNUC_PACKED;
uint32_t footer_ofs GNUC_PACKED;
} v50;
struct {
uint32_t ID GNUC_PACKED;
uint64_t footer_ofs GNUC_PACKED;
} v55;
} buf;
PRAGMA_END_PACKED
cdio_assert (sizeof (buf) == 12);
cdio_stream_seek (_obj->nrg_src, size - sizeof (buf));
cdio_stream_read (_obj->nrg_src, (void *) &buf, sizeof (buf), 1);
if (buf.v50.ID == UINT32_TO_BE (0x4e45524f)) /* "NERO" */
{
cdio_info ("detected v50 (32bit offsets) NRG magic");
footer_start = uint32_to_be (buf.v50.footer_ofs);
}
else if (buf.v55.ID == UINT32_TO_BE (0x4e455235)) /* "NER5" */
{
cdio_info ("detected v55 (64bit offsets) NRG magic");
footer_start = uint64_from_be (buf.v55.footer_ofs);
}
else
{
cdio_error ("Image not recognized as either v50 or v55 type NRG");
return -1;
}
cdio_debug ("nrg footer start = %ld, length = %ld",
(long) footer_start, (long) (size - footer_start));
cdio_assert (IN ((size - footer_start), 0, 4096));
footer_buf = _cdio_malloc (size - footer_start);
cdio_stream_seek (_obj->nrg_src, footer_start);
cdio_stream_read (_obj->nrg_src, footer_buf, size - footer_start, 1);
}
{
int pos = 0;
while (pos < size - footer_start) {
_chunk_t *chunk = (void *) (footer_buf + pos);
bool break_out = false;
switch (UINT32_FROM_BE (chunk->id)) {
case CUES_ID: { /* "CUES" */
unsigned entries = UINT32_FROM_BE (chunk->len);
_cuex_array_t *_entries = (void *) chunk->data;
cdio_assert (_obj->mapping == NULL);
cdio_assert (sizeof (_cuex_array_t) == 8);
cdio_assert ( UINT32_FROM_BE(chunk->len) % sizeof(_cuex_array_t)
== 0 );
entries /= sizeof (_cuex_array_t);
cdio_info ("CUES type image detected");
{
lsn_t lsn = UINT32_FROM_BE (_entries[0].lsn);
int idx;
/*cdio_assert (lsn == 0?);*/
_obj->total_tracks = 0;
_obj->first_track_num = 1;
for (idx = 1; idx < entries-1; idx += 2) {
lsn_t lsn2;
cdio_assert (_entries[idx].index == 0);
cdio_assert (_entries[idx].track == _entries[idx + 1].track);
lsn = UINT32_FROM_BE (_entries[idx].lsn);
lsn2 = UINT32_FROM_BE (_entries[idx + 1].lsn);
_register_mapping (_obj, lsn, lsn2 - lsn,
(lsn+CDIO_PREGAP_SECTORS) * CD_RAW_SECTOR_SIZE,
CD_RAW_SECTOR_SIZE);
}
}
break;
}
case CUEX_ID: /* "CUEX" */ {
unsigned entries = UINT32_FROM_BE (chunk->len);
_cuex_array_t *_entries = (void *) chunk->data;
cdio_assert (_obj->mapping == NULL);
cdio_assert ( sizeof (_cuex_array_t) == 8 );
cdio_assert ( UINT32_FROM_BE (chunk->len) % sizeof(_cuex_array_t)
== 0 );
entries /= sizeof (_cuex_array_t);
cdio_info ("DAO type image detected");
{
uint32_t lsn = UINT32_FROM_BE (_entries[0].lsn);
int idx;
cdio_assert (lsn == 0xffffff6a);
for (idx = 2; idx < entries; idx += 2) {
lsn_t lsn2;
cdio_assert (_entries[idx].index == 1);
cdio_assert (_entries[idx].track != _entries[idx + 1].track);
lsn = UINT32_FROM_BE (_entries[idx].lsn);
lsn2 = UINT32_FROM_BE (_entries[idx + 1].lsn);
_register_mapping (_obj, lsn, lsn2 - lsn,
(lsn + CDIO_PREGAP_SECTORS)*M2RAW_SECTOR_SIZE,
M2RAW_SECTOR_SIZE);
}
}
break;
}
case DAOI_ID: /* "DAOI" */
cdio_debug ("DAOI tag detected...");
break;
case DAOX_ID: /* "DAOX" */
cdio_debug ("DAOX tag detected...");
break;
case NER5_ID: /* "NER5" */
cdio_error ("unexpected nrg magic ID NER5 detected");
return -1;
break;
case NERO_ID: /* "NER0" */
cdio_error ("unexpected nrg magic ID NER0 detected");
return -1;
break;
case END1_ID: /* "END!" */
cdio_debug ("nrg end tag detected");
break_out = true;
break;
case ETNF_ID: /* "ETNF" */ {
unsigned entries = UINT32_FROM_BE (chunk->len);
_etnf_array_t *_entries = (void *) chunk->data;
cdio_assert (_obj->mapping == NULL);
cdio_assert ( sizeof (_etnf_array_t) == 20 );
cdio_assert ( UINT32_FROM_BE(chunk->len) % sizeof(_etnf_array_t)
== 0 );
entries /= sizeof (_etnf_array_t);
cdio_info ("SAO type image (ETNF) detected");
_obj->sector_2336_flag = true;
{
int idx;
for (idx = 0; idx < entries; idx++) {
uint32_t _len = UINT32_FROM_BE (_entries[idx].length);
uint32_t _start = UINT32_FROM_BE (_entries[idx].start_lsn);
uint32_t _start2 = UINT32_FROM_BE (_entries[idx].start);
cdio_assert (UINT32_FROM_BE (_entries[idx].type) == 3);
cdio_assert (_len % M2RAW_SECTOR_SIZE == 0);
_len /= M2RAW_SECTOR_SIZE;
cdio_assert (_start * M2RAW_SECTOR_SIZE == _start2);
_start += idx * CDIO_PREGAP_SECTORS;
_register_mapping (_obj, _start, _len, _start2, M2RAW_SECTOR_SIZE);
}
}
break;
}
case ETN2_ID: { /* "ETN2", same as above, but with 64bit stuff instead */
unsigned entries = uint32_from_be (chunk->len);
_etn2_array_t *_entries = (void *) chunk->data;
cdio_assert (_obj->mapping == NULL);
cdio_assert (sizeof (_etn2_array_t) == 32);
cdio_assert (uint32_from_be (chunk->len) % sizeof (_etn2_array_t) == 0);
entries /= sizeof (_etn2_array_t);
cdio_info ("SAO type image (ETN2) detected");
_obj->sector_2336_flag = true;
{
int idx;
for (idx = 0; idx < entries; idx++) {
uint32_t _len = uint64_from_be (_entries[idx].length);
uint32_t _start = uint32_from_be (_entries[idx].start_lsn);
uint32_t _start2 = uint64_from_be (_entries[idx].start);
cdio_assert (uint32_from_be (_entries[idx].type) == 3);
cdio_assert (_len % M2RAW_SECTOR_SIZE == 0);
_len /= M2RAW_SECTOR_SIZE;
cdio_assert (_start * M2RAW_SECTOR_SIZE == _start2);
_start += idx * CDIO_PREGAP_SECTORS;
_register_mapping (_obj, _start, _len, _start2, M2RAW_SECTOR_SIZE);
}
}
break;
}
case SINF_ID: { /* "SINF" */
uint32_t *_sessions = (void *) chunk->data;
cdio_assert (UINT32_FROM_BE (chunk->len) == 4);
cdio_debug ("SINF: %d sessions", UINT32_FROM_BE (*_sessions));
}
break;
default:
cdio_warn ("unknown tag %8.8x seen", UINT32_FROM_BE (chunk->id));
break;
}
if (break_out)
break;
pos += 8;
pos += UINT32_FROM_BE (chunk->len);
}
}
/* Fake out leadout track. */
/* Don't use _cdio_stat_size since that will lead to recursion since
we haven't fully initialized things yet.
*/
cdio_lsn_to_msf (_obj->size, &_obj->tocent[_obj->total_tracks].start_msf);
return 0;
}
/*!
Initialize image structures.
*/
static bool
_cdio_init (_img_private_t *_obj)
{
if (_obj->init) {
cdio_error ("init called more than once");
return false;
}
if (!(_obj->nrg_src = cdio_stdio_new (_obj->source_name))) {
cdio_error ("init failed");
return false;
}
_cdio_parse_nero_footer (_obj);
_obj->init = true;
return true;
}
static uint32_t
_cdio_stat_size (void *user_data)
{
_img_private_t *_obj = user_data;
return _obj->size;
}
static int
_read_mode2_sector (void *user_data, void *data, lsn_t lsn, bool form2)
{
_img_private_t *_obj = user_data;
char buf[CD_RAW_SECTOR_SIZE] = { 0, };
CdioListNode *node;
if (lsn >= _obj->size)
{
cdio_warn ("trying to read beyond image size (%d >= %u)", lsn,
_obj->size);
return -1;
}
_CDIO_LIST_FOREACH (node, _obj->mapping)
{
_mapping_t *_map = _cdio_list_node_data (node);
if (IN (lsn, _map->start_lsn, (_map->start_lsn + _map->secsize - 1)))
{
long img_offset = _map->img_offset;
int blocksize = _obj->sector_2336_flag
? M2RAW_SECTOR_SIZE : CD_RAW_SECTOR_SIZE;
img_offset += (lsn - _map->start_lsn) * blocksize;
cdio_stream_seek (_obj->nrg_src, img_offset);
cdio_stream_read (_obj->nrg_src,
_obj->sector_2336_flag ? (buf + 12 + 4) : buf,
blocksize, 1);
break;
}
}
if (!node)
cdio_warn ("reading into pre gap (lsn %d)", lsn);
if (form2)
memcpy (data, buf + 12 + 4, M2RAW_SECTOR_SIZE);
else
memcpy (data, buf + 12 + 4 + 8, M2F1_SECTOR_SIZE);
return 0;
}
/*!
Reads nblocks of mode2 sectors from cd device into data starting
from lsn.
Returns 0 if no error.
*/
static int
_read_mode2_sectors (void *user_data, void *data, uint32_t lsn,
bool mode2_form2, unsigned nblocks)
{
_img_private_t *_obj = user_data;
int i;
int retval;
for (i = 0; i < nblocks; i++) {
if (mode2_form2) {
if ( (retval = _read_mode2_sector (_obj,
((char *)data) + (M2RAW_SECTOR_SIZE * i),
lsn + i, true)) )
return retval;
} else {
char buf[M2RAW_SECTOR_SIZE] = { 0, };
if ( (retval = _read_mode2_sector (_obj, buf, lsn + i, true)) )
return retval;
memcpy (((char *)data) + (M2F1_SECTOR_SIZE * i), buf + 8,
M2F1_SECTOR_SIZE);
}
}
return 0;
}
/*!
Set the device to use in I/O operations.
*/
static int
_cdio_set_arg (void *user_data, const char key[], const char value[])
{
_img_private_t *_obj = user_data;
if (!strcmp (key, "source"))
{
free (_obj->source_name);
if (!value)
return -2;
_obj->source_name = strdup (value);
}
else
return -1;
return 0;
}
/*!
Eject media -- there's nothing to do here. We always return 2.
also free obj.
*/
static int
_cdio_eject_media (void *user_data) {
/* Sort of a stub here. Perhaps log a message? */
return 2;
}
/*!
Return the value associated with the key "arg".
*/
static const char *
_cdio_get_arg (void *user_data, const char key[])
{
_img_private_t *_obj = user_data;
if (!strcmp (key, "source")) {
return _obj->source_name;
}
return NULL;
}
/*!
Return a string containing the default VCD device if none is specified.
*/
static char *
_cdio_get_default_device()
{
return strdup(DEFAULT_CDIO_DEVICE);
}
/*!
Return the number of of the first track.
CDIO_INVALID_TRACK is returned on error.
*/
static track_t
_cdio_get_first_track_num(void *user_data)
{
_img_private_t *_obj = user_data;
return _obj->first_track_num;
}
/*!
Return the number of tracks. We fake it an just say there's
one big track.
*/
static track_t
_cdio_get_num_tracks(void *user_data)
{
_img_private_t *_obj = user_data;
return _obj->total_tracks;
}
/*!
Return the number of tracks in the current medium.
CDIO_INVALID_TRACK is returned on error.
*/
static track_format_t
_cdio_get_track_format(void *user_data, track_t track_num)
{
_img_private_t *_obj = user_data;
if (track_num > _obj->total_tracks || track_num == 0)
return TRACK_FORMAT_ERROR;
return _obj->tocent[track_num-1].track_format;
}
/*!
Return true if we have XA data (green, mode2 form1) or
XA data (green, mode2 form2). That is track begins:
sync - header - subheader
12 4 - 8
FIXME: there's gotta be a better design for this and get_track_format?
*/
static bool
_cdio_get_track_green(void *user_data, track_t track_num)
{
_img_private_t *_obj = user_data;
if (track_num > _obj->total_tracks || track_num == 0)
return false;
return _obj->tocent[track_num-1].track_green;
}
/*!
Return the starting MSF (minutes/secs/frames) for the track number
track_num in obj. Tracks numbers start at 1.
*/
static bool
_cdio_get_track_msf(void *user_data, track_t track_num, msf_t *msf)
{
_img_private_t *_obj = user_data;
if (NULL == msf) return 1;
if (track_num == CDIO_LEADOUT_TRACK) track_num = _obj->total_tracks+1;
if (track_num <= _obj->total_tracks+1 && track_num != 0) {
*msf = _obj->tocent[track_num-1].start_msf;
return true;
} else
return false;
}
CdIo *
cdio_open_nrg (const char *source_name)
{
CdIo *ret;
_img_private_t *_data;
cdio_funcs _funcs = {
.eject_media = _cdio_eject_media,
.free = _cdio_free,
.get_arg = _cdio_get_arg,
.get_default_device = _cdio_get_default_device,
.get_first_track_num= _cdio_get_first_track_num,
.get_num_tracks = _cdio_get_num_tracks,
.get_track_format = _cdio_get_track_format,
.get_track_green = _cdio_get_track_green,
.get_track_lba = NULL, /* This could be implemented if need be. */
.get_track_msf = _cdio_get_track_msf,
.read_mode2_sector = _read_mode2_sector,
.read_mode2_sectors = _read_mode2_sectors,
.set_arg = _cdio_set_arg,
.stat_size = _cdio_stat_size,
};
_data = _cdio_malloc (sizeof (_img_private_t));
_data->init = false;
_data->total_tracks = 0;
_data->first_track_num= 1;
_data->sector_2336_flag = false;
_cdio_set_arg(_data, "source", (NULL == source_name)
? DEFAULT_CDIO_DEVICE: source_name);
ret = cdio_new (_data, &_funcs);
if (ret == NULL) return NULL;
if (_cdio_init(_data))
return ret;
else {
_cdio_free (_data);
return NULL;
}
}
bool
cdio_have_nrg (void)
{
return true;
}

177
lib/_cdio_stdio.c Normal file
View File

@@ -0,0 +1,177 @@
/*
$Id: _cdio_stdio.c,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include "logging.h"
#include "util.h"
#include "_cdio_stream.h"
#include "_cdio_stdio.h"
static const char _rcsid[] = "$Id: _cdio_stdio.c,v 1.1 2003/03/24 19:01:09 rocky Exp $";
#define CDIO_STDIO_BUFSIZE (128*1024)
typedef struct {
char *pathname;
FILE *fd;
char *fd_buf;
off_t st_size; /* used only for source */
} _UserData;
static int
_stdio_open (void *user_data)
{
_UserData *const ud = user_data;
if ((ud->fd = fopen (ud->pathname, "rb")))
{
ud->fd_buf = _cdio_malloc (CDIO_STDIO_BUFSIZE);
setvbuf (ud->fd, ud->fd_buf, _IOFBF, CDIO_STDIO_BUFSIZE);
}
return (ud->fd == NULL);
}
static int
_stdio_close(void *user_data)
{
_UserData *const ud = user_data;
if (fclose (ud->fd))
cdio_error ("fclose (): %s", strerror (errno));
ud->fd = NULL;
free (ud->fd_buf);
ud->fd_buf = NULL;
return 0;
}
static void
_stdio_free(void *user_data)
{
_UserData *const ud = user_data;
if (ud->pathname)
free(ud->pathname);
if (ud->fd) /* should be NULL anyway... */
_stdio_close(user_data);
free(ud);
}
static long
_stdio_seek(void *user_data, long offset)
{
_UserData *const ud = user_data;
if (fseek (ud->fd, offset, SEEK_SET))
cdio_error ("fseek (): %s", strerror (errno));
return offset;
}
static long
_stdio_stat(void *user_data)
{
const _UserData *const ud = user_data;
return ud->st_size;
}
static long
_stdio_read(void *user_data, void *buf, long count)
{
_UserData *const ud = user_data;
long read;
read = fread(buf, 1, count, ud->fd);
if (read != count)
{ /* fixme -- ferror/feof */
if (feof (ud->fd))
{
cdio_debug ("fread (): EOF encountered");
clearerr (ud->fd);
}
else if (ferror (ud->fd))
{
cdio_error ("fread (): %s", strerror (errno));
clearerr (ud->fd);
}
else
cdio_debug ("fread (): short read and no EOF?!?");
}
return read;
}
CdioDataSource*
cdio_stdio_new(const char pathname[])
{
CdioDataSource *new_obj = NULL;
cdio_stream_io_functions funcs = { 0, };
_UserData *ud = NULL;
struct stat statbuf;
if (stat (pathname, &statbuf) == -1)
{
cdio_error ("could not stat() file `%s': %s", pathname, strerror (errno));
return NULL;
}
ud = _cdio_malloc (sizeof (_UserData));
ud->pathname = strdup(pathname);
ud->st_size = statbuf.st_size; /* let's hope it doesn't change... */
funcs.open = _stdio_open;
funcs.seek = _stdio_seek;
funcs.stat = _stdio_stat;
funcs.read = _stdio_read;
funcs.close = _stdio_close;
funcs.free = _stdio_free;
new_obj = cdio_stream_new(ud, &funcs);
return new_obj;
}
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

40
lib/_cdio_stdio.h Normal file
View File

@@ -0,0 +1,40 @@
/*
$Id: _cdio_stdio.h,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __CDIO_STDIO_H__
#define __CDIO_STDIO_H__
#include "_cdio_stream.h"
CdioDataSource*
cdio_stdio_new(const char pathname[]);
#endif /* __CDIO_STREAM_STDIO_H__ */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

156
lib/_cdio_stream.c Normal file
View File

@@ -0,0 +1,156 @@
/*
$Id: _cdio_stream.c,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "cdio_assert.h"
/* #define STREAM_DEBUG */
#include "logging.h"
#include "util.h"
#include "_cdio_stream.h"
static const char _rcsid[] = "$Id: _cdio_stream.c,v 1.1 2003/03/24 19:01:09 rocky Exp $";
/*
* DataSource implementations
*/
struct _CdioDataSource {
void* user_data;
cdio_stream_io_functions op;
int is_open;
long position;
};
static void
_cdio_stream_open_if_necessary(CdioDataSource *obj)
{
cdio_assert (obj != NULL);
if (!obj->is_open) {
if (obj->op.open(obj->user_data))
cdio_error ("could not opening input stream...");
else {
#ifdef STREAM_DEBUG
cdio_debug ("opened source...");
#endif
obj->is_open = 1;
obj->position = 0;
}
}
}
long
cdio_stream_seek(CdioDataSource* obj, long offset)
{
cdio_assert (obj != NULL);
_cdio_stream_open_if_necessary(obj);
if (obj->position != offset) {
#ifdef STREAM_DEBUG
cdio_warn("had to reposition DataSource from %ld to %ld!", obj->position, offset);
#endif
obj->position = offset;
return obj->op.seek(obj->user_data, offset);
}
return 0;
}
CdioDataSource*
cdio_stream_new(void *user_data, const cdio_stream_io_functions *funcs)
{
CdioDataSource *new_obj;
new_obj = _cdio_malloc (sizeof (CdioDataSource));
new_obj->user_data = user_data;
memcpy(&(new_obj->op), funcs, sizeof(cdio_stream_io_functions));
return new_obj;
}
long
cdio_stream_read(CdioDataSource* obj, void *ptr, long size, long nmemb)
{
long read_bytes;
cdio_assert (obj != NULL);
_cdio_stream_open_if_necessary(obj);
read_bytes = obj->op.read(obj->user_data, ptr, size*nmemb);
obj->position += read_bytes;
return read_bytes;
}
long
cdio_stream_stat(CdioDataSource* obj)
{
cdio_assert (obj != NULL);
_cdio_stream_open_if_necessary(obj);
return obj->op.stat(obj->user_data);
}
void
cdio_stream_close(CdioDataSource* obj)
{
cdio_assert (obj != NULL);
if (obj->is_open) {
#ifdef STREAM_DEBUG
cdio_debug ("closed source...");
#endif
obj->op.close(obj->user_data);
obj->is_open = 0;
obj->position = 0;
}
}
void
cdio_stream_destroy(CdioDataSource* obj)
{
cdio_assert (obj != NULL);
cdio_stream_close(obj);
obj->op.free(obj->user_data);
}
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

91
lib/_cdio_stream.h Normal file
View File

@@ -0,0 +1,91 @@
/*
$Id: _cdio_stream.h,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __CDIO_STREAM_H__
#define __CDIO_STREAM_H__
#include "cdio_types.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* typedef'ed IO functions prototypes */
typedef int(*cdio_data_open_t)(void *user_data);
typedef long(*cdio_data_read_t)(void *user_data, void *buf, long count);
typedef long(*cdio_data_seek_t)(void *user_data, long offset);
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 _CdioDataSource CdioDataSource;
typedef struct {
cdio_data_open_t open;
cdio_data_seek_t seek;
cdio_data_stat_t stat;
cdio_data_read_t read;
cdio_data_close_t close;
cdio_data_free_t free;
} cdio_stream_io_functions;
CdioDataSource*
cdio_stream_new(void *user_data, const cdio_stream_io_functions *funcs);
long
cdio_stream_read(CdioDataSource* obj, void *ptr, long size, long nmemb);
long
cdio_stream_seek(CdioDataSource* obj, long offset);
long
cdio_stream_stat(CdioDataSource* obj);
void
cdio_stream_destroy(CdioDataSource* obj);
void
cdio_stream_close(CdioDataSource* obj);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __CDIO_STREAM_H__ */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

658
lib/_cdio_sunos.c Normal file
View File

@@ -0,0 +1,658 @@
/*
$Id: _cdio_sunos.c,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2002,2003 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "cdio_assert.h"
#include "cdio_private.h"
#include "logging.h"
#include "sector.h"
#include "util.h"
#ifdef HAVE_SOLARIS_CDROM
static const char _rcsid[] = "$Id: _cdio_sunos.c,v 1.1 2003/03/24 19:01:09 rocky Exp $";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef HAVE_SYS_CDIO_H
# include <sys/cdio.h> /* CDIOCALLOW etc... */
#else
#error "You need <sys/cdio.h> to have CDROM support"
#endif
#include <sys/dkio.h>
#include <sys/scsi/generic/commands.h>
#include <sys/scsi/impl/uscsi.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#define DEFAULT_CDIO_DEVICE "/vol/dev/aliases/cdrom0"
#define TOTAL_TRACKS (_obj->tochdr.cdth_trk1)
#define FIRST_TRACK_NUM (_obj->tochdr.cdth_trk0)
/* reader */
typedef struct {
int fd;
int ioctls_debugged; /* for debugging */
enum {
_AM_NONE,
_AM_SUN_CTRL_ATAPI,
_AM_SUN_CTRL_SCSI
#if FINISHED
_AM_READ_CD,
_AM_READ_10
#endif
} access_mode;
char *source_name;
bool init;
/* Track information */
bool toc_init; /* if true, info below is valid. */
struct cdrom_tochdr tochdr;
struct cdrom_tocentry tocent[100]; /* entry info for each track */
} _img_private_t;
/*!
Initialize CD device.
*/
static bool
_cdio_init (_img_private_t *_obj)
{
struct dk_cinfo cinfo;
_obj->fd = open (_obj->source_name, O_RDONLY, 0);
if (_obj->fd < 0)
{
cdio_error ("open (%s): %s", _obj->source_name, strerror (errno));
return false;
}
/*
* CDROMCDXA/CDROMREADMODE2 are broken on IDE/ATAPI devices.
* Try to send MMC3 SCSI commands via the uscsi interface on
* ATAPI devices.
*/
if ( ioctl(_obj->fd, DKIOCINFO, &cinfo) == 0
&& ((strcmp(cinfo.dki_cname, "ide") == 0)
|| (strncmp(cinfo.dki_cname, "pci", 3) == 0)) ) {
_obj->access_mode = _AM_SUN_CTRL_ATAPI;
} else {
_obj->access_mode = _AM_SUN_CTRL_SCSI;
}
_obj->init = true;
_obj->toc_init = false;
return true;
}
/*!
Release and free resources associated with cd.
*/
static void
_cdio_free (void *user_data)
{
_img_private_t *_obj = user_data;
if (NULL == _obj) return;
free (_obj->source_name);
if (_obj->fd >= 0)
close (_obj->fd);
free (_obj);
}
/*!
Reads a single mode2 sector from cd device into data starting from lsn.
Returns 0 if no error.
*/
static int
_read_mode2_sector (void *user_data, void *data, lsn_t lsn,
bool mode2_form2)
{
char buf[M2RAW_SECTOR_SIZE] = { 0, };
struct cdrom_msf *msf = (struct cdrom_msf *) &buf;
msf_t _msf;
_img_private_t *_obj = user_data;
cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf);
msf->cdmsf_min0 = from_bcd8(_msf.m);
msf->cdmsf_sec0 = from_bcd8(_msf.s);
msf->cdmsf_frame0 = from_bcd8(_msf.f);
if (_obj->ioctls_debugged == 75)
cdio_debug ("only displaying every 75th ioctl from now on");
if (_obj->ioctls_debugged == 30 * 75)
cdio_debug ("only displaying every 30*75th ioctl from now on");
if (_obj->ioctls_debugged < 75
|| (_obj->ioctls_debugged < (30 * 75)
&& _obj->ioctls_debugged % 75 == 0)
|| _obj->ioctls_debugged % (30 * 75) == 0)
cdio_debug ("reading %2.2d:%2.2d:%2.2d",
msf->cdmsf_min0, msf->cdmsf_sec0, msf->cdmsf_frame0);
_obj->ioctls_debugged++;
switch (_obj->access_mode)
{
case _AM_NONE:
cdio_error ("No way to read CD mode2.");
return 1;
break;
case _AM_SUN_CTRL_SCSI:
if (ioctl (_obj->fd, CDROMREADMODE2, &buf) == -1) {
perror ("ioctl(..,CDROMREADMODE2,..)");
return 1;
/* exit (EXIT_FAILURE); */
}
break;
case _AM_SUN_CTRL_ATAPI:
{
struct uscsi_cmd sc;
union scsi_cdb cdb;
int blocks = 1;
int sector_type;
int sync, header_code, user_data, edc_ecc, error_field;
int sub_channel;
sector_type = 0; /* all types */
/*sector_type = 1;*/ /* CD-DA */
/*sector_type = 2;*/ /* mode1 */
/*sector_type = 3;*/ /* mode2 */
/*sector_type = 4;*/ /* mode2/form1 */
/*sector_type = 5;*/ /* mode2/form2 */
sync = 0;
header_code = 2;
user_data = 1;
edc_ecc = 0;
error_field = 0;
sub_channel = 0;
memset(&cdb, 0, sizeof(cdb));
memset(&sc, 0, sizeof(sc));
cdb.scc_cmd = 0xBE;
cdb.cdb_opaque[1] = (sector_type) << 2;
cdb.cdb_opaque[2] = (lsn >> 24) & 0xff;
cdb.cdb_opaque[3] = (lsn >> 16) & 0xff;
cdb.cdb_opaque[4] = (lsn >> 8) & 0xff;
cdb.cdb_opaque[5] = lsn & 0xff;
cdb.cdb_opaque[6] = (blocks >> 16) & 0xff;
cdb.cdb_opaque[7] = (blocks >> 8) & 0xff;
cdb.cdb_opaque[8] = blocks & 0xff;
cdb.cdb_opaque[9] = (sync << 7) |
(header_code << 5) |
(user_data << 4) |
(edc_ecc << 3) |
(error_field << 1);
cdb.cdb_opaque[10] = sub_channel;
sc.uscsi_cdb = (caddr_t)&cdb;
sc.uscsi_cdblen = 12;
sc.uscsi_bufaddr = (caddr_t) buf;
sc.uscsi_buflen = M2RAW_SECTOR_SIZE;
sc.uscsi_flags = USCSI_ISOLATE | USCSI_READ;
sc.uscsi_timeout = 20;
if (ioctl(_obj->fd, USCSICMD, &sc)) {
perror("USCSICMD: READ CD");
return 1;
}
if (sc.uscsi_status) {
cdio_error("SCSI command failed with status %d\n",
sc.uscsi_status);
return 1;
}
break;
}
}
if (mode2_form2)
memcpy (data, buf, M2RAW_SECTOR_SIZE);
else
memcpy (((char *)data), buf + 8, M2F1_SECTOR_SIZE);
return 0;
}
/*!
Reads nblocks of mode2 sectors from cd device into data starting
from lsn.
Returns 0 if no error.
*/
static int
_read_mode2_sectors (void *user_data, void *data, uint32_t lsn,
bool mode2_form2, unsigned nblocks)
{
_img_private_t *_obj = user_data;
int i;
int retval;
for (i = 0; i < nblocks; i++) {
if (mode2_form2) {
if ( (retval = _read_mode2_sector (_obj,
((char *)data) + (M2RAW_SECTOR_SIZE * i),
lsn + i, true)) )
return retval;
} else {
char buf[M2RAW_SECTOR_SIZE] = { 0, };
if ( (retval = _read_mode2_sector (_obj, buf, lsn + i, true)) )
return retval;
memcpy (((char *)data) + (M2F1_SECTOR_SIZE * i), buf + 8,
M2F1_SECTOR_SIZE);
}
}
return 0;
}
/*!
Return the size of the CD in logical block address (LBA) units.
*/
static uint32_t
_cdio_stat_size (void *user_data)
{
_img_private_t *_obj = user_data;
struct cdrom_tocentry tocent;
uint32_t size;
tocent.cdte_track = CDROM_LEADOUT;
tocent.cdte_format = CDROM_LBA;
if (ioctl (_obj->fd, CDROMREADTOCENTRY, &tocent) == -1)
{
perror ("ioctl(CDROMREADTOCENTRY)");
exit (EXIT_FAILURE);
}
size = tocent.cdte_addr.lba;
return size;
}
/*!
Set the key "arg" to "value" in source device.
*/
static int
_cdio_set_arg (void *user_data, const char key[], const char value[])
{
_img_private_t *_obj = user_data;
if (!strcmp (key, "source"))
{
if (!value)
return -2;
free (_obj->source_name);
_obj->source_name = strdup (value);
}
else if (!strcmp (key, "access-mode"))
{
if (!strcmp(value, "ATAPI"))
_obj->access_mode = _AM_SUN_CTRL_ATAPI;
else if (!strcmp(value, "SCSI"))
_obj->access_mode = _AM_SUN_CTRL_SCSI;
else
cdio_error ("unknown access type: %s. ignored.", value);
}
else
return -1;
return 0;
}
/*!
Read and cache the CD's Track Table of Contents and track info.
Return true if successful or false if an error.
*/
static bool
_cdio_read_toc (_img_private_t *_obj)
{
int i;
/* read TOC header */
if ( ioctl(_obj->fd, CDROMREADTOCHDR, &_obj->tochdr) == -1 ) {
cdio_error("%s: %s\n",
"error in ioctl CDROMREADTOCHDR", strerror(errno));
return false;
}
/* read individual tracks */
for (i=_obj->tochdr.cdth_trk0; i<=_obj->tochdr.cdth_trk1; i++) {
_obj->tocent[i-1].cdte_track = i;
_obj->tocent[i-1].cdte_format = CDROM_MSF;
if ( ioctl(_obj->fd, CDROMREADTOCENTRY, &_obj->tocent[i-1]) == -1 ) {
cdio_error("%s %d: %s\n",
"error in ioctl CDROMREADTOCENTRY for track",
i, strerror(errno));
return false;
}
}
/* read the lead-out track */
_obj->tocent[_obj->tochdr.cdth_trk1].cdte_track = CDROM_LEADOUT;
_obj->tocent[_obj->tochdr.cdth_trk1].cdte_format = CDROM_MSF;
if (ioctl(_obj->fd, CDROMREADTOCENTRY,
&_obj->tocent[_obj->tochdr.cdth_trk1]) == -1 ) {
cdio_error("%s: %s\n",
"error in ioctl CDROMREADTOCENTRY for lead-out",
strerror(errno));
return false;
}
return true;
}
/*!
Eject media in CD drive. If successful, as a side effect we
also free obj.
*/
static int
_cdio_eject_media (void *user_data) {
_img_private_t *_obj = user_data;
int ret;
if (_obj->fd > -1) {
if ((ret = ioctl(_obj->fd, CDROMEJECT)) != 0) {
_cdio_free((void *) _obj);
cdio_error ("CDROMEJECT failed: %s\n", strerror(errno));
return 1;
} else {
_cdio_free((void *) _obj);
return 0;
}
}
return 2;
}
static void *
_cdio_malloc_and_zero(size_t size) {
void *ptr;
if( !size ) size++;
if((ptr = malloc(size)) == NULL) {
cdio_error("malloc() failed: %s", strerror(errno));
return NULL;
}
memset(ptr, 0, size);
return ptr;
}
/*!
Return the value associated with the key "arg".
*/
static const char *
_cdio_get_arg (void *user_data, const char key[])
{
_img_private_t *_obj = user_data;
if (!strcmp (key, "source")) {
return _obj->source_name;
} else if (!strcmp (key, "access-mode")) {
switch (_obj->access_mode) {
case _AM_SUN_CTRL_ATAPI:
return "ATAPI";
case _AM_SUN_CTRL_SCSI:
return "SCSI";
case _AM_NONE:
return "no access method";
}
}
return NULL;
}
/*!
Return a string containing the default VCD device if none is specified.
*/
static char *
_cdio_get_default_device(void)
{
char *volume_device;
char *volume_name;
char *volume_action;
char *device;
struct stat stb;
if ((volume_device = getenv("VOLUME_DEVICE")) != NULL &&
(volume_name = getenv("VOLUME_NAME")) != NULL &&
(volume_action = getenv("VOLUME_ACTION")) != NULL &&
strcmp(volume_action, "insert") == 0) {
device = _cdio_malloc_and_zero(strlen(volume_device)
+ strlen(volume_name) + 2);
if (device == NULL)
return strdup(DEFAULT_CDIO_DEVICE);
sprintf(device, "%s/%s", volume_device, volume_name);
if (stat(device, &stb) != 0 || !S_ISCHR(stb.st_mode)) {
free(device);
return strdup(DEFAULT_CDIO_DEVICE);
}
return device;
}
return strdup(DEFAULT_CDIO_DEVICE);
}
/*!
Return the number of of the first track.
CDIO_INVALID_TRACK is returned on error.
*/
static track_t
_cdio_get_first_track_num(void *user_data)
{
_img_private_t *_obj = user_data;
if (!_obj->toc_init) _cdio_read_toc (_obj) ;
return FIRST_TRACK_NUM;
}
/*!
Return the number of tracks in the current medium.
*/
static track_t
_cdio_get_num_tracks(void *user_data)
{
_img_private_t *_obj = user_data;
if (!_obj->toc_init) _cdio_read_toc (_obj) ;
return TOTAL_TRACKS;
}
/*!
Get format of track.
*/
static track_format_t
_cdio_get_track_format(void *user_data, track_t track_num)
{
_img_private_t *_obj = user_data;
if (!_obj->init) _cdio_init(_obj);
if (!_obj->toc_init) _cdio_read_toc (_obj) ;
if (track_num > TOTAL_TRACKS || track_num == 0)
return TRACK_FORMAT_ERROR;
/* This is pretty much copied from the "badly broken" cdrom_count_tracks
in linux/cdrom.c.
*/
if (_obj->tocent[track_num-1].cdte_ctrl & CDROM_DATA_TRACK) {
if (_obj->tocent[track_num-1].cdte_format == 0x10)
return TRACK_FORMAT_CDI;
else if (_obj->tocent[track_num-1].cdte_format == 0x20)
return TRACK_FORMAT_XA;
else
return TRACK_FORMAT_DATA;
} else
return TRACK_FORMAT_AUDIO;
}
/*!
Return true if we have XA data (green, mode2 form1) or
XA data (green, mode2 form2). That is track begins:
sync - header - subheader
12 4 - 8
FIXME: there's gotta be a better design for this and get_track_format?
*/
static bool
_cdio_get_track_green(void *user_data, track_t track_num)
{
_img_private_t *_obj = user_data;
if (!_obj->init) _cdio_init(_obj);
if (!_obj->toc_init) _cdio_read_toc (_obj) ;
if (track_num == CDIO_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1;
if (track_num > TOTAL_TRACKS+1 || track_num == 0)
return false;
/* FIXME: Dunno if this is the right way, but it's what
I was using in cdinfo for a while.
*/
return ((_obj->tocent[track_num-1].cdte_ctrl & 2) != 0);
}
/*!
Return the starting MSF (minutes/secs/frames) for track number
track_num in obj. Tracks numbers start at 1.
The "leadout" track is specified either by
using track_num LEADOUT_TRACK or the total tracks+1.
NULL is returned if there is no entry.
*/
static bool
_cdio_get_track_msf(void *user_data, track_t track_num, msf_t *msf)
{
_img_private_t *_obj = user_data;
if (NULL == msf) return false;
if (!_obj->init) _cdio_init(_obj);
if (!_obj->toc_init) _cdio_read_toc (_obj) ;
if (track_num == CDIO_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1;
if (track_num > TOTAL_TRACKS+1 || track_num == 0) {
return false;
} else {
struct cdrom_tocentry *msf0 = &_obj->tocent[track_num-1];
msf->m = to_bcd8(msf0->cdte_addr.msf.minute);
msf->s = to_bcd8(msf0->cdte_addr.msf.second);
msf->f = to_bcd8(msf0->cdte_addr.msf.frame);
return true;
}
}
#endif /* HAVE_SOLARIS_CDROM */
/*!
Initialization routine. This is the only thing that doesn't
get called via a function pointer. In fact *we* are the
ones to set that up.
*/
CdIo *
cdio_open_solaris (const char *source_name)
{
#ifdef HAVE_SOLARIS_CDROM
CdIo *ret;
_img_private_t *_data;
cdio_funcs _funcs = {
.eject_media = _cdio_eject_media,
.free = _cdio_free,
.get_arg = _cdio_get_arg,
.get_default_device = _cdio_get_default_device,
.get_first_track_num= _cdio_get_first_track_num,
.get_num_tracks = _cdio_get_num_tracks,
.get_track_format = _cdio_get_track_format,
.get_track_green = _cdio_get_track_green,
.get_track_msf = _cdio_get_track_msf,
.read_mode2_sector = _read_mode2_sector,
.read_mode2_sectors = _read_mode2_sectors,
.stat_size = _cdio_stat_size,
.set_arg = _cdio_set_arg
};
_data = _cdio_malloc (sizeof (_img_private_t));
_data->fd = -1;
_cdio_set_arg(_data, "source", (NULL == source_name)
? DEFAULT_CDIO_DEVICE: source_name);
ret = cdio_new (_data, &_funcs);
if (ret == NULL) return NULL;
if (_cdio_init(_data))
return ret;
else {
_cdio_free (_data);
return NULL;
}
#else
return NULL;
#endif /* HAVE_SOLARIS_CDROM */
}
bool
cdio_have_solaris (void)
{
#ifdef HAVE_SOLARIS_CDROM
return true;
#else
return false;
#endif /* HAVE_SOLARIS_CDROM */
}

196
lib/bytesex.h Normal file
View File

@@ -0,0 +1,196 @@
/*
$Id: bytesex.h,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __CDIO_BYTESEX_H__
#define __CDIO_BYTESEX_H__
#include "cdio_types.h"
#include "logging.h"
#include "bytesex_asm.h"
/* generic byteswap routines */
#define UINT16_SWAP_LE_BE_C(val) ((uint16_t) ( \
(((uint16_t) (val) & (uint16_t) 0x00ffU) << 8) | \
(((uint16_t) (val) & (uint16_t) 0xff00U) >> 8)))
#define UINT32_SWAP_LE_BE_C(val) ((uint32_t) ( \
(((uint32_t) (val) & (uint32_t) 0x000000ffU) << 24) | \
(((uint32_t) (val) & (uint32_t) 0x0000ff00U) << 8) | \
(((uint32_t) (val) & (uint32_t) 0x00ff0000U) >> 8) | \
(((uint32_t) (val) & (uint32_t) 0xff000000U) >> 24)))
#define UINT64_SWAP_LE_BE_C(val) ((uint64_t) ( \
(((uint64_t) (val) & (uint64_t) UINT64_C(0x00000000000000ff)) << 56) | \
(((uint64_t) (val) & (uint64_t) UINT64_C(0x000000000000ff00)) << 40) | \
(((uint64_t) (val) & (uint64_t) UINT64_C(0x0000000000ff0000)) << 24) | \
(((uint64_t) (val) & (uint64_t) UINT64_C(0x00000000ff000000)) << 8) | \
(((uint64_t) (val) & (uint64_t) UINT64_C(0x000000ff00000000)) >> 8) | \
(((uint64_t) (val) & (uint64_t) UINT64_C(0x0000ff0000000000)) >> 24) | \
(((uint64_t) (val) & (uint64_t) UINT64_C(0x00ff000000000000)) >> 40) | \
(((uint64_t) (val) & (uint64_t) UINT64_C(0xff00000000000000)) >> 56)))
#ifndef UINT16_SWAP_LE_BE
# define UINT16_SWAP_LE_BE UINT16_SWAP_LE_BE_C
#endif
#ifndef UINT32_SWAP_LE_BE
# define UINT32_SWAP_LE_BE UINT32_SWAP_LE_BE_C
#endif
#ifndef UINT64_SWAP_LE_BE
# define UINT64_SWAP_LE_BE UINT64_SWAP_LE_BE_C
#endif
inline static
uint16_t uint16_swap_le_be (const uint16_t val)
{
return UINT16_SWAP_LE_BE (val);
}
inline static
uint32_t uint32_swap_le_be (const uint32_t val)
{
return UINT32_SWAP_LE_BE (val);
}
inline static
uint64_t uint64_swap_le_be (const uint64_t val)
{
return UINT64_SWAP_LE_BE (val);
}
# define UINT8_TO_BE(val) ((uint8_t) (val))
# define UINT8_TO_LE(val) ((uint8_t) (val))
#ifdef WORDS_BIGENDIAN
# define UINT16_TO_BE(val) ((uint16_t) (val))
# define UINT16_TO_LE(val) ((uint16_t) UINT16_SWAP_LE_BE(val))
# define UINT32_TO_BE(val) ((uint32_t) (val))
# define UINT32_TO_LE(val) ((uint32_t) UINT32_SWAP_LE_BE(val))
# define UINT64_TO_BE(val) ((uint64_t) (val))
# define UINT64_TO_LE(val) ((uint64_t) UINT64_SWAP_LE_BE(val))
#else
# define UINT16_TO_BE(val) ((uint16_t) UINT16_SWAP_LE_BE(val))
# define UINT16_TO_LE(val) ((uint16_t) (val))
# define UINT32_TO_BE(val) ((uint32_t) UINT32_SWAP_LE_BE(val))
# define UINT32_TO_LE(val) ((uint32_t) (val))
# define UINT64_TO_BE(val) ((uint64_t) UINT64_SWAP_LE_BE(val))
# define UINT64_TO_LE(val) ((uint64_t) (val))
#endif
/* symmetric conversions */
#define UINT8_FROM_BE(val) (UINT8_TO_BE (val))
#define UINT8_FROM_LE(val) (UINT8_TO_LE (val))
#define UINT16_FROM_BE(val) (UINT16_TO_BE (val))
#define UINT16_FROM_LE(val) (UINT16_TO_LE (val))
#define UINT32_FROM_BE(val) (UINT32_TO_BE (val))
#define UINT32_FROM_LE(val) (UINT32_TO_LE (val))
#define UINT64_FROM_BE(val) (UINT64_TO_BE (val))
#define UINT64_FROM_LE(val) (UINT64_TO_LE (val))
/* converter function template */
#define CVT_TO_FUNC(bits) \
static inline uint ## bits ## _t \
uint ## bits ## _to_be (uint ## bits ## _t val) \
{ return UINT ## bits ## _TO_BE (val); } \
static inline uint ## bits ## _t \
uint ## bits ## _to_le (uint ## bits ## _t val) \
{ return UINT ## bits ## _TO_LE (val); } \
CVT_TO_FUNC(8)
CVT_TO_FUNC(16)
CVT_TO_FUNC(32)
CVT_TO_FUNC(64)
#undef CVT_TO_FUNC
#define uint8_from_be(val) (uint8_to_be (val))
#define uint8_from_le(val) (uint8_to_le (val))
#define uint16_from_be(val) (uint16_to_be (val))
#define uint16_from_le(val) (uint16_to_le (val))
#define uint32_from_be(val) (uint32_to_be (val))
#define uint32_from_le(val) (uint32_to_le (val))
#define uint64_from_be(val) (uint64_to_be (val))
#define uint64_from_le(val) (uint64_to_le (val))
/* ISO9660 related stuff */
#define to_711(i) uint8_to_le(i)
#define from_711(i) uint8_from_le(i)
#define to_721(i) uint16_to_le(i)
#define from_721(i) uint16_from_le(i)
#define to_721(i) uint16_to_le(i)
#define from_721(i) uint16_from_le(i)
#define to_722(i) uint16_to_be(i)
#define from_722(i) uint16_from_be(i)
static inline uint32_t
to_723(uint16_t i)
{
return uint32_swap_le_be(i) | i;
}
static inline uint16_t
from_723 (uint32_t p)
{
if (uint32_swap_le_be (p) != p)
cdio_warn ("from_723: broken byte order");
return (0xFFFF & p);
}
#define to_731(i) uint32_to_le(i)
#define from_731(i) uint32_from_le(i)
#define to_732(i) uint32_to_be(i)
#define from_732(i) uint32_from_be(i)
static inline uint64_t
to_733(uint32_t i)
{
return uint64_swap_le_be(i) | i;
}
static inline uint32_t
from_733 (uint64_t p)
{
if (uint64_swap_le_be (p) != p)
cdio_warn ("from_733: broken byte order");
return (UINT32_C(0xFFFFFFFF) & p);
}
#endif /* __CDIO_BYTESEX_H__ */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

123
lib/bytesex_asm.h Normal file
View File

@@ -0,0 +1,123 @@
/*
$Id: bytesex_asm.h,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2001 Sven Ottemann <ac-logic@freenet.de>
2001 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __CDIO_BYTESEX_ASM_H__
#define __CDIO_BYTESEX_ASM_H__
#if !defined(DISABLE_ASM_OPTIMIZE)
#include "cdio_types.h"
#if defined(__powerpc__) && defined(__GNUC__)
inline static
uint32_t uint32_swap_le_be_asm(const uint32_t a)
{
uint32_t b;
__asm__ ("lwbrx %0,0,%1"
:"=r"(b)
:"r"(&a), "m"(a));
return b;
}
inline static
uint16_t uint16_swap_le_be_asm(const uint16_t a)
{
uint32_t b;
__asm__ ("lhbrx %0,0,%1"
:"=r"(b)
:"r"(&a), "m"(a));
return b;
}
#define UINT16_SWAP_LE_BE uint16_swap_le_be_asm
#define UINT32_SWAP_LE_BE uint32_swap_le_be_asm
#elif defined(__mc68000__) && defined(__STORMGCC__)
inline static
uint32_t uint32_swap_le_be_asm(uint32_t a __asm__("d0"))
{
/* __asm__("rolw #8,%0; swap %0; rolw #8,%0" : "=d" (val) : "0" (val)); */
__asm__("move.l %1,d0;rol.w #8,d0;swap d0;rol.w #8,d0;move.l d0,%0"
:"=r"(a)
:"r"(a));
return(a);
}
inline static
uint16_t uint16_swap_le_be_asm(uint16_t a __asm__("d0"))
{
__asm__("move.l %1,d0;rol.w #8,d0;move.l d0,%0"
:"=r"(a)
:"r"(a));
return(a);
}
#define UINT16_SWAP_LE_BE uint16_swap_le_be_asm
#define UINT32_SWAP_LE_BE uint32_swap_le_be_asm
#elif 0 && defined(__i386__) && defined(__GNUC__)
inline static
uint32_t uint32_swap_le_be_asm(uint32_t a)
{
__asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */
"rorl $16,%0\n\t" /* swap words */
"xchgb %b0,%h0" /* swap higher bytes */
:"=q" (a)
: "0" (a));
return(a);
}
inline static
uint16_t uint16_swap_le_be_asm(uint16_t a)
{
__asm__("xchgb %b0,%h0" /* swap bytes */
: "=q" (a)
: "0" (a));
return(a);
}
#define UINT16_SWAP_LE_BE uint16_swap_le_be_asm
#define UINT32_SWAP_LE_BE uint32_swap_le_be_asm
#endif
#endif /* !defined(DISABLE_ASM_OPTIMIZE) */
#endif /* __CDIO_BYTESEX_ASM_H__ */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

454
lib/cdio.c Normal file
View File

@@ -0,0 +1,454 @@
/*
$Id: cdio.c,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "cdio_assert.h"
#include "util.h"
#include "logging.h"
#include "cdio_private.h"
static const char _rcsid[] = "$Id: cdio.c,v 1.1 2003/03/24 19:01:09 rocky Exp $";
const char *track_format2str[5] =
{
"audio", "CD-i", "XA", "data", "error"
};
/* The below array gives of the drivers that are currently available for
on a particular host. */
CdIo_driver_t CdIo_driver[MAX_DRIVER] = { {0} };
struct _CdIo {
void *user_data;
cdio_funcs op;
};
/* The last valid entry of Cdio_driver. -1 means uninitialzed. -2
means some sort of error.
*/
int CdIo_last_driver = -1;
static bool
cdio_have_false(void)
{
return false;
}
/* The below array gives all drivers that can possibly appear.
on a particular host. */
CdIo_driver_t CdIo_all_drivers[MAX_DRIVER+1] = {
{DRIVER_UNKNOWN,
0,
"Unknown",
"No driver",
&cdio_have_false,
NULL
},
{DRIVER_LINUX,
CDIO_SRC_IS_DEVICE_MASK|CDIO_SRC_IS_NATIVE_MASK,
"Linux",
"Linux ioctl and packet driver",
&cdio_have_linux,
&cdio_open_linux
},
{DRIVER_SOLARIS,
CDIO_SRC_IS_DEVICE_MASK|CDIO_SRC_IS_NATIVE_MASK|CDIO_SRC_IS_SCSI_MASK,
"Solaris",
"Solaris ATAPI and SCSI driver",
&cdio_have_solaris,
&cdio_open_solaris
},
{DRIVER_BSDI,
CDIO_SRC_IS_DEVICE_MASK|CDIO_SRC_IS_NATIVE_MASK|CDIO_SRC_IS_SCSI_MASK,
"BSDI",
"BSDI ATAPI and SCSI driver",
&cdio_have_bsdi,
cdio_open_bsdi
},
{DRIVER_NRG,
CDIO_SRC_IS_DISK_IMAGE_MASK,
"NRG",
"Nero NRG disk image driver",
&cdio_have_nrg,
&cdio_open_nrg
},
{DRIVER_BINCUE,
CDIO_SRC_IS_DISK_IMAGE_MASK,
"BIN/CUE",
"bin/cuesheet disk image driver",
&cdio_have_bincue,
&cdio_open_bincue
}
};
/*!
Eject media in CD drive if there is a routine to do so.
Return 0 if success and 1 for failure, and 2 if no routine.
*/
int
cdio_eject_media (const CdIo *obj)
{
cdio_assert (obj != NULL);
if (obj->op.eject_media) {
return obj->op.eject_media (obj->user_data);
} else {
return 2;
}
}
/*!
Return a string containing the default CD device if none is specified.
*/
const char *
cdio_get_arg (const CdIo *obj, const char key[])
{
cdio_assert (obj != NULL);
if (obj->op.get_arg) {
return obj->op.get_arg (obj->user_data, key);
} else {
return NULL;
}
}
/*!
Return a string containing the default CD device if none is specified.
*/
char *
cdio_get_default_device (const CdIo *obj)
{
cdio_assert (obj != NULL);
if (obj->op.get_default_device) {
return obj->op.get_default_device ();
} else {
return NULL;
}
}
/*!
Return the number of of the first track.
CDIO_INVALID_TRACK is returned on error.
*/
track_t
cdio_get_first_track_num (const CdIo *obj)
{
cdio_assert (obj != NULL);
if (obj->op.get_first_track_num) {
return obj->op.get_first_track_num (obj->user_data);
} else {
return CDIO_INVALID_TRACK;
}
}
/*!
Return the number of tracks in the current medium.
CDIO_INVALID_TRACK is returned on error.
*/
track_t
cdio_get_num_tracks (const CdIo *obj)
{
cdio_assert (obj != NULL);
if (obj->op.get_num_tracks) {
return obj->op.get_num_tracks (obj->user_data);
} else {
return CDIO_INVALID_TRACK;
}
}
/*!
Get format of track.
*/
track_format_t
cdio_get_track_format(const CdIo *obj, track_t track_num)
{
cdio_assert (obj != NULL);
if (obj->op.get_track_format) {
return obj->op.get_track_format (obj->user_data, track_num);
} else {
return TRACK_FORMAT_ERROR;
}
}
/*!
Return true if we have XA data (green, mode2 form1) or
XA data (green, mode2 form2). That is track begins:
sync - header - subheader
12 4 - 8
FIXME: there's gotta be a better design for this and get_track_format?
*/
bool
cdio_get_track_green(const CdIo *obj, track_t track_num)
{
cdio_assert (obj != NULL);
if (obj->op.get_track_green) {
return obj->op.get_track_green (obj->user_data, track_num);
} else {
return false;
}
}
/*!
Return the starting MSF (minutes/secs/frames) for track number
track_num in obj. Track numbers start at 1.
The "leadout" track is specified either by
using track_num LEADOUT_TRACK or the total tracks+1.
False is returned if there is no track entry.
*/
bool
cdio_get_track_msf(const CdIo *obj, track_t track_num, msf_t *msf)
{
cdio_assert (obj != NULL);
if (obj->op.get_track_msf) {
return obj->op.get_track_msf (obj->user_data, track_num, msf);
} else {
return false;
}
}
bool
cdio_have_driver(driver_id_t driver_id)
{
return (*CdIo_all_drivers[driver_id].have_driver)();
}
/*!
Initialize CD Reading and control routines. Should be called first.
May be implicitly called by other routines if not called first.
*/
bool
cdio_init(void)
{
CdIo_driver_t *all_dp;
CdIo_driver_t *dp = CdIo_driver;
driver_id_t driver_id;
if (CdIo_last_driver != -1) {
cdio_warn ("Init routine called more than once.");
return false;
}
for (driver_id=DRIVER_UNKNOWN; driver_id<=MAX_DRIVER; driver_id++) {
all_dp = &CdIo_all_drivers[driver_id];
if ((*CdIo_all_drivers[driver_id].have_driver)()) {
*dp++ = *all_dp;
CdIo_last_driver++;
}
}
return true;
}
CdIo *
cdio_new (void *user_data, const cdio_funcs *funcs)
{
CdIo *new_obj;
new_obj = _cdio_malloc (sizeof (CdIo));
new_obj->user_data = user_data;
new_obj->op = *funcs;
return new_obj;
}
void
cdio_destroy (CdIo *obj)
{
cdio_assert (obj != NULL);
obj->op.free (obj->user_data);
free (obj);
}
int
cdio_read_mode2_sectors (CdIo *obj, void *buf, lsn_t lsn, bool mode2raw,
unsigned num_sectors)
{
char *_buf = buf;
const int blocksize = mode2raw ? M2RAW_SECTOR_SIZE : M2F1_SECTOR_SIZE;
int n, rc;
cdio_assert (obj != NULL);
cdio_assert (buf != NULL);
cdio_assert (obj->op.read_mode2_sector != NULL
|| obj->op.read_mode2_sectors != NULL);
if (obj->op.read_mode2_sectors)
return obj->op.read_mode2_sectors (obj->user_data, buf, lsn,
mode2raw, num_sectors);
/* fallback */
if (obj->op.read_mode2_sector != NULL)
for (n = 0; n < num_sectors; n++)
if ((rc = cdio_read_mode2_sector (obj, &_buf[n * blocksize],
lsn + n, mode2raw)))
return rc;
return 0;
}
/*!
Reads a single mode2 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
int
cdio_read_mode2_sector (CdIo *obj, void *buf, uint32_t lsn, bool mode2raw)
{
cdio_assert (obj != NULL);
cdio_assert (buf != NULL);
cdio_assert (obj->op.read_mode2_sector != NULL
|| obj->op.read_mode2_sectors != NULL);
if (obj->op.read_mode2_sector)
return obj->op.read_mode2_sector (obj->user_data, buf, lsn, mode2raw);
/* fallback */
if (obj->op.read_mode2_sectors != NULL)
return cdio_read_mode2_sectors (obj, buf, lsn, mode2raw, 1);
return 1;
}
uint32_t
cdio_stat_size (CdIo *obj)
{
cdio_assert (obj != NULL);
return obj->op.stat_size (obj->user_data);
}
/*!
Set the arg "key" with "value" in the source device.
*/
int
cdio_set_arg (CdIo *obj, const char key[], const char value[])
{
cdio_assert (obj != NULL);
cdio_assert (obj->op.set_arg != NULL);
cdio_assert (key != NULL);
return obj->op.set_arg (obj->user_data, key, value);
}
/*! Sets up to read from place specified by source_name and
driver_id This should be called before using any other routine,
except cdio_init. This will call cdio_init, if that hasn't been
done previously. to call one of the specific routines below.
NULL is returned on error.
*/
/* In the future we'll have more complicated code to allow selection
of an I/O routine as well as code to find an appropriate default
routine among the "registered" routines. Possibly classes too
disk-based, SCSI-based, native-based, vendor (e.g. Sony, or
Plextor) based
For now though, we'll start more simply...
*/
CdIo *
cdio_open (const char *source_name, driver_id_t driver_id)
{
if (CdIo_last_driver == -1) cdio_init();
switch (driver_id) {
case DRIVER_UNKNOWN:
case DRIVER_DEVICE:
{
/* Scan for a driver. */
for (driver_id=DRIVER_UNKNOWN; driver_id<=MAX_DRIVER; driver_id++) {
if ((*CdIo_all_drivers[driver_id].have_driver)()) {
CdIo *ret=(*CdIo_all_drivers[driver_id].driver_open)(source_name);
if (ret != NULL) return ret;
}
}
return NULL;
}
break;
case DRIVER_LINUX:
case DRIVER_SOLARIS:
case DRIVER_BSDI:
case DRIVER_NRG:
case DRIVER_BINCUE:
if ((*CdIo_all_drivers[driver_id].have_driver)()) {
return (*CdIo_all_drivers[driver_id].driver_open)(source_name);
}
}
return NULL;
}
/* In the future we'll have more complicated code to allow selection
of an I/O routine as well as code to find an appropriate default
routine among the "registered" routines. Possibly classes too
disk-based, SCSI-based, native-based, vendor (e.g. Sony, or
Plextor) based
For now though, we'll start more simply...
*/
CdIo *
cdio_open_cd (const char *source_name)
{
driver_id_t driver_id;
if (CdIo_last_driver == -1) cdio_init();
/* Scan for a driver. */
for (driver_id=DRIVER_UNKNOWN; driver_id<=MAX_DRIVER; driver_id++) {
if ((*CdIo_all_drivers[driver_id].have_driver)()) {
CdIo *ret=(*CdIo_all_drivers[driver_id].driver_open)(source_name);
if (ret != NULL) return ret;
}
}
return NULL;
}
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

219
lib/cdio.h Normal file
View File

@@ -0,0 +1,219 @@
/*
$Id: cdio.h,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Public CD Input and Control Interface . */
#ifndef __CDIO_H__
#define __CDIO_H__
#include "cdio_types.h"
#include "sector.h"
/* Flags specifying the category of device to open or is opened. */
#define CDIO_SRC_IS_DISK_IMAGE_MASK 0x0001
#define CDIO_SRC_IS_DEVICE_MASK 0x0002
#define CDIO_SRC_IS_SCSI_MASK 0x0004
#define CDIO_SRC_IS_NATIVE_MASK 0x0008
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* opaque structure */
typedef struct _CdIo CdIo;
/* The below enumerations may be used to tag a specific driver
that is opened or is desired to be opened. Note that this is
different than what is available on a given host.
*/
typedef enum {
DRIVER_UNKNOWN,
DRIVER_LINUX,
DRIVER_SOLARIS,
DRIVER_BSDI,
DRIVER_NRG,
DRIVER_BINCUE,
DRIVER_DEVICE,
} driver_id_t;
/* Make sure what's listed below is the last one above. Since we have
a bogus (but useful) 0th entry above we don't have to add one below.
*/
#define MAX_DRIVER DRIVER_BINCUE
typedef enum {
TRACK_FORMAT_AUDIO, /* Audio track, e.g. CD-DA */
TRACK_FORMAT_CDI, /* CD-i. How this is different from DATA below? */
TRACK_FORMAT_XA, /* Mode2 of some sort */
TRACK_FORMAT_DATA, /* Mode1 of some sort */
TRACK_FORMAT_ERROR /* Dunno what is or some other error. */
} track_format_t;
/* Printable tags for above enumeration. */
extern const char *track_format2str[5];
/*!
Eject media in CD drive if there is a routine to do so.
Return 0 if success and 1 for failure, and 2 if no routine.
*/
int cdio_eject_media (const CdIo *obj);
void cdio_destroy (CdIo *obj);
/*!
Return the value associated with the key "arg".
*/
const char * cdio_get_arg (const CdIo *obj, const char key[]);
/*!
Return a string containing the default CD device if none is specified.
*/
char * cdio_get_default_device (const CdIo *obj);
/*!
Return the number of of the first track.
CDIO_INVALID_TRACK is returned on error.
*/
track_t cdio_get_first_track_num(const CdIo *obj);
/*!
Return a string containing the default CD device if none is specified.
*/
track_t cdio_get_num_tracks (const CdIo *obj);
/*!
Get format of track.
*/
track_format_t cdio_get_track_format(const CdIo *obj, track_t track_num);
/*!
Return true if we have XA data (green, mode2 form1) or
XA data (green, mode2 form2). That is track begins:
sync - header - subheader
12 4 - 8
FIXME: there's gotta be a better design for this and get_track_format?
*/
bool cdio_get_track_green(const CdIo *obj, track_t track_num);
/*!
Return the starting MSF (minutes/secs/frames) for track number
track_num in obj. Track numbers start at 1.
The "leadout" track is specified either by
using track_num LEADOUT_TRACK or the total tracks+1.
False is returned if there is no track entry.
*/
bool cdio_get_track_msf(const CdIo *obj, track_t track_num, msf_t *msf);
/*!
Reads a single mode2 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
int cdio_read_mode2_sector (CdIo *obj, void *buf, lsn_t lsn, bool mode2raw);
/*!
Reads nblocks of mode2 sectors from cd device into data starting
from lsn.
Returns 0 if no error.
*/
int cdio_read_mode2_sectors (CdIo *obj, void *buf, lsn_t lsn, bool mode2raw,
unsigned int num_sectors);
/*!
Set the arg "key" with "value" in the source device.
*/
int cdio_set_arg (CdIo *obj, const char key[], const char value[]);
/*!
Return the size of the CD in logical block address (LBA) units.
*/
uint32_t cdio_stat_size (CdIo *obj);
/*!
Initialize CD Reading and control routines. Should be called first.
*/
bool cdio_init(void);
/* True if xxx driver is available. where xxx=linux, solaris, nrg, ...
*/
bool cdio_have_linux (void);
bool cdio_have_solaris (void);
bool cdio_have_nrg (void);
bool cdio_have_bincue (void);
bool cdio_have_bsdi (void);
/* Like above but uses the enumeration instead. */
bool cdio_have_driver (driver_id_t driver_id);
/*! Sets up to read from place specified by source_name and
driver_id This should be called before using any other routine,
except cdio_init. This will call cdio_init, if that hasn't been
done previously. to call one of the specific routines below.
NULL is returned on error.
*/
CdIo * cdio_open (const char *source_name, driver_id_t driver_id);
/*! cdrao BIN/CUE CD disk-image routines. Source is the .bin file
NULL is returned on error.
*/
CdIo * cdio_open_bincue (const char *bin_name);
/*! cdrao CD routines. Source is the some sort of device.
NULL is returned on error.
*/
CdIo * cdio_open_cd (const char *cue_name);
/*! cdrao BIN/CUE CD disk-image routines. Source is the .cue file
NULL is returned on error.
*/
CdIo * cdio_open_cue (const char *cue_name);
/*! BSDI CD-reading routines.
NULL is returned on error.
*/
CdIo * cdio_open_bsdi (const char *source_name);
/*! Linux CD-reading routines.
NULL is returned on error.
*/
CdIo * cdio_open_linux (const char *source_name);
/*! Solaris CD-reading routines.
NULL is returned on error.
*/
CdIo * cdio_open_solaris (const char *soruce_name);
/*! Nero CD disk-image routines.
NULL is returned on error.
*/
CdIo * cdio_open_nrg (const char *source_name);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __CDIO_H__ */

55
lib/cdio_assert.h Normal file
View File

@@ -0,0 +1,55 @@
/*
$Id: cdio_assert.h,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __CDIO_ASSERT_H__
#define __CDIO_ASSERT_H__
#if defined(__GNUC__)
#include "cdio_types.h"
#include "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__ */

158
lib/cdio_private.h Normal file
View File

@@ -0,0 +1,158 @@
/*
$Id: cdio_private.h,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Internal routines for CD I/O drivers. */
#ifndef __CDIO_PRIVATE_H__
#define __CDIO_PRIVATE_H__
#include <cdio.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct {
/*!
Eject media in CD drive. If successful, as a side effect we
also free obj. Return 0 if success and 1 for failure.
*/
int (*eject_media) (void *user_data);
/*!
Release and free resources associated with cd.
*/
void (*free) (void *user_data);
/*!
Return the value associated with the key "arg".
*/
const char * (*get_arg) (void *user_data, const char key[]);
/*!
Return a string containing the default VCD device if none is specified.
*/
char * (*get_default_device)(void);
/*!
Return the number of of the first track.
CDIO_INVALID_TRACK is returned on error.
*/
track_t (*get_first_track_num) (void *user_data);
/*!
Return the number of tracks in the current medium.
CDIO_INVALID_TRACK is returned on error.
*/
track_t (*get_num_tracks) (void *user_data);
/*!
Return the starting MSF (minutes/secs/frames) for track number
track_num in obj. Tracks numbers start at 1.
The "leadout" track is specified either by
using track_num LEADOUT_TRACK or the total tracks+1.
1 is returned on error.
*/
uint32_t (*get_track_lba) (void *user_data, track_t track_num);
/*!
Get format of track.
*/
track_format_t (*get_track_format) (void *user_data, track_t track_num);
/*!
Return true if we have XA data (green, mode2 form1) or
XA data (green, mode2 form2). That is track begins:
sync - header - subheader
12 4 - 8
FIXME: there's gotta be a better design for this and get_track_format?
*/
bool (*get_track_green) (void *user_data, track_t track_num);
/*!
Return the starting MSF (minutes/secs/frames) for track number
track_num in obj. Tracks numbers start at 1.
The "leadout" track is specified either by
using track_num LEADOUT_TRACK or the total tracks+1.
1 is returned on error.
*/
bool (*get_track_msf) (void *user_data, track_t track_num, msf_t *msf);
/*!
Reads a single mode2 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
int (*read_mode2_sector) (void *user_data, void *buf, lsn_t lsn,
bool mode2raw);
/*!
Reads nblocks of mode2 sectors from cd device into data starting
from lsn.
Returns 0 if no error.
*/
int (*read_mode2_sectors) (void *user_data, void *buf, lsn_t lsn,
bool mode2raw, unsigned nblocks);
/*!
Set the arg "key" with "value" in the source device.
*/
int (*set_arg) (void *user_data, const char key[], const char value[]);
/*!
Return the size of the CD in logical block address (LBA) units.
*/
uint32_t (*stat_size) (void *user_data);
} cdio_funcs;
CdIo * cdio_new (void *user_data, const cdio_funcs *funcs);
/* The below structure describes a specific CD Input driver */
typedef struct
{
unsigned int flags;
driver_id_t id;
const char *name;
const char *describe;
bool (*have_driver) (void);
CdIo *(*driver_open) (const char *source_name);
} 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[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[MAX_DRIVER+1];
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __CDIO_PRIVATE_H__ */

217
lib/cdio_types.h Normal file
View File

@@ -0,0 +1,217 @@
/*
$Id: cdio_types.h,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2002,2003 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __CDIO_TYPES_H__
#define __CDIO_TYPES_H__
/* provide some C99 definitions */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#if defined(HAVE_STDINT_H)
# include <stdint.h>
#elif defined(HAVE_INTTYPES_H)
# include <inttypes.h>
#elif defined(__CYGWIN__) || defined(AMIGA) || defined(__linux__)
# include <sys/types.h>
typedef u_int8_t uint8_t;
typedef u_int16_t uint16_t;
typedef u_int32_t uint32_t;
typedef u_int64_t uint64_t;
#else
/* warning ISO/IEC 9899:1999 <stdint.h> was missing and even <inttypes.h> */
/* fixme */
#endif /* HAVE_STDINT_H */
/* default HP/UX macros are broken */
#if defined(__hpux__)
# undef UINT16_C
# undef UINT32_C
# undef UINT64_C
# undef INT64_C
#endif
/* if it's still not defined, take a good guess... should work for
most 32bit and 64bit archs */
#ifndef UINT16_C
# define UINT16_C(c) c ## U
#endif
#ifndef UINT32_C
# if defined (SIZEOF_INT) && SIZEOF_INT == 4
# define UINT32_C(c) c ## U
# elif defined (SIZEOF_LONG) && SIZEOF_LONG == 4
# define UINT32_C(c) c ## UL
# else
# define UINT32_C(c) c ## U
# endif
#endif
#ifndef UINT64_C
# if defined (SIZEOF_LONG) && SIZEOF_LONG == 8
# define UINT64_C(c) c ## UL
# elif defined (SIZEOF_INT) && SIZEOF_INT == 8
# define UINT64_C(c) c ## U
# else
# define UINT64_C(c) c ## ULL
# endif
#endif
#ifndef INT64_C
# if defined (SIZEOF_LONG) && SIZEOF_LONG == 8
# define INT64_C(c) c ## L
# elif defined (SIZEOF_INT) && SIZEOF_INT == 8
# define INT64_C(c) c
# else
# define INT64_C(c) c ## LL
# endif
#endif
#if defined(HAVE_STDBOOL_H)
#include <stdbool.h>
#else
/* ISO/IEC 9899:1999 <stdbool.h> missing -- enabling workaround */
# ifndef __cplusplus
typedef enum
{
false = 0,
true = 1
} _Bool;
# define false false
# define true true
# define bool _Bool
# endif
#endif
/* some GCC optimizations -- gcc 2.5+ */
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
#define GNUC_PRINTF( format_idx, arg_idx ) \
__attribute__((format (printf, format_idx, arg_idx)))
#define GNUC_SCANF( format_idx, arg_idx ) \
__attribute__((format (scanf, format_idx, arg_idx)))
#define GNUC_FORMAT( arg_idx ) \
__attribute__((format_arg (arg_idx)))
#define GNUC_NORETURN \
__attribute__((noreturn))
#define GNUC_CONST \
__attribute__((const))
#define GNUC_UNUSED \
__attribute__((unused))
#define GNUC_PACKED \
__attribute__((packed))
#else /* !__GNUC__ */
#define GNUC_PRINTF( format_idx, arg_idx )
#define GNUC_SCANF( format_idx, arg_idx )
#define GNUC_FORMAT( arg_idx )
#define GNUC_NORETURN
#define GNUC_CONST
#define GNUC_UNUSED
#define GNUC_PACKED
#endif /* !__GNUC__ */
#if defined(__GNUC__)
/* for GCC we try to use GNUC_PACKED */
# define PRAGMA_BEGIN_PACKED
# define PRAGMA_END_PACKED
#elif defined(HAVE_ISOC99_PRAGMA)
/* should work with most EDG-frontend based compilers */
# define PRAGMA_BEGIN_PACKED _Pragma("pack(1)")
# define PRAGMA_END_PACKED _Pragma("pack()")
#else /* neither gcc nor _Pragma() available... */
/* ...so let's be naive and hope the regression testsuite is run... */
# define PRAGMA_BEGIN_PACKED
# define PRAGMA_END_PACKED
#endif
/*
* user directed static branch prediction gcc 2.96+
*/
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 95)
# define GNUC_LIKELY(x) __builtin_expect((x),true)
# define GNUC_UNLIKELY(x) __builtin_expect((x),false)
#else
# define GNUC_LIKELY(x) (x)
# define GNUC_UNLIKELY(x) (x)
#endif
#ifndef NULL
# define NULL ((void*) 0)
#endif
/* our own offsetof()-like macro */
#define __cd_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
/* In many structures on the disk a sector address is stored as a
BCD-encoded mmssff in three bytes. */
PRAGMA_BEGIN_PACKED
typedef struct {
uint8_t m, s, f;
} GNUC_PACKED msf_t;
PRAGMA_END_PACKED
#define msf_t_SIZEOF 3
/* type used for bit-fields in structs (1 <= bits <= 8) */
#if defined(__GNUC__)
/* this is strict ISO C99 which allows only 'unsigned int', 'signed
int' and '_Bool' explicitly as bit-field type */
typedef unsigned int bitfield_t;
#else
/* other compilers might increase alignment requirements to match the
'unsigned int' type -- fixme: find out how unalignment accesses can
be pragma'ed on non-gcc compilers */
typedef uint8_t bitfield_t;
#endif
/* The type of a Logical Block Address. */
typedef uint32_t lba_t;
/* The type of an Logical Sector Number. */
typedef uint32_t lsn_t;
/* The type of an track number. */
typedef uint8_t track_t;
/*!
Constant for invalid track number
*/
#define CDIO_INVALID_TRACK 0xFF
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __CDIO_TYPES_H__ */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

249
lib/ds.c Normal file
View File

@@ -0,0 +1,249 @@
/*
$Id: ds.c,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include "ds.h"
#include "util.h"
#include "cdio_types.h"
#include "cdio_assert.h"
static const char _rcsid[] = "$Id: ds.c,v 1.1 2003/03/24 19:01:09 rocky Exp $";
struct _CdioList
{
unsigned length;
CdioListNode *begin;
CdioListNode *end;
};
struct _CdioListNode
{
CdioList *list;
CdioListNode *next;
void *data;
};
/* impl */
CdioList *
_cdio_list_new (void)
{
CdioList *new_obj = _cdio_malloc (sizeof (CdioList));
return new_obj;
}
void
_cdio_list_free (CdioList *list, int free_data)
{
while (_cdio_list_length (list))
_cdio_list_node_free (_cdio_list_begin (list), free_data);
free (list);
}
unsigned
_cdio_list_length (const CdioList *list)
{
cdio_assert (list != NULL);
return list->length;
}
void
_cdio_list_prepend (CdioList *list, void *data)
{
CdioListNode *new_node;
cdio_assert (list != NULL);
new_node = _cdio_malloc (sizeof (CdioListNode));
new_node->list = list;
new_node->next = list->begin;
new_node->data = data;
list->begin = new_node;
if (list->length == 0)
list->end = new_node;
list->length++;
}
void
_cdio_list_append (CdioList *list, void *data)
{
cdio_assert (list != NULL);
if (list->length == 0)
{
_cdio_list_prepend (list, data);
}
else
{
CdioListNode *new_node = _cdio_malloc (sizeof (CdioListNode));
new_node->list = list;
new_node->next = NULL;
new_node->data = data;
list->end->next = new_node;
list->end = new_node;
list->length++;
}
}
void
_cdio_list_foreach (CdioList *list, _cdio_list_iterfunc func, void *user_data)
{
CdioListNode *node;
cdio_assert (list != NULL);
cdio_assert (func != 0);
for (node = _cdio_list_begin (list);
node != NULL;
node = _cdio_list_node_next (node))
func (_cdio_list_node_data (node), user_data);
}
CdioListNode *
_cdio_list_find (CdioList *list, _cdio_list_iterfunc cmp_func, void *user_data)
{
CdioListNode *node;
cdio_assert (list != NULL);
cdio_assert (cmp_func != 0);
for (node = _cdio_list_begin (list);
node != NULL;
node = _cdio_list_node_next (node))
if (cmp_func (_cdio_list_node_data (node), user_data))
break;
return node;
}
CdioListNode *
_cdio_list_begin (const CdioList *list)
{
cdio_assert (list != NULL);
return list->begin;
}
CdioListNode *
_cdio_list_end (CdioList *list)
{
cdio_assert (list != NULL);
return list->end;
}
CdioListNode *
_cdio_list_node_next (CdioListNode *node)
{
if (node)
return node->next;
return NULL;
}
void
_cdio_list_node_free (CdioListNode *node, int free_data)
{
CdioList *list;
CdioListNode *prev_node;
cdio_assert (node != NULL);
list = node->list;
cdio_assert (_cdio_list_length (list) > 0);
if (free_data)
free (_cdio_list_node_data (node));
if (_cdio_list_length (list) == 1)
{
cdio_assert (list->begin == list->end);
list->end = list->begin = NULL;
list->length = 0;
free (node);
return;
}
cdio_assert (list->begin != list->end);
if (list->begin == node)
{
list->begin = node->next;
free (node);
list->length--;
return;
}
for (prev_node = list->begin; prev_node->next; prev_node = prev_node->next)
if (prev_node->next == node)
break;
cdio_assert (prev_node->next != NULL);
if (list->end == node)
list->end = prev_node;
prev_node->next = node->next;
list->length--;
free (node);
}
void *
_cdio_list_node_data (CdioListNode *node)
{
if (node)
return node->data;
return NULL;
}
/* eof */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

73
lib/ds.h Normal file
View File

@@ -0,0 +1,73 @@
/*
$Id: ds.h,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __CDIO_DS_H__
#define __CDIO_DS_H__
#include "cdio_types.h"
/* opaque... */
typedef struct _CdioList CdioList;
typedef struct _CdioListNode CdioListNode;
typedef int (*_cdio_list_cmp_func) (void *data1, void *data2);
typedef int (*_cdio_list_iterfunc) (void *data, void *user_data);
/* methods */
CdioList *_cdio_list_new (void);
void _cdio_list_free (CdioList *list, int free_data);
unsigned _cdio_list_length (const CdioList *list);
void _cdio_list_prepend (CdioList *list, void *data);
void _cdio_list_append (CdioList *list, void *data);
void _cdio_list_foreach (CdioList *list, _cdio_list_iterfunc func, void *user_data);
CdioListNode *_cdio_list_find (CdioList *list, _cdio_list_iterfunc cmp_func, void *user_data);
#define _CDIO_LIST_FOREACH(node, list) \
for (node = _cdio_list_begin (list); node; node = _cdio_list_node_next (node))
/* node ops */
CdioListNode *_cdio_list_begin (const CdioList *list);
CdioListNode *_cdio_list_end (CdioList *list);
CdioListNode *_cdio_list_node_next (CdioListNode *node);
void _cdio_list_node_free (CdioListNode *node, int free_data);
void *_cdio_list_node_data (CdioListNode *node);
#endif /* __CDIO_DS_H__ */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

129
lib/logging.c Normal file
View File

@@ -0,0 +1,129 @@
/*
$Id: logging.c,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include "cdio_assert.h"
#include "logging.h"
static const char _rcsid[] = "$Id: logging.c,v 1.1 2003/03/24 19:01:09 rocky Exp $";
static void
default_cdio_log_handler (cdio_log_level_t level, const char message[])
{
switch (level)
{
case CDIO_LOG_ERROR:
fprintf (stderr, "**ERROR: %s\n", message);
fflush (stderr);
exit (EXIT_FAILURE);
break;
case CDIO_LOG_DEBUG:
fprintf (stdout, "--DEBUG: %s\n", message);
break;
case CDIO_LOG_WARN:
fprintf (stdout, "++ WARN: %s\n", message);
break;
case CDIO_LOG_INFO:
fprintf (stdout, " INFO: %s\n", message);
break;
case CDIO_LOG_ASSERT:
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:
*/

64
lib/logging.h Normal file
View File

@@ -0,0 +1,64 @@
/*
$Id: logging.h,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __LOGGING_H__
#define __LOGGING_H__
#include "cdio_types.h"
typedef enum {
CDIO_LOG_DEBUG = 1,
CDIO_LOG_INFO,
CDIO_LOG_WARN,
CDIO_LOG_ERROR,
CDIO_LOG_ASSERT
} cdio_log_level_t;
void
cdio_log (cdio_log_level_t level, const char format[], ...) GNUC_PRINTF(2, 3);
typedef void (*cdio_log_handler_t) (cdio_log_level_t level,
const char message[]);
cdio_log_handler_t
cdio_log_set_handler (cdio_log_handler_t new_handler);
void
cdio_debug (const char format[], ...) GNUC_PRINTF(1,2);
void
cdio_info (const char format[], ...) GNUC_PRINTF(1,2);
void
cdio_warn (const char format[], ...) GNUC_PRINTF(1,2);
void
cdio_error (const char format[], ...) GNUC_PRINTF(1,2);
#endif /* __LOGGING_H__ */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

79
lib/sector.c Normal file
View File

@@ -0,0 +1,79 @@
/*
$Id: sector.c,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "cdio_assert.h"
#include "sector.h"
#include "util.h"
static const char _rcsid[] = "$Id: sector.c,v 1.1 2003/03/24 19:01:09 rocky Exp $";
void
cdio_lba_to_msf (uint32_t lba, msf_t *msf)
{
cdio_assert (msf != 0);
msf->m = to_bcd8 (lba / (60 * 75));
msf->s = to_bcd8 ((lba / 75) % 60);
msf->f = to_bcd8 (lba % 75);
}
void
cdio_lsn_to_msf (lsn_t lsn, msf_t *msf)
{
cdio_assert (msf != 0);
cdio_lba_to_msf(cdio_lsn_to_lba(lsn), msf);
}
uint32_t
cdio_msf_to_lba (const msf_t *msf)
{
uint32_t lba = 0;
cdio_assert (msf != 0);
lba = from_bcd8 (msf->m);
lba *= 60;
lba += from_bcd8 (msf->s);
lba *= 75;
lba += from_bcd8 (msf->f);
return lba;
}
uint32_t
cdio_msf_to_lsn (const msf_t *msf)
{
return cdio_lba_to_lsn(cdio_msf_to_lba (msf));
}
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

127
lib/sector.h Normal file
View File

@@ -0,0 +1,127 @@
/*
$Id: sector.h,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
Things related to CDROM layout. Sector sizes, MSFs, LBAs,
*/
#ifndef _CDIO_SECTOR_H_
#define _CDIO_SECTOR_H_
#include "cdio_types.h"
#define CDIO_PREGAP_SECTORS 150
#define CDIO_POSTGAP_SECTORS 150
/*!
Constant for ending or "leadout" track.
*/
#define CDIO_LEADOUT_TRACK 0xaa
/*
* A CD-ROM physical sector size is 2048, 2052, 2056, 2324, 2332, 2336,
* 2340, or 2352 bytes long.
* Sector types of the standard CD-ROM data formats:
*
* format sector type user data size (bytes)
* -----------------------------------------------------------------------------
* 1 (Red Book) CD-DA 2352 (CDDA_SECTOR_SIZE)
* 2 (Yellow Book) Mode1 Form1 2048 (M2F1_SECTOR_SIZE)
* 3 (Yellow Book) Mode1 Form2 2336 (M2RAW_SECTOR_SIZE)
* 4 (Green Book) Mode2 Form1 2048 (M2F1_SECTOR_SIZE)
* 5 (Green Book) Mode2 Form2 2328 (2324+4 spare bytes)
*
*
* The layout of the standard CD-ROM data formats:
* -----------------------------------------------------------------------------
* - audio (red): | audio_sample_bytes |
* | 2352 |
*
* - data (yellow, mode1): | sync - head - data - EDC - zero - ECC |
* | 12 - 4 - 2048 - 4 - 8 - 276 |
*
* - data (yellow, mode2): | sync - head - data |
* | 12 - 4 - 2336 |
*
* - XA data (green, mode2 form1): | sync - head - sub - data - EDC - ECC |
* | 12 - 4 - 8 - 2048 - 4 - 276 |
*
* - XA data (green, mode2 form2): | sync - head - sub - data - Spare |
* | 12 - 4 - 8 - 2324 - 4 |
*
*/
#define CD_RAW_SECTOR_SIZE 2352
#define CDDA_SECTOR_SIZE CD_RAW_SECTOR_SIZE
#define M2F1_SECTOR_SIZE 2048
#define M2F2_SECTOR_SIZE 2324
#define M2SUB_SECTOR_SIZE 2332
#define M2RAW_SECTOR_SIZE 2336
#define CD_MAX_TRACKS 99
#define CD_FRAMES_PER_SECOND 75
#define CD_FRAMES_PER_MINUTE (60*(CD_FRAMES_PER_SECOND))
#define CD_74MIN_SECTORS (UINT32_C(74)*CD_FRAMES_PER_MINUTE)
#define CD_80MIN_SECTORS (UINT32_C(80)*CD_FRAMES_PER_MINUTE)
#define CD_90MIN_SECTORS (UINT32_C(90)*CD_FRAMES_PER_MINUTE)
#define CD_MAX_SECTORS (UINT32_C(100)*CD_FRAMES_PER_MINUTE-CDIO_PREGAP_SECTORS)
#define msf_t_SIZEOF 3
/* warning, returns new allocated string */
char *
cdio_lba_to_msf_str (lba_t lba);
static inline lba_t
cdio_lba_to_lsn (lba_t lba)
{
return lba - CDIO_PREGAP_SECTORS;
}
void
cdio_lba_to_msf(lba_t lba, msf_t *msf);
static inline lba_t
cdio_lsn_to_lba (lsn_t lsn)
{
return lsn + CDIO_PREGAP_SECTORS;
}
void
cdio_lsn_to_msf (lsn_t lsn, msf_t *msf);
uint32_t
cdio_msf_to_lba (const msf_t *msf);
uint32_t
cdio_msf_to_lsn (const msf_t *msf);
#endif /* _CDIO_SECTOR_H_ */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

192
lib/util.c Normal file
View File

@@ -0,0 +1,192 @@
/*
$Id: util.c,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "cdio_assert.h"
#include "util.h"
static const char _rcsid[] = "$Id: util.c,v 1.1 2003/03/24 19:01:09 rocky Exp $";
size_t
_cdio_strlenv(char **str_array)
{
size_t n = 0;
cdio_assert (str_array != NULL);
while(str_array[n])
n++;
return n;
}
void
_cdio_strfreev(char **strv)
{
int n;
cdio_assert (strv != NULL);
for(n = 0; strv[n]; n++)
free(strv[n]);
free(strv);
}
char *
_cdio_strjoin (char *strv[], unsigned count, const char delim[])
{
size_t len;
char *new_str;
unsigned n;
cdio_assert (strv != NULL);
cdio_assert (delim != NULL);
len = (count-1) * strlen (delim);
for (n = 0;n < count;n++)
len += strlen (strv[n]);
len++;
new_str = _cdio_malloc (len);
new_str[0] = '\0';
for (n = 0;n < count;n++)
{
if (n)
strcat (new_str, delim);
strcat (new_str, strv[n]);
}
return new_str;
}
char **
_cdio_strsplit(const char str[], char delim) /* fixme -- non-reentrant */
{
int n;
char **strv = NULL;
char *_str, *p;
char _delim[2] = { 0, 0 };
cdio_assert (str != NULL);
_str = strdup(str);
_delim[0] = delim;
cdio_assert (_str != NULL);
n = 1;
p = _str;
while(*p)
if (*(p++) == delim)
n++;
strv = _cdio_malloc (sizeof (char *) * (n+1));
n = 0;
while((p = strtok(n ? NULL : _str, _delim)) != NULL)
strv[n++] = strdup(p);
free(_str);
return strv;
}
void *
_cdio_malloc (size_t size)
{
void *new_mem = malloc (size);
cdio_assert (new_mem != NULL);
memset (new_mem, 0, size);
return new_mem;
}
void *
_cdio_memdup (const void *mem, size_t count)
{
void *new_mem = NULL;
if (mem)
{
new_mem = _cdio_malloc (count);
memcpy (new_mem, mem, count);
}
return new_mem;
}
char *
_cdio_strdup_upper (const char str[])
{
char *new_str = NULL;
if (str)
{
char *p;
p = new_str = strdup (str);
while (*p)
{
*p = toupper (*p);
p++;
}
}
return new_str;
}
uint8_t
to_bcd8 (uint8_t n)
{
cdio_assert (n < 100);
return ((n/10)<<4) | (n%10);
}
uint8_t
from_bcd8(uint8_t p)
{
return (0xf & p)+(10*(p >> 4));
}
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

109
lib/util.h Normal file
View File

@@ -0,0 +1,109 @@
/*
$Id: util.h,v 1.1 2003/03/24 19:01:09 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __CDIO_UTIL_H__
#define __CDIO_UTIL_H__
#include <stdlib.h>
#undef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#undef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#undef IN
#define IN(x, low, high) ((x) >= (low) && (x) <= (high))
#undef CLAMP
#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
static inline unsigned
_cdio_len2blocks (unsigned len, int blocksize)
{
unsigned blocks;
blocks = len / blocksize;
if (len % blocksize)
blocks++;
return blocks;
}
/* round up to next block boundary */
static inline unsigned
_cdio_ceil2block (unsigned offset, int blocksize)
{
return _cdio_len2blocks (offset, blocksize) * blocksize;
}
static inline unsigned
_cdio_ofs_add (unsigned offset, unsigned length, int blocksize)
{
if (blocksize - (offset % blocksize) < length)
offset = _cdio_ceil2block (offset, blocksize);
offset += length;
return offset;
}
void *
_cdio_malloc (size_t size);
void *
_cdio_memdup (const void *mem, size_t count);
char *
_cdio_strdup_upper (const char str[]);
void
_cdio_strfreev(char **strv);
char *
_cdio_strjoin (char *strv[], unsigned count, const char delim[]);
size_t
_cdio_strlenv(char **str_array);
char **
_cdio_strsplit(const char str[], char delim);
static inline const char *
_cdio_bool_str (bool b)
{
return b ? "yes" : "no";
}
/* BCD */
uint8_t to_bcd8(uint8_t n);
uint8_t from_bcd8(uint8_t p);
#endif /* __CDIO_UTIL_H__ */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

68
libpopt.m4 Normal file
View File

@@ -0,0 +1,68 @@
# Configure paths for libpopt, based on m4's part of gnome
# (c) 2002 Herbert Valerio Riedel
dnl AM_PATH_LIBPOPT([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
dnl Test for libpopt, sets LIBPOPT_{CFLAGS,LIBS}
dnl alas there's no easy way to check the version available
AC_DEFUN(AM_PATH_LIBPOPT, [
AC_ARG_WITH(libpopt-prefix,[ --with-libpopt-prefix=PFX Prefix where libpopt is installed (optional)],
libpopt_prefix="$withval", libpopt_prefix="")
if test x$libpopt_prefix != x ; then
LIBPOPT_CFLAGS="-I$libpopt_prefix/include"
LIBPOPT_LIBS="-L$libpopt_prefix/lib -lpopt"
else
LIBPOPT_CFLAGS=""
LIBPOPT_LIBS="-lpopt"
fi
AC_MSG_CHECKING(for libpopt library)
dnl save CFLAGS and LIBS
ac_save_CFLAGS="$CFLAGS"
ac_save_LIBS="$LIBS"
CFLAGS="$CFLAGS $LIBPOPT_CFLAGS"
LIBS="$LIBPOPT_LIBS $LIBS"
dnl now check whether the installed libpopt is usable
rm -f conf.glibtest
AC_TRY_RUN([
#include <popt.h>
int
main(int argc, const char *argv[])
{
const struct poptOption options[] = {
POPT_AUTOHELP
{ NULL, 0, 0, NULL, 0 }
};
poptContext context = poptGetContext("popt-test", argc, argv, options, 0);
poptSetOtherOptionHelp (context, "[OPTION...] <argument...>");
poptGetNextOpt(context);
return 0;
}
],, no_popt=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
CFLAGS="$ac_save_CFLAGS"
LIBS="$ac_save_LIBS"
dnl handle test result
if test "x$no_popt" = x ; then
AC_MSG_RESULT(yes)
ifelse([$1], , :, [$1])
else
AC_MSG_RESULT(no)
LIBPOPT_CFLAGS=""
LIBPOPT_LIBS=""
ifelse([$2], , :, [$2])
fi
AC_SUBST(LIBPOPT_CFLAGS)
AC_SUBST(LIBPOPT_LIBS)
]) dnl AC_DEFUN(AM_PATH_LIBPOPT, [...
dnl EOF

8
src/.cvsignore Normal file
View File

@@ -0,0 +1,8 @@
.deps
.libs
Makefile
Makefile.in
*.o
cdinfo
cdinfo-linux
*.right

34
src/Makefile.am Normal file
View File

@@ -0,0 +1,34 @@
# $Id: Makefile.am,v 1.1 2003/03/24 19:01:09 rocky Exp $
#
# Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
####################################################
# Things to make the sample/test programs
####################################################
if BUILD_CDINFO_LINUX
bin_PROGRAMS = cdinfo cdinfo-linux
cdinfo_linux_SOURCES = cdinfo-linux.c
cdinfo_linux_LDADD = $(LIBCDIO_LIBS) -lpopt
else
EXTRA_DIST = cdinfo-linux.c
bin_PROGRAMS = cdinfo
endif
INCLUDES = -I$(top_srcdir) $(LIBCDIO_CFLAGS)
cdinfo_SOURCES = cdinfo.c
cdinfo_LDADD = $(LIBCDIO_LIBS) -lpopt

911
src/cdinfo-linux.c Normal file
View File

@@ -0,0 +1,911 @@
/*
$Id: cdinfo-linux.c,v 1.1 2003/03/24 19:01:10 rocky Exp $
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
Copyright (C) 1996,1997,1998 Gerd Knorr <kraxel@bytesex.org>
and Heiko Ei<45>feldt <heiko@hexco.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
CD Info - prints various information about a CD, and detects the type of
the CD.
usage: cdinfo [options] [ dev ]
*/
#define PROGRAM_NAME "CD Info"
#define CDINFO_VERSION "2.0"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#ifdef __linux__
# include <linux/version.h>
# include <linux/cdrom.h>
# if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,50)
# include <linux/ucdrom.h>
# endif
#endif
#include <sys/ioctl.h>
#include <errno.h>
#include <argp.h>
#include "config.h"
#include "cdio.h"
#include "logging.h"
#include "util.h"
#ifdef ENABLE_NLS
#include <locale.h>
# include <libintl.h>
# define _(String) dgettext ("cdinfo", String)
#else
/* Stubs that do something close enough. */
# define _(String) (String)
#endif
/* The following test is to work around the gross typo in
systems like Sony NEWS-OS Release 4.0C, whereby EXIT_FAILURE
is defined to 0, not 1. */
#if !EXIT_FAILURE
# undef EXIT_FAILURE
# define EXIT_FAILURE 1
#endif
#ifndef EXIT_SUCCESS
# define EXIT_SUCCESS 0
#endif
/* Used by `main' to communicate with `parse_opt'. And global options
*/
struct arguments
{
bool show_tracks;
bool show_ioctl;
bool show_analysis;
int debug_level;
bool silent;
} opts;
#define DEBUG 1
#if DEBUG
#define dbg_print(level, s, args...) \
if (opts.debug_level >= level) \
fprintf(stderr, "%s: "s, __func__ , ##args)
#else
#define dbg_print(level, s, args...)
#endif
#define err_exit(fmt, args...) \
fprintf(stderr, "%s: "fmt, program_name, ##args); \
myexit(EXIT_FAILURE)
/*
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.
*/
#define FS_NO_DATA 0 /* audio only */
#define FS_HIGH_SIERRA 1
#define FS_ISO_9660 2
#define FS_INTERACTIVE 3
#define FS_HFS 4
#define FS_UFS 5
#define FS_EXT2 6
#define FS_ISO_HFS 7 /* both hfs & isofs filesystem */
#define FS_ISO_9660_INTERACTIVE 8 /* both CD-RTOS and isofs filesystem */
#define FS_3DO 9
#define FS_UNKNOWN 15
#define FS_MASK 15
#define XA 16
#define MULTISESSION 32
#define PHOTO_CD 64
#define HIDDEN_TRACK 128
#define CDTV 256
#define BOOTABLE 512
#define VIDEOCDI 1024
#define ROCKRIDGE 2048
#define JOLIET 4096
/* Some interesting sector numbers. */
#define ISO_SUPERBLOCK_SECTOR 16
#define UFS_SUPERBLOCK_SECTOR 4
#define BOOT_SECTOR 17
#define VCD_INFO_SECTOR 150
#if 0
#define STRONG "\033[1m"
#define NORMAL "\033[0m"
#else
#define STRONG "__________________________________\n"
#define NORMAL ""
#endif
typedef struct signature
{
unsigned int buf_num;
unsigned int offset;
const char *sig_str;
const char *description;
} signature_t;
#define IS_ISOFS 0
#define IS_CD_I 1
#define IS_CDTV 2
#define IS_CD_RTOS 3
#define IS_HS 4
#define IS_BRIDGE 5
#define IS_XA 6
#define IS_PHOTO_CD 7
#define IS_EXT2 8
#define IS_UFS 9
#define IS_BOOTABLE 10
#define IS_VIDEO_CD 11
static signature_t sigs[] =
{
/* Buff off look for description */
{0, 1, "CD001", "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, 1024, "CD-XA001", "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"},
{ 0 }
};
int filehandle; /* Handle of /dev/>cdrom< */
int rc; /* return code */
int i,j; /* index */
int isofs_size = 0; /* size of session */
int start_track; /* first sector of track */
int ms_offset; /* multisession offset found by track-walking */
int data_start; /* start of data area */
int joliet_level = 0;
char buffer[6][CDDA_SECTOR_SIZE]; /* for CD-Data */
CdIo *img;
track_t num_tracks;
track_t first_track_num;
struct cdrom_tocentry *toc[CDIO_LEADOUT_TRACK+1]; /* TOC-entries */
struct cdrom_mcn mcn;
struct cdrom_multisession ms;
struct cdrom_subchnl sub;
int first_data = -1; /* # of first data track */
int num_data = 0; /* # of data tracks */
int first_audio = -1; /* # of first audio track */
int num_audio = 0; /* # of audio tracks */
char *devname = NULL;
char *program_name;
const char *argp_program_version = PROGRAM_NAME CDINFO_VERSION;
const char *argp_program_bug_address = "rocky@panix.com";
/* Program documentation. */
const char doc[] =
PROGRAM_NAME " -- Get information about a Compact Disk or CD image.";
/* A description of the arguments we accept. */
const char args_doc[] = "[DEVICE or DISK-IMAGE]";
static struct argp_option options[] =
{
{"debug", 'd', "LEVEL", 0, "Set debugging to LEVEL"},
{"quiet", 'q', 0, 0, "Don't produce any output" },
{"silent", 's', 0, OPTION_ALIAS },
{"notracks", 'T', 0, 0, "Don't show track information"},
{"noanalyze",'A', 0, 0, "Don't filesystem analysis"},
{"noioctl", 'I', 0, 0, "Don't show ioctl() information"},
{ 0 }
};
/* Parse a single option. */
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
/* Get the INPUT argument from `argp_parse', which we
know is a pointer to our arguments structure. */
struct arguments *arguments = state->input;
switch (key)
{
case 'q': case 's':
arguments->silent = 1;
break;
case 'd':
/* Default debug level is 1. */
arguments->debug_level = arg ? atol(arg): 1;
break;
case 'I':
arguments->show_ioctl = false;
break;
case 'T':
arguments->show_tracks = false;
break;
case 'A':
arguments->show_analysis = false;
break;
case ARGP_KEY_ARG:
/* Let the next case parse it. */
return ARGP_ERR_UNKNOWN;
break;
case ARGP_KEY_ARGS:
{
/* Check that only one device given. If so, handle it. */
unsigned int num_remaining_args = state->argc - state->next;
char **remaining_args = state->argv + state->next;
if (num_remaining_args > 1) {
argp_usage (state);
}
if (0 == strncmp(remaining_args[0],"/dev/",5))
devname = remaining_args[0];
else {
devname=malloc(6+strlen(remaining_args[0]));
sprintf(devname,"/dev/%s", remaining_args[0]);
}
}
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
static void
print_version (void)
{
printf( _("CD Info %s | (c) 2003 Gerd Knorr, Heiko Ei<45>feldt & R. Bernstein\n\
This is free software; see the source for copying conditions.\n\
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n\
PARTICULAR PURPOSE.\n\
"),
CDINFO_VERSION);
}
/* ------------------------------------------------------------------------ */
/* some ISO 9660 fiddling */
static int
read_block(int superblock, uint32_t offset, uint8_t bufnum, bool is_green)
{
memset(buffer[bufnum],0,M2F1_SECTOR_SIZE);
dbg_print(2, "about to read sector %u\n", offset+superblock);
if (cdio_read_mode2_sector(img, buffer[bufnum],
offset+superblock, !is_green))
return -1;
/* For now compare with what we get the old way.... */
if (0 > lseek(filehandle,M2F1_SECTOR_SIZE*(offset+superblock),SEEK_SET))
return -1;
memset(buffer[5],0,M2F1_SECTOR_SIZE);
if (0 > read(filehandle,buffer[5],M2F1_SECTOR_SIZE))
return -1;
if (memcmp(buffer[bufnum], buffer[5], M2F1_SECTOR_SIZE) != 0) {
dbg_print(0,
"libcdio conversion problem in reading super, buf %d\n",
bufnum);
}
return 0;
}
static bool
is_it(int num)
{
signature_t *sigp;
/* TODO: check that num < largest sig. */
sigp = &sigs[num];
int len = strlen(sigp->sig_str);
return 0 == memcmp(&buffer[sigp->buf_num][sigp->offset],
sigp->sig_str, len);
}
static int
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
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 is_joliet(void)
{
return 2 == buffer[3][0] && buffer[3][88] == 0x25 && buffer[3][89] == 0x2f;
}
/* ISO 9660 volume space in M2F1_SECTOR_SIZE byte units */
static int
get_size(void)
{
return ((buffer[0][80] & 0xff) |
((buffer[0][81] & 0xff) << 8) |
((buffer[0][82] & 0xff) << 16) |
((buffer[0][83] & 0xff) << 24));
}
static int
get_joliet_level( void )
{
switch (buffer[3][90]) {
case 0x40: return 1;
case 0x43: return 2;
case 0x45: return 3;
}
return 0;
}
#define is_it_dbg(sig) \
if (is_it(sig)) printf("%s, ", sigs[sig].description)
static int
guess_filesystem(int start_session, bool is_green)
{
int ret = 0;
if (read_block(ISO_SUPERBLOCK_SECTOR, start_session, 0, is_green) < 0)
return FS_UNKNOWN;
if (opts.debug_level > 0) {
/* buffer is defined */
is_it_dbg(IS_CD_I);
is_it_dbg(IS_CD_RTOS);
is_it_dbg(IS_ISOFS);
is_it_dbg(IS_HS);
is_it_dbg(IS_BRIDGE);
is_it_dbg(IS_XA);
is_it_dbg(IS_CDTV);
puts("");
}
/* filesystem */
if (is_it(IS_CD_I) && is_it(IS_CD_RTOS)
&& !is_it(IS_BRIDGE) && !is_it(IS_XA)) {
return FS_INTERACTIVE;
} else { /* read sector 0 ONLY, when NO greenbook CD-I !!!! */
if (read_block(0, start_session, 1, true) < 0)
return ret;
if (opts.debug_level > 0) {
/* buffer[1] is defined */
is_it_dbg(IS_PHOTO_CD);
if (is_hfs()) printf("HFS, ");
is_it_dbg(IS_EXT2);
if (is_3do()) printf("3DO, ");
puts("");
}
if (is_it(IS_HS))
ret |= FS_HIGH_SIERRA;
else if (is_it(IS_ISOFS)) {
if (is_it(IS_CD_RTOS) && is_it(IS_BRIDGE))
ret = FS_ISO_9660_INTERACTIVE;
else if (is_hfs())
ret = FS_ISO_HFS;
else
ret = FS_ISO_9660;
isofs_size = get_size();
#if 0
if (is_rockridge())
ret |= ROCKRIDGE;
#endif
if (read_block(BOOT_SECTOR, start_session, 3, true) < 0)
return ret;
if (opts.debug_level > 0) {
/* buffer[3] is defined */
if (is_joliet()) printf("JOLIET, ");
puts("");
is_it_dbg(IS_BOOTABLE);
puts("");
}
if (is_joliet()) {
joliet_level = get_joliet_level();
ret |= JOLIET;
}
if (is_it(IS_BOOTABLE))
ret |= BOOTABLE;
if (is_it(IS_BRIDGE) && is_it(IS_XA) && is_it(IS_ISOFS)
&& is_it(IS_CD_RTOS) &&
!is_it(IS_PHOTO_CD)) {
if (read_block(VCD_INFO_SECTOR, start_session, 4, true) < 0)
return ret;
if (opts.debug_level > 0) {
/* buffer[4] is defined */
is_it_dbg(IS_VIDEO_CD);
puts("");
}
if (is_it(IS_VIDEO_CD)) ret |= VIDEOCDI;
}
}
else if (is_hfs()) ret |= FS_HFS;
else if (is_it(IS_EXT2)) ret |= FS_EXT2;
else if (is_3do()) ret |= FS_3DO;
else {
if (read_block(UFS_SUPERBLOCK_SECTOR, start_session, 2, true) < 0)
return ret;
if (opts.debug_level > 0) {
/* buffer[2] is defined */
is_it_dbg(IS_UFS);
puts("");
}
if (is_it(IS_UFS))
ret |= FS_UFS;
else
ret |= FS_UNKNOWN;
}
}
/* other checks */
if (is_it(IS_XA)) ret |= XA;
if (is_it(IS_PHOTO_CD)) ret |= PHOTO_CD;
if (is_it(IS_CDTV)) ret |= CDTV;
return ret;
}
static void
myexit(int rc)
{
close(filehandle);
cdio_destroy(img);
exit(rc);
}
/* ------------------------------------------------------------------------ */
/* CDDB */
/*
Returns the sum of the decimal digits in a number. Eg. 1955 = 20
*/
static int
cddb_dec_digit_sum(int n)
{
int ret=0;
for (;;) {
ret += n%10;
n = n/10;
if (!n)
return ret;
}
}
/* Return the number of seconds (discarding frame portion) of an MSF */
static inline unsigned int
msf_seconds(msf_t *msf)
{
return from_bcd8(msf->m)*60 + from_bcd8(msf->s);
}
/*
Compute the CDDB disk ID for an Audio disk. This is a funny checksum
consisting of the concatenation of 3 things:
the sum of the decimal digits of sizes of all tracks,
the total length of the disk, and
the number of tracks.
*/
static unsigned long
cddb_discid()
{
int i,t,n=0;
msf_t start_msf;
msf_t msf;
for (i = 1; i <= num_tracks; i++) {
cdio_get_track_msf(img, i, &msf);
n += cddb_dec_digit_sum(msf_seconds(&msf));
}
cdio_get_track_msf(img, 1, &start_msf);
cdio_get_track_msf(img, CDIO_LEADOUT_TRACK, &msf);
t = msf_seconds(&msf) - msf_seconds(&start_msf);
return ((n % 0xff) << 24 | t << 8 | num_tracks);
}
/* CDIO logging routines */
static cdio_log_handler_t gl_default_log_handler = NULL;
static void
_log_handler (log_level_t level, const char message[])
{
if (level == LOG_DEBUG && opts.debug_level < 2)
return;
if (level == LOG_INFO && opts.debug_level < 1)
return;
if (level == LOG_WARN && opts.silent)
return;
gl_default_log_handler (level, message);
}
static void
print_analysis(int fs, int num_audio)
{
int need_lf;
switch(fs & FS_MASK) {
case FS_NO_DATA:
if (num_audio > 0)
printf("Audio CD, CDDB disc ID is %08lx\n", cddb_discid());
break;
case FS_ISO_9660:
printf("CD-ROM with ISO 9660 filesystem");
if (fs & JOLIET)
printf(" and joliet extension level %d", joliet_level);
if (fs & ROCKRIDGE)
printf(" and rockridge extensions");
printf("\n");
break;
case FS_ISO_9660_INTERACTIVE:
printf("CD-ROM with CD-RTOS and ISO 9660 filesystem\n");
break;
case FS_HIGH_SIERRA:
printf("CD-ROM with High Sierra filesystem\n");
break;
case FS_INTERACTIVE:
printf("CD-Interactive%s\n", num_audio > 0 ? "/Ready" : "");
break;
case FS_HFS:
printf("CD-ROM with Macintosh HFS\n");
break;
case FS_ISO_HFS:
printf("CD-ROM with both Macintosh HFS and ISO 9660 filesystem\n");
break;
case FS_UFS:
printf("CD-ROM with Unix UFS\n");
break;
case FS_EXT2:
printf("CD-ROM with Linux second extended filesystem\n");
break;
case FS_3DO:
printf("CD-ROM with Panasonic 3DO filesystem\n");
break;
case FS_UNKNOWN:
printf("CD-ROM with unknown filesystem\n");
break;
}
switch(fs & FS_MASK) {
case FS_ISO_9660:
case FS_ISO_9660_INTERACTIVE:
case FS_ISO_HFS:
printf("ISO 9660: %i blocks, label `%.32s'\n",
isofs_size, buffer[0]+40);
break;
}
need_lf = 0;
if (first_data == 1 && num_audio > 0)
need_lf += printf("mixed mode CD ");
if (fs & XA)
need_lf += printf("XA sectors ");
if (fs & MULTISESSION)
need_lf += printf("Multisession, offset = %i ",ms_offset);
if (fs & HIDDEN_TRACK)
need_lf += printf("Hidden Track ");
if (fs & PHOTO_CD)
need_lf += printf("%sPhoto CD ", num_audio > 0 ? " Portfolio " : "");
if (fs & CDTV)
need_lf += printf("Commodore CDTV ");
if (first_data > 1)
need_lf += printf("CD-Plus/Extra ");
if (fs & BOOTABLE)
need_lf += printf("bootable CD ");
if (fs & VIDEOCDI && num_audio == 0)
need_lf += printf("Video CD ");
if (need_lf) puts("");
}
/* ------------------------------------------------------------------------ */
/* Our argp parser. */
static struct argp argp = { options, parse_opt, args_doc, doc };
int
main(int argc, char *argv[])
{
int fs=0;
gl_default_log_handler = cdio_log_set_handler (_log_handler);
program_name = strrchr(argv[0],'/');
program_name = program_name ? program_name+1 : argv[0];
/* Default option values. */
opts.silent = false;
opts.debug_level = 0;
opts.show_tracks = true;
opts.show_ioctl = true;
opts.show_analysis = true;
/* Parse our arguments; every option seen by `parse_opt' will
be reflected in `arguments'. */
argp_parse (&argp, argc, argv, 0, 0, &opts);
print_version();
img = cdio_new_cd ();
if (devname==NULL) {
devname=strdup(cdio_get_default_device(img));
}
cdio_set_arg (img, "device", devname);
/* open device */
filehandle = open(devname,O_RDONLY);
if (filehandle == -1) {
err_exit("%s: %s\n", devname, strerror(errno));
}
first_track_num = cdio_get_first_track_num(img);
num_tracks = cdio_get_num_tracks(img);
if (opts.show_tracks) {
printf(STRONG "Track List (%i - %i)\n" NORMAL,
first_track_num, num_tracks);
printf(" nr: MSF LSN Ctrl Adr Type\n");
}
/* Read and possibly print track information. */
for (i = first_track_num; i <= CDIO_LEADOUT_TRACK; i++) {
msf_t msf;
toc[i] = malloc(sizeof(struct cdrom_tocentry));
if (toc[i] == NULL) {
err_exit("out of memory");
}
memset(toc[i],0,sizeof(struct cdrom_tocentry));
toc[i]->cdte_track = i;
toc[i]->cdte_format = CDROM_MSF;
if (ioctl(filehandle,CDROMREADTOCENTRY,toc[i])) {
err_exit("read TOC entry ioctl failed for track %i, give up\n", i);
}
if (!cdio_get_track_msf(img, i, &msf)) {
err_exit("cdio_track_msf for track %i failed, I give up.\n", i);
}
if (opts.show_tracks) {
printf("%3d: %2.2x:%2.2x:%2.2x (%06d) 0x%x 0x%x %s%s\n",
(int) i,
msf.m, msf.s, msf.f,
cdio_msf_to_lsn(&msf),
(int)toc[i]->cdte_ctrl,
(int)toc[i]->cdte_adr,
track_format2str[cdio_get_track_format(img, i)],
CDIO_LEADOUT_TRACK == i ? " (leadout)" : "");
}
if (i == CDIO_LEADOUT_TRACK)
break;
if (TRACK_FORMAT_DATA == cdio_get_track_format(img, i)) {
num_data++;
if (-1 == first_data)
first_data = i;
} else {
num_audio++;
if (-1 == first_audio)
first_audio = i;
}
/* skip to leadout */
if (i == num_tracks)
i = CDIO_LEADOUT_TRACK-1;
}
if (opts.show_ioctl) {
printf(STRONG "What ioctl's report...\n" NORMAL);
#ifdef CDROM_GET_MCN
/* get mcn */
printf("Get MCN : "); fflush(stdout);
if (ioctl(filehandle,CDROM_GET_MCN, &mcn))
printf("FAILED\n");
else
printf("%s\n",mcn.medium_catalog_number);
#endif
#ifdef CDROM_DISC_STATUS
/* get disk status */
printf("disc status : "); fflush(stdout);
switch (ioctl(filehandle,CDROM_DISC_STATUS,0)) {
case CDS_NO_INFO: printf("no info\n"); break;
case CDS_NO_DISC: printf("no disc\n"); break;
case CDS_AUDIO: printf("audio\n"); break;
case CDS_DATA_1: printf("data mode 1\n"); break;
case CDS_DATA_2: printf("data mode 2\n"); break;
case CDS_XA_2_1: printf("XA mode 1\n"); break;
case CDS_XA_2_2: printf("XA mode 2\n"); break;
default: printf("unknown (failed?)\n");
}
#endif
#ifdef CDROMMULTISESSION
/* get multisession */
printf("multisession: "); fflush(stdout);
ms.addr_format = CDROM_LBA;
if (ioctl(filehandle,CDROMMULTISESSION,&ms))
printf("FAILED\n");
else
printf("%d%s\n",ms.addr.lba,ms.xa_flag?" XA":"");
#endif
#ifdef CDROMSUBCHNL
/* get audio status from subchnl */
printf("audio status: "); fflush(stdout);
sub.cdsc_format = CDROM_MSF;
if (ioctl(filehandle,CDROMSUBCHNL,&sub))
printf("FAILED\n");
else {
switch (sub.cdsc_audiostatus) {
case CDROM_AUDIO_INVALID: printf("invalid\n"); break;
case CDROM_AUDIO_PLAY: printf("playing"); break;
case CDROM_AUDIO_PAUSED: printf("paused"); break;
case CDROM_AUDIO_COMPLETED: printf("completed\n"); break;
case CDROM_AUDIO_ERROR: printf("error\n"); break;
case CDROM_AUDIO_NO_STATUS: printf("no status\n"); break;
default: printf("Oops: unknown\n");
}
if (sub.cdsc_audiostatus == CDROM_AUDIO_PLAY ||
sub.cdsc_audiostatus == CDROM_AUDIO_PAUSED) {
printf(" at: %02d:%02d abs / %02d:%02d track %d\n",
sub.cdsc_absaddr.msf.minute,
sub.cdsc_absaddr.msf.second,
sub.cdsc_reladdr.msf.minute,
sub.cdsc_reladdr.msf.second,
sub.cdsc_trk);
}
}
#endif
}
if (opts.show_analysis) {
printf(STRONG "try to find out what sort of CD this is\n" NORMAL);
/* try to find out what sort of CD we have */
if (0 == num_data) {
/* no data track, may be a "real" audio CD or hidden track CD */
msf_t msf;
cdio_get_track_msf(img, 1, &msf);
start_track = cdio_msf_to_lsn(&msf);
/* CD-I/Ready says start_track <= 30*75 then CDDA */
if (start_track > 100 /* 100 is just a guess */) {
fs = guess_filesystem(0, false);
if ((fs & FS_MASK) != FS_UNKNOWN)
fs |= HIDDEN_TRACK;
else {
fs &= ~FS_MASK; /* del filesystem info */
printf("Oops: %i unused sectors at start, but hidden track check failed.\n",start_track);
}
}
print_analysis(fs, num_audio);
} else {
/* we have data track(s) */
for (j = 2, i = first_data; i <= num_tracks; i++) {
msf_t msf;
track_format_t track_format = cdio_get_track_format(img, i);
cdio_get_track_msf(img, i, &msf);
switch ( track_format ) {
case TRACK_FORMAT_AUDIO:
case TRACK_FORMAT_ERROR:
break;
case TRACK_FORMAT_CDI:
case TRACK_FORMAT_XA:
case TRACK_FORMAT_DATA:
;
}
start_track = (i == 1) ? 0 : cdio_msf_to_lsn(&msf);
/* save the start of the data area */
if (i == first_data)
data_start = start_track;
/* skip tracks which belong to the current walked session */
if (start_track < data_start + isofs_size)
continue;
fs = guess_filesystem(start_track, cdio_get_track_green(img, i));
if (i > 1) {
/* track is beyond last session -> new session found */
ms_offset = start_track;
printf("session #%d starts at track %2i, LSN: %6i,"
" ISO 9660 blocks: %6i\n",
j++, i, start_track, isofs_size);
printf("ISO 9660: %i blocks, label `%.32s'\n",
isofs_size, buffer[0]+40);
fs |= MULTISESSION;
} else {
print_analysis(fs, num_audio);
}
if (!(((fs & FS_MASK) == FS_ISO_9660 ||
(fs & FS_MASK) == FS_ISO_HFS ||
/* (fs & FS_MASK) == FS_ISO_9660_INTERACTIVE) && (fs & XA))) */
(fs & FS_MASK) == FS_ISO_9660_INTERACTIVE)))
break; /* no method for non-iso9660 multisessions */
}
}
}
myexit(EXIT_SUCCESS);
/* Not reached:*/
return(EXIT_SUCCESS);
}

999
src/cdinfo.c Normal file
View File

@@ -0,0 +1,999 @@
/*
$Id: cdinfo.c,v 1.1 2003/03/24 19:01:10 rocky Exp $
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
Copyright (C) 1996,1997,1998 Gerd Knorr <kraxel@bytesex.org>
and Heiko Ei<45>feldt <heiko@hexco.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
CD Info - prints various information about a CD, and detects the type of
the CD.
usage: cdinfo [options] [ dev ]
*/
#define PROGRAM_NAME "CD Info"
#define CDINFO_VERSION "2.0"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <popt.h>
/* Accomodate to older popt that doesn't support the "optional" flag */
#ifndef POPT_ARGFLAG_OPTIONAL
#define POPT_ARGFLAG_OPTIONAL 0
#endif
#include <fcntl.h>
#include <sys/ioctl.h>
#ifdef __linux__
# include <linux/version.h>
# include <linux/cdrom.h>
# if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,50)
# include <linux/ucdrom.h>
# endif
#endif
#include <sys/ioctl.h>
#include <errno.h>
#include "config.h"
#include "cdio.h"
#include "logging.h"
#include "util.h"
#ifdef ENABLE_NLS
#include <locale.h>
# include <libintl.h>
# define _(String) dgettext ("cdinfo", String)
#else
/* Stubs that do something close enough. */
# define _(String) (String)
#endif
/* The following test is to work around the gross typo in
systems like Sony NEWS-OS Release 4.0C, whereby EXIT_FAILURE
is defined to 0, not 1. */
#if !EXIT_FAILURE
# undef EXIT_FAILURE
# define EXIT_FAILURE 1
#endif
#ifndef EXIT_SUCCESS
# define EXIT_SUCCESS 0
#endif
#define DEBUG 1
#if DEBUG
#define dbg_print(level, s, args...) \
if (opts.debug_level >= level) \
fprintf(stderr, "%s: "s, __func__ , ##args)
#else
#define dbg_print(level, s, args...)
#endif
#define err_exit(fmt, args...) \
fprintf(stderr, "%s: "fmt, program_name, ##args); \
myexit(EXIT_FAILURE)
/*
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.
*/
#define FS_NO_DATA 0 /* audio only */
#define FS_HIGH_SIERRA 1
#define FS_ISO_9660 2
#define FS_INTERACTIVE 3
#define FS_HFS 4
#define FS_UFS 5
#define FS_EXT2 6
#define FS_ISO_HFS 7 /* both hfs & isofs filesystem */
#define FS_ISO_9660_INTERACTIVE 8 /* both CD-RTOS and isofs filesystem */
#define FS_3DO 9
#define FS_UNKNOWN 15
#define FS_MASK 15
#define XA 16
#define MULTISESSION 32
#define PHOTO_CD 64
#define HIDDEN_TRACK 128
#define CDTV 256
#define BOOTABLE 512
#define VIDEOCDI 1024
#define ROCKRIDGE 2048
#define JOLIET 4096
/* Some interesting sector numbers. */
#define ISO_SUPERBLOCK_SECTOR 16
#define UFS_SUPERBLOCK_SECTOR 4
#define BOOT_SECTOR 17
#define VCD_INFO_SECTOR 150
#if 0
#define STRONG "\033[1m"
#define NORMAL "\033[0m"
#else
#define STRONG "__________________________________\n"
#define NORMAL ""
#endif
typedef struct signature
{
unsigned int buf_num;
unsigned int offset;
const char *sig_str;
const char *description;
} signature_t;
#define IS_ISOFS 0
#define IS_CD_I 1
#define IS_CDTV 2
#define IS_CD_RTOS 3
#define IS_HS 4
#define IS_BRIDGE 5
#define IS_XA 6
#define IS_PHOTO_CD 7
#define IS_EXT2 8
#define IS_UFS 9
#define IS_BOOTABLE 10
#define IS_VIDEO_CD 11
static signature_t sigs[] =
{
/* Buff off look for description */
{0, 1, "CD001", "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, 1024, "CD-XA001", "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"},
{ 0 }
};
int rc; /* return code */
int i,j; /* index */
int isofs_size = 0; /* size of session */
int start_track; /* first sector of track */
int ms_offset; /* multisession offset found by track-walking */
int data_start; /* start of data area */
int joliet_level = 0;
char buffer[6][CDDA_SECTOR_SIZE]; /* for CD-Data */
CdIo *img;
track_t num_tracks;
track_t first_track_num;
#if CDIO_IOCTL_FINISHED
struct cdrom_mcn mcn;
struct cdrom_multisession ms;
struct cdrom_subchnl sub;
#endif
int first_data = -1; /* # of first data track */
int num_data = 0; /* # of data tracks */
int first_audio = -1; /* # of first audio track */
int num_audio = 0; /* # of audio tracks */
char *source_name = NULL;
char *program_name;
const char *argp_program_version = PROGRAM_NAME CDINFO_VERSION;
const char *argp_program_bug_address = "rocky@panix.com";
typedef enum
{
IMAGE_AUTO,
IMAGE_DEVICE,
IMAGE_BIN,
IMAGE_CUE,
IMAGE_NRG,
IMAGE_UNKNOWN
} source_image_t;
/* Used by `main' to communicate with `parse_opt'. And global options
*/
struct arguments
{
bool no_tracks;
bool no_ioctl;
bool no_analysis;
int debug_level;
bool silent;
source_image_t source_image;
} opts;
/* Program documentation. */
const char doc[] =
PROGRAM_NAME " -- Get information about a Compact Disk or CD image.";
/* A description of the arguments we accept. */
const char args_doc[] = "[DEVICE or DISK-IMAGE]";
/* Configuration option codes */
enum {
OP_SOURCE_UNDEF,
OP_SOURCE_AUTO,
OP_SOURCE_BIN,
OP_SOURCE_CUE,
OP_SOURCE_NRG ,
OP_SOURCE_DEVICE,
/* These are the remaining configuration options */
OP_VERSION, OP_NOIOCTL, OP_NOTRACKS, OP_QUIET,
OP_NOANALYZE
};
char *temp_str;
struct poptOption optionsTable[] = {
{"debug", 'd', POPT_ARG_INT, &opts.debug_level, 0,
"Set debugging to LEVEL"},
{"quiet", 'q', POPT_ARG_NONE, &opts.silent, 0,
"Don't produce warning output" },
{"notracks", 'T', POPT_ARG_NONE, &opts.no_tracks, 0,
"Don't show track information"},
{"noanalyze",'A', POPT_ARG_NONE, &opts.no_analysis, 0,
"Don't filesystem analysis"},
{"noioctl", 'I', POPT_ARG_NONE, &opts.no_ioctl, 0,
"Don't show ioctl() information"},
{"bin-file", 'b', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, &source_name,
OP_SOURCE_BIN, "set \"bin\" CD-ROM disk image file as source", "FILE"},
{"cue-file", 'c', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, &source_name,
OP_SOURCE_CUE, "set \"cue\" CD-ROM disk image file as source", "FILE"},
{"input", 'i', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, &source_name,
OP_SOURCE_AUTO,
"set source and determine if \"bin\" image or device", "FILE"},
{"cdrom-device", 'C', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, &source_name,
OP_SOURCE_DEVICE,
"set CD-ROM device as source", "DEVICE"},
{"nrg-file", 'N', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, &source_name,
OP_SOURCE_NRG, "set Nero CD-ROM disk image file as source", "FILE"},
{"quiet", 'q', POPT_ARG_NONE, &opts.silent, 0,
"show only critical messages"},
{"version", 'V', POPT_ARG_NONE, NULL, OP_VERSION,
"display version and copyright information and exit"},
POPT_AUTOHELP {NULL, 0, 0, NULL, 0}
};
#define DEV_PREFIX "/dev/"
static char *
fillout_device_name(const char *device_name)
{
unsigned int prefix_len=strlen(DEV_PREFIX);
if (0 == strncmp(device_name, DEV_PREFIX, prefix_len))
return strdup(device_name);
else {
char *full_device_name=malloc(strlen(device_name)+prefix_len);
sprintf(full_device_name, DEV_PREFIX "%s", device_name);
return full_device_name;
}
}
/* Parse a single option. */
static bool
parse_options (poptContext optCon)
{
int opt;
while ((opt = poptGetNextOpt (optCon)) != -1) {
switch (opt) {
case OP_SOURCE_AUTO:
case OP_SOURCE_BIN:
case OP_SOURCE_CUE:
case OP_SOURCE_NRG:
case OP_SOURCE_DEVICE:
if (opts.source_image != IMAGE_UNKNOWN) {
fprintf(stderr,
"%s: another source type option given before.\n",
program_name);
fprintf(stderr, "%s: give only one source type option.\n",
program_name);
break;
}
switch (opt) {
case OP_SOURCE_BIN:
opts.source_image = IMAGE_BIN;
break;
case OP_SOURCE_CUE:
opts.source_image = IMAGE_CUE;
break;
case OP_SOURCE_NRG:
opts.source_image = IMAGE_NRG;
break;
case OP_SOURCE_AUTO:
opts.source_image = IMAGE_AUTO;
break;
case OP_SOURCE_DEVICE:
opts.source_image = IMAGE_DEVICE;
source_name = fillout_device_name(source_name);
break;
}
break;
default:
return false;
}
}
{
const char *remaining_arg = poptGetArg(optCon);
if ( remaining_arg != NULL) {
if (opts.source_image != IMAGE_UNKNOWN) {
fprintf (stderr,
"%s: Source specified in option %s and as %s\n",
program_name, source_name, remaining_arg);
exit (EXIT_FAILURE);
}
if (opts.source_image == OP_SOURCE_DEVICE)
source_name = fillout_device_name(remaining_arg);
if ( (poptGetArgs(optCon)) != NULL) {
fprintf (stderr,
"%s: Source specified in previously %s and %s\n",
program_name, source_name, remaining_arg);
exit (EXIT_FAILURE);
}
}
}
return true;
}
static void
print_version (void)
{
printf( _("CD Info %s | (c) 2003 Gerd Knorr, Heiko Ei<45>feldt & R. Bernstein\n\
This is free software; see the source for copying conditions.\n\
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n\
PARTICULAR PURPOSE.\n\
"),
CDINFO_VERSION);
}
/* ------------------------------------------------------------------------ */
/* some ISO 9660 fiddling */
static int
read_block(int superblock, uint32_t offset, uint8_t bufnum, bool is_green)
{
memset(buffer[bufnum],0,M2F1_SECTOR_SIZE);
dbg_print(2, "about to read sector %u\n", offset+superblock);
if (cdio_read_mode2_sector(img, buffer[bufnum],
offset+superblock, !is_green))
return -1;
return 0;
}
static bool
is_it(int num)
{
signature_t *sigp;
/* TODO: check that num < largest sig. */
sigp = &sigs[num];
int len = strlen(sigp->sig_str);
return 0 == memcmp(&buffer[sigp->buf_num][sigp->offset],
sigp->sig_str, len);
}
static int
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
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 is_joliet(void)
{
return 2 == buffer[3][0] && buffer[3][88] == 0x25 && buffer[3][89] == 0x2f;
}
/* ISO 9660 volume space in M2F1_SECTOR_SIZE byte units */
static int
get_size(void)
{
return ((buffer[0][80] & 0xff) |
((buffer[0][81] & 0xff) << 8) |
((buffer[0][82] & 0xff) << 16) |
((buffer[0][83] & 0xff) << 24));
}
static int
get_joliet_level( void )
{
switch (buffer[3][90]) {
case 0x40: return 1;
case 0x43: return 2;
case 0x45: return 3;
}
return 0;
}
#define is_it_dbg(sig) \
if (is_it(sig)) printf("%s, ", sigs[sig].description)
static int
guess_filesystem(int start_session, bool is_green)
{
int ret = 0;
if (read_block(ISO_SUPERBLOCK_SECTOR, start_session, 0, is_green) < 0)
return FS_UNKNOWN;
if (opts.debug_level > 0) {
/* buffer is defined */
is_it_dbg(IS_CD_I);
is_it_dbg(IS_CD_RTOS);
is_it_dbg(IS_ISOFS);
is_it_dbg(IS_HS);
is_it_dbg(IS_BRIDGE);
is_it_dbg(IS_XA);
is_it_dbg(IS_CDTV);
puts("");
}
/* filesystem */
if (is_it(IS_CD_I) && is_it(IS_CD_RTOS)
&& !is_it(IS_BRIDGE) && !is_it(IS_XA)) {
return FS_INTERACTIVE;
} else { /* read sector 0 ONLY, when NO greenbook CD-I !!!! */
if (read_block(0, start_session, 1, true) < 0)
return ret;
if (opts.debug_level > 0) {
/* buffer[1] is defined */
is_it_dbg(IS_PHOTO_CD);
if (is_hfs()) printf("HFS, ");
is_it_dbg(IS_EXT2);
if (is_3do()) printf("3DO, ");
puts("");
}
if (is_it(IS_HS))
ret |= FS_HIGH_SIERRA;
else if (is_it(IS_ISOFS)) {
if (is_it(IS_CD_RTOS) && is_it(IS_BRIDGE))
ret = FS_ISO_9660_INTERACTIVE;
else if (is_hfs())
ret = FS_ISO_HFS;
else
ret = FS_ISO_9660;
isofs_size = get_size();
#if 0
if (is_rockridge())
ret |= ROCKRIDGE;
#endif
if (read_block(BOOT_SECTOR, start_session, 3, true) < 0)
return ret;
if (opts.debug_level > 0) {
/* buffer[3] is defined */
if (is_joliet()) printf("JOLIET, ");
puts("");
is_it_dbg(IS_BOOTABLE);
puts("");
}
if (is_joliet()) {
joliet_level = get_joliet_level();
ret |= JOLIET;
}
if (is_it(IS_BOOTABLE))
ret |= BOOTABLE;
if (is_it(IS_BRIDGE) && is_it(IS_XA) && is_it(IS_ISOFS)
&& is_it(IS_CD_RTOS) &&
!is_it(IS_PHOTO_CD)) {
if (read_block(VCD_INFO_SECTOR, start_session, 4, true) < 0)
return ret;
if (opts.debug_level > 0) {
/* buffer[4] is defined */
is_it_dbg(IS_VIDEO_CD);
puts("");
}
if (is_it(IS_VIDEO_CD)) ret |= VIDEOCDI;
}
}
else if (is_hfs()) ret |= FS_HFS;
else if (is_it(IS_EXT2)) ret |= FS_EXT2;
else if (is_3do()) ret |= FS_3DO;
else {
if (read_block(UFS_SUPERBLOCK_SECTOR, start_session, 2, true) < 0)
return ret;
if (opts.debug_level > 0) {
/* buffer[2] is defined */
is_it_dbg(IS_UFS);
puts("");
}
if (is_it(IS_UFS))
ret |= FS_UFS;
else
ret |= FS_UNKNOWN;
}
}
/* other checks */
if (is_it(IS_XA)) ret |= XA;
if (is_it(IS_PHOTO_CD)) ret |= PHOTO_CD;
if (is_it(IS_CDTV)) ret |= CDTV;
return ret;
}
static void
myexit(int rc)
{
cdio_destroy(img);
exit(rc);
}
/* ------------------------------------------------------------------------ */
/* CDDB */
/*
Returns the sum of the decimal digits in a number. Eg. 1955 = 20
*/
static int
cddb_dec_digit_sum(int n)
{
int ret=0;
for (;;) {
ret += n%10;
n = n/10;
if (!n)
return ret;
}
}
/* Return the number of seconds (discarding frame portion) of an MSF */
static inline unsigned int
msf_seconds(msf_t *msf)
{
return from_bcd8(msf->m)*60 + from_bcd8(msf->s);
}
/*
Compute the CDDB disk ID for an Audio disk. This is a funny checksum
consisting of the concatenation of 3 things:
the sum of the decimal digits of sizes of all tracks,
the total length of the disk, and
the number of tracks.
*/
static unsigned long
cddb_discid()
{
int i,t,n=0;
msf_t start_msf;
msf_t msf;
for (i = 1; i <= num_tracks; i++) {
cdio_get_track_msf(img, i, &msf);
n += cddb_dec_digit_sum(msf_seconds(&msf));
}
cdio_get_track_msf(img, 1, &start_msf);
cdio_get_track_msf(img, CDIO_LEADOUT_TRACK, &msf);
t = msf_seconds(&msf) - msf_seconds(&start_msf);
return ((n % 0xff) << 24 | t << 8 | num_tracks);
}
/* CDIO logging routines */
static cdio_log_handler_t gl_default_log_handler = NULL;
static void
_log_handler (cdio_log_level_t level, const char message[])
{
if (level == CDIO_LOG_DEBUG && opts.debug_level < 2)
return;
if (level == CDIO_LOG_INFO && opts.debug_level < 1)
return;
if (level == CDIO_LOG_WARN && opts.silent)
return;
gl_default_log_handler (level, message);
}
static void
print_analysis(int fs, int num_audio)
{
int need_lf;
switch(fs & FS_MASK) {
case FS_NO_DATA:
if (num_audio > 0)
printf("Audio CD, CDDB disc ID is %08lx\n", cddb_discid());
break;
case FS_ISO_9660:
printf("CD-ROM with ISO 9660 filesystem");
if (fs & JOLIET)
printf(" and joliet extension level %d", joliet_level);
if (fs & ROCKRIDGE)
printf(" and rockridge extensions");
printf("\n");
break;
case FS_ISO_9660_INTERACTIVE:
printf("CD-ROM with CD-RTOS and ISO 9660 filesystem\n");
break;
case FS_HIGH_SIERRA:
printf("CD-ROM with High Sierra filesystem\n");
break;
case FS_INTERACTIVE:
printf("CD-Interactive%s\n", num_audio > 0 ? "/Ready" : "");
break;
case FS_HFS:
printf("CD-ROM with Macintosh HFS\n");
break;
case FS_ISO_HFS:
printf("CD-ROM with both Macintosh HFS and ISO 9660 filesystem\n");
break;
case FS_UFS:
printf("CD-ROM with Unix UFS\n");
break;
case FS_EXT2:
printf("CD-ROM with Linux second extended filesystem\n");
break;
case FS_3DO:
printf("CD-ROM with Panasonic 3DO filesystem\n");
break;
case FS_UNKNOWN:
printf("CD-ROM with unknown filesystem\n");
break;
}
switch(fs & FS_MASK) {
case FS_ISO_9660:
case FS_ISO_9660_INTERACTIVE:
case FS_ISO_HFS:
printf("ISO 9660: %i blocks, label `%.32s'\n",
isofs_size, buffer[0]+40);
break;
}
need_lf = 0;
if (first_data == 1 && num_audio > 0)
need_lf += printf("mixed mode CD ");
if (fs & XA)
need_lf += printf("XA sectors ");
if (fs & MULTISESSION)
need_lf += printf("Multisession, offset = %i ",ms_offset);
if (fs & HIDDEN_TRACK)
need_lf += printf("Hidden Track ");
if (fs & PHOTO_CD)
need_lf += printf("%sPhoto CD ", num_audio > 0 ? " Portfolio " : "");
if (fs & CDTV)
need_lf += printf("Commodore CDTV ");
if (first_data > 1)
need_lf += printf("CD-Plus/Extra ");
if (fs & BOOTABLE)
need_lf += printf("bootable CD ");
if (fs & VIDEOCDI && num_audio == 0)
need_lf += printf("Video CD ");
if (need_lf) puts("");
}
/* ------------------------------------------------------------------------ */
int
main(int argc, const char *argv[])
{
int fs=0;
poptContext optCon = poptGetContext (NULL, argc, argv, optionsTable, 0);
gl_default_log_handler = cdio_log_set_handler (_log_handler);
program_name = strrchr(argv[0],'/');
program_name = program_name ? program_name+1 : strdup(argv[0]);
/* Default option values. */
opts.silent = false;
opts.debug_level = 0;
opts.no_tracks = false;
opts.no_ioctl = false;
opts.no_analysis = false;
opts.source_image = IMAGE_UNKNOWN;
/* Parse our arguments; every option seen by `parse_opt' will
be reflected in `arguments'. */
parse_options(optCon);
print_version();
switch (opts.source_image) {
case IMAGE_UNKNOWN:
case IMAGE_AUTO:
img = cdio_open (source_name, DRIVER_UNKNOWN);
break;
case IMAGE_DEVICE:
img = cdio_open (source_name, DRIVER_DEVICE);
break;
case IMAGE_BIN:
img = cdio_open (source_name, DRIVER_BINCUE);
break;
case IMAGE_CUE:
img = cdio_open_cue(source_name);
break;
case IMAGE_NRG:
img = cdio_open (source_name, DRIVER_NRG);
break;
}
if (source_name==NULL) {
source_name=strdup(cdio_get_arg(img, "source"));
}
first_track_num = cdio_get_first_track_num(img);
num_tracks = cdio_get_num_tracks(img);
if (!opts.no_tracks) {
printf(STRONG "CD-ROM Track List (%i - %i)\n" NORMAL,
first_track_num, num_tracks);
printf(" #: MSF LSN Type\n");
}
/* Read and possibly print track information. */
for (i = first_track_num; i <= CDIO_LEADOUT_TRACK; i++) {
msf_t msf;
if (!cdio_get_track_msf(img, i, &msf)) {
err_exit("cdio_track_msf for track %i failed, I give up.\n", i);
}
if (i == CDIO_LEADOUT_TRACK) {
if (!opts.no_tracks)
printf("%3d: %2.2x:%2.2x:%2.2x %06d leadout\n",
(int) i,
msf.m, msf.s, msf.f,
cdio_msf_to_lsn(&msf));
break;
} else if (!opts.no_tracks) {
printf("%3d: %2.2x:%2.2x:%2.2x %06d %s\n",
(int) i,
msf.m, msf.s, msf.f,
cdio_msf_to_lsn(&msf),
track_format2str[cdio_get_track_format(img, i)]);
}
if (TRACK_FORMAT_AUDIO == cdio_get_track_format(img, i)) {
num_audio++;
if (-1 == first_audio)
first_audio = i;
} else {
num_data++;
if (-1 == first_data)
first_data = i;
}
/* skip to leadout? */
if (i == num_tracks) i = CDIO_LEADOUT_TRACK-1;
}
#if CDIO_IOCTL_FINISHED
if (!opts.no_ioctl) {
printf(STRONG "What ioctl's report...\n" NORMAL);
#ifdef CDROM_GET_MCN
/* get mcn */
printf("Get MCN : "); fflush(stdout);
if (ioctl(filehandle,CDROM_GET_MCN, &mcn))
printf("FAILED\n");
else
printf("%s\n",mcn.medium_catalog_number);
#endif
#ifdef CDROM_DISC_STATUS
/* get disk status */
printf("disc status : "); fflush(stdout);
switch (ioctl(filehandle,CDROM_DISC_STATUS,0)) {
case CDS_NO_INFO: printf("no info\n"); break;
case CDS_NO_DISC: printf("no disc\n"); break;
case CDS_AUDIO: printf("audio\n"); break;
case CDS_DATA_1: printf("data mode 1\n"); break;
case CDS_DATA_2: printf("data mode 2\n"); break;
case CDS_XA_2_1: printf("XA mode 1\n"); break;
case CDS_XA_2_2: printf("XA mode 2\n"); break;
default: printf("unknown (failed?)\n");
}
#endif
#ifdef CDROMMULTISESSION
/* get multisession */
printf("multisession: "); fflush(stdout);
ms.addr_format = CDROM_LBA;
if (ioctl(filehandle,CDROMMULTISESSION,&ms))
printf("FAILED\n");
else
printf("%d%s\n",ms.addr.lba,ms.xa_flag?" XA":"");
#endif
#ifdef CDROMSUBCHNL
/* get audio status from subchnl */
printf("audio status: "); fflush(stdout);
sub.cdsc_format = CDROM_MSF;
if (ioctl(filehandle,CDROMSUBCHNL,&sub))
printf("FAILED\n");
else {
switch (sub.cdsc_audiostatus) {
case CDROM_AUDIO_INVALID: printf("invalid\n"); break;
case CDROM_AUDIO_PLAY: printf("playing"); break;
case CDROM_AUDIO_PAUSED: printf("paused"); break;
case CDROM_AUDIO_COMPLETED: printf("completed\n"); break;
case CDROM_AUDIO_ERROR: printf("error\n"); break;
case CDROM_AUDIO_NO_STATUS: printf("no status\n"); break;
default: printf("Oops: unknown\n");
}
if (sub.cdsc_audiostatus == CDROM_AUDIO_PLAY ||
sub.cdsc_audiostatus == CDROM_AUDIO_PAUSED) {
printf(" at: %02d:%02d abs / %02d:%02d track %d\n",
sub.cdsc_absaddr.msf.minute,
sub.cdsc_absaddr.msf.second,
sub.cdsc_reladdr.msf.minute,
sub.cdsc_reladdr.msf.second,
sub.cdsc_trk);
}
}
#endif /* CDROMSUBCHNL */
}
#endif /*CDIO_IOCTL_FINISHED*/
if (!opts.no_analysis) {
printf(STRONG "try to find out what sort of CD this is\n" NORMAL);
/* try to find out what sort of CD we have */
if (0 == num_data) {
/* no data track, may be a "real" audio CD or hidden track CD */
msf_t msf;
cdio_get_track_msf(img, 1, &msf);
start_track = cdio_msf_to_lsn(&msf);
/* CD-I/Ready says start_track <= 30*75 then CDDA */
if (start_track > 100 /* 100 is just a guess */) {
fs = guess_filesystem(0, false);
if ((fs & FS_MASK) != FS_UNKNOWN)
fs |= HIDDEN_TRACK;
else {
fs &= ~FS_MASK; /* del filesystem info */
printf("Oops: %i unused sectors at start, but hidden track check failed.\n",start_track);
}
}
print_analysis(fs, num_audio);
} else {
/* we have data track(s) */
for (j = 2, i = first_data; i <= num_tracks; i++) {
msf_t msf;
track_format_t track_format = cdio_get_track_format(img, i);
cdio_get_track_msf(img, i, &msf);
switch ( track_format ) {
case TRACK_FORMAT_AUDIO:
case TRACK_FORMAT_ERROR:
break;
case TRACK_FORMAT_CDI:
case TRACK_FORMAT_XA:
case TRACK_FORMAT_DATA:
;
}
start_track = (i == 1) ? 0 : cdio_msf_to_lsn(&msf);
/* save the start of the data area */
if (i == first_data)
data_start = start_track;
/* skip tracks which belong to the current walked session */
if (start_track < data_start + isofs_size)
continue;
fs = guess_filesystem(start_track, cdio_get_track_green(img, i));
if (i > 1) {
/* track is beyond last session -> new session found */
ms_offset = start_track;
printf("session #%d starts at track %2i, LSN: %6i,"
" ISO 9660 blocks: %6i\n",
j++, i, start_track, isofs_size);
printf("ISO 9660: %i blocks, label `%.32s'\n",
isofs_size, buffer[0]+40);
fs |= MULTISESSION;
} else {
print_analysis(fs, num_audio);
}
if (!(((fs & FS_MASK) == FS_ISO_9660 ||
(fs & FS_MASK) == FS_ISO_HFS ||
/* (fs & FS_MASK) == FS_ISO_9660_INTERACTIVE) && (fs & XA))) */
(fs & FS_MASK) == FS_ISO_9660_INTERACTIVE)))
break; /* no method for non-iso9660 multisessions */
}
}
}
myexit(EXIT_SUCCESS);
/* Not reached:*/
return(EXIT_SUCCESS);
}

6
tests/.cvsignore Normal file
View File

@@ -0,0 +1,6 @@
Makefile
Makefile.in
*.dump
*.cue
*.bin
*.nrg

32
tests/Makefile.am Normal file
View File

@@ -0,0 +1,32 @@
# $Id: Makefile.am,v 1.1 2003/03/24 19:01:10 rocky Exp $
#
# Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
####################################################
# Things to regression testing
####################################################
#
check_SCRIPTS = check_nrg.sh check_cue.sh
check_DATA = monvoisin.right svcd_ogt_test_ntsc.right vcd_demo.right
EXTRA_DIST = $(check_SCRIPTS) $(check_DATA) \
check_common_fn
TESTS = $(check_SCRIPTS)
MOSTLYCLEANFILES = core.* *.dump

70
tests/check_common_fn Executable file
View File

@@ -0,0 +1,70 @@
# $Id: check_common_fn,v 1.1 2003/03/24 19:01:10 rocky Exp $
have_cmp() {
if cmp /dev/null /dev/null > /dev/null 2>&1; then
:
else
return 1;
fi
if cmp /dev/zero /dev/null > /dev/null 2>&1; then
return 1;
fi
return 0;
}
check_result() {
RC=$1
shift
msg=$*
if test $RC -ne 0 ; then
if test $RC -ne 77 ; then
echo "$0: $msg failed."
exit $RC
else
echo "$0: $msg skipped."
fi
else
echo "$0: $msg ok."
fi
}
test_cdinfo() {
opts="$1"
outfile="$2"
rightfile="$3"
CDINFO="../src/cdinfo"
if [ ! -x ${CDINFO} ]; then
echo "$0: No cdinfo"
return 1
fi
if ${CDINFO} ${opts} >${outfile} 2>&1 ; then
if have_cmp; then
if cmp ${outfile} ${rightfile} ; then
rm -f $outfile
return 0
else
return 3
fi
else
echo "$0: No cmp(1) found - cannot test cdinfo"
rm -f $outfile
return 77
fi
else
echo "$0: ${CDINFO} ${opts} failed"
return 2
fi
}
#;;; Local Variables: ***
#;;; mode:shell-script ***
#;;; eval: (sh-set-shell "bash") ***
#;;; End: ***

27
tests/check_cue.sh Executable file
View File

@@ -0,0 +1,27 @@
#!/bin/sh
#$Id: check_cue.sh,v 1.1 2003/03/24 19:01:10 rocky Exp $
if test -z $srcdir ; then
srcdir=`pwd`
fi
. ${srcdir}/check_common_fn
BASE=`basename $0 .sh`
test_cdinfo "--cue-file ${srcdir}/svcd_ogt_test_ntsc.cue" \
svcd_ogt_test_ntsc.dump ${srcdir}/svcd_ogt_test_ntsc.right
RC=$?
check_result $RC 'cdinfo CUE test 1'
test_cdinfo "-c ${srcdir}/vcd_demo.cue" \
vcd_demo.dump ${srcdir}/vcd_demo.right
RC=$?
check_result $RC 'cdinfo CUE test 2'
exit $RC
#;;; Local Variables: ***
#;;; mode:shell-script ***
#;;; eval: (sh-set-shell "bash") ***
#;;; End: ***

22
tests/check_nrg.sh Executable file
View File

@@ -0,0 +1,22 @@
#!/bin/sh
#$Id: check_nrg.sh,v 1.1 2003/03/24 19:01:10 rocky Exp $
if test -z $srcdir ; then
srcdir=`pwd`
fi
. ${srcdir}/check_common_fn
BASE=`basename $0 .sh`
test_cdinfo "--nrg-file ${srcdir}/monvoisin.nrg" \
monvoisin.dump ${srcdir}/monvoisin.right
RC=$?
check_result $RC 'cdinfo NRG test 1'
exit $RC
#;;; Local Variables: ***
#;;; mode:shell-script ***
#;;; eval: (sh-set-shell "bash") ***
#;;; End: ***

17
tests/monvoisin.right Normal file
View File

@@ -0,0 +1,17 @@
CD Info 2.0 | (c) 2003 Gerd Knorr, Heiko Ei<45>feldt & R. Bernstein
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
__________________________________
CD-ROM Track List (1 - 2)
#: MSF LSN Type
1: 00:02:00 000000 XA
2: 00:18:51 001251 XA
170: 00:39:71 002846 leadout
__________________________________
try to find out what sort of CD this is
CD-ROM with CD-RTOS and ISO 9660 filesystem
ISO 9660: 1101 blocks, label `MONVOISIN '
XA sectors Video CD
session #2 starts at track 2, LSN: 1251, ISO 9660 blocks: 1101
ISO 9660: 1101 blocks, label `'

View File

@@ -0,0 +1,17 @@
CD Info 2.0 | (c) 2003 Gerd Knorr, Heiko Ei<45>feldt & R. Bernstein
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
__________________________________
CD-ROM Track List (1 - 2)
#: MSF LSN Type
1: 00:02:00 000000 XA
2: 00:09:01 000526 XA
170: 00:56:56 004106 leadout
__________________________________
try to find out what sort of CD this is
CD-ROM with CD-RTOS and ISO 9660 filesystem
ISO 9660: 376 blocks, label `SVCD_OGT_TEST_NTSC '
XA sectors
session #2 starts at track 2, LSN: 526, ISO 9660 blocks: 376
ISO 9660: 376 blocks, label `DD3#3"C"$<24>@'

18
tests/vcd_demo.right Normal file
View File

@@ -0,0 +1,18 @@
CD Info 2.0 | (c) 2003 Gerd Knorr, Heiko Ei<45>feldt & R. Bernstein
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
__________________________________
CD-ROM Track List (1 - 3)
#: MSF LSN Type
1: 00:02:00 000000 XA
2: 00:17:57 001182 XA
3: 00:24:71 001721 XA
170: 00:30:10 002110 leadout
__________________________________
try to find out what sort of CD this is
CD-ROM with CD-RTOS and ISO 9660 filesystem
ISO 9660: 1032 blocks, label `V0469 '
XA sectors Video CD
session #2 starts at track 2, LSN: 1182, ISO 9660 blocks: 1032
ISO 9660: 1032 blocks, label `'