Initial revision
This commit is contained in:
15
.cvsignore
Normal file
15
.cvsignore
Normal 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
2
AUTHORS
Normal file
@@ -0,0 +1,2 @@
|
||||
Herbert Valerio Riedel <hvr@gnu.org>
|
||||
Rocky Bernstein <rocky@panix.com>
|
||||
30
Makefile.am
Normal file
30
Makefile.am
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
3
README
Normal file
3
README
Normal 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
128
autogen.sh
Executable 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
174
configure.ac
Normal 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
7
lib/.cvsignore
Normal file
@@ -0,0 +1,7 @@
|
||||
.deps
|
||||
.libs
|
||||
Makefile
|
||||
Makefile.in
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
77
lib/Makefile.am
Normal file
77
lib/Makefile.am
Normal 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
581
lib/_cdio_bincue.c
Normal 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
441
lib/_cdio_bsdi.c
Normal 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
29
lib/_cdio_bsdi.h
Normal 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
725
lib/_cdio_linux.c
Normal 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
770
lib/_cdio_nrg.c
Normal 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
177
lib/_cdio_stdio.c
Normal 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
40
lib/_cdio_stdio.h
Normal 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
156
lib/_cdio_stream.c
Normal 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
91
lib/_cdio_stream.h
Normal 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
658
lib/_cdio_sunos.c
Normal 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
196
lib/bytesex.h
Normal 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
123
lib/bytesex_asm.h
Normal 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
454
lib/cdio.c
Normal 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
219
lib/cdio.h
Normal 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
55
lib/cdio_assert.h
Normal 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
158
lib/cdio_private.h
Normal 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
217
lib/cdio_types.h
Normal 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
249
lib/ds.c
Normal 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
73
lib/ds.h
Normal 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
129
lib/logging.c
Normal 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
64
lib/logging.h
Normal 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
79
lib/sector.c
Normal 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
127
lib/sector.h
Normal 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
192
lib/util.c
Normal 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
109
lib/util.h
Normal 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
68
libpopt.m4
Normal 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
8
src/.cvsignore
Normal file
@@ -0,0 +1,8 @@
|
||||
.deps
|
||||
.libs
|
||||
Makefile
|
||||
Makefile.in
|
||||
*.o
|
||||
cdinfo
|
||||
cdinfo-linux
|
||||
*.right
|
||||
34
src/Makefile.am
Normal file
34
src/Makefile.am
Normal 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
911
src/cdinfo-linux.c
Normal 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
999
src/cdinfo.c
Normal 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
6
tests/.cvsignore
Normal file
@@ -0,0 +1,6 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
*.dump
|
||||
*.cue
|
||||
*.bin
|
||||
*.nrg
|
||||
32
tests/Makefile.am
Normal file
32
tests/Makefile.am
Normal 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
70
tests/check_common_fn
Executable 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
27
tests/check_cue.sh
Executable 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
22
tests/check_nrg.sh
Executable 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
17
tests/monvoisin.right
Normal 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 `'
|
||||
17
tests/svcd_ogt_test_ntsc.right
Normal file
17
tests/svcd_ogt_test_ntsc.right
Normal 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
18
tests/vcd_demo.right
Normal 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 `'
|
||||
Reference in New Issue
Block a user