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