dsp \
dummy \
dvd \
+ dvdread \
esd \
fb \
ggi \
dummy/dummy \
dummy/null \
dvd/dvd \
+ dvdread/dvdread \
esd/esd \
fb/fb \
ggi/ggi \
#
# Cleaning rules
#
-clean: libdvdcss-clean plugins-clean vlc-clean
+clean: libdvdcss-clean libdvdread-clean plugins-clean vlc-clean
rm -f src/*/*.o extras/*/*.o
rm -f lib/*.so* lib/*.a
rm -f plugins/*.so plugins/*.a
libdvdcss-clean:
-cd extras/libdvdcss && $(MAKE) clean
+libdvdread-clean:
+ -cd extras/libdvdread && $(MAKE) clean
+
plugins-clean:
for dir in $(PLUGINS_DIR) ; do \
( cd plugins/$${dir} && $(MAKE) clean ) ; done
#
libdvdcss: Makefile.opts
cd extras/libdvdcss && $(MAKE)
+
+#
+# libdvdread target
+#
+libdvdread: Makefile.opts
+ cd extras/libdvdread && $(MAKE)
+
LIB_DARWIN = @LIB_DARWIN@
LIB_DVD = @LIB_DVD@
LIB_DVD_PLUGIN = @LIB_DVD_PLUGIN@
+LIB_DVDREAD = @LIB_DVDREAD@
+LIB_DVDREAD_PLUGIN = @LIB_DVDREAD_PLUGIN@
LIB_ESD = @LIB_ESD@
LIB_GGI = @LIB_GGI@
LIB_GLIDE = @LIB_GLIDE@
#
CFLAGS_ALTIVEC = @CFLAGS_ALTIVEC@
CFLAGS_DVD = @CFLAGS_DVD@
+CFLAGS_DVDREAD = @CFLAGS_DVDREAD@
CFLAGS_ARTS = @CFLAGS_ARTS@
CFLAGS_ESD = @CFLAGS_ESD@
CFLAGS_LIBDVDCSS = @CFLAGS_LIBDVDCSS@
or 'local-static', 'local-shared', or a path to
another libdvdcss such as '/usr/local'
(default 'local-static')"
+ac_help="$ac_help
+ --enable-dvdread Enable dvdread support (default enabled)"
ac_help="$ac_help
--enable-vcd VCD support for Linux (default enabled)"
ac_help="$ac_help
fi
echo $ac_n "checking host system type""... $ac_c" 1>&6
-echo "configure:657: checking host system type" >&5
+echo "configure:659: checking host system type" >&5
host_alias=$host
case "$host_alias" in
echo "$ac_t""$host" 1>&6
echo $ac_n "checking target system type""... $ac_c" 1>&6
-echo "configure:678: checking target system type" >&5
+echo "configure:680: checking target system type" >&5
target_alias=$target
case "$target_alias" in
echo "$ac_t""$target" 1>&6
echo $ac_n "checking build system type""... $ac_c" 1>&6
-echo "configure:696: checking build system type" >&5
+echo "configure:698: checking build system type" >&5
build_alias=$build
case "$build_alias" in
save_LDFLAGS="${LDFLAGS}"
echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
-echo "configure:745: checking whether ${MAKE-make} sets \${MAKE}" >&5
+echo "configure:747: checking whether ${MAKE-make} sets \${MAKE}" >&5
set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
# Extract the first word of "gcc", so it can be a program name with args.
set dummy gcc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:774: checking for $ac_word" >&5
+echo "configure:776: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
# Extract the first word of "cc", so it can be a program name with args.
set dummy cc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:804: checking for $ac_word" >&5
+echo "configure:806: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
# Extract the first word of "cl", so it can be a program name with args.
set dummy cl; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:855: checking for $ac_word" >&5
+echo "configure:857: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
fi
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
-echo "configure:887: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+echo "configure:889: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
ac_ext=c
# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
cat > conftest.$ac_ext << EOF
-#line 898 "configure"
+#line 900 "configure"
#include "confdefs.h"
main(){return(0);}
EOF
-if { (eval echo configure:903: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:905: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
ac_cv_prog_cc_works=yes
# If we can't run a trivial program, we are probably using a cross compiler.
if (./conftest; exit) 2>/dev/null; then
{ echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
fi
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
-echo "configure:929: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "configure:931: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
cross_compiling=$ac_cv_prog_cc_cross
echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
-echo "configure:934: checking whether we are using GNU C" >&5
+echo "configure:936: checking whether we are using GNU C" >&5
if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
yes;
#endif
EOF
-if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:943: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:945: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
ac_cv_prog_gcc=yes
else
ac_cv_prog_gcc=no
ac_save_CFLAGS="$CFLAGS"
CFLAGS=
echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
-echo "configure:962: checking whether ${CC-cc} accepts -g" >&5
+echo "configure:964: checking whether ${CC-cc} accepts -g" >&5
if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
fi
echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
-echo "configure:994: checking how to run the C preprocessor" >&5
+echo "configure:996: checking how to run the C preprocessor" >&5
# On Suns, sometimes $CPP names a directory.
if test -n "$CPP" && test -d "$CPP"; then
CPP=
# On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp.
cat > conftest.$ac_ext <<EOF
-#line 1009 "configure"
+#line 1011 "configure"
#include "confdefs.h"
#include <assert.h>
Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1015: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1017: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
:
rm -rf conftest*
CPP="${CC-cc} -E -traditional-cpp"
cat > conftest.$ac_ext <<EOF
-#line 1026 "configure"
+#line 1028 "configure"
#include "confdefs.h"
#include <assert.h>
Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1032: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1034: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
:
rm -rf conftest*
CPP="${CC-cc} -nologo -E"
cat > conftest.$ac_ext <<EOF
-#line 1043 "configure"
+#line 1045 "configure"
#include "confdefs.h"
#include <assert.h>
Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1049: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1051: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
:
# Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
set dummy ${ac_tool_prefix}ranlib; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1082: checking for $ac_word" >&5
+echo "configure:1084: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
# Extract the first word of "ranlib", so it can be a program name with args.
set dummy ranlib; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1114: checking for $ac_word" >&5
+echo "configure:1116: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
# ./install, which can be erroneously created by make from ./install.sh.
echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
-echo "configure:1159: checking for a BSD compatible install" >&5
+echo "configure:1161: checking for a BSD compatible install" >&5
if test -z "$INSTALL"; then
if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
if test x${cross_compiling} != xyes; then
echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6
-echo "configure:1214: checking whether byte ordering is bigendian" >&5
+echo "configure:1216: checking whether byte ordering is bigendian" >&5
if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
ac_cv_c_bigendian=unknown
# See if sys/param.h defines the BYTE_ORDER macro.
cat > conftest.$ac_ext <<EOF
-#line 1221 "configure"
+#line 1223 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <sys/param.h>
#endif
; return 0; }
EOF
-if { (eval echo configure:1232: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1234: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
# It does; now see whether it defined to BIG_ENDIAN or not.
cat > conftest.$ac_ext <<EOF
-#line 1236 "configure"
+#line 1238 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <sys/param.h>
#endif
; return 0; }
EOF
-if { (eval echo configure:1247: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1249: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_c_bigendian=yes
else
{ echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
else
cat > conftest.$ac_ext <<EOF
-#line 1267 "configure"
+#line 1269 "configure"
#include "confdefs.h"
main () {
/* Are we little or big endian? From Harbison&Steele. */
exit (u.c[sizeof (long) - 1] == 1);
}
EOF
-if { (eval echo configure:1280: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1282: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
then
ac_cv_c_bigendian=no
else
*)
ac_cv_c_bigendian=unknown
echo $ac_n "checking what the byte order looks to be""... $ac_c" 1>&6
-echo "configure:1320: checking what the byte order looks to be" >&5
+echo "configure:1322: checking what the byte order looks to be" >&5
cat >conftest.c <<EOF
short am[] = { 0x4249, 0x4765, 0x6e44, 0x6961, 0x6e53, 0x7953, 0 };
short ai[] = { 0x694c, 0x5454, 0x656c, 0x6e45, 0x6944, 0x6e61, 0 };
for ac_func in gettimeofday select strerror strtod strtol
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1365: checking for $ac_func" >&5
+echo "configure:1367: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1370 "configure"
+#line 1372 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
; return 0; }
EOF
-if { (eval echo configure:1393: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1395: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
for ac_func in setenv putenv
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1420: checking for $ac_func" >&5
+echo "configure:1422: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1425 "configure"
+#line 1427 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
; return 0; }
EOF
-if { (eval echo configure:1448: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1450: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
done
echo $ac_n "checking for connect""... $ac_c" 1>&6
-echo "configure:1473: checking for connect" >&5
+echo "configure:1475: checking for connect" >&5
if eval "test \"`echo '$''{'ac_cv_func_connect'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1478 "configure"
+#line 1480 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char connect(); below. */
; return 0; }
EOF
-if { (eval echo configure:1501: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1503: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_connect=yes"
else
echo "$ac_t""no" 1>&6
echo $ac_n "checking for connect in -lsocket""... $ac_c" 1>&6
-echo "configure:1520: checking for connect in -lsocket" >&5
+echo "configure:1522: checking for connect in -lsocket" >&5
ac_lib_var=`echo socket'_'connect | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
ac_save_LIBS="$LIBS"
LIBS="-lsocket $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 1528 "configure"
+#line 1530 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
connect()
; return 0; }
EOF
-if { (eval echo configure:1539: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1541: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
fi
echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6
-echo "configure:1563: checking for gethostbyname" >&5
+echo "configure:1565: checking for gethostbyname" >&5
if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1568 "configure"
+#line 1570 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char gethostbyname(); below. */
; return 0; }
EOF
-if { (eval echo configure:1591: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1593: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_gethostbyname=yes"
else
echo "$ac_t""no" 1>&6
echo $ac_n "checking for gethostbyname in -lnsl""... $ac_c" 1>&6
-echo "configure:1610: checking for gethostbyname in -lnsl" >&5
+echo "configure:1612: checking for gethostbyname in -lnsl" >&5
ac_lib_var=`echo nsl'_'gethostbyname | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
ac_save_LIBS="$LIBS"
LIBS="-lnsl $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 1618 "configure"
+#line 1620 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
gethostbyname()
; return 0; }
EOF
-if { (eval echo configure:1629: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1631: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
fi
echo $ac_n "checking for nanosleep""... $ac_c" 1>&6
-echo "configure:1653: checking for nanosleep" >&5
+echo "configure:1655: checking for nanosleep" >&5
if eval "test \"`echo '$''{'ac_cv_func_nanosleep'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1658 "configure"
+#line 1660 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char nanosleep(); below. */
; return 0; }
EOF
-if { (eval echo configure:1681: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1683: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_nanosleep=yes"
else
echo "$ac_t""no" 1>&6
echo $ac_n "checking for nanosleep in -lrt""... $ac_c" 1>&6
-echo "configure:1700: checking for nanosleep in -lrt" >&5
+echo "configure:1702: checking for nanosleep in -lrt" >&5
ac_lib_var=`echo rt'_'nanosleep | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
ac_save_LIBS="$LIBS"
LIBS="-lrt $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 1708 "configure"
+#line 1710 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
nanosleep()
; return 0; }
EOF
-if { (eval echo configure:1719: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1721: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
echo "$ac_t""no" 1>&6
echo $ac_n "checking for nanosleep in -lposix4""... $ac_c" 1>&6
-echo "configure:1739: checking for nanosleep in -lposix4" >&5
+echo "configure:1741: checking for nanosleep in -lposix4" >&5
ac_lib_var=`echo posix4'_'nanosleep | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
ac_save_LIBS="$LIBS"
LIBS="-lposix4 $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 1747 "configure"
+#line 1749 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
nanosleep()
; return 0; }
EOF
-if { (eval echo configure:1758: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1760: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
for ac_func in usleep
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1787: checking for $ac_func" >&5
+echo "configure:1789: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1792 "configure"
+#line 1794 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
; return 0; }
EOF
-if { (eval echo configure:1815: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1817: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
done
echo $ac_n "checking for inet_aton""... $ac_c" 1>&6
-echo "configure:1840: checking for inet_aton" >&5
+echo "configure:1842: checking for inet_aton" >&5
if eval "test \"`echo '$''{'ac_cv_func_inet_aton'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1845 "configure"
+#line 1847 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char inet_aton(); below. */
; return 0; }
EOF
-if { (eval echo configure:1868: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1870: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_inet_aton=yes"
else
echo "$ac_t""no" 1>&6
echo $ac_n "checking for inet_aton in -lresolv""... $ac_c" 1>&6
-echo "configure:1887: checking for inet_aton in -lresolv" >&5
+echo "configure:1889: checking for inet_aton in -lresolv" >&5
ac_lib_var=`echo resolv'_'inet_aton | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
ac_save_LIBS="$LIBS"
LIBS="-lresolv $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 1895 "configure"
+#line 1897 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
inet_aton()
; return 0; }
EOF
-if { (eval echo configure:1906: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1908: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
for ac_func in vasprintf
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1932: checking for $ac_func" >&5
+echo "configure:1934: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1937 "configure"
+#line 1939 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
; return 0; }
EOF
-if { (eval echo configure:1960: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1962: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
for ac_func in swab
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1987: checking for $ac_func" >&5
+echo "configure:1989: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1992 "configure"
+#line 1994 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
; return 0; }
EOF
-if { (eval echo configure:2015: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2017: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
for ac_func in memalign valloc
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2042: checking for $ac_func" >&5
+echo "configure:2044: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 2047 "configure"
+#line 2049 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
; return 0; }
EOF
-if { (eval echo configure:2070: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2072: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
for ac_func in sigrelse
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2098: checking for $ac_func" >&5
+echo "configure:2100: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 2103 "configure"
+#line 2105 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
; return 0; }
EOF
-if { (eval echo configure:2126: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2128: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
NEED_GETOPT=0
echo $ac_n "checking for getopt_long""... $ac_c" 1>&6
-echo "configure:2153: checking for getopt_long" >&5
+echo "configure:2155: checking for getopt_long" >&5
if eval "test \"`echo '$''{'ac_cv_func_getopt_long'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 2158 "configure"
+#line 2160 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char getopt_long(); below. */
; return 0; }
EOF
-if { (eval echo configure:2181: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2183: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_getopt_long=yes"
else
echo "$ac_t""no" 1>&6
# FreeBSD has a gnugetopt library for this:
echo $ac_n "checking for getopt_long in -lgnugetopt""... $ac_c" 1>&6
-echo "configure:2203: checking for getopt_long in -lgnugetopt" >&5
+echo "configure:2205: checking for getopt_long in -lgnugetopt" >&5
ac_lib_var=`echo gnugetopt'_'getopt_long | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
ac_save_LIBS="$LIBS"
LIBS="-lgnugetopt $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 2211 "configure"
+#line 2213 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
getopt_long()
; return 0; }
EOF
-if { (eval echo configure:2222: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2224: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:2253: checking for $ac_hdr" >&5
+echo "configure:2255: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 2258 "configure"
+#line 2260 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2263: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:2265: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
for ac_func in getpagesize
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2292: checking for $ac_func" >&5
+echo "configure:2294: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 2297 "configure"
+#line 2299 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
; return 0; }
EOF
-if { (eval echo configure:2320: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2322: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
done
echo $ac_n "checking for working mmap""... $ac_c" 1>&6
-echo "configure:2345: checking for working mmap" >&5
+echo "configure:2347: checking for working mmap" >&5
if eval "test \"`echo '$''{'ac_cv_func_mmap_fixed_mapped'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
ac_cv_func_mmap_fixed_mapped=no
else
cat > conftest.$ac_ext <<EOF
-#line 2353 "configure"
+#line 2355 "configure"
#include "confdefs.h"
/* Thanks to Mike Haertel and Jim Avera for this test.
}
EOF
-if { (eval echo configure:2493: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2495: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
then
ac_cv_func_mmap_fixed_mapped=yes
else
fi
echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
-echo "configure:2516: checking return type of signal handlers" >&5
+echo "configure:2518: checking return type of signal handlers" >&5
if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 2521 "configure"
+#line 2523 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <signal.h>
int i;
; return 0; }
EOF
-if { (eval echo configure:2538: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2540: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_type_signal=void
else
echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6
-echo "configure:2557: checking for dlopen in -ldl" >&5
+echo "configure:2559: checking for dlopen in -ldl" >&5
ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
ac_save_LIBS="$LIBS"
LIBS="-ldl $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 2565 "configure"
+#line 2567 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
dlopen()
; return 0; }
EOF
-if { (eval echo configure:2576: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2578: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
fi
echo $ac_n "checking for pow in -lm""... $ac_c" 1>&6
-echo "configure:2597: checking for pow in -lm" >&5
+echo "configure:2599: checking for pow in -lm" >&5
ac_lib_var=`echo m'_'pow | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
ac_save_LIBS="$LIBS"
LIBS="-lm $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 2605 "configure"
+#line 2607 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
pow()
; return 0; }
EOF
-if { (eval echo configure:2616: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2618: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
THREAD_LIB=error
if test "x${THREAD_LIB}" = xerror; then
echo $ac_n "checking for pthread_attr_init in -lpthread""... $ac_c" 1>&6
-echo "configure:2640: checking for pthread_attr_init in -lpthread" >&5
+echo "configure:2642: checking for pthread_attr_init in -lpthread" >&5
ac_lib_var=`echo pthread'_'pthread_attr_init | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
ac_save_LIBS="$LIBS"
LIBS="-lpthread $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 2648 "configure"
+#line 2650 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
pthread_attr_init()
; return 0; }
EOF
-if { (eval echo configure:2659: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2661: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
fi
if test "x${THREAD_LIB}" = xerror; then
echo $ac_n "checking for pthread_attr_init in -lpthreads""... $ac_c" 1>&6
-echo "configure:2682: checking for pthread_attr_init in -lpthreads" >&5
+echo "configure:2684: checking for pthread_attr_init in -lpthreads" >&5
ac_lib_var=`echo pthreads'_'pthread_attr_init | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
ac_save_LIBS="$LIBS"
LIBS="-lpthreads $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 2690 "configure"
+#line 2692 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
pthread_attr_init()
; return 0; }
EOF
-if { (eval echo configure:2701: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2703: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
fi
if test "x${THREAD_LIB}" = xerror; then
echo $ac_n "checking for pthread_attr_init in -lc_r""... $ac_c" 1>&6
-echo "configure:2724: checking for pthread_attr_init in -lc_r" >&5
+echo "configure:2726: checking for pthread_attr_init in -lc_r" >&5
ac_lib_var=`echo c_r'_'pthread_attr_init | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
ac_save_LIBS="$LIBS"
LIBS="-lc_r $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 2732 "configure"
+#line 2734 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
pthread_attr_init()
; return 0; }
EOF
-if { (eval echo configure:2743: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2745: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
fi
if test "x${THREAD_LIB}" = xerror; then
echo $ac_n "checking for pthread_attr_init""... $ac_c" 1>&6
-echo "configure:2766: checking for pthread_attr_init" >&5
+echo "configure:2768: checking for pthread_attr_init" >&5
if eval "test \"`echo '$''{'ac_cv_func_pthread_attr_init'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 2771 "configure"
+#line 2773 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char pthread_attr_init(); below. */
; return 0; }
EOF
-if { (eval echo configure:2794: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2796: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_pthread_attr_init=yes"
else
fi
echo $ac_n "checking for cthread_fork in -lthreads""... $ac_c" 1>&6
-echo "configure:2817: checking for cthread_fork in -lthreads" >&5
+echo "configure:2819: checking for cthread_fork in -lthreads" >&5
ac_lib_var=`echo threads'_'cthread_fork | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
ac_save_LIBS="$LIBS"
LIBS="-lthreads $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 2825 "configure"
+#line 2827 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
cthread_fork()
; return 0; }
EOF
-if { (eval echo configure:2836: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2838: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
cat > conftest.$ac_ext <<EOF
-#line 2858 "configure"
+#line 2860 "configure"
#include "confdefs.h"
#include <pthread.h>
EOF
rm -f conftest*
cat > conftest.$ac_ext <<EOF
-#line 2874 "configure"
+#line 2876 "configure"
#include "confdefs.h"
#include <strings.h>
EOF
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:2894: checking for $ac_hdr" >&5
+echo "configure:2896: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 2899 "configure"
+#line 2901 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2904: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:2906: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:2934: checking for $ac_hdr" >&5
+echo "configure:2936: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 2939 "configure"
+#line 2941 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2944: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:2946: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:2974: checking for $ac_hdr" >&5
+echo "configure:2976: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 2979 "configure"
+#line 2981 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2984: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:2986: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:3014: checking for $ac_hdr" >&5
+echo "configure:3016: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3019 "configure"
+#line 3021 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:3024: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:3026: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:3054: checking for $ac_hdr" >&5
+echo "configure:3056: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3059 "configure"
+#line 3061 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:3064: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:3066: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:3094: checking for $ac_hdr" >&5
+echo "configure:3096: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3099 "configure"
+#line 3101 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:3104: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:3106: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:3135: checking for $ac_hdr" >&5
+echo "configure:3137: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3140 "configure"
+#line 3142 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:3145: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:3147: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
echo $ac_n "checking for ntohl in sys/param.h""... $ac_c" 1>&6
-echo "configure:3173: checking for ntohl in sys/param.h" >&5
+echo "configure:3175: checking for ntohl in sys/param.h" >&5
if eval "test \"`echo '$''{'ac_cv_c_ntohl_sys_param_h'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
CFLAGS="${save_CFLAGS} -Wall -Werror"
cat > conftest.$ac_ext <<EOF
-#line 3179 "configure"
+#line 3181 "configure"
#include "confdefs.h"
#include <sys/param.h>
int main() {
void foo() { int meuh; ntohl(meuh); }
; return 0; }
EOF
-if { (eval echo configure:3186: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3188: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_c_ntohl_sys_param_h=yes
else
fi
echo $ac_n "checking if \$CC accepts -finline-limit""... $ac_c" 1>&6
-echo "configure:3207: checking if \$CC accepts -finline-limit" >&5
+echo "configure:3209: checking if \$CC accepts -finline-limit" >&5
if eval "test \"`echo '$''{'ac_cv_c_inline_limit'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
CFLAGS="${save_CFLAGS} -finline-limit-30000"
cat > conftest.$ac_ext <<EOF
-#line 3213 "configure"
+#line 3215 "configure"
#include "confdefs.h"
int main() {
; return 0; }
EOF
-if { (eval echo configure:3220: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3222: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_c_inline_limit=yes
else
fi
echo $ac_n "checking if \$CC accepts -bundle -undefined error""... $ac_c" 1>&6
-echo "configure:3238: checking if \$CC accepts -bundle -undefined error" >&5
+echo "configure:3240: checking if \$CC accepts -bundle -undefined error" >&5
if eval "test \"`echo '$''{'ac_cv_ld_darwin'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
CFLAGS="${save_CFLAGS} -bundle -undefined error"
cat > conftest.$ac_ext <<EOF
-#line 3244 "configure"
+#line 3246 "configure"
#include "confdefs.h"
int main() {
; return 0; }
EOF
-if { (eval echo configure:3251: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3253: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_ld_darwin=yes
else
fi
echo $ac_n "checking if \$CC accepts -shared""... $ac_c" 1>&6
-echo "configure:3269: checking if \$CC accepts -shared" >&5
+echo "configure:3271: checking if \$CC accepts -shared" >&5
if eval "test \"`echo '$''{'ac_cv_ld_plugins'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
CFLAGS="${save_CFLAGS} -shared"
cat > conftest.$ac_ext <<EOF
-#line 3275 "configure"
+#line 3277 "configure"
#include "confdefs.h"
int main() {
; return 0; }
EOF
-if { (eval echo configure:3282: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3284: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_ld_plugins=yes
else
if test x"${SOFLAGS}" = x; then
echo $ac_n "checking for soname setting""... $ac_c" 1>&6
-echo "configure:3301: checking for soname setting" >&5
+echo "configure:3303: checking for soname setting" >&5
if eval "test \"`echo '$''{'ac_cv_ld_soname'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
try_SOFLAGS="-Wl,-soname -Wl,"
LDFLAGS="${save_LDFLAGS} ${try_SOFLAGS}foo.so.0"
cat > conftest.$ac_ext <<EOF
-#line 3310 "configure"
+#line 3312 "configure"
#include "confdefs.h"
int main() {
; return 0; }
EOF
-if { (eval echo configure:3317: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:3319: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
ac_cv_ld_soname="${try_SOFLAGS}"
else
try_SOFLAGS="-Wl,-h -Wl,"
LDFLAGS="${save_LDFLAGS} ${try_SOFLAGS}foo.so.0"
cat > conftest.$ac_ext <<EOF
-#line 3329 "configure"
+#line 3331 "configure"
#include "confdefs.h"
int main() {
; return 0; }
EOF
-if { (eval echo configure:3336: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:3338: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
ac_cv_ld_soname="${try_SOFLAGS}"
else
fi
echo $ac_n "checking __attribute__ ((aligned ())) support""... $ac_c" 1>&6
-echo "configure:3365: checking __attribute__ ((aligned ())) support" >&5
+echo "configure:3367: checking __attribute__ ((aligned ())) support" >&5
if eval "test \"`echo '$''{'ac_cv_c_attribute_aligned'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
CFLAGS="${save_CFLAGS} -Werror"
for ac_cv_c_attr_align_try in 2 4 8 16 32 64; do
cat > conftest.$ac_ext <<EOF
-#line 3373 "configure"
+#line 3375 "configure"
#include "confdefs.h"
int main() {
static char c __attribute__ ((aligned($ac_cv_c_attr_align_try))) = 0; return c;
; return 0; }
EOF
-if { (eval echo configure:3380: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3382: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_c_attribute_aligned=$ac_cv_c_attr_align_try
else
LDFLAGS="${save_LDFLAGS}"
echo $ac_n "checking for boolean_t in sys/types.h""... $ac_c" 1>&6
-echo "configure:3403: checking for boolean_t in sys/types.h" >&5
+echo "configure:3405: checking for boolean_t in sys/types.h" >&5
if eval "test \"`echo '$''{'ac_cv_c_boolean_t_sys_types_h'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3408 "configure"
+#line 3410 "configure"
#include "confdefs.h"
#include <sys/types.h>
int main() {
boolean_t foo;
; return 0; }
EOF
-if { (eval echo configure:3415: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3417: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_c_boolean_t_sys_types_h=yes
else
fi
echo $ac_n "checking for boolean_t in pthread.h""... $ac_c" 1>&6
-echo "configure:3436: checking for boolean_t in pthread.h" >&5
+echo "configure:3438: checking for boolean_t in pthread.h" >&5
if eval "test \"`echo '$''{'ac_cv_c_boolean_t_pthread_h'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3441 "configure"
+#line 3443 "configure"
#include "confdefs.h"
#include <pthread.h>
int main() {
boolean_t foo;
; return 0; }
EOF
-if { (eval echo configure:3448: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3450: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_c_boolean_t_pthread_h=yes
else
fi
echo $ac_n "checking for boolean_t in cthreads.h""... $ac_c" 1>&6
-echo "configure:3469: checking for boolean_t in cthreads.h" >&5
+echo "configure:3471: checking for boolean_t in cthreads.h" >&5
if eval "test \"`echo '$''{'ac_cv_c_boolean_t_cthreads_h'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3474 "configure"
+#line 3476 "configure"
#include "confdefs.h"
#include <cthreads.h>
int main() {
boolean_t foo;
; return 0; }
EOF
-if { (eval echo configure:3481: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3483: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_c_boolean_t_cthreads_h=yes
else
fi
echo $ac_n "checking for working const""... $ac_c" 1>&6
-echo "configure:3502: checking for working const" >&5
+echo "configure:3504: checking for working const" >&5
if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3507 "configure"
+#line 3509 "configure"
#include "confdefs.h"
int main() {
; return 0; }
EOF
-if { (eval echo configure:3556: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3558: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_c_const=yes
else
fi
echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
-echo "configure:3577: checking for ANSI C header files" >&5
+echo "configure:3579: checking for ANSI C header files" >&5
if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3582 "configure"
+#line 3584 "configure"
#include "confdefs.h"
#include <stdlib.h>
#include <stdarg.h>
#include <float.h>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:3590: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:3592: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
if test $ac_cv_header_stdc = yes; then
# SunOS 4.x string.h does not declare mem*, contrary to ANSI.
cat > conftest.$ac_ext <<EOF
-#line 3607 "configure"
+#line 3609 "configure"
#include "confdefs.h"
#include <string.h>
EOF
if test $ac_cv_header_stdc = yes; then
# ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
cat > conftest.$ac_ext <<EOF
-#line 3625 "configure"
+#line 3627 "configure"
#include "confdefs.h"
#include <stdlib.h>
EOF
:
else
cat > conftest.$ac_ext <<EOF
-#line 3646 "configure"
+#line 3648 "configure"
#include "confdefs.h"
#include <ctype.h>
#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
exit (0); }
EOF
-if { (eval echo configure:3657: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:3659: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
then
:
else
fi
echo $ac_n "checking for size_t""... $ac_c" 1>&6
-echo "configure:3681: checking for size_t" >&5
+echo "configure:3683: checking for size_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3686 "configure"
+#line 3688 "configure"
#include "confdefs.h"
#include <sys/types.h>
#if STDC_HEADERS
fi
echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
-echo "configure:3714: checking whether time.h and sys/time.h may both be included" >&5
+echo "configure:3716: checking whether time.h and sys/time.h may both be included" >&5
if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3719 "configure"
+#line 3721 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <sys/time.h>
struct tm *tp;
; return 0; }
EOF
-if { (eval echo configure:3728: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3730: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_header_time=yes
else
ALTIVEC_MODULES="idctaltivec motionaltivec"
echo $ac_n "checking if \$CC groks MMX inline assembly""... $ac_c" 1>&6
-echo "configure:3762: checking if \$CC groks MMX inline assembly" >&5
+echo "configure:3764: checking if \$CC groks MMX inline assembly" >&5
if eval "test \"`echo '$''{'ac_cv_mmx_inline'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3767 "configure"
+#line 3769 "configure"
#include "confdefs.h"
int main() {
void *p;asm volatile("packuswb %%mm1,%%mm2"::"r"(p));
; return 0; }
EOF
-if { (eval echo configure:3774: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3776: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_mmx_inline=yes
else
fi
echo $ac_n "checking if \$CC groks MMX EXT inline assembly""... $ac_c" 1>&6
-echo "configure:3792: checking if \$CC groks MMX EXT inline assembly" >&5
+echo "configure:3794: checking if \$CC groks MMX EXT inline assembly" >&5
if eval "test \"`echo '$''{'ac_cv_mmxext_inline'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3797 "configure"
+#line 3799 "configure"
#include "confdefs.h"
int main() {
void *p;asm volatile("maskmovq %%mm1,%%mm2"::"r"(p));
; return 0; }
EOF
-if { (eval echo configure:3804: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3806: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_mmxext_inline=yes
else
fi
echo $ac_n "checking if \$CC groks 3D Now! inline assembly""... $ac_c" 1>&6
-echo "configure:3822: checking if \$CC groks 3D Now! inline assembly" >&5
+echo "configure:3824: checking if \$CC groks 3D Now! inline assembly" >&5
if eval "test \"`echo '$''{'ac_cv_3dnow_inline'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3827 "configure"
+#line 3829 "configure"
#include "confdefs.h"
int main() {
void *p;asm volatile("pfadd %%mm1,%%mm2"::"r"(p));
; return 0; }
EOF
-if { (eval echo configure:3834: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3836: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_3dnow_inline=yes
else
fi
echo $ac_n "checking if \$CC groks SSE inline assembly""... $ac_c" 1>&6
-echo "configure:3856: checking if \$CC groks SSE inline assembly" >&5
+echo "configure:3858: checking if \$CC groks SSE inline assembly" >&5
if eval "test \"`echo '$''{'ac_cv_sse_inline'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3861 "configure"
+#line 3863 "configure"
#include "confdefs.h"
int main() {
void *p;asm volatile("xorps %%xmm1,%%xmm2"::"r"(p));
; return 0; }
EOF
-if { (eval echo configure:3868: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3870: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_sse_inline=yes
else
fi
echo $ac_n "checking if \$CC groks Altivec inline assembly""... $ac_c" 1>&6
-echo "configure:3890: checking if \$CC groks Altivec inline assembly" >&5
+echo "configure:3892: checking if \$CC groks Altivec inline assembly" >&5
if eval "test \"`echo '$''{'ac_cv_altivec_inline'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3895 "configure"
+#line 3897 "configure"
#include "confdefs.h"
int main() {
asm volatile("vperm 0,1,2,3");
; return 0; }
EOF
-if { (eval echo configure:3902: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3904: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_altivec_inline=yes
else
save_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS -Wa,-m7400"
cat > conftest.$ac_ext <<EOF
-#line 3912 "configure"
+#line 3914 "configure"
#include "confdefs.h"
int main() {
asm volatile("vperm 0,1,2,3");
; return 0; }
EOF
-if { (eval echo configure:3919: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3921: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_altivec_inline=yes; CFLAGS_ALTIVEC="-Wa,-m7400"
else
fi
echo $ac_n "checking if \$CC groks Altivec C extensions""... $ac_c" 1>&6
-echo "configure:3945: checking if \$CC groks Altivec C extensions" >&5
+echo "configure:3947: checking if \$CC groks Altivec C extensions" >&5
if eval "test \"`echo '$''{'ac_cv_c_altivec'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
CFLAGS="$CFLAGS -faltivec"
# Darwin test
cat > conftest.$ac_ext <<EOF
-#line 3953 "configure"
+#line 3955 "configure"
#include "confdefs.h"
int main() {
vec_mtvscr((vector unsigned int)(0));
; return 0; }
EOF
-if { (eval echo configure:3960: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3962: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_c_altivec=-faltivec
else
# Linux/PPC test
CFLAGS="$save_CFLAGS $CFLAGS_ALTIVEC -fvec"
cat > conftest.$ac_ext <<EOF
-#line 3971 "configure"
+#line 3973 "configure"
#include "confdefs.h"
int main() {
vec_mtvscr((vector unsigned int)(0));
; return 0; }
EOF
-if { (eval echo configure:3978: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3980: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_c_altivec="-fvec"
else
fi
echo $ac_n "checking if linker needs -framework vecLib""... $ac_c" 1>&6
-echo "configure:4006: checking if linker needs -framework vecLib" >&5
+echo "configure:4008: checking if linker needs -framework vecLib" >&5
if eval "test \"`echo '$''{'ac_cv_ld_altivec'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
save_LDFLAGS=$LDFLAGS
LDFLAGS="$LDFLAGS -framework vecLib"
cat > conftest.$ac_ext <<EOF
-#line 4013 "configure"
+#line 4015 "configure"
#include "confdefs.h"
int main() {
; return 0; }
EOF
-if { (eval echo configure:4020: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:4022: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
ac_cv_ld_altivec=yes
else
# Extract the first word of "${ac_tool_prefix}windres", so it can be a program name with args.
set dummy ${ac_tool_prefix}windres; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:4058: checking for $ac_word" >&5
+echo "configure:4060: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_WINDRES'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
# Extract the first word of "windres", so it can be a program name with args.
set dummy windres; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:4090: checking for $ac_word" >&5
+echo "configure:4092: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_WINDRES'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:4131: checking for $ac_hdr" >&5
+echo "configure:4133: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 4136 "configure"
+#line 4138 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:4141: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:4143: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:4174: checking for $ac_hdr" >&5
+echo "configure:4176: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 4179 "configure"
+#line 4181 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:4184: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:4186: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:4210: checking for $ac_hdr" >&5
+echo "configure:4212: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 4215 "configure"
+#line 4217 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:4220: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:4222: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
LINUX_DVD_STRUCT=0
OPENBSD_DVD_STRUCT=0
cat > conftest.$ac_ext <<EOF
-#line 4250 "configure"
+#line 4252 "configure"
#include "confdefs.h"
#include <sys/cdio.h>
EOF
EOF
cat > conftest.$ac_ext <<EOF
-#line 4263 "configure"
+#line 4265 "configure"
#include "confdefs.h"
#include <sys/cdio.h>
EOF
rm -f conftest*
cat > conftest.$ac_ext <<EOF
-#line 4283 "configure"
+#line 4285 "configure"
#include "confdefs.h"
#include <sys/dvdio.h>
EOF
EOF
cat > conftest.$ac_ext <<EOF
-#line 4296 "configure"
+#line 4298 "configure"
#include "confdefs.h"
#include <sys/dvdio.h>
EOF
rm -f conftest*
cat > conftest.$ac_ext <<EOF
-#line 4316 "configure"
+#line 4318 "configure"
#include "confdefs.h"
#include <linux/cdrom.h>
EOF
NEED_BSDI_LIBDVD=0
cat > conftest.$ac_ext <<EOF
-#line 4335 "configure"
+#line 4337 "configure"
#include "confdefs.h"
#include <dvd.h>
EOF
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:4357: checking for $ac_hdr" >&5
+echo "configure:4359: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 4362 "configure"
+#line 4364 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:4367: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:4369: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
ac_safe=`echo "sys/scsi/scsi_types.h" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for sys/scsi/scsi_types.h""... $ac_c" 1>&6
-echo "configure:4407: checking for sys/scsi/scsi_types.h" >&5
+echo "configure:4409: checking for sys/scsi/scsi_types.h" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 4412 "configure"
+#line 4414 "configure"
#include "confdefs.h"
#include <sys/scsi/scsi_types.h>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:4417: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:4419: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
ac_safe=`echo "sys/scsi/impl/uscsi.h" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for sys/scsi/impl/uscsi.h""... $ac_c" 1>&6
-echo "configure:4436: checking for sys/scsi/impl/uscsi.h" >&5
+echo "configure:4438: checking for sys/scsi/impl/uscsi.h" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 4441 "configure"
+#line 4443 "configure"
#include "confdefs.h"
#include <sys/scsi/impl/uscsi.h>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:4446: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:4448: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
enableval="$enable_pth"
if test x$enableval = xyes; then
echo $ac_n "checking for pth_init in -lpth""... $ac_c" 1>&6
-echo "configure:4601: checking for pth_init in -lpth" >&5
+echo "configure:4603: checking for pth_init in -lpth" >&5
ac_lib_var=`echo pth'_'pth_init | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
ac_save_LIBS="$LIBS"
LIBS="-lpth $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 4609 "configure"
+#line 4611 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
pth_init()
; return 0; }
EOF
-if { (eval echo configure:4620: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:4622: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
fi
cat > conftest.$ac_ext <<EOF
-#line 4648 "configure"
+#line 4650 "configure"
#include "confdefs.h"
#include <pth.h>
EOF
fi
+# Check whether --enable-dvdread or --disable-dvdread was given.
+if test "${enable_dvdread+set}" = set; then
+ enableval="$enable_dvdread"
+ if test x$enableval = xyes
+ then
+ NEED_LIBDVDCSS=1
+ STATIC_LIBDVDCSS=1
+ BUILTINS="${BUILTINS} dvdread"
+ CFLAGS_DVDREAD="${CFLAGS_DVDREAD} -I../../extras/libdvdread"
+ LIB_DVDREAD="${LIB_DVDREAD} lib/libdvdread.a lib/libdvdcss.a"
+ fi
+else
+ NEED_LIBDVDCSS=1
+ STATIC_LIBDVDCSS=1
+ BUILTINS="${BUILTINS} dvdread"
+ CFLAGS_DVDREAD="${CFLAGS_DVDREAD} -I../../extras/libdvdread"
+ LIB_DVDREAD="${LIB_DVDREAD} lib/libdvdread.a lib/libdvdcss.a"
+fi
+
+
# Check whether --enable-vcd or --disable-vcd was given.
if test "${enable_vcd+set}" = set; then
enableval="$enable_vcd"
if test x$enable_vcd != xno
then
cat > conftest.$ac_ext <<EOF
-#line 4755 "configure"
+#line 4777 "configure"
#include "confdefs.h"
#include <linux/cdrom.h>
EOF
# Extract the first word of "esd-config", so it can be a program name with args.
set dummy esd-config; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:4843: checking for $ac_word" >&5
+echo "configure:4865: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_ESD_CONFIG'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
# Extract the first word of "artsc-config", so it can be a program name with args.
set dummy artsc-config; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:4894: checking for $ac_word" >&5
+echo "configure:4916: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_ARTS_CONFIG'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:4961: checking for $ac_hdr" >&5
+echo "configure:4983: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 4966 "configure"
+#line 4988 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:4971: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:4993: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:5015: checking for $ac_hdr" >&5
+echo "configure:5037: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 5020 "configure"
+#line 5042 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:5025: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:5047: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
# Extract the first word of "sdl12-config", so it can be a program name with args.
set dummy sdl12-config; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:5103: checking for $ac_word" >&5
+echo "configure:5125: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_SDL12_CONFIG'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
# Extract the first word of "sdl11-config", so it can be a program name with args.
set dummy sdl11-config; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:5143: checking for $ac_word" >&5
+echo "configure:5165: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_SDL11_CONFIG'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
# Extract the first word of "sdl-config", so it can be a program name with args.
set dummy sdl-config; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:5184: checking for $ac_word" >&5
+echo "configure:5206: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_SDL_CONFIG'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:5230: checking for $ac_hdr" >&5
+echo "configure:5252: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 5235 "configure"
+#line 5257 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:5240: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:5262: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:5308: checking for $ac_hdr" >&5
+echo "configure:5330: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 5313 "configure"
+#line 5335 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:5318: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:5340: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
fi
else
echo $ac_n "checking for directX headers in ${enableval}""... $ac_c" 1>&6
-echo "configure:5351: checking for directX headers in ${enableval}" >&5
+echo "configure:5373: checking for directX headers in ${enableval}" >&5
if test -f ${enableval}/include/directx.h
then
LIB_DIRECTX="-L${enableval}/lib -lgdi32 -ldxguid"
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:5370: checking for $ac_hdr" >&5
+echo "configure:5392: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 5375 "configure"
+#line 5397 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:5380: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:5402: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
# Extract the first word of "gnome-config", so it can be a program name with args.
set dummy gnome-config; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:5480: checking for $ac_word" >&5
+echo "configure:5502: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_GNOME_CONFIG'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:5525: checking for $ac_hdr" >&5
+echo "configure:5547: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 5530 "configure"
+#line 5552 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:5535: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:5557: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
# Extract the first word of "gtk-config", so it can be a program name with args.
set dummy gtk-config; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:5595: checking for $ac_word" >&5
+echo "configure:5617: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_GTK_CONFIG'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:5640: checking for $ac_hdr" >&5
+echo "configure:5662: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 5645 "configure"
+#line 5667 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:5650: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:5672: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:5702: checking for $ac_hdr" >&5
+echo "configure:5724: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 5707 "configure"
+#line 5729 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:5712: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:5734: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:5765: checking for $ac_hdr" >&5
+echo "configure:5787: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 5770 "configure"
+#line 5792 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:5775: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:5797: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
then
ac_safe=`echo "sys/asoundlib.h" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for sys/asoundlib.h""... $ac_c" 1>&6
-echo "configure:5815: checking for sys/asoundlib.h" >&5
+echo "configure:5837: checking for sys/asoundlib.h" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 5820 "configure"
+#line 5842 "configure"
#include "confdefs.h"
#include <sys/asoundlib.h>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:5825: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:5847: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
echo "$ac_t""yes" 1>&6
echo $ac_n "checking for main in -lasound""... $ac_c" 1>&6
-echo "configure:5842: checking for main in -lasound" >&5
+echo "configure:5864: checking for main in -lasound" >&5
ac_lib_var=`echo asound'_'main | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
ac_save_LIBS="$LIBS"
LIBS="-lasound $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 5850 "configure"
+#line 5872 "configure"
#include "confdefs.h"
int main() {
main()
; return 0; }
EOF
-if { (eval echo configure:5857: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:5879: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
+
+
+
s%@LIB_DARWIN@%$LIB_DARWIN%g
s%@LIB_DVD@%$LIB_DVD%g
s%@LIB_DVD_PLUGIN@%$LIB_DVD_PLUGIN%g
+s%@LIB_DVDREAD@%$LIB_DVDREAD%g
+s%@LIB_DVDREAD_PLUGIN@%$LIB_DVDREAD_PLUGIN%g
s%@LIB_ESD@%$LIB_ESD%g
s%@LIB_GGI@%$LIB_GGI%g
s%@LIB_GLIDE@%$LIB_GLIDE%g
s%@CFLAGS_VLC@%$CFLAGS_VLC%g
s%@CFLAGS_ALTIVEC@%$CFLAGS_ALTIVEC%g
s%@CFLAGS_DVD@%$CFLAGS_DVD%g
+s%@CFLAGS_DVDREAD@%$CFLAGS_DVDREAD%g
s%@CFLAGS_LIBDVDCSS@%$CFLAGS_LIBDVDCSS%g
s%@CFLAGS_ARTS@%$CFLAGS_ARTS%g
s%@CFLAGS_ESD@%$CFLAGS_ESD%g
LIB_DVD_PLUGIN="${LIB_DVD_PLUGIN} -ldl"
fi ])
+dnl
+dnl DVDREAD module: check for libdvdread plugin
+dnl
+AC_ARG_ENABLE(dvdread,
+[ --enable-dvdread Enable dvdread support (default enabled)],
+[ if test x$enableval = xyes
+ then
+ NEED_LIBDVDCSS=1
+ STATIC_LIBDVDCSS=1
+ BUILTINS="${BUILTINS} dvdread"
+ CFLAGS_DVDREAD="${CFLAGS_DVDREAD} -I../../extras/libdvdread"
+ LIB_DVDREAD="${LIB_DVDREAD} lib/libdvdread.a lib/libdvdcss.a"
+ fi ],
+[ NEED_LIBDVDCSS=1
+ STATIC_LIBDVDCSS=1
+ BUILTINS="${BUILTINS} dvdread"
+ CFLAGS_DVDREAD="${CFLAGS_DVDREAD} -I../../extras/libdvdread"
+ LIB_DVDREAD="${LIB_DVDREAD} lib/libdvdread.a lib/libdvdcss.a" ])
+
dnl
dnl VCD module
dnl
AC_SUBST(LIB_DARWIN)
AC_SUBST(LIB_DVD)
AC_SUBST(LIB_DVD_PLUGIN)
+AC_SUBST(LIB_DVDREAD)
+AC_SUBST(LIB_DVDREAD_PLUGIN)
AC_SUBST(LIB_ESD)
AC_SUBST(LIB_GGI)
AC_SUBST(LIB_GLIDE)
AC_SUBST(CFLAGS_VLC)
AC_SUBST(CFLAGS_ALTIVEC)
AC_SUBST(CFLAGS_DVD)
+AC_SUBST(CFLAGS_DVDREAD)
AC_SUBST(CFLAGS_LIBDVDCSS)
AC_SUBST(CFLAGS_ARTS)
AC_SUBST(CFLAGS_ESD)
--- /dev/null
+###############################################################################
+# vlc (VideoLAN Client) dvdread module Makefile
+# (c)2001 VideoLAN
+###############################################################################
+
+LIBDVDREAD_VERSION := 0.9.2
+CFLAGS_LIBDVDREAD := -I. -DHAVE_CONFIG_H
+LIB_LIBDVDREAD := -ldl
+
+BASE_A := libdvdread.a
+BASE_SO := libdvdread.so
+MAJOR_SO := libdvdread.so.$(shell echo $(LIBDVDREAD_VERSION) | cut -f1 -d.)
+FULL_SO := libdvdread.so.$(LIBDVDREAD_VERSION)
+ifneq (,$(SOFLAGS))
+ALL_SOFLAGS := $(SOFLAGS)$(MAJOR_SO)
+SOFLAGS :=
+endif
+
+#
+# Objects
+#
+
+OBJ_C = dvdread.o dvd_udf.o nav_print.o nav_read.o ifo_print.o ifo_read.o
+
+PLUGIN_OBJ = $(OBJ_C) $(OBJ_LIBDVDREAD)
+BUILTIN_OBJ = $(OBJ_C:%.o=DVDREAD_%.o)
+
+ALL_OBJ = $(PLUGIN_OBJ) $(BUILTIN_OBJ)
+
+include ../../Makefile.modules
+
+$(OBJ_C): %.o: .dep/%.d
+$(OBJ_C): %.o: %.c
+ $(CC) $(CFLAGS) $(CFLAGS_LIBDVDREAD) $(PCFLAGS) -c -o $@ $<
+
+$(BUILTIN_OBJ): DVDREAD_%.o: .dep/%.d
+$(BUILTIN_OBJ): DVDREAD_%.o: %.c
+ $(CC) $(CFLAGS) $(CFLAGS_LIBDVDREAD) $(PCFLAGS) -c -o $@ $<
+
+../../lib/$(FULL_SO): $(OBJ_C) $(OBJ_LIBDVDREAD)
+ $(CC) $(PCFLAGS) $(ALL_SOFLAGS) -o $@ $^ $(PLCFLAGS) $(LIB_LIBDVDREAD)
+ rm -f ../../lib/$(BASE_SO) && ln -s $(FULL_SO) ../../lib/$(BASE_SO)
+ rm -f ../../lib/$(MAJOR_SO) && ln -s $(FULL_SO) ../../lib/$(MAJOR_SO)
+
+../../lib/$(BASE_A): libdvdcss $(BUILTIN_OBJ) $(OBJ_LIBDVDREAD)
+ ar r $@ $(BUILTIN_OBJ)
+ $(RANLIB) $@
+
+#
+# Virtual targets
+#
+all: ../../lib/$(BASE_A)
+
+libdvdcss:
+ cd ../../ && $(MAKE) libdvdcss
+
+#install:
+# mkdir -p $(DESTDIR)$(includedir)/videolan
+# $(INSTALL) -m 644 videolan/dvdcss.h $(DESTDIR)$(includedir)/videolan
+# mkdir -p $(DESTDIR)$(libdir)
+# -$(INSTALL) -m 644 ../../lib/$(BASE_A) $(DESTDIR)$(libdir)
+# -$(INSTALL) -m 644 ../../lib/$(FULL_SO) $(DESTDIR)$(libdir)
+# rm -f $(DESTDIR)$(libdir)/$(BASE_SO) && ln -s $(FULL_SO) $(DESTDIR)$(libdir)/$(BASE_SO)
+# rm -f $(DESTDIR)$(libdir)/$(MAJOR_SO) && ln -s $(FULL_SO) $(DESTDIR)$(libdir)/$(MAJOR_SO)
+#
+#uninstall:
+# rm -f $(DESTDIR)$(includedir)/videolan/dvdcss.h
+# rm -f $(DESTDIR)$(libdir)/$(BASE_A)
+# rm -f $(DESTDIR)$(libdir)/$(BASE_SO)
+# rm -f $(DESTDIR)$(libdir)/$(MAJOR_SO)
+# rm -f $(DESTDIR)$(libdir)/$(FULL_SO)
+
--- /dev/null
+/**
+ * Copyright (C) 2000, 2001 Billy Biggs <vektor@dumbterm.net>,
+ * Håkan Hjort <d95hjort@dtek.chalmers.se>
+ *
+ * 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 BSWAP_H_INCLUDED
+#define BSWAP_H_INCLUDED
+
+#include <config.h>
+
+#if defined(WORDS_BIGENDIAN)
+/* All bigendian systems are fine, just ignore the swaps. */
+#define B2N_16(x) (void)(x)
+#define B2N_32(x) (void)(x)
+#define B2N_64(x) (void)(x)
+
+#else
+
+#if defined(__linux__)
+#include <byteswap.h>
+#define B2N_16(x) x = bswap_16(x)
+#define B2N_32(x) x = bswap_32(x)
+#define B2N_64(x) x = bswap_64(x)
+
+#elif defined(__NetBSD__)
+#include <sys/endian.h>
+#define B2N_16(x) BE16TOH(x)
+#define B2N_32(x) BE32TOH(x)
+#define B2N_64(x) BE64TOH(x)
+
+#elif defined(__OpenBSD__)
+#include <sys/endian.h>
+#define B2N_16(x) x = swap16(x)
+#define B2N_32(x) x = swap32(x)
+#define B2N_64(x) x = swap64(x)
+
+/* This is a slow but portable implementation, it has multiple evaluation
+ * problems so beware.
+ * FreeBSD and Solaris don't have <byteswap.h> or any other such
+ * functionality!
+ */
+
+#elif defined(__FreeBSD__) || defined(__sun) || defined(__bsdi__)
+#define B2N_16(x) \
+ x = ((((x) & 0xff00) >> 8) | \
+ (((x) & 0x00ff) << 8))
+#define B2N_32(x) \
+ x = ((((x) & 0xff000000) >> 24) | \
+ (((x) & 0x00ff0000) >> 8) | \
+ (((x) & 0x0000ff00) << 8) | \
+ (((x) & 0x000000ff) << 24))
+#define B2N_64(x) \
+ x = ((((x) & 0xff00000000000000) >> 56) | \
+ (((x) & 0x00ff000000000000) >> 40) | \
+ (((x) & 0x0000ff0000000000) >> 24) | \
+ (((x) & 0x000000ff00000000) >> 8) | \
+ (((x) & 0x00000000ff000000) << 8) | \
+ (((x) & 0x0000000000ff0000) << 24) | \
+ (((x) & 0x000000000000ff00) << 40) | \
+ (((x) & 0x00000000000000ff) << 56))
+
+#else
+
+/* If there isn't a header provided with your system with this functionality
+ * add the relevant || define( ) to the portable implementation above.
+ */
+#error "You need to add endian swap macros for you're system"
+
+#endif
+
+#endif /* WORDS_BIGENDIAN */
+
+#endif /* BSWAP_H_INCLUDED */
--- /dev/null
+/**
+ * Copyright (C) 2001 Billy Biggs <vektor@dumbterm.net>.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h> /* For the timing of dvdcss_title crack. */
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <dlfcn.h>
+#include <dirent.h>
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__)
+#define SYS_BSD 1
+#endif
+
+#if defined(__sun)
+#include <sys/mnttab.h>
+#elif defined(SYS_BSD)
+#include <fstab.h>
+#elif defined(__linux__)
+#include <mntent.h>
+#endif
+
+#if defined(SYS_BSD)
+typedef off_t off64_t;
+#define lseek64 lseek
+#define stat64 stat
+#endif
+
+/* #include "dvdcss.h" */
+typedef struct dvdcss_s* dvdcss_handle;
+#define DVDCSS_NOFLAGS 0
+#define DVDCSS_INIT_QUIET (1 << 0)
+#define DVDCSS_INIT_DEBUG (1 << 1)
+#define DVDCSS_READ_DECRYPT (1 << 0)
+
+#include "dvd_udf.h"
+#include "dvd_reader.h"
+
+/**
+ * Handle to the loaded dvdcss library.
+ */
+void *dvdcss_library = 0;
+
+/**
+ * libdvdcss functions.
+ */
+static dvdcss_handle (*dvdcss_open) ( char *psz_target,
+ int i_flags );
+static int (*dvdcss_close) ( dvdcss_handle );
+static int (*dvdcss_title) ( dvdcss_handle,
+ int i_block );
+static int (*dvdcss_seek) ( dvdcss_handle,
+ int i_blocks );
+static int (*dvdcss_read) ( dvdcss_handle,
+ void *p_buffer,
+ int i_blocks,
+ int i_title );
+static char * (*dvdcss_error) ( dvdcss_handle );
+
+struct dvd_reader_s {
+ /* Basic information. */
+ int isImageFile;
+
+ /* Information required for an image file. */
+ dvdcss_handle dev;
+ int init_keys;
+ int fd;
+
+ /* Information required for a directory path drive. */
+ char *path_root;
+};
+
+struct dvd_file_s {
+ /* Basic information. */
+ dvd_reader_t *dvd;
+
+ /* Information required for an image file. */
+ uint32_t lb_start;
+ uint32_t seek_pos;
+
+ /* Information required for a directory path drive. */
+ size_t title_sizes[ 9 ];
+ int title_fds[ 9 ];
+
+ /* Calculated at open-time, size in blocks. */
+ ssize_t filesize;
+};
+
+static void setupCSS( void )
+{
+ if( !dvdcss_library ) {
+ dvdcss_library = dlopen( "libdvdcss.so.0", RTLD_LAZY );
+
+ if( !dvdcss_library ) {
+ fprintf( stderr, "libdvdread: Can't open libdvdcss: %s.\n",
+ dlerror() );
+ } else {
+#if defined(__OpenBSD__)
+#define U_S "_"
+#else
+#define U_S
+#endif
+ dvdcss_open = (dvdcss_handle (*)(char*, int))
+ dlsym( dvdcss_library, U_S "dvdcss_open" );
+ dvdcss_close = (int (*)(dvdcss_handle))
+ dlsym( dvdcss_library, U_S "dvdcss_close" );
+ dvdcss_title = (int (*)(dvdcss_handle, int))
+ dlsym( dvdcss_library, U_S "dvdcss_title" );
+ dvdcss_seek = (int (*)(dvdcss_handle, int))
+ dlsym( dvdcss_library, U_S "dvdcss_seek" );
+ dvdcss_read = (int (*)(dvdcss_handle, void*, int, int))
+ dlsym( dvdcss_library, U_S "dvdcss_read" );
+ dvdcss_error = (char* (*)(dvdcss_handle))
+ dlsym( dvdcss_library, U_S "dvdcss_error" );
+
+ if( dlsym( dvdcss_library, U_S "dvdcss_crack" ) ) {
+ fprintf( stderr, "libdvdread: Old (pre-0.0.2) version of "
+ "libdvdcss found.\n"
+ "libdvdread: You should get the "
+ "latest version from "
+ "http://www.videolan.org/\n" );
+ dlclose( dvdcss_library );
+ dvdcss_library = 0;
+ } else if( !dvdcss_open || !dvdcss_close || !dvdcss_seek ||
+ !dvdcss_title || !dvdcss_read || !dvdcss_error ) {
+
+ fprintf( stderr, "libdvdread: Unknown incompatible version "
+ "of libdvdcss found.\n"
+ "libdvdread: Try to find a "
+ "newer version of libdvdread?\n" );
+ dlclose( dvdcss_library );
+ dvdcss_library = 0;
+ }
+ }
+ }
+
+ if( !dvdcss_library ) {
+ fprintf( stderr, "libdvdread: Encrypted DVD support unavailable.\n" );
+ }
+}
+
+
+/* Loop over all titles and call dvdcss_title to crack the keys. */
+static int initAllCSSKeys( dvd_reader_t *dvd )
+{
+
+ if( dvdcss_library ) {
+ struct timeval all_s, all_e;
+ struct timeval t_s, t_e;
+ char filename[ MAX_UDF_FILE_NAME_LEN ];
+ uint32_t start, len;
+ int title;
+
+ fprintf( stderr, "\n" );
+ fprintf( stderr, "libdvdread: Attempting to retrieve all CSS keys\n" );
+ fprintf( stderr, "libdvdread: This can take a _long_ time, "
+ "please be patient\n\n" );
+
+ gettimeofday(&all_s, NULL);
+
+ for( title = 0; title < 100; title++ ) {
+ gettimeofday( &t_s, NULL );
+ if( title == 0 ) {
+ sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" );
+ } else {
+ sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, 0 );
+ }
+ start = UDFFindFile( dvd, filename, &len );
+ if( start != 0 && len != 0 ) {
+ /* Perform CSS key cracking for this title. */
+ fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n",
+ filename, start );
+ if( dvdcss_title( dvd->dev, (int)start ) < 0 ) {
+ fprintf( stderr, "libdvdread: Error cracking CSS key!!\n");
+ }
+ gettimeofday( &t_e, NULL );
+ fprintf( stderr, "libdvdread: Elapsed time %ld\n",
+ (long int) t_e.tv_sec - t_s.tv_sec );
+ }
+
+ if( title == 0 ) continue;
+
+ gettimeofday( &t_s, NULL );
+ sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, 1 );
+ start = UDFFindFile( dvd, filename, &len );
+ if( start == 0 || len == 0 ) break;
+
+ /* Perform CSS key cracking for this title. */
+ fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n",
+ filename, start );
+ if( dvdcss_title( dvd->dev, (int)start ) < 0 ) {
+ fprintf( stderr, "libdvdread: Error cracking CSS key!!\n");
+ }
+ gettimeofday( &t_e, NULL );
+ fprintf( stderr, "libdvdread: Elapsed time %ld\n",
+ (long int) t_e.tv_sec - t_s.tv_sec );
+ }
+ title--;
+
+ fprintf( stderr, "libdvdread: Found %d VTS's\n", title );
+ gettimeofday(&all_e, NULL);
+ fprintf( stderr, "libdvdread: Elapsed time %ld\n",
+ (long int) all_e.tv_sec - all_s.tv_sec );
+ }
+
+ return 0;
+}
+
+
+
+/**
+ * Open a DVD image or block device file.
+ */
+static dvd_reader_t *DVDOpenImageFile( const char *location )
+{
+ dvd_reader_t *dvd;
+ dvdcss_handle dev = 0;
+ int fd = -1;
+
+ setupCSS();
+
+ if( dvdcss_library ) {
+ dev = dvdcss_open( (char *) location, DVDCSS_INIT_DEBUG );
+ if( !dev ) {
+ fprintf( stderr, "libdvdread: Can't open %s for reading.\n",
+ location );
+ return 0;
+ }
+ } else {
+ fd = open( location, O_RDONLY );
+ if( fd < 0 ) {
+ fprintf( stderr, "libdvdread: Can't open %s for reading.\n",
+ location );
+ return 0;
+ }
+ }
+
+ dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) );
+ if( !dvd ) return 0;
+ dvd->isImageFile = 1;
+ dvd->dev = dev;
+ dvd->init_keys = 0;
+ dvd->fd = fd;
+ dvd->path_root = 0;
+
+ return dvd;
+}
+
+static dvd_reader_t *DVDOpenPath( const char *path_root )
+{
+ dvd_reader_t *dvd;
+
+ dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) );
+ if( !dvd ) return 0;
+ dvd->isImageFile = 0;
+ dvd->dev = 0;
+ dvd->init_keys = 0;
+ dvd->fd = -1;
+ dvd->path_root = strdup( path_root );
+
+ return dvd;
+}
+
+#if defined(__sun)
+/* /dev/rdsk/c0t6d0s0 (link to /devices/...)
+ /vol/dev/rdsk/c0t6d0/??
+ /vol/rdsk/<name> */
+static char *sun_block2char( const char *path )
+{
+ char *new_path;
+
+ /* Must contain "/dsk/" */
+ if( !strstr( path, "/dsk/" ) ) return (char *) strdup( path );
+
+ /* Replace "/dsk/" with "/rdsk/" */
+ new_path = malloc( strlen(path) + 2 );
+ strcpy( new_path, path );
+ strcpy( strstr( new_path, "/dsk/" ), "" );
+ strcat( new_path, "/rdsk/" );
+ strcat( new_path, strstr( path, "/dsk/" ) + strlen( "/dsk/" ) );
+
+ return new_path;
+}
+#endif
+
+#if defined(SYS_BSD)
+/* FreeBSD /dev/(r)(a)cd0 (a is for atapi, should work without r)
+ OpenBSD /dev/rcd0c
+ NetBSD /dev/rcd0d or /dev/rcd0c (for non x86)
+ BSD/OS /dev/sr0 (if not mounted) or /dev/rsr0 */
+static char *bsd_block2char( const char *path )
+{
+ char *new_path;
+
+ /* If it doesn't start with "/dev/" or does start with "/dev/r" exit */
+ if( !strncmp( path, "/dev/", 5 ) || strncmp( path, "/dev/r", 6 ) )
+ return (char *) strdup( path );
+
+ /* Replace "/dev/" with "/dev/r" */
+ new_path = malloc( strlen(path) + 2 );
+ strcpy( new_path, "/dev/r" );
+ strcat( new_path, path + strlen( "/dev/" ) );
+
+ return new_path;
+}
+#endif
+
+dvd_reader_t *DVDOpen( const char *path )
+{
+ struct stat64 fileinfo;
+ int ret;
+
+ if( !path ) return 0;
+
+ ret = stat64( path, &fileinfo );
+ if( ret < 0 ) {
+ /* If we can't stat the file, give up */
+ fprintf( stderr, "libdvdread: Can't stat %s\n", path );
+ perror("");
+ return 0;
+ }
+
+ /* First check if this is a block/char device or a file*/
+ if( S_ISBLK( fileinfo.st_mode ) ||
+ S_ISCHR( fileinfo.st_mode ) ||
+ S_ISREG( fileinfo.st_mode ) ) {
+
+ /**
+ * Block devices and regular files are assumed to be DVD-Video images.
+ */
+#if defined(__sun)
+ return DVDOpenImageFile( sun_block2char( path ) );
+#elif defined(SYS_BSD)
+ return DVDOpenImageFile( bsd_block2char( path ) );
+#else
+ return DVDOpenImageFile( path );
+#endif
+
+ } else if( S_ISDIR( fileinfo.st_mode ) ) {
+ dvd_reader_t *auth_drive = 0;
+ char *path_copy;
+#if defined(SYS_BSD)
+ struct fstab* fe;
+#elif defined(__sun) || defined(__linux__)
+ FILE *mntfile;
+#endif
+
+ /* XXX: We should scream real loud here. */
+ if( !(path_copy = strdup( path ) ) ) return 0;
+
+ /* Resolve any symlinks and get the absolut dir name. */
+ {
+ char *new_path;
+ int cdir = open( ".", O_RDONLY );
+
+ if( cdir >= 0 ) {
+ chdir( path_copy );
+ new_path = getcwd( NULL, PATH_MAX );
+ fchdir( cdir );
+ close( cdir );
+ if( new_path ) {
+ free( path_copy );
+ path_copy = new_path;
+ }
+ }
+ }
+
+ /**
+ * If we're being asked to open a directory, check if that directory
+ * is the mountpoint for a DVD-ROM which we can use instead.
+ */
+
+ if( strlen( path_copy ) > 1 ) {
+ if( path[ strlen( path_copy ) - 1 ] == '/' )
+ path_copy[ strlen( path_copy ) - 1 ] = '\0';
+ }
+
+ if( strlen( path_copy ) > 9 ) {
+ if( !strcasecmp( &(path_copy[ strlen( path_copy ) - 9 ]),
+ "/video_ts" ) ) {
+ path_copy[ strlen( path_copy ) - 9 ] = '\0';
+ }
+ }
+
+#if defined(SYS_BSD)
+ if( ( fe = getfsfile( path_copy ) ) ) {
+ char *dev_name = bsd_block2char( fe->fs_spec );
+ fprintf( stderr,
+ "libdvdread: Attempting to use device %s"
+ " mounted on %s for CSS authentication\n",
+ dev_name,
+ fe->fs_file );
+ auth_drive = DVDOpenImageFile( dev_name );
+ free( dev_name );
+ }
+#elif defined(__sun)
+ mntfile = fopen( MNTTAB, "r" );
+ if( mntfile ) {
+ struct mnttab mp;
+ int res;
+
+ while( ( res = getmntent( mntfile, &mp ) ) != -1 ) {
+ if( res == 0 && !strcmp( mp.mnt_mountp, path_copy ) ) {
+ char *dev_name = sun_block2char( mp.mnt_special );
+ fprintf( stderr,
+ "libdvdread: Attempting to use device %s"
+ " mounted on %s for CSS authentication\n",
+ dev_name,
+ mp.mnt_mountp );
+ auth_drive = DVDOpenImageFile( dev_name );
+ free( dev_name );
+ break;
+ }
+ }
+ fclose( mntfile );
+ }
+#elif defined(__linux__)
+ mntfile = fopen( MOUNTED, "r" );
+ if( mntfile ) {
+ struct mntent *me;
+
+ while( ( me = getmntent( mntfile ) ) ) {
+ if( !strcmp( me->mnt_dir, path_copy ) ) {
+ fprintf( stderr,
+ "libdvdread: Attempting to use device %s"
+ " mounted on %s for CSS authentication\n",
+ me->mnt_fsname,
+ me->mnt_dir );
+ auth_drive = DVDOpenImageFile( me->mnt_fsname );
+ break;
+ }
+ }
+ fclose( mntfile );
+ }
+#endif
+ if( !auth_drive ) {
+ fprintf( stderr, "libdvdread: Device inaccessible, "
+ "CSS authentication not available.\n" );
+ }
+
+ free( path_copy );
+
+ /**
+ * If we've opened a drive, just use that.
+ */
+ if( auth_drive ) return auth_drive;
+
+ /**
+ * Otherwise, we now try to open the directory tree instead.
+ */
+ fprintf( stderr, "libdvdread: Using normal filesystem access.\n" );
+ return DVDOpenPath( path );
+ }
+
+ /* If it's none of the above, screw it. */
+ fprintf( stderr, "libdvdread: Could not open %s\n", path );
+ return 0;
+}
+
+void DVDClose( dvd_reader_t *dvd )
+{
+ if( dvd ) {
+ if( dvd->dev ) dvdcss_close( dvd->dev );
+ if( dvd->fd >= 0 ) close( dvd->fd );
+ if( dvd->path_root ) free( dvd->path_root );
+ free( dvd );
+ dvd = 0;
+ }
+}
+
+/**
+ * Open an unencrypted file on a DVD image file.
+ */
+static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *dvd, char *filename )
+{
+ uint32_t start, len;
+ dvd_file_t *dvd_file;
+
+ start = UDFFindFile( dvd, filename, &len );
+ if( !start ) return 0;
+
+ dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
+ if( !dvd_file ) return 0;
+ dvd_file->dvd = dvd;
+ dvd_file->lb_start = start;
+ dvd_file->seek_pos = 0;
+ memset( dvd_file->title_fds, -1, sizeof( dvd_file->title_fds ) );
+ dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
+
+ return dvd_file;
+}
+
+/**
+ * Searches for <file> in directory <path>, ignoring case.
+ * Returns 0 and full filename in <filename>.
+ * or -1 on file not found.
+ * or -2 on path not found.
+ */
+static int findDirFile( const char *path, const char *file, char *filename )
+{
+ DIR *dir;
+ struct dirent *ent;
+
+ dir = opendir( path );
+ if( !dir ) return -2;
+
+ while( ( ent = readdir( dir ) ) != NULL ) {
+ if( !strcasecmp( ent->d_name, file ) ) {
+ sprintf( filename, "%s%s%s", path,
+ ( ( path[ strlen( path ) - 1 ] == '/' ) ? "" : "/" ),
+ ent->d_name );
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static int findDVDFile( dvd_reader_t *dvd, const char *file, char *filename )
+{
+ char video_path[ PATH_MAX + 1 ];
+ const char *nodirfile;
+ int ret;
+
+ /* Strip off the directory for our search */
+ if( !strncasecmp( "/VIDEO_TS/", file, 10 ) ) {
+ nodirfile = &(file[ 10 ]);
+ } else {
+ nodirfile = file;
+ }
+
+ ret = findDirFile( dvd->path_root, nodirfile, filename );
+ if( ret < 0 ) {
+ /* Try also with adding the path, just in case. */
+ sprintf( video_path, "%s/VIDEO_TS/", dvd->path_root );
+ ret = findDirFile( video_path, nodirfile, filename );
+ if( ret < 0 ) {
+ /* Try with the path, but in lower case. */
+ sprintf( video_path, "%s/video_ts/", dvd->path_root );
+ ret = findDirFile( video_path, nodirfile, filename );
+ if( ret < 0 ) {
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+/**
+ * Open an unencrypted file from a DVD directory tree.
+ */
+static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, char *filename )
+{
+ char full_path[ PATH_MAX + 1 ];
+ dvd_file_t *dvd_file;
+ struct stat fileinfo;
+ int fd;
+
+ /* Get the full path of the file. */
+ if( !findDVDFile( dvd, filename, full_path ) ) return 0;
+
+ fd = open( full_path, O_RDONLY );
+ if( fd < 0 ) return 0;
+
+ dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
+ if( !dvd_file ) return 0;
+ dvd_file->dvd = dvd;
+ dvd_file->lb_start = 0;
+ dvd_file->seek_pos = 0;
+ memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
+ memset( dvd_file->title_fds, -1, sizeof( dvd_file->title_fds ) );
+ dvd_file->filesize = 0;
+
+ if( stat( full_path, &fileinfo ) < 0 ) {
+ fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
+ free( dvd_file );
+ return 0;
+ }
+ dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
+ dvd_file->title_fds[ 0 ] = fd;
+ dvd_file->filesize = dvd_file->title_sizes[ 0 ];
+
+ return dvd_file;
+}
+
+static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *dvd,
+ int title, int menu )
+{
+ char filename[ MAX_UDF_FILE_NAME_LEN ];
+ uint32_t start, len;
+ dvd_file_t *dvd_file;
+
+ if( title == 0 ) {
+ sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" );
+ } else {
+ sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, menu ? 0 : 1 );
+ }
+ start = UDFFindFile( dvd, filename, &len );
+ if( start == 0 ) return 0;
+
+ dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
+ if( !dvd_file ) return 0;
+ dvd_file->dvd = dvd;
+ dvd_file->lb_start = start;
+ dvd_file->seek_pos = 0;
+ memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
+ memset( dvd_file->title_fds, -1, sizeof( dvd_file->title_fds ) );
+ dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
+
+ /* Calculate the complete file size for every file in the VOBS */
+ if( !menu ) {
+ int cur;
+
+ for( cur = 2; cur < 10; cur++ ) {
+ sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, cur );
+ if( !UDFFindFile( dvd, filename, &len ) ) break;
+ dvd_file->filesize += len / DVD_VIDEO_LB_LEN;
+ }
+ }
+
+ /* Hack to crack all the keys on the first open. */
+ if( dvdcss_library ) {
+ if( !dvd_file->dvd->init_keys ) {
+ initAllCSSKeys( dvd_file->dvd );
+ dvd_file->dvd->init_keys = 1;
+ }
+ }
+
+ /* Perform CSS key cracking for this title. */
+ if( dvdcss_library ) {
+ if( dvdcss_title( dvd_file->dvd->dev, (int)start ) < 0 ) {
+ fprintf( stderr, "libdvdread: Error cracking CSS key for %s\n",
+ filename );
+ }
+ }
+
+ return dvd_file;
+}
+
+static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd,
+ int title, int menu )
+{
+ char filename[ MAX_UDF_FILE_NAME_LEN ];
+ char full_path[ PATH_MAX + 1 ];
+ struct stat fileinfo;
+ dvd_file_t *dvd_file;
+ int i;
+
+ dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
+ if( !dvd_file ) return 0;
+ dvd_file->dvd = dvd;
+ dvd_file->lb_start = 0;
+ dvd_file->seek_pos = 0;
+ memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
+ memset( dvd_file->title_fds, -1, sizeof( dvd_file->title_fds ) );
+ dvd_file->filesize = 0;
+
+ if( menu ) {
+ int fd;
+
+ if( title == 0 ) {
+ sprintf( filename, "VIDEO_TS.VOB" );
+ } else {
+ sprintf( filename, "VTS_%02i_0.VOB", title );
+ }
+ if( !findDVDFile( dvd, filename, full_path ) ) {
+ free( dvd_file );
+ return 0;
+ }
+
+ fd = open( full_path, O_RDONLY );
+ if( fd < 0 ) {
+ free( dvd_file );
+ return 0;
+ }
+
+ if( stat( full_path, &fileinfo ) < 0 ) {
+ fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
+ free( dvd_file );
+ return 0;
+ }
+ dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
+ dvd_file->title_fds[ 0 ] = fd;
+ dvd_file->filesize = dvd_file->title_sizes[ 0 ];
+
+ } else {
+ for( i = 0; i < 9; ++i ) {
+
+ sprintf( filename, "VTS_%02i_%i.VOB", title, i + 1 );
+ if( !findDVDFile( dvd, filename, full_path ) ) {
+ break;
+ }
+
+ if( stat( full_path, &fileinfo ) < 0 ) {
+ fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
+ break;
+ }
+
+ dvd_file->title_sizes[ i ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
+ dvd_file->title_fds[ i ] = open( full_path, O_RDONLY );
+ dvd_file->filesize += dvd_file->title_sizes[ i ];
+ }
+ if( !(dvd_file->title_sizes[ 0 ]) ) {
+ free( dvd_file );
+ return 0;
+ }
+ }
+
+ return dvd_file;
+}
+
+dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum,
+ dvd_read_domain_t domain )
+{
+ char filename[ MAX_UDF_FILE_NAME_LEN ];
+
+ switch( domain ) {
+ case DVD_READ_INFO_FILE:
+ if( titlenum == 0 ) {
+ sprintf( filename, "/VIDEO_TS/VIDEO_TS.IFO" );
+ } else {
+ sprintf( filename, "/VIDEO_TS/VTS_%02i_0.IFO", titlenum );
+ }
+ break;
+ case DVD_READ_INFO_BACKUP_FILE:
+ if( titlenum == 0 ) {
+ sprintf( filename, "/VIDEO_TS/VIDEO_TS.BUP" );
+ } else {
+ sprintf( filename, "/VIDEO_TS/VTS_%02i_0.BUP", titlenum );
+ }
+ break;
+ case DVD_READ_MENU_VOBS:
+ if( dvd->isImageFile ) {
+ return DVDOpenVOBUDF( dvd, titlenum, 1 );
+ } else {
+ return DVDOpenVOBPath( dvd, titlenum, 1 );
+ }
+ break;
+ case DVD_READ_TITLE_VOBS:
+ if( titlenum == 0 ) return 0;
+ if( dvd->isImageFile ) {
+ return DVDOpenVOBUDF( dvd, titlenum, 0 );
+ } else {
+ return DVDOpenVOBPath( dvd, titlenum, 0 );
+ }
+ break;
+ default:
+ fprintf( stderr, "libdvdread: Invalid domain for file open.\n" );
+ return 0;
+ }
+
+ if( dvd->isImageFile ) {
+ return DVDOpenFileUDF( dvd, filename );
+ } else {
+ return DVDOpenFilePath( dvd, filename );
+ }
+}
+
+void DVDCloseFile( dvd_file_t *dvd_file )
+{
+ int i;
+
+ if( dvd_file ) {
+ if( !dvd_file->dvd->isImageFile ) {
+ for( i = 0; i < 9; ++i ) {
+ if( dvd_file->title_fds[ i ] >= 0 )
+ close( dvd_file->title_fds[ i ] );
+ }
+ }
+
+ free( dvd_file );
+ dvd_file = 0;
+ }
+}
+
+int64_t DVDReadLBUDF( dvd_reader_t *device, uint32_t lb_number,
+ size_t block_count, unsigned char *data,
+ int encrypted )
+{
+ if( dvdcss_library ) {
+ int ret;
+
+ if( !device->dev ) {
+ fprintf( stderr, "libdvdread: Fatal error in block read.\n" );
+ return 0;
+ }
+
+ ret = dvdcss_seek( device->dev, (int) lb_number );
+ if( ret != (int) lb_number ) {
+ fprintf( stderr, "libdvdread: Can't seek to block %u\n",
+ lb_number );
+ return 0;
+ }
+
+ return (int64_t) ( dvdcss_read( device->dev, (char *) data,
+ (int) block_count, encrypted )
+ * (uint64_t) DVD_VIDEO_LB_LEN );
+ } else {
+ off64_t off;
+
+ if( device->fd < 0) {
+ fprintf( stderr, "libdvdread: Fatal error in block read.\n" );
+ return 0;
+ }
+
+ off = lseek64( device->fd, lb_number * (int64_t) DVD_VIDEO_LB_LEN,
+ SEEK_SET );
+ if( off != ( lb_number * (int64_t) DVD_VIDEO_LB_LEN ) ) {
+ fprintf( stderr, "libdvdread: Can't seek to block %u\n",
+ lb_number );
+ return 0;
+ }
+ return (int64_t) ( read( device->fd, data,
+ block_count * DVD_VIDEO_LB_LEN ) );
+ }
+}
+
+static int64_t DVDReadBlocksUDF( dvd_file_t *dvd_file, uint32_t offset,
+ size_t block_count, unsigned char *data )
+{
+ return DVDReadLBUDF( dvd_file->dvd, dvd_file->lb_start + offset,
+ block_count, data, DVDCSS_READ_DECRYPT );
+}
+
+static int64_t DVDReadBlocksPath( dvd_file_t *dvd_file, size_t offset,
+ size_t block_count, unsigned char *data )
+{
+ int i;
+ ssize_t ret, ret2;
+ off64_t off;
+
+ ret = 0;
+ ret2 = 0;
+ for( i = 0; i < 9; ++i ) {
+ if( !dvd_file->title_sizes[ i ] ) return 0;
+
+ if( offset < dvd_file->title_sizes[ i ] ) {
+ if( ( offset + block_count ) <= dvd_file->title_sizes[ i ] ) {
+ off = lseek64( dvd_file->title_fds[ i ],
+ offset * (int64_t) DVD_VIDEO_LB_LEN, SEEK_SET );
+ if( off != ( offset * (int64_t) DVD_VIDEO_LB_LEN ) ) {
+ fprintf( stderr, "libdvdread: Can't seek to block %d\n",
+ offset );
+ return 0;
+ }
+ ret = read( dvd_file->title_fds[ i ], data,
+ block_count * DVD_VIDEO_LB_LEN );
+ break;
+ } else {
+ size_t part1_size
+ = ( dvd_file->title_sizes[ i ] - offset ) * DVD_VIDEO_LB_LEN;
+ /* FIXME: Really needs to be a while loop.
+ (This is only true if you try and read >1GB at a time) */
+
+ /* Read part 1 */
+ off = lseek64( dvd_file->title_fds[ i ],
+ offset * (int64_t) DVD_VIDEO_LB_LEN, SEEK_SET );
+ if( off != ( offset * (int64_t) DVD_VIDEO_LB_LEN ) ) {
+ fprintf( stderr, "libdvdread: Can't seek to block %d\n",
+ offset );
+ return 0;
+ }
+ ret = read( dvd_file->title_fds[ i ], data, part1_size );
+ if( ret < 0 ) return ret;
+ /* FIXME: This is wrong if i is the last file in the set.
+ also error from this read will not show in ret. */
+
+ /* Read part 2 */
+ lseek64( dvd_file->title_fds[ i + 1 ], (off64_t)0, SEEK_SET );
+ ret2 = read( dvd_file->title_fds[ i + 1 ], data + part1_size,
+ block_count * DVD_VIDEO_LB_LEN - part1_size );
+ if( ret2 < 0 ) return ret2;
+ break;
+ }
+ } else {
+ offset -= dvd_file->title_sizes[ i ];
+ }
+ }
+
+ return ( (int64_t) ret + (int64_t) ret2 );
+}
+
+/* These are broken for some cases reading more than 2Gb at a time. */
+ssize_t DVDReadBlocks( dvd_file_t *dvd_file, int offset,
+ size_t block_count, unsigned char *data )
+{
+ int64_t ret;
+
+ if( dvd_file->dvd->isImageFile ) {
+ ret = DVDReadBlocksUDF( dvd_file, (uint32_t)offset,
+ block_count, data );
+ } else {
+ ret = DVDReadBlocksPath( dvd_file, (size_t) offset,
+ block_count, data );
+ }
+ if( ret <= 0 ) {
+ return (ssize_t) ret;
+ }
+ {
+ ssize_t sret = (ssize_t) (ret / (int64_t)DVD_VIDEO_LB_LEN );
+ if( sret == 0 ) {
+ fprintf(stderr, "libdvdread: DVDReadBlocks got %d bytes\n", (int)ret );
+ }
+ return sret;
+ }
+}
+
+int32_t DVDFileSeek( dvd_file_t *dvd_file, int32_t offset )
+{
+ if( dvd_file->dvd->isImageFile ) {
+ dvd_file->seek_pos = (uint32_t) offset;
+ return offset;
+ } else {
+ return (int32_t) ( lseek( dvd_file->title_fds[ 0 ],
+ (off_t) offset, SEEK_SET ) );
+ }
+}
+
+static ssize_t DVDReadBytesUDF( dvd_file_t *dvd_file, void *data,
+ size_t byte_size )
+{
+ unsigned char *secbuf;
+ unsigned int numsec, seek_sector, seek_byte;
+ int64_t len;
+
+ seek_sector = dvd_file->seek_pos / DVD_VIDEO_LB_LEN;
+ seek_byte = dvd_file->seek_pos % DVD_VIDEO_LB_LEN;
+
+ numsec = ( ( seek_byte + byte_size ) / DVD_VIDEO_LB_LEN ) + 1;
+ secbuf = (unsigned char *) malloc( numsec * DVD_VIDEO_LB_LEN );
+ if( !secbuf ) {
+ fprintf( stderr, "libdvdread: Can't allocate memory "
+ "for file read!\n" );
+ return 0;
+ }
+
+ len = DVDReadLBUDF( dvd_file->dvd, dvd_file->lb_start + seek_sector,
+ numsec, secbuf, DVDCSS_NOFLAGS );
+ if( len != numsec * (int64_t) DVD_VIDEO_LB_LEN ) {
+ free( secbuf );
+ return 0;
+ }
+
+ dvd_file->seek_pos += byte_size;
+
+ memcpy( data, &(secbuf[ seek_byte ]), byte_size );
+ free( secbuf );
+
+ return byte_size;
+}
+
+static ssize_t DVDReadBytesPath( dvd_file_t *dvd_file, void *data,
+ size_t byte_size )
+{
+ return read( dvd_file->title_fds[ 0 ], data, byte_size );
+}
+
+ssize_t DVDReadBytes( dvd_file_t *dvd_file, void *data, size_t byte_size )
+{
+ if( dvd_file->dvd->isImageFile ) {
+ return DVDReadBytesUDF( dvd_file, data, byte_size );
+ } else {
+ return DVDReadBytesPath( dvd_file, data, byte_size );
+ }
+}
+
+ssize_t DVDFileSize( dvd_file_t *dvd_file )
+{
+ return dvd_file->filesize;
+}
+
--- /dev/null
+/**
+ * Copyright (C) 2001 Billy Biggs <vektor@dumbterm.net>,
+ * Håkan Hjort <d95hjort@dtek.chalmers.se>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DVD_READER_H_INCLUDED
+#define DVD_READER_H_INCLUDED
+
+#include <sys/types.h>
+#include <inttypes.h>
+
+/**
+ * The length of one Logical Block of a DVD Video.
+ */
+#define DVD_VIDEO_LB_LEN 2048
+
+/**
+ * Maximum length of filenames for UDF.
+ */
+#define MAX_UDF_FILE_NAME_LEN 2048
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct dvd_reader_s dvd_reader_t;
+typedef struct dvd_file_s dvd_file_t;
+
+/**
+ * Opens a block device of a DVD-ROM file, or an image file, or a directory
+ * name for a mounted DVD or HD copy of a DVD. Returns 0 if we can't get any
+ * of those methods to work.
+ *
+ * If the given file is a block device, or is the mountpoint for a block
+ * device, then that device is used for CSS authentication using libdvdcss.
+ * If no device is available, then no CSS authentication is performed,
+ * and we hope that the image is decrypted.
+ *
+ * If the path given is a directory, then the files in that directory may be in
+ * any one of these formats:
+ *
+ * path/VIDEO_TS/VTS_01_1.VOB
+ * path/video_ts/vts_01_1.vob
+ * path/VTS_01_1.VOB
+ * path/vts_01_1.vob
+ */
+dvd_reader_t *DVDOpen( const char *path );
+
+/**
+ * Closes and cleans up the DVD reader object. You must close all open files
+ * before calling this function.
+ */
+void DVDClose( dvd_reader_t *dvd );
+
+/**
+ * INFO_FILE : VIDEO_TS.IFO (manager)
+ * VTS_XX_0.IFO (title)
+ *
+ * INFO_BACKUP_FILE: VIDEO_TS.BUP (manager)
+ * VTS_XX_0.BUP (title)
+ *
+ * MENU_VOBS : VIDEO_TS.VOB (manager)
+ * VTS_XX_0.VOB (title)
+ *
+ * TITLE_VOBS : VTS_XX_[1-9].VOB (title)
+ * All files in the title set are opened and read as a single
+ * file.
+ */
+typedef enum {
+ DVD_READ_INFO_FILE,
+ DVD_READ_INFO_BACKUP_FILE,
+ DVD_READ_MENU_VOBS,
+ DVD_READ_TITLE_VOBS
+} dvd_read_domain_t;
+
+/**
+ * Opens a file on the DVD given the title number and domain. If the title
+ * number is 0, the video manager information is opened
+ * (VIDEO_TS.[IFO,BUP,VOB]). Returns a file structure which may be used for
+ * reads, or 0 if the file was not found.
+ */
+dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum,
+ dvd_read_domain_t domain );
+
+/**
+ * Closes a file and frees the associated structure.
+ */
+void DVDCloseFile( dvd_file_t *dvd_file );
+
+/**
+ * Reads block_count number of blocks from the file at the given block offset.
+ * Returns number of blocks read on success, -1 on error. This call is only
+ * for reading VOB data, and should not be used when reading the IFO files.
+ * When reading from an encrypted drive, blocks are decrypted using libdvdcss
+ * where required.
+ */
+ssize_t DVDReadBlocks( dvd_file_t *dvd_file, int offset,
+ size_t block_count, unsigned char *data );
+
+/**
+ * Seek to the given position in the file. Returns the resulting position in
+ * bytes from the beginning of the file. The seek position is only used for
+ * byte reads from the file, the block read call always reads from the given
+ * offset.
+ */
+int DVDFileSeek( dvd_file_t *dvd_file, int offset );
+
+/**
+ * Reads the given number of bytes from the file. This call can only be used
+ * on the information files, and may not be used for reading from a VOB. This
+ * reads from and increments the currrent seek position for the file.
+ */
+ssize_t DVDReadBytes( dvd_file_t *dvd_file, void *data, size_t byte_size );
+
+/**
+ * Returns the file size in blocks.
+ */
+ssize_t DVDFileSize( dvd_file_t *dvd_file );
+
+#ifdef __cplusplus
+};
+#endif
+#endif /* DVD_READER_H_INCLUDED */
--- /dev/null
+/**
+ * This code is based on dvdudf by:
+ * Christian Wolff <scarabaeus@convergence.de>.
+ *
+ * Modifications by:
+ * Billy Biggs <vektor@dumbterm.net>.
+ *
+ * dvdudf: parse and read the UDF volume information of a DVD Video
+ * Copyright (C) 1999 Christian Wolff for convergence integrated media
+ * GmbH The author can be reached at scarabaeus@convergence.de, the
+ * project's page is at http://linuxtv.org/dvd/
+ *
+ * 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. Or, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "dvd_udf.h"
+
+extern int64_t DVDReadLBUDF( dvd_reader_t *device, uint32_t lb_number,
+ size_t block_count, unsigned char *data,
+ int encrypted );
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+struct Partition {
+ int valid;
+ char VolumeDesc[128];
+ uint16_t Flags;
+ uint16_t Number;
+ char Contents[32];
+ uint32_t AccessType;
+ uint32_t Start;
+ uint32_t Length;
+};
+
+struct AD {
+ uint32_t Location;
+ uint32_t Length;
+ uint8_t Flags;
+ uint16_t Partition;
+};
+
+/* For direct data access, LSB first */
+#define GETN1(p) ((uint8_t)data[p])
+#define GETN2(p) ((uint16_t)data[p] | ((uint16_t)data[(p) + 1] << 8))
+#define GETN3(p) ((uint32_t)data[p] | ((uint32_t)data[(p) + 1] << 8) \
+ | ((uint32_t)data[(p) + 2] << 16))
+#define GETN4(p) ((uint32_t)data[p] \
+ | ((uint32_t)data[(p) + 1] << 8) \
+ | ((uint32_t)data[(p) + 2] << 16) \
+ | ((uint32_t)data[(p) + 3] << 24))
+/* This is wrong with regard to endianess */
+#define GETN(p, n, target) memcpy(target, &data[p], n)
+
+static int Unicodedecode( uint8_t *data, int len, char *target )
+{
+ int p = 1, i = 0;
+
+ if( ( data[ 0 ] == 8 ) || ( data[ 0 ] == 16 ) ) do {
+ if( data[ 0 ] == 16 ) p++; /* Ignore MSB of unicode16 */
+ if( p < len ) {
+ target[ i++ ] = data[ p++ ];
+ }
+ } while( p < len );
+
+ target[ i ] = '\0';
+ return 0;
+}
+
+static int UDFDescriptor( uint8_t *data, uint16_t *TagID )
+{
+ *TagID = GETN2(0);
+ // TODO: check CRC 'n stuff
+ return 0;
+}
+
+static int UDFExtentAD( uint8_t *data, uint32_t *Length, uint32_t *Location )
+{
+ *Length = GETN4(0);
+ *Location = GETN4(4);
+ return 0;
+}
+
+static int UDFShortAD( uint8_t *data, struct AD *ad,
+ struct Partition *partition )
+{
+ ad->Length = GETN4(0);
+ ad->Flags = ad->Length >> 30;
+ ad->Length &= 0x3FFFFFFF;
+ ad->Location = GETN4(4);
+ ad->Partition = partition->Number; // use number of current partition
+ return 0;
+}
+
+static int UDFLongAD( uint8_t *data, struct AD *ad )
+{
+ ad->Length = GETN4(0);
+ ad->Flags = ad->Length >> 30;
+ ad->Length &= 0x3FFFFFFF;
+ ad->Location = GETN4(4);
+ ad->Partition = GETN2(8);
+ //GETN(10, 6, Use);
+ return 0;
+}
+
+static int UDFExtAD( uint8_t *data, struct AD *ad )
+{
+ ad->Length = GETN4(0);
+ ad->Flags = ad->Length >> 30;
+ ad->Length &= 0x3FFFFFFF;
+ ad->Location = GETN4(12);
+ ad->Partition = GETN2(16);
+ //GETN(10, 6, Use);
+ return 0;
+}
+
+static int UDFICB( uint8_t *data, uint8_t *FileType, uint16_t *Flags )
+{
+ *FileType = GETN1(11);
+ *Flags = GETN2(18);
+ return 0;
+}
+
+
+static int UDFPartition( uint8_t *data, uint16_t *Flags, uint16_t *Number,
+ char *Contents, uint32_t *Start, uint32_t *Length )
+{
+ *Flags = GETN2(20);
+ *Number = GETN2(22);
+ GETN(24, 32, Contents);
+ *Start = GETN4(188);
+ *Length = GETN4(192);
+ return 0;
+}
+
+/**
+ * Reads the volume descriptor and checks the parameters. Returns 0 on OK, 1
+ * on error.
+ */
+static int UDFLogVolume( uint8_t *data, char *VolumeDescriptor )
+{
+ uint32_t lbsize, MT_L, N_PM;
+ Unicodedecode(&data[84], 128, VolumeDescriptor);
+ lbsize = GETN4(212); // should be 2048
+ MT_L = GETN4(264); // should be 6
+ N_PM = GETN4(268); // should be 1
+ if (lbsize != DVD_VIDEO_LB_LEN) return 1;
+ return 0;
+}
+
+static int UDFFileEntry( uint8_t *data, uint8_t *FileType,
+ struct Partition *partition, struct AD *ad )
+{
+ uint16_t flags;
+ uint32_t L_EA, L_AD;
+ unsigned int p;
+
+ UDFICB( &data[ 16 ], FileType, &flags );
+
+ /* Init ad for an empty file (i.e. there isn't a AD, L_AD == 0 ) */
+ ad->Length = GETN4( 60 ); // Really 8 bytes a 56
+ ad->Flags = 0;
+ ad->Location = 0; // what should we put here?
+ ad->Partition = partition->Number; // use number of current partition
+
+ L_EA = GETN4( 168 );
+ L_AD = GETN4( 172 );
+ p = 176 + L_EA;
+ while( p < 176 + L_EA + L_AD ) {
+ switch( flags & 0x0007 ) {
+ case 0: UDFShortAD( &data[ p ], ad, partition ); p += 8; break;
+ case 1: UDFLongAD( &data[ p ], ad ); p += 16; break;
+ case 2: UDFExtAD( &data[ p ], ad ); p += 20; break;
+ case 3:
+ switch( L_AD ) {
+ case 8: UDFShortAD( &data[ p ], ad, partition ); break;
+ case 16: UDFLongAD( &data[ p ], ad ); break;
+ case 20: UDFExtAD( &data[ p ], ad ); break;
+ }
+ p += L_AD;
+ break;
+ default:
+ p += L_AD; break;
+ }
+ }
+ return 0;
+}
+
+static int UDFFileIdentifier( uint8_t *data, uint8_t *FileCharacteristics,
+ char *FileName, struct AD *FileICB )
+{
+ uint8_t L_FI;
+ uint16_t L_IU;
+
+ *FileCharacteristics = GETN1(18);
+ L_FI = GETN1(19);
+ UDFLongAD(&data[20], FileICB);
+ L_IU = GETN2(36);
+ if (L_FI) Unicodedecode(&data[38 + L_IU], L_FI, FileName);
+ else FileName[0] = '\0';
+ return 4 * ((38 + L_FI + L_IU + 3) / 4);
+}
+
+/**
+ * Maps ICB to FileAD
+ * ICB: Location of ICB of directory to scan
+ * FileType: Type of the file
+ * File: Location of file the ICB is pointing to
+ * return 1 on success, 0 on error;
+ */
+static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType,
+ struct Partition *partition, struct AD *File )
+{
+ uint8_t LogBlock[DVD_VIDEO_LB_LEN];
+ uint32_t lbnum;
+ uint16_t TagID;
+
+ lbnum = partition->Start + ICB.Location;
+ do {
+ if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) {
+ TagID = 0;
+ } else {
+ UDFDescriptor( LogBlock, &TagID );
+ }
+
+ if( TagID == 261 ) {
+ UDFFileEntry( LogBlock, FileType, partition, File );
+ return 1;
+ };
+ } while( ( lbnum <= partition->Start + ICB.Location + ( ICB.Length - 1 )
+ / DVD_VIDEO_LB_LEN ) && ( TagID != 261 ) );
+
+ return 0;
+}
+
+/**
+ * Dir: Location of directory to scan
+ * FileName: Name of file to look for
+ * FileICB: Location of ICB of the found file
+ * return 1 on success, 0 on error;
+ */
+static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName,
+ struct Partition *partition, struct AD *FileICB )
+{
+ char filename[ MAX_UDF_FILE_NAME_LEN ];
+ uint8_t directory[ 2 * DVD_VIDEO_LB_LEN ];
+ uint32_t lbnum;
+ uint16_t TagID;
+ uint8_t filechar;
+ unsigned int p;
+
+ /* Scan dir for ICB of file */
+ lbnum = partition->Start + Dir.Location;
+
+ if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) {
+ return 0;
+ }
+
+ p = 0;
+ while( p < Dir.Length ) {
+ if( p > DVD_VIDEO_LB_LEN ) {
+ ++lbnum;
+ p -= DVD_VIDEO_LB_LEN;
+ Dir.Length -= DVD_VIDEO_LB_LEN;
+ if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) {
+ return 0;
+ }
+ }
+ UDFDescriptor( &directory[ p ], &TagID );
+ if( TagID == 257 ) {
+ p += UDFFileIdentifier( &directory[ p ], &filechar,
+ filename, FileICB );
+ if( !strcasecmp( FileName, filename ) ) {
+ return 1;
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Looks for partition on the disc. Returns 1 if partition found, 0 on error.
+ * partnum: Number of the partition, starting at 0.
+ * part: structure to fill with the partition information
+ */
+static int UDFFindPartition( dvd_reader_t *device, int partnum,
+ struct Partition *part )
+{
+ uint8_t LogBlock[ DVD_VIDEO_LB_LEN ], Anchor[ DVD_VIDEO_LB_LEN ];
+ uint32_t lbnum, MVDS_location, MVDS_length;
+ uint16_t TagID;
+ uint32_t lastsector;
+ int i, terminate, volvalid;
+
+ /* Find Anchor */
+ lastsector = 0;
+ lbnum = 256; /* Try #1, prime anchor */
+ terminate = 0;
+
+ for(;;) {
+ if( DVDReadLBUDF( device, lbnum, 1, Anchor, 0 ) > 0 ) {
+ UDFDescriptor( Anchor, &TagID );
+ } else {
+ TagID = 0;
+ }
+ if (TagID != 2) {
+ /* Not an anchor */
+ if( terminate ) return 0; /* Final try failed */
+
+ if( lastsector ) {
+
+ /* We already found the last sector. Try #3, alternative
+ * backup anchor. If that fails, don't try again.
+ */
+ lbnum = lastsector;
+ terminate = 1;
+ } else {
+ /* TODO: Find last sector of the disc (this is optional). */
+ if( lastsector ) {
+ /* Try #2, backup anchor */
+ lbnum = lastsector - 256;
+ } else {
+ /* Unable to find last sector */
+ return 0;
+ }
+ }
+ } else {
+ /* It's an anchor! We can leave */
+ break;
+ }
+ }
+ /* Main volume descriptor */
+ UDFExtentAD( &Anchor[ 16 ], &MVDS_length, &MVDS_location );
+
+ part->valid = 0;
+ volvalid = 0;
+ part->VolumeDesc[ 0 ] = '\0';
+ i = 1;
+ do {
+ /* Find Volume Descriptor */
+ lbnum = MVDS_location;
+ do {
+
+ if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) {
+ TagID = 0;
+ } else {
+ UDFDescriptor( LogBlock, &TagID );
+ }
+
+ if( ( TagID == 5 ) && ( !part->valid ) ) {
+ /* Partition Descriptor */
+ UDFPartition( LogBlock, &part->Flags, &part->Number,
+ part->Contents, &part->Start, &part->Length );
+ part->valid = ( partnum == part->Number );
+ } else if( ( TagID == 6 ) && ( !volvalid ) ) {
+ /* Logical Volume Descriptor */
+ if( UDFLogVolume( LogBlock, part->VolumeDesc ) ) {
+ /* TODO: sector size wrong! */
+ } else {
+ volvalid = 1;
+ }
+ }
+
+ } while( ( lbnum <= MVDS_location + ( MVDS_length - 1 )
+ / DVD_VIDEO_LB_LEN ) && ( TagID != 8 )
+ && ( ( !part->valid ) || ( !volvalid ) ) );
+
+ if( ( !part->valid) || ( !volvalid ) ) {
+ /* Backup volume descriptor */
+ UDFExtentAD( &Anchor[ 24 ], &MVDS_length, &MVDS_location );
+ }
+ } while( i-- && ( ( !part->valid ) || ( !volvalid ) ) );
+
+ /* We only care for the partition, not the volume */
+ return part->valid;
+}
+
+uint32_t UDFFindFile( dvd_reader_t *device, char *filename,
+ uint32_t *filesize )
+{
+ uint8_t LogBlock[ DVD_VIDEO_LB_LEN ];
+ uint32_t lbnum;
+ uint16_t TagID;
+ struct Partition partition;
+ struct AD RootICB, File, ICB;
+ char tokenline[ MAX_UDF_FILE_NAME_LEN ];
+ char *token;
+ uint8_t filetype;
+
+ *filesize = 0;
+ tokenline[0] = '\0';
+ strcat( tokenline, filename );
+
+ /* Find partition, 0 is the standard location for DVD Video.*/
+ if( !UDFFindPartition( device, 0, &partition ) ) return 0;
+
+ /* Find root dir ICB */
+ lbnum = partition.Start;
+ do {
+ if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) {
+ TagID = 0;
+ } else {
+ UDFDescriptor( LogBlock, &TagID );
+ }
+
+ /* File Set Descriptor */
+ if( TagID == 256 ) { // File Set Descriptor
+ UDFLongAD( &LogBlock[ 400 ], &RootICB );
+ }
+ } while( ( lbnum < partition.Start + partition.Length )
+ && ( TagID != 8 ) && ( TagID != 256 ) );
+
+ /* Sanity checks. */
+ if( TagID != 256 ) return 0;
+ if( RootICB.Partition != 0 ) return 0;
+
+ /* Find root dir */
+ if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) ) return 0;
+ if( filetype != 4 ) return 0; /* Root dir should be dir */
+
+ /* Tokenize filepath */
+ token = strtok(tokenline, "/");
+ while( token != NULL ) {
+ if( !UDFScanDir( device, File, token, &partition, &ICB ) ) return 0;
+ if( !UDFMapICB( device, ICB, &filetype, &partition, &File ) ) return 0;
+ token = strtok( NULL, "/" );
+ }
+
+ /* Sanity check. */
+ if( File.Partition != 0 ) return 0;
+
+ *filesize = File.Length;
+ /* Hack to not return partition.Start for empty files. */
+ if( !File.Location )
+ return 0;
+ else
+ return partition.Start + File.Location;
+}
--- /dev/null
+/**
+ * This code is based on dvdudf by:
+ * Christian Wolff <scarabaeus@convergence.de>.
+ *
+ * Modifications by:
+ * Billy Biggs <vektor@dumbterm.net>.
+ *
+ * dvdudf: parse and read the UDF volume information of a DVD Video
+ * Copyright (C) 1999 Christian Wolff for convergence integrated media
+ * GmbH The author can be reached at scarabaeus@convergence.de, the
+ * project's page is at http://linuxtv.org/dvd/
+ *
+ * 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. Or, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef DVD_UDF_H_INCLUDED
+#define DVD_UDF_H_INCLUDED
+
+#include "dvd_reader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Looks for a file on the UDF disc/imagefile and returns the block number
+ * where it begins, or 0 if it is not found. The filename should be an
+ * absolute pathname on the UDF filesystem, starting with '/'. For example,
+ * '/VIDEO_TS/VTS_01_1.IFO'. On success, filesize will be set to the size of
+ * the file in bytes.
+ */
+uint32_t UDFFindFile( dvd_reader_t *device, char *filename, uint32_t *size );
+
+#ifdef __cplusplus
+};
+#endif
+#endif /* DVD_UDF_H_INCLUDED */
--- /dev/null
+/*****************************************************************************
+ * libdvdcss.h: DVD reading library, exported functions.
+ *****************************************************************************
+ * Copyright (C) 1998-2001 VideoLAN
+ * $Id: dvdcss.h,v 1.1 2001/11/25 05:04:38 stef Exp $
+ *
+ * Authors: Stéphane Borel <stef@via.ecp.fr>
+ * Samuel Hocevar <sam@zoy.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, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * The libdvdcss structure
+ *****************************************************************************/
+typedef struct dvdcss_s* dvdcss_handle;
+
+/*****************************************************************************
+ * Flags
+ *****************************************************************************/
+#define DVDCSS_NOFLAGS 0
+
+#define DVDCSS_INIT_QUIET (1 << 0)
+#define DVDCSS_INIT_DEBUG (1 << 1)
+
+#define DVDCSS_READ_DECRYPT (1 << 0)
+
+#define DVDCSS_BLOCK_SIZE 2048
+
--- /dev/null
+/*****************************************************************************
+ * dvdread.c: replacement for dvd_reader.c that always takes dvdcss functions
+ * (hard-linked) and adds a readv call function to tha API.
+ *****************************************************************************
+ * Copyright (C) 2001 Billy Biggs <vektor@dumbterm.net>.
+ * $Id: dvdread.c,v 1.1 2001/11/25 05:04:38 stef Exp $
+ *
+ * Author: Billy Biggs <vektor@dumbterm.net>
+ * Stéphane Borel <stef@via.ecp.fr>
+ *
+ * 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, USA.
+ *****************************************************************************/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/uio.h> /* readv() */
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <dlfcn.h>
+#include <dirent.h>
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__)
+#define SYS_BSD 1
+#endif
+
+#if defined(__sun)
+#include <sys/mnttab.h>
+#elif defined(SYS_BSD)
+#include <fstab.h>
+#elif defined(__linux__)
+#include <mntent.h>
+#endif
+
+#if defined(SYS_BSD)
+typedef off_t off64_t;
+#define lseek64 lseek
+#define stat64 stat
+#endif
+
+#include "dvd_udf.h"
+#include "dvd_reader.h"
+
+#include "../libdvdcss/videolan/dvdcss.h"
+
+struct dvd_reader_s {
+ /* Basic information. */
+ int isImageFile;
+
+ /* Information required for an image file. */
+ dvdcss_handle dev;
+ int init_keys;
+ int fd;
+
+ /* Information required for a directory path drive. */
+ char *path_root;
+};
+
+struct dvd_file_s {
+ /* Basic information. */
+ dvd_reader_t *dvd;
+
+ /* Information required for an image file. */
+ uint32_t lb_start;
+ uint32_t seek_pos;
+
+ /* Information required for a directory path drive. */
+ size_t title_sizes[ 9 ];
+ int title_fds[ 9 ];
+
+ /* Calculated at open-time, size in blocks. */
+ ssize_t filesize;
+};
+
+/**
+ * Open a DVD image or block device file.
+ */
+static dvd_reader_t *DVDOpenImageFile( const char *location )
+{
+ dvd_reader_t *dvd;
+ dvdcss_handle dev = 0;
+ int fd = -1;
+
+ dev = dvdcss_open( (char *) location );
+ if( !dev ) {
+ fprintf( stderr, "libdvdread: Can't open %s for reading.\n",
+ location );
+ return 0;
+ }
+
+ dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) );
+ if( !dvd ) return 0;
+ dvd->isImageFile = 1;
+ dvd->dev = dev;
+ dvd->init_keys = 0;
+ dvd->fd = fd;
+ dvd->path_root = 0;
+
+ return dvd;
+}
+
+static dvd_reader_t *DVDOpenPath( const char *path_root )
+{
+ dvd_reader_t *dvd;
+
+ dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) );
+ if( !dvd ) return 0;
+ dvd->isImageFile = 0;
+ dvd->dev = 0;
+ dvd->init_keys = 0;
+ dvd->fd = -1;
+ dvd->path_root = strdup( path_root );
+
+ return dvd;
+}
+
+#if defined(__sun)
+/* /dev/rdsk/c0t6d0s0 (link to /devices/...)
+ /vol/dev/rdsk/c0t6d0/??
+ /vol/rdsk/<name> */
+static char *sun_block2char( const char *path )
+{
+ char *new_path;
+
+ /* Must contain "/dsk/" */
+ if( !strstr( path, "/dsk/" ) ) return (char *) strdup( path );
+
+ /* Replace "/dsk/" with "/rdsk/" */
+ new_path = malloc( strlen(path) + 2 );
+ strcpy( new_path, path );
+ strcpy( strstr( new_path, "/dsk/" ), "" );
+ strcat( new_path, "/rdsk/" );
+ strcat( new_path, strstr( path, "/dsk/" ) + strlen( "/dsk/" ) );
+
+ return new_path;
+}
+#endif
+
+#if defined(SYS_BSD)
+/* FreeBSD /dev/(r)(a)cd0 (a is for atapi, should work without r)
+ OpenBSD /dev/rcd0c
+ NetBSD /dev/rcd0d or /dev/rcd0c (for non x86)
+ BSD/OS /dev/sr0 (if not mounted) or /dev/rsr0 */
+static char *bsd_block2char( const char *path )
+{
+ char *new_path;
+
+ /* If it doesn't start with "/dev/" or does start with "/dev/r" exit */
+ if( !strncmp( path, "/dev/", 5 ) || strncmp( path, "/dev/r", 6 ) )
+ return (char *) strdup( path );
+
+ /* Replace "/dev/" with "/dev/r" */
+ new_path = malloc( strlen(path) + 2 );
+ strcpy( new_path, "/dev/r" );
+ strcat( new_path, path + strlen( "/dev/" ) );
+
+ return new_path;
+}
+#endif
+
+dvd_reader_t *DVDOpen( const char *path )
+{
+ struct stat64 fileinfo;
+ int ret;
+
+ if( !path ) return 0;
+
+ ret = stat64( path, &fileinfo );
+ if( ret < 0 ) {
+ /* If we can't stat the file, give up */
+ fprintf( stderr, "libdvdread: Can't stat %s\n", path );
+ perror("");
+ return 0;
+ }
+
+ /* First check if this is a block/char device or a file*/
+ if( S_ISBLK( fileinfo.st_mode ) ||
+ S_ISCHR( fileinfo.st_mode ) ||
+ S_ISREG( fileinfo.st_mode ) ) {
+
+ /**
+ * Block devices and regular files are assumed to be DVD-Video images.
+ */
+#if defined(__sun)
+ return DVDOpenImageFile( sun_block2char( path ) );
+#elif defined(SYS_BSD)
+ return DVDOpenImageFile( bsd_block2char( path ) );
+#else
+ return DVDOpenImageFile( path );
+#endif
+
+ } else if( S_ISDIR( fileinfo.st_mode ) ) {
+ dvd_reader_t *auth_drive = 0;
+ char *path_copy;
+#if defined(SYS_BSD)
+ struct fstab* fe;
+#elif defined(__sun) || defined(__linux__)
+ FILE *mntfile;
+#endif
+
+ /* XXX: We should scream real loud here. */
+ if( !(path_copy = strdup( path ) ) ) return 0;
+
+ /* Resolve any symlinks and get the absolut dir name. */
+ {
+ char *new_path;
+ int cdir = open( ".", O_RDONLY );
+
+ if( cdir >= 0 ) {
+ chdir( path_copy );
+ new_path = getcwd( NULL, PATH_MAX );
+ fchdir( cdir );
+ close( cdir );
+ if( new_path ) {
+ free( path_copy );
+ path_copy = new_path;
+ }
+ }
+ }
+
+ /**
+ * If we're being asked to open a directory, check if that directory
+ * is the mountpoint for a DVD-ROM which we can use instead.
+ */
+
+ if( strlen( path_copy ) > 1 ) {
+ if( path[ strlen( path_copy ) - 1 ] == '/' )
+ path_copy[ strlen( path_copy ) - 1 ] = '\0';
+ }
+
+ if( strlen( path_copy ) > 9 ) {
+ if( !strcasecmp( &(path_copy[ strlen( path_copy ) - 9 ]),
+ "/video_ts" ) ) {
+ path_copy[ strlen( path_copy ) - 9 ] = '\0';
+ }
+ }
+
+#if defined(SYS_BSD)
+ if( ( fe = getfsfile( path_copy ) ) ) {
+ char *dev_name = bsd_block2char( fe->fs_spec );
+ fprintf( stderr,
+ "libdvdread: Attempting to use device %s"
+ " mounted on %s for CSS authentication\n",
+ dev_name,
+ fe->fs_file );
+ auth_drive = DVDOpenImageFile( dev_name );
+ free( dev_name );
+ }
+#elif defined(__sun)
+ mntfile = fopen( MNTTAB, "r" );
+ if( mntfile ) {
+ struct mnttab mp;
+ int res;
+
+ while( ( res = getmntent( mntfile, &mp ) ) != -1 ) {
+ if( res == 0 && !strcmp( mp.mnt_mountp, path_copy ) ) {
+ char *dev_name = sun_block2char( mp.mnt_special );
+ fprintf( stderr,
+ "libdvdread: Attempting to use device %s"
+ " mounted on %s for CSS authentication\n",
+ dev_name,
+ mp.mnt_mountp );
+ auth_drive = DVDOpenImageFile( dev_name );
+ free( dev_name );
+ break;
+ }
+ }
+ fclose( mntfile );
+ }
+#elif defined(__linux__)
+ mntfile = fopen( MOUNTED, "r" );
+ if( mntfile ) {
+ struct mntent *me;
+
+ while( ( me = getmntent( mntfile ) ) ) {
+ if( !strcmp( me->mnt_dir, path_copy ) ) {
+ fprintf( stderr,
+ "libdvdread: Attempting to use device %s"
+ " mounted on %s for CSS authentication\n",
+ me->mnt_fsname,
+ me->mnt_dir );
+ auth_drive = DVDOpenImageFile( me->mnt_fsname );
+ break;
+ }
+ }
+ fclose( mntfile );
+ }
+#endif
+ if( !auth_drive ) {
+ fprintf( stderr, "libdvdread: Device inaccessible, "
+ "CSS authentication not available.\n" );
+ }
+
+ free( path_copy );
+
+ /**
+ * If we've opened a drive, just use that.
+ */
+ if( auth_drive ) return auth_drive;
+
+ /**
+ * Otherwise, we now try to open the directory tree instead.
+ */
+ fprintf( stderr, "libdvdread: Using normal filesystem access.\n" );
+ return DVDOpenPath( path );
+ }
+
+ /* If it's none of the above, screw it. */
+ fprintf( stderr, "libdvdread: Could not open %s\n", path );
+ return 0;
+}
+
+void DVDClose( dvd_reader_t *dvd )
+{
+ if( dvd ) {
+ if( dvd->dev ) dvdcss_close( dvd->dev );
+ if( dvd->fd >= 0 ) close( dvd->fd );
+ if( dvd->path_root ) free( dvd->path_root );
+ free( dvd );
+ dvd = 0;
+ }
+}
+
+/**
+ * Open an unencrypted file on a DVD image file.
+ */
+static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *dvd, char *filename )
+{
+ uint32_t start, len;
+ dvd_file_t *dvd_file;
+
+ start = UDFFindFile( dvd, filename, &len );
+ if( !start ) return 0;
+
+ dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
+ if( !dvd_file ) return 0;
+ dvd_file->dvd = dvd;
+ dvd_file->lb_start = start;
+ dvd_file->seek_pos = 0;
+ memset( dvd_file->title_fds, -1, sizeof( dvd_file->title_fds ) );
+ dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
+
+ return dvd_file;
+}
+
+/**
+ * Searches for <file> in directory <path>, ignoring case.
+ * Returns 0 and full filename in <filename>.
+ * or -1 on file not found.
+ * or -2 on path not found.
+ */
+static int findDirFile( const char *path, const char *file, char *filename )
+{
+ DIR *dir;
+ struct dirent *ent;
+
+ dir = opendir( path );
+ if( !dir ) return -2;
+
+ while( ( ent = readdir( dir ) ) != NULL ) {
+ if( !strcasecmp( ent->d_name, file ) ) {
+ sprintf( filename, "%s%s%s", path,
+ ( ( path[ strlen( path ) - 1 ] == '/' ) ? "" : "/" ),
+ ent->d_name );
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static int findDVDFile( dvd_reader_t *dvd, const char *file, char *filename )
+{
+ char video_path[ PATH_MAX + 1 ];
+ const char *nodirfile;
+ int ret;
+
+ /* Strip off the directory for our search */
+ if( !strncasecmp( "/VIDEO_TS/", file, 10 ) ) {
+ nodirfile = &(file[ 10 ]);
+ } else {
+ nodirfile = file;
+ }
+
+ ret = findDirFile( dvd->path_root, nodirfile, filename );
+ if( ret < 0 ) {
+ /* Try also with adding the path, just in case. */
+ sprintf( video_path, "%s/VIDEO_TS/", dvd->path_root );
+ ret = findDirFile( video_path, nodirfile, filename );
+ if( ret < 0 ) {
+ /* Try with the path, but in lower case. */
+ sprintf( video_path, "%s/video_ts/", dvd->path_root );
+ ret = findDirFile( video_path, nodirfile, filename );
+ if( ret < 0 ) {
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+/**
+ * Open an unencrypted file from a DVD directory tree.
+ */
+static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, char *filename )
+{
+ char full_path[ PATH_MAX + 1 ];
+ dvd_file_t *dvd_file;
+ struct stat fileinfo;
+ int fd;
+
+ /* Get the full path of the file. */
+ if( !findDVDFile( dvd, filename, full_path ) ) return 0;
+
+ fd = open( full_path, O_RDONLY );
+ if( fd < 0 ) return 0;
+
+ dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
+ if( !dvd_file ) return 0;
+ dvd_file->dvd = dvd;
+ dvd_file->lb_start = 0;
+ dvd_file->seek_pos = 0;
+ memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
+ memset( dvd_file->title_fds, -1, sizeof( dvd_file->title_fds ) );
+ dvd_file->filesize = 0;
+
+ if( stat( full_path, &fileinfo ) < 0 ) {
+ fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
+ free( dvd_file );
+ return 0;
+ }
+ dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
+ dvd_file->title_fds[ 0 ] = fd;
+ dvd_file->filesize = dvd_file->title_sizes[ 0 ];
+
+ return dvd_file;
+}
+
+static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *dvd,
+ int title, int menu )
+{
+ char filename[ MAX_UDF_FILE_NAME_LEN ];
+ uint32_t start, len;
+ dvd_file_t *dvd_file;
+
+ if( title == 0 ) {
+ sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" );
+ } else {
+ sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, menu ? 0 : 1 );
+ }
+ start = UDFFindFile( dvd, filename, &len );
+ if( start == 0 ) return 0;
+
+ dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
+ if( !dvd_file ) return 0;
+ dvd_file->dvd = dvd;
+ dvd_file->lb_start = start;
+ dvd_file->seek_pos = 0;
+ memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
+ memset( dvd_file->title_fds, -1, sizeof( dvd_file->title_fds ) );
+ dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
+
+ /* Calculate the complete file size for every file in the VOBS */
+ if( !menu ) {
+ int cur;
+
+ for( cur = 2; cur < 10; cur++ ) {
+ sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, cur );
+ if( !UDFFindFile( dvd, filename, &len ) ) break;
+ dvd_file->filesize += len / DVD_VIDEO_LB_LEN;
+ }
+ }
+
+ if( dvdcss_seek( dvd_file->dvd->dev, (int)start, DVDCSS_SEEK_KEY ) < 0 ) {
+ fprintf( stderr, "libdvdread: Error cracking CSS key for %s\n",
+ filename );
+ }
+
+ return dvd_file;
+}
+
+static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd,
+ int title, int menu )
+{
+ char filename[ MAX_UDF_FILE_NAME_LEN ];
+ char full_path[ PATH_MAX + 1 ];
+ struct stat fileinfo;
+ dvd_file_t *dvd_file;
+ int i;
+
+ dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
+ if( !dvd_file ) return 0;
+ dvd_file->dvd = dvd;
+ dvd_file->lb_start = 0;
+ dvd_file->seek_pos = 0;
+ memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
+ memset( dvd_file->title_fds, -1, sizeof( dvd_file->title_fds ) );
+ dvd_file->filesize = 0;
+
+ if( menu ) {
+ int fd;
+
+ if( title == 0 ) {
+ sprintf( filename, "VIDEO_TS.VOB" );
+ } else {
+ sprintf( filename, "VTS_%02i_0.VOB", title );
+ }
+ if( !findDVDFile( dvd, filename, full_path ) ) {
+ free( dvd_file );
+ return 0;
+ }
+
+ fd = open( full_path, O_RDONLY );
+ if( fd < 0 ) {
+ free( dvd_file );
+ return 0;
+ }
+
+ if( stat( full_path, &fileinfo ) < 0 ) {
+ fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
+ free( dvd_file );
+ return 0;
+ }
+ dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
+ dvd_file->title_fds[ 0 ] = fd;
+ dvd_file->filesize = dvd_file->title_sizes[ 0 ];
+
+ } else {
+ for( i = 0; i < 9; ++i ) {
+
+ sprintf( filename, "VTS_%02i_%i.VOB", title, i + 1 );
+ if( !findDVDFile( dvd, filename, full_path ) ) {
+ break;
+ }
+
+ if( stat( full_path, &fileinfo ) < 0 ) {
+ fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
+ break;
+ }
+
+ dvd_file->title_sizes[ i ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
+ dvd_file->title_fds[ i ] = open( full_path, O_RDONLY );
+ dvd_file->filesize += dvd_file->title_sizes[ i ];
+ }
+ if( !(dvd_file->title_sizes[ 0 ]) ) {
+ free( dvd_file );
+ return 0;
+ }
+ }
+
+ return dvd_file;
+}
+
+dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum,
+ dvd_read_domain_t domain )
+{
+ char filename[ MAX_UDF_FILE_NAME_LEN ];
+
+ switch( domain ) {
+ case DVD_READ_INFO_FILE:
+ if( titlenum == 0 ) {
+ sprintf( filename, "/VIDEO_TS/VIDEO_TS.IFO" );
+ } else {
+ sprintf( filename, "/VIDEO_TS/VTS_%02i_0.IFO", titlenum );
+ }
+ break;
+ case DVD_READ_INFO_BACKUP_FILE:
+ if( titlenum == 0 ) {
+ sprintf( filename, "/VIDEO_TS/VIDEO_TS.BUP" );
+ } else {
+ sprintf( filename, "/VIDEO_TS/VTS_%02i_0.BUP", titlenum );
+ }
+ break;
+ case DVD_READ_MENU_VOBS:
+ if( dvd->isImageFile ) {
+ return DVDOpenVOBUDF( dvd, titlenum, 1 );
+ } else {
+ return DVDOpenVOBPath( dvd, titlenum, 1 );
+ }
+ break;
+ case DVD_READ_TITLE_VOBS:
+ if( titlenum == 0 ) return 0;
+ if( dvd->isImageFile ) {
+ return DVDOpenVOBUDF( dvd, titlenum, 0 );
+ } else {
+ return DVDOpenVOBPath( dvd, titlenum, 0 );
+ }
+ break;
+ default:
+ fprintf( stderr, "libdvdread: Invalid domain for file open.\n" );
+ return 0;
+ }
+
+ if( dvd->isImageFile ) {
+ return DVDOpenFileUDF( dvd, filename );
+ } else {
+ return DVDOpenFilePath( dvd, filename );
+ }
+}
+
+void DVDCloseFile( dvd_file_t *dvd_file )
+{
+ int i;
+
+ if( dvd_file ) {
+ if( !dvd_file->dvd->isImageFile ) {
+ for( i = 0; i < 9; ++i ) {
+ if( dvd_file->title_fds[ i ] >= 0 )
+ close( dvd_file->title_fds[ i ] );
+ }
+ }
+
+ free( dvd_file );
+ dvd_file = 0;
+ }
+}
+
+int64_t DVDReadLBUDF( dvd_reader_t *device, uint32_t lb_number,
+ size_t block_count, unsigned char *data,
+ int encrypted )
+{
+ int ret;
+
+ if( !device->dev ) {
+ fprintf( stderr, "libdvdread: Fatal error in block read.\n" );
+ return 0;
+ }
+
+ ret = dvdcss_seek( device->dev, (int) lb_number, DVDCSS_NOFLAGS );
+ if( ret != (int) lb_number ) {
+ fprintf( stderr, "libdvdread: Can't seek to block %u\n",
+ lb_number );
+ return 0;
+ }
+
+ return (int64_t) ( dvdcss_read( device->dev, (char *) data,
+ (int) block_count, encrypted )
+ * (uint64_t) DVD_VIDEO_LB_LEN );
+}
+
+static int64_t DVDReadBlocksUDF( dvd_file_t *dvd_file, uint32_t offset,
+ size_t block_count, unsigned char *data )
+{
+ return DVDReadLBUDF( dvd_file->dvd, dvd_file->lb_start + offset,
+ block_count, data, DVDCSS_READ_DECRYPT );
+}
+
+static int64_t DVDReadBlocksPath( dvd_file_t *dvd_file, size_t offset,
+ size_t block_count, unsigned char *data )
+{
+ int i;
+ ssize_t ret, ret2;
+ off64_t off;
+
+ ret = 0;
+ ret2 = 0;
+ for( i = 0; i < 9; ++i ) {
+ if( !dvd_file->title_sizes[ i ] ) return 0;
+
+ if( offset < dvd_file->title_sizes[ i ] ) {
+ if( ( offset + block_count ) <= dvd_file->title_sizes[ i ] ) {
+ off = lseek64( dvd_file->title_fds[ i ],
+ offset * (int64_t) DVD_VIDEO_LB_LEN, SEEK_SET );
+ if( off != ( offset * (int64_t) DVD_VIDEO_LB_LEN ) ) {
+ fprintf( stderr, "libdvdread: Can't seek to block %d\n",
+ offset );
+ return 0;
+ }
+ ret = read( dvd_file->title_fds[ i ], data,
+ block_count * DVD_VIDEO_LB_LEN );
+ break;
+ } else {
+ size_t part1_size
+ = ( dvd_file->title_sizes[ i ] - offset ) * DVD_VIDEO_LB_LEN;
+ /* FIXME: Really needs to be a while loop.
+ (This is only true if you try and read >1GB at a time) */
+
+ /* Read part 1 */
+ off = lseek64( dvd_file->title_fds[ i ],
+ offset * (int64_t) DVD_VIDEO_LB_LEN, SEEK_SET );
+ if( off != ( offset * (int64_t) DVD_VIDEO_LB_LEN ) ) {
+ fprintf( stderr, "libdvdread: Can't seek to block %d\n",
+ offset );
+ return 0;
+ }
+ ret = read( dvd_file->title_fds[ i ], data, part1_size );
+ if( ret < 0 ) return ret;
+ /* FIXME: This is wrong if i is the last file in the set.
+ also error from this read will not show in ret. */
+
+ /* Read part 2 */
+ lseek64( dvd_file->title_fds[ i + 1 ], (off64_t)0, SEEK_SET );
+ ret2 = read( dvd_file->title_fds[ i + 1 ], data + part1_size,
+ block_count * DVD_VIDEO_LB_LEN - part1_size );
+ if( ret2 < 0 ) return ret2;
+ break;
+ }
+ } else {
+ offset -= dvd_file->title_sizes[ i ];
+ }
+ }
+
+ return ( (int64_t) ret + (int64_t) ret2 );
+}
+
+/* These are broken for some cases reading more than 2Gb at a time. */
+ssize_t DVDReadBlocks( dvd_file_t *dvd_file, int offset,
+ size_t block_count, unsigned char *data )
+{
+ int64_t ret;
+
+ if( dvd_file->dvd->isImageFile ) {
+ ret = DVDReadBlocksUDF( dvd_file, (uint32_t)offset,
+ block_count, data );
+ } else {
+ ret = DVDReadBlocksPath( dvd_file, (size_t) offset,
+ block_count, data );
+ }
+ if( ret <= 0 ) {
+ return (ssize_t) ret;
+ }
+ {
+ ssize_t sret = (ssize_t) (ret / (int64_t)DVD_VIDEO_LB_LEN );
+ if( sret == 0 ) {
+ fprintf(stderr, "libdvdread: DVDReadBlocks got %d bytes\n", (int)ret );
+ }
+ return sret;
+ }
+}
+
+int32_t DVDFileSeek( dvd_file_t *dvd_file, int32_t offset )
+{
+ if( dvd_file->dvd->isImageFile ) {
+ dvd_file->seek_pos = (uint32_t) offset;
+ return offset;
+ } else {
+ return (int32_t) ( lseek( dvd_file->title_fds[ 0 ],
+ (off_t) offset, SEEK_SET ) );
+ }
+}
+
+static ssize_t DVDReadBytesUDF( dvd_file_t *dvd_file, void *data,
+ size_t byte_size )
+{
+ unsigned char *secbuf;
+ unsigned int numsec, seek_sector, seek_byte;
+ int64_t len;
+
+ seek_sector = dvd_file->seek_pos / DVD_VIDEO_LB_LEN;
+ seek_byte = dvd_file->seek_pos % DVD_VIDEO_LB_LEN;
+
+ numsec = ( ( seek_byte + byte_size ) / DVD_VIDEO_LB_LEN ) + 1;
+ secbuf = (unsigned char *) malloc( numsec * DVD_VIDEO_LB_LEN );
+ if( !secbuf ) {
+ fprintf( stderr, "libdvdread: Can't allocate memory "
+ "for file read!\n" );
+ return 0;
+ }
+
+ len = DVDReadLBUDF( dvd_file->dvd, dvd_file->lb_start + seek_sector,
+ numsec, secbuf, DVDCSS_NOFLAGS );
+ if( len != numsec * (int64_t) DVD_VIDEO_LB_LEN ) {
+ free( secbuf );
+ return 0;
+ }
+
+ dvd_file->seek_pos += byte_size;
+
+ memcpy( data, &(secbuf[ seek_byte ]), byte_size );
+ free( secbuf );
+
+ return byte_size;
+}
+
+static ssize_t DVDReadBytesPath( dvd_file_t *dvd_file, void *data,
+ size_t byte_size )
+{
+ return read( dvd_file->title_fds[ 0 ], data, byte_size );
+}
+
+ssize_t DVDReadBytes( dvd_file_t *dvd_file, void *data, size_t byte_size )
+{
+ if( dvd_file->dvd->isImageFile ) {
+ return DVDReadBytesUDF( dvd_file, data, byte_size );
+ } else {
+ return DVDReadBytesPath( dvd_file, data, byte_size );
+ }
+}
+
+ssize_t DVDFileSize( dvd_file_t *dvd_file )
+{
+ return dvd_file->filesize;
+}
+
+int64_t DVDReadVLBUDF( dvd_reader_t *device, uint32_t lb_number,
+ size_t block_count, struct iovec * vector,
+ int encrypted )
+{
+ int ret;
+
+ if( !device->dev ) {
+ fprintf( stderr, "libdvdread: Fatal error in block read.\n" );
+ return 0;
+ }
+
+ ret = dvdcss_seek( device->dev, (int) lb_number, 0 );
+ if( ret != (int) lb_number ) {
+ fprintf( stderr, "libdvdread: Can't seek to block %u\n",
+ lb_number );
+ return 0;
+ }
+
+ return (int64_t) ( dvdcss_readv( device->dev, vector,
+ (int)block_count, encrypted )
+ * (uint64_t) DVD_VIDEO_LB_LEN );
+}
+
+static int64_t DVDReadVBlocksUDF( dvd_file_t *dvd_file, uint32_t offset,
+ size_t block_count, struct iovec *vector )
+{
+ return DVDReadVLBUDF( dvd_file->dvd, dvd_file->lb_start + offset,
+ block_count, vector, DVDCSS_READ_DECRYPT );
+}
+
+
+ssize_t DVDReadVBlocks( dvd_file_t *dvd_file, int offset,
+ size_t block_count, struct iovec * vector )
+{
+ int64_t ret;
+
+ if( dvd_file->dvd->isImageFile ) {
+ ret = DVDReadVBlocksUDF( dvd_file, (uint32_t)offset,
+ block_count, vector );
+ } else {
+ ret = 0;//= DVDReadVBlocksPath( dvd_file, (size_t) offset,
+// block_count, vector );
+ }
+ if( ret <= 0 ) {
+ return (ssize_t) ret;
+ }
+ {
+ ssize_t sret = (ssize_t) (ret / (int64_t)DVD_VIDEO_LB_LEN );
+ if( sret == 0 ) {
+ fprintf(stderr, "libdvdread: DVDReadVBlocks got %d bytes\n", (int)ret );
+ }
+ return sret;
+ }
+
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2000 Björn Englund <d4bjorn@dtek.chalmers.se>,
+ * Håkan Hjort <d95hjort@dtek.chalmers.se>
+ *
+ * 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
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "config.h" // Needed for WORDS_BIGENDIAN
+#include "ifo_types.h"
+#include "ifo_read.h"
+#include "ifo_print.h"
+
+/* Put this in some other file / package? It's used in nav_print too. */
+static void ifoPrint_time(int level, dvd_time_t *dtime) {
+ const char *rate;
+ assert((dtime->hour>>4) < 0xa && (dtime->hour&0xf) < 0xa);
+ assert((dtime->minute>>4) < 0x7 && (dtime->minute&0xf) < 0xa);
+ assert((dtime->second>>4) < 0x7 && (dtime->second&0xf) < 0xa);
+ assert((dtime->frame_u&0xf) < 0xa);
+
+ printf("%02x:%02x:%02x.%02x",
+ dtime->hour,
+ dtime->minute,
+ dtime->second,
+ dtime->frame_u & 0x3f);
+ switch((dtime->frame_u & 0xc0) >> 6) {
+ case 1:
+ rate = "25.00";
+ break;
+ case 3:
+ rate = "29.97";
+ break;
+ default:
+ if(dtime->hour == 0 && dtime->minute == 0
+ && dtime->second == 0 && dtime->frame_u == 0)
+ rate = "no";
+ else
+ rate = "(please send a bug report)";
+ break;
+ }
+ printf(" @ %s fps", rate);
+}
+
+/* Put this in some other file / package? It's used in nav_print too.
+ Possibly also by the vm / navigator. */
+static void ifoPrint_CMD(int row, vm_cmd_t *command) {
+ int i;
+
+ printf("(%03d) ", row + 1);
+ for(i=0;i<8;i++)
+ printf("%02x ", command->bytes[i]);
+ printf("| ");
+
+ //vmcmd(command);
+ printf("\n");
+}
+
+static void ifoPrint_video_attributes(int level, video_attr_t *attr) {
+
+ /* The following test is shorter but not correct ISO C,
+ memcmp(attr,my_friendly_zeros, sizeof(video_attr_t)) */
+ if(attr->mpeg_version == 0
+ && attr->video_format == 0
+ && attr->display_aspect_ratio == 0
+ && attr->permitted_df == 0
+ && attr->unknown1 == 0
+ && attr->line21_cc_1 == 0
+ && attr->line21_cc_2 == 0
+ && attr->video_format == 0
+ && attr->letterboxed == 0
+ && attr->film_mode == 0) {
+ printf("-- Unspecified --");
+ return;
+ }
+
+ switch(attr->mpeg_version) {
+ case 0:
+ printf("mpeg1 ");
+ break;
+ case 1:
+ printf("mpeg2 ");
+ break;
+ default:
+ printf("(please send a bug report) ");
+ }
+
+ switch(attr->video_format) {
+ case 0:
+ printf("ntsc ");
+ break;
+ case 1:
+ printf("pal ");
+ break;
+ default:
+ printf("(please send a bug report) ");
+ }
+
+ switch(attr->display_aspect_ratio) {
+ case 0:
+ printf("4:3 ");
+ break;
+ case 3:
+ printf("16:9 ");
+ break;
+ default:
+ printf("(please send a bug report) ");
+ }
+
+ // Wide is allways allowed..!!!
+ switch(attr->permitted_df) {
+ case 0:
+ printf("pan&scan+letterboxed ");
+ break;
+ case 1:
+ printf("only pan&scan "); //??
+ break;
+ case 2:
+ printf("only letterboxed ");
+ break;
+ case 3:
+ // not specified
+ break;
+ default:
+ printf("(please send a bug report)");
+ }
+
+ printf("U%x ", attr->unknown1);
+ assert(!attr->unknown1);
+
+ if(attr->line21_cc_1 || attr->line21_cc_2) {
+ printf("NTSC CC ");
+ if(attr->line21_cc_1)
+ printf("1 ");
+ if(attr->line21_cc_2)
+ printf("2 ");
+ }
+
+ {
+ int height = 480;
+ if(attr->video_format != 0)
+ height = 576;
+ switch(attr->picture_size) {
+ case 0:
+ printf("720x%d ", height);
+ break;
+ case 1:
+ printf("704x%d ", height);
+ break;
+ case 2:
+ printf("352x%d ", height);
+ break;
+ case 3:
+ printf("352x%d ", height/2);
+ break;
+ default:
+ printf("(please send a bug report) ");
+ }
+ }
+
+ if(attr->letterboxed) {
+ printf("letterboxed ");
+ }
+
+ if(attr->film_mode) {
+ printf("film");
+ } else {
+ printf("video"); //camera
+ }
+}
+
+static void ifoPrint_audio_attributes(int level, audio_attr_t *attr) {
+
+ if(attr->audio_format == 0
+ && attr->multichannel_extension == 0
+ && attr->lang_type == 0
+ && attr->application_mode == 0
+ && attr->quantization == 0
+ && attr->sample_frequency == 0
+ && attr->channels == 0
+ && attr->lang_extension == 0
+ && attr->unknown1 == 0
+ && attr->unknown1 == 0) {
+ printf("-- Unspecified --");
+ return;
+ }
+
+ switch(attr->audio_format) {
+ case 0:
+ printf("ac3 ");
+ break;
+ case 1:
+ printf("(please send a bug report) ");
+ break;
+ case 2:
+ printf("mpeg1 ");
+ break;
+ case 3:
+ printf("mpeg2ext ");
+ break;
+ case 4:
+ printf("lpcm ");
+ break;
+ case 5:
+ printf("(please send a bug report) ");
+ break;
+ case 6:
+ printf("dts ");
+ break;
+ default:
+ printf("(please send a bug report) ");
+ }
+
+ if(attr->multichannel_extension)
+ printf("multichannel_extension ");
+
+ switch(attr->lang_type) {
+ case 0:
+ // not specified
+ assert(attr->lang_code == 0);
+ break;
+ case 1:
+ printf("%c%c ", attr->lang_code>>8, attr->lang_code & 0xff);
+ break;
+ default:
+ printf("(please send a bug report) ");
+ }
+
+ switch(attr->application_mode) {
+ case 0:
+ // not specified
+ break;
+ case 1:
+ printf("karaoke mode ");
+ break;
+ case 2:
+ printf("surround sound mode ");
+ break;
+ default:
+ printf("(please send a bug report) ");
+ }
+
+ switch(attr->quantization) {
+ case 0:
+ printf("16bit ");
+ break;
+ case 1:
+ printf("20bit ");
+ break;
+ case 2:
+ printf("24bit ");
+ break;
+ case 3:
+ printf("drc ");
+ break;
+ default:
+ printf("(please send a bug report) ");
+ }
+
+ switch(attr->sample_frequency) {
+ case 0:
+ printf("48kHz ");
+ break;
+ default:
+ printf("(please send a bug report) ");
+ }
+
+ printf("%dCh ", attr->channels + 1);
+
+ switch(attr->lang_extension) {
+ case 0:
+ printf("Not specified ");
+ break;
+ case 1: // Normal audio
+ printf("Normal Caption ");
+ break;
+ case 2: // visually imparied
+ printf("Audio for visually impaired ");
+ break;
+ case 3: // Directors 1
+ printf("Director's comments 1 ");
+ break;
+ case 4: // Directors 2
+ printf("Director's comments 2 ");
+ break;
+ //case 4: // Music score ?
+ default:
+ printf("(please send a bug report) ");
+ }
+
+ printf("%d ", attr->unknown1);
+ printf("%d ", attr->unknown2);
+}
+
+static void ifoPrint_subp_attributes(int level, subp_attr_t *attr) {
+
+ if(attr->type == 0
+ && attr->lang_code == 0
+ && attr->zero1 == 0
+ && attr->zero2 == 0
+ && attr->lang_extension== 0) {
+ printf("-- Unspecified --");
+ return;
+ }
+
+ printf("type %02x ", attr->type);
+
+ if(isalpha((int)(attr->lang_code >> 8))
+ && isalpha((int)(attr->lang_code & 0xff))) {
+ printf("%c%c ", attr->lang_code >> 8, attr->lang_code & 0xff);
+ } else {
+ printf("%02x%02x ", 0xff & (unsigned)(attr->lang_code >> 8),
+ 0xff & (unsigned)(attr->lang_code & 0xff));
+ }
+
+ printf("%d ", attr->zero1);
+ printf("%d ", attr->zero2);
+
+ switch(attr->lang_extension) {
+ case 0:
+ printf("Not specified ");
+ break;
+ case 1:
+ printf("Caption with normal size character ");
+ break;
+ case 2:
+ printf("Caption with bigger size character ");
+ break;
+ case 3:
+ printf("Caption for children ");
+ break;
+ case 4:
+ printf("reserved ");
+ break;
+ case 5:
+ printf("Closed Caption with normal size character ");
+ break;
+ case 6:
+ printf("Closed Caption with bigger size character ");
+ break;
+ case 7:
+ printf("Closed Caption for children ");
+ break;
+ case 8:
+ printf("reserved ");
+ break;
+ case 9:
+ printf("Forced Caption");
+ break;
+ case 10:
+ printf("reserved ");
+ break;
+ case 11:
+ printf("reserved ");
+ break;
+ case 12:
+ printf("reserved ");
+ break;
+ case 13:
+ printf("Director's comments with normal size character ");
+ break;
+ case 14:
+ printf("Director's comments with bigger size character ");
+ break;
+ case 15:
+ printf("Director's comments for children ");
+ break;
+ default:
+ printf("(please send a bug report) ");
+ }
+
+}
+
+
+void ifoPrint_USER_OPS(user_ops_t *user_ops) {
+ uint32_t uops;
+ unsigned char *ptr = (unsigned char *)user_ops;
+
+ uops = (*ptr++ << 24);
+ uops |= (*ptr++ << 16);
+ uops |= (*ptr++ << 8);
+ uops |= (*ptr++);
+
+ if(uops == 0) {
+ printf("None\n");
+ } else if(uops == 0x01ffffff) {
+ printf("All\n");
+ } else {
+ if(user_ops->title_or_time_play)
+ printf("Title or Time Play, ");
+ if(user_ops->chapter_search_or_play)
+ printf("Chapter Search or Play, ");
+ if(user_ops->title_play)
+ printf("Title Play, ");
+ if(user_ops->stop)
+ printf("Stop, ");
+ if(user_ops->go_up)
+ printf("Go Up, ");
+ if(user_ops->time_or_chapter_search)
+ printf("Time or Chapter Search, ");
+ if(user_ops->prev_or_top_pg_search)
+ printf("Prev or Top PG Search, ");
+ if(user_ops->next_pg_search)
+ printf("Next PG Search, ");
+ if(user_ops->forward_scan)
+ printf("Forward Scan, ");
+ if(user_ops->backward_scan)
+ printf("Backward Scan, ");
+ if(user_ops->title_menu_call)
+ printf("Title Menu Call, ");
+ if(user_ops->root_menu_call)
+ printf("Root Menu Call, ");
+ if(user_ops->subpic_menu_call)
+ printf("SubPic Menu Call, ");
+ if(user_ops->audio_menu_call)
+ printf("Audio Menu Call, ");
+ if(user_ops->angle_menu_call)
+ printf("Angle Menu Call, ");
+ if(user_ops->chapter_menu_call)
+ printf("Chapter Menu Call, ");
+ if(user_ops->resume)
+ printf("Resume, ");
+ if(user_ops->button_select_or_activate)
+ printf("Button Select or Activate, ");
+ if(user_ops->still_off)
+ printf("Still Off, ");
+ if(user_ops->pause_on)
+ printf("Pause On, ");
+ if(user_ops->audio_stream_change)
+ printf("Audio Stream Change, ");
+ if(user_ops->subpic_stream_change)
+ printf("SubPic Stream Change, ");
+ if(user_ops->angle_change)
+ printf("Angle Change, ");
+ if(user_ops->karaoke_audio_pres_mode_change)
+ printf("Karaoke Audio Pres Mode Change, ");
+ if(user_ops->video_pres_mode_change)
+ printf("Video Pres Mode Change, ");
+ printf("\n");
+ }
+}
+
+
+void ifoPrint_VMGI_MAT(vmgi_mat_t *vmgi_mat) {
+
+ printf("VMG Identifier: %.12s\n", vmgi_mat->vmg_identifier);
+ printf("Last Sector of VMG: %08x\n", vmgi_mat->vmg_last_sector);
+ printf("Last Sector of VMGI: %08x\n", vmgi_mat->vmgi_last_sector);
+ printf("Specification version number: %01x.%01x\n",
+ vmgi_mat->specification_version >> 4,
+ vmgi_mat->specification_version & 0xf);
+ /* Byte 2 of 'VMG Category' (00xx0000) is the Region Code */
+ printf("VMG Category: %08x\n", vmgi_mat->vmg_category);
+ printf("VMG Number of Volumes: %i\n", vmgi_mat->vmg_nr_of_volumes);
+ printf("VMG This Volume: %i\n", vmgi_mat->vmg_this_volume_nr);
+ printf("Disc side %i\n", vmgi_mat->disc_side);
+ printf("VMG Number of Title Sets %i\n", vmgi_mat->vmg_nr_of_title_sets);
+ printf("Provider ID: %.32s\n", vmgi_mat->provider_identifier);
+ printf("VMG POS Code: %08x", (uint32_t)(vmgi_mat->vmg_pos_code >> 32));
+ printf("%08x\n", (uint32_t)vmgi_mat->vmg_pos_code);
+ printf("End byte of VMGI_MAT: %08x\n", vmgi_mat->vmgi_last_byte);
+ printf("Start byte of First Play PGC FP PGC: %08x\n",
+ vmgi_mat->first_play_pgc);
+ printf("Start sector of VMGM_VOBS: %08x\n", vmgi_mat->vmgm_vobs);
+ printf("Start sector of TT_SRPT: %08x\n", vmgi_mat->tt_srpt);
+ printf("Start sector of VMGM_PGCI_UT: %08x\n", vmgi_mat->vmgm_pgci_ut);
+ printf("Start sector of PTL_MAIT: %08x\n", vmgi_mat->ptl_mait);
+ printf("Start sector of VTS_ATRT: %08x\n", vmgi_mat->vts_atrt);
+ printf("Start sector of TXTDT_MG: %08x\n", vmgi_mat->txtdt_mgi);
+ printf("Start sector of VMGM_C_ADT: %08x\n", vmgi_mat->vmgm_c_adt);
+ printf("Start sector of VMGM_VOBU_ADMAP: %08x\n",
+ vmgi_mat->vmgm_vobu_admap);
+ printf("Video attributes of VMGM_VOBS: ");
+ ifoPrint_video_attributes(5, &vmgi_mat->vmgm_video_attr);
+ printf("\n");
+ printf("VMGM Number of Audio attributes: %i\n",
+ vmgi_mat->nr_of_vmgm_audio_streams);
+ if(vmgi_mat->nr_of_vmgm_audio_streams > 0) {
+ printf("\tstream %i status: ", 1);
+ ifoPrint_audio_attributes(5, &vmgi_mat->vmgm_audio_attr);
+ printf("\n");
+ }
+ printf("VMGM Number of Sub-picture attributes: %i\n",
+ vmgi_mat->nr_of_vmgm_subp_streams);
+ if(vmgi_mat->nr_of_vmgm_subp_streams > 0) {
+ printf("\tstream %2i status: ", 1);
+ ifoPrint_subp_attributes(5, &vmgi_mat->vmgm_subp_attr);
+ printf("\n");
+ }
+}
+
+
+void ifoPrint_VTSI_MAT(vtsi_mat_t *vtsi_mat) {
+ int i;
+
+ printf("VTS Identifier: %.12s\n", vtsi_mat->vts_identifier);
+ printf("Last Sector of VTS: %08x\n", vtsi_mat->vts_last_sector);
+ printf("Last Sector of VTSI: %08x\n", vtsi_mat->vtsi_last_sector);
+ printf("Specification version number: %01x.%01x\n",
+ vtsi_mat->specification_version>>4,
+ vtsi_mat->specification_version&0xf);
+ printf("VTS Category: %08x\n", vtsi_mat->vts_category);
+ printf("End byte of VTSI_MAT: %08x\n", vtsi_mat->vtsi_last_byte);
+ printf("Start sector of VTSM_VOBS: %08x\n", vtsi_mat->vtsm_vobs);
+ printf("Start sector of VTSTT_VOBS: %08x\n", vtsi_mat->vtstt_vobs);
+ printf("Start sector of VTS_PTT_SRPT: %08x\n", vtsi_mat->vts_ptt_srpt);
+ printf("Start sector of VTS_PGCIT: %08x\n", vtsi_mat->vts_pgcit);
+ printf("Start sector of VTSM_PGCI_UT: %08x\n", vtsi_mat->vtsm_pgci_ut);
+ printf("Start sector of VTS_TMAPT: %08x\n", vtsi_mat->vts_tmapt);
+ printf("Start sector of VTSM_C_ADT: %08x\n", vtsi_mat->vtsm_c_adt);
+ printf("Start sector of VTSM_VOBU_ADMAP: %08x\n",vtsi_mat->vtsm_vobu_admap);
+ printf("Start sector of VTS_C_ADT: %08x\n", vtsi_mat->vts_c_adt);
+ printf("Start sector of VTS_VOBU_ADMAP: %08x\n", vtsi_mat->vts_vobu_admap);
+
+ printf("Video attributes of VTSM_VOBS: ");
+ ifoPrint_video_attributes(5, &vtsi_mat->vtsm_video_attr);
+ printf("\n");
+
+ printf("VTSM Number of Audio attributes: %i\n",
+ vtsi_mat->nr_of_vtsm_audio_streams);
+ if(vtsi_mat->nr_of_vtsm_audio_streams > 0) {
+ printf("\tstream %i status: ", 1);
+ ifoPrint_audio_attributes(5, &vtsi_mat->vtsm_audio_attr);
+ printf("\n");
+ }
+
+ printf("VTSM Number of Sub-picture attributes: %i\n",
+ vtsi_mat->nr_of_vtsm_subp_streams);
+ if(vtsi_mat->nr_of_vtsm_subp_streams > 0) {
+ printf("\tstream %2i status: ", 1);
+ ifoPrint_subp_attributes(5, &vtsi_mat->vtsm_subp_attr);
+ printf("\n");
+ }
+
+ printf("Video attributes of VTS_VOBS: ");
+ ifoPrint_video_attributes(5, &vtsi_mat->vts_video_attr);
+ printf("\n");
+
+ printf("VTS Number of Audio attributes: %i\n",
+ vtsi_mat->nr_of_vts_audio_streams);
+ for(i = 0; i < vtsi_mat->nr_of_vts_audio_streams; i++) {
+ printf("\tstream %i status: ", i);
+ ifoPrint_audio_attributes(5, &vtsi_mat->vts_audio_attr[i]);
+ printf("\n");
+ }
+
+ printf("VTS Number of Subpicture attributes: %i\n",
+ vtsi_mat->nr_of_vts_subp_streams);
+ for(i = 0; i < vtsi_mat->nr_of_vts_subp_streams; i++) {
+ printf("\tstream %2i status: ", i);
+ ifoPrint_subp_attributes(5, &vtsi_mat->vts_subp_attr[i]);
+ printf("\n");
+ }
+}
+
+
+static void ifoPrint_PGC_COMMAND_TBL(pgc_command_tbl_t *cmd_tbl) {
+ int i;
+
+ if(cmd_tbl == NULL) {
+ printf("No Command table present\n");
+ return;
+ }
+
+ printf("Number of Pre commands: %i\n", cmd_tbl->nr_of_pre);
+ for(i = 0; i < cmd_tbl->nr_of_pre; i++) {
+ ifoPrint_CMD(i, &cmd_tbl->pre_cmds[i]);
+ }
+
+ printf("Number of Post commands: %i\n", cmd_tbl->nr_of_post);
+ for(i = 0; i < cmd_tbl->nr_of_post; i++) {
+ ifoPrint_CMD(i, &cmd_tbl->post_cmds[i]);
+ }
+
+ printf("Number of Cell commands: %i\n", cmd_tbl->nr_of_cell);
+ for(i = 0; i < cmd_tbl->nr_of_cell; i++) {
+ ifoPrint_CMD(i, &cmd_tbl->cell_cmds[i]);
+ }
+}
+
+
+static void ifoPrint_PGC_PROGRAM_MAP(pgc_program_map_t *program_map, int nr) {
+ int i;
+
+ if(program_map == NULL) {
+ printf("No Program map present\n");
+ return;
+ }
+
+ for(i = 0; i < nr; i++) {
+ printf("Program %3i Entry Cell: %3i\n", i + 1, program_map[i]);
+ }
+}
+
+
+static void ifoPrint_CELL_PLAYBACK(cell_playback_t *cell_playback, int nr) {
+ int i;
+
+ if(cell_playback == NULL) {
+ printf("No Cell Playback info present\n");
+ return;
+ }
+
+ for(i=0;i<nr;i++) {
+ printf("Cell: %3i ", i + 1);
+
+ ifoPrint_time(5, &cell_playback[i].playback_time);
+ printf("\t");
+
+ if(cell_playback[i].block_mode || cell_playback[i].block_type) {
+ const char *s;
+ switch(cell_playback[i].block_mode) {
+ case 0:
+ s = "not a"; break;
+ case 1:
+ s = "the first"; break;
+ case 2:
+ default:
+ s = ""; break;
+ case 3:
+ s = "last"; break;
+ }
+ printf("%s cell in the block ", s);
+
+ switch(cell_playback[i].block_type) {
+ case 0:
+ printf("not part of the block ");
+ break;
+ case 1:
+ printf("angle block ");
+ break;
+ case 2:
+ case 3:
+ printf("(send bug repport) ");
+ break;
+ }
+ }
+ if(cell_playback[i].seamless_play)
+ printf("presented seamlessly ");
+ if(cell_playback[i].interleaved)
+ printf("cell is interleaved ");
+ if(cell_playback[i].stc_discontinuity)
+ printf("STC_discontinuty ");
+ if(cell_playback[i].seamless_angle)
+ printf("only seamless angle ");
+ if(cell_playback[i].restricted)
+ printf("restricted cell ");
+
+ if(cell_playback[i].still_time)
+ printf("still time %d ", cell_playback[i].still_time);
+ if(cell_playback[i].cell_cmd_nr)
+ printf("cell command %d", cell_playback[i].cell_cmd_nr);
+
+ printf("\n\tStart sector: %08x\tFirst ILVU end sector: %08x\n",
+ cell_playback[i].first_sector,
+ cell_playback[i].first_ilvu_end_sector);
+ printf("\tEnd sector: %08x\tLast VOBU start sector: %08x\n",
+ cell_playback[i].last_sector,
+ cell_playback[i].last_vobu_start_sector);
+ }
+}
+
+static void ifoPrint_CELL_POSITION(cell_position_t *cell_position, int nr) {
+ int i;
+
+ if(cell_position == NULL) {
+ printf("No Cell Position info present\n");
+ return;
+ }
+
+ for(i=0;i<nr;i++) {
+ printf("Cell: %3i has VOB ID: %3i, Cell ID: %3i\n", i + 1,
+ cell_position[i].vob_id_nr, cell_position[i].cell_nr);
+ }
+}
+
+
+void ifoPrint_PGC(pgc_t *pgc) {
+ int i;
+
+ printf("Number of Programs: %i\n", pgc->nr_of_programs);
+ printf("Number of Cells: %i\n", pgc->nr_of_cells);
+ /* Check that time is 0:0:0:0 also if nr_of_programs==0 */
+ printf("Playback time: ");
+ ifoPrint_time(5, &pgc->playback_time); printf("\n");
+
+ /* If no programs/no time then does this mean anything? */
+ printf("Prohibited user operations: ");
+ ifoPrint_USER_OPS(&pgc->prohibited_ops);
+
+ for(i = 0; i < 8; i++) {
+ if(pgc->audio_control[i] & 0x8000) { /* The 'is present' bit */
+ printf("Audio stream %i control: %04x\n",
+ i, pgc->audio_control[i]);
+ }
+ }
+
+ for(i = 0; i < 32; i++) {
+ if(pgc->subp_control[i] & 0x80000000) { /* The 'is present' bit */
+ printf("Subpicture stream %2i control: %08x\n",
+ i, pgc->subp_control[i]);
+ }
+ }
+
+ printf("Next PGC number: %i\n", pgc->next_pgc_nr);
+ printf("Prev PGC number: %i\n", pgc->prev_pgc_nr);
+ printf("GoUp PGC number: %i\n", pgc->goup_pgc_nr);
+ if(pgc->nr_of_programs != 0) {
+ printf("Still time: %i seconds (255=inf)\n", pgc->still_time);
+ printf("PG Playback mode %02x\n", pgc->pg_playback_mode);
+ }
+
+ if(pgc->nr_of_programs != 0) {
+ for(i = 0; i < 16; i++) {
+ printf("Color %2i: %08x\n", i, pgc->palette[i]);
+ }
+ }
+
+ /* Memmory offsets to div. tables. */
+ ifoPrint_PGC_COMMAND_TBL(pgc->command_tbl);
+ ifoPrint_PGC_PROGRAM_MAP(pgc->program_map, pgc->nr_of_programs);
+ ifoPrint_CELL_PLAYBACK(pgc->cell_playback, pgc->nr_of_cells);
+ ifoPrint_CELL_POSITION(pgc->cell_position, pgc->nr_of_cells);
+}
+
+
+void ifoPrint_TT_SRPT(tt_srpt_t *tt_srpt) {
+ int i;
+
+ printf("Number of TitleTrack search pointers: %i\n",
+ tt_srpt->nr_of_srpts);
+ for(i=0;i<tt_srpt->nr_of_srpts;i++) {
+ printf("Title Track index %i\n", i + 1);
+ printf("\tTitle set number (VTS): %i",
+ tt_srpt->title[i].title_set_nr);
+ printf("\tVTS_TTN: %i\n", tt_srpt->title[i].vts_ttn);
+ printf("\tNumber of PTTs: %i\n", tt_srpt->title[i].nr_of_ptts);
+ printf("\tNumber of angles: %i\n",
+ tt_srpt->title[i].nr_of_angles);
+ printf("\tTitle playback type: %02x\n", /* XXX: TODO FIXME */
+ *(uint8_t *)&(tt_srpt->title[i].pb_ty));
+ printf("\tParental ID field: %04x\n",
+ tt_srpt->title[i].parental_id);
+ printf("\tTitle set starting sector %08x\n",
+ tt_srpt->title[i].title_set_sector);
+ }
+}
+
+
+void ifoPrint_VTS_PTT_SRPT(vts_ptt_srpt_t *vts_ptt_srpt) {
+ int i, j;
+ printf(" nr_of_srpts %i last byte %i\n",
+ vts_ptt_srpt->nr_of_srpts,
+ vts_ptt_srpt->last_byte);
+ for(i=0;i<vts_ptt_srpt->nr_of_srpts;i++) {
+ for(j=0;j<vts_ptt_srpt->title[i].nr_of_ptts;j++) {
+ printf("VTS_PTT_SRPT - Title %3i part %3i: PGC: %3i PG: %3i\n",
+ i + 1, j + 1,
+ vts_ptt_srpt->title[i].ptt[j].pgcn,
+ vts_ptt_srpt->title[i].ptt[j].pgn );
+ }
+ }
+}
+
+
+static void hexdump(uint8_t *ptr, int len) {
+ while(len--)
+ printf("%02x ", *ptr++);
+}
+
+void ifoPrint_PTL_MAIT(ptl_mait_t *ptl_mait) {
+ int i, j;
+
+ printf("Number of Countries: %i\n", ptl_mait->nr_of_countries);
+ printf("Number of VTSs: %i\n", ptl_mait->nr_of_vtss);
+ //printf("Last byte: %i\n", ptl_mait->last_byte);
+
+ for(i = 0; i < ptl_mait->nr_of_countries; i++) {
+ printf("Country code: %c%c\n",
+ ptl_mait->countries[i].country_code >> 8,
+ ptl_mait->countries[i].country_code & 0xff);
+ /*
+ printf("Start byte: %04x %i\n",
+ ptl_mait->countries[i].pf_ptl_mai_start_byte,
+ ptl_mait->countries[i].pf_ptl_mai_start_byte);
+ */
+ /* This seems to be pointing at a array with 8 2byte fields per VTS
+ ? and one extra for the menu? always an odd number of VTSs on
+ all the dics I tested so it might be padding to even also.
+ If it is for the menu it probably the first entry. */
+ for(j=0;j<8;j++) {
+ hexdump( (uint8_t *)ptl_mait->countries - PTL_MAIT_COUNTRY_SIZE
+ + ptl_mait->countries[i].pf_ptl_mai_start_byte
+ + j*(ptl_mait->nr_of_vtss+1)*2, (ptl_mait->nr_of_vtss+1)*2);
+ printf("\n");
+ }
+ }
+}
+
+
+void ifoPrint_C_ADT(c_adt_t *c_adt) {
+ int i, entries;
+
+ printf("Number of VOBs in this VOBS: %i\n", c_adt->nr_of_vobs);
+ entries = (c_adt->last_byte + 1 - C_ADT_SIZE)/sizeof(c_adt_t);
+
+ for(i = 0; i < entries; i++) {
+ printf("VOB ID: %3i, Cell ID: %3i ",
+ c_adt->cell_adr_table[i].vob_id, c_adt->cell_adr_table[i].cell_id);
+ printf("Sector (first): 0x%08x (last): 0x%08x\n",
+ c_adt->cell_adr_table[i].start_sector,
+ c_adt->cell_adr_table[i].last_sector);
+ }
+}
+
+
+void ifoPrint_VOBU_ADMAP(vobu_admap_t *vobu_admap) {
+ int i, entries;
+
+ entries = (vobu_admap->last_byte + 1 - VOBU_ADMAP_SIZE)/4;
+ for(i = 0; i < entries; i++) {
+ printf("VOBU %5i First sector: 0x%08x\n", i + 1,
+ vobu_admap->vobu_start_sectors[i]);
+ }
+}
+
+
+void ifoPrint_PGCIT(pgcit_t *pgcit) {
+ int i;
+
+ for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
+ printf("\nProgram (PGC): %3i\t", i + 1);
+ printf("PGC Category: Entry id 0x%02x, ", pgcit->pgci_srp[i].entry_id);
+ printf("Parental ID mask 0x%04x\n", pgcit->pgci_srp[i].ptl_id_mask);
+ ifoPrint_PGC(pgcit->pgci_srp[i].pgc);
+ }
+}
+
+
+void ifoPrint_PGCI_UT(pgci_ut_t *pgci_ut) {
+ int i;
+
+ printf("Number of Menu Language Units (PGCI_LU): %3i\n", pgci_ut->nr_of_lus);
+ for(i = 0; i < pgci_ut->nr_of_lus; i++) {
+ printf("\nMenu Language Code: %c%c\n",
+ pgci_ut->lu[i].lang_code >> 8,
+ pgci_ut->lu[i].lang_code & 0xff);
+ printf("Menu Existence: %02x\n", pgci_ut->lu[i].exists);
+ ifoPrint_PGCIT(pgci_ut->lu[i].pgcit);
+ }
+}
+
+
+void ifoPrint_VTS_ATTRIBUTES(vts_attributes_t *vts_attributes) {
+ int i;
+
+ printf("VTS_CAT Application type: %08x\n", vts_attributes->vts_cat);
+
+ printf("Video attributes of VTSM_VOBS: ");
+ ifoPrint_video_attributes(5, &vts_attributes->vtsm_vobs_attr);
+ printf("\n");
+ printf("Number of Audio streams: %i\n",
+ vts_attributes->nr_of_vtsm_audio_streams);
+ if(vts_attributes->nr_of_vtsm_audio_streams > 0) {
+ printf("\tstream %i attributes: ", 1);
+ ifoPrint_audio_attributes(5, &vts_attributes->vtsm_audio_attr);
+ printf("\n");
+ }
+ printf("Number of Subpicture streams: %i\n",
+ vts_attributes->nr_of_vtsm_subp_streams);
+ if(vts_attributes->nr_of_vtsm_subp_streams > 0) {
+ printf("\tstream %2i attributes: ", 1);
+ ifoPrint_subp_attributes(5, &vts_attributes->vtsm_subp_attr);
+ printf("\n");
+ }
+
+ printf("Video attributes of VTSTT_VOBS: ");
+ ifoPrint_video_attributes(5, &vts_attributes->vtstt_vobs_video_attr);
+ printf("\n");
+ printf("Number of Audio streams: %i\n",
+ vts_attributes->nr_of_vtstt_audio_streams);
+ for(i = 0; i < vts_attributes->nr_of_vtstt_audio_streams; i++) {
+ printf("\tstream %i attributes: ", i);
+ ifoPrint_audio_attributes(5, &vts_attributes->vtstt_audio_attr[i]);
+ printf("\n");
+ }
+
+ printf("Number of Subpicture streams: %i\n",
+ vts_attributes->nr_of_vtstt_subp_streams);
+ for(i = 0; i < vts_attributes->nr_of_vtstt_subp_streams; i++) {
+ printf("\tstream %2i attributes: ", i);
+ ifoPrint_subp_attributes(5, &vts_attributes->vtstt_subp_attr[i]);
+ printf("\n");
+ }
+}
+
+
+void ifoPrint_VTS_ATRT(vts_atrt_t *vts_atrt) {
+ int i;
+
+ printf("Number of Video Title Sets: %3i\n", vts_atrt->nr_of_vtss);
+ for(i = 0; i < vts_atrt->nr_of_vtss; i++) {
+ printf("\nVideo Title Set %i\n", i + 1);
+ ifoPrint_VTS_ATTRIBUTES(&vts_atrt->vts[i]);
+ }
+}
+
+
+void ifoPrint(dvd_reader_t *dvd, int title) {
+ ifo_handle_t *ifohandle;
+
+ ifohandle = ifoOpen(dvd, title);
+ if(!ifohandle) {
+ fprintf(stderr, "Can't open info file for title %d\n", title);
+ return;
+ }
+
+
+ if(ifohandle->vmgi_mat) {
+
+ printf("VMG top level\n-------------\n");
+ ifoPrint_VMGI_MAT(ifohandle->vmgi_mat);
+
+ printf("\nFirst Play PGC\n--------------\n");
+ ifoPrint_PGC(ifohandle->first_play_pgc);
+
+ printf("\nTitle Track search pointer table\n");
+ printf( "------------------------------------------------\n");
+ ifoPrint_TT_SRPT(ifohandle->tt_srpt);
+
+ printf("\nMenu PGCI Unit table\n");
+ printf( "--------------------\n");
+ if(ifohandle->pgci_ut) {
+ ifoPrint_PGCI_UT(ifohandle->pgci_ut);
+ } else {
+ printf("No PGCI Unit table present\n");
+ }
+
+ printf("\nParental Manegment Information table\n");
+ printf( "------------------------------------\n");
+ if(ifohandle->ptl_mait) {
+ ifoPrint_PTL_MAIT(ifohandle->ptl_mait);
+ } else {
+ printf("No Parental Management Information present\n");
+ }
+
+ printf("\nVideo Title Set Attribute Table\n");
+ printf( "-------------------------------\n");
+ ifoPrint_VTS_ATRT(ifohandle->vts_atrt);
+
+ printf("\nText Data Manager Information\n");
+ printf( "-----------------------------\n");
+ if(ifohandle->txtdt_mgi) {
+ //ifoPrint_TXTDT_MGI(&(vmgi->txtdt_mgi));
+ } else {
+ printf("No Text Data Manager Information present\n");
+ }
+
+ printf("\nMenu Cell Adress table\n");
+ printf( "-----------------\n");
+ if(ifohandle->menu_c_adt) {
+ ifoPrint_C_ADT(ifohandle->menu_c_adt);
+ } else {
+ printf("No Menu Cell Adress table present\n");
+ }
+
+ printf("\nVideo Manager Menu VOBU address map\n");
+ printf( "-----------------\n");
+ if(ifohandle->menu_vobu_admap) {
+ ifoPrint_VOBU_ADMAP(ifohandle->menu_vobu_admap);
+ } else {
+ printf("No Menu VOBU address map present\n");
+ }
+ }
+
+
+ if(ifohandle->vtsi_mat) {
+
+ printf("VTS top level\n-------------\n");
+ ifoPrint_VTSI_MAT(ifohandle->vtsi_mat);
+
+ printf("\nPart of Title Track search pointer table\n");
+ printf( "----------------------------------------------\n");
+ ifoPrint_VTS_PTT_SRPT(ifohandle->vts_ptt_srpt);
+
+ printf("\nPGCI Unit table\n");
+ printf( "--------------------\n");
+ ifoPrint_PGCIT(ifohandle->vts_pgcit);
+
+ printf("\nMenu PGCI Unit table\n");
+ printf( "--------------------\n");
+ if(ifohandle->pgci_ut) {
+ ifoPrint_PGCI_UT(ifohandle->pgci_ut);
+ } else {
+ printf("No Menu PGCI Unit table present\n");
+ }
+
+ printf("\nMenu Cell Adress table\n");
+ printf( "-----------------\n");
+ if(ifohandle->menu_c_adt) {
+ ifoPrint_C_ADT(ifohandle->menu_c_adt);
+ } else {
+ printf("No Cell Adress table present\n");
+ }
+
+ printf("\nVideo Title Set Menu VOBU address map\n");
+ printf( "-----------------\n");
+ if(ifohandle->menu_vobu_admap) {
+ ifoPrint_VOBU_ADMAP(ifohandle->menu_vobu_admap);
+ } else {
+ printf("No Menu VOBU address map present\n");
+ }
+
+ printf("\nCell Adress table\n");
+ printf( "-----------------\n");
+ ifoPrint_C_ADT(ifohandle->vts_c_adt);
+
+ printf("\nVideo Title Set VOBU address map\n");
+ printf( "-----------------\n");
+ ifoPrint_VOBU_ADMAP(ifohandle->vts_vobu_admap);
+ }
+
+ ifoClose(ifohandle);
+}
+
--- /dev/null
+/**
+ * Copyright (C) 2000 Björn Englund <d4bjorn@dtek.chalmers.se>,
+ * Håkan Hjort <d95hjort@dtek.chalmers.se>
+ *
+ * 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 IFO_PRINT_H_INCLUDED
+#define IFO_PRINT_H_INCLUDED
+
+#include <dvdread/ifo_types.h>
+#include <dvdread/dvd_reader.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * This file provides example functions for printing information about the IFO
+ * file to stdout.
+ */
+
+/**
+ * Print the complete parsing information for the given file.
+ */
+void ifoPrint(dvd_reader_t *dvd, int title);
+
+void ifoPrint_VMGI_MAT(vmgi_mat_t *vmgi_mat);
+void ifoPrint_VTSI_MAT(vtsi_mat_t *vtsi_mat);
+
+void ifoPrint_PTL_MAIT(ptl_mait_t *ptl_mait);
+void ifoPrint_VTS_ATRT(vts_atrt_t *vts_atrt);
+void ifoPrint_TT_SRPT(tt_srpt_t *vmg_ptt_srpt);
+void ifoPrint_VTS_PTT_SRPT(vts_ptt_srpt_t *vts_ptt_srpt);
+void ifoPrint_PGC(pgc_t *pgc);
+void ifoPrint_PGCIT(pgcit_t *pgcit);
+void ifoPrint_PGCI_UT(pgci_ut_t *pgci_ut);
+void ifoPrint_C_ADT(c_adt_t *c_adt);
+void ifoPrint_VOBU_ADMAP(vobu_admap_t *vobu_admap);
+
+#ifdef __cplusplus
+};
+#endif
+#endif /* IFO_PRINT_H_INCLUDED */
--- /dev/null
+/*
+ * Copyright (C) 2000 Björn Englund <d4bjorn@dtek.chalmers.se>,
+ * Håkan Hjort <d95hjort@dtek.chalmers.se>
+ *
+ * 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
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <string.h>
+#include <assert.h>
+
+#include "dvd_reader.h"
+
+#include "config.h" // Needed for WORDS_BIGENDIAN
+#include "bswap.h"
+#include "ifo_types.h"
+#include "ifo_read.h"
+
+#ifndef DVD_BLOCK_LEN
+#define DVD_BLOCK_LEN 2048
+#endif
+
+#ifndef NDEBUG
+#define CHECK_ZERO(arg) \
+ if(memcmp(my_friendly_zeros, &arg, sizeof(arg))) { \
+ unsigned int i_CZ; \
+ fprintf(stderr, "*** Zero check failed in %s:%i\n for %s = 0x", \
+ __FILE__, __LINE__, # arg ); \
+ for(i_CZ = 0; i_CZ < sizeof(arg); i_CZ++) \
+ fprintf(stderr, "%02x", *((uint8_t *)&arg + i_CZ)); \
+ fprintf(stderr, "\n"); \
+ }
+static const uint8_t my_friendly_zeros[2048];
+#else
+#define CHECK_ZERO(arg) (void)(arg)
+#endif
+
+
+/* Prototypes for internal functions */
+static int ifoRead_VMG(ifo_handle_t *ifofile);
+static int ifoRead_VTS(ifo_handle_t *ifofile);
+static int ifoRead_PGC(ifo_handle_t *ifofile, pgc_t *pgc, unsigned int offset);
+static int ifoRead_PGC_COMMAND_TBL(ifo_handle_t *ifofile,
+ pgc_command_tbl_t *cmd_tbl,
+ unsigned int offset);
+static int ifoRead_PGC_PROGRAM_MAP(ifo_handle_t *ifofile,
+ pgc_program_map_t *program_map,
+ unsigned int nr, unsigned int offset);
+static int ifoRead_CELL_PLAYBACK_TBL(ifo_handle_t *ifofile,
+ cell_playback_t *cell_playback,
+ unsigned int nr, unsigned int offset);
+static int ifoRead_CELL_POSITION_TBL(ifo_handle_t *ifofile,
+ cell_position_t *cell_position,
+ unsigned int nr, unsigned int offset);
+static int ifoRead_VTS_ATTRIBUTES(ifo_handle_t *ifofile,
+ vts_attributes_t *vts_attributes,
+ unsigned int offset);
+static int ifoRead_C_ADT_internal(ifo_handle_t *ifofile, c_adt_t *c_adt,
+ unsigned int sector);
+static int ifoRead_VOBU_ADMAP_internal(ifo_handle_t *ifofile,
+ vobu_admap_t *vobu_admap,
+ unsigned int sector);
+static int ifoRead_PGCIT_internal(ifo_handle_t *ifofile, pgcit_t *pgcit,
+ unsigned int offset);
+
+static void ifoFree_PGC(pgc_t *pgc);
+static void ifoFree_PGC_COMMAND_TBL(pgc_command_tbl_t *cmd_tbl);
+static void ifoFree_PGCIT_internal(pgcit_t *pgcit);
+
+
+static int DVDFileSeek_( dvd_file_t *dvd_file, uint32_t offset ) {
+ return (DVDFileSeek(dvd_file, (int)offset) == (int)offset);
+}
+
+
+ifo_handle_t *ifoOpen(dvd_reader_t *dvd, int title) {
+ ifo_handle_t *ifofile;
+
+ ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t));
+ if(!ifofile)
+ return 0;
+
+ memset(ifofile, 0, sizeof(ifo_handle_t));
+
+ ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE);
+ if(!ifofile->file) {
+ if(title) {
+ fprintf(stderr, "libdvdread: Can't open file VTS_%02d_0.IFO.\n", title);
+ } else {
+ fprintf(stderr, "libdvdread: Can't open file VIDEO_TS.IFO.\n");
+ }
+ free(ifofile);
+ return 0;
+ }
+
+ /* First check if this is a VMGI file. */
+ if(ifoRead_VMG(ifofile)) {
+
+ /* These are both mandatory. */
+ if(!ifoRead_FP_PGC(ifofile) || !ifoRead_TT_SRPT(ifofile)) {
+ fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO).\n");
+ ifoClose(ifofile);
+ return 0;
+ }
+
+ ifoRead_PGCI_UT(ifofile);
+ ifoRead_PTL_MAIT(ifofile);
+
+ /* This is also mandatory. */
+ if(!ifoRead_VTS_ATRT(ifofile)) {
+ fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO).\n");
+ ifoClose(ifofile);
+ return 0;
+ }
+
+ ifoRead_TXTDT_MGI(ifofile);
+ ifoRead_C_ADT(ifofile);
+ ifoRead_VOBU_ADMAP(ifofile);
+
+ return ifofile;
+ }
+
+ if(ifoRead_VTS(ifofile)) {
+
+ if(!ifoRead_VTS_PTT_SRPT(ifofile) || !ifoRead_PGCIT(ifofile)) {
+ fprintf(stderr, "libdvdread: Invalid title IFO (VTS_%02d_0.IFO).\n",
+ title);
+ ifoClose(ifofile);
+ return 0;
+ }
+
+
+ ifoRead_PGCI_UT(ifofile);
+ ifoRead_C_ADT(ifofile);
+ ifoRead_VOBU_ADMAP(ifofile);
+
+ if(!ifoRead_TITLE_C_ADT(ifofile) || !ifoRead_TITLE_VOBU_ADMAP(ifofile)) {
+ fprintf(stderr, "libdvdread: Invalid title IFO (VTS_%02d_0.IFO).\n",
+ title);
+ ifoClose(ifofile);
+ return 0;
+ }
+
+ return ifofile;
+ }
+
+ fprintf(stderr, "libdvdread: Invalid IFO for title %d (VTS_%02d_0.IFO).\n",
+ title, title);
+ ifoClose(ifofile);
+ return 0;
+}
+
+
+ifo_handle_t *ifoOpenVMGI(dvd_reader_t *dvd) {
+ ifo_handle_t *ifofile;
+
+ ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t));
+ if(!ifofile)
+ return 0;
+
+ memset(ifofile, 0, sizeof(ifo_handle_t));
+
+ ifofile->file = DVDOpenFile(dvd, 0, DVD_READ_INFO_FILE);
+ if(!ifofile->file) {
+ fprintf(stderr, "libdvdread: Can't open file VIDEO_TS.IFO.\n");
+ free(ifofile);
+ return 0;
+ }
+
+ if(ifoRead_VMG(ifofile))
+ return ifofile;
+
+ fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO).\n");
+ ifoClose(ifofile);
+ return 0;
+}
+
+
+ifo_handle_t *ifoOpenVTSI(dvd_reader_t *dvd, int title) {
+ ifo_handle_t *ifofile;
+
+ ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t));
+ if(!ifofile)
+ return 0;
+
+ memset(ifofile, 0, sizeof(ifo_handle_t));
+
+ ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE);
+ if(!ifofile->file) {
+ fprintf(stderr, "libdvdread: Can't open file VTS_%02d_0.IFO.\n", title);
+ free(ifofile);
+ return 0;
+ }
+
+ ifoRead_VTS(ifofile);
+ if(ifofile->vtsi_mat)
+ return ifofile;
+
+ fprintf(stderr, "libdvdread: Invalid IFO for title %d (VTS_%02d_0.IFO).\n",
+ title, title);
+ ifoClose(ifofile);
+ return 0;
+}
+
+
+void ifoClose(ifo_handle_t *ifofile) {
+ if(!ifofile)
+ return;
+
+ ifoFree_VOBU_ADMAP(ifofile);
+ ifoFree_TITLE_VOBU_ADMAP(ifofile);
+ ifoFree_C_ADT(ifofile);
+ ifoFree_TITLE_C_ADT(ifofile);
+ ifoFree_TXTDT_MGI(ifofile);
+ ifoFree_VTS_ATRT(ifofile);
+ ifoFree_PTL_MAIT(ifofile);
+ ifoFree_PGCI_UT(ifofile);
+ ifoFree_TT_SRPT(ifofile);
+ ifoFree_FP_PGC(ifofile);
+ ifoFree_PGCIT(ifofile);
+ ifoFree_VTS_PTT_SRPT(ifofile);
+
+ if(ifofile->vmgi_mat)
+ free(ifofile->vmgi_mat);
+
+ if(ifofile->vtsi_mat)
+ free(ifofile->vtsi_mat);
+
+ DVDCloseFile(ifofile->file);
+ ifofile->file = 0;
+ free(ifofile);
+ ifofile = 0;
+}
+
+
+static int ifoRead_VMG(ifo_handle_t *ifofile) {
+ vmgi_mat_t *vmgi_mat;
+
+ vmgi_mat = (vmgi_mat_t *)malloc(sizeof(vmgi_mat_t));
+ if(!vmgi_mat)
+ return 0;
+
+ ifofile->vmgi_mat = vmgi_mat;
+
+ if(!DVDFileSeek_(ifofile->file, 0)) {
+ free(ifofile->vmgi_mat);
+ ifofile->vmgi_mat = 0;
+ return 0;
+ }
+
+ if(!DVDReadBytes(ifofile->file, vmgi_mat, sizeof(vmgi_mat_t))) {
+ free(ifofile->vmgi_mat);
+ ifofile->vmgi_mat = 0;
+ return 0;
+ }
+
+ if(strncmp("DVDVIDEO-VMG", vmgi_mat->vmg_identifier, 12) != 0) {
+ free(ifofile->vmgi_mat);
+ ifofile->vmgi_mat = 0;
+ return 0;
+ }
+
+ B2N_32(vmgi_mat->vmg_last_sector);
+ B2N_32(vmgi_mat->vmgi_last_sector);
+ B2N_32(vmgi_mat->vmg_category);
+ B2N_16(vmgi_mat->vmg_nr_of_volumes);
+ B2N_16(vmgi_mat->vmg_this_volume_nr);
+ B2N_16(vmgi_mat->vmg_nr_of_title_sets);
+ B2N_64(vmgi_mat->vmg_pos_code);
+ B2N_32(vmgi_mat->vmgi_last_byte);
+ B2N_32(vmgi_mat->first_play_pgc);
+ B2N_32(vmgi_mat->vmgm_vobs);
+ B2N_32(vmgi_mat->tt_srpt);
+ B2N_32(vmgi_mat->vmgm_pgci_ut);
+ B2N_32(vmgi_mat->ptl_mait);
+ B2N_32(vmgi_mat->vts_atrt);
+ B2N_32(vmgi_mat->txtdt_mgi);
+ B2N_32(vmgi_mat->vmgm_c_adt);
+ B2N_32(vmgi_mat->vmgm_vobu_admap);
+ B2N_16(vmgi_mat->vmgm_audio_attr.lang_code);
+ B2N_16(vmgi_mat->vmgm_subp_attr.lang_code);
+
+
+ CHECK_ZERO(vmgi_mat->zero_1);
+ CHECK_ZERO(vmgi_mat->zero_2);
+ CHECK_ZERO(vmgi_mat->zero_3);
+ CHECK_ZERO(vmgi_mat->zero_4);
+ CHECK_ZERO(vmgi_mat->zero_5);
+ CHECK_ZERO(vmgi_mat->zero_6);
+ CHECK_ZERO(vmgi_mat->zero_7);
+ CHECK_ZERO(vmgi_mat->zero_8);
+ CHECK_ZERO(vmgi_mat->zero_9);
+ CHECK_ZERO(vmgi_mat->zero_10);
+ assert(vmgi_mat->vmg_last_sector != 0);
+ assert(vmgi_mat->vmgi_last_sector != 0);
+ assert(vmgi_mat->vmgi_last_sector * 2 <= vmgi_mat->vmg_last_sector);
+ assert(vmgi_mat->vmg_nr_of_volumes != 0);
+ assert(vmgi_mat->vmg_this_volume_nr != 0);
+ assert(vmgi_mat->vmg_this_volume_nr <= vmgi_mat->vmg_nr_of_volumes);
+ assert(vmgi_mat->disc_side == 1 || vmgi_mat->disc_side == 2);
+ assert(vmgi_mat->vmg_nr_of_title_sets != 0);
+ assert(vmgi_mat->vmgi_last_byte >= 341);
+ assert(vmgi_mat->vmgi_last_byte / DVD_BLOCK_LEN <=
+ vmgi_mat->vmgi_last_sector);
+ assert(vmgi_mat->first_play_pgc != 0 &&
+ vmgi_mat->first_play_pgc < vmgi_mat->vmgi_last_byte);
+ assert(vmgi_mat->vmgm_vobs == 0 ||
+ (vmgi_mat->vmgm_vobs > vmgi_mat->vmgi_last_sector &&
+ vmgi_mat->vmgm_vobs < vmgi_mat->vmg_last_sector));
+ assert(vmgi_mat->tt_srpt <= vmgi_mat->vmgi_last_sector);
+ assert(vmgi_mat->vmgm_pgci_ut <= vmgi_mat->vmgi_last_sector);
+ assert(vmgi_mat->ptl_mait <= vmgi_mat->vmgi_last_sector);
+ assert(vmgi_mat->vts_atrt <= vmgi_mat->vmgi_last_sector);
+ assert(vmgi_mat->txtdt_mgi <= vmgi_mat->vmgi_last_sector);
+ assert(vmgi_mat->vmgm_c_adt <= vmgi_mat->vmgi_last_sector);
+ assert(vmgi_mat->vmgm_vobu_admap <= vmgi_mat->vmgi_last_sector);
+
+ assert(vmgi_mat->nr_of_vmgm_audio_streams <= 1);
+ assert(vmgi_mat->nr_of_vmgm_subp_streams <= 1);
+
+ return 1;
+}
+
+
+static int ifoRead_VTS(ifo_handle_t *ifofile) {
+ vtsi_mat_t *vtsi_mat;
+ int i;
+
+ vtsi_mat = (vtsi_mat_t *)malloc(sizeof(vtsi_mat_t));
+ if(!vtsi_mat)
+ return 0;
+
+ ifofile->vtsi_mat = vtsi_mat;
+
+ if(!DVDFileSeek_(ifofile->file, 0)) {
+ free(ifofile->vtsi_mat);
+ ifofile->vtsi_mat = 0;
+ return 0;
+ }
+
+ if(!(DVDReadBytes(ifofile->file, vtsi_mat, sizeof(vtsi_mat_t)))) {
+ free(ifofile->vtsi_mat);
+ ifofile->vtsi_mat = 0;
+ return 0;
+ }
+
+ if(strncmp("DVDVIDEO-VTS", vtsi_mat->vts_identifier, 12) != 0) {
+ free(ifofile->vtsi_mat);
+ ifofile->vtsi_mat = 0;
+ return 0;
+ }
+
+ B2N_32(vtsi_mat->vts_last_sector);
+ B2N_32(vtsi_mat->vtsi_last_sector);
+ B2N_32(vtsi_mat->vts_category);
+ B2N_32(vtsi_mat->vtsi_last_byte);
+ B2N_32(vtsi_mat->vtsm_vobs);
+ B2N_32(vtsi_mat->vtstt_vobs);
+ B2N_32(vtsi_mat->vts_ptt_srpt);
+ B2N_32(vtsi_mat->vts_pgcit);
+ B2N_32(vtsi_mat->vtsm_pgci_ut);
+ B2N_32(vtsi_mat->vts_tmapt);
+ B2N_32(vtsi_mat->vtsm_c_adt);
+ B2N_32(vtsi_mat->vtsm_vobu_admap);
+ B2N_32(vtsi_mat->vts_c_adt);
+ B2N_32(vtsi_mat->vts_vobu_admap);
+ B2N_16(vtsi_mat->vtsm_audio_attr.lang_code);
+ B2N_16(vtsi_mat->vtsm_subp_attr.lang_code);
+ for(i = 0; i < 8; i++)
+ B2N_16(vtsi_mat->vts_audio_attr[i].lang_code);
+ for(i = 0; i < 32; i++)
+ B2N_16(vtsi_mat->vts_subp_attr[i].lang_code);
+
+
+ CHECK_ZERO(vtsi_mat->zero_1);
+ CHECK_ZERO(vtsi_mat->zero_2);
+ CHECK_ZERO(vtsi_mat->zero_3);
+ CHECK_ZERO(vtsi_mat->zero_4);
+ CHECK_ZERO(vtsi_mat->zero_5);
+ CHECK_ZERO(vtsi_mat->zero_6);
+ CHECK_ZERO(vtsi_mat->zero_7);
+ CHECK_ZERO(vtsi_mat->zero_8);
+ CHECK_ZERO(vtsi_mat->zero_9);
+ CHECK_ZERO(vtsi_mat->zero_10);
+ CHECK_ZERO(vtsi_mat->zero_11);
+ CHECK_ZERO(vtsi_mat->zero_12);
+ CHECK_ZERO(vtsi_mat->zero_13);
+ CHECK_ZERO(vtsi_mat->zero_14);
+ CHECK_ZERO(vtsi_mat->zero_15);
+ CHECK_ZERO(vtsi_mat->zero_16);
+ CHECK_ZERO(vtsi_mat->zero_17);
+ CHECK_ZERO(vtsi_mat->zero_18);
+ CHECK_ZERO(vtsi_mat->zero_19);
+ CHECK_ZERO(vtsi_mat->zero_20);
+ assert(vtsi_mat->vtsi_last_sector*2 <= vtsi_mat->vts_last_sector);
+ assert(vtsi_mat->vtsi_last_byte/DVD_BLOCK_LEN <= vtsi_mat->vtsi_last_sector);
+ assert(vtsi_mat->vtsm_vobs == 0 ||
+ (vtsi_mat->vtsm_vobs > vtsi_mat->vtsi_last_sector &&
+ vtsi_mat->vtsm_vobs < vtsi_mat->vts_last_sector));
+ assert(vtsi_mat->vtstt_vobs == 0 ||
+ (vtsi_mat->vtstt_vobs > vtsi_mat->vtsi_last_sector &&
+ vtsi_mat->vtstt_vobs < vtsi_mat->vts_last_sector));
+ assert(vtsi_mat->vts_ptt_srpt <= vtsi_mat->vtsi_last_sector);
+ assert(vtsi_mat->vts_pgcit <= vtsi_mat->vtsi_last_sector);
+ assert(vtsi_mat->vtsm_pgci_ut <= vtsi_mat->vtsi_last_sector);
+ assert(vtsi_mat->vts_tmapt <= vtsi_mat->vtsi_last_sector);
+ assert(vtsi_mat->vtsm_c_adt <= vtsi_mat->vtsi_last_sector);
+ assert(vtsi_mat->vtsm_vobu_admap <= vtsi_mat->vtsi_last_sector);
+ assert(vtsi_mat->vts_c_adt <= vtsi_mat->vtsi_last_sector);
+ assert(vtsi_mat->vts_vobu_admap <= vtsi_mat->vtsi_last_sector);
+
+ assert(vtsi_mat->nr_of_vtsm_audio_streams <= 1);
+ assert(vtsi_mat->nr_of_vtsm_subp_streams <= 1);
+
+ assert(vtsi_mat->nr_of_vts_audio_streams <= 8);
+ for(i = vtsi_mat->nr_of_vts_audio_streams; i < 8; i++)
+ CHECK_ZERO(vtsi_mat->vts_audio_attr[i]);
+
+ assert(vtsi_mat->nr_of_vts_subp_streams <= 32);
+ for(i = vtsi_mat->nr_of_vts_subp_streams; i < 32; i++)
+ CHECK_ZERO(vtsi_mat->vts_subp_attr[i]);
+
+ return 1;
+}
+
+
+static int ifoRead_PGC_COMMAND_TBL(ifo_handle_t *ifofile,
+ pgc_command_tbl_t *cmd_tbl,
+ unsigned int offset) {
+
+ memset(cmd_tbl, 0, sizeof(pgc_command_tbl_t));
+
+ if(!DVDFileSeek_(ifofile->file, offset))
+ return 0;
+
+ if(!(DVDReadBytes(ifofile->file, cmd_tbl, PGC_COMMAND_TBL_SIZE)))
+ return 0;
+
+ B2N_16(cmd_tbl->nr_of_pre);
+ B2N_16(cmd_tbl->nr_of_post);
+ B2N_16(cmd_tbl->nr_of_cell);
+
+ assert(cmd_tbl->nr_of_pre + cmd_tbl->nr_of_post + cmd_tbl->nr_of_cell<= 128);
+
+ if(cmd_tbl->nr_of_pre != 0) {
+ unsigned int pre_cmds_size = cmd_tbl->nr_of_pre * COMMAND_DATA_SIZE;
+ cmd_tbl->pre_cmds = (vm_cmd_t *)malloc(pre_cmds_size);
+ if(!cmd_tbl->pre_cmds)
+ return 0;
+
+ if(!(DVDReadBytes(ifofile->file, cmd_tbl->pre_cmds, pre_cmds_size))) {
+ free(cmd_tbl->pre_cmds);
+ return 0;
+ }
+ }
+
+ if(cmd_tbl->nr_of_post != 0) {
+ unsigned int post_cmds_size = cmd_tbl->nr_of_post * COMMAND_DATA_SIZE;
+ cmd_tbl->post_cmds = (vm_cmd_t *)malloc(post_cmds_size);
+ if(!cmd_tbl->post_cmds) {
+ if(cmd_tbl->pre_cmds)
+ free(cmd_tbl->pre_cmds);
+ return 0;
+ }
+ if(!(DVDReadBytes(ifofile->file, cmd_tbl->post_cmds, post_cmds_size))) {
+ if(cmd_tbl->pre_cmds)
+ free(cmd_tbl->pre_cmds);
+ free(cmd_tbl->post_cmds);
+ return 0;
+ }
+ }
+
+ if(cmd_tbl->nr_of_cell != 0) {
+ unsigned int cell_cmds_size = cmd_tbl->nr_of_cell * COMMAND_DATA_SIZE;
+ cmd_tbl->cell_cmds = (vm_cmd_t *)malloc(cell_cmds_size);
+ if(!cmd_tbl->cell_cmds) {
+ if(cmd_tbl->pre_cmds)
+ free(cmd_tbl->pre_cmds);
+ if(cmd_tbl->post_cmds)
+ free(cmd_tbl->post_cmds);
+ return 0;
+ }
+ if(!(DVDReadBytes(ifofile->file, cmd_tbl->cell_cmds, cell_cmds_size))) {
+ if(cmd_tbl->pre_cmds)
+ free(cmd_tbl->pre_cmds);
+ if(cmd_tbl->post_cmds)
+ free(cmd_tbl->post_cmds);
+ free(cmd_tbl->cell_cmds);
+ return 0;
+ }
+ }
+
+ /*
+ * Make a run over all the commands and see that we can interpret them all?
+ */
+ return 1;
+}
+
+
+static void ifoFree_PGC_COMMAND_TBL(pgc_command_tbl_t *cmd_tbl) {
+ if(cmd_tbl) {
+ if(cmd_tbl->nr_of_pre && cmd_tbl->pre_cmds)
+ free(cmd_tbl->pre_cmds);
+ if(cmd_tbl->nr_of_post && cmd_tbl->post_cmds)
+ free(cmd_tbl->post_cmds);
+ if(cmd_tbl->nr_of_cell && cmd_tbl->cell_cmds)
+ free(cmd_tbl->cell_cmds);
+ free(cmd_tbl);
+ }
+}
+
+static int ifoRead_PGC_PROGRAM_MAP(ifo_handle_t *ifofile,
+ pgc_program_map_t *program_map,
+ unsigned int nr, unsigned int offset) {
+ unsigned int size = nr * sizeof(pgc_program_map_t);
+
+ if(!DVDFileSeek_(ifofile->file, offset))
+ return 0;
+
+ if(!(DVDReadBytes(ifofile->file, program_map, size)))
+ return 0;
+
+ return 1;
+}
+
+static int ifoRead_CELL_PLAYBACK_TBL(ifo_handle_t *ifofile,
+ cell_playback_t *cell_playback,
+ unsigned int nr, unsigned int offset) {
+ unsigned int i;
+ unsigned int size = nr * sizeof(cell_playback_t);
+
+ if(!DVDFileSeek_(ifofile->file, offset))
+ return 0;
+
+ if(!(DVDReadBytes(ifofile->file, cell_playback, size)))
+ return 0;
+
+ for(i = 0; i < nr; i++) {
+ B2N_32(cell_playback[i].first_sector);
+ B2N_32(cell_playback[i].first_ilvu_end_sector);
+ B2N_32(cell_playback[i].last_vobu_start_sector);
+ B2N_32(cell_playback[i].last_sector);
+
+ /* Changed < to <= because this was false in the movie 'Pi'. */
+ assert(cell_playback[i].last_vobu_start_sector <=
+ cell_playback[i].last_sector);
+ assert(cell_playback[i].first_sector <=
+ cell_playback[i].last_vobu_start_sector);
+ }
+
+ return 1;
+}
+
+
+static int ifoRead_CELL_POSITION_TBL(ifo_handle_t *ifofile,
+ cell_position_t *cell_position,
+ unsigned int nr, unsigned int offset) {
+ unsigned int i;
+ unsigned int size = nr * sizeof(cell_position_t);
+
+ if(!DVDFileSeek_(ifofile->file, offset))
+ return 0;
+
+ if(!(DVDReadBytes(ifofile->file, cell_position, size)))
+ return 0;
+
+ for(i = 0; i < nr; i++) {
+ B2N_16(cell_position[i].vob_id_nr);
+ CHECK_ZERO(cell_position[i].zero_1);
+ }
+
+ return 1;
+}
+
+static int ifoRead_PGC(ifo_handle_t *ifofile, pgc_t *pgc, unsigned int offset) {
+ unsigned int i;
+
+ if(!DVDFileSeek_(ifofile->file, offset))
+ return 0;
+
+ if(!(DVDReadBytes(ifofile->file, pgc, PGC_SIZE)))
+ return 0;
+
+ B2N_16(pgc->next_pgc_nr);
+ B2N_16(pgc->prev_pgc_nr);
+ B2N_16(pgc->goup_pgc_nr);
+ B2N_16(pgc->command_tbl_offset);
+ B2N_16(pgc->program_map_offset);
+ B2N_16(pgc->cell_playback_offset);
+ B2N_16(pgc->cell_position_offset);
+
+ for(i = 0; i < 8; i++)
+ B2N_16(pgc->audio_control[i]);
+ for(i = 0; i < 32; i++)
+ B2N_32(pgc->subp_control[i]);
+ for(i = 0; i < 16; i++)
+ B2N_32(pgc->palette[i]);
+
+ CHECK_ZERO(pgc->zero_1);
+ assert(pgc->nr_of_programs <= pgc->nr_of_cells);
+
+ /* verify time (look at print_time) */
+ for(i = 0; i < 8; i++)
+ if(!pgc->audio_control[i] & 0x8000) /* The 'is present' bit */
+ CHECK_ZERO(pgc->audio_control[i]);
+ for(i = 0; i < 32; i++)
+ if(!pgc->subp_control[i] & 0x80000000) /* The 'is present' bit */
+ CHECK_ZERO(pgc->subp_control[i]);
+
+ /* Check that time is 0:0:0:0 also if nr_of_programs == 0 */
+ if(pgc->nr_of_programs == 0) {
+ CHECK_ZERO(pgc->still_time);
+ CHECK_ZERO(pgc->pg_playback_mode); // ??
+ assert(pgc->program_map_offset == 0);
+ assert(pgc->cell_playback_offset == 0);
+ assert(pgc->cell_position_offset == 0);
+ } else {
+ assert(pgc->program_map_offset != 0);
+ assert(pgc->cell_playback_offset != 0);
+ assert(pgc->cell_position_offset != 0);
+ }
+
+ if(pgc->command_tbl_offset != 0) {
+ pgc->command_tbl = malloc(sizeof(pgc_command_tbl_t));
+ if(!pgc->command_tbl)
+ return 0;
+
+ if(!ifoRead_PGC_COMMAND_TBL(ifofile, pgc->command_tbl,
+ offset + pgc->command_tbl_offset)) {
+ free(pgc->command_tbl);
+ return 0;
+ }
+ } else {
+ pgc->command_tbl = NULL;
+ }
+
+ if(pgc->program_map_offset != 0) {
+ pgc->program_map = malloc(pgc->nr_of_programs * sizeof(pgc_program_map_t));
+ if(!pgc->program_map) {
+ ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
+ return 0;
+ }
+ if(!ifoRead_PGC_PROGRAM_MAP(ifofile, pgc->program_map,pgc->nr_of_programs,
+ offset + pgc->program_map_offset)) {
+ ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
+ free(pgc->program_map);
+ return 0;
+ }
+ } else {
+ pgc->program_map = NULL;
+ }
+
+ if(pgc->cell_playback_offset != 0) {
+ pgc->cell_playback = malloc(pgc->nr_of_cells * sizeof(cell_playback_t));
+ if(!pgc->cell_playback) {
+ ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
+ if(pgc->program_map)
+ free(pgc->program_map);
+ return 0;
+ }
+ if(!ifoRead_CELL_PLAYBACK_TBL(ifofile, pgc->cell_playback,
+ pgc->nr_of_cells,
+ offset + pgc->cell_playback_offset)) {
+ ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
+ if(pgc->program_map)
+ free(pgc->program_map);
+ free(pgc->cell_playback);
+ return 0;
+ }
+ } else {
+ pgc->cell_playback = NULL;
+ }
+
+ if(pgc->cell_position_offset != 0) {
+ pgc->cell_position = malloc(pgc->nr_of_cells * sizeof(cell_position_t));
+ if(!pgc->cell_position) {
+ ifoFree_PGC(pgc);
+ return 0;
+ }
+ if(!ifoRead_CELL_POSITION_TBL(ifofile, pgc->cell_position,
+ pgc->nr_of_cells,
+ offset + pgc->cell_position_offset)) {
+ ifoFree_PGC(pgc);
+ return 0;
+ }
+ } else {
+ pgc->cell_position = NULL;
+ }
+
+ return 1;
+}
+
+int ifoRead_FP_PGC(ifo_handle_t *ifofile) {
+
+ if(!ifofile)
+ return 0;
+
+ if(!ifofile->vmgi_mat)
+ return 0;
+
+ if(ifofile->vmgi_mat->first_play_pgc == 0) /* mandatory */
+ return 0;
+
+ ifofile->first_play_pgc = (pgc_t *)malloc(sizeof(pgc_t));
+ if(!ifofile->first_play_pgc)
+ return 0;
+
+ if(!ifoRead_PGC(ifofile, ifofile->first_play_pgc,
+ ifofile->vmgi_mat->first_play_pgc)) {
+ free(ifofile->first_play_pgc);
+ ifofile->first_play_pgc = 0;
+ return 0;
+ }
+
+ return 1;
+}
+
+static void ifoFree_PGC(pgc_t *pgc) {
+ if(pgc) {
+ ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
+ if(pgc->program_map)
+ free(pgc->program_map);
+ if(pgc->cell_playback)
+ free(pgc->cell_playback);
+ if(pgc->cell_position)
+ free(pgc->cell_position);
+ }
+}
+
+void ifoFree_FP_PGC(ifo_handle_t *ifofile) {
+ if(!ifofile)
+ return;
+
+ if(ifofile->first_play_pgc) {
+ ifoFree_PGC(ifofile->first_play_pgc);
+ free(ifofile->first_play_pgc);
+ ifofile->first_play_pgc = 0;
+ }
+}
+
+
+int ifoRead_TT_SRPT(ifo_handle_t *ifofile) {
+ tt_srpt_t *tt_srpt;
+ int i, info_length;
+
+ if(!ifofile)
+ return 0;
+
+ if(!ifofile->vmgi_mat)
+ return 0;
+
+ if(ifofile->vmgi_mat->tt_srpt == 0) /* mandatory */
+ return 0;
+
+ if(!DVDFileSeek_(ifofile->file, ifofile->vmgi_mat->tt_srpt * DVD_BLOCK_LEN))
+ return 0;
+
+ tt_srpt = (tt_srpt_t *)malloc(sizeof(tt_srpt_t));
+ if(!tt_srpt)
+ return 0;
+
+ ifofile->tt_srpt = tt_srpt;
+
+ if(!(DVDReadBytes(ifofile->file, tt_srpt, TT_SRPT_SIZE))) {
+ fprintf(stderr, "libdvdread: Unable to read read TT_SRPT.\n");
+ free(tt_srpt);
+ return 0;
+ }
+
+ B2N_16(tt_srpt->nr_of_srpts);
+ B2N_32(tt_srpt->last_byte);
+
+ info_length = tt_srpt->last_byte + 1 - TT_SRPT_SIZE;
+
+ tt_srpt->title = (title_info_t *)malloc(info_length);
+ if(!tt_srpt->title) {
+ free(tt_srpt);
+ ifofile->tt_srpt = 0;
+ return 0;
+ }
+ if(!(DVDReadBytes(ifofile->file, tt_srpt->title, info_length))) {
+ fprintf(stderr, "libdvdread: Unable to read read TT_SRPT.\n");
+ ifoFree_TT_SRPT(ifofile);
+ return 0;
+ }
+
+ for(i = 0; i < tt_srpt->nr_of_srpts; i++) {
+ B2N_16(tt_srpt->title[i].nr_of_ptts);
+ B2N_16(tt_srpt->title[i].parental_id);
+ B2N_32(tt_srpt->title[i].title_set_sector);
+ }
+
+
+ CHECK_ZERO(tt_srpt->zero_1);
+ assert(tt_srpt->nr_of_srpts != 0);
+ assert(tt_srpt->nr_of_srpts < 100); // ??
+ assert((int)tt_srpt->nr_of_srpts * sizeof(title_info_t) <= info_length);
+
+ for(i = 0; i < tt_srpt->nr_of_srpts; i++) {
+ assert(tt_srpt->title[i].pb_ty.zero_1 == 0);
+ assert(tt_srpt->title[i].nr_of_angles != 0);
+ assert(tt_srpt->title[i].nr_of_angles < 10);
+ //assert(tt_srpt->title[i].nr_of_ptts != 0);
+ // XXX: this assertion breaks Ghostbusters:
+ assert(tt_srpt->title[i].nr_of_ptts < 1000); // ??
+ assert(tt_srpt->title[i].title_set_nr != 0);
+ assert(tt_srpt->title[i].title_set_nr < 100); // ??
+ assert(tt_srpt->title[i].vts_ttn != 0);
+ assert(tt_srpt->title[i].vts_ttn < 100); // ??
+ //assert(tt_srpt->title[i].title_set_sector != 0);
+ }
+
+ // Make this a function
+#if 0
+ if(memcmp((uint8_t *)tt_srpt->title +
+ tt_srpt->nr_of_srpts * sizeof(title_info_t),
+ my_friendly_zeros,
+ info_length - tt_srpt->nr_of_srpts * sizeof(title_info_t))) {
+ fprintf(stderr, "VMG_PTT_SRPT slack is != 0, ");
+ hexdump((uint8_t *)tt_srpt->title +
+ tt_srpt->nr_of_srpts * sizeof(title_info_t),
+ info_length - tt_srpt->nr_of_srpts * sizeof(title_info_t));
+ }
+#endif
+
+ return 1;
+}
+
+
+void ifoFree_TT_SRPT(ifo_handle_t *ifofile) {
+ if(!ifofile)
+ return;
+
+ if(ifofile->tt_srpt) {
+ free(ifofile->tt_srpt->title);
+ free(ifofile->tt_srpt);
+ ifofile->tt_srpt = 0;
+ }
+}
+
+
+int ifoRead_VTS_PTT_SRPT(ifo_handle_t *ifofile) {
+ vts_ptt_srpt_t *vts_ptt_srpt;
+ int info_length, i, j;
+ uint32_t *data;
+
+ if(!ifofile)
+ return 0;
+
+ if(!ifofile->vtsi_mat)
+ return 0;
+
+ if(ifofile->vtsi_mat->vts_ptt_srpt == 0) /* mandatory */
+ return 0;
+
+ if(!DVDFileSeek_(ifofile->file,
+ ifofile->vtsi_mat->vts_ptt_srpt * DVD_BLOCK_LEN))
+ return 0;
+
+ vts_ptt_srpt = (vts_ptt_srpt_t *)malloc(sizeof(vts_ptt_srpt_t));
+ if(!vts_ptt_srpt)
+ return 0;
+
+ ifofile->vts_ptt_srpt = vts_ptt_srpt;
+
+ if(!(DVDReadBytes(ifofile->file, vts_ptt_srpt, VTS_PTT_SRPT_SIZE))) {
+ fprintf(stderr, "libdvdread: Unable to read PTT search table.\n");
+ free(vts_ptt_srpt);
+ return 0;
+ }
+
+ B2N_16(vts_ptt_srpt->nr_of_srpts);
+ B2N_32(vts_ptt_srpt->last_byte);
+
+ CHECK_ZERO(vts_ptt_srpt->zero_1);
+ assert(vts_ptt_srpt->nr_of_srpts != 0);
+ assert(vts_ptt_srpt->nr_of_srpts < 100); // ??
+
+ info_length = vts_ptt_srpt->last_byte + 1 - VTS_PTT_SRPT_SIZE;
+
+ data = (uint32_t *)malloc(info_length);
+ if(!data) {
+ free(vts_ptt_srpt);
+ ifofile->vts_ptt_srpt = 0;
+ return 0;
+ }
+ if(!(DVDReadBytes(ifofile->file, data, info_length))) {
+ fprintf(stderr, "libdvdread: Unable to read PTT search table.\n");
+ free(vts_ptt_srpt);
+ free(data);
+ ifofile->vts_ptt_srpt = 0;
+ return 0;
+ }
+
+ for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) {
+ B2N_32(data[i]);
+ /* assert(data[i] + sizeof(ptt_info_t) <= vts_ptt_srpt->last_byte + 1);
+ Magic Knight Rayearth Daybreak is mastered very strange and has
+ Titles with 0 PTTs. They all have a data[i] offsets beyond the end of
+ of the vts_ptt_srpt structure. */
+ assert(data[i] + sizeof(ptt_info_t) <= vts_ptt_srpt->last_byte + 1 + 4);
+ }
+
+ vts_ptt_srpt->title = malloc(vts_ptt_srpt->nr_of_srpts * sizeof(ttu_t));
+ if(!vts_ptt_srpt->title) {
+ free(vts_ptt_srpt);
+ free(data);
+ ifofile->vts_ptt_srpt = 0;
+ return 0;
+ }
+ for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) {
+ int n;
+ if(i < vts_ptt_srpt->nr_of_srpts - 1)
+ n = (data[i+1] - data[i]);
+ else
+ n = (vts_ptt_srpt->last_byte + 1 - data[i]);
+ /* assert(n > 0 && (n % 4) == 0);
+ Magic Knight Rayearth Daybreak is mastered very strange and has
+ Titles with 0 PTTs. */
+ if(n < 0) n = 0;
+ assert(n % 4 == 0);
+
+ vts_ptt_srpt->title[i].nr_of_ptts = n / 4;
+ vts_ptt_srpt->title[i].ptt = malloc(n * sizeof(ptt_info_t));
+ if(!vts_ptt_srpt->title[i].ptt) {
+ for(n = 0; n < i; n++)
+ free(vts_ptt_srpt->title[n].ptt);
+ free(vts_ptt_srpt);
+ free(data);
+ ifofile->vts_ptt_srpt = 0;
+ return 0;
+ }
+ for(j = 0; j < vts_ptt_srpt->title[i].nr_of_ptts; j++) {
+ /* The assert placed here because of Magic Knight Rayearth Daybreak */
+ assert(data[i] + sizeof(ptt_info_t) <= vts_ptt_srpt->last_byte + 1);
+ vts_ptt_srpt->title[i].ptt[j].pgcn
+ = *(uint16_t*)(((char *)data) + data[i] + 4*j - VTS_PTT_SRPT_SIZE);
+ vts_ptt_srpt->title[i].ptt[j].pgn
+ = *(uint16_t*)(((char *)data) + data[i] + 4*j + 2 - VTS_PTT_SRPT_SIZE);
+ }
+ }
+ free(data);
+
+ for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) {
+ for(j = 0; j < vts_ptt_srpt->title[i].nr_of_ptts; j++) {
+ B2N_16(vts_ptt_srpt->title[i].ptt[j].pgcn);
+ B2N_16(vts_ptt_srpt->title[i].ptt[j].pgn);
+ }
+ }
+
+ for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) {
+ assert(vts_ptt_srpt->title[i].nr_of_ptts < 1000); // ??
+ for(j = 0; j < vts_ptt_srpt->title[i].nr_of_ptts; j++) {
+ assert(vts_ptt_srpt->title[i].ptt[j].pgcn != 0 );
+ assert(vts_ptt_srpt->title[i].ptt[j].pgcn < 1000); // ??
+ assert(vts_ptt_srpt->title[i].ptt[j].pgn != 0);
+ assert(vts_ptt_srpt->title[i].ptt[j].pgn < 100); // ??
+ }
+ }
+
+ return 1;
+}
+
+
+void ifoFree_VTS_PTT_SRPT(ifo_handle_t *ifofile) {
+ if(!ifofile)
+ return;
+
+ if(ifofile->vts_ptt_srpt) {
+ int i;
+ for(i = 0; i < ifofile->vts_ptt_srpt->nr_of_srpts; i++)
+ free(ifofile->vts_ptt_srpt->title[i].ptt);
+ free(ifofile->vts_ptt_srpt->title);
+ free(ifofile->vts_ptt_srpt);
+ ifofile->vts_ptt_srpt = 0;
+ }
+}
+
+
+int ifoRead_PTL_MAIT(ifo_handle_t *ifofile) {
+ ptl_mait_t *ptl_mait;
+ int info_length;
+ unsigned int i;
+
+ if(!ifofile)
+ return 0;
+
+ if(!ifofile->vmgi_mat)
+ return 0;
+
+ if(ifofile->vmgi_mat->ptl_mait == 0)
+ return 1;
+
+ if(!DVDFileSeek_(ifofile->file,
+ ifofile->vmgi_mat->ptl_mait * DVD_BLOCK_LEN))
+ return 0;
+
+ ptl_mait = (ptl_mait_t *)malloc(sizeof(ptl_mait_t));
+ if(!ptl_mait)
+ return 0;
+
+ ifofile->ptl_mait = ptl_mait;
+
+ if(!(DVDReadBytes(ifofile->file, ptl_mait, PTL_MAIT_SIZE))) {
+ free(ptl_mait);
+ ifofile->ptl_mait = 0;
+ return 0;
+ }
+
+ B2N_16(ptl_mait->nr_of_countries);
+ B2N_16(ptl_mait->nr_of_vtss);
+ B2N_32(ptl_mait->last_byte);
+
+ info_length = ptl_mait->last_byte + 1 - PTL_MAIT_SIZE;
+
+ assert(ptl_mait->nr_of_countries != 0);
+ assert(ptl_mait->nr_of_countries < 100); // ??
+ assert(ptl_mait->nr_of_vtss != 0);
+ assert(ptl_mait->nr_of_vtss < 100); // ??
+ assert(ptl_mait->nr_of_countries * PTL_MAIT_COUNTRY_SIZE <= info_length);
+
+ /* Change this to read and 'translate' the tables too.
+ I.e don't read so much here */
+ ptl_mait->countries = (ptl_mait_country_t *)malloc(info_length);
+ if(!ptl_mait->countries) {
+ free(ptl_mait);
+ ifofile->ptl_mait = 0;
+ return 0;
+ }
+ if(!(DVDReadBytes(ifofile->file, ptl_mait->countries, info_length))) {
+ fprintf(stderr, "libdvdread: Unable to read PTL_MAIT.\n");
+ ifoFree_PTL_MAIT(ifofile);
+ return 0;
+ }
+
+ for(i = 0; i < ptl_mait->nr_of_countries; i++) {
+ B2N_16(ptl_mait->countries[i].country_code);
+ B2N_16(ptl_mait->countries[i].pf_ptl_mai_start_byte);
+ }
+
+ for(i = 0; i < ptl_mait->nr_of_countries; i++) {
+ CHECK_ZERO(ptl_mait->countries[i].zero_1);
+ CHECK_ZERO(ptl_mait->countries[i].zero_2);
+ assert(ptl_mait->countries[i].pf_ptl_mai_start_byte +
+ 8 * (ptl_mait->nr_of_vtss + 1) * 2 <= ptl_mait->last_byte + 1);
+ }
+
+ return 1;
+}
+
+
+void ifoFree_PTL_MAIT(ifo_handle_t *ifofile) {
+ if(!ifofile)
+ return;
+
+ if(ifofile->ptl_mait) {
+ free(ifofile->ptl_mait->countries);
+ free(ifofile->ptl_mait);
+ ifofile->ptl_mait = 0;
+ }
+}
+
+int ifoRead_TITLE_C_ADT(ifo_handle_t *ifofile) {
+
+ if(!ifofile)
+ return 0;
+
+ if(!ifofile->vtsi_mat)
+ return 0;
+
+ if(ifofile->vtsi_mat->vts_c_adt == 0) /* mandatory */
+ return 0;
+
+ ifofile->vts_c_adt = (c_adt_t *)malloc(sizeof(c_adt_t));
+ if(!ifofile->vts_c_adt)
+ return 0;
+
+ if(!ifoRead_C_ADT_internal(ifofile, ifofile->vts_c_adt,
+ ifofile->vtsi_mat->vts_c_adt)) {
+ free(ifofile->vts_c_adt);
+ ifofile->vts_c_adt = 0;
+ return 0;
+ }
+
+ return 1;
+}
+
+int ifoRead_C_ADT(ifo_handle_t *ifofile) {
+ unsigned int sector;
+
+ if(!ifofile)
+ return 0;
+
+ if(ifofile->vmgi_mat) {
+ if(ifofile->vmgi_mat->vmgm_c_adt == 0)
+ return 1;
+ sector = ifofile->vmgi_mat->vmgm_c_adt;
+ } else if(ifofile->vtsi_mat) {
+ if(ifofile->vtsi_mat->vtsm_c_adt == 0)
+ return 1;
+ sector = ifofile->vtsi_mat->vtsm_c_adt;
+ } else {
+ return 0;
+ }
+
+ ifofile->menu_c_adt = (c_adt_t *)malloc(sizeof(c_adt_t));
+ if(!ifofile->menu_c_adt)
+ return 0;
+
+ if(!ifoRead_C_ADT_internal(ifofile, ifofile->menu_c_adt, sector)) {
+ free(ifofile->menu_c_adt);
+ ifofile->menu_c_adt = 0;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ifoRead_C_ADT_internal(ifo_handle_t *ifofile,
+ c_adt_t *c_adt, unsigned int sector) {
+ int i, info_length;
+
+ if(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN))
+ return 0;
+
+ if(!(DVDReadBytes(ifofile->file, c_adt, C_ADT_SIZE)))
+ return 0;
+
+ B2N_16(c_adt->nr_of_vobs);
+ B2N_32(c_adt->last_byte);
+
+ info_length = c_adt->last_byte + 1 - C_ADT_SIZE;
+
+ CHECK_ZERO(c_adt->zero_1);
+ /* assert(c_adt->nr_of_vobs > 0);
+ Magic Knight Rayearth Daybreak is mastered very strange and has
+ Titles with a VOBS that has no cells. */
+ assert(info_length % sizeof(cell_adr_t) == 0);
+ assert(info_length / sizeof(cell_adr_t) >= c_adt->nr_of_vobs);
+
+ c_adt->cell_adr_table = (cell_adr_t *)malloc(info_length);
+ if(!c_adt->cell_adr_table)
+ return 0;
+
+ if(info_length &&
+ !(DVDReadBytes(ifofile->file, c_adt->cell_adr_table, info_length))) {
+ free(c_adt->cell_adr_table);
+ return 0;
+ }
+
+ for(i = 0; i < info_length/sizeof(cell_adr_t); i++) {
+ B2N_16(c_adt->cell_adr_table[i].vob_id);
+ B2N_32(c_adt->cell_adr_table[i].start_sector);
+ B2N_32(c_adt->cell_adr_table[i].last_sector);
+
+ CHECK_ZERO(c_adt->cell_adr_table[i].zero_1);
+ assert(c_adt->cell_adr_table[i].vob_id > 0);
+ assert(c_adt->cell_adr_table[i].vob_id <= c_adt->nr_of_vobs);
+ assert(c_adt->cell_adr_table[i].cell_id > 0);
+ assert(c_adt->cell_adr_table[i].start_sector <
+ c_adt->cell_adr_table[i].last_sector);
+ }
+
+ return 1;
+}
+
+
+static void ifoFree_C_ADT_internal(c_adt_t *c_adt) {
+ if(c_adt) {
+ free(c_adt->cell_adr_table);
+ free(c_adt);
+ }
+}
+
+void ifoFree_C_ADT(ifo_handle_t *ifofile) {
+ if(!ifofile)
+ return;
+
+ ifoFree_C_ADT_internal(ifofile->menu_c_adt);
+ ifofile->menu_c_adt = 0;
+}
+
+void ifoFree_TITLE_C_ADT(ifo_handle_t *ifofile) {
+ if(!ifofile)
+ return;
+
+ ifoFree_C_ADT_internal(ifofile->vts_c_adt);
+ ifofile->vts_c_adt = 0;
+}
+
+int ifoRead_TITLE_VOBU_ADMAP(ifo_handle_t *ifofile) {
+ if(!ifofile)
+ return 0;
+
+ if(!ifofile->vtsi_mat)
+ return 0;
+
+ if(ifofile->vtsi_mat->vts_vobu_admap == 0) /* mandatory */
+ return 0;
+
+ ifofile->vts_vobu_admap = (vobu_admap_t *)malloc(sizeof(vobu_admap_t));
+ if(!ifofile->vts_vobu_admap)
+ return 0;
+
+ if(!ifoRead_VOBU_ADMAP_internal(ifofile, ifofile->vts_vobu_admap,
+ ifofile->vtsi_mat->vts_vobu_admap)) {
+ free(ifofile->vts_vobu_admap);
+ ifofile->vts_vobu_admap = 0;
+ return 0;
+ }
+
+ return 1;
+}
+
+int ifoRead_VOBU_ADMAP(ifo_handle_t *ifofile) {
+ unsigned int sector;
+
+ if(!ifofile)
+ return 0;
+
+ if(ifofile->vmgi_mat) {
+ if(ifofile->vmgi_mat->vmgm_vobu_admap == 0)
+ return 1;
+ sector = ifofile->vmgi_mat->vmgm_vobu_admap;
+ } else if(ifofile->vtsi_mat) {
+ if(ifofile->vtsi_mat->vtsm_vobu_admap == 0)
+ return 1;
+ sector = ifofile->vtsi_mat->vtsm_vobu_admap;
+ } else {
+ return 0;
+ }
+
+ ifofile->menu_vobu_admap = (vobu_admap_t *)malloc(sizeof(vobu_admap_t));
+ if(!ifofile->menu_vobu_admap)
+ return 0;
+
+ if(!ifoRead_VOBU_ADMAP_internal(ifofile, ifofile->menu_vobu_admap, sector)) {
+ free(ifofile->menu_vobu_admap);
+ ifofile->menu_vobu_admap = 0;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ifoRead_VOBU_ADMAP_internal(ifo_handle_t *ifofile,
+ vobu_admap_t *vobu_admap,
+ unsigned int sector) {
+ unsigned int i;
+ int info_length;
+
+ if(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN))
+ return 0;
+
+ if(!(DVDReadBytes(ifofile->file, vobu_admap, VOBU_ADMAP_SIZE)))
+ return 0;
+
+ B2N_32(vobu_admap->last_byte);
+
+ info_length = vobu_admap->last_byte + 1 - VOBU_ADMAP_SIZE;
+ /* assert(info_length > 0);
+ Magic Knight Rayearth Daybreak is mastered very strange and has
+ Titles with a VOBS that has no VOBUs. */
+ assert(info_length % sizeof(uint32_t) == 0);
+
+ vobu_admap->vobu_start_sectors = (uint32_t *)malloc(info_length);
+ if(!vobu_admap->vobu_start_sectors) {
+ return 0;
+ }
+ if(info_length &&
+ !(DVDReadBytes(ifofile->file,
+ vobu_admap->vobu_start_sectors, info_length))) {
+ free(vobu_admap->vobu_start_sectors);
+ return 0;
+ }
+
+ for(i = 0; i < info_length/sizeof(uint32_t); i++)
+ B2N_32(vobu_admap->vobu_start_sectors[i]);
+
+ return 1;
+}
+
+
+static void ifoFree_VOBU_ADMAP_internal(vobu_admap_t *vobu_admap) {
+ if(vobu_admap) {
+ free(vobu_admap->vobu_start_sectors);
+ free(vobu_admap);
+ }
+}
+
+void ifoFree_VOBU_ADMAP(ifo_handle_t *ifofile) {
+ if(!ifofile)
+ return;
+
+ ifoFree_VOBU_ADMAP_internal(ifofile->menu_vobu_admap);
+ ifofile->menu_vobu_admap = 0;
+}
+
+void ifoFree_TITLE_VOBU_ADMAP(ifo_handle_t *ifofile) {
+ if(!ifofile)
+ return;
+
+ ifoFree_VOBU_ADMAP_internal(ifofile->vts_vobu_admap);
+ ifofile->vts_vobu_admap = 0;
+}
+
+int ifoRead_PGCIT(ifo_handle_t *ifofile) {
+
+ if(!ifofile)
+ return 0;
+
+ if(!ifofile->vtsi_mat)
+ return 0;
+
+ if(ifofile->vtsi_mat->vts_pgcit == 0) /* mandatory */
+ return 0;
+
+ ifofile->vts_pgcit = (pgcit_t *)malloc(sizeof(pgcit_t));
+ if(!ifofile->vts_pgcit)
+ return 0;
+
+ if(!ifoRead_PGCIT_internal(ifofile, ifofile->vts_pgcit,
+ ifofile->vtsi_mat->vts_pgcit * DVD_BLOCK_LEN)) {
+ free(ifofile->vts_pgcit);
+ ifofile->vts_pgcit = 0;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ifoRead_PGCIT_internal(ifo_handle_t *ifofile, pgcit_t *pgcit,
+ unsigned int offset) {
+ int i, info_length;
+ uint8_t *data, *ptr;
+
+ if(!DVDFileSeek_(ifofile->file, offset))
+ return 0;
+
+ if(!(DVDReadBytes(ifofile->file, pgcit, PGCIT_SIZE)))
+ return 0;
+
+ B2N_16(pgcit->nr_of_pgci_srp);
+ B2N_32(pgcit->last_byte);
+
+ CHECK_ZERO(pgcit->zero_1);
+ /* assert(pgcit->nr_of_pgci_srp != 0);
+ Magic Knight Rayearth Daybreak is mastered very strange and has
+ Titles with 0 PTTs. */
+ assert(pgcit->nr_of_pgci_srp < 10000); // ?? seen max of 1338
+
+ info_length = pgcit->nr_of_pgci_srp * PGCI_SRP_SIZE;
+ data = malloc(info_length);
+ if(!data)
+ return 0;
+
+ if(info_length && !(DVDReadBytes(ifofile->file, data, info_length))) {
+ free(data);
+ return 0;
+ }
+
+ pgcit->pgci_srp = malloc(pgcit->nr_of_pgci_srp * sizeof(pgci_srp_t));
+ if(!pgcit->pgci_srp) {
+ free(data);
+ return 0;
+ }
+ ptr = data;
+ for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
+ memcpy(&pgcit->pgci_srp[i], ptr, PGCI_LU_SIZE);
+ ptr += PGCI_LU_SIZE;
+ B2N_16(pgcit->pgci_srp[i].ptl_id_mask);
+ B2N_32(pgcit->pgci_srp[i].pgc_start_byte);
+ assert(pgcit->pgci_srp[i].unknown1 == 0);
+ }
+ free(data);
+
+ for(i = 0; i < pgcit->nr_of_pgci_srp; i++)
+ assert(pgcit->pgci_srp[i].pgc_start_byte + PGC_SIZE <= pgcit->last_byte+1);
+
+ for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
+ pgcit->pgci_srp[i].pgc = malloc(sizeof(pgc_t));
+ if(!pgcit->pgci_srp[i].pgc) {
+ int j;
+ for(j = 0; j < i; j++) {
+ ifoFree_PGC(pgcit->pgci_srp[j].pgc);
+ free(pgcit->pgci_srp[j].pgc);
+ }
+ return 0;
+ }
+ if(!ifoRead_PGC(ifofile, pgcit->pgci_srp[i].pgc,
+ offset + pgcit->pgci_srp[i].pgc_start_byte)) {
+ int j;
+ for(j = 0; j < i; j++) {
+ ifoFree_PGC(pgcit->pgci_srp[j].pgc);
+ free(pgcit->pgci_srp[j].pgc);
+ }
+ free(pgcit->pgci_srp);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void ifoFree_PGCIT_internal(pgcit_t *pgcit) {
+ if(pgcit) {
+ int i;
+ for(i = 0; i < pgcit->nr_of_pgci_srp; i++)
+ ifoFree_PGC(pgcit->pgci_srp[i].pgc);
+ free(pgcit->pgci_srp);
+ }
+}
+
+void ifoFree_PGCIT(ifo_handle_t *ifofile) {
+ if(!ifofile)
+ return;
+
+ if(ifofile->vts_pgcit) {
+ ifoFree_PGCIT_internal(ifofile->vts_pgcit);
+ free(ifofile->vts_pgcit);
+ ifofile->vts_pgcit = 0;
+ }
+}
+
+
+int ifoRead_PGCI_UT(ifo_handle_t *ifofile) {
+ pgci_ut_t *pgci_ut;
+ unsigned int sector;
+ unsigned int i;
+ int info_length;
+ uint8_t *data, *ptr;
+
+ if(!ifofile)
+ return 0;
+
+ if(ifofile->vmgi_mat) {
+ if(ifofile->vmgi_mat->vmgm_pgci_ut == 0)
+ return 1;
+ sector = ifofile->vmgi_mat->vmgm_pgci_ut;
+ } else if(ifofile->vtsi_mat) {
+ if(ifofile->vtsi_mat->vtsm_pgci_ut == 0)
+ return 1;
+ sector = ifofile->vtsi_mat->vtsm_pgci_ut;
+ } else {
+ return 0;
+ }
+
+ ifofile->pgci_ut = (pgci_ut_t *)malloc(sizeof(pgci_ut_t));
+ if(!ifofile->pgci_ut)
+ return 0;
+
+ if(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN)) {
+ free(ifofile->pgci_ut);
+ ifofile->pgci_ut = 0;
+ return 0;
+ }
+
+ if(!(DVDReadBytes(ifofile->file, ifofile->pgci_ut, PGCI_UT_SIZE))) {
+ free(ifofile->pgci_ut);
+ ifofile->pgci_ut = 0;
+ return 0;
+ }
+
+ pgci_ut = ifofile->pgci_ut;
+
+ B2N_16(pgci_ut->nr_of_lus);
+ B2N_32(pgci_ut->last_byte);
+
+ CHECK_ZERO(pgci_ut->zero_1);
+ assert(pgci_ut->nr_of_lus != 0);
+ assert(pgci_ut->nr_of_lus < 100); // ?? 3-4 ?
+ assert((uint32_t)pgci_ut->nr_of_lus * PGCI_LU_SIZE < pgci_ut->last_byte);
+
+ info_length = pgci_ut->nr_of_lus * PGCI_LU_SIZE;
+ data = malloc(info_length);
+ if(!data) {
+ free(pgci_ut);
+ ifofile->pgci_ut = 0;
+ return 0;
+ }
+ if(!(DVDReadBytes(ifofile->file, data, info_length))) {
+ free(data);
+ free(pgci_ut);
+ ifofile->pgci_ut = 0;
+ return 0;
+ }
+
+ pgci_ut->lu = malloc(pgci_ut->nr_of_lus * sizeof(pgci_lu_t));
+ if(!pgci_ut->lu) {
+ free(data);
+ free(pgci_ut);
+ ifofile->pgci_ut = 0;
+ return 0;
+ }
+ ptr = data;
+ for(i = 0; i < pgci_ut->nr_of_lus; i++) {
+ memcpy(&pgci_ut->lu[i], ptr, PGCI_LU_SIZE);
+ ptr += PGCI_LU_SIZE;
+ B2N_16(pgci_ut->lu[i].lang_code);
+ B2N_32(pgci_ut->lu[i].lang_start_byte);
+ }
+ free(data);
+
+ for(i = 0; i < pgci_ut->nr_of_lus; i++) {
+ CHECK_ZERO(pgci_ut->lu[i].zero_1);
+ // Maybe this is only defined for v1.1 and later titles?
+ /* If the bits in 'lu[i].exists' are enumerated abcd efgh then:
+ VTS_x_yy.IFO VIDEO_TS.IFO
+ a == 0x83 "Root" 0x82 "Title"
+ b == 0x84 "Subpicture"
+ c == 0x85 "Audio"
+ d == 0x86 "Angle"
+ e == 0x87 "PTT"
+ */
+ assert((pgci_ut->lu[i].exists & 0x07) == 0);
+ }
+
+ for(i = 0; i < pgci_ut->nr_of_lus; i++) {
+ pgci_ut->lu[i].pgcit = malloc(sizeof(pgcit_t));
+ if(!pgci_ut->lu[i].pgcit) {
+ unsigned int j;
+ for(j = 0; j < i; j++) {
+ ifoFree_PGCIT_internal(pgci_ut->lu[j].pgcit);
+ free(pgci_ut->lu[j].pgcit);
+ }
+ free(pgci_ut->lu);
+ free(pgci_ut);
+ ifofile->pgci_ut = 0;
+ return 0;
+ }
+ if(!ifoRead_PGCIT_internal(ifofile, pgci_ut->lu[i].pgcit,
+ sector * DVD_BLOCK_LEN
+ + pgci_ut->lu[i].lang_start_byte)) {
+ unsigned int j;
+ for(j = 0; j < i; j++) {
+ ifoFree_PGCIT_internal(pgci_ut->lu[j].pgcit);
+ free(pgci_ut->lu[j].pgcit);
+ }
+ free(pgci_ut->lu[i].pgcit);
+ free(pgci_ut->lu);
+ free(pgci_ut);
+ ifofile->pgci_ut = 0;
+ return 0;
+ }
+ // FIXME: Iterate and verify that all menus that should exists accordingly
+ // to pgci_ut->lu[i].exists really do?
+ }
+
+ return 1;
+}
+
+
+void ifoFree_PGCI_UT(ifo_handle_t *ifofile) {
+ unsigned int i;
+
+ if(!ifofile)
+ return;
+
+ if(ifofile->pgci_ut) {
+ for(i = 0; i < ifofile->pgci_ut->nr_of_lus; i++) {
+ ifoFree_PGCIT_internal(ifofile->pgci_ut->lu[i].pgcit);
+ free(ifofile->pgci_ut->lu[i].pgcit);
+ }
+ free(ifofile->pgci_ut->lu);
+ free(ifofile->pgci_ut);
+ ifofile->pgci_ut = 0;
+ }
+}
+
+static int ifoRead_VTS_ATTRIBUTES(ifo_handle_t *ifofile,
+ vts_attributes_t *vts_attributes,
+ unsigned int offset) {
+ unsigned int i;
+
+ if(!DVDFileSeek_(ifofile->file, offset))
+ return 0;
+
+ if(!(DVDReadBytes(ifofile->file, vts_attributes, sizeof(vts_attributes_t))))
+ return 0;
+
+ B2N_32(vts_attributes->last_byte);
+ B2N_32(vts_attributes->vts_cat);
+ B2N_16(vts_attributes->vtsm_audio_attr.lang_code);
+ B2N_16(vts_attributes->vtsm_subp_attr.lang_code);
+ for(i = 0; i < 8; i++)
+ B2N_16(vts_attributes->vtstt_audio_attr[i].lang_code);
+ for(i = 0; i < 32; i++)
+ B2N_16(vts_attributes->vtstt_subp_attr[i].lang_code);
+
+ CHECK_ZERO(vts_attributes->zero_1);
+ CHECK_ZERO(vts_attributes->zero_2);
+ CHECK_ZERO(vts_attributes->zero_3);
+ CHECK_ZERO(vts_attributes->zero_4);
+ CHECK_ZERO(vts_attributes->zero_5);
+ CHECK_ZERO(vts_attributes->zero_6);
+ CHECK_ZERO(vts_attributes->zero_7);
+ assert(vts_attributes->nr_of_vtsm_audio_streams <= 1);
+ assert(vts_attributes->nr_of_vtsm_subp_streams <= 1);
+ assert(vts_attributes->nr_of_vtstt_audio_streams <= 8);
+ for(i = vts_attributes->nr_of_vtstt_audio_streams; i < 8; i++)
+ CHECK_ZERO(vts_attributes->vtstt_audio_attr[i]);
+ assert(vts_attributes->nr_of_vtstt_subp_streams <= 32);
+ {
+ int nr_coded;
+ assert(vts_attributes->last_byte + 1 - VTS_ATTRIBUTES_MIN_SIZE >= 0);
+ nr_coded = (vts_attributes->last_byte + 1 - VTS_ATTRIBUTES_MIN_SIZE)/6;
+ // This is often nr_coded = 70, how do you know how many there really are?
+ if(nr_coded > 32) { // We haven't read more from disk/file anyway
+ nr_coded = 32;
+ }
+ assert(vts_attributes->nr_of_vtstt_subp_streams <= nr_coded);
+ for(i = vts_attributes->nr_of_vtstt_subp_streams; i < nr_coded; i++)
+ CHECK_ZERO(vts_attributes->vtstt_subp_attr[i]);
+ }
+
+ return 1;
+}
+
+
+
+int ifoRead_VTS_ATRT(ifo_handle_t *ifofile) {
+ vts_atrt_t *vts_atrt;
+ unsigned int i, info_length, sector;
+ uint32_t *data;
+
+ if(!ifofile)
+ return 0;
+
+ if(!ifofile->vmgi_mat)
+ return 0;
+
+ if(ifofile->vmgi_mat->vts_atrt == 0) /* mandatory */
+ return 0;
+
+ sector = ifofile->vmgi_mat->vts_atrt;
+ if(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN))
+ return 0;
+
+ vts_atrt = (vts_atrt_t *)malloc(sizeof(vts_atrt_t));
+ if(!vts_atrt)
+ return 0;
+
+ ifofile->vts_atrt = vts_atrt;
+
+ if(!(DVDReadBytes(ifofile->file, vts_atrt, VTS_ATRT_SIZE))) {
+ free(vts_atrt);
+ ifofile->vts_atrt = 0;
+ return 0;
+ }
+
+ B2N_16(vts_atrt->nr_of_vtss);
+ B2N_32(vts_atrt->last_byte);
+
+ CHECK_ZERO(vts_atrt->zero_1);
+ assert(vts_atrt->nr_of_vtss != 0);
+ assert(vts_atrt->nr_of_vtss < 100); //??
+ assert((uint32_t)vts_atrt->nr_of_vtss * (4 + VTS_ATTRIBUTES_MIN_SIZE) +
+ VTS_ATRT_SIZE < vts_atrt->last_byte + 1);
+
+ info_length = vts_atrt->nr_of_vtss * sizeof(uint32_t);
+ data = (uint32_t *)malloc(info_length);
+ if(!data) {
+ free(vts_atrt);
+ ifofile->vts_atrt = 0;
+ return 0;
+ }
+ if(!(DVDReadBytes(ifofile->file, data, info_length))) {
+ free(data);
+ free(vts_atrt);
+ ifofile->vts_atrt = 0;
+ return 0;
+ }
+
+ for(i = 0; i < vts_atrt->nr_of_vtss; i++) {
+ B2N_32(data[i]);
+ assert(data[i] + VTS_ATTRIBUTES_MIN_SIZE < vts_atrt->last_byte + 1);
+ }
+
+ info_length = vts_atrt->nr_of_vtss * sizeof(vts_attributes_t);
+ vts_atrt->vts = (vts_attributes_t *)malloc(info_length);
+ if(!vts_atrt->vts) {
+ free(data);
+ free(vts_atrt);
+ ifofile->vts_atrt = 0;
+ return 0;
+ }
+ for(i = 0; i < vts_atrt->nr_of_vtss; i++) {
+ unsigned int offset = data[i];
+ if(!ifoRead_VTS_ATTRIBUTES(ifofile, &(vts_atrt->vts[i]),
+ (sector * DVD_BLOCK_LEN) + offset)) {
+ free(data);
+ free(vts_atrt);
+ ifofile->vts_atrt = 0;
+ return 0;
+ }
+
+ // This assert cant be in ifoRead_VTS_ATTRIBUTES
+ assert(offset + vts_atrt->vts[i].last_byte <= vts_atrt->last_byte + 1);
+ // Is this check correct?
+ }
+ free(data);
+
+ return 1;
+}
+
+
+void ifoFree_VTS_ATRT(ifo_handle_t *ifofile) {
+ if(!ifofile)
+ return;
+
+ if(ifofile->vts_atrt) {
+ free(ifofile->vts_atrt->vts);
+ free(ifofile->vts_atrt);
+ ifofile->vts_atrt = 0;
+ }
+}
+
+
+int ifoRead_TXTDT_MGI(ifo_handle_t *ifofile) {
+ txtdt_mgi_t *txtdt_mgi;
+
+ if(!ifofile)
+ return 0;
+
+ if(!ifofile->vmgi_mat)
+ return 0;
+
+ /* Return successfully if there is nothing to read. */
+ if(ifofile->vmgi_mat->txtdt_mgi == 0)
+ return 1;
+
+ if(!DVDFileSeek_(ifofile->file,
+ ifofile->vmgi_mat->txtdt_mgi * DVD_BLOCK_LEN))
+ return 0;
+
+ txtdt_mgi = (txtdt_mgi_t *)malloc(sizeof(txtdt_mgi_t));
+ if(!txtdt_mgi) {
+ return 0;
+ }
+ ifofile->txtdt_mgi = txtdt_mgi;
+
+ if(!(DVDReadBytes(ifofile->file, txtdt_mgi, TXTDT_MGI_SIZE))) {
+ fprintf(stderr, "libdvdread: Unable to read TXTDT_MGI.\n");
+ free(txtdt_mgi);
+ ifofile->txtdt_mgi = 0;
+ return 0;
+ }
+
+ // fprintf(stderr, "-- Not done yet --\n");
+ return 1;
+}
+
+void ifoFree_TXTDT_MGI(ifo_handle_t *ifofile) {
+ if(!ifofile)
+ return;
+
+ if(ifofile->txtdt_mgi) {
+ free(ifofile->txtdt_mgi);
+ ifofile->txtdt_mgi = 0;
+ }
+}
+
--- /dev/null
+/**
+ * Copyright (C) 2000 Björn Englund <d4bjorn@dtek.chalmers.se>,
+ * Håkan Hjort <d95hjort@dtek.chalmers.se>
+ *
+ * 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 IFO_READ_H_INCLUDED
+#define IFO_READ_H_INCLUDED
+
+#include <dvdread/ifo_types.h>
+#include <dvdread/dvd_reader.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Opens an IFO and reads in all the data for the IFO file corresponding to the
+ * given title. If title 0 is given, the video manager IFO file is read.
+ * Returns a handle to a completely parsed structure.
+ */
+ifo_handle_t *ifoOpen(dvd_reader_t *dvd, int title);
+
+/**
+ * Opens an IFO and reads in _only_ the vmgi_mat data. This call can be used
+ * together with the calls below to read in each segment of the IFO file on
+ * demand.
+ */
+ifo_handle_t *ifoOpenVMGI(dvd_reader_t *dvd);
+
+/**
+ * Opens an IFO and reads in _only_ the vtsi_mat data. This call can be used
+ * together with the calls below to read in each segment of the IFO file on
+ * demand.
+ */
+ifo_handle_t *ifoOpenVTSI(dvd_reader_t *dvd, int title);
+
+/**
+ * Cleans up the IFO information. This will free all data allocated for the
+ * substructures.
+ */
+void ifoClose(ifo_handle_t *ifofile);
+
+/**
+ * The following functions are for reading only part of the VMGI/VTSI files.
+ * Returns 1 if the data was successfully read and 0 on error.
+ */
+
+/**
+ * Read in the Parental Management Information table, filling the
+ * ifofile->ptl_mait structure and its substructures. This data is only
+ * located in the video manager information file. This fills the
+ * ifofile->ptl_mait structure and all its substructures.
+ */
+int ifoRead_PTL_MAIT(ifo_handle_t *ifofile);
+
+/**
+ * Read in the attribute table for the main menu vob, filling the
+ * ifofile->vts_atrt structure and its substructures. Only located in the
+ * video manager information file. This fills in the ifofile->vts_atrt
+ * structure and all its substructures.
+ */
+int ifoRead_VTS_ATRT(ifo_handle_t *ifofile);
+
+/**
+ * Reads the title info for the main menu, filling the ifofile->tt_srpt
+ * structure and its substructures. This data is only located in the video
+ * manager information file. This structure is mandatory in the IFO file.
+ */
+int ifoRead_TT_SRPT(ifo_handle_t *ifofile);
+
+/**
+ * Reads in the part of title search pointer table, filling the
+ * ifofile->vts_ptt_srpt structure and its substructures. This data is only
+ * located in the video title set information file. This structure is
+ * mandatory, and must be included in the VTSI file.
+ */
+int ifoRead_VTS_PTT_SRPT(ifo_handle_t *ifofile);
+
+/**
+ * Reads in the first play program chain data, filling the
+ * ifofile->first_play_pgc structure. This data is only located in the video
+ * manager information file. This structure is mandatory, and must be included
+ * in the VMGI file.
+ */
+int ifoRead_FP_PGC(ifo_handle_t *ifofile);
+
+/**
+ * Reads in the program chain information table for the video title set. Fills
+ * in the ifofile->vts_pgcit structure and its substructures, which includes
+ * the data for each program chain in the set. This data is only located in
+ * the video title set information file. This structure is mandatory, and must
+ * be included in the VTSI file.
+ */
+int ifoRead_PGCIT(ifo_handle_t *ifofile);
+
+/**
+ * Reads in the menu PGCI unit table for the menu VOB. For the video manager,
+ * this corresponds to the VIDEO_TS.VOB file, and for each title set, this
+ * corresponds to the VTS_XX_0.VOB file. This data is located in both the
+ * video manager and video title set information files. For VMGI files, this
+ * fills the ifofile->vmgi_pgci_ut structure and all its substructures. For
+ * VTSI files, this fills the ifofile->vtsm_pgci_ut structure.
+ */
+int ifoRead_PGCI_UT(ifo_handle_t *ifofile);
+
+/**
+ * Reads in the cell address table for the menu VOB. For the video manager,
+ * this corresponds to the VIDEO_TS.VOB file, and for each title set, this
+ * corresponds to the VTS_XX_0.VOB file. This data is located in both the
+ * video manager and video title set information files. For VMGI files, this
+ * fills the ifofile->vmgm_c_adt structure and all its substructures. For VTSI
+ * files, this fills the ifofile->vtsm_c_adt structure.
+ */
+int ifoRead_C_ADT(ifo_handle_t *ifofile);
+
+/**
+ * Reads in the cell address table for the video title set corresponding to
+ * this IFO file. This data is only located in the video title set information
+ * file. This structure is mandatory, and must be included in the VTSI file.
+ * This call fills the ifofile->vts_c_adt structure and its substructures.
+ */
+int ifoRead_TITLE_C_ADT(ifo_handle_t *ifofile);
+
+/**
+ * Reads in the VOBU address map for the menu VOB. For the video manager, this
+ * corresponds to the VIDEO_TS.VOB file, and for each title set, this
+ * corresponds to the VTS_XX_0.VOB file. This data is located in both the
+ * video manager and video title set information files. For VMGI files, this
+ * fills the ifofile->vmgm_vobu_admap structure and all its substructures. For
+ * VTSI files, this fills the ifofile->vtsm_vobu_admap structure.
+ */
+int ifoRead_VOBU_ADMAP(ifo_handle_t *ifofile);
+
+/**
+ * Reads in the VOBU address map for the associated video title set. This data
+ * is only located in the video title set information file. This structure is
+ * mandatory, and must be included in the VTSI file. Fills the
+ * ifofile->vts_vobu_admap structure and its substructures.
+ */
+int ifoRead_TITLE_VOBU_ADMAP(ifo_handle_t *ifofile);
+
+/**
+ * Reads in the text data strings for the DVD. Fills the ifofile->txtdt_mgi
+ * structure and all its substructures. This data is only located in the video
+ * manager information file. This structure is mandatory, and must be included
+ * in the VMGI file.
+ */
+int ifoRead_TXTDT_MGI(ifo_handle_t *ifofile);
+
+/**
+ * The following functions are used for freeing parsed sections of the
+ * ifo_handle_t structure and the allocated substructures. The free calls
+ * below are safe: they will not mind if you attempt to free part of an IFO
+ * file which was not read in or which does not exist.
+ */
+void ifoFree_PTL_MAIT(ifo_handle_t *ifofile);
+void ifoFree_VTS_ATRT(ifo_handle_t *ifofile);
+void ifoFree_TT_SRPT(ifo_handle_t *ifofile);
+void ifoFree_VTS_PTT_SRPT(ifo_handle_t *ifofile);
+void ifoFree_FP_PGC(ifo_handle_t *ifofile);
+void ifoFree_PGCIT(ifo_handle_t *ifofile);
+void ifoFree_PGCI_UT(ifo_handle_t *ifofile);
+void ifoFree_C_ADT(ifo_handle_t *ifofile);
+void ifoFree_TITLE_C_ADT(ifo_handle_t *ifofile);
+void ifoFree_VOBU_ADMAP(ifo_handle_t *ifofile);
+void ifoFree_TITLE_VOBU_ADMAP(ifo_handle_t *ifofile);
+void ifoFree_TXTDT_MGI(ifo_handle_t *ifofile);
+
+#ifdef __cplusplus
+};
+#endif
+#endif /* IFO_READ_H_INCLUDED */
--- /dev/null
+/**
+ * Copyright (C) 2000 Björn Englund <d4bjorn@dtek.chalmers.se>,
+ * Håkan Hjort <d95hjort@dtek.chalmers.se>
+ *
+ * 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 IFO_TYPES_H_INCLUDED
+#define IFO_TYPES_H_INCLUDED
+
+#include <inttypes.h>
+#include <dvdread/dvd_reader.h>
+
+
+#undef ATTRIBUTE_PACKED
+#undef PRAGMA_PACK_BEGIN
+#undef PRAGMA_PACK_END
+
+#if defined(__GNUC__)
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+#define ATTRIBUTE_PACKED __attribute__ ((packed))
+#define PRAGMA_PACK 0
+#endif
+#endif
+
+#if !defined(ATTRIBUTE_PACKED)
+#define ATTRIBUTE_PACKED
+#define PRAGMA_PACK 1
+#endif
+
+#if PRAGMA_PACK
+#pragma pack(1)
+#endif
+
+
+/**
+ * Common
+ *
+ * The following structures are used in both the VMGI and VTSI.
+ */
+
+
+/**
+ * DVD Time Information.
+ */
+typedef struct {
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
+ uint8_t frame_u; // The two high bits are the frame rate.
+} ATTRIBUTE_PACKED dvd_time_t;
+
+/**
+ * Type to store per-command data.
+ */
+typedef struct {
+ uint8_t bytes[8];
+} ATTRIBUTE_PACKED vm_cmd_t;
+#define COMMAND_DATA_SIZE 8
+
+
+/**
+ * Video Attributes.
+ */
+typedef struct {
+#ifdef WORDS_BIGENDIAN
+ unsigned int mpeg_version : 2;
+ unsigned int video_format : 2;
+ unsigned int display_aspect_ratio : 2;
+ unsigned int permitted_df : 2;
+
+ unsigned int line21_cc_1 : 1;
+ unsigned int line21_cc_2 : 1;
+ unsigned int unknown1 : 2;
+
+ unsigned int picture_size : 2;
+ unsigned int letterboxed : 1;
+ unsigned int film_mode : 1;
+#else
+ unsigned int permitted_df : 2;
+ unsigned int display_aspect_ratio : 2;
+ unsigned int video_format : 2;
+ unsigned int mpeg_version : 2;
+
+ unsigned int film_mode : 1;
+ unsigned int letterboxed : 1;
+ unsigned int picture_size : 2;
+
+ unsigned int unknown1 : 2;
+ unsigned int line21_cc_2 : 1;
+ unsigned int line21_cc_1 : 1;
+#endif
+} ATTRIBUTE_PACKED video_attr_t;
+
+/**
+ * Audio Attributes. (Incomplete/Wrong?)
+ */
+typedef struct {
+#ifdef WORDS_BIGENDIAN
+ unsigned int audio_format : 3;
+ unsigned int multichannel_extension : 1;
+ unsigned int lang_type : 2;
+ unsigned int application_mode : 2;
+
+ unsigned int quantization : 2;
+ unsigned int sample_frequency : 2;
+ unsigned int unknown1 : 1;
+ unsigned int channels : 3;
+#else
+ unsigned int application_mode : 2;
+ unsigned int lang_type : 2;
+ unsigned int multichannel_extension : 1;
+ unsigned int audio_format : 3;
+
+ unsigned int channels : 3;
+ unsigned int unknown1 : 1;
+ unsigned int sample_frequency : 2;
+ unsigned int quantization : 2;
+#endif
+ uint16_t lang_code;
+ uint8_t lang_code2; // ??
+ uint8_t lang_extension;
+ uint16_t unknown2;
+} ATTRIBUTE_PACKED audio_attr_t;
+
+/**
+ * Subpicture Attributes.(Incomplete/Wrong)
+ */
+typedef struct {
+ /*
+ * type: 0 not specified
+ * 1 language
+ * 2 other
+ * coding mode: 0 run length
+ * 1 extended
+ * 2 other
+ * language: indicates language if type == 1
+ * lang extension: if type == 1 contains the lang extension
+ */
+ uint8_t type;
+ uint8_t zero1;
+ uint16_t lang_code;
+ uint8_t lang_extension;
+ uint8_t zero2;
+} ATTRIBUTE_PACKED subp_attr_t;
+
+
+
+/**
+ * PGC Command Table.
+ */
+typedef struct {
+ uint16_t nr_of_pre;
+ uint16_t nr_of_post;
+ uint16_t nr_of_cell;
+ uint16_t zero_1;
+ vm_cmd_t *pre_cmds;
+ vm_cmd_t *post_cmds;
+ vm_cmd_t *cell_cmds;
+} ATTRIBUTE_PACKED pgc_command_tbl_t;
+#define PGC_COMMAND_TBL_SIZE 8
+
+/**
+ * PGC Program Map
+ */
+typedef uint8_t pgc_program_map_t;
+
+/**
+ * Cell Playback Information.
+ */
+typedef struct {
+#ifdef WORDS_BIGENDIAN
+ unsigned int block_mode : 2;
+ unsigned int block_type : 2;
+ unsigned int seamless_play : 1;
+ unsigned int interleaved : 1;
+ unsigned int stc_discontinuity: 1;
+ unsigned int seamless_angle : 1;
+
+ unsigned int unknown1 : 1;
+ unsigned int restricted : 1;
+ unsigned int unknown2 : 6;
+#else
+ unsigned int seamless_angle : 1;
+ unsigned int stc_discontinuity: 1;
+ unsigned int interleaved : 1;
+ unsigned int seamless_play : 1;
+ unsigned int block_type : 2;
+ unsigned int block_mode : 2;
+
+ unsigned int unknown2 : 6;
+ unsigned int restricted : 1;
+ unsigned int unknown1 : 1;
+#endif
+ uint8_t still_time;
+ uint8_t cell_cmd_nr;
+ dvd_time_t playback_time;
+ uint32_t first_sector;
+ uint32_t first_ilvu_end_sector;
+ uint32_t last_vobu_start_sector;
+ uint32_t last_sector;
+} ATTRIBUTE_PACKED cell_playback_t;
+
+#define BLOCK_TYPE_NONE 0x0
+#define BLOCK_TYPE_ANGLE_BLOCK 0x1
+
+#define BLOCK_MODE_NOT_IN_BLOCK 0x0
+#define BLOCK_MODE_FIRST_CELL 0x1
+#define BLOCK_MODE_IN_BLOCK 0x2
+#define BLOCK_MODE_LAST_CELL 0x3
+
+/**
+ * Cell Position Information.
+ */
+typedef struct {
+ uint16_t vob_id_nr;
+ uint8_t zero_1;
+ uint8_t cell_nr;
+} ATTRIBUTE_PACKED cell_position_t;
+
+/**
+ * User Operations.
+ */
+typedef struct {
+#ifdef WORDS_BIGENDIAN
+ unsigned int zero : 7; // 25-31
+ unsigned int video_pres_mode_change : 1; // 24
+
+ unsigned int karaoke_audio_pres_mode_change : 1; // 23
+ unsigned int angle_change : 1; // 22
+ unsigned int subpic_stream_change : 1; // 21
+ unsigned int audio_stream_change : 1; // 20
+ unsigned int pause_on : 1; // 19
+ unsigned int still_off : 1; // 18
+ unsigned int button_select_or_activate : 1; // 17
+ unsigned int resume : 1; // 16
+
+ unsigned int chapter_menu_call : 1; // 15
+ unsigned int angle_menu_call : 1; // 14
+ unsigned int audio_menu_call : 1; // 13
+ unsigned int subpic_menu_call : 1; // 12
+ unsigned int root_menu_call : 1; // 11
+ unsigned int title_menu_call : 1; // 10
+ unsigned int backward_scan : 1; // 9
+ unsigned int forward_scan : 1; // 8
+
+ unsigned int next_pg_search : 1; // 7
+ unsigned int prev_or_top_pg_search : 1; // 6
+ unsigned int time_or_chapter_search : 1; // 5
+ unsigned int go_up : 1; // 4
+ unsigned int stop : 1; // 3
+ unsigned int title_play : 1; // 2
+ unsigned int chapter_search_or_play : 1; // 1
+ unsigned int title_or_time_play : 1; // 0
+#else
+ unsigned int video_pres_mode_change : 1; // 24
+ unsigned int zero : 7; // 25-31
+
+ unsigned int resume : 1; // 16
+ unsigned int button_select_or_activate : 1; // 17
+ unsigned int still_off : 1; // 18
+ unsigned int pause_on : 1; // 19
+ unsigned int audio_stream_change : 1; // 20
+ unsigned int subpic_stream_change : 1; // 21
+ unsigned int angle_change : 1; // 22
+ unsigned int karaoke_audio_pres_mode_change : 1; // 23
+
+ unsigned int forward_scan : 1; // 8
+ unsigned int backward_scan : 1; // 9
+ unsigned int title_menu_call : 1; // 10
+ unsigned int root_menu_call : 1; // 11
+ unsigned int subpic_menu_call : 1; // 12
+ unsigned int audio_menu_call : 1; // 13
+ unsigned int angle_menu_call : 1; // 14
+ unsigned int chapter_menu_call : 1; // 15
+
+ unsigned int title_or_time_play : 1; // 0
+ unsigned int chapter_search_or_play : 1; // 1
+ unsigned int title_play : 1; // 2
+ unsigned int stop : 1; // 3
+ unsigned int go_up : 1; // 4
+ unsigned int time_or_chapter_search : 1; // 5
+ unsigned int prev_or_top_pg_search : 1; // 6
+ unsigned int next_pg_search : 1; // 7
+#endif
+} ATTRIBUTE_PACKED user_ops_t;
+
+/**
+ * Program Chain Information.
+ */
+typedef struct {
+ uint16_t zero_1;
+ uint8_t nr_of_programs;
+ uint8_t nr_of_cells;
+ dvd_time_t playback_time;
+ user_ops_t prohibited_ops;
+ uint16_t audio_control[8]; /* New type? */
+ uint32_t subp_control[32]; /* New type? */
+ uint16_t next_pgc_nr;
+ uint16_t prev_pgc_nr;
+ uint16_t goup_pgc_nr;
+ uint8_t still_time;
+ uint8_t pg_playback_mode;
+ uint32_t palette[16]; /* New type struct {zero_1, Y, Cr, Cb} ? */
+ uint16_t command_tbl_offset;
+ uint16_t program_map_offset;
+ uint16_t cell_playback_offset;
+ uint16_t cell_position_offset;
+ pgc_command_tbl_t *command_tbl;
+ pgc_program_map_t *program_map;
+ cell_playback_t *cell_playback;
+ cell_position_t *cell_position;
+} ATTRIBUTE_PACKED pgc_t;
+#define PGC_SIZE 236
+
+/**
+ * Program Chain Information Search Pointer.
+ */
+typedef struct {
+ uint8_t entry_id;
+#ifdef WORDS_BIGENDIAN
+ unsigned int block_mode : 2;
+ unsigned int block_type : 2;
+ unsigned int unknown1 : 4;
+#else
+ unsigned int unknown1 : 4;
+ unsigned int block_type : 2;
+ unsigned int block_mode : 2;
+#endif
+ uint16_t ptl_id_mask;
+ uint32_t pgc_start_byte;
+ pgc_t *pgc;
+} ATTRIBUTE_PACKED pgci_srp_t;
+#define PGCI_SRP_SIZE 8
+
+/**
+ * Program Chain Information Table.
+ */
+typedef struct {
+ uint16_t nr_of_pgci_srp;
+ uint16_t zero_1;
+ uint32_t last_byte;
+ pgci_srp_t *pgci_srp;
+} ATTRIBUTE_PACKED pgcit_t;
+#define PGCIT_SIZE 8
+
+/**
+ * Menu PGCI Language Unit.
+ */
+typedef struct {
+ uint16_t lang_code;
+ uint8_t zero_1;
+ uint8_t exists;
+ uint32_t lang_start_byte;
+ pgcit_t *pgcit;
+} ATTRIBUTE_PACKED pgci_lu_t;
+#define PGCI_LU_SIZE 8
+
+/**
+ * Menu PGCI Unit Table.
+ */
+typedef struct {
+ uint16_t nr_of_lus;
+ uint16_t zero_1;
+ uint32_t last_byte;
+ pgci_lu_t *lu;
+} ATTRIBUTE_PACKED pgci_ut_t;
+#define PGCI_UT_SIZE 8
+
+/**
+ * Cell Address Information.
+ */
+typedef struct {
+ uint16_t vob_id;
+ uint8_t cell_id;
+ uint8_t zero_1;
+ uint32_t start_sector;
+ uint32_t last_sector;
+} ATTRIBUTE_PACKED cell_adr_t;
+
+/**
+ * Cell Address Table.
+ */
+typedef struct {
+ uint16_t nr_of_vobs; /* VOBs */
+ uint16_t zero_1;
+ uint32_t last_byte;
+ cell_adr_t *cell_adr_table;
+} ATTRIBUTE_PACKED c_adt_t;
+#define C_ADT_SIZE 8
+
+/**
+ * VOBU Address Map.
+ */
+typedef struct {
+ uint32_t last_byte;
+ uint32_t *vobu_start_sectors;
+} ATTRIBUTE_PACKED vobu_admap_t;
+#define VOBU_ADMAP_SIZE 4
+
+
+
+
+/**
+ * VMGI
+ *
+ * The following structures relate to the Video Manager.
+ */
+
+/**
+ * Video Manager Information Management Table.
+ */
+typedef struct {
+ char vmg_identifier[12];
+ uint32_t vmg_last_sector;
+ uint8_t zero_1[12];
+ uint32_t vmgi_last_sector;
+ uint8_t zero_2;
+ uint8_t specification_version;
+ uint32_t vmg_category;
+ uint16_t vmg_nr_of_volumes;
+ uint16_t vmg_this_volume_nr;
+ uint8_t disc_side;
+ uint8_t zero_3[19];
+ uint16_t vmg_nr_of_title_sets; /* Number of VTSs. */
+ char provider_identifier[32];
+ uint64_t vmg_pos_code;
+ uint8_t zero_4[24];
+ uint32_t vmgi_last_byte;
+ uint32_t first_play_pgc;
+ uint8_t zero_5[56];
+ uint32_t vmgm_vobs; /* sector */
+ uint32_t tt_srpt; /* sector */
+ uint32_t vmgm_pgci_ut; /* sector */
+ uint32_t ptl_mait; /* sector */
+ uint32_t vts_atrt; /* sector */
+ uint32_t txtdt_mgi; /* sector */
+ uint32_t vmgm_c_adt; /* sector */
+ uint32_t vmgm_vobu_admap; /* sector */
+ uint8_t zero_6[32];
+
+ video_attr_t vmgm_video_attr;
+ uint8_t zero_7;
+ uint8_t nr_of_vmgm_audio_streams; // should be 0 or 1
+ audio_attr_t vmgm_audio_attr;
+ audio_attr_t zero_8[7];
+ uint8_t zero_9[17];
+ uint8_t nr_of_vmgm_subp_streams; // should be 0 or 1
+ subp_attr_t vmgm_subp_attr;
+ subp_attr_t zero_10[27]; /* XXX: how much 'padding' here? */
+} ATTRIBUTE_PACKED vmgi_mat_t;
+
+typedef struct {
+#ifdef WORDS_BIGENDIAN
+ unsigned int zero_1 : 1;
+ unsigned int multi_or_random_pgc_title : 1; // 0 == one sequential pgc title
+ unsigned int jlc_exists_in_cell_cmd : 1;
+ unsigned int jlc_exists_in_prepost_cmd : 1;
+ unsigned int jlc_exists_in_button_cmd : 1;
+ unsigned int jlc_exists_in_tt_dom : 1;
+ unsigned int chapter_search_or_play : 1; // UOP 1
+ unsigned int title_or_time_play : 1; // UOP 0
+#else
+ unsigned int title_or_time_play : 1; // UOP 0
+ unsigned int chapter_search_or_play : 1; // UOP 1
+ unsigned int jlc_exists_in_tt_dom : 1;
+ unsigned int jlc_exists_in_button_cmd : 1;
+ unsigned int jlc_exists_in_prepost_cmd : 1;
+ unsigned int jlc_exists_in_cell_cmd : 1;
+ unsigned int multi_or_random_pgc_title : 1; // 0 == one sequential pgc title
+ unsigned int zero_1 : 1;
+#endif
+} ATTRIBUTE_PACKED playback_type_t;
+
+/**
+ * Title Information.
+ */
+typedef struct {
+ playback_type_t pb_ty;
+ uint8_t nr_of_angles;
+ uint16_t nr_of_ptts;
+ uint16_t parental_id;
+ uint8_t title_set_nr;
+ uint8_t vts_ttn;
+ uint32_t title_set_sector;
+} ATTRIBUTE_PACKED title_info_t;
+
+/**
+ * PartOfTitle Search Pointer Table.
+ */
+typedef struct {
+ uint16_t nr_of_srpts;
+ uint16_t zero_1;
+ uint32_t last_byte;
+ title_info_t *title;
+} ATTRIBUTE_PACKED tt_srpt_t;
+#define TT_SRPT_SIZE 8
+
+/**
+ * Parental Management Information Unit Table.
+ */
+typedef struct {
+ uint16_t country_code;
+ uint16_t zero_1;
+ uint16_t pf_ptl_mai_start_byte;
+ uint16_t zero_2;
+ /* uint16_t *pf_ptl_mai // table of nr_of_vtss+1 x 8 */
+} ATTRIBUTE_PACKED ptl_mait_country_t;
+#define PTL_MAIT_COUNTRY_SIZE 8
+
+/**
+ * Parental Management Information Table.
+ */
+typedef struct {
+ uint16_t nr_of_countries;
+ uint16_t nr_of_vtss;
+ uint32_t last_byte;
+ ptl_mait_country_t *countries;
+} ATTRIBUTE_PACKED ptl_mait_t;
+#define PTL_MAIT_SIZE 8
+
+/**
+ * Video Title Set Attributes.
+ */
+typedef struct {
+ uint32_t last_byte;
+ uint32_t vts_cat;
+
+ video_attr_t vtsm_vobs_attr;
+ uint8_t zero_1;
+ uint8_t nr_of_vtsm_audio_streams; // should be 0 or 1
+ audio_attr_t vtsm_audio_attr;
+ audio_attr_t zero_2[7];
+ uint8_t zero_3[16];
+ uint8_t zero_4;
+ uint8_t nr_of_vtsm_subp_streams; // should be 0 or 1
+ subp_attr_t vtsm_subp_attr;
+ subp_attr_t zero_5[27];
+
+ uint8_t zero_6[2];
+
+ video_attr_t vtstt_vobs_video_attr;
+ uint8_t zero_7;
+ uint8_t nr_of_vtstt_audio_streams;
+ audio_attr_t vtstt_audio_attr[8];
+ uint8_t zero_8[16];
+ uint8_t zero_9;
+ uint8_t nr_of_vtstt_subp_streams;
+ subp_attr_t vtstt_subp_attr[32];
+} ATTRIBUTE_PACKED vts_attributes_t;
+#define VTS_ATTRIBUTES_SIZE 542
+#define VTS_ATTRIBUTES_MIN_SIZE 356
+
+/**
+ * Video Title Set Attribute Table.
+ */
+typedef struct {
+ uint16_t nr_of_vtss;
+ uint16_t zero_1;
+ uint32_t last_byte;
+ vts_attributes_t *vts;
+} ATTRIBUTE_PACKED vts_atrt_t;
+#define VTS_ATRT_SIZE 8
+
+/**
+ * Text Data. (Incomplete)
+ */
+typedef struct {
+ uint32_t last_byte; /* offsets are relative here */
+ uint16_t offsets[100]; /* == nr_of_srpts + 1 (first is disc title) */
+#if 0
+ uint16_t unknown; // 0x48 ?? 0x48 words (16bit) info following
+ uint16_t zero_1;
+
+ uint8_t type_of_info;//?? 01 == disc, 02 == Title, 04 == Title part
+ uint8_t unknown1;
+ uint8_t unknown2;
+ uint8_t unknown3;
+ uint8_t unknown4;//?? allways 0x30 language?, text format?
+ uint8_t unknown5;
+ uint16_t offset; // from first
+
+ char text[12]; // ended by 0x09
+#endif
+} ATTRIBUTE_PACKED txtdt_t;
+
+/**
+ * Text Data Language Unit. (Incomplete)
+ */
+typedef struct {
+ uint16_t lang_code;
+ uint16_t unknown; /* 0x0001, title 1? disc 1? side 1? */
+ uint32_t txtdt_start_byte; /* prt, rel start of vmg_txtdt_mgi */
+ txtdt_t *txtdt;
+} ATTRIBUTE_PACKED txtdt_lu_t;
+#define TXTDT_LU_SIZE 8
+
+/**
+ * Text Data Manager Information. (Incomplete)
+ */
+typedef struct {
+ char disc_name[14]; /* how many bytes?? */
+ uint16_t nr_of_language_units; /* 32bit?? */
+ uint32_t last_byte;
+ txtdt_lu_t *lu;
+} ATTRIBUTE_PACKED txtdt_mgi_t;
+#define TXTDT_MGI_SIZE 20
+
+
+/**
+ * VTS
+ *
+ * Structures relating to the Video Title Set (VTS).
+ */
+
+/**
+ * Video Title Set Information Management Table.
+ */
+typedef struct {
+ char vts_identifier[12];
+ uint32_t vts_last_sector;
+ uint8_t zero_1[12];
+ uint32_t vtsi_last_sector;
+ uint8_t zero_2;
+ uint8_t specification_version;
+ uint32_t vts_category;
+ uint16_t zero_3;
+ uint16_t zero_4;
+ uint8_t zero_5;
+ uint8_t zero_6[19];
+ uint16_t zero_7;
+ uint8_t zero_8[32];
+ uint64_t zero_9;
+ uint8_t zero_10[24];
+ uint32_t vtsi_last_byte;
+ uint32_t zero_11;
+ uint8_t zero_12[56];
+ uint32_t vtsm_vobs; /* sector */
+ uint32_t vtstt_vobs; /* sector */
+ uint32_t vts_ptt_srpt; /* sector */
+ uint32_t vts_pgcit; /* sector */
+ uint32_t vtsm_pgci_ut; /* sector */
+ uint32_t vts_tmapt; /* sector */ // XXX: FIXME TODO Implement
+ uint32_t vtsm_c_adt; /* sector */
+ uint32_t vtsm_vobu_admap; /* sector */
+ uint32_t vts_c_adt; /* sector */
+ uint32_t vts_vobu_admap; /* sector */
+ uint8_t zero_13[24];
+
+ video_attr_t vtsm_video_attr;
+ uint8_t zero_14;
+ uint8_t nr_of_vtsm_audio_streams; // should be 0 or 1
+ audio_attr_t vtsm_audio_attr;
+ audio_attr_t zero_15[7];
+ uint8_t zero_16[17];
+ uint8_t nr_of_vtsm_subp_streams; // should be 0 or 1
+ subp_attr_t vtsm_subp_attr;
+ subp_attr_t zero_17[27];
+ uint8_t zero_18[2];
+
+ video_attr_t vts_video_attr;
+ uint8_t zero_19;
+ uint8_t nr_of_vts_audio_streams;
+ audio_attr_t vts_audio_attr[8];
+ uint8_t zero_20[17];
+ uint8_t nr_of_vts_subp_streams;
+ subp_attr_t vts_subp_attr[32];
+ /* XXX: how much 'padding' here, if any? */
+} ATTRIBUTE_PACKED vtsi_mat_t;
+
+/**
+ * PartOfTitle Unit Information.
+ */
+typedef struct {
+ uint16_t pgcn;
+ uint16_t pgn;
+} ATTRIBUTE_PACKED ptt_info_t;
+
+/**
+ * PartOfTitle Information.
+ */
+typedef struct {
+ uint16_t nr_of_ptts;
+ ptt_info_t *ptt;
+} ATTRIBUTE_PACKED ttu_t;
+
+/**
+ * PartOfTitle Search Pointer Table.
+ */
+typedef struct {
+ uint16_t nr_of_srpts;
+ uint16_t zero_1;
+ uint32_t last_byte;
+ ttu_t *title;
+} ATTRIBUTE_PACKED vts_ptt_srpt_t;
+#define VTS_PTT_SRPT_SIZE 8
+
+
+#if PRAGMA_PACK
+#pragma pack()
+#endif
+
+
+/**
+ * The following structure defines an IFO file. The structure is divided into
+ * two parts, the VMGI, or Video Manager Information, which is read from the
+ * VIDEO_TS.[IFO,BUP] file, and the VTSI, or Video Title Set Information, which
+ * is read in from the VTS_XX_0.[IFO,BUP] files.
+ */
+typedef struct {
+ dvd_file_t *file;
+
+ /* VMGI */
+ vmgi_mat_t *vmgi_mat;
+ tt_srpt_t *tt_srpt;
+ pgc_t *first_play_pgc;
+ ptl_mait_t *ptl_mait;
+ vts_atrt_t *vts_atrt;
+ txtdt_mgi_t *txtdt_mgi;
+
+ /* Common */
+ pgci_ut_t *pgci_ut;
+ c_adt_t *menu_c_adt;
+ vobu_admap_t *menu_vobu_admap;
+
+ /* VTSI */
+ vtsi_mat_t *vtsi_mat;
+ vts_ptt_srpt_t *vts_ptt_srpt;
+ pgcit_t *vts_pgcit;
+ int *vts_tmapt; // FIXME add/correct the type
+ c_adt_t *vts_c_adt;
+ vobu_admap_t *vts_vobu_admap;
+} ifo_handle_t;
+
+#endif /* IFO_TYPES_H_INCLUDED */
--- /dev/null
+/*
+ * Copyright (C) 2000 Håkan Hjort <d95hjort@dtek.chalmers.se>
+ *
+ * Much of the contents in this file is based on VOBDUMP.
+ *
+ * VOBDUMP: a program for examining DVD .VOB filse
+ *
+ * Copyright 1998, 1999 Eric Smith <eric@brouhaha.com>
+ *
+ * VOBDUMP is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. Note that I am not
+ * granting permission to redistribute or modify VOBDUMP under the
+ * terms of any later version of the General Public License.
+ *
+ * This program is distributed in the hope that it will be useful (or
+ * at least amusing), 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
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#include "config.h" // Needed for WORDS_BIGENDIAN
+#include "nav_types.h"
+#include "nav_print.h"
+
+
+static void print_time(dvd_time_t *dtime) {
+ const char *rate;
+ assert((dtime->hour>>4) < 0xa && (dtime->hour&0xf) < 0xa);
+ assert((dtime->minute>>4) < 0x7 && (dtime->minute&0xf) < 0xa);
+ assert((dtime->second>>4) < 0x7 && (dtime->second&0xf) < 0xa);
+ assert((dtime->frame_u&0xf) < 0xa);
+
+ printf("%02x:%02x:%02x.%02x",
+ dtime->hour,
+ dtime->minute,
+ dtime->second,
+ dtime->frame_u & 0x3f);
+ switch((dtime->frame_u & 0xc0) >> 6) {
+ case 1:
+ rate = "25.00";
+ break;
+ case 3:
+ rate = "29.97";
+ break;
+ default:
+ rate = "(please send a bug report)";
+ break;
+ }
+ printf(" @ %s fps", rate);
+}
+
+
+static void navPrint_PCI_GI(pci_gi_t *pci_gi) {
+ int i;
+
+ printf("pci_gi:\n");
+ printf("nv_pck_lbn 0x%08x\n", pci_gi->nv_pck_lbn);
+ printf("vobu_cat 0x%04x\n", pci_gi->vobu_cat);
+ printf("vobu_uop_ctl 0x%08x\n", *(uint32_t*)&pci_gi->vobu_uop_ctl);
+ printf("vobu_s_ptm 0x%08x\n", pci_gi->vobu_s_ptm);
+ printf("vobu_e_ptm 0x%08x\n", pci_gi->vobu_e_ptm);
+ printf("vobu_se_e_ptm 0x%08x\n", pci_gi->vobu_se_e_ptm);
+ printf("e_eltm ");
+ print_time(&pci_gi->e_eltm);
+ printf("\n");
+
+ printf("vobu_isrc \"");
+ for(i = 0; i < 32; i++) {
+ char c = pci_gi->vobu_isrc[i];
+ if((c >= ' ') && (c <= '~'))
+ printf("%c", c);
+ else
+ printf(".");
+ }
+ printf("\"\n");
+}
+
+static void navPrint_NSML_AGLI(nsml_agli_t *nsml_agli) {
+ int i, j = 0;
+
+ for(i = 0; i < 9; i++)
+ j |= nsml_agli->nsml_agl_dsta[i];
+ if(j == 0)
+ return;
+
+ printf("nsml_agli:\n");
+ for(i = 0; i < 9; i++)
+ if(nsml_agli->nsml_agl_dsta[i])
+ printf("nsml_agl_c%d_dsta 0x%08x\n", i + 1,
+ nsml_agli->nsml_agl_dsta[i]);
+}
+
+static void navPrint_HL_GI(hl_gi_t *hl_gi, int *btngr_ns, int *btn_ns) {
+
+ if((hl_gi->hli_ss & 0x03) == 0)
+ return;
+
+ printf("hl_gi:\n");
+ printf("hli_ss 0x%01x\n", hl_gi->hli_ss & 0x03);
+ printf("hli_s_ptm 0x%08x\n", hl_gi->hli_s_ptm);
+ printf("hli_e_ptm 0x%08x\n", hl_gi->hli_e_ptm);
+ printf("btn_se_e_ptm 0x%08x\n", hl_gi->btn_se_e_ptm);
+
+ *btngr_ns = hl_gi->btngr_ns;
+ printf("btngr_ns %d\n", hl_gi->btngr_ns);
+ printf("btngr%d_dsp_ty 0x%02x\n", 1, hl_gi->btngr1_dsp_ty);
+ printf("btngr%d_dsp_ty 0x%02x\n", 2, hl_gi->btngr2_dsp_ty);
+ printf("btngr%d_dsp_ty 0x%02x\n", 3, hl_gi->btngr3_dsp_ty);
+
+ printf("btn_ofn %d\n", hl_gi->btn_ofn);
+ *btn_ns = hl_gi->btn_ns;
+ printf("btn_ns %d\n", hl_gi->btn_ns);
+ printf("nsl_btn_ns %d\n", hl_gi->nsl_btn_ns);
+ printf("fosl_btnn %d\n", hl_gi->fosl_btnn);
+ printf("foac_btnn %d\n", hl_gi->foac_btnn);
+}
+
+static void navPrint_BTN_COLIT(btn_colit_t *btn_colit) {
+ int i, j;
+
+ j = 0;
+ for(i = 0; i < 6; i++)
+ j |= btn_colit->btn_coli[i/2][i&1];
+ if(j == 0)
+ return;
+
+ printf("btn_colit:\n");
+ for(i = 0; i < 3; i++)
+ for(j = 0; j < 2; j++)
+ printf("btn_cqoli %d %s_coli: %08x\n",
+ i, (j == 0) ? "sl" : "ac",
+ btn_colit->btn_coli[i][j]);
+}
+
+static void navPrint_BTNIT(btni_t *btni_table, int btngr_ns, int btn_ns) {
+ int i, j;
+
+ printf("btnit:\n");
+ printf("btngr_ns: %i\n", btngr_ns);
+ printf("btn_ns: %i\n", btn_ns);
+
+ if(btngr_ns == 0)
+ return;
+
+ for(i = 0; i < btngr_ns; i++) {
+ for(j = 0; j < (36 / btngr_ns); j++) {
+ if(j < btn_ns) {
+ btni_t *btni = &btni_table[(36 / btngr_ns) * i + j];
+
+ printf("group %d btni %d: ", i+1, j+1);
+ printf("btn_coln %d, auto_action_mode %d\n",
+ btni->btn_coln, btni->auto_action_mode);
+ printf("coords (%d, %d) .. (%d, %d)\n",
+ btni->x_start, btni->y_start, btni->x_end, btni->y_end);
+
+ printf("up %d, ", btni->up);
+ printf("down %d, ", btni->down);
+ printf("left %d, ", btni->left);
+ printf("right %d\n", btni->right);
+
+ // ifoPrint_COMMAND(&btni->cmd);
+ printf("\n");
+ }
+ }
+ }
+}
+
+static void navPrint_HLI(hli_t *hli) {
+ int btngr_ns = 0, btn_ns = 0;
+
+ printf("hli:\n");
+ navPrint_HL_GI(&hli->hl_gi, & btngr_ns, & btn_ns);
+ navPrint_BTN_COLIT(&hli->btn_colit);
+ navPrint_BTNIT(hli->btnit, btngr_ns, btn_ns);
+}
+
+void navPrint_PCI(pci_t *pci) {
+ printf("pci packet:\n");
+ navPrint_PCI_GI(&pci->pci_gi);
+ navPrint_NSML_AGLI(&pci->nsml_agli);
+ navPrint_HLI(&pci->hli);
+}
+
+static void navPrint_DSI_GI(dsi_gi_t *dsi_gi) {
+ printf("dsi_gi:\n");
+ printf("nv_pck_scr 0x%08x\n", dsi_gi->nv_pck_scr);
+ printf("nv_pck_lbn 0x%08x\n", dsi_gi->nv_pck_lbn );
+ printf("vobu_ea 0x%08x\n", dsi_gi->vobu_ea);
+ printf("vobu_1stref_ea 0x%08x\n", dsi_gi->vobu_1stref_ea);
+ printf("vobu_2ndref_ea 0x%08x\n", dsi_gi->vobu_2ndref_ea);
+ printf("vobu_3rdref_ea 0x%08x\n", dsi_gi->vobu_3rdref_ea);
+ printf("vobu_vob_idn 0x%04x\n", dsi_gi->vobu_vob_idn);
+ printf("vobu_c_idn 0x%02x\n", dsi_gi->vobu_c_idn);
+ printf("c_eltm ");
+ print_time(&dsi_gi->c_eltm);
+ printf("\n");
+}
+
+static void navPrint_SML_PBI(sml_pbi_t *sml_pbi) {
+ printf("sml_pbi:\n");
+ printf("category 0x%04x\n", sml_pbi->category);
+ if(sml_pbi->category & 0x8000)
+ printf("VOBU is in preunit\n");
+ if(sml_pbi->category & 0x4000)
+ printf("VOBU is in ILVU\n");
+ if(sml_pbi->category & 0x2000)
+ printf("VOBU at the beginning of ILVU\n");
+ if(sml_pbi->category & 0x1000)
+ printf("VOBU at end of PREU of ILVU\n");
+
+ printf("ilvu_ea 0x%08x\n", sml_pbi->ilvu_ea);
+ printf("nxt_ilvu_sa 0x%08x\n", sml_pbi->ilvu_sa);
+ printf("nxt_ilvu_size 0x%04x\n", sml_pbi->size);
+
+ printf("vob_v_s_s_ptm 0x%08x\n", sml_pbi->vob_v_s_s_ptm);
+ printf("vob_v_e_e_ptm 0x%08x\n", sml_pbi->vob_v_e_e_ptm);
+
+ /* $$$ more code needed here */
+}
+
+static void navPrint_SML_AGLI(sml_agli_t *sml_agli) {
+ int i;
+ printf("sml_agli:\n");
+ for(i = 0; i < 9; i++) {
+ printf("agl_c%d address: 0x%08x size 0x%04x\n", i,
+ sml_agli->data[i].address, sml_agli->data[i].size);
+ }
+}
+
+static void navPrint_VOBU_SRI(vobu_sri_t *vobu_sri) {
+ int i;
+ int stime[19] = { 240, 120, 60, 20, 15, 14, 13, 12, 11,
+ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
+ printf("vobu_sri:\n");
+ printf("Next VOBU with Video %08x\n", vobu_sri->next_video);
+ for(i = 0; i < 19; i++) {
+ printf("%3.1f %08x ", stime[i]/2.0, vobu_sri->fwda[i]);
+ }
+ printf("\n");
+ printf("Next VOBU %08x\n", vobu_sri->next_vobu);
+ printf("--\n");
+ printf("Prev VOBU %08x\n", vobu_sri->prev_vobu);
+ for(i = 0; i < 19; i++) {
+ printf("%3.1f %08x ", stime[18 - i]/2.0, vobu_sri->bwda[i]);
+ }
+ printf("\n");
+ printf("Prev VOBU with Video %08x\n", vobu_sri->prev_video);
+}
+
+static void navPrint_SYNCI(synci_t *synci) {
+ int i;
+
+ printf("synci:\n");
+ /* $$$ more code needed here */
+ for(i = 0; i < 8; i++)
+ printf("%04x ", synci->a_synca[i]);
+ for(i = 0; i < 32; i++)
+ printf("%08x ", synci->sp_synca[i]);
+}
+
+void navPrint_DSI(dsi_t *dsi) {
+ printf("dsi packet:\n");
+ navPrint_DSI_GI(&dsi->dsi_gi);
+ navPrint_SML_PBI(&dsi->sml_pbi);
+ navPrint_SML_AGLI(&dsi->sml_agli);
+ navPrint_VOBU_SRI(&dsi->vobu_sri);
+ navPrint_SYNCI(&dsi->synci);
+}
+
+
--- /dev/null
+/**
+ * Copyright (C) 2001 Billy Biggs <vektor@dumbterm.net>,
+ * Håkan Hjort <d95hjort@dtek.chalmers.se>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef NAV_PRINT_H_INCLUDED
+#define NAV_PRINT_H_INCLUDED
+
+#include <stdio.h>
+#include <dvdread/nav_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * This file provides example functions for printing information about the NAV
+ * packet to stdout.
+ */
+
+void navPrint_PCI(pci_t *pci);
+void navPrint_DSI(dsi_t *dsi);
+
+#ifdef __cplusplus
+};
+#endif
+#endif /* NAV_PRINT_H_INCLUDED */
--- /dev/null
+/**
+ * Copyright (C) 2000 Håkan Hjort <d95hjort@dtek.chalmers.se>
+ *
+ * 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
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#include "config.h" // Needed for WORDS_BIGENDIAN
+#include "bswap.h"
+#include "nav_types.h"
+#include "nav_read.h"
+
+void navRead_PCI(pci_t *pci, unsigned char *buffer) {
+ int i, j;
+
+ assert(sizeof(pci_t) == PCI_BYTES - 1); // -1 for substream id
+
+ memcpy(pci, buffer, sizeof(pci_t));
+
+ /* Endian conversions */
+
+ /* pci pci_gi */
+ B2N_32(pci->pci_gi.nv_pck_lbn);
+ B2N_16(pci->pci_gi.vobu_cat);
+ B2N_32(pci->pci_gi.vobu_s_ptm);
+ B2N_32(pci->pci_gi.vobu_e_ptm);
+ B2N_32(pci->pci_gi.vobu_se_e_ptm);
+
+ /* pci nsml_agli */
+ for(i = 0; i < 9; i++)
+ B2N_32(pci->nsml_agli.nsml_agl_dsta[i]);
+
+ /* pci hli hli_gi */
+ B2N_16(pci->hli.hl_gi.hli_ss);
+ B2N_32(pci->hli.hl_gi.hli_s_ptm);
+ B2N_32(pci->hli.hl_gi.hli_e_ptm);
+ B2N_32(pci->hli.hl_gi.btn_se_e_ptm);
+
+ /* pci hli btn_colit */
+ for(i = 0; i < 3; i++)
+ for(j = 0; j < 2; j++)
+ B2N_32(pci->hli.btn_colit.btn_coli[i][j]);
+
+
+ /* pci hli btni */
+ /* There are some issues with this bitfiled with some compilers
+ because they stradle word boundaries. */
+
+#if !defined(WORDS_BIGENDIAN)
+ for(i = 0; i < 36; i++) {
+#if 0 /* Wierd Sun CC code that does not work */
+ unsigned char m[6];
+ memcpy(m, &pci->hli.btnit[i], 6);
+ pci->hli.btnit[i].zero1 = (m[1] >> 2);
+ pci->hli.btnit[i].x_start = (m[0] << 4) | (m[1] >> 4);
+ pci->hli.btnit[i].x_end = (m[1] << 8) | m[2];
+ pci->hli.btnit[i].y_start = (m[3] << 4) | (m[4] >> 4);
+ pci->hli.btnit[i].y_end = (m[4] << 8) | m[5];
+ pci->hli.btnit[i].zero2 = (m[4] >> 2);
+ pci->hli.btnit[i].btn_coln = (m[0] >> 6);
+ pci->hli.btnit[i].auto_action_mode = (m[3] >> 6);
+#else
+ char tmp[6], swap;
+ memcpy(tmp, &(pci->hli.btnit[i]), 6);
+ /* This is a B2N_24() */
+ swap = tmp[0]; tmp[0] = tmp[2]; tmp[2] = swap;
+ /* This is a B2N_24() */
+ swap = tmp[3]; tmp[3] = tmp[5]; tmp[5] = swap;
+ memcpy(&(pci->hli.btnit[i]), tmp, 6);
+#endif
+ }
+#endif
+
+
+ /* Asserts */
+
+ /* pci pci gi */
+ assert(pci->pci_gi.zero1 == 0);
+
+ /* pci hli hli_gi */
+ assert(pci->hli.hl_gi.zero1 == 0);
+ assert(pci->hli.hl_gi.zero2 == 0);
+ assert(pci->hli.hl_gi.zero3 == 0);
+ assert(pci->hli.hl_gi.zero4 == 0);
+ assert(pci->hli.hl_gi.zero5 == 0);
+
+ /* Are there buttons defined here? */
+ if((pci->hli.hl_gi.hli_ss & 0x03) != 0) {
+ assert(pci->hli.hl_gi.btn_ns != 0);
+ assert(pci->hli.hl_gi.btngr_ns != 0);
+ } else {
+ assert((pci->hli.hl_gi.btn_ns != 0 && pci->hli.hl_gi.btngr_ns != 0)
+ || (pci->hli.hl_gi.btn_ns == 0 && pci->hli.hl_gi.btngr_ns == 0));
+ }
+
+ /* pci hli btnit */
+
+#if NDEBUG
+ for(i = 0; i < pci->hli.hl_gi.btngr_ns; i++) {
+ for(j = 0; j < (36 / pci->hli.hl_gi.btngr_ns); j++) {
+ int n = (36 / pci->hli.hl_gi.btngr_ns) * i + j;
+ assert(pci->hli.btnit[n].zero1 == 0);
+ assert(pci->hli.btnit[n].zero2 == 0);
+ assert(pci->hli.btnit[n].zero3 == 0);
+ assert(pci->hli.btnit[n].zero4 == 0);
+ assert(pci->hli.btnit[n].zero5 == 0);
+ assert(pci->hli.btnit[n].zero6 == 0);
+
+ if (j < pci->hli.hl_gi.btn_ns) {
+ assert(pci->hli.btnit[n].x_start <= pci->hli.btnit[n].x_end);
+ assert(pci->hli.btnit[n].y_start <= pci->hli.btnit[n].y_end);
+ assert(pci->hli.btnit[n].up <= pci->hli.hl_gi.btn_ns);
+ assert(pci->hli.btnit[n].down <= pci->hli.hl_gi.btn_ns);
+ assert(pci->hli.btnit[n].left <= pci->hli.hl_gi.btn_ns);
+ assert(pci->hli.btnit[n].right <= pci->hli.hl_gi.btn_ns);
+ //vmcmd_verify(pci->hli.btnit[n].cmd);
+ } else {
+ int k;
+ assert(pci->hli.btnit[n].btn_coln == 0);
+ assert(pci->hli.btnit[n].auto_action_mode == 0);
+ assert(pci->hli.btnit[n].x_start == 0);
+ assert(pci->hli.btnit[n].y_start == 0);
+ assert(pci->hli.btnit[n].x_end == 0);
+ assert(pci->hli.btnit[n].y_end == 0);
+ assert(pci->hli.btnit[n].up == 0);
+ assert(pci->hli.btnit[n].down == 0);
+ assert(pci->hli.btnit[n].left == 0);
+ assert(pci->hli.btnit[n].right == 0);
+ for (k = 0; k < 8; k++)
+ assert(pci->hli.btnit[n].cmd.bytes[k] == 0); //CHECK_ZERO?
+ }
+ }
+ }
+#endif
+}
+
+void navRead_DSI(dsi_t *dsi, unsigned char *buffer) {
+ int i;
+
+ assert(sizeof(dsi_t) == DSI_BYTES - 1); // -1 for substream id
+
+ memcpy(dsi, buffer, sizeof(dsi_t));
+
+ /* Endian conversions */
+
+ /* dsi dsi gi */
+ B2N_32(dsi->dsi_gi.nv_pck_scr);
+ B2N_32(dsi->dsi_gi.nv_pck_lbn);
+ B2N_32(dsi->dsi_gi.vobu_ea);
+ B2N_32(dsi->dsi_gi.vobu_1stref_ea);
+ B2N_32(dsi->dsi_gi.vobu_2ndref_ea);
+ B2N_32(dsi->dsi_gi.vobu_3rdref_ea);
+ B2N_16(dsi->dsi_gi.vobu_vob_idn);
+
+ /* dsi sml pbi */
+ B2N_16(dsi->sml_pbi.category);
+ B2N_32(dsi->sml_pbi.ilvu_ea);
+ B2N_32(dsi->sml_pbi.ilvu_sa);
+ B2N_16(dsi->sml_pbi.size);
+ B2N_32(dsi->sml_pbi.vob_v_s_s_ptm);
+ B2N_32(dsi->sml_pbi.vob_v_e_e_ptm);
+
+ /* dsi sml agli */
+ for(i = 0; i < 9; i++) {
+ B2N_32(dsi->sml_agli.data[ i ].address);
+ B2N_16(dsi->sml_agli.data[ i ].size);
+ }
+
+ /* dsi vobu sri */
+ B2N_32(dsi->vobu_sri.next_video);
+ for(i = 0; i < 19; i++)
+ B2N_32(dsi->vobu_sri.fwda[i]);
+ B2N_32(dsi->vobu_sri.next_vobu);
+ B2N_32(dsi->vobu_sri.prev_vobu);
+ for(i = 0; i < 19; i++)
+ B2N_32(dsi->vobu_sri.bwda[i]);
+ B2N_32(dsi->vobu_sri.prev_video);
+
+ /* dsi synci */
+ for(i = 0; i < 8; i++)
+ B2N_16(dsi->synci.a_synca[i]);
+ for(i = 0; i < 32; i++)
+ B2N_32(dsi->synci.sp_synca[i]);
+
+
+ /* Asserts */
+
+ /* dsi dsi gi */
+ assert(dsi->dsi_gi.zero1 == 0);
+}
+
--- /dev/null
+/**
+ * Copyright (C) 2000, 2001 Håkan Hjort <d95hjort@dtek.chalmers.se>.
+ *
+ * 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 NAV_READ_H_INCLUDED
+#define NAV_READ_H_INCLUDED
+
+#include <dvdread/nav_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Reads the PCI packet which begins at buffer into pci.
+ */
+void navRead_PCI(pci_t *pci, unsigned char *buffer);
+
+/**
+ * Reads the DSI packet which begins at buffer into dsi.
+ */
+void navRead_DSI(dsi_t *dsi, unsigned char *buffer);
+
+#ifdef __cplusplus
+};
+#endif
+#endif /* NAV_READ_H_INCLUDED */
--- /dev/null
+/**
+ * Copyright (C) 2000 Håkan Hjort <d95hjort@dtek.chalmers.se>
+ *
+ * The data structures in this file should represent the layout of the
+ * pci and dsi packets as they are stored in the stream. Information
+ * found by reading the source to VOBDUMP is the base for the structure
+ * and names of these data types.
+ *
+ * VOBDUMP: a program for examining DVD .VOB files.
+ * Copyright 1998, 1999 Eric Smith <eric@brouhaha.com>
+ *
+ * VOBDUMP is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. Note that I am not
+ * granting permission to redistribute or modify VOBDUMP under the terms
+ * of any later version of the General Public License.
+ *
+ * This program is distributed in the hope that it will be useful (or at
+ * least amusing), 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 NAV_TYPES_H_INCLUDED
+#define NAV_TYPES_H_INCLUDED
+
+#include <inttypes.h>
+#include <dvdread/ifo_types.h> // only dvd_time_t, vm_cmd_t and user_ops_t
+
+
+#undef ATTRIBUTE_PACKED
+#undef PRAGMA_PACK_BEGIN
+#undef PRAGMA_PACK_END
+
+#if defined(__GNUC__)
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+#define ATTRIBUTE_PACKED __attribute__ ((packed))
+#define PRAGMA_PACK 0
+#endif
+#endif
+
+#if !defined(ATTRIBUTE_PACKED)
+#define ATTRIBUTE_PACKED
+#define PRAGMA_PACK 1
+#endif
+
+
+/* The length including the substream id byte. */
+#define PCI_BYTES 0x3d4
+#define DSI_BYTES 0x3fa
+
+#define PS2_PCI_SUBSTREAM_ID 0x00
+#define PS2_DSI_SUBSTREAM_ID 0x01
+
+/* Remove this */
+#define DSI_START_BYTE 1031
+
+
+#if PRAGMA_PACK
+#pragma pack(1)
+#endif
+
+
+/**
+ * PCI General Information
+ */
+typedef struct {
+ uint32_t nv_pck_lbn;
+ uint16_t vobu_cat;
+ uint16_t zero1;
+ user_ops_t vobu_uop_ctl;
+ uint32_t vobu_s_ptm;
+ uint32_t vobu_e_ptm;
+ uint32_t vobu_se_e_ptm;
+ dvd_time_t e_eltm;
+ char vobu_isrc[32];
+} ATTRIBUTE_PACKED pci_gi_t;
+
+/**
+ * Non Seamless Angle Information
+ */
+typedef struct {
+ uint32_t nsml_agl_dsta[9];
+} ATTRIBUTE_PACKED nsml_agli_t;
+
+/**
+ * Highlight General Information
+ */
+typedef struct {
+ uint16_t hli_ss; // only low 2 bits
+ uint32_t hli_s_ptm;
+ uint32_t hli_e_ptm;
+ uint32_t btn_se_e_ptm;
+#ifdef WORDS_BIGENDIAN
+ unsigned int zero1 : 2;
+ unsigned int btngr_ns : 2;
+ unsigned int zero2 : 1;
+ unsigned int btngr1_dsp_ty : 3;
+ unsigned int zero3 : 1;
+ unsigned int btngr2_dsp_ty : 3;
+ unsigned int zero4 : 1;
+ unsigned int btngr3_dsp_ty : 3;
+#else
+ unsigned int btngr1_dsp_ty : 3;
+ unsigned int zero2 : 1;
+ unsigned int btngr_ns : 2;
+ unsigned int zero1 : 2;
+ unsigned int btngr3_dsp_ty : 3;
+ unsigned int zero4 : 1;
+ unsigned int btngr2_dsp_ty : 3;
+ unsigned int zero3 : 1;
+#endif
+ uint8_t btn_ofn;
+ uint8_t btn_ns; // only low 6 bits
+ uint8_t nsl_btn_ns; // only low 6 bits
+ uint8_t zero5;
+ uint8_t fosl_btnn; // only low 6 bits
+ uint8_t foac_btnn; // only low 6 bits
+} ATTRIBUTE_PACKED hl_gi_t;
+
+
+/**
+ * Button Color Information Table
+ */
+typedef struct {
+ uint32_t btn_coli[3][2];
+} ATTRIBUTE_PACKED btn_colit_t;
+
+
+/*
+ btn_coln 11000000 00000000 00000000 00000000 00000000 00000000
+ x_start 00111111 11110000 00000000 00000000 00000000 00000000
+ zero1 00000000 00001100 00000000 00000000 00000000 00000000
+ x_end 00000000 00000011 11111111 00000000 00000000 00000000
+ auto_action_mode 00000000 00000000 00000000 11000000 00000000 00000000
+ y_start 00000000 00000000 00000000 00111111 11110000 00000000
+ zero2 00000000 00000000 00000000 00000000 00001100 00000000
+ y_end 00000000 00000000 00000000 00000000 00000011 11111111
+
+ unsigned int btn_coln : 2; // 0 - m[0]>>6
+ unsigned int x_start : 10; // 2 - m[0]<<4 | m[1]>>4
+ unsigned int zero1 : 2; // 12 - m[1]>>2
+ unsigned int x_end : 10; // 14 - m[1]<<8 | m[2]
+
+ unsigned int auto_action_mode : 2; // 24 - m[3]>>6
+ unsigned int y_start : 10; // 26 - m[3]<<4 | m[4]>>4
+ unsigned int zero2 : 2; // 36 - m[4]>>2
+ unsigned int y_end : 10; // 38 - m[4]<<8 | m[5]
+ */
+
+/**
+ * Button Information
+ */
+typedef struct {
+#if 0 /* Wierd Sun CC code that does not work */
+ unsigned int zero1 : 2;
+ unsigned int x_start : 10;
+ unsigned int x_end : 10;
+ unsigned int y_start : 10;
+
+ unsigned int zero2 : 2;
+ unsigned int btn_coln : 2;
+ unsigned int auto_action_mode : 2;
+ unsigned int y_end : 10;
+#endif
+#ifdef WORDS_BIGENDIAN
+ unsigned int btn_coln : 2;
+ unsigned int x_start : 10;
+ unsigned int zero1 : 2;
+ unsigned int x_end : 10;
+ unsigned int auto_action_mode : 2;
+ unsigned int y_start : 10;
+ unsigned int zero2 : 2;
+ unsigned int y_end : 10;
+
+ unsigned int zero3 : 2;
+ unsigned int up : 6;
+ unsigned int zero4 : 2;
+ unsigned int down : 6;
+ unsigned int zero5 : 2;
+ unsigned int left : 6;
+ unsigned int zero6 : 2;
+ unsigned int right : 6;
+#else
+ unsigned int x_end : 10;
+ unsigned int zero1 : 2;
+ unsigned int x_start : 10;
+ unsigned int btn_coln : 2;
+ unsigned int y_end : 10;
+ unsigned int zero2 : 2;
+ unsigned int y_start : 10;
+ unsigned int auto_action_mode : 2;
+
+ unsigned int up : 6;
+ unsigned int zero3 : 2;
+ unsigned int down : 6;
+ unsigned int zero4 : 2;
+ unsigned int left : 6;
+ unsigned int zero5 : 2;
+ unsigned int right : 6;
+ unsigned int zero6 : 2;
+#endif
+ vm_cmd_t cmd;
+} ATTRIBUTE_PACKED btni_t;
+
+/**
+ * Highlight Information
+ */
+typedef struct {
+ hl_gi_t hl_gi;
+ btn_colit_t btn_colit;
+ btni_t btnit[36];
+} ATTRIBUTE_PACKED hli_t;
+
+/**
+ * PCI packet
+ */
+typedef struct {
+ pci_gi_t pci_gi;
+ nsml_agli_t nsml_agli;
+ hli_t hli;
+ uint8_t zero1[189];
+} ATTRIBUTE_PACKED pci_t;
+
+
+
+
+/**
+ * DSI General Information
+ */
+typedef struct {
+ uint32_t nv_pck_scr;
+ uint32_t nv_pck_lbn;
+ uint32_t vobu_ea;
+ uint32_t vobu_1stref_ea;
+ uint32_t vobu_2ndref_ea;
+ uint32_t vobu_3rdref_ea;
+ uint16_t vobu_vob_idn;
+ uint8_t zero1;
+ uint8_t vobu_c_idn;
+ dvd_time_t c_eltm;
+} ATTRIBUTE_PACKED dsi_gi_t;
+
+/**
+ * Seamless Playback Information
+ */
+typedef struct {
+ uint16_t category; // category of seamless VOBU
+ uint32_t ilvu_ea; // end address of interleaved Unit (sectors)
+ uint32_t ilvu_sa; // start address of next interleaved unit (sectors)
+ uint16_t size; // size of next interleaved unit (sectors)
+ uint32_t vob_v_s_s_ptm; /* video start ptm in vob */
+ uint32_t vob_v_e_e_ptm; /* video end ptm in vob */
+ struct {
+ uint32_t stp_ptm1;
+ uint32_t stp_ptm2;
+ uint32_t gap_len1;
+ uint32_t gap_len2;
+ } vob_a[8];
+} ATTRIBUTE_PACKED sml_pbi_t;
+
+/**
+ * Seamless Angle Infromation for one angle
+ */
+typedef struct {
+ uint32_t address; // Sector offset to next ILVU, high bit is before/after
+ uint16_t size; // Byte size of the ILVU poited to by address.
+} ATTRIBUTE_PACKED sml_agl_data_t;
+
+/**
+ * Seamless Angle Infromation
+ */
+typedef struct {
+ sml_agl_data_t data[9];
+} ATTRIBUTE_PACKED sml_agli_t;
+
+/**
+ * VOBU Search Information
+ */
+typedef struct {
+ uint32_t next_video; // Next vobu that contains video
+ uint32_t fwda[19]; // Forwards, time
+ uint32_t next_vobu;
+ uint32_t prev_vobu;
+ uint32_t bwda[19]; // Backwards, time
+ uint32_t prev_video;
+} ATTRIBUTE_PACKED vobu_sri_t;
+
+#define SRI_END_OF_CELL 0x3fffffff
+
+/**
+ * Synchronous Information
+ */
+typedef struct {
+ uint16_t a_synca[8]; // Sector offset to first audio packet for this VOBU
+ uint32_t sp_synca[32]; // Sector offset to first subpicture packet
+} ATTRIBUTE_PACKED synci_t;
+
+/**
+ * DSI packet
+ */
+typedef struct {
+ dsi_gi_t dsi_gi;
+ sml_pbi_t sml_pbi;
+ sml_agli_t sml_agli;
+ vobu_sri_t vobu_sri;
+ synci_t synci;
+ uint8_t zero1[471];
+} ATTRIBUTE_PACKED dsi_t;
+
+
+#if PRAGMA_PACK
+#pragma pack()
+#endif
+
+#endif /* NAV_TYPES_H_INCLUDED */
--- /dev/null
+/*****************************************************************************
+ * dvdread.c: replacement for dvd_reader.c that always takes dvdcss functions
+ * (hard-linked) and adds a readv call function to tha API.
+ *****************************************************************************
+ * Copyright (C) 2001 Billy Biggs <vektor@dumbterm.net>.
+ * $Id: dvdread.c,v 1.1 2001/11/25 05:04:38 stef Exp $
+ *
+ * Author: Billy Biggs <vektor@dumbterm.net>
+ * Stéphane Borel <stef@via.ecp.fr>
+ *
+ * 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, USA.
+ *****************************************************************************/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/uio.h> /* readv() */
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <dlfcn.h>
+#include <dirent.h>
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__)
+#define SYS_BSD 1
+#endif
+
+#if defined(__sun)
+#include <sys/mnttab.h>
+#elif defined(SYS_BSD)
+#include <fstab.h>
+#elif defined(__linux__)
+#include <mntent.h>
+#endif
+
+#if defined(SYS_BSD)
+typedef off_t off64_t;
+#define lseek64 lseek
+#define stat64 stat
+#endif
+
+#include "dvd_udf.h"
+#include "dvd_reader.h"
+
+#include "../libdvdcss/videolan/dvdcss.h"
+
+struct dvd_reader_s {
+ /* Basic information. */
+ int isImageFile;
+
+ /* Information required for an image file. */
+ dvdcss_handle dev;
+ int init_keys;
+ int fd;
+
+ /* Information required for a directory path drive. */
+ char *path_root;
+};
+
+struct dvd_file_s {
+ /* Basic information. */
+ dvd_reader_t *dvd;
+
+ /* Information required for an image file. */
+ uint32_t lb_start;
+ uint32_t seek_pos;
+
+ /* Information required for a directory path drive. */
+ size_t title_sizes[ 9 ];
+ int title_fds[ 9 ];
+
+ /* Calculated at open-time, size in blocks. */
+ ssize_t filesize;
+};
+
+/**
+ * Open a DVD image or block device file.
+ */
+static dvd_reader_t *DVDOpenImageFile( const char *location )
+{
+ dvd_reader_t *dvd;
+ dvdcss_handle dev = 0;
+ int fd = -1;
+
+ dev = dvdcss_open( (char *) location );
+ if( !dev ) {
+ fprintf( stderr, "libdvdread: Can't open %s for reading.\n",
+ location );
+ return 0;
+ }
+
+ dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) );
+ if( !dvd ) return 0;
+ dvd->isImageFile = 1;
+ dvd->dev = dev;
+ dvd->init_keys = 0;
+ dvd->fd = fd;
+ dvd->path_root = 0;
+
+ return dvd;
+}
+
+static dvd_reader_t *DVDOpenPath( const char *path_root )
+{
+ dvd_reader_t *dvd;
+
+ dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) );
+ if( !dvd ) return 0;
+ dvd->isImageFile = 0;
+ dvd->dev = 0;
+ dvd->init_keys = 0;
+ dvd->fd = -1;
+ dvd->path_root = strdup( path_root );
+
+ return dvd;
+}
+
+#if defined(__sun)
+/* /dev/rdsk/c0t6d0s0 (link to /devices/...)
+ /vol/dev/rdsk/c0t6d0/??
+ /vol/rdsk/<name> */
+static char *sun_block2char( const char *path )
+{
+ char *new_path;
+
+ /* Must contain "/dsk/" */
+ if( !strstr( path, "/dsk/" ) ) return (char *) strdup( path );
+
+ /* Replace "/dsk/" with "/rdsk/" */
+ new_path = malloc( strlen(path) + 2 );
+ strcpy( new_path, path );
+ strcpy( strstr( new_path, "/dsk/" ), "" );
+ strcat( new_path, "/rdsk/" );
+ strcat( new_path, strstr( path, "/dsk/" ) + strlen( "/dsk/" ) );
+
+ return new_path;
+}
+#endif
+
+#if defined(SYS_BSD)
+/* FreeBSD /dev/(r)(a)cd0 (a is for atapi, should work without r)
+ OpenBSD /dev/rcd0c
+ NetBSD /dev/rcd0d or /dev/rcd0c (for non x86)
+ BSD/OS /dev/sr0 (if not mounted) or /dev/rsr0 */
+static char *bsd_block2char( const char *path )
+{
+ char *new_path;
+
+ /* If it doesn't start with "/dev/" or does start with "/dev/r" exit */
+ if( !strncmp( path, "/dev/", 5 ) || strncmp( path, "/dev/r", 6 ) )
+ return (char *) strdup( path );
+
+ /* Replace "/dev/" with "/dev/r" */
+ new_path = malloc( strlen(path) + 2 );
+ strcpy( new_path, "/dev/r" );
+ strcat( new_path, path + strlen( "/dev/" ) );
+
+ return new_path;
+}
+#endif
+
+dvd_reader_t *DVDOpen( const char *path )
+{
+ struct stat64 fileinfo;
+ int ret;
+
+ if( !path ) return 0;
+
+ ret = stat64( path, &fileinfo );
+ if( ret < 0 ) {
+ /* If we can't stat the file, give up */
+ fprintf( stderr, "libdvdread: Can't stat %s\n", path );
+ perror("");
+ return 0;
+ }
+
+ /* First check if this is a block/char device or a file*/
+ if( S_ISBLK( fileinfo.st_mode ) ||
+ S_ISCHR( fileinfo.st_mode ) ||
+ S_ISREG( fileinfo.st_mode ) ) {
+
+ /**
+ * Block devices and regular files are assumed to be DVD-Video images.
+ */
+#if defined(__sun)
+ return DVDOpenImageFile( sun_block2char( path ) );
+#elif defined(SYS_BSD)
+ return DVDOpenImageFile( bsd_block2char( path ) );
+#else
+ return DVDOpenImageFile( path );
+#endif
+
+ } else if( S_ISDIR( fileinfo.st_mode ) ) {
+ dvd_reader_t *auth_drive = 0;
+ char *path_copy;
+#if defined(SYS_BSD)
+ struct fstab* fe;
+#elif defined(__sun) || defined(__linux__)
+ FILE *mntfile;
+#endif
+
+ /* XXX: We should scream real loud here. */
+ if( !(path_copy = strdup( path ) ) ) return 0;
+
+ /* Resolve any symlinks and get the absolut dir name. */
+ {
+ char *new_path;
+ int cdir = open( ".", O_RDONLY );
+
+ if( cdir >= 0 ) {
+ chdir( path_copy );
+ new_path = getcwd( NULL, PATH_MAX );
+ fchdir( cdir );
+ close( cdir );
+ if( new_path ) {
+ free( path_copy );
+ path_copy = new_path;
+ }
+ }
+ }
+
+ /**
+ * If we're being asked to open a directory, check if that directory
+ * is the mountpoint for a DVD-ROM which we can use instead.
+ */
+
+ if( strlen( path_copy ) > 1 ) {
+ if( path[ strlen( path_copy ) - 1 ] == '/' )
+ path_copy[ strlen( path_copy ) - 1 ] = '\0';
+ }
+
+ if( strlen( path_copy ) > 9 ) {
+ if( !strcasecmp( &(path_copy[ strlen( path_copy ) - 9 ]),
+ "/video_ts" ) ) {
+ path_copy[ strlen( path_copy ) - 9 ] = '\0';
+ }
+ }
+
+#if defined(SYS_BSD)
+ if( ( fe = getfsfile( path_copy ) ) ) {
+ char *dev_name = bsd_block2char( fe->fs_spec );
+ fprintf( stderr,
+ "libdvdread: Attempting to use device %s"
+ " mounted on %s for CSS authentication\n",
+ dev_name,
+ fe->fs_file );
+ auth_drive = DVDOpenImageFile( dev_name );
+ free( dev_name );
+ }
+#elif defined(__sun)
+ mntfile = fopen( MNTTAB, "r" );
+ if( mntfile ) {
+ struct mnttab mp;
+ int res;
+
+ while( ( res = getmntent( mntfile, &mp ) ) != -1 ) {
+ if( res == 0 && !strcmp( mp.mnt_mountp, path_copy ) ) {
+ char *dev_name = sun_block2char( mp.mnt_special );
+ fprintf( stderr,
+ "libdvdread: Attempting to use device %s"
+ " mounted on %s for CSS authentication\n",
+ dev_name,
+ mp.mnt_mountp );
+ auth_drive = DVDOpenImageFile( dev_name );
+ free( dev_name );
+ break;
+ }
+ }
+ fclose( mntfile );
+ }
+#elif defined(__linux__)
+ mntfile = fopen( MOUNTED, "r" );
+ if( mntfile ) {
+ struct mntent *me;
+
+ while( ( me = getmntent( mntfile ) ) ) {
+ if( !strcmp( me->mnt_dir, path_copy ) ) {
+ fprintf( stderr,
+ "libdvdread: Attempting to use device %s"
+ " mounted on %s for CSS authentication\n",
+ me->mnt_fsname,
+ me->mnt_dir );
+ auth_drive = DVDOpenImageFile( me->mnt_fsname );
+ break;
+ }
+ }
+ fclose( mntfile );
+ }
+#endif
+ if( !auth_drive ) {
+ fprintf( stderr, "libdvdread: Device inaccessible, "
+ "CSS authentication not available.\n" );
+ }
+
+ free( path_copy );
+
+ /**
+ * If we've opened a drive, just use that.
+ */
+ if( auth_drive ) return auth_drive;
+
+ /**
+ * Otherwise, we now try to open the directory tree instead.
+ */
+ fprintf( stderr, "libdvdread: Using normal filesystem access.\n" );
+ return DVDOpenPath( path );
+ }
+
+ /* If it's none of the above, screw it. */
+ fprintf( stderr, "libdvdread: Could not open %s\n", path );
+ return 0;
+}
+
+void DVDClose( dvd_reader_t *dvd )
+{
+ if( dvd ) {
+ if( dvd->dev ) dvdcss_close( dvd->dev );
+ if( dvd->fd >= 0 ) close( dvd->fd );
+ if( dvd->path_root ) free( dvd->path_root );
+ free( dvd );
+ dvd = 0;
+ }
+}
+
+/**
+ * Open an unencrypted file on a DVD image file.
+ */
+static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *dvd, char *filename )
+{
+ uint32_t start, len;
+ dvd_file_t *dvd_file;
+
+ start = UDFFindFile( dvd, filename, &len );
+ if( !start ) return 0;
+
+ dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
+ if( !dvd_file ) return 0;
+ dvd_file->dvd = dvd;
+ dvd_file->lb_start = start;
+ dvd_file->seek_pos = 0;
+ memset( dvd_file->title_fds, -1, sizeof( dvd_file->title_fds ) );
+ dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
+
+ return dvd_file;
+}
+
+/**
+ * Searches for <file> in directory <path>, ignoring case.
+ * Returns 0 and full filename in <filename>.
+ * or -1 on file not found.
+ * or -2 on path not found.
+ */
+static int findDirFile( const char *path, const char *file, char *filename )
+{
+ DIR *dir;
+ struct dirent *ent;
+
+ dir = opendir( path );
+ if( !dir ) return -2;
+
+ while( ( ent = readdir( dir ) ) != NULL ) {
+ if( !strcasecmp( ent->d_name, file ) ) {
+ sprintf( filename, "%s%s%s", path,
+ ( ( path[ strlen( path ) - 1 ] == '/' ) ? "" : "/" ),
+ ent->d_name );
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static int findDVDFile( dvd_reader_t *dvd, const char *file, char *filename )
+{
+ char video_path[ PATH_MAX + 1 ];
+ const char *nodirfile;
+ int ret;
+
+ /* Strip off the directory for our search */
+ if( !strncasecmp( "/VIDEO_TS/", file, 10 ) ) {
+ nodirfile = &(file[ 10 ]);
+ } else {
+ nodirfile = file;
+ }
+
+ ret = findDirFile( dvd->path_root, nodirfile, filename );
+ if( ret < 0 ) {
+ /* Try also with adding the path, just in case. */
+ sprintf( video_path, "%s/VIDEO_TS/", dvd->path_root );
+ ret = findDirFile( video_path, nodirfile, filename );
+ if( ret < 0 ) {
+ /* Try with the path, but in lower case. */
+ sprintf( video_path, "%s/video_ts/", dvd->path_root );
+ ret = findDirFile( video_path, nodirfile, filename );
+ if( ret < 0 ) {
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+/**
+ * Open an unencrypted file from a DVD directory tree.
+ */
+static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, char *filename )
+{
+ char full_path[ PATH_MAX + 1 ];
+ dvd_file_t *dvd_file;
+ struct stat fileinfo;
+ int fd;
+
+ /* Get the full path of the file. */
+ if( !findDVDFile( dvd, filename, full_path ) ) return 0;
+
+ fd = open( full_path, O_RDONLY );
+ if( fd < 0 ) return 0;
+
+ dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
+ if( !dvd_file ) return 0;
+ dvd_file->dvd = dvd;
+ dvd_file->lb_start = 0;
+ dvd_file->seek_pos = 0;
+ memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
+ memset( dvd_file->title_fds, -1, sizeof( dvd_file->title_fds ) );
+ dvd_file->filesize = 0;
+
+ if( stat( full_path, &fileinfo ) < 0 ) {
+ fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
+ free( dvd_file );
+ return 0;
+ }
+ dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
+ dvd_file->title_fds[ 0 ] = fd;
+ dvd_file->filesize = dvd_file->title_sizes[ 0 ];
+
+ return dvd_file;
+}
+
+static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *dvd,
+ int title, int menu )
+{
+ char filename[ MAX_UDF_FILE_NAME_LEN ];
+ uint32_t start, len;
+ dvd_file_t *dvd_file;
+
+ if( title == 0 ) {
+ sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" );
+ } else {
+ sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, menu ? 0 : 1 );
+ }
+ start = UDFFindFile( dvd, filename, &len );
+ if( start == 0 ) return 0;
+
+ dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
+ if( !dvd_file ) return 0;
+ dvd_file->dvd = dvd;
+ dvd_file->lb_start = start;
+ dvd_file->seek_pos = 0;
+ memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
+ memset( dvd_file->title_fds, -1, sizeof( dvd_file->title_fds ) );
+ dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
+
+ /* Calculate the complete file size for every file in the VOBS */
+ if( !menu ) {
+ int cur;
+
+ for( cur = 2; cur < 10; cur++ ) {
+ sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, cur );
+ if( !UDFFindFile( dvd, filename, &len ) ) break;
+ dvd_file->filesize += len / DVD_VIDEO_LB_LEN;
+ }
+ }
+
+ if( dvdcss_seek( dvd_file->dvd->dev, (int)start, DVDCSS_SEEK_KEY ) < 0 ) {
+ fprintf( stderr, "libdvdread: Error cracking CSS key for %s\n",
+ filename );
+ }
+
+ return dvd_file;
+}
+
+static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd,
+ int title, int menu )
+{
+ char filename[ MAX_UDF_FILE_NAME_LEN ];
+ char full_path[ PATH_MAX + 1 ];
+ struct stat fileinfo;
+ dvd_file_t *dvd_file;
+ int i;
+
+ dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
+ if( !dvd_file ) return 0;
+ dvd_file->dvd = dvd;
+ dvd_file->lb_start = 0;
+ dvd_file->seek_pos = 0;
+ memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
+ memset( dvd_file->title_fds, -1, sizeof( dvd_file->title_fds ) );
+ dvd_file->filesize = 0;
+
+ if( menu ) {
+ int fd;
+
+ if( title == 0 ) {
+ sprintf( filename, "VIDEO_TS.VOB" );
+ } else {
+ sprintf( filename, "VTS_%02i_0.VOB", title );
+ }
+ if( !findDVDFile( dvd, filename, full_path ) ) {
+ free( dvd_file );
+ return 0;
+ }
+
+ fd = open( full_path, O_RDONLY );
+ if( fd < 0 ) {
+ free( dvd_file );
+ return 0;
+ }
+
+ if( stat( full_path, &fileinfo ) < 0 ) {
+ fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
+ free( dvd_file );
+ return 0;
+ }
+ dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
+ dvd_file->title_fds[ 0 ] = fd;
+ dvd_file->filesize = dvd_file->title_sizes[ 0 ];
+
+ } else {
+ for( i = 0; i < 9; ++i ) {
+
+ sprintf( filename, "VTS_%02i_%i.VOB", title, i + 1 );
+ if( !findDVDFile( dvd, filename, full_path ) ) {
+ break;
+ }
+
+ if( stat( full_path, &fileinfo ) < 0 ) {
+ fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
+ break;
+ }
+
+ dvd_file->title_sizes[ i ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
+ dvd_file->title_fds[ i ] = open( full_path, O_RDONLY );
+ dvd_file->filesize += dvd_file->title_sizes[ i ];
+ }
+ if( !(dvd_file->title_sizes[ 0 ]) ) {
+ free( dvd_file );
+ return 0;
+ }
+ }
+
+ return dvd_file;
+}
+
+dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum,
+ dvd_read_domain_t domain )
+{
+ char filename[ MAX_UDF_FILE_NAME_LEN ];
+
+ switch( domain ) {
+ case DVD_READ_INFO_FILE:
+ if( titlenum == 0 ) {
+ sprintf( filename, "/VIDEO_TS/VIDEO_TS.IFO" );
+ } else {
+ sprintf( filename, "/VIDEO_TS/VTS_%02i_0.IFO", titlenum );
+ }
+ break;
+ case DVD_READ_INFO_BACKUP_FILE:
+ if( titlenum == 0 ) {
+ sprintf( filename, "/VIDEO_TS/VIDEO_TS.BUP" );
+ } else {
+ sprintf( filename, "/VIDEO_TS/VTS_%02i_0.BUP", titlenum );
+ }
+ break;
+ case DVD_READ_MENU_VOBS:
+ if( dvd->isImageFile ) {
+ return DVDOpenVOBUDF( dvd, titlenum, 1 );
+ } else {
+ return DVDOpenVOBPath( dvd, titlenum, 1 );
+ }
+ break;
+ case DVD_READ_TITLE_VOBS:
+ if( titlenum == 0 ) return 0;
+ if( dvd->isImageFile ) {
+ return DVDOpenVOBUDF( dvd, titlenum, 0 );
+ } else {
+ return DVDOpenVOBPath( dvd, titlenum, 0 );
+ }
+ break;
+ default:
+ fprintf( stderr, "libdvdread: Invalid domain for file open.\n" );
+ return 0;
+ }
+
+ if( dvd->isImageFile ) {
+ return DVDOpenFileUDF( dvd, filename );
+ } else {
+ return DVDOpenFilePath( dvd, filename );
+ }
+}
+
+void DVDCloseFile( dvd_file_t *dvd_file )
+{
+ int i;
+
+ if( dvd_file ) {
+ if( !dvd_file->dvd->isImageFile ) {
+ for( i = 0; i < 9; ++i ) {
+ if( dvd_file->title_fds[ i ] >= 0 )
+ close( dvd_file->title_fds[ i ] );
+ }
+ }
+
+ free( dvd_file );
+ dvd_file = 0;
+ }
+}
+
+int64_t DVDReadLBUDF( dvd_reader_t *device, uint32_t lb_number,
+ size_t block_count, unsigned char *data,
+ int encrypted )
+{
+ int ret;
+
+ if( !device->dev ) {
+ fprintf( stderr, "libdvdread: Fatal error in block read.\n" );
+ return 0;
+ }
+
+ ret = dvdcss_seek( device->dev, (int) lb_number, DVDCSS_NOFLAGS );
+ if( ret != (int) lb_number ) {
+ fprintf( stderr, "libdvdread: Can't seek to block %u\n",
+ lb_number );
+ return 0;
+ }
+
+ return (int64_t) ( dvdcss_read( device->dev, (char *) data,
+ (int) block_count, encrypted )
+ * (uint64_t) DVD_VIDEO_LB_LEN );
+}
+
+static int64_t DVDReadBlocksUDF( dvd_file_t *dvd_file, uint32_t offset,
+ size_t block_count, unsigned char *data )
+{
+ return DVDReadLBUDF( dvd_file->dvd, dvd_file->lb_start + offset,
+ block_count, data, DVDCSS_READ_DECRYPT );
+}
+
+static int64_t DVDReadBlocksPath( dvd_file_t *dvd_file, size_t offset,
+ size_t block_count, unsigned char *data )
+{
+ int i;
+ ssize_t ret, ret2;
+ off64_t off;
+
+ ret = 0;
+ ret2 = 0;
+ for( i = 0; i < 9; ++i ) {
+ if( !dvd_file->title_sizes[ i ] ) return 0;
+
+ if( offset < dvd_file->title_sizes[ i ] ) {
+ if( ( offset + block_count ) <= dvd_file->title_sizes[ i ] ) {
+ off = lseek64( dvd_file->title_fds[ i ],
+ offset * (int64_t) DVD_VIDEO_LB_LEN, SEEK_SET );
+ if( off != ( offset * (int64_t) DVD_VIDEO_LB_LEN ) ) {
+ fprintf( stderr, "libdvdread: Can't seek to block %d\n",
+ offset );
+ return 0;
+ }
+ ret = read( dvd_file->title_fds[ i ], data,
+ block_count * DVD_VIDEO_LB_LEN );
+ break;
+ } else {
+ size_t part1_size
+ = ( dvd_file->title_sizes[ i ] - offset ) * DVD_VIDEO_LB_LEN;
+ /* FIXME: Really needs to be a while loop.
+ (This is only true if you try and read >1GB at a time) */
+
+ /* Read part 1 */
+ off = lseek64( dvd_file->title_fds[ i ],
+ offset * (int64_t) DVD_VIDEO_LB_LEN, SEEK_SET );
+ if( off != ( offset * (int64_t) DVD_VIDEO_LB_LEN ) ) {
+ fprintf( stderr, "libdvdread: Can't seek to block %d\n",
+ offset );
+ return 0;
+ }
+ ret = read( dvd_file->title_fds[ i ], data, part1_size );
+ if( ret < 0 ) return ret;
+ /* FIXME: This is wrong if i is the last file in the set.
+ also error from this read will not show in ret. */
+
+ /* Read part 2 */
+ lseek64( dvd_file->title_fds[ i + 1 ], (off64_t)0, SEEK_SET );
+ ret2 = read( dvd_file->title_fds[ i + 1 ], data + part1_size,
+ block_count * DVD_VIDEO_LB_LEN - part1_size );
+ if( ret2 < 0 ) return ret2;
+ break;
+ }
+ } else {
+ offset -= dvd_file->title_sizes[ i ];
+ }
+ }
+
+ return ( (int64_t) ret + (int64_t) ret2 );
+}
+
+/* These are broken for some cases reading more than 2Gb at a time. */
+ssize_t DVDReadBlocks( dvd_file_t *dvd_file, int offset,
+ size_t block_count, unsigned char *data )
+{
+ int64_t ret;
+
+ if( dvd_file->dvd->isImageFile ) {
+ ret = DVDReadBlocksUDF( dvd_file, (uint32_t)offset,
+ block_count, data );
+ } else {
+ ret = DVDReadBlocksPath( dvd_file, (size_t) offset,
+ block_count, data );
+ }
+ if( ret <= 0 ) {
+ return (ssize_t) ret;
+ }
+ {
+ ssize_t sret = (ssize_t) (ret / (int64_t)DVD_VIDEO_LB_LEN );
+ if( sret == 0 ) {
+ fprintf(stderr, "libdvdread: DVDReadBlocks got %d bytes\n", (int)ret );
+ }
+ return sret;
+ }
+}
+
+int32_t DVDFileSeek( dvd_file_t *dvd_file, int32_t offset )
+{
+ if( dvd_file->dvd->isImageFile ) {
+ dvd_file->seek_pos = (uint32_t) offset;
+ return offset;
+ } else {
+ return (int32_t) ( lseek( dvd_file->title_fds[ 0 ],
+ (off_t) offset, SEEK_SET ) );
+ }
+}
+
+static ssize_t DVDReadBytesUDF( dvd_file_t *dvd_file, void *data,
+ size_t byte_size )
+{
+ unsigned char *secbuf;
+ unsigned int numsec, seek_sector, seek_byte;
+ int64_t len;
+
+ seek_sector = dvd_file->seek_pos / DVD_VIDEO_LB_LEN;
+ seek_byte = dvd_file->seek_pos % DVD_VIDEO_LB_LEN;
+
+ numsec = ( ( seek_byte + byte_size ) / DVD_VIDEO_LB_LEN ) + 1;
+ secbuf = (unsigned char *) malloc( numsec * DVD_VIDEO_LB_LEN );
+ if( !secbuf ) {
+ fprintf( stderr, "libdvdread: Can't allocate memory "
+ "for file read!\n" );
+ return 0;
+ }
+
+ len = DVDReadLBUDF( dvd_file->dvd, dvd_file->lb_start + seek_sector,
+ numsec, secbuf, DVDCSS_NOFLAGS );
+ if( len != numsec * (int64_t) DVD_VIDEO_LB_LEN ) {
+ free( secbuf );
+ return 0;
+ }
+
+ dvd_file->seek_pos += byte_size;
+
+ memcpy( data, &(secbuf[ seek_byte ]), byte_size );
+ free( secbuf );
+
+ return byte_size;
+}
+
+static ssize_t DVDReadBytesPath( dvd_file_t *dvd_file, void *data,
+ size_t byte_size )
+{
+ return read( dvd_file->title_fds[ 0 ], data, byte_size );
+}
+
+ssize_t DVDReadBytes( dvd_file_t *dvd_file, void *data, size_t byte_size )
+{
+ if( dvd_file->dvd->isImageFile ) {
+ return DVDReadBytesUDF( dvd_file, data, byte_size );
+ } else {
+ return DVDReadBytesPath( dvd_file, data, byte_size );
+ }
+}
+
+ssize_t DVDFileSize( dvd_file_t *dvd_file )
+{
+ return dvd_file->filesize;
+}
+
+int64_t DVDReadVLBUDF( dvd_reader_t *device, uint32_t lb_number,
+ size_t block_count, struct iovec * vector,
+ int encrypted )
+{
+ int ret;
+
+ if( !device->dev ) {
+ fprintf( stderr, "libdvdread: Fatal error in block read.\n" );
+ return 0;
+ }
+
+ ret = dvdcss_seek( device->dev, (int) lb_number, 0 );
+ if( ret != (int) lb_number ) {
+ fprintf( stderr, "libdvdread: Can't seek to block %u\n",
+ lb_number );
+ return 0;
+ }
+
+ return (int64_t) ( dvdcss_readv( device->dev, vector,
+ (int)block_count, encrypted )
+ * (uint64_t) DVD_VIDEO_LB_LEN );
+}
+
+static int64_t DVDReadVBlocksUDF( dvd_file_t *dvd_file, uint32_t offset,
+ size_t block_count, struct iovec *vector )
+{
+ return DVDReadVLBUDF( dvd_file->dvd, dvd_file->lb_start + offset,
+ block_count, vector, DVDCSS_READ_DECRYPT );
+}
+
+
+ssize_t DVDReadVBlocks( dvd_file_t *dvd_file, int offset,
+ size_t block_count, struct iovec * vector )
+{
+ int64_t ret;
+
+ if( dvd_file->dvd->isImageFile ) {
+ ret = DVDReadVBlocksUDF( dvd_file, (uint32_t)offset,
+ block_count, vector );
+ } else {
+ ret = 0;//= DVDReadVBlocksPath( dvd_file, (size_t) offset,
+// block_count, vector );
+ }
+ if( ret <= 0 ) {
+ return (ssize_t) ret;
+ }
+ {
+ ssize_t sret = (ssize_t) (ret / (int64_t)DVD_VIDEO_LB_LEN );
+ if( sret == 0 ) {
+ fprintf(stderr, "libdvdread: DVDReadVBlocks got %d bytes\n", (int)ret );
+ }
+ return sret;
+ }
+
+}
+
--- /dev/null
+/*****************************************************************************
+ * dvdread.h: DVD reading library, exported functions.
+ *****************************************************************************
+ * Copyright (C) 1998-2001 VideoLAN
+ * $Id: dvdread.h,v 1.1 2001/11/25 05:04:38 stef Exp $
+ *
+ * Authors: Stéphane Borel <stef@via.ecp.fr>
+ *
+ * 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, USA.
+ *****************************************************************************/
+
+ssize_t DVDReadVBlocks( dvd_file_t *dvd_file, int offset,
+ size_t block_count, struct iovec * vector );
--- /dev/null
+###############################################################################
+# vlc (VideoLAN Client) dvdread module Makefile
+# (c)2001 VideoLAN
+###############################################################################
+
+#
+# Objects
+#
+
+PLUGIN_DVDREAD = dvdread.o input_dvdread.o $(OBJ_DVDREAD)
+BUILTIN_DVDREAD = $(PLUGIN_DVDREAD:%.o=BUILTIN_%.o)
+
+ALL_OBJ = $(PLUGIN_DVDREAD) $(BUILTIN_DVDREAD)
+
+#
+# Virtual targets
+#
+
+include ../../Makefile.modules
+
+$(PLUGIN_DVDREAD): %.o: .dep/%.d
+$(PLUGIN_DVDREAD): %.o: %.c
+ $(CC) $(CFLAGS_DVD) $(CFLAGS_DVDREAD) $(CFLAGS) $(PCFLAGS) -DPLUGIN -c -o $@ $<
+
+$(BUILTIN_DVDREAD): BUILTIN_%.o: .dep/%.d
+$(BUILTIN_DVDREAD): BUILTIN_%.o: %.c
+ $(CC) $(CFLAGS_DVD) $(CFLAGS_DVDREAD) $(CFLAGS) -DBUILTIN -c -o $@ $<
+
+#
+# Real targets
+#
+
+ifeq (1,$(NEED_LIBDVDCSS))
+../dvdread.so: libdvdcss libdvdread $(PLUGIN_DVDREAD)
+ $(CC) $(PCFLAGS) -o $@ $(PLUGIN_DVDREAD) $(PLCFLAGS) $(LIB_DVD_PLUGIN) $(LIB_DVDREAD_PLUGIN)
+
+../dvdread.a: libdvdcss libdvdread $(BUILTIN_DVDREAD)
+ ar r $@ $(BUILTIN_DVDREAD)
+ $(RANLIB) $@
+else
+../dvdread.so: libdvdread $(PLUGIN_DVDREAD)
+ $(CC) $(PCFLAGS) -o $@ $(PLUGIN_DVD) $(PLCFLAGS) $(LIB_DVD_PLUGIN) $(LIB_DVDREAD_PLUGIN)
+
+../dvdread.a: libdvdread $(BUILTIN_DVDREAD)
+ ar r $@ $(BUILTIN_DVDREAD)
+ $(RANLIB) $@
+endif
+
+libdvdcss:
+ cd ../../ && $(MAKE) libdvdcss
+
+libdvdread:
+ cd ../../ && $(MAKE) libdvdread
--- /dev/null
+/*****************************************************************************
+ * dvdread.c : DvdRead input module for vlc
+ *****************************************************************************
+ * Copyright (C) 2001 VideoLAN
+ * $Id: dvdread.c,v 1.1 2001/11/25 05:04:38 stef Exp $
+ *
+ * Authors: Samuel Hocevar <sam@zoy.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, USA.
+ *****************************************************************************/
+
+#define MODULE_NAME dvdread
+#include "modules_inner.h"
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include "defs.h"
+
+#include <stdlib.h> /* malloc(), free() */
+#include <string.h> /* strdup() */
+
+#ifdef GOD_DAMN_DMCA
+# include <dlfcn.h>
+# include "dummy_dvdcss.h"
+#endif
+
+#include "config.h"
+#include "common.h" /* boolean_t, byte_t */
+#include "threads.h"
+#include "mtime.h"
+
+#include "intf_msg.h"
+
+#include "modules.h"
+#include "modules_export.h"
+
+/*****************************************************************************
+ * Capabilities defined in the other files.
+ *****************************************************************************/
+void _M( input_getfunctions )( function_list_t * p_function_list );
+
+/*****************************************************************************
+ * Local prototypes.
+ *****************************************************************************/
+#ifdef GOD_DAMN_DMCA
+static void *p_libdvdcss;
+static void ProbeLibDVDCSS ( void );
+static void UnprobeLibDVDCSS( void );
+#endif
+
+/*****************************************************************************
+ * Build configuration tree.
+ *****************************************************************************/
+MODULE_CONFIG_START
+ADD_WINDOW( "Configuration for DVD module" )
+ ADD_COMMENT( "foobar !" )
+MODULE_CONFIG_STOP
+
+MODULE_INIT_START
+ p_module->i_capabilities = MODULE_CAPABILITY_NULL
+ | MODULE_CAPABILITY_INPUT;
+#ifdef GOD_DAMN_DMCA
+ p_module->psz_longname = "DVD input module, uses libdvdcss if present";
+#else
+ p_module->psz_longname = "DVD input module, linked with libdvdcss";
+#endif
+MODULE_INIT_STOP
+
+MODULE_ACTIVATE_START
+ _M( input_getfunctions )( &p_module->p_functions->input );
+#ifdef GOD_DAMN_DMCA
+ ProbeLibDVDCSS();
+#endif
+MODULE_ACTIVATE_STOP
+
+MODULE_DEACTIVATE_START
+#ifdef GOD_DAMN_DMCA
+ UnprobeLibDVDCSS();
+#endif
+MODULE_DEACTIVATE_STOP
+
+
+/* Following functions are local */
+
+#ifdef GOD_DAMN_DMCA
+/*****************************************************************************
+ * ProbeLibDVDCSS: look for a libdvdcss object.
+ *****************************************************************************
+ * This functions looks for libdvdcss, using dlopen(), and fills function
+ * pointers with what it finds. On failure, uses the dummy libdvdcss
+ * replacement provided by vlc.
+ *****************************************************************************/
+static void ProbeLibDVDCSS( void )
+{
+ char *pp_filelist[4] = { "libdvdcss.so.0",
+ "./libdvdcss.so.0",
+ "./lib/libdvdcss.so.0",
+ NULL };
+ char **pp_file = pp_filelist;
+
+ /* Try to open the dynamic object */
+ do
+ {
+ p_libdvdcss = dlopen( *pp_file, RTLD_LAZY );
+ if( p_libdvdcss != NULL )
+ {
+ intf_WarnMsg( 2, "module: builtin module `dvd' found libdvdcss "
+ "in `%s'", *pp_file );
+ break;
+ }
+ pp_file++;
+
+ } while( *pp_file != NULL );
+
+ /* If libdvdcss.so was found, check that it's valid */
+ if( p_libdvdcss == NULL )
+ {
+ intf_ErrMsg( "dvd warning: libdvdcss.so.0 not present" );
+ }
+ else
+ {
+ /* Check for libdvdcss 0.0.1 */
+ if( dlsym( p_libdvdcss, "dvdcss_crack" ) != NULL )
+ {
+ intf_ErrMsg( "dvd warning: libdvdcss.so.0 has deprecated symbol "
+ "dvdcss_crack(), please upgrade" );
+ dlclose( p_libdvdcss );
+ p_libdvdcss = NULL;
+ }
+ else
+ {
+ dvdcss_open = dlsym( p_libdvdcss, "dvdcss_open" );
+ dvdcss_close = dlsym( p_libdvdcss, "dvdcss_close" );
+ dvdcss_title = dlsym( p_libdvdcss, "dvdcss_title" );
+ dvdcss_seek = dlsym( p_libdvdcss, "dvdcss_seek" );
+ dvdcss_read = dlsym( p_libdvdcss, "dvdcss_read" );
+ dvdcss_readv = dlsym( p_libdvdcss, "dvdcss_readv" );
+ dvdcss_error = dlsym( p_libdvdcss, "dvdcss_error" );
+
+ if( dvdcss_open == NULL || dvdcss_close == NULL
+ || dvdcss_title == NULL || dvdcss_seek == NULL
+ || dvdcss_read == NULL || dvdcss_readv == NULL
+ || dvdcss_error == NULL )
+ {
+ intf_ErrMsg( "dvd warning: missing symbols in libdvdcss.so.0, "
+ "please upgrade libdvdcss or vlc" );
+ dlclose( p_libdvdcss );
+ p_libdvdcss = NULL;
+ }
+ }
+ }
+
+ /* If libdvdcss was not found or was not valid, use the dummy
+ * replacement functions. */
+ if( p_libdvdcss == NULL )
+ {
+ intf_ErrMsg( "dvd warning: no valid libdvdcss found, "
+ "I will only play unencrypted DVDs" );
+ intf_ErrMsg( "dvd warning: get libdvdcss at "
+ "http://www.videolan.org/libdvdcss/" );
+
+ dvdcss_open = dummy_dvdcss_open;
+ dvdcss_close = dummy_dvdcss_close;
+ dvdcss_title = dummy_dvdcss_title;
+ dvdcss_seek = dummy_dvdcss_seek;
+ dvdcss_read = dummy_dvdcss_read;
+ dvdcss_readv = dummy_dvdcss_readv;
+ dvdcss_error = dummy_dvdcss_error;
+ }
+}
+
+/*****************************************************************************
+ * UnprobeLibDVDCSS: free resources allocated by ProbeLibDVDCSS, if any.
+ *****************************************************************************/
+static void UnprobeLibDVDCSS( void )
+{
+ if( p_libdvdcss != NULL )
+ {
+ dlclose( p_libdvdcss );
+ p_libdvdcss = NULL;
+ }
+}
+#endif
+
--- /dev/null
+/*****************************************************************************
+ * input_dvdread.c: DvdRead plugin.
+ *****************************************************************************
+ * This plugins should handle all the known specificities of the DVD format,
+ * especially the 2048 bytes logical block size.
+ * It depends on: libdvdread for ifo files and block reading.
+ *****************************************************************************
+ * Copyright (C) 2001 VideoLAN
+ * $Id: input_dvdread.c,v 1.1 2001/11/25 05:04:38 stef Exp $
+ *
+ * Author: Stéphane Borel <stef@via.ecp.fr>
+ *
+ * Some code taken form the play_title.c by Billy Biggs <vektor@dumbterm.net>
+ * in libdvdread.
+ *
+ * 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, USA.
+ *****************************************************************************/
+
+#define MODULE_NAME dvdread
+#include "modules_inner.h"
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include "defs.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#ifdef STRNCASECMP_IN_STRINGS_H
+# include <strings.h>
+#endif
+
+#if defined( WIN32 )
+# include <io.h> /* read() */
+#else
+# include <sys/uio.h> /* struct iovec */
+#endif
+
+
+#include "config.h"
+#include "common.h"
+#include "threads.h"
+#include "mtime.h"
+#include "iso_lang.h"
+#include "tests.h"
+
+#if defined( WIN32 )
+# include "input_iovec.h"
+#endif
+
+#include "intf_msg.h"
+
+#include "main.h"
+
+#include "stream_control.h"
+#include "input_ext-intf.h"
+#include "input_ext-dec.h"
+#include "input_ext-plugins.h"
+
+#include "input_dvdread.h"
+
+#include "debug.h"
+
+#include "modules.h"
+#include "modules_export.h"
+
+/* how many blocks DVDRead will read in each loop */
+#define DVD_BLOCK_READ_ONCE 64
+#define DVD_DATA_READ_ONCE (4 * DVD_BLOCK_READ_ONCE)
+
+/* Size of netlist */
+#define DVD_NETLIST_SIZE 512
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+/* called from outside */
+static int DvdReadProbe ( probedata_t *p_data );
+static void DvdReadInit ( struct input_thread_s * );
+static void DvdReadEnd ( struct input_thread_s * );
+static void DvdReadOpen ( struct input_thread_s * );
+static void DvdReadClose ( struct input_thread_s * );
+static int DvdReadSetArea ( struct input_thread_s *, struct input_area_s * );
+static int DvdReadRead ( struct input_thread_s *, data_packet_t ** );
+static void DvdReadSeek ( struct input_thread_s *, off_t );
+static int DvdReadRewind ( struct input_thread_s * );
+
+/* called only from here */
+static void DvdReadHandleDSI( thread_dvd_data_t * p_dvd, u8 * p_data );
+static void DvdReadFindCell ( thread_dvd_data_t * p_dvd );
+
+/*****************************************************************************
+ * Functions exported as capabilities. They are declared as static so that
+ * we don't pollute the namespace too much.
+ *****************************************************************************/
+void _M( input_getfunctions )( function_list_t * p_function_list )
+{
+#define input p_function_list->functions.input
+ p_function_list->pf_probe = DvdReadProbe;
+ input.pf_init = DvdReadInit;
+ input.pf_open = DvdReadOpen;
+ input.pf_close = DvdReadClose;
+ input.pf_end = DvdReadEnd;
+ input.pf_init_bit_stream = InitBitstream;
+ input.pf_read = DvdReadRead;
+ input.pf_set_area = DvdReadSetArea;
+ input.pf_demux = input_DemuxPS;
+ input.pf_new_packet = input_NetlistNewPacket;
+ input.pf_new_pes = input_NetlistNewPES;
+ input.pf_delete_packet = input_NetlistDeletePacket;
+ input.pf_delete_pes = input_NetlistDeletePES;
+ input.pf_rewind = DvdReadRewind;
+ input.pf_seek = DvdReadSeek;
+#undef input
+}
+
+/*
+ * Data reading functions
+ */
+
+/*****************************************************************************
+ * DvdReadProbe: verifies that the stream is a PS stream
+ *****************************************************************************/
+static int DvdReadProbe( probedata_t *p_data )
+{
+ input_thread_t * p_input = (input_thread_t *)p_data;
+
+ char * psz_name = p_input->p_source;
+ int i_score = 5;
+
+ if( TestMethod( INPUT_METHOD_VAR, "dvdread" ) )
+ {
+ return( 999 );
+ }
+
+ if( ( strlen(psz_name) > 8 ) && !strncasecmp( psz_name, "dvdread:", 8 ) )
+ {
+ /* If the user specified "dvdread:" then he probably wants
+ * to use libdvdread */
+ i_score = 100;
+ psz_name += 4;
+ }
+
+ return( i_score );
+}
+
+/*****************************************************************************
+ * DvdReadInit: initializes DVD structures
+ *****************************************************************************/
+static void DvdReadInit( input_thread_t * p_input )
+{
+ thread_dvd_data_t * p_dvd;
+ input_area_t * p_area;
+ int i_title;
+ int i_chapter;
+ int i;
+
+ p_dvd = malloc( sizeof(thread_dvd_data_t) );
+ if( p_dvd == NULL )
+ {
+ intf_ErrMsg( "dvdread error: out of memory" );
+ p_input->b_error = 1;
+ return;
+ }
+
+ /* we take the pointer to dvd_reader_t back */
+ p_dvd->p_dvdread = (dvd_reader_t *)p_input->p_plugin_data;
+ p_dvd->p_title = NULL;
+ p_dvd->p_vts_file = NULL;
+
+ p_input->p_plugin_data = (void *)p_dvd;
+ p_input->p_method_data = NULL;
+
+ /* We read DVD_BLOCK_READ_ONCE in each loop, so the input will receive
+ * DVD_DATA_READ_ONCE at most */
+ p_dvd->i_block_once = DVD_BLOCK_READ_ONCE;
+ /* this value mustn't be modifed */
+ p_input->i_read_once = DVD_DATA_READ_ONCE;
+
+ /* Reading structures initialisation */
+ input_NetlistInit( p_input, DVD_NETLIST_SIZE, 2 * DVD_NETLIST_SIZE,
+ DVD_NETLIST_SIZE, DVD_VIDEO_LB_LEN, p_dvd->i_block_once );
+ intf_WarnMsg( 2, "dvdread info: netlist initialized" );
+
+ /* Ifo allocation & initialisation */
+ if( ! ( p_dvd->p_vmg_file = ifoOpen( p_dvd->p_dvdread, 0 ) ) )
+ {
+ intf_ErrMsg( "dvdread error: can't open VMG info" );
+ DVDClose( p_dvd->p_dvdread );
+ free( p_dvd );
+ p_input->b_error = 1;
+ return;
+ }
+ intf_WarnMsg( 2, "dvdread info: VMG opened" );
+
+ /* Set stream and area data */
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+
+ /* Initialize ES structures */
+ input_InitStream( p_input, sizeof( stream_ps_data_t ) );
+
+ /* disc input method */
+ p_input->stream.i_method = INPUT_METHOD_DVD;
+
+#define tt_srpt p_dvd->p_vmg_file->tt_srpt
+ intf_WarnMsg( 2, "dvdread info: number of titles: %d", tt_srpt->nr_of_srpts );
+
+#define area p_input->stream.pp_areas
+ /* We start from 1 here since the default area 0
+ * is reserved for video_ts.vob */
+ for( i = 1 ; i <= tt_srpt->nr_of_srpts ; i++ )
+ {
+ input_AddArea( p_input );
+
+ /* Titles are Program Chains */
+ area[i]->i_id = i;
+
+ /* Absolute start offset and size
+ * We can only set that with vts ifo, so we do it during the
+ * first call to DVDSetArea */
+ area[i]->i_start = 0;
+ area[i]->i_size = 0;
+
+ /* Number of chapters */
+ area[i]->i_part_nb = tt_srpt->title[i-1].nr_of_ptts;
+ area[i]->i_part = 1;
+
+ /* Number of angles */
+ area[i]->i_angle_nb = 0;
+ area[i]->i_angle = 1;
+
+ area[i]->i_plugin_data = tt_srpt->title[i-1].title_set_nr;
+ }
+#undef area
+
+ /* Get requested title - if none try the first title */
+ i_title = main_GetIntVariable( INPUT_TITLE_VAR, 1 );
+ if( i_title <= 0 || i_title > tt_srpt->nr_of_srpts )
+ {
+ i_title = 1;
+ }
+
+#undef tt_srpt
+
+ /* Get requested chapter - if none defaults to first one */
+ i_chapter = main_GetIntVariable( INPUT_CHAPTER_VAR, 1 );
+ if( i_chapter <= 0 )
+ {
+ i_chapter = 1;
+ }
+
+ p_input->stream.pp_areas[i_title]->i_part = i_chapter;
+
+ p_area = p_input->stream.pp_areas[i_title];
+
+ /* set title, chapter, audio and subpic */
+ DvdReadSetArea( p_input, p_area );
+
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+ return;
+}
+
+/*****************************************************************************
+ * DvdReadOpen: open libdvdread
+ *****************************************************************************/
+static void DvdReadOpen( struct input_thread_s *p_input )
+{
+ dvd_reader_t *p_dvdread;
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+
+ /* If we are here we can control the pace... */
+ p_input->stream.b_pace_control = 1;
+
+ p_input->stream.b_seekable = 1;
+ p_input->stream.p_selected_area->i_size = 0;
+
+ p_input->stream.p_selected_area->i_tell = 0;
+
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+ /* XXX: put this shit in an access plugin */
+ if( strlen( p_input->p_source ) > 8
+ && !strncasecmp( p_input->p_source, "dvdread:", 8 ) )
+ {
+ p_dvdread = DVDOpen( p_input->p_source + 8 );
+ }
+ else
+ {
+ p_dvdread = DVDOpen( p_input->p_source );
+ }
+
+ if( ! p_dvdread )
+ {
+ p_input->b_error = 1;
+ return;
+ }
+
+ /* the vlc input doesn't handle the file descriptor with libdvdread */
+ p_input->i_handle = -1;
+
+ /* p_dvdread is stored in p_plugin_data until we have
+ * malloc'ed a dvd_thread_data_t */
+ p_input->p_plugin_data = (void *) p_dvdread;
+}
+
+/*****************************************************************************
+ * DvdReadClose: close libdvdread
+ *****************************************************************************/
+static void DvdReadClose( struct input_thread_s *p_input )
+{
+ DVDClose( ((thread_dvd_data_t*)p_input->p_plugin_data)->p_dvdread );
+ free( p_input->p_plugin_data );
+ p_input->p_plugin_data = NULL;
+
+}
+
+/*****************************************************************************
+ * DvdReadEnd: frees unused data
+ *****************************************************************************/
+static void DvdReadEnd( input_thread_t * p_input )
+{
+ thread_dvd_data_t * p_dvd;
+
+ p_dvd = (thread_dvd_data_t *)p_input->p_plugin_data;
+
+ /* close libdvdread */
+ DVDCloseFile( p_dvd->p_title );
+ ifoClose( p_dvd->p_vts_file );
+ ifoClose( p_dvd->p_vmg_file );
+
+ /* Close netlist */
+ input_NetlistEnd( p_input );
+ p_input->p_method_data = NULL;
+}
+
+#define p_pgc p_dvd->p_cur_pgc
+
+/*****************************************************************************
+ * DvdReadSetArea: initialize input data for title x, chapter y.
+ * It should be called for each user navigation request.
+ *****************************************************************************
+ * Take care that i_title starts from 0 (vmg) and i_chapter start from 1.
+ * Note that you have to take the lock before entering here.
+ *****************************************************************************/
+static int DvdReadSetArea( input_thread_t * p_input, input_area_t * p_area )
+{
+ thread_dvd_data_t * p_dvd;
+ int pgc_id = 0;
+ int pgn = 0;
+
+ p_dvd = (thread_dvd_data_t*)p_input->p_plugin_data;
+
+ /* we can't use the interface slider until initilization is complete */
+ p_input->stream.b_seekable = 0;
+
+ if( p_area != p_input->stream.p_selected_area )
+ {
+ es_descriptor_t * p_es;
+ int i_cell = 0;
+ int i_audio_nb = 0;
+ int i_spu_nb = 0;
+ int i;
+
+#define p_vmg p_dvd->p_vmg_file
+#define p_vts p_dvd->p_vts_file
+ if( p_dvd->p_title != NULL )
+ {
+ DVDCloseFile( p_dvd->p_title );
+ }
+
+ if( p_vts != NULL )
+ {
+ ifoClose( p_vts );
+ }
+
+ /* Reset the Chapter position of the old title */
+ p_input->stream.p_selected_area->i_part = 1;
+
+ /*
+ * We have to load all title information
+ */
+ /* Change the default area */
+ p_input->stream.p_selected_area = p_area;
+
+ intf_WarnMsg( 12, "dvdread: open VTS %d, for title %d",
+ p_vmg->tt_srpt->title[ p_area->i_id - 1 ].title_set_nr,
+ p_area->i_id );
+
+ /* ifo vts */
+ if( ! ( p_vts = ifoOpen( p_dvd->p_dvdread,
+ p_vmg->tt_srpt->title[ p_area->i_id - 1 ].title_set_nr ) ) )
+ {
+ intf_ErrMsg( "dvdread error: fatal error in vts ifo" );
+ ifoClose( p_vmg );
+ DVDClose( p_dvd->p_dvdread );
+ p_input->b_error = 1;
+ return -1;
+ }
+
+ /* title position inside the selected vts */
+ p_dvd->i_ttn = p_vmg->tt_srpt->title[ p_area->i_id - 1 ].vts_ttn;
+
+ /*
+ * Set selected title start
+ */
+ pgc_id = p_vts->vts_ptt_srpt->title[p_dvd->i_ttn-1].ptt[0].pgcn;
+ pgn = p_vts->vts_ptt_srpt->title[p_dvd->i_ttn-1].ptt[0].pgn;
+ p_pgc = p_vts->vts_pgcit->pgci_srp[ pgc_id - 1 ].pgc;
+ i_cell = p_pgc->program_map[ pgn - 1 ] - 1;
+
+ p_area->i_start =
+ LB2OFF( p_dvd->p_cur_pgc->cell_playback[ i_cell ].first_sector );
+
+ intf_WarnMsg( 3, "dvdread: start %d vts_title %d pgc %d pgn %d",
+ p_area->i_id, p_dvd->i_ttn, pgc_id, pgn );
+
+ /*
+ * Find title end
+ */
+ i_cell = p_dvd->p_cur_pgc->nr_of_cells - 1;
+
+ p_dvd->i_end_block = p_pgc->cell_playback[ i_cell ].last_sector;
+ p_area->i_size = LB2OFF( p_dvd->i_end_block )- p_area->i_start;
+
+ intf_WarnMsg( 12, "dvdread: start %lld size %lld end %d",
+ p_area->i_start , p_area->i_size, p_dvd->i_end_block );
+
+ /*
+ * Set properties for current chapter
+ */
+ /* Remeber current chapter */
+ p_dvd->i_chapter = p_area->i_part;
+ p_dvd->b_eoc = 0;
+
+ pgc_id = p_vts->vts_ptt_srpt->title[
+ p_dvd->i_ttn-1].ptt[p_area->i_part-1].pgcn;
+ pgn = p_vts->vts_ptt_srpt->title[
+ p_dvd->i_ttn-1].ptt[p_area->i_part-1].pgn;
+
+ p_pgc = p_vts->vts_pgcit->pgci_srp[pgc_id-1].pgc;
+ p_dvd->i_pack_len = 0;
+ p_dvd->i_next_cell = p_dvd->i_cur_cell = p_pgc->program_map[pgn-1] - 1;
+ DvdReadFindCell( p_dvd );
+
+ p_dvd->i_next_vobu = p_dvd->i_cur_block =
+ p_pgc->cell_playback[p_dvd->i_cur_cell].first_sector;
+
+ /*
+ * Angle management
+ */
+ p_area->i_angle_nb = p_vmg->tt_srpt->title[p_area->i_id-1].nr_of_angles;
+ p_area->i_angle = main_GetIntVariable( INPUT_ANGLE_VAR, 1 );
+
+ if( ( p_area->i_angle <= 0 ) || p_area->i_angle > p_area->i_angle_nb )
+ {
+ p_area->i_angle = 1;
+ }
+ p_dvd->i_angle = p_area->i_angle;
+ p_dvd->i_angle_nb = p_area->i_angle_nb;
+
+ /*
+ * We've got enough info, time to open the title set data.
+ */
+ if( ! ( p_dvd->p_title = DVDOpenFile( p_dvd->p_dvdread,
+ p_vmg->tt_srpt->title[ p_area->i_id - 1 ].title_set_nr,
+ DVD_READ_TITLE_VOBS ) ) )
+ {
+ intf_ErrMsg( "dvdread error: can't open title (VTS_%02d_1.VOB)",
+ p_vmg->tt_srpt->title[p_area->i_id-1].title_set_nr );
+ ifoClose( p_vts );
+ ifoClose( p_vmg );
+ DVDClose( p_dvd->p_dvdread );
+ return -1;
+ }
+
+// IfoPrintTitle( p_dvd );
+
+ /*
+ * Destroy obsolete ES by reinitializing program 0
+ * and find all ES in title with ifo data
+ */
+ if( p_input->stream.pp_programs != NULL )
+ {
+ /* We don't use input_EndStream here since
+ * we keep area structures */
+
+ for( i = 0 ; i < p_input->stream.i_selected_es_number ; i++ )
+ {
+ input_UnselectES( p_input, p_input->stream.pp_selected_es[i] );
+ }
+
+ free( p_input->stream.pp_selected_es );
+ input_DelProgram( p_input, p_input->stream.pp_programs[0] );
+
+ p_input->stream.pp_selected_es = NULL;
+ p_input->stream.i_selected_es_number = 0;
+ }
+
+ input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
+
+ /* No PSM to read in DVD mode, we already have all information */
+ p_input->stream.pp_programs[0]->b_is_ok = 1;
+
+ p_es = NULL;
+
+ /* ES 0 -> video MPEG2 */
+// IfoPrintVideo( p_dvd );
+
+ p_es = input_AddES( p_input, p_input->stream.pp_programs[0], 0xe0, 0 );
+ p_es->i_stream_id = 0xe0;
+ p_es->i_type = MPEG2_VIDEO_ES;
+ p_es->i_cat = VIDEO_ES;
+ if( p_main->b_video )
+ {
+ input_SelectES( p_input, p_es );
+ }
+
+#define audio_control \
+ p_dvd->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc->audio_control[i-1]
+ /* Audio ES, in the order they appear in .ifo */
+ for( i = 1 ; i <= p_vts->vtsi_mat->nr_of_vts_audio_streams ; i++ )
+ {
+ int i_position = 0;
+ u16 i_id;
+
+// IfoPrintAudio( p_dvd, i );
+
+ /* audio channel is active if first byte is 0x80 */
+ if( audio_control & 0x8000 )
+ {
+ i_audio_nb++;
+ i_position = ( audio_control & 0x7F00 ) >> 8;
+
+ intf_WarnMsg( 12, "dvd audio position %d", i_position );
+ switch( p_vts->vtsi_mat->vts_audio_attr[i-1].audio_format )
+ {
+ case 0x00: /* AC3 */
+ i_id = ( ( 0x80 + i_position ) << 8 ) | 0xbd;
+ p_es = input_AddES( p_input,
+ p_input->stream.pp_programs[0], i_id, 0 );
+ p_es->i_stream_id = 0xbd;
+ p_es->i_type = AC3_AUDIO_ES;
+ p_es->b_audio = 1;
+ p_es->i_cat = AUDIO_ES;
+ strcpy( p_es->psz_desc, DecodeLanguage( hton16(
+ p_vts->vtsi_mat->vts_audio_attr[i-1].lang_code ) ) );
+ strcat( p_es->psz_desc, " (ac3)" );
+
+ break;
+ case 0x02:
+ case 0x03: /* MPEG audio */
+ i_id = 0xc0 + i_position;
+ p_es = input_AddES( p_input,
+ p_input->stream.pp_programs[0], i_id, 0 );
+ p_es->i_stream_id = i_id;
+ p_es->i_type = MPEG2_AUDIO_ES;
+ p_es->b_audio = 1;
+ p_es->i_cat = AUDIO_ES;
+ strcpy( p_es->psz_desc, DecodeLanguage( hton16(
+ p_vts->vtsi_mat->vts_audio_attr[i-1].lang_code ) ) );
+ strcat( p_es->psz_desc, " (mpeg)" );
+
+ break;
+ case 0x04: /* LPCM */
+
+ i_id = ( ( 0xa0 + i_position ) << 8 ) | 0xbd;
+ p_es = input_AddES( p_input,
+ p_input->stream.pp_programs[0], i_id, 0 );
+ p_es->i_stream_id = i_id;
+ p_es->i_type = LPCM_AUDIO_ES;
+ p_es->b_audio = 1;
+ p_es->i_cat = AUDIO_ES;
+ strcpy( p_es->psz_desc, DecodeLanguage( hton16(
+ p_vts->vtsi_mat->vts_audio_attr[i-1].lang_code ) ) );
+ strcat( p_es->psz_desc, " (lpcm)" );
+
+ break;
+ case 0x06: /* DTS */
+ i_id = ( ( 0x88 + i_position ) << 8 ) | 0xbd;
+ intf_ErrMsg( "dvd warning: DTS audio not handled yet"
+ "(0x%x)", i_id );
+ break;
+ default:
+ i_id = 0;
+ intf_ErrMsg( "dvd warning: unknown audio type %.2x",
+ p_vts->vtsi_mat->vts_audio_attr[i-1].audio_format );
+ }
+ }
+ }
+#undef audio_control
+#define spu_control \
+ p_dvd->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc->subp_control[i-1]
+
+ /* Sub Picture ES */
+
+ for( i = 1 ; i <= p_vts->vtsi_mat->nr_of_vts_subp_streams; i++ )
+ {
+ int i_position = 0;
+ u16 i_id;
+
+// IfoPrintSpu( p_dvd, i );
+ intf_WarnMsg( 12, "dvd spu %d 0x%02x", i, spu_control );
+
+ if( spu_control & 0x80000000 )
+ {
+ i_spu_nb++;
+
+ /* there are several streams for one spu */
+ if( p_vts->vtsi_mat->vts_video_attr.display_aspect_ratio )
+ {
+ /* 16:9 */
+ switch( p_vts->vtsi_mat->vts_video_attr.permitted_df )
+ {
+ case 1:
+ i_position = spu_control & 0xff;
+ break;
+ case 2:
+ i_position = ( spu_control >> 8 ) & 0xff;
+ break;
+ default:
+ i_position = ( spu_control >> 16 ) & 0xff;
+ break;
+ }
+ }
+ else
+ {
+ /* 4:3 */
+ i_position = ( spu_control >> 24 ) & 0x7F;
+ }
+
+ i_id = ( ( 0x20 + i_position ) << 8 ) | 0xbd;
+ p_es = input_AddES( p_input,
+ p_input->stream.pp_programs[0], i_id, 0 );
+ p_es->i_stream_id = 0xbd;
+ p_es->i_type = DVD_SPU_ES;
+ p_es->i_cat = SPU_ES;
+ strcpy( p_es->psz_desc, DecodeLanguage( hton16(
+ p_vts->vtsi_mat->vts_subp_attr[i-1].lang_code ) ) );
+ }
+ }
+#undef spu_control
+ if( p_main->b_audio )
+ {
+ /* For audio: first one if none or a not existing one specified */
+ int i_audio = main_GetIntVariable( INPUT_CHANNEL_VAR, 1 );
+ if( i_audio < 0 || i_audio > i_audio_nb )
+ {
+ main_PutIntVariable( INPUT_CHANNEL_VAR, 1 );
+ i_audio = 1;
+ }
+ if( i_audio > 0 && i_audio_nb > 0 )
+ {
+ if( main_GetIntVariable( AOUT_SPDIF_VAR, 0 ) ||
+ ( main_GetIntVariable( INPUT_AUDIO_VAR, 0 ) ==
+ REQUESTED_AC3 ) )
+ {
+ int i_ac3 = i_audio;
+ while( ( p_input->stream.pp_es[i_ac3]->i_type !=
+ AC3_AUDIO_ES ) && ( i_ac3 <=
+ p_vts->vtsi_mat->nr_of_vts_audio_streams ) )
+ {
+ i_ac3++;
+ }
+ if( p_input->stream.pp_es[i_ac3]->i_type == AC3_AUDIO_ES )
+ {
+ input_SelectES( p_input,
+ p_input->stream.pp_es[i_ac3] );
+ }
+ }
+ else
+ {
+ input_SelectES( p_input,
+ p_input->stream.pp_es[i_audio] );
+ }
+ }
+ }
+
+ if( p_main->b_video )
+ {
+ /* for spu, default is none */
+ int i_spu = main_GetIntVariable( INPUT_SUBTITLE_VAR, 0 );
+ if( i_spu < 0 || i_spu > i_spu_nb )
+ {
+ main_PutIntVariable( INPUT_SUBTITLE_VAR, 0 );
+ i_spu = 0;
+ }
+ if( i_spu > 0 && i_spu_nb > 0 )
+ {
+ i_spu += p_vts->vtsi_mat->nr_of_vts_audio_streams;
+ input_SelectES( p_input, p_input->stream.pp_es[i_spu] );
+ }
+ }
+ } /* i_title >= 0 */
+ else
+ {
+ p_area = p_input->stream.p_selected_area;
+ }
+
+ /*
+ * Chapter selection
+ */
+
+ if( p_area->i_part != p_dvd->i_chapter )
+ {
+ if( ( p_area->i_part > 0 ) &&
+ ( p_area->i_part <= p_area->i_part_nb ))
+ {
+ p_dvd->i_ttn = p_vmg->tt_srpt->title[p_area->i_id-1].vts_ttn;
+ pgc_id = p_vts->vts_ptt_srpt->title[
+ p_dvd->i_ttn-1].ptt[p_area->i_part-1].pgcn;
+ pgn = p_vts->vts_ptt_srpt->title[
+ p_dvd->i_ttn-1].ptt[p_area->i_part-1].pgn;
+
+ p_pgc = p_vts->vts_pgcit->pgci_srp[ pgc_id - 1 ].pgc;
+
+ p_dvd->i_cur_cell = p_pgc->program_map[ pgn - 1 ] - 1;
+ p_dvd->i_chapter = p_area->i_part;
+ DvdReadFindCell( p_dvd );
+
+ p_dvd->i_pack_len = 0;
+ p_dvd->i_next_vobu = p_dvd->i_cur_block =
+ p_pgc->cell_playback[p_dvd->i_cur_cell].first_sector;
+ }
+ else
+ {
+ p_area->i_part = p_dvd->i_chapter;
+ }
+ }
+#undef p_vts
+#undef p_vmg
+
+ if( p_area->i_angle != p_dvd->i_angle )
+ {
+ p_dvd->i_angle = p_area->i_angle;
+
+ intf_WarnMsg( 3, "dvd info: angle %d selected", p_area->i_angle );
+ }
+ /* warn interface that something has changed */
+ p_area->i_tell = LB2OFF( p_dvd->i_next_vobu ) - p_area->i_start;
+ p_input->stream.b_seekable = 1;
+ p_input->stream.b_changed = 1;
+
+ return 0;
+}
+
+
+/*****************************************************************************
+ * DvdReadRead: reads data packets into the netlist.
+ *****************************************************************************
+ * Returns -1 in case of error, 0 if everything went well, and 1 in case of
+ * EOF.
+ *****************************************************************************/
+static int DvdReadRead( input_thread_t * p_input,
+ data_packet_t ** pp_packets )
+{
+ thread_dvd_data_t * p_dvd;
+ netlist_t * p_netlist;
+ u8 p_data[DVD_VIDEO_LB_LEN];
+ struct iovec * p_vec;
+ struct data_packet_s * pp_data[DVD_DATA_READ_ONCE];
+ u8 * pi_cur;
+ int i_blocks;
+ int i_read;
+ int i_iovec;
+ int i_packet_size;
+ int i_packet;
+ int i_pos;
+
+ p_dvd = (thread_dvd_data_t *)p_input->p_plugin_data;
+ p_netlist = (netlist_t *)p_input->p_method_data;
+
+ /*
+ * Playback by cell in this pgc, starting at the cell for our chapter.
+ */
+
+ /*
+ * End of pack, we select the following one
+ */
+ if( ! p_dvd->i_pack_len )
+ {
+ /*
+ * Read NAV packet.
+ */
+ if( ( i_read = DVDReadBlocks( p_dvd->p_title, p_dvd->i_next_vobu,
+ 1, p_data ) ) != 1 )
+ {
+ intf_ErrMsg( "dvdread error: read failed for block %d",
+ p_dvd->i_next_vobu );
+ return -1;
+ }
+
+ assert( p_data[41] == 0xbf && p_data[1027] == 0xbf );
+
+ /*
+ * Parse the contained dsi packet.
+ */
+
+ DvdReadHandleDSI( p_dvd, p_data );
+
+ /* End of File */
+ if( p_dvd->i_next_vobu >= p_dvd->i_end_block + 1 )
+ {
+ return 1;
+ }
+
+ assert( p_dvd->i_pack_len < 1024 );
+ /* Ugly kludge: we send the pack block to the input for it
+ * sometimes has a zero scr and restart the sync */
+// p_dvd->i_cur_block ++;
+ p_dvd->i_pack_len++;
+
+ }
+
+ /*
+ * Compute the number of blocks to read
+ */
+ i_blocks = p_dvd->i_pack_len >= DVD_BLOCK_READ_ONCE
+ ? DVD_BLOCK_READ_ONCE : p_dvd->i_pack_len;
+ p_dvd->i_pack_len -= i_blocks;
+ p_netlist->i_read_once = i_blocks;
+
+ /* Get an iovec pointer */
+ if( ( p_vec = input_NetlistGetiovec( p_netlist ) ) == NULL )
+ {
+ intf_ErrMsg( "dvdread error: can't get iovec" );
+ return -1;
+ }
+
+ /* Reads from DVD */
+ i_read = DVDReadVBlocks( p_dvd->p_title, p_dvd->i_cur_block,
+ i_blocks, p_vec );
+ if( i_read != i_blocks )
+ {
+ intf_ErrMsg( "dvdread error: read failed for %d/%d blocks at 0x%02x",
+ i_read, i_blocks, p_dvd->i_cur_block );
+ return -1;
+ }
+
+ p_dvd->i_cur_block += i_read;
+/*
+ intf_WarnMsg( 12, "dvdread i_blocks: %d len: %d current: 0x%02x", i_read, p_dvd->i_pack_len, p_dvd->i_cur_block );
+*/
+ /* Update netlist indexes: we don't do it in DVDGetiovec since we
+ * need know the real number of blocks read */
+ input_NetlistMviovec( p_netlist, i_read, pp_data );
+
+ i_packet = 0;
+
+ /* Read headers to compute payload length */
+ for( i_iovec = 0 ; i_iovec < i_read ; i_iovec++ )
+ {
+ i_pos = 0;
+
+ while( i_pos < p_netlist->i_buffer_size )
+ {
+ pi_cur = (u8*)p_vec[i_iovec].iov_base + i_pos;
+
+ /*default header */
+ if( U32_AT( pi_cur ) != 0x1BA )
+ {
+ /* That's the case for all packets, except pack header. */
+ i_packet_size = U16_AT( pi_cur + 4 );
+ pp_packets[i_packet] = input_NetlistNewPtr( p_netlist );
+ (*pp_data[i_iovec]->pi_refcount)++;
+ pp_packets[i_packet]->pi_refcount =
+ pp_data[i_iovec]->pi_refcount;
+ pp_packets[i_packet]->p_buffer = pp_data[i_iovec]->p_buffer;
+ }
+ else
+ {
+ /* MPEG-2 Pack header. */
+ i_packet_size = 8;
+ pp_packets[i_packet] = pp_data[i_iovec];
+
+ }
+
+ pp_packets[i_packet]->p_payload_start =
+ pp_packets[i_packet]->p_buffer + i_pos;
+
+ pp_packets[i_packet]->p_payload_end =
+ pp_packets[i_packet]->p_payload_start + i_packet_size + 6;
+
+ pp_packets[i_packet]->p_next = NULL;
+ pp_packets[i_packet]->b_discard_payload = 0;
+
+ i_packet++;
+ i_pos += i_packet_size + 6;
+ }
+ }
+
+ pp_packets[i_packet] = NULL;
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+
+ p_input->stream.p_selected_area->i_tell =
+ LB2OFF( p_dvd->i_cur_block ) -
+ p_input->stream.p_selected_area->i_start;
+
+ if( p_dvd->b_eoc )
+ {
+ /* We modify i_part only at end of chapter not to erase
+ * some modification from the interface */
+ p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
+ p_dvd->b_eoc = 0;
+ }
+
+
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+ return 0;
+}
+#undef p_pgc
+
+/*****************************************************************************
+ * DVDRewind : reads a stream backward
+ *****************************************************************************/
+static int DvdReadRewind( input_thread_t * p_input )
+{
+ return( -1 );
+}
+
+/*****************************************************************************
+ * DvdReadSeek : Goes to a given position on the stream.
+ *****************************************************************************
+ * This one is used by the input and translate chronological position from
+ * input to logical position on the device.
+ * The lock should be taken before calling this function.
+ *****************************************************************************/
+static void DvdReadSeek( input_thread_t * p_input, off_t i_off )
+{
+ thread_dvd_data_t * p_dvd;
+ int i_lb;
+ int i_tmp;
+ int i_chapter = 0;
+ int i_cell = 0;
+ int i_vobu = 0;
+ int i_sub_cell = 0;
+
+ i_off += p_input->stream.p_selected_area->i_start;
+ i_lb = OFF2LB( i_off );
+ p_dvd = ( thread_dvd_data_t * )p_input->p_plugin_data;
+
+ /* find cell */
+ while( p_dvd->p_cur_pgc->cell_playback[i_cell].last_sector < i_lb )
+ {
+ i_cell++;
+ }
+
+ /* find chapter */
+ do
+ {
+ pgc_t * p_pgc;
+ int pgc_id, pgn;
+
+ i_chapter++;
+ pgc_id = p_dvd->p_vts_file->vts_ptt_srpt->title[
+ p_dvd->i_ttn-1].ptt[i_chapter].pgcn;
+ pgn = p_dvd->p_vts_file->vts_ptt_srpt->title[
+ p_dvd->i_ttn-1].ptt[i_chapter].pgn;
+
+ p_pgc = p_dvd->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc;
+ i_tmp = p_pgc->program_map[pgn-1];
+
+ } while( i_tmp <= i_cell );
+
+ /* find vobu */
+ while( p_dvd->p_vts_file->vts_vobu_admap->vobu_start_sectors[i_vobu]
+ <= i_lb )
+ {
+ i_vobu++;
+ }
+
+ /* find sub_cell */
+ while( p_dvd->p_vts_file->vts_c_adt->cell_adr_table[i_sub_cell].start_sector <
+ p_dvd->p_vts_file->vts_vobu_admap->vobu_start_sectors[i_vobu-1] )
+ {
+ i_sub_cell++;
+ }
+
+/*
+ intf_WarnMsg(12, "cell %d i_sub_cell %d chapter %d vobu %d cell_sector %d vobu_sector %d sub_cell_sector %d",
+ i_cell, i_sub_cell,i_chapter, i_vobu,
+ p_dvd->p_cur_pgc->cell_playback[i_cell].first_sector,
+ p_dvd->p_vts_file->vts_vobu_admap->vobu_start_sectors[i_vobu],
+ p_dvd->p_vts_file->vts_c_adt->cell_adr_table[i_sub_cell-1].start_sector);
+*/
+ p_dvd->i_cur_block = i_lb;
+ p_dvd->i_next_vobu =
+ p_dvd->p_vts_file->vts_vobu_admap->vobu_start_sectors[i_vobu];
+ p_dvd->i_pack_len = p_dvd->i_next_vobu - i_lb;
+ p_dvd->i_cur_cell = i_cell;
+ p_dvd->i_chapter = i_chapter;
+ DvdReadFindCell( p_dvd );
+
+ p_input->stream.p_selected_area->i_tell =
+ LB2OFF ( p_dvd->i_cur_block )
+ - p_input->stream.p_selected_area->i_start;
+ p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
+
+ return;
+}
+
+/*****************************************************************************
+ * DvdReadHandleDSI
+ *****************************************************************************/
+static void DvdReadHandleDSI( thread_dvd_data_t * p_dvd, u8 * p_data )
+{
+ navRead_DSI( &(p_dvd->dsi_pack), &(p_data[ DSI_START_BYTE ]) );
+
+ /*
+ * Determine where we go next. These values are the ones we mostly
+ * care about.
+ */
+ p_dvd->i_cur_block = p_dvd->dsi_pack.dsi_gi.nv_pck_lbn;
+
+ /*
+ * If we're not at the end of this cell, we can determine the next
+ * VOBU to display using the VOBU_SRI information section of the
+ * DSI. Using this value correctly follows the current angle,
+ * avoiding the doubled scenes in The Matrix, and makes our life
+ * really happy.
+ */
+ if( p_dvd->dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL )
+ {
+#if 1
+ switch( ( p_dvd->dsi_pack.sml_pbi.category & 0xf000 ) >> 12 )
+ {
+ case 0x4:
+ /* interleaved unit with no angle */
+ if( p_dvd->dsi_pack.sml_pbi.ilvu_sa != -1 )
+ {
+ p_dvd->i_next_vobu = p_dvd->i_cur_block +
+ p_dvd->dsi_pack.sml_pbi.ilvu_sa;
+ p_dvd->i_pack_len = p_dvd->dsi_pack.sml_pbi.ilvu_ea;
+ }
+ else
+ {
+ p_dvd->i_next_vobu = p_dvd->i_cur_block +
+ p_dvd->dsi_pack.dsi_gi.vobu_ea + 1;
+ p_dvd->i_pack_len = p_dvd->dsi_pack.dsi_gi.vobu_ea;
+ }
+ break;
+ case 0x5:
+ /* vobu is end of ilvu */
+ if( p_dvd->dsi_pack.sml_agli.data[p_dvd->i_angle-1].address )
+ {
+ p_dvd->i_next_vobu = p_dvd->i_cur_block +
+ p_dvd->dsi_pack.sml_agli.data[p_dvd->i_angle-1].address;
+ p_dvd->i_pack_len = p_dvd->dsi_pack.sml_pbi.ilvu_ea;
+
+ break;
+ }
+ case 0x6:
+ /* vobu is beginning of ilvu */
+ case 0x9:
+ /* next scr is 0 */
+ case 0xa:
+ /* entering interleaved section */
+ case 0x8:
+ /* non interleaved cells in interleaved section */
+ default:
+ p_dvd->i_next_vobu = p_dvd->i_cur_block +
+ ( p_dvd->dsi_pack.vobu_sri.next_vobu & 0x7fffffff );
+ p_dvd->i_pack_len = p_dvd->dsi_pack.dsi_gi.vobu_ea;
+ break;
+ }
+#else
+ p_dvd->i_next_vobu = p_dvd->i_cur_block +
+ ( p_dvd->dsi_pack.vobu_sri.next_vobu & 0x7fffffff );
+ p_dvd->i_pack_len = p_dvd->dsi_pack.dsi_gi.vobu_ea;
+#endif
+ }
+ else
+ {
+ p_dvd->i_cur_cell = p_dvd->i_next_cell;
+ DvdReadFindCell( p_dvd );
+
+ p_dvd->i_pack_len = p_dvd->dsi_pack.dsi_gi.vobu_ea;
+ p_dvd->i_next_vobu =
+ p_dvd->p_cur_pgc->cell_playback[p_dvd->i_cur_cell].first_sector;
+ }
+
+#if 0
+ intf_WarnMsg( 12, "scr %d lbn 0x%02x vobu_ea %d vob_id %d c_id %d",
+ p_dvd->dsi_pack.dsi_gi.nv_pck_scr,
+ p_dvd->dsi_pack.dsi_gi.nv_pck_lbn,
+ p_dvd->dsi_pack.dsi_gi.vobu_ea,
+ p_dvd->dsi_pack.dsi_gi.vobu_vob_idn,
+ p_dvd->dsi_pack.dsi_gi.vobu_c_idn );
+
+ intf_WarnMsg( 12, "cat 0x%02x ilvu_ea %d ilvu_sa %d size %d",
+ p_dvd->dsi_pack.sml_pbi.category,
+ p_dvd->dsi_pack.sml_pbi.ilvu_ea,
+ p_dvd->dsi_pack.sml_pbi.ilvu_sa,
+ p_dvd->dsi_pack.sml_pbi.size );
+
+ intf_WarnMsg( 12, "next_vobu %d next_ilvu1 %d next_ilvu2 %d",
+ p_dvd->dsi_pack.vobu_sri.next_vobu & 0x7fffffff,
+ p_dvd->dsi_pack.sml_agli.data[ p_dvd->i_angle - 1 ].address,
+ p_dvd->dsi_pack.sml_agli.data[ p_dvd->i_angle ].address);
+#endif
+}
+
+/*****************************************************************************
+ * DvdReadFindCell
+ *****************************************************************************/
+static void DvdReadFindCell( thread_dvd_data_t * p_dvd )
+{
+ int pgc_id, pgn;
+ int i = 0;
+ pgc_t * p_pgc;
+#define cell p_dvd->p_cur_pgc->cell_playback
+ if( cell[p_dvd->i_cur_cell].block_type == BLOCK_TYPE_ANGLE_BLOCK )
+ {
+#if 0
+ p_dvd->i_next_cell = p_dvd->i_cur_cell + p_dvd->i_angle_nb;
+ p_dvd->i_cur_cell += p_dvd->i_angle - 1;
+#else
+ p_dvd->i_cur_cell += p_dvd->i_angle - 1;
+
+ while( cell[p_dvd->i_cur_cell+i].block_mode != BLOCK_MODE_LAST_CELL )
+ {
+ i++;
+ }
+ p_dvd->i_next_cell = p_dvd->i_cur_cell + i + 1;
+#endif
+ }
+ else
+ {
+ p_dvd->i_next_cell = p_dvd->i_cur_cell + 1;
+ }
+#undef cell
+ pgc_id = p_dvd->p_vts_file->vts_ptt_srpt->title[
+ p_dvd->i_ttn-1].ptt[p_dvd->i_chapter].pgcn;
+ pgn = p_dvd->p_vts_file->vts_ptt_srpt->title[
+ p_dvd->i_ttn-1].ptt[p_dvd->i_chapter].pgn;
+ p_pgc = p_dvd->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc;
+
+ if( p_pgc->program_map[pgn-1] <= p_dvd->i_cur_cell )
+ {
+ p_dvd->i_chapter++;
+ p_dvd->b_eoc = 1;
+ }
+}
--- /dev/null
+/*****************************************************************************
+ * input_dvdread.h: thread structure of the DVD plugin
+ *****************************************************************************
+ * Copyright (C) 1999-2001 VideoLAN
+ * $Id: input_dvdread.h,v 1.1 2001/11/25 05:04:38 stef Exp $
+ *
+ * Author: Stéphane Borel <stef@via.ecp.fr>
+ *
+ * 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, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+/* dvdread includes */
+#include "dvd_reader.h"
+#include "ifo_types.h"
+#include "ifo_read.h"
+#include "dvd_udf.h"
+#include "nav_read.h"
+#include "nav_print.h"
+#include "videolan/dvdread.h"
+
+/* Logical block size for DVD-VIDEO */
+#define LB2OFF(x) ((off_t)(x) * (off_t)(DVD_VIDEO_LB_LEN))
+#define OFF2LB(x) ((x) >> 11)
+
+/*****************************************************************************
+ * thread_dvd_data_t: extension of input_thread_t for DVD specificity.
+ *****************************************************************************/
+typedef struct thread_dvd_data_s
+{
+ dvd_reader_t * p_dvdread;
+ dvd_file_t * p_title;
+
+ ifo_handle_t * p_vmg_file;
+ ifo_handle_t * p_vts_file;
+
+ tt_srpt_t * p_tt_srpt;
+ pgc_t * p_cur_pgc;
+
+ dsi_t dsi_pack;
+
+ int i_ttn;
+
+ unsigned int i_pack_len;
+ unsigned int i_cur_block;
+ unsigned int i_next_vobu;
+ unsigned int i_end_block;
+
+ int i_cur_cell;
+ int i_next_cell;
+ int i_chapter;
+ boolean_t b_eoc;
+ int i_angle_nb;
+ int i_angle;
+
+ int i_block_once; // Nb of block read once
+} thread_dvd_data_t;
+
* decoders.
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
- * $Id: input.c,v 1.158 2001/11/23 18:47:51 massiot Exp $
+ * $Id: input.c,v 1.159 2001/11/25 05:04:38 stef Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
f.pf_open( p_input );
p_input->stream.i_method = INPUT_METHOD_DVD;
}
+ else if( ( ( strlen( p_input->p_source ) > 8 )
+ && !strncasecmp( p_input->p_source, "dvdread:", 8 ) )
+ || TestMethod( INPUT_METHOD_VAR, "dvdread" ) )
+ {
+ /* DVDRead - this is THE kludge */
+ f.pf_open( p_input );
+ p_input->stream.i_method = INPUT_METHOD_DVD;
+ }
else if( ( strlen( p_input->p_source ) > 4 )
&& !strncasecmp( p_input->p_source, "vlc:", 4 ) )
{
{
int i_size = strlen( psz_name );
- if( ( i_size > 4 )
+ if( ( i_size > 8 )
+ && !strncasecmp( psz_name, "dvdread:", 8 ) )
+ {
+ /* get rid of the 'dvdread:' stuff and try again */
+ psz_name += 8;
+ i_stat = stat( psz_name, &stat_info );
+ }
+ else if( ( i_size > 4 )
&& !strncasecmp( psz_name, "dvd:", 4 ) )
{
/* get rid of the 'dvd:' stuff and try again */