aboutsummaryrefslogtreecommitdiff
path: root/lib/libdvd
diff options
context:
space:
mode:
authortheuni <theuni-nospam-@xbmc.org>2011-01-24 16:05:21 -0500
committertheuni <theuni-nospam-@xbmc.org>2011-01-24 16:05:21 -0500
commitc51b1189e3d5353e842991f5859ddcea0f73e426 (patch)
treeef2cb8a6184699aa614f3655dca4ce661cdc108e /lib/libdvd
parentbe61ebdc9e897fe40c6f371111724de79ddee8d5 (diff)
Merged cptspiff's code-reshuffle branch.
Squashed commit due to build breakage during code-reshuffle history. Conflicts: xbmc/Util.cpp xbmc/cdrip/CDDARipper.cpp xbmc/filesystem/Directory.cpp xbmc/filesystem/File.cpp
Diffstat (limited to 'lib/libdvd')
-rw-r--r--lib/libdvd/Makefile.in75
-rw-r--r--lib/libdvd/build-xbmc-win32.sh59
-rw-r--r--lib/libdvd/includes/dvdcss/.ignoreme0
-rw-r--r--lib/libdvd/includes/dvdread/.ignoreme2
-rw-r--r--lib/libdvd/libdvdcss/AUTHORS69
-rw-r--r--lib/libdvd/libdvdcss/COPYING340
-rw-r--r--lib/libdvd/libdvdcss/ChangeLog2171
-rw-r--r--lib/libdvd/libdvdcss/INSTALL77
-rw-r--r--lib/libdvd/libdvdcss/Makefile.am12
-rw-r--r--lib/libdvd/libdvdcss/NEWS112
-rw-r--r--lib/libdvd/libdvdcss/README71
-rwxr-xr-xlib/libdvd/libdvdcss/bootstrap132
-rw-r--r--lib/libdvd/libdvdcss/configure.ac215
-rw-r--r--lib/libdvd/libdvdcss/doc/Makefile.am28
-rw-r--r--lib/libdvd/libdvdcss/doc/doxygen.cfg.in1419
-rw-r--r--lib/libdvd/libdvdcss/doc/footer.html3
-rw-r--r--lib/libdvd/libdvdcss/doc/header.html10
-rw-r--r--lib/libdvd/libdvdcss/libdvdcss.spec181
-rw-r--r--lib/libdvd/libdvdcss/src/Makefile.am37
-rw-r--r--lib/libdvd/libdvdcss/src/bsdi_dvd.h344
-rw-r--r--lib/libdvd/libdvdcss/src/bsdi_ioctl.c770
-rw-r--r--lib/libdvd/libdvdcss/src/common.h81
-rw-r--r--lib/libdvd/libdvdcss/src/css.c1696
-rw-r--r--lib/libdvd/libdvdcss/src/css.h56
-rw-r--r--lib/libdvd/libdvdcss/src/csstables.h392
-rw-r--r--lib/libdvd/libdvdcss/src/device.c1086
-rw-r--r--lib/libdvd/libdvdcss/src/device.h58
-rw-r--r--lib/libdvd/libdvdcss/src/dvdcss/Makefile.am3
-rw-r--r--lib/libdvd/libdvdcss/src/dvdcss/dvdcss.h107
-rw-r--r--lib/libdvd/libdvdcss/src/error.c68
-rw-r--r--lib/libdvd/libdvdcss/src/ioctl.c2183
-rw-r--r--lib/libdvd/libdvdcss/src/ioctl.h433
-rw-r--r--lib/libdvd/libdvdcss/src/libdvdcss.c835
-rw-r--r--lib/libdvd/libdvdcss/src/libdvdcss.h104
-rw-r--r--lib/libdvd/libdvdcss/src/libdvdcss.pc.in10
-rw-r--r--lib/libdvd/libdvdcss/test/Makefile.am15
-rw-r--r--lib/libdvd/libdvdcss/test/csstest.c130
-rw-r--r--lib/libdvd/libdvdnav/.relignore2
-rw-r--r--lib/libdvd/libdvdnav/AUTHORS6
-rw-r--r--lib/libdvd/libdvdnav/COPYING340
-rw-r--r--lib/libdvd/libdvdnav/ChangeLog134
-rw-r--r--lib/libdvd/libdvdnav/DEVELOPMENT-POLICY.txt25
-rw-r--r--lib/libdvd/libdvdnav/Makefile166
-rw-r--r--lib/libdvd/libdvdnav/Makefile.am42
-rw-r--r--lib/libdvd/libdvdnav/NEWS2
-rw-r--r--lib/libdvd/libdvdnav/README57
-rw-r--r--lib/libdvd/libdvdnav/TODO12
-rwxr-xr-xlib/libdvd/libdvdnav/autogen.sh29
-rw-r--r--lib/libdvd/libdvdnav/configure.ac253
-rwxr-xr-xlib/libdvd/libdvdnav/configure2172
-rw-r--r--lib/libdvd/libdvdnav/doc/Makefile.am8
-rw-r--r--lib/libdvd/libdvdnav/doc/doxy.conf947
-rw-r--r--lib/libdvd/libdvdnav/doc/dvd_structures107
-rw-r--r--lib/libdvd/libdvdnav/doc/library_layout53
-rw-r--r--lib/libdvd/libdvdnav/doc/mainpage.cpp51
-rw-r--r--lib/libdvd/libdvdnav/doc/tutorial.cpp253
-rw-r--r--lib/libdvd/libdvdnav/examples/Makefile.am13
-rw-r--r--lib/libdvd/libdvdnav/examples/menus.c281
-rw-r--r--lib/libdvd/libdvdnav/m4/Makefile.am11
-rw-r--r--lib/libdvd/libdvdnav/m4/dvdnav.m4181
-rw-r--r--lib/libdvd/libdvdnav/misc/Makefile.am8
-rw-r--r--lib/libdvd/libdvdnav/misc/Makefile.common10
-rw-r--r--lib/libdvd/libdvdnav/misc/dvdnav-config.in88
-rw-r--r--lib/libdvd/libdvdnav/misc/dvdnav-config2.sh72
-rw-r--r--lib/libdvd/libdvdnav/misc/dvdnav.pc.in12
-rw-r--r--lib/libdvd/libdvdnav/misc/dvdnavmini.pc.in11
-rw-r--r--lib/libdvd/libdvdnav/misc/libdvdnav.spec.in50
-rwxr-xr-xlib/libdvd/libdvdnav/misc/relchk.sh.in66
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/config.h51
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/contrib/bcopy.c8
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/contrib/dirent/dirent.c135
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/contrib/dirent/dirent.h32
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/contrib/dlfcn.c97
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/contrib/getopt.c1009
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/contrib/timer/timer.c102
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/contrib/timer/timer.h39
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/ifo_dump.dsp110
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/include/dlfcn.h23
-rw-r--r--lib/libdvd/libdvdnav/msvc/include/dvdnav_internal.h185
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/include/getopt.h134
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/include/inttypes.h32
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/include/os_types.h27
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/include/pthreads/pthread.h1077
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/include/pthreads/sched.h89
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/include/sys/time.h28
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/include/timer.h39
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/include/unistd.h69
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/install/README7
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/libdvdcss.def12
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/libdvdcss.dsp139
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/libdvdnav.def82
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/libdvdnav.dsp156
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/libdvdnav.dsw101
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/libwin32utils.def229
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/libwin32utils.dsp136
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/play_title.dsp101
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/scripts/libdvdcss_install.bat8
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/scripts/libdvdnav_install.bat21
-rwxr-xr-xlib/libdvd/libdvdnav/msvc/title_info.dsp101
-rw-r--r--lib/libdvd/libdvdnav/src/FELLOWSHIP.map163
-rw-r--r--lib/libdvd/libdvdnav/src/Makefile.am34
-rw-r--r--lib/libdvd/libdvdnav/src/README.MAP105
-rw-r--r--lib/libdvd/libdvdnav/src/dvd_types.h278
-rw-r--r--lib/libdvd/libdvdnav/src/dvdnav.c1451
-rw-r--r--lib/libdvd/libdvdnav/src/dvdnav.h720
-rw-r--r--lib/libdvd/libdvdnav/src/dvdnav_events.h239
-rw-r--r--lib/libdvd/libdvdnav/src/dvdnav_internal.h218
-rw-r--r--lib/libdvd/libdvdnav/src/highlight.c497
-rw-r--r--lib/libdvd/libdvdnav/src/navigation.c200
-rw-r--r--lib/libdvd/libdvdnav/src/read_cache.c356
-rw-r--r--lib/libdvd/libdvdnav/src/read_cache.h49
-rw-r--r--lib/libdvd/libdvdnav/src/remap.c269
-rw-r--r--lib/libdvd/libdvdnav/src/remap.h33
-rw-r--r--lib/libdvd/libdvdnav/src/searching.c782
-rw-r--r--lib/libdvd/libdvdnav/src/settings.c97
-rw-r--r--lib/libdvd/libdvdnav/src/vm/Makefile.am16
-rw-r--r--lib/libdvd/libdvdnav/src/vm/decoder.c788
-rw-r--r--lib/libdvd/libdvdnav/src/vm/decoder.h112
-rw-r--r--lib/libdvd/libdvdnav/src/vm/vm.c1947
-rw-r--r--lib/libdvd/libdvdnav/src/vm/vm.h185
-rw-r--r--lib/libdvd/libdvdnav/src/vm/vmcmd.c549
-rw-r--r--lib/libdvd/libdvdnav/src/vm/vmcmd.h31
-rw-r--r--lib/libdvd/libdvdnav/version.h1
-rwxr-xr-xlib/libdvd/libdvdnav/version.sh18
-rw-r--r--lib/libdvd/libdvdread/.relignore2
-rw-r--r--lib/libdvd/libdvdread/AUTHORS6
-rw-r--r--lib/libdvd/libdvdread/COPYING340
-rw-r--r--lib/libdvd/libdvdread/ChangeLog130
-rw-r--r--lib/libdvd/libdvdread/DEVELOPMENT-POLICY.txt25
-rw-r--r--lib/libdvd/libdvdread/Makefile166
-rw-r--r--lib/libdvd/libdvdread/Makefile.am42
-rw-r--r--lib/libdvd/libdvdread/NEWS2
-rw-r--r--lib/libdvd/libdvdread/README57
-rw-r--r--lib/libdvd/libdvdread/TODO12
-rwxr-xr-xlib/libdvd/libdvdread/autogen.sh29
-rw-r--r--lib/libdvd/libdvdread/configure.ac210
-rwxr-xr-xlib/libdvd/libdvdread/configure2155
-rw-r--r--lib/libdvd/libdvdread/m4/Makefile.am11
-rw-r--r--lib/libdvd/libdvdread/m4/dvdread.m4181
-rw-r--r--lib/libdvd/libdvdread/misc/Makefile.am8
-rw-r--r--lib/libdvd/libdvdread/misc/Makefile.common10
-rw-r--r--lib/libdvd/libdvdread/misc/dvdread-config.in80
-rw-r--r--lib/libdvd/libdvdread/misc/dvdread-config.sh56
-rw-r--r--lib/libdvd/libdvdread/misc/dvdread.pc.in11
-rw-r--r--lib/libdvd/libdvdread/misc/libdvdread.spec.in50
-rwxr-xr-xlib/libdvd/libdvdread/misc/relchk.sh.in66
-rwxr-xr-xlib/libdvd/libdvdread/msvc/config.h51
-rwxr-xr-xlib/libdvd/libdvdread/msvc/contrib/bcopy.c8
-rwxr-xr-xlib/libdvd/libdvdread/msvc/contrib/dirent/dirent.c135
-rwxr-xr-xlib/libdvd/libdvdread/msvc/contrib/dirent/dirent.h32
-rwxr-xr-xlib/libdvd/libdvdread/msvc/contrib/dlfcn.c97
-rwxr-xr-xlib/libdvd/libdvdread/msvc/contrib/getopt.c1009
-rwxr-xr-xlib/libdvd/libdvdread/msvc/contrib/timer/timer.c102
-rwxr-xr-xlib/libdvd/libdvdread/msvc/contrib/timer/timer.h39
-rwxr-xr-xlib/libdvd/libdvdread/msvc/ifo_dump.dsp110
-rwxr-xr-xlib/libdvd/libdvdread/msvc/include/dlfcn.h23
-rw-r--r--lib/libdvd/libdvdread/msvc/include/dvdnav_internal.h185
-rwxr-xr-xlib/libdvd/libdvdread/msvc/include/getopt.h134
-rwxr-xr-xlib/libdvd/libdvdread/msvc/include/inttypes.h32
-rwxr-xr-xlib/libdvd/libdvdread/msvc/include/os_types.h27
-rwxr-xr-xlib/libdvd/libdvdread/msvc/include/pthreads/pthread.h1077
-rwxr-xr-xlib/libdvd/libdvdread/msvc/include/pthreads/sched.h89
-rwxr-xr-xlib/libdvd/libdvdread/msvc/include/sys/time.h28
-rwxr-xr-xlib/libdvd/libdvdread/msvc/include/timer.h39
-rwxr-xr-xlib/libdvd/libdvdread/msvc/include/unistd.h69
-rwxr-xr-xlib/libdvd/libdvdread/msvc/install/README7
-rwxr-xr-xlib/libdvd/libdvdread/msvc/libdvdcss.def12
-rwxr-xr-xlib/libdvd/libdvdread/msvc/libdvdcss.dsp139
-rwxr-xr-xlib/libdvd/libdvdread/msvc/libdvdnav.def82
-rwxr-xr-xlib/libdvd/libdvdread/msvc/libdvdnav.dsp188
-rwxr-xr-xlib/libdvd/libdvdread/msvc/libdvdnav.dsw101
-rwxr-xr-xlib/libdvd/libdvdread/msvc/libwin32utils.def229
-rwxr-xr-xlib/libdvd/libdvdread/msvc/libwin32utils.dsp136
-rwxr-xr-xlib/libdvd/libdvdread/msvc/play_title.dsp101
-rwxr-xr-xlib/libdvd/libdvdread/msvc/scripts/libdvdcss_install.bat8
-rwxr-xr-xlib/libdvd/libdvdread/msvc/scripts/libdvdnav_install.bat21
-rwxr-xr-xlib/libdvd/libdvdread/msvc/title_info.dsp101
-rw-r--r--lib/libdvd/libdvdread/src/Makefile.am19
-rw-r--r--lib/libdvd/libdvdread/src/bitreader.c116
-rw-r--r--lib/libdvd/libdvdread/src/bitreader.h40
-rw-r--r--lib/libdvd/libdvdread/src/bswap.h104
-rw-r--r--lib/libdvd/libdvdread/src/dvd_input.c362
-rw-r--r--lib/libdvd/libdvdread/src/dvd_input.h67
-rw-r--r--lib/libdvd/libdvdread/src/dvd_reader.c1395
-rw-r--r--lib/libdvd/libdvdread/src/dvd_reader.h275
-rw-r--r--lib/libdvd/libdvdread/src/dvd_udf.c968
-rw-r--r--lib/libdvd/libdvdread/src/dvd_udf.h62
-rw-r--r--lib/libdvd/libdvdread/src/dvdread_internal.h15
-rw-r--r--lib/libdvd/libdvdread/src/ifo_print.c1251
-rw-r--r--lib/libdvd/libdvdread/src/ifo_print.h53
-rw-r--r--lib/libdvd/libdvdread/src/ifo_read.c2212
-rw-r--r--lib/libdvd/libdvdread/src/ifo_read.h227
-rw-r--r--lib/libdvd/libdvdread/src/ifo_types.h747
-rw-r--r--lib/libdvd/libdvdread/src/md5.c411
-rw-r--r--lib/libdvd/libdvdread/src/md5.h161
-rw-r--r--lib/libdvd/libdvdread/src/nav_print.c252
-rw-r--r--lib/libdvd/libdvdread/src/nav_print.h50
-rw-r--r--lib/libdvd/libdvdread/src/nav_read.c265
-rw-r--r--lib/libdvd/libdvdread/src/nav_read.h51
-rw-r--r--lib/libdvd/libdvdread/src/nav_types.h249
-rw-r--r--lib/libdvd/libdvdread/version.h1
-rwxr-xr-xlib/libdvd/libdvdread/version.sh18
202 files changed, 45794 insertions, 0 deletions
diff --git a/lib/libdvd/Makefile.in b/lib/libdvd/Makefile.in
new file mode 100644
index 0000000000..e7910dae16
--- /dev/null
+++ b/lib/libdvd/Makefile.in
@@ -0,0 +1,75 @@
+
+ARCH=@ARCH@
+SYSDIR=@abs_top_srcdir@/system/players/dvdplayer
+SOS= libdvdnav-$(ARCH).so
+DIRS= libdvdread \
+ libdvdnav
+
+WRAPPER=@abs_top_srcdir@/xbmc/cores/DllLoader/exports/wrapper.o
+WRAPPER_OSX=@abs_top_srcdir@/tools/Mach5/wrapper.rb
+
+LDFLAGS += -shared -fPIC -rdynamic
+ifeq ($(ARCH), powerpc-osx)
+ # Add -lbundle1.o for powerpc-osx
+ BUNDLE1_O = -lbundle1.o
+endif
+
+# Allows us to optionally build xbmc with DVDCSS support
+ifeq (@BUILD_DVDCSS@,1)
+ DIRS += libdvdcss
+ SOS += libdvdcss-$(ARCH).so
+ DVDCSS_A = libdvdcss/src/.libs/libdvdcss.a
+ DVDCSS_O = libdvdcss/src/.libs/*.o
+ DVDNAV_PREREQ = libdvdcss
+endif
+
+SLIB=$(addprefix $(SYSDIR)/, $(SOS))
+
+DISTCLEAN_FILES=includes/dvdread/*.h \
+ includes/dvdcss/*.h \
+ libdvdnav/config.h \
+ libdvdread/config.h
+
+.PHONY: $(DIRS) compile
+
+all: $(SLIB)
+
+ifeq ($(findstring osx,$(ARCH)), osx)
+
+$(SYSDIR)/libdvdcss-$(ARCH).so: $(WRAPPER_OSX) libdvdcss/src/.libs/libdvdcss.a
+ ld -bundle -flat_namespace -undefined suppress -o $@ \
+ libdvdcss/src/*.o $(BUNDLE1_O)
+ $(WRAPPER_OSX) $@;mv output.so $@
+
+$(SYSDIR)/libdvdnav-$(ARCH).so: $(WRAPPER_OSX) $(DVDCSS_A) libdvdread/obj/libdvdread.a libdvdnav/obj/libdvdnav.a
+ ld -bundle -flat_namespace -undefined suppress -o $@ \
+ $(DVDCSS_O) libdvdread/obj/*.o libdvdnav/obj/*.o $(BUNDLE1_O)
+ $(WRAPPER_OSX) $@;mv output.so $@
+
+else
+
+$(SYSDIR)/libdvdcss-$(ARCH).so: $(WRAPPER) libdvdcss/src/.libs/libdvdcss.a
+ $(CC) -o $@ $(LDFLAGS) --soname,$@ \
+ libdvdcss/src/*.o \
+ `cat $(WRAPPER:.o=.def)` $(WRAPPER)
+
+$(SYSDIR)/libdvdnav-$(ARCH).so: $(WRAPPER) $(DVDCSS_A) libdvdread/obj/libdvdread.a libdvdnav/obj/libdvdnav.a
+ $(CC) -o $@ $(LDFLAGS) --soname,$@ $(DVDCSS_O) libdvdread/obj/*.o libdvdnav/obj/*.o \
+ `cat $(WRAPPER:.o=.def)` $(WRAPPER)
+
+endif
+
+libdvdcss/src/.libs/libdvdcss.a: libdvdcss
+libdvdcss: compile
+ $(MAKE) -C $@
+
+libdvdread/obj/libdvdread.a: libdvdread
+libdvdread: compile
+ $(MAKE) -C $@
+
+libdvdnav/obj/libdvdnav.a: libdvdnav
+libdvdnav: compile
+ $(MAKE) -C $@
+
+include @abs_top_srcdir@/Makefile.include
+
diff --git a/lib/libdvd/build-xbmc-win32.sh b/lib/libdvd/build-xbmc-win32.sh
new file mode 100644
index 0000000000..db39eef2d8
--- /dev/null
+++ b/lib/libdvd/build-xbmc-win32.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+
+#libdvdcss
+cd libdvdcss
+echo "***** Cleaning libdvdcss *****"
+make distclean
+echo "***** Building libdvdcss *****"
+sh bootstrap
+./configure \
+ CFLAGS="-DNDEBUG" \
+ --disable-doc \
+ --enable-static \
+ --with-pic
+make
+strip -S src/.libs/libdvdcss-2.dll
+cd ..
+mkdir -p includes/dvdcss
+cp libdvdcss/src/dvdcss/dvdcss.h includes/dvdcss
+cp libdvdcss/src/.libs/libdvdcss-2.dll ../../../../../system/players/dvdplayer/
+
+#libdvdread
+cd libdvdread
+echo "***** Cleaning libdvdread *****"
+make distclean
+echo "***** Building libdvdread *****"
+./configure2 \
+ --disable-shared \
+ --enable-static \
+ --extra-cflags="-DHAVE_DVDCSS_DVDCSS_H -D_XBMC -DNDEBUG -D_MSC_VER -I`pwd`/../includes" \
+ --disable-debug
+mkdir -p ../includes/dvdread
+cp ../libdvdread/src/*.h ../includes/dvdread
+make
+cd ..
+
+#libdvdnav
+cd libdvdnav
+echo "***** Cleaning libdvdnav *****"
+make distclean
+echo "***** Building libdvdnav *****"
+./configure2 \
+ --disable-shared \
+ --enable-static \
+ --extra-cflags="-D_XBMC -DNDEBUG -I`pwd`/../includes" \
+ --with-dvdread-config="`pwd`/../libdvdread/obj/dvdread-config" \
+ --disable-debug
+make
+gcc \
+ -shared \
+ -o obj/libdvdnav.dll \
+ ../libdvdread/obj/*.o obj/*.o ../libdvdcss/src/.libs/libdvdcss.dll.a \
+ -ldl \
+ -Wl,--enable-auto-image-base \
+ -Xlinker --enable-auto-import
+
+strip -S obj/libdvdnav.dll
+cd ..
+cp libdvdnav/obj/libdvdnav.dll ../../../../../system/players/dvdplayer/
+echo "***** Done *****"
diff --git a/lib/libdvd/includes/dvdcss/.ignoreme b/lib/libdvd/includes/dvdcss/.ignoreme
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/libdvd/includes/dvdcss/.ignoreme
diff --git a/lib/libdvd/includes/dvdread/.ignoreme b/lib/libdvd/includes/dvdread/.ignoreme
new file mode 100644
index 0000000000..62d0910142
--- /dev/null
+++ b/lib/libdvd/includes/dvdread/.ignoreme
@@ -0,0 +1,2 @@
+Dummy file so that this directory shows up for git users.
+Ignore this file.
diff --git a/lib/libdvd/libdvdcss/AUTHORS b/lib/libdvd/libdvdcss/AUTHORS
new file mode 100644
index 0000000000..810cbdd0e2
--- /dev/null
+++ b/lib/libdvd/libdvdcss/AUTHORS
@@ -0,0 +1,69 @@
+# The format of this file was inspired by the Linux kernel CREDITS file.
+#
+# Authors and contributors are listed alphabetically.
+#
+# The fields are: name (N), email (E), web-address (W), CVS account login (C),
+# PGP key ID and fingerprint (P), description (D), and snail-mail address (S).
+
+N: Billy Biggs
+E: vektor@dumbterm.net
+D: libdvdcss enhancements
+
+N: Stéphane Borel
+E: stef@via.ecp.fr
+C: stef
+D: original CSS decryption code from vlc
+
+N: Sven Heithecker
+E: sven.heithecker@web.de
+D: cache bug fix for discs with identical content but different keys
+
+N: Håkan Hjort
+E: d95hjort@dtek.chalmers.se
+D: Solaris port of the DVD ioctls
+D: libdvdcss enhancements
+
+N: Samuel Hocevar
+E: sam@zoy.org
+C: sam
+D: original CSS decryption code from vlc
+
+N: Eugenio Jarosiewicz
+E: ej0@cise.ufl.edu
+C: ej
+D: MacOS X DVD ioctls
+
+N: Jon Lech Johansen
+E: jon-vl@nanocrew.net
+C: jlj
+D: Win32 port
+D: Fixes to the Darwin port
+
+N: Markus Kuespert
+E: ltlBeBoy@beosmail.com
+D: BeOS port of the DVD ioctls
+
+N: Pascal Levesque
+E: Pascal.Levesque@mindready.com
+D: QNX port
+
+N: Steven M. Schultz
+E: sms@TO.GD-ES.COM
+D: BSD/OS port
+
+N: David Siebörger
+E: drs-videolan@rucus.ru.ac.za
+D: HP-UX port of the DVD ioctls
+
+N: Alex Strelnikov
+E: lelik@os2.ru
+D: OS/2 port
+
+N: German Tischler
+E: tanis@gaspode.franken.de
+D: FreeBSD DVD input patch
+
+N: Gildas Bazin
+E: gbazin@netcourrier.com
+C: gbazin
+D: various fixes to the Win32 port
diff --git a/lib/libdvd/libdvdcss/COPYING b/lib/libdvd/libdvdcss/COPYING
new file mode 100644
index 0000000000..d60c31a97a
--- /dev/null
+++ b/lib/libdvd/libdvdcss/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/lib/libdvd/libdvdcss/ChangeLog b/lib/libdvd/libdvdcss/ChangeLog
new file mode 100644
index 0000000000..7b3abcacc8
--- /dev/null
+++ b/lib/libdvd/libdvdcss/ChangeLog
@@ -0,0 +1,2171 @@
+------------------------------------------------------------------------
+r217 | sam | 2008-08-29 18:57:52 +0000 (Fri, 29 Aug 2008) | 2 lines
+Changed paths:
+ M /trunk/src/Makefile.am
+
+ * src/Makefile.am: bump the library minor version since we ship an extra
+ symbole (dvdcss_is_scrambled).
+------------------------------------------------------------------------
+r216 | sam | 2008-08-29 18:57:51 +0000 (Fri, 29 Aug 2008) | 1 line
+Changed paths:
+ M /trunk/configure.ac
+ M /trunk/src/Makefile.am
+ A /trunk/src/libdvdcss.pc.in
+
+ * Ship a .pc file with the library.
+------------------------------------------------------------------------
+r215 | sam | 2008-08-29 18:57:48 +0000 (Fri, 29 Aug 2008) | 1 line
+Changed paths:
+ M /trunk/libdvdcss.spec
+ M /trunk/src/common.h
+ M /trunk/src/css.c
+ M /trunk/src/device.h
+ M /trunk/src/dvdcss/dvdcss.h
+ M /trunk/src/error.c
+ M /trunk/src/ioctl.c
+ M /trunk/src/ioctl.h
+ M /trunk/src/libdvdcss.c
+ M /trunk/src/libdvdcss.h
+ M /trunk/test/csstest.c
+
+ * Update copyeight information here and there.
+------------------------------------------------------------------------
+r214 | sam | 2008-08-29 18:57:45 +0000 (Fri, 29 Aug 2008) | 3 lines
+Changed paths:
+ A /trunk/.gitignore
+ M /trunk/bootstrap
+ M /trunk/configure.ac
+
+ * bootstrap: update bootstrapping script.
+ * configure.ac: hide autotools files in .auto/.
+ * .gitignore: add an ignore file for git-svn users.
+------------------------------------------------------------------------
+r213 | sam | 2008-08-29 18:57:42 +0000 (Fri, 29 Aug 2008) | 2 lines
+Changed paths:
+ M /trunk/src/libdvdcss.c
+
+ * libdvdcss.c: ignore failure to get the disc key in case we have a
+ chance to decrypt anyway afterwards. Patch courtesy of Diego Biurrun.
+------------------------------------------------------------------------
+r212 | sam | 2008-07-13 12:52:22 +0000 (Sun, 13 Jul 2008) | 2 lines
+Changed paths:
+ M /trunk/src/css.c
+ M /trunk/src/css.h
+ M /trunk/src/csstables.h
+ M /trunk/src/device.c
+ M /trunk/src/device.h
+ M /trunk/src/dvdcss/dvdcss.h
+ M /trunk/src/ioctl.c
+ M /trunk/src/libdvdcss.c
+ M /trunk/src/libdvdcss.h
+
+ * Convert all source code to UTF-8, or Doxygen will fail to generate proper
+ LaTeX documents.
+------------------------------------------------------------------------
+r211 | sam | 2008-07-13 12:52:19 +0000 (Sun, 13 Jul 2008) | 1 line
+Changed paths:
+ M /trunk/doc/doxygen.cfg.in
+
+ * Update outdated Doxygen configuration file using doxygen -u.
+------------------------------------------------------------------------
+r210 | massiot | 2008-07-12 12:19:57 +0000 (Sat, 12 Jul 2008) | 5 lines
+Changed paths:
+ M /trunk/src/css.c
+ M /trunk/src/libdvdcss.c
+
+ * src/libdvdcss.c: initialize p_disc_key in the case when DVD is encrypted
+ but no ioctl is available ;
+ * src/css.c: initialize p_disc_key in the case when key decryption fails.
+Patch by Kirill Belokurov.
+
+------------------------------------------------------------------------
+r209 | massiot | 2008-07-11 17:23:25 +0000 (Fri, 11 Jul 2008) | 3 lines
+Changed paths:
+ M /trunk/src/dvdcss/dvdcss.h
+ M /trunk/src/libdvdcss.c
+
+ * src/libdvdcss.c: add dvdcss_is_scrambled() function, patch courtesy of
+ Olivier Rolland.
+
+------------------------------------------------------------------------
+r208 | robux4 | 2008-01-07 16:48:35 +0000 (Mon, 07 Jan 2008) | 1 line
+Changed paths:
+ M /trunk/src/dvdcss/dvdcss.h
+
+nicer comment, patch by Diego Biurrun
+------------------------------------------------------------------------
+r207 | robux4 | 2007-09-17 12:10:20 +0000 (Mon, 17 Sep 2007) | 1 line
+Changed paths:
+ M /trunk/src/bsdi_dvd.h
+ M /trunk/src/dvdcss/dvdcss.h
+ M /trunk/src/ioctl.h
+
+(from Diego Biurrun) Identifiers starting with two underscores or an underscore and capital letters are reserved for the system in C.
+------------------------------------------------------------------------
+r206 | robux4 | 2007-09-17 12:07:41 +0000 (Mon, 17 Sep 2007) | 4 lines
+Changed paths:
+ M /trunk/src/libdvdcss.c
+
+(from Diego Biurrun) This patch removes the following warning when compiling MPlayer:
+
+libdvdcss.c:145: warning: redundant redeclaration of 'dvdcss_interface_2'
+dvdcss/dvdcss.h:70: warning: previous declaration of 'dvdcss_interface_2' was here
+------------------------------------------------------------------------
+r205 | robux4 | 2007-07-29 10:14:53 +0000 (Sun, 29 Jul 2007) | 7 lines
+Changed paths:
+ M /trunk/src/libdvdcss.c
+
+Pathc from iive (via Diego Biurrun)
+Date: Sat Jul 7 01:22:51 2007
+
+Fix crash on some DVDs
+sprintf(tmp,"%.02x",(char)0xef); would print "ffffffef" instead of "ef",
+in this case this leads to local array buffer overflow and hard to trace stack corruption.
+The quick, easy & dirty solution is to use (unsigned char) or (uint8_t)
+------------------------------------------------------------------------
+r204 | xtophe | 2007-07-15 22:23:39 +0000 (Sun, 15 Jul 2007) | 2 lines
+Changed paths:
+ M /trunk/bootstrap
+
+support automake 1.10
+
+------------------------------------------------------------------------
+r203 | robux4 | 2006-11-07 16:27:40 +0000 (Tue, 07 Nov 2006) | 2 lines
+Changed paths:
+ M /trunk/src/common.h
+ M /trunk/src/device.c
+
+fix cygwin compilation regarding the lseek change
+(patch by Diego Biurrun)
+------------------------------------------------------------------------
+r202 | robux4 | 2006-11-01 14:31:51 +0000 (Wed, 01 Nov 2006) | 2 lines
+Changed paths:
+ M /trunk/src/common.h
+
+fix compilation on MINGW (patch by Diego Biurrun)
+(lseek vs lseek64 typo)
+------------------------------------------------------------------------
+r201 | sam | 2006-09-19 23:03:53 +0000 (Tue, 19 Sep 2006) | 2 lines
+Changed paths:
+ M /trunk/src/libdvdcss.c
+
+ * Fixed spelling in documentation. Also testing buildbot.
+
+------------------------------------------------------------------------
+r200 | sam | 2006-09-19 22:28:06 +0000 (Tue, 19 Sep 2006) | 2 lines
+Changed paths:
+ M /trunk/src/css.c
+ M /trunk/src/libdvdcss.c
+
+ * Fix warnings due to signed / unsigned pointer targets.
+
+------------------------------------------------------------------------
+r199 | sam | 2006-09-19 22:27:46 +0000 (Tue, 19 Sep 2006) | 2 lines
+Changed paths:
+ M /trunk/bootstrap
+
+ * Update bootstrap script.
+
+------------------------------------------------------------------------
+r198 | robux4 | 2006-09-13 13:12:23 +0000 (Wed, 13 Sep 2006) | 4 lines
+Changed paths:
+ M /trunk/src/libdvdcss.c
+
+fallback to USERPROFILE environment variable for caching CSS keys when
+HOME is not set (for MinGW builds running outside of MinGW).
+patch from MPlayer via Diego Biurrun (diego at biurrun dot de)
+
+------------------------------------------------------------------------
+r197 | robux4 | 2006-09-13 13:11:25 +0000 (Wed, 13 Sep 2006) | 2 lines
+Changed paths:
+ M /trunk/src/device.c
+
+now accepts X:\ as a device name, as well as X:
+patch from MPlayer via Diego Biurrun (diego at biurrun dot de)
+------------------------------------------------------------------------
+r196 | sam | 2006-03-30 14:31:12 +0000 (Thu, 30 Mar 2006) | 2 lines
+Changed paths:
+ M /trunk/configure.ac
+
+ * Oops, forgot to commit configure.ac when removing the debian/ directory.
+
+------------------------------------------------------------------------
+r195 | sam | 2006-03-30 14:30:43 +0000 (Thu, 30 Mar 2006) | 3 lines
+Changed paths:
+ M /trunk/Makefile.am
+ D /trunk/debian
+
+ * Removed the debian/ directory. Debian packaging is now handled
+ separately, in the pkg-multimedia repository.
+
+------------------------------------------------------------------------
+r194 | sam | 2006-01-26 20:48:06 +0000 (Thu, 26 Jan 2006) | 3 lines
+Changed paths:
+ M /trunk/src/device.c
+
+ * src/device.c: reduced code duplication and fixed a pointer/integer
+ confusion in the OS X drive detection.
+
+------------------------------------------------------------------------
+r193 | sam | 2005-11-09 22:12:32 +0000 (Wed, 09 Nov 2005) | 3 lines
+Changed paths:
+ M /trunk/src/common.h
+
+ * src/common.h: do not override lseek on Cygwin, only on mingw32. Cygwin
+ provides its own 64-bit offset lseek. Patch courtesy of the MPlayer team.
+
+------------------------------------------------------------------------
+r192 | sam | 2005-10-26 16:58:08 +0000 (Wed, 26 Oct 2005) | 2 lines
+Changed paths:
+ M /trunk/debian/control
+
+ * debian/control: build-depend on tetex-extra (needed by doxygen).
+
+------------------------------------------------------------------------
+r191 | robux4 | 2005-09-04 08:49:23 +0000 (Sun, 04 Sep 2005) | 1 line
+Changed paths:
+ M /trunk/src/dvdcss/dvdcss.h
+
+* libdvdcss: more fixes for DLL building
+------------------------------------------------------------------------
+r190 | robux4 | 2005-09-04 08:31:58 +0000 (Sun, 04 Sep 2005) | 1 line
+Changed paths:
+ M /trunk/msvc/config.h
+
+* libdvdcss: the current version is 1.2.9
+------------------------------------------------------------------------
+r189 | robux4 | 2005-09-04 08:31:26 +0000 (Sun, 04 Sep 2005) | 1 line
+Changed paths:
+ M /trunk/src/device.c
+
+* libdvdcss: MSVC7 compilation fixes (shouldn't break mingw32)
+------------------------------------------------------------------------
+r188 | robux4 | 2005-09-04 08:25:26 +0000 (Sun, 04 Sep 2005) | 1 line
+Changed paths:
+ M /trunk/src/common.h
+ M /trunk/src/ioctl.h
+ M /trunk/src/libdvdcss.h
+
+* libdvdcss: MSVC7 compilation fixes (shouldn't break mingw32)
+------------------------------------------------------------------------
+r187 | robux4 | 2005-09-04 07:54:41 +0000 (Sun, 04 Sep 2005) | 1 line
+Changed paths:
+ M /trunk/src/dvdcss/dvdcss.h
+ M /trunk/src/libdvdcss.c
+
+* libdvdcss: oops mismatch #ifdef
+------------------------------------------------------------------------
+r186 | robux4 | 2005-09-04 07:43:15 +0000 (Sun, 04 Sep 2005) | 1 line
+Changed paths:
+ M /trunk/AUTHORS
+ M /trunk/COPYING
+ M /trunk/ChangeLog
+ M /trunk/INSTALL
+ M /trunk/Makefile.am
+ M /trunk/NEWS
+ M /trunk/README
+ M /trunk/debian/Makefile.am
+ M /trunk/doc/Makefile.am
+ M /trunk/doc/doxygen.cfg.in
+ M /trunk/doc/footer.html
+ M /trunk/doc/header.html
+ M /trunk/msvc/config.h
+ M /trunk/msvc/csstest.dsp
+ M /trunk/msvc/libdvdcss.dsp
+ M /trunk/msvc/workspace.dsw
+ M /trunk/src/Makefile.am
+ M /trunk/src/bsdi_dvd.h
+ M /trunk/src/bsdi_ioctl.c
+ M /trunk/src/common.h
+ M /trunk/src/css.c
+ M /trunk/src/css.h
+ M /trunk/src/csstables.h
+ M /trunk/src/device.c
+ M /trunk/src/device.h
+ M /trunk/src/dvdcss/Makefile.am
+ M /trunk/src/dvdcss/dvdcss.h
+ M /trunk/src/error.c
+ M /trunk/src/ioctl.c
+ M /trunk/src/ioctl.h
+ M /trunk/src/libdvdcss.c
+ M /trunk/src/libdvdcss.h
+ M /trunk/test/Makefile.am
+ M /trunk/test/csstest.c
+ M /trunk/test/dvd_region.c
+
+* libdvdcss: set EOL style in SVN
+------------------------------------------------------------------------
+r185 | robux4 | 2005-09-04 07:39:37 +0000 (Sun, 04 Sep 2005) | 1 line
+Changed paths:
+ M /trunk/src/dvdcss/dvdcss.h
+
+* libdvdcss: better DLL/library difference
+------------------------------------------------------------------------
+r184 | robux4 | 2005-09-04 07:36:01 +0000 (Sun, 04 Sep 2005) | 1 line
+Changed paths:
+ M /trunk/src/dvdcss/dvdcss.h
+
+* libdvdcss: allow building DLL exports
+------------------------------------------------------------------------
+r183 | sam | 2005-09-03 13:17:55 +0000 (Sat, 03 Sep 2005) | 4 lines
+Changed paths:
+ M /trunk/configure.ac
+ M /trunk/doc
+ M /trunk/test
+
+ * configure.ac: patch from Diego Pettenò to let the user disable the
+ documentation build.
+ * test doc: added missing svn:ignore entries.
+
+------------------------------------------------------------------------
+r182 | massiot | 2005-09-01 17:12:42 +0000 (Thu, 01 Sep 2005) | 2 lines
+Changed paths:
+ M /trunk/bootstrap
+
+ * Revert [181] since it breaks on some OS X versions.
+
+------------------------------------------------------------------------
+r181 | massiot | 2005-09-01 12:40:25 +0000 (Thu, 01 Sep 2005) | 3 lines
+Changed paths:
+ M /trunk/bootstrap
+
+ * bootstrap: Use libtoolize instead of glibtoolize when it is available
+ because libtool under OS X sucks.
+
+------------------------------------------------------------------------
+r180 | massiot | 2005-08-31 19:07:00 +0000 (Wed, 31 Aug 2005) | 2 lines
+Changed paths:
+ M /trunk/src/device.c
+
+ * src/device.c: Under Windows remove the trailing backslash.
+
+------------------------------------------------------------------------
+r179 | sam | 2005-08-30 10:20:18 +0000 (Tue, 30 Aug 2005) | 2 lines
+Changed paths:
+ M /trunk/configure.ac
+ M /trunk/src/Makefile.am
+
+ * configure.ac: forward -framework options to the linker.
+
+------------------------------------------------------------------------
+r178 | massiot | 2005-08-30 09:48:19 +0000 (Tue, 30 Aug 2005) | 2 lines
+Changed paths:
+ M /trunk/src/device.c
+
+ * src/device.c: Fixed compilation under Darwin.
+
+------------------------------------------------------------------------
+r177 | sam | 2005-08-29 22:25:20 +0000 (Mon, 29 Aug 2005) | 2 lines
+Changed paths:
+ M /trunk/src/device.c
+
+ * src/device.c: tried to port the device autodetection to OS X.
+
+------------------------------------------------------------------------
+r176 | sam | 2005-08-29 22:02:55 +0000 (Mon, 29 Aug 2005) | 3 lines
+Changed paths:
+ M /trunk/src/device.c
+ M /trunk/src/device.h
+ M /trunk/src/libdvdcss.c
+
+ * src/device.c: if the target is the empty string, attempt to autodetect
+ the DVD drive instead of giving up.
+
+------------------------------------------------------------------------
+r175 | sam | 2005-08-23 16:15:38 +0000 (Tue, 23 Aug 2005) | 3 lines
+Changed paths:
+ M /trunk/doc/Makefile.am
+ D /trunk/doc/doxygen.cfg
+ A /trunk/doc/doxygen.cfg.in (from /trunk/doc/doxygen.cfg:174)
+
+ * doc/Makefile.am: fixed build in a separate directory. Patch courtesy
+ of Bernard Leak with a few additions.
+
+------------------------------------------------------------------------
+r173 | sam | 2005-07-11 12:32:57 +0000 (Mon, 11 Jul 2005) | 2 lines
+Changed paths:
+ M /trunk/ChangeLog
+
+ * Updated ChangeLog.
+
+------------------------------------------------------------------------
+r172 | sam | 2005-07-11 12:31:58 +0000 (Mon, 11 Jul 2005) | 2 lines
+Changed paths:
+ M /trunk/src/Makefile.am
+
+ * src/Makefile.am: bumped libtool version information.
+
+------------------------------------------------------------------------
+r171 | sam | 2005-07-11 12:25:18 +0000 (Mon, 11 Jul 2005) | 2 lines
+Changed paths:
+ M /trunk/debian/changelog
+ M /trunk/debian/control
+
+ * debian/*: updated Debian packaging information.
+
+------------------------------------------------------------------------
+r170 | sam | 2005-07-11 12:23:07 +0000 (Mon, 11 Jul 2005) | 2 lines
+Changed paths:
+ M /trunk/src/css.c
+
+ * src/css.c: grmbl, compile fix.
+
+------------------------------------------------------------------------
+r169 | massiot | 2005-07-11 12:15:10 +0000 (Mon, 11 Jul 2005) | 2 lines
+Changed paths:
+ M /trunk/NEWS
+ M /trunk/configure.ac
+ M /trunk/debian/changelog
+ M /trunk/libdvdcss.spec
+
+ * Bumped up version number to 1.2.9.
+
+------------------------------------------------------------------------
+r168 | sam | 2005-07-11 12:10:43 +0000 (Mon, 11 Jul 2005) | 2 lines
+Changed paths:
+ M /trunk/src/css.c
+
+ * src/css.c: reworked my verbosity patch to fix a compilation issue.
+
+------------------------------------------------------------------------
+r167 | sam | 2005-07-11 11:58:58 +0000 (Mon, 11 Jul 2005) | 3 lines
+Changed paths:
+ M /trunk/src/ioctl.c
+
+ * src/ioctl.c: under Solaris, use libsmedia for ioctls when available. Code
+ reworked from a patch courtesy of the MPlayer team.
+
+------------------------------------------------------------------------
+r166 | sam | 2005-07-11 11:41:15 +0000 (Mon, 11 Jul 2005) | 3 lines
+Changed paths:
+ M /trunk/src/bsdi_ioctl.c
+
+ * src/bsdi_ioctl.c: use memset instead of bzero. Patch courtesy of the
+ MPlayer team.
+
+------------------------------------------------------------------------
+r165 | sam | 2005-07-11 11:32:33 +0000 (Mon, 11 Jul 2005) | 3 lines
+Changed paths:
+ M /trunk/src/device.c
+ M /trunk/src/ioctl.h
+
+ * src/device.c src/ioctl.h: cosmetic fix that uses real Win32 types for
+ dynamically loaded functions and gets rid of lvalue casts.
+
+------------------------------------------------------------------------
+r164 | sam | 2005-07-11 11:25:47 +0000 (Mon, 11 Jul 2005) | 2 lines
+Changed paths:
+ M /trunk/src/css.c
+
+ * src/css.c: be slightly more verbose in which keys we manipulate.
+
+------------------------------------------------------------------------
+r163 | sam | 2005-07-11 11:22:33 +0000 (Mon, 11 Jul 2005) | 2 lines
+Changed paths:
+ M /trunk/bootstrap
+
+ * bootstrap: allow to bootstrap with aclocal/automake version 1.9.
+
+------------------------------------------------------------------------
+r162 | gbazin | 2004-09-02 12:17:13 +0000 (Thu, 02 Sep 2004) | 1 line
+Changed paths:
+ M /trunk/src/common.h
+
+* src/common.h: use lseeki64 for file seeking on win32 (works above the 2.1G boundary).
+------------------------------------------------------------------------
+r161 | sam | 2004-08-13 13:53:27 +0000 (Fri, 13 Aug 2004) | 4 lines
+Changed paths:
+ M /trunk/src/css.c
+
+ * src/css.c:
+ + Save the cached key as ASCII in hexadecimal form.
+ + Overwrite cached files if the data was invalid.
+
+------------------------------------------------------------------------
+r160 | sam | 2004-08-13 13:40:44 +0000 (Fri, 13 Aug 2004) | 4 lines
+Changed paths:
+ M /trunk/src/libdvdcss.c
+
+ * src/libdvdcss.c:
+ + Recreate the cache dir information on each launch, in case the
+ information it contains ever changes.
+
+------------------------------------------------------------------------
+r159 | sam | 2004-08-11 23:26:35 +0000 (Wed, 11 Aug 2004) | 2 lines
+Changed paths:
+ M /trunk
+ M /trunk/Makefile.am
+ D /trunk/autotools
+ M /trunk/bootstrap
+ M /trunk/configure.ac
+
+ * Don't put autotools/ under revision control.
+
+------------------------------------------------------------------------
+r158 | sam | 2004-08-11 23:24:54 +0000 (Wed, 11 Aug 2004) | 2 lines
+Changed paths:
+ D /trunk/autotools/Makefile.am
+
+ * Don't put autotools/ under revision control.
+
+------------------------------------------------------------------------
+r157 | sam | 2004-08-11 23:04:39 +0000 (Wed, 11 Aug 2004) | 2 lines
+Changed paths:
+ M /trunk/libdvdcss.spec
+
+ * libdvdcss.spec: updated Red Hat rules for RH9.
+
+------------------------------------------------------------------------
+r156 | sam | 2004-08-11 22:59:42 +0000 (Wed, 11 Aug 2004) | 4 lines
+Changed paths:
+ M /trunk/src/libdvdcss.c
+
+ * src/libdvdcss.c:
+ + Support for cache directory tags, as proposed on
+ http://www.brynosaurus.com/cachedir/spec.html .
+
+------------------------------------------------------------------------
+r155 | sam | 2004-08-11 22:15:30 +0000 (Wed, 11 Aug 2004) | 6 lines
+Changed paths:
+ M /trunk/AUTHORS
+ M /trunk/src/libdvdcss.c
+
+ * src/libdvdcss.c:
+ + Append the disc key to the cache directory name to avoid issues with
+ identical discs which have different encryption keys, thanks to Sven
+ Heithecker.
+ + Use - instead of # as a separator in the cache filename.
+
+------------------------------------------------------------------------
+r154 | sam | 2004-07-05 09:17:20 +0000 (Mon, 05 Jul 2004) | 2 lines
+Changed paths:
+ M /trunk/bootstrap
+
+ * bootstrap: fixed a syntax error.
+
+------------------------------------------------------------------------
+r153 | sam | 2004-07-05 09:15:35 +0000 (Mon, 05 Jul 2004) | 4 lines
+Changed paths:
+ M /trunk/bootstrap
+
+ * bootstrap:
+ + Run libtoolize before aclocal.
+ + Support automake 1.8.
+
+------------------------------------------------------------------------
+r152 | sam | 2004-02-24 15:47:00 +0000 (Tue, 24 Feb 2004) | 2 lines
+Changed paths:
+ M /trunk
+ D /trunk/.cvsignore
+ M /trunk/NEWS
+ M /trunk/README
+ M /trunk/autotools
+ D /trunk/autotools/.cvsignore
+ M /trunk/bootstrap
+ M /trunk/debian
+ D /trunk/debian/.cvsignore
+ M /trunk/doc
+ D /trunk/doc/.cvsignore
+ M /trunk/doc/footer.html
+ M /trunk/doc/header.html
+ M /trunk/msvc
+ D /trunk/msvc/.cvsignore
+ M /trunk/src
+ D /trunk/src/.cvsignore
+ M /trunk/src/bsdi_dvd.h
+ M /trunk/src/common.h
+ M /trunk/src/css.c
+ M /trunk/src/css.h
+ M /trunk/src/csstables.h
+ M /trunk/src/device.c
+ M /trunk/src/device.h
+ M /trunk/src/dvdcss
+ D /trunk/src/dvdcss/.cvsignore
+ M /trunk/src/dvdcss/dvdcss.h
+ M /trunk/src/error.c
+ M /trunk/src/ioctl.c
+ M /trunk/src/ioctl.h
+ M /trunk/src/libdvdcss.c
+ M /trunk/src/libdvdcss.h
+ M /trunk/test
+ D /trunk/test/.cvsignore
+
+ * Added proper SVN keywords to files and directories (for $Id and ignores).
+
+------------------------------------------------------------------------
+r141 | sam | 2003-12-11 15:13:40 +0000 (Thu, 11 Dec 2003) | 3 lines
+Changed paths:
+ M /trunk/doc/.cvsignore
+ M /trunk/doc/doxygen.cfg
+
+ * doc/doxygen.cfg: Updated doxygen configuration.
+ * doc/.cvsignore: Ignore stamp files.
+
+------------------------------------------------------------------------
+r140 | sam | 2003-12-11 15:12:42 +0000 (Thu, 11 Dec 2003) | 5 lines
+Changed paths:
+ M /trunk/src/device.c
+
+ * src/device.c:
+ + Store the off_t values for seek and read in a temporary variable to
+ work around a strange gentoo gcc behaviour as seen here:
+ http://www.via.ecp.fr/via/ml/libdvdcss-devel/200312/msg00000.html
+
+------------------------------------------------------------------------
+r139 | sam | 2003-11-26 20:16:38 +0000 (Wed, 26 Nov 2003) | 2 lines
+Changed paths:
+ M /trunk/libdvdcss.spec
+
+ * libdvdcss.spec: Fixed a syntax error (#1488).
+
+------------------------------------------------------------------------
+r138 | sam | 2003-11-06 10:12:38 +0000 (Thu, 06 Nov 2003) | 2 lines
+Changed paths:
+ M /trunk/bootstrap
+
+ * bootstrap: remove autom4te.cache before running autoconf
+
+------------------------------------------------------------------------
+r137 | sam | 2003-09-15 17:12:46 +0000 (Mon, 15 Sep 2003) | 2 lines
+Changed paths:
+ M /trunk/src/css.c
+ M /trunk/src/libdvdcss.c
+
+ * libdvdcss.c: Added more debug messages.
+
+------------------------------------------------------------------------
+r136 | sam | 2003-09-09 13:17:24 +0000 (Tue, 09 Sep 2003) | 2 lines
+Changed paths:
+ M /trunk/configure.ac
+ M /trunk/src/css.c
+ M /trunk/src/device.c
+
+ * src/css.c, src/device.c: more meaningful error messages.
+
+------------------------------------------------------------------------
+r135 | sam | 2003-09-09 12:32:40 +0000 (Tue, 09 Sep 2003) | 4 lines
+Changed paths:
+ M /trunk/.cvsignore
+ M /trunk/Makefile.am
+ M /trunk/NEWS
+ M /trunk/README
+ M /trunk/configure.ac
+ M /trunk/debian/Makefile.am
+ M /trunk/debian/changelog
+ A /trunk/debian/compat
+ M /trunk/debian/control
+ M /trunk/debian/rules
+ M /trunk/doc/Makefile.am
+ M /trunk/doc/footer.html
+ M /trunk/doc/header.html
+ M /trunk/test/csstest.c
+
+ * configure.ac: check for doxygen and latex to build documentation.
+ * doc/Makefile.am: conditionally build documentation.
+ * debian/*: use debian/compat instead of DH_COMPAT.
+
+------------------------------------------------------------------------
+r134 | sam | 2003-09-09 12:05:44 +0000 (Tue, 09 Sep 2003) | 2 lines
+Changed paths:
+ M /trunk/bootstrap
+
+ * bootstrap: code clean-up.
+
+------------------------------------------------------------------------
+r133 | sam | 2003-09-09 10:03:48 +0000 (Tue, 09 Sep 2003) | 3 lines
+Changed paths:
+ M /trunk/src/css.c
+ M /trunk/src/device.c
+ M /trunk/src/error.c
+ M /trunk/src/libdvdcss.c
+ M /trunk/src/libdvdcss.h
+
+ * Changed _dvdcss_error and _dvdcss_debug to print_error and print_debug
+ because they aren't libdvdcss functions.
+
+------------------------------------------------------------------------
+r132 | gbazin | 2003-07-29 19:49:13 +0000 (Tue, 29 Jul 2003) | 3 lines
+Changed paths:
+ M /trunk/NEWS
+
+
+* NEWS: forgot to update this one for the release.
+
+------------------------------------------------------------------------
+r131 | gbazin | 2003-07-29 19:03:02 +0000 (Tue, 29 Jul 2003) | 3 lines
+Changed paths:
+ M /trunk/libdvdcss.spec
+
+
+* libdvdcss.spec: fixed typo.
+
+------------------------------------------------------------------------
+r130 | gbazin | 2003-07-28 23:41:52 +0000 (Mon, 28 Jul 2003) | 3 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/configure.ac
+ M /trunk/debian/changelog
+ M /trunk/libdvdcss.spec
+
+
+* ALL: bumped version number to 1.2.8
+
+------------------------------------------------------------------------
+r129 | sam | 2003-07-16 21:40:01 +0000 (Wed, 16 Jul 2003) | 7 lines
+Changed paths:
+ M /trunk/src/css.c
+
+ * src/css.c:
+ + Workaround in CrackTitleKey for strange discs that report read errors
+ seemingly at random. Testcase was on Linux 2.4.20, with a region 2 RPC2
+ drive, and the region 1 copy of "Chasing Amy".
+ + Used macros instead of numerals where appropriate.
+ + Fixed spelling here and there.
+
+------------------------------------------------------------------------
+r128 | gbazin | 2003-07-08 18:00:54 +0000 (Tue, 08 Jul 2003) | 3 lines
+Changed paths:
+ M /trunk/src/device.c
+
+
+* src/device.c: grmblgrmbl!! Fixed a bug that prevented encrypted dvds from working under win32.
+
+------------------------------------------------------------------------
+r127 | massiot | 2003-06-22 20:59:45 +0000 (Sun, 22 Jun 2003) | 2 lines
+Changed paths:
+ M /trunk/src/Makefile.am
+
+* Updated library version.
+
+------------------------------------------------------------------------
+r126 | sam | 2003-06-18 17:23:55 +0000 (Wed, 18 Jun 2003) | 2 lines
+Changed paths:
+ M /trunk/src/libdvdcss.c
+
+ * ./src/libdvdcss.c: if DVDCSS_VERBOSE is greater than 2, do as if it was 2.
+
+------------------------------------------------------------------------
+r125 | sam | 2003-06-13 00:41:35 +0000 (Fri, 13 Jun 2003) | 12 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/NEWS
+ M /trunk/configure.ac
+ M /trunk/debian/changelog
+ M /trunk/debian/control
+ M /trunk/debian/rules
+ M /trunk/libdvdcss.spec
+
+ * Everything is ready for a 1.2.7 release.
+
+ * debian/control:
+ + Set policy to 3.5.10.
+ + Removed the leading "a" in the package description.
+ + Set the source section to libs.
+ + Set the -dev package section to libdevel.
+ + Changed the debhelper build dependency to (>=3.0).
+ * debian/rules:
+ + Added magic to avoid autotools timestamp skews on autobuilders (as if
+ libdvdcss was ever going to hit the Debian autobuilders anyway).
+
+------------------------------------------------------------------------
+r124 | sam | 2003-06-12 23:22:34 +0000 (Thu, 12 Jun 2003) | 6 lines
+Changed paths:
+ M /trunk/src/libdvdcss.c
+
+ * ./src/libdvdcss.c: if DVDCSS_CACHE is not set, we force a default value.
+ - under Win32: C:\Documents and Settings\$USER\Application Data\dvdcss\
+ - under Unix and everything else: ${HOME}/.dvdcss/
+ - the special value DVDCSS_CACHE=off disables caching.
+ * ./src/libdvdcss.c: updated doxygen documentation accordingly.
+
+------------------------------------------------------------------------
+r123 | sam | 2003-06-12 23:15:18 +0000 (Thu, 12 Jun 2003) | 3 lines
+Changed paths:
+ M /trunk/Makefile.am
+ M /trunk/configure.ac
+
+ * ./Makefile.am: put autotools/ in DIST_SUBDIRS instead of SUBDIRS.
+ * ./configure.ac: forgot to generate autotools/Makefile.
+
+------------------------------------------------------------------------
+r122 | sam | 2003-06-10 22:50:31 +0000 (Tue, 10 Jun 2003) | 4 lines
+Changed paths:
+ M /trunk/Makefile.am
+ A /trunk/autotools
+ A /trunk/autotools/.cvsignore
+ A /trunk/autotools/Makefile.am
+ M /trunk/bootstrap
+ M /trunk/configure.ac
+
+ * ./configure.ac: make use of the autotools/ directory.
+ * ./bootstrap: libfool is a tool. Worked around its blatant ignorance of
+ the AC_CONFIG_AUX_DIR directive.
+
+------------------------------------------------------------------------
+r121 | sam | 2003-05-27 17:12:33 +0000 (Tue, 27 May 2003) | 4 lines
+Changed paths:
+ M /trunk/debian/changelog
+ M /trunk/debian/control
+
+ * ./debian/control: removed libc6-dev from libdvdcss2-dev's dependencies
+ because it is part of build-essential and it isn't even called libc6-dev
+ on all architectures.
+
+------------------------------------------------------------------------
+r120 | sam | 2003-05-16 22:12:48 +0000 (Fri, 16 May 2003) | 2 lines
+Changed paths:
+ M /trunk/src/css.c
+
+ * ./src/css.c: typos in comments.
+
+------------------------------------------------------------------------
+r119 | gbazin | 2003-04-11 10:00:29 +0000 (Fri, 11 Apr 2003) | 3 lines
+Changed paths:
+ M /trunk/configure.ac
+ M /trunk/src/common.h
+
+
+* configure.ac, src/common.h: fixes for the cygwin build using the mno-cygwin flag.
+
+------------------------------------------------------------------------
+r118 | yves | 2003-04-06 20:36:07 +0000 (Sun, 06 Apr 2003) | 2 lines
+Changed paths:
+ M /trunk/libdvdcss.spec
+
+better RH part thx Kipp Cannon <kipp@sgl.crestech.ca>
+
+------------------------------------------------------------------------
+r117 | gbazin | 2003-03-27 18:57:12 +0000 (Thu, 27 Mar 2003) | 3 lines
+Changed paths:
+ M /trunk/src/libdvdcss.c
+
+
+* src/libdvdcss.c: CSS key cache collisions patch, courtesy of Michael Roitzsch.
+
+------------------------------------------------------------------------
+r116 | gbazin | 2003-03-22 16:37:37 +0000 (Sat, 22 Mar 2003) | 3 lines
+Changed paths:
+ M /trunk/src/libdvdcss.c
+
+
+* src/libdvdcss.c: fix for NetBSD's mkdir that doesn't like trailing "/" on its argument. (courtesy of Christopher Richards)
+
+------------------------------------------------------------------------
+r115 | sam | 2003-03-10 18:01:40 +0000 (Mon, 10 Mar 2003) | 3 lines
+Changed paths:
+ M /trunk/debian/changelog
+ M /trunk/src/Makefile.am
+
+ * ./debian/changelog: updated Debian changelog.
+ * ./src/Makefile.am: bumped version information.
+
+------------------------------------------------------------------------
+r114 | alexis | 2003-03-10 17:41:31 +0000 (Mon, 10 Mar 2003) | 2 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/libdvdcss.spec
+
+- preparing the 1.2.6 release...
+
+------------------------------------------------------------------------
+r113 | massiot | 2003-03-09 23:50:42 +0000 (Sun, 09 Mar 2003) | 2 lines
+Changed paths:
+ M /trunk/NEWS
+ M /trunk/configure.ac
+
+Bumped up to 1.2.6.
+
+------------------------------------------------------------------------
+r112 | gbazin | 2003-03-09 23:34:18 +0000 (Sun, 09 Mar 2003) | 3 lines
+Changed paths:
+ M /trunk/src/common.h
+ M /trunk/src/error.c
+
+
+* src/common.h, src/error.c: fixed the PATH_MAX breakage on win32.
+
+------------------------------------------------------------------------
+r111 | massiot | 2003-02-04 11:54:36 +0000 (Tue, 04 Feb 2003) | 2 lines
+Changed paths:
+ M /trunk/src/css.c
+ M /trunk/src/device.c
+ M /trunk/src/error.c
+
+Fixed compilation problems with PATH_MAX.
+
+------------------------------------------------------------------------
+r110 | massiot | 2003-01-29 22:59:35 +0000 (Wed, 29 Jan 2003) | 2 lines
+Changed paths:
+ M /trunk/configure.ac
+ M /trunk/src/libdvdcss.c
+
+Fixed MAX_PATH on Darwin.
+
+------------------------------------------------------------------------
+r109 | yves | 2003-01-28 07:58:22 +0000 (Tue, 28 Jan 2003) | 3 lines
+Changed paths:
+ M /trunk/libdvdcss.spec
+
+- release number is 1. do not forget to update it too, aka sam sux.
+- fix a redhat "macro".
+
+------------------------------------------------------------------------
+r108 | sam | 2003-01-28 01:17:02 +0000 (Tue, 28 Jan 2003) | 6 lines
+Changed paths:
+ M /trunk/ChangeLog
+ A /trunk/NEWS
+ M /trunk/configure.ac
+ M /trunk/debian/changelog
+ M /trunk/debian/rules
+ M /trunk/doc/doxygen.cfg
+ M /trunk/libdvdcss.spec
+ M /trunk/src/Makefile.am
+ M /trunk/test/Makefile.am
+
+ * updated ChangeLog.
+ * updated version numbers and timestamps everywhere.
+ * created NEWS file.
+ * ./configure.ac: BSD/OS compilation fix when a local copy of libdvd is
+ found on the system, thanks to Steven M. Schultz.
+
+------------------------------------------------------------------------
+r107 | sam | 2003-01-28 00:41:10 +0000 (Tue, 28 Jan 2003) | 3 lines
+Changed paths:
+ M /trunk/src/libdvdcss.c
+ M /trunk/test/csstest.c
+
+ * ./test/csstest.c: we align our read buffer in case of raw device access.
+ * ./src/libdvdcss.c: updated documentation about raw devices.
+
+------------------------------------------------------------------------
+r106 | sam | 2003-01-27 16:57:19 +0000 (Mon, 27 Jan 2003) | 2 lines
+Changed paths:
+ M /trunk/src/libdvdcss.c
+
+ * ./src/libdvdcss.c: disabled key cache when reading VOBs.
+
+------------------------------------------------------------------------
+r105 | sam | 2003-01-16 22:58:29 +0000 (Thu, 16 Jan 2003) | 2 lines
+Changed paths:
+ M /trunk/src/ioctl.c
+ M /trunk/src/ioctl.h
+
+ * ./src/ioctl.c, ./src/ioctl.h: removed minor gcc-isms.
+
+------------------------------------------------------------------------
+r104 | yves | 2003-01-16 14:45:14 +0000 (Thu, 16 Jan 2003) | 3 lines
+Changed paths:
+ M /trunk/libdvdcss.spec
+
+* macros to fix build on redhat system. put %define redhat80 to 1.
+* few fixes.
+
+------------------------------------------------------------------------
+r103 | sam | 2002-12-19 16:50:50 +0000 (Thu, 19 Dec 2002) | 4 lines
+Changed paths:
+ M /trunk/src/device.c
+
+ * ./src/device.c: seek() calls don't do anything if we're already at the
+ right position.
+ * ./src/device.c: we now handle partial reads.
+
+------------------------------------------------------------------------
+r102 | sam | 2002-12-19 15:44:30 +0000 (Thu, 19 Dec 2002) | 2 lines
+Changed paths:
+ M /trunk/configure.ac
+ M /trunk/src/css.c
+ M /trunk/src/libdvdcss.c
+
+ * ./configure.ac: added warning flags whenever possible.
+
+------------------------------------------------------------------------
+r101 | sam | 2002-12-19 15:36:04 +0000 (Thu, 19 Dec 2002) | 3 lines
+Changed paths:
+ M /trunk/configure.ac
+ M /trunk/src/device.c
+ M /trunk/src/libdvdcss.h
+
+ * ./src/device.c: dvdcss->i_pos now gets updated on each seek and each
+ read. Partial reads are not handled yet, but it's a step.
+
+------------------------------------------------------------------------
+r100 | sam | 2002-12-19 15:29:53 +0000 (Thu, 19 Dec 2002) | 3 lines
+Changed paths:
+ M /trunk/src/bsdi_dvd.h
+ M /trunk/src/bsdi_ioctl.c
+
+ * ./src/bsdi_ioctl.c, ./src/bsdi_dvd.h: updated the bsdi libdvd with
+ Steven M. Schultz's latest changes.
+
+------------------------------------------------------------------------
+r99 | sam | 2002-12-19 12:37:30 +0000 (Thu, 19 Dec 2002) | 2 lines
+Changed paths:
+ M /trunk/configure.ac
+ M /trunk/msvc/config.h
+ M /trunk/src/device.c
+ M /trunk/src/device.h
+ M /trunk/src/libdvdcss.c
+ M /trunk/src/libdvdcss.h
+
+ * Ported the library build to Cygwin.
+
+------------------------------------------------------------------------
+r98 | sam | 2002-12-11 13:12:10 +0000 (Wed, 11 Dec 2002) | 2 lines
+Changed paths:
+ M /trunk/src/bsdi_dvd.h
+ M /trunk/src/bsdi_ioctl.c
+ M /trunk/src/device.c
+ M /trunk/src/dvdcss/dvdcss.h
+ M /trunk/src/libdvdcss.c
+
+ * minor coding style fixes.
+
+------------------------------------------------------------------------
+r97 | sam | 2002-12-10 10:43:25 +0000 (Tue, 10 Dec 2002) | 2 lines
+Changed paths:
+ M /trunk/msvc/csstest.dsp
+ M /trunk/msvc/libdvdcss.dsp
+ M /trunk/msvc/workspace.dsw
+
+ * ./msvc/*: grmbl, for some reason the project files were empty.
+
+------------------------------------------------------------------------
+r96 | sam | 2002-12-10 10:38:12 +0000 (Tue, 10 Dec 2002) | 2 lines
+Changed paths:
+ M /trunk/configure.ac
+ A /trunk/msvc
+ A /trunk/msvc/.cvsignore
+ A /trunk/msvc/config.h
+ A /trunk/msvc/csstest.dsp
+ A /trunk/msvc/libdvdcss.dsp
+ A /trunk/msvc/workspace.dsw
+ M /trunk/src/device.c
+ M /trunk/src/libdvdcss.c
+ M /trunk/test/csstest.c
+
+ * ./msvc/*: MS VC++ project files.
+
+------------------------------------------------------------------------
+r95 | babal | 2002-12-06 00:16:57 +0000 (Fri, 06 Dec 2002) | 3 lines
+Changed paths:
+ M /trunk/src/css.c
+ M /trunk/src/device.c
+ M /trunk/src/error.c
+ M /trunk/src/libdvdcss.c
+
+- Early versions of Mingw32 (at least until 1.2) do not include
+ <limits.h> automatically, so PATH_MAX was undefined.
+
+------------------------------------------------------------------------
+r94 | sam | 2002-12-05 10:24:42 +0000 (Thu, 05 Dec 2002) | 4 lines
+Changed paths:
+ M /trunk/configure.ac
+ M /trunk/src/common.h
+ M /trunk/src/css.c
+ M /trunk/src/css.h
+ M /trunk/src/csstables.h
+ M /trunk/src/device.c
+ M /trunk/src/device.h
+ M /trunk/src/error.c
+ M /trunk/src/ioctl.c
+ M /trunk/src/ioctl.h
+ M /trunk/src/libdvdcss.c
+ M /trunk/src/libdvdcss.h
+
+ * ./src/libdvdcss.c: fixed Win32 mkdir() call.
+ * ALL: removed trailing spaces in files.
+ * ALL: moved everything to C99 integer types.
+
+------------------------------------------------------------------------
+r93 | sam | 2002-12-02 12:58:23 +0000 (Mon, 02 Dec 2002) | 2 lines
+Changed paths:
+ M /trunk/bootstrap
+
+ * ./bootstrap: we also look for glibtoolize (Closes: #37).
+
+------------------------------------------------------------------------
+r92 | jlj | 2002-12-02 07:38:21 +0000 (Mon, 02 Dec 2002) | 2 lines
+Changed paths:
+ M /trunk/src/device.h
+
+ ./src/device.h: Applied FreeBSD compile fix from Steven M. Schultz.
+
+------------------------------------------------------------------------
+r91 | jlj | 2002-11-25 18:44:31 +0000 (Mon, 25 Nov 2002) | 3 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/src/ioctl.c
+ M /trunk/src/ioctl.h
+ M /trunk/test/dvd_region.c
+
+ * ./src/ioctl.[ch]: Implemented ioctl_SendRPC.
+ * ./test/dvd_region.c: enabled set_region.
+
+------------------------------------------------------------------------
+r90 | sam | 2002-11-24 17:34:23 +0000 (Sun, 24 Nov 2002) | 3 lines
+Changed paths:
+ M /trunk/src/css.c
+ M /trunk/src/device.c
+ M /trunk/src/error.c
+ M /trunk/src/libdvdcss.c
+ M /trunk/src/libdvdcss.h
+
+ * ./src/css.c, ./src/libdvdcss.c: applied a patch from the MPlayer folks
+ to cache title keys on disk.
+
+------------------------------------------------------------------------
+r89 | sam | 2002-11-21 12:13:20 +0000 (Thu, 21 Nov 2002) | 3 lines
+Changed paths:
+ M /trunk/debian/control
+
+ * ./debian/control: set the package sections to libs and devel instead of
+ graphics.
+
+------------------------------------------------------------------------
+r88 | alexis | 2002-11-17 23:46:44 +0000 (Sun, 17 Nov 2002) | 6 lines
+Changed paths:
+ M /trunk/libdvdcss.spec
+
+Changes in order to support RedHat and RPM 4.1 (courtesy of Ryurick
+Hristev and Kenton Groombridge).
+
+I have already uploaded new RPM packages on the FTP site (1.2.4-2) and
+updated the download page. Please test and give feedback.
+
+------------------------------------------------------------------------
+r87 | jlj | 2002-11-15 18:39:08 +0000 (Fri, 15 Nov 2002) | 2 lines
+Changed paths:
+ M /trunk/src/ioctl.c
+ M /trunk/src/ioctl.h
+
+ * ./src/ioctl.[ch]: ReportRPC win32 changes. Needs testing.
+
+------------------------------------------------------------------------
+r86 | gbazin | 2002-11-14 15:12:34 +0000 (Thu, 14 Nov 2002) | 3 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/debian/changelog
+ M /trunk/libdvdcss.spec
+
+
+* updated the changelogs for the 1.2.4 release.
+
+------------------------------------------------------------------------
+r85 | sam | 2002-11-14 12:41:47 +0000 (Thu, 14 Nov 2002) | 6 lines
+Changed paths:
+ M /trunk/bootstrap
+ M /trunk/configure.ac
+ M /trunk/libdvdcss.spec
+
+ * ./configure.ac: explicitly set AC_CONFIG_AUX_DIR(.) so that people who
+ do bootstrap without paying attention to error messages don't screw up
+ packages :-)
+ * ./libdvdcss.spec: removed bootstrap from the build phase.
+ * ./bootstrap: we accept automake 1.7.
+
+------------------------------------------------------------------------
+r84 | gbazin | 2002-11-14 12:38:57 +0000 (Thu, 14 Nov 2002) | 9 lines
+Changed paths:
+ M /trunk/src/css.c
+ M /trunk/src/ioctl.c
+
+
+* src/css.c src/ioctl.c, src/libdvdcss.c: changed the work-around to detect
+ if the dvd is encrypted on Win2K in non-administrator mode.
+ Because we cannot use an ioctl to get the copyright status of the DVD,
+ we try to get the disc key and if this succeed, we assume the DVD is
+ encrypted, otherwise we assume it to be unencrypted.
+ I hope this logic is not too much flawed... at least it seems to be working
+ with the few DVDs I've got.
+
+------------------------------------------------------------------------
+r83 | jlj | 2002-11-14 01:32:37 +0000 (Thu, 14 Nov 2002) | 2 lines
+Changed paths:
+ M /trunk/src/ioctl.c
+
+ * ./src/ioctl.c: Broke OpenBSD port with my previous commit. Fixed.
+
+------------------------------------------------------------------------
+r82 | alexis | 2002-11-13 23:43:01 +0000 (Wed, 13 Nov 2002) | 3 lines
+Changed paths:
+ M /trunk/libdvdcss.spec
+
+
+Added ./bootstrap for the build target
+
+------------------------------------------------------------------------
+r81 | gbazin | 2002-11-13 23:08:11 +0000 (Wed, 13 Nov 2002) | 3 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/debian/changelog
+ M /trunk/libdvdcss.spec
+
+
+* update changelogs.
+
+------------------------------------------------------------------------
+r80 | jlj | 2002-11-13 22:45:05 +0000 (Wed, 13 Nov 2002) | 3 lines
+Changed paths:
+ M /trunk/AUTHORS
+ M /trunk/src/ioctl.c
+
+ * ./src/ioctl.c: cosmetic fixes.
+ * ./AUTHORS: updated my entry.
+
+------------------------------------------------------------------------
+r79 | alexis | 2002-11-13 22:24:41 +0000 (Wed, 13 Nov 2002) | 3 lines
+Changed paths:
+ M /trunk/configure.ac
+
+
+Update version number to 1.2.4
+
+------------------------------------------------------------------------
+r78 | alexis | 2002-11-13 22:14:28 +0000 (Wed, 13 Nov 2002) | 2 lines
+Changed paths:
+ M /trunk/libdvdcss.spec
+
+Update for 1.2.4 release.
+
+------------------------------------------------------------------------
+r77 | sam | 2002-11-13 22:11:38 +0000 (Wed, 13 Nov 2002) | 3 lines
+Changed paths:
+ M /trunk/debian/changelog
+
+ Updated Debian changelog (though there are no changes in this version
+ apart from Win32, so what's the point of building new packages :p)
+
+------------------------------------------------------------------------
+r76 | gbazin | 2002-11-13 21:23:08 +0000 (Wed, 13 Nov 2002) | 3 lines
+Changed paths:
+ M /trunk/ChangeLog
+
+
+* ChangeLog: updated changelog.
+
+------------------------------------------------------------------------
+r75 | gbazin | 2002-10-29 18:51:37 +0000 (Tue, 29 Oct 2002) | 4 lines
+Changed paths:
+ M /trunk/src/ioctl.c
+
+
+* src/ioctl.c: fixed typo that prevented unencrypted DVDs to work in
+ non-administrator mode.
+
+------------------------------------------------------------------------
+r74 | gbazin | 2002-10-19 09:53:33 +0000 (Sat, 19 Oct 2002) | 4 lines
+Changed paths:
+ M /trunk/src/device.c
+ M /trunk/src/ioctl.h
+
+
+* src/device.c, src/ioctl.h: on win9x, when using ASPI, make sure the drive
+ we are trying to open is actually a cdrom/dvdrom drive.
+
+------------------------------------------------------------------------
+r73 | sam | 2002-10-18 18:48:59 +0000 (Fri, 18 Oct 2002) | 5 lines
+Changed paths:
+ M /trunk/src/css.c
+ M /trunk/src/device.c
+ M /trunk/src/device.h
+ M /trunk/src/libdvdcss.c
+ M /trunk/src/libdvdcss.h
+
+ * ./src/device.c: split the open, read and seek functions so that we can
+ use function pointers instead of doing the if(WIN2K) test.
+ * ./src/device.c: if the target is not a drive name such as F:, we open
+ it with the standard libc functions, even under Win32.
+
+------------------------------------------------------------------------
+r72 | massiot | 2002-10-12 23:02:49 +0000 (Sat, 12 Oct 2002) | 2 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/debian/changelog
+ M /trunk/libdvdcss.spec
+
+Updated changelog and release tag.
+
+------------------------------------------------------------------------
+r71 | gbazin | 2002-10-12 12:41:24 +0000 (Sat, 12 Oct 2002) | 4 lines
+Changed paths:
+ M /trunk/src/ioctl.c
+ M /trunk/src/ioctl.h
+
+
+* src/ioctl.c, src/ioctl.h: fix in ioctl_ReadCopyright to try to work around
+ the buggy IOCTL_DVD_READ_STRUCTURE on WinNT/2k/XP.
+
+------------------------------------------------------------------------
+r70 | sam | 2002-10-11 10:09:56 +0000 (Fri, 11 Oct 2002) | 2 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/debian/changelog
+ M /trunk/libdvdcss.spec
+
+ * Updated changelog and package files.
+
+------------------------------------------------------------------------
+r69 | sam | 2002-10-11 10:03:48 +0000 (Fri, 11 Oct 2002) | 6 lines
+Changed paths:
+ M /trunk/.cvsignore
+ M /trunk/Makefile.am
+ D /trunk/NEWS
+ M /trunk/bootstrap
+ A /trunk/configure.ac
+ D /trunk/configure.in
+ M /trunk/src/.cvsignore
+ M /trunk/src/Makefile.am
+ D /trunk/src/config.h.in
+
+ * ./configure.ac, ./bootstrap: used libdvbpsi's bootstrap, moved config.h
+ to ., renamed configure.in into configure.ac, removed useless files that
+ are autogenerated.
+ * ./src/Makefile.am: instead of using -no-undefined "only under BeOS" we
+ use it "never with MSVC".
+
+------------------------------------------------------------------------
+r68 | massiot | 2002-10-10 22:29:31 +0000 (Thu, 10 Oct 2002) | 2 lines
+Changed paths:
+ M /trunk/bootstrap
+
+Exit cleanly in case of error.
+
+------------------------------------------------------------------------
+r67 | massiot | 2002-10-10 21:40:41 +0000 (Thu, 10 Oct 2002) | 4 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/configure.in
+ M /trunk/src/config.h.in
+ M /trunk/src/css.c
+
+* Bumped up version number to 1.2.3 (soleil !).
+* Updated Changelog.
+* Merged in hh's patch for broken DVD drives/kernel/whatever.
+
+------------------------------------------------------------------------
+r66 | gbazin | 2002-10-10 12:44:28 +0000 (Thu, 10 Oct 2002) | 7 lines
+Changed paths:
+ M /trunk/AUTHORS
+ M /trunk/src/css.c
+ M /trunk/src/device.c
+ M /trunk/src/ioctl.c
+ M /trunk/src/ioctl.h
+
+
+* src/css.c, src/device.c, src/ioctl.[ch]: We don't need to be in administrator mode
+anymore to authenticate the drive on Windows NT/2k/XP. As a result any user can now
+play a DVD on these OSs :)
+* src/ioctl.c: fixed ioctl_ReadTitleKey which wasn't working on Windows NT/2k/XP.
+Because of this bug, the disc and key methods for key decryption where not working.
+
+------------------------------------------------------------------------
+r65 | sam | 2002-10-07 16:37:15 +0000 (Mon, 07 Oct 2002) | 5 lines
+Changed paths:
+ M /trunk/configure.in
+ M /trunk/src/Makefile.am
+ M /trunk/src/config.h.in
+
+ * ./src/Makefile.am: -no-undefined is now only used under BeOS because it
+ causes the Win32 compilation to fail.
+ * ./configure.in, src/Makefile.am: used AM_CONDITIONAL to conditionally
+ build the BSDi stuff.
+
+------------------------------------------------------------------------
+r64 | sam | 2002-08-10 21:27:42 +0000 (Sat, 10 Aug 2002) | 2 lines
+Changed paths:
+ M /trunk/src/Makefile.am
+
+ * Bumped the revision number... thanks Hï¿œkan :-)
+
+------------------------------------------------------------------------
+r63 | sam | 2002-08-10 21:19:55 +0000 (Sat, 10 Aug 2002) | 2 lines
+Changed paths:
+ M /trunk/src/css.c
+
+ * ./src/css.c: removed useless debug messages on Hï¿œkan's advice.
+
+------------------------------------------------------------------------
+r62 | sam | 2002-08-10 20:21:54 +0000 (Sat, 10 Aug 2002) | 2 lines
+Changed paths:
+ M /trunk/AUTHORS
+ M /trunk/ChangeLog
+ M /trunk/debian/changelog
+ M /trunk/libdvdcss.spec
+ M /trunk/src/libdvdcss.c
+
+ * Updated release-related files.
+
+------------------------------------------------------------------------
+r61 | sam | 2002-08-10 17:42:09 +0000 (Sat, 10 Aug 2002) | 3 lines
+Changed paths:
+ M /trunk/src/device.c
+ M /trunk/src/device.h
+ M /trunk/src/ioctl.c
+ M /trunk/src/ioctl.h
+
+ * ./src/ioctl.c: fixed ReportRPC for Win32.
+ * ./src/device.h: removed unneeded exported symbols.
+
+------------------------------------------------------------------------
+r60 | sam | 2002-08-10 14:27:26 +0000 (Sat, 10 Aug 2002) | 4 lines
+Changed paths:
+ M /trunk/src/css.c
+ M /trunk/src/css.h
+ M /trunk/src/device.c
+ M /trunk/src/device.h
+ M /trunk/src/dvdcss/dvdcss.h
+ M /trunk/src/error.c
+ M /trunk/src/libdvdcss.c
+ M /trunk/src/libdvdcss.h
+ M /trunk/test/csstest.c
+
+ * ./src/dvdcss/dvdcss.h: marked deprecated stuff.
+ * ./test/csstest.c: more documentation.
+ see http://www.videolan.org/libdvdcss/doc/
+
+------------------------------------------------------------------------
+r59 | sam | 2002-08-10 12:56:04 +0000 (Sat, 10 Aug 2002) | 3 lines
+Changed paths:
+ M /trunk/.cvsignore
+ M /trunk/Makefile.am
+ D /trunk/Makefile.in
+ D /trunk/aclocal.m4
+ D /trunk/config.guess
+ D /trunk/config.sub
+ D /trunk/configure
+ M /trunk/configure.in
+ M /trunk/debian/.cvsignore
+ D /trunk/debian/Makefile.in
+ A /trunk/doc
+ A /trunk/doc/.cvsignore
+ A /trunk/doc/Makefile.am
+ A /trunk/doc/doxygen.cfg
+ A /trunk/doc/footer.html
+ A /trunk/doc/header.html
+ D /trunk/install-sh
+ D /trunk/ltmain.sh
+ D /trunk/missing
+ D /trunk/mkinstalldirs
+ M /trunk/src/.cvsignore
+ D /trunk/src/Makefile.in
+ M /trunk/src/dvdcss/.cvsignore
+ D /trunk/src/dvdcss/Makefile.in
+ M /trunk/src/libdvdcss.c
+ M /trunk/test/.cvsignore
+ D /trunk/test/Makefile.in
+
+ * ALL: removed autotools files.
+ * ./doc/*: added doxygen files.
+
+------------------------------------------------------------------------
+r58 | sam | 2002-08-10 12:21:28 +0000 (Sat, 10 Aug 2002) | 2 lines
+Changed paths:
+ M /trunk/src/dvdcss/dvdcss.h
+ M /trunk/src/libdvdcss.c
+
+ * ./src/libdvdcss.c, ./src/dvdcss/dvdcss.h: documented the API.
+
+------------------------------------------------------------------------
+r57 | sam | 2002-08-09 22:03:34 +0000 (Fri, 09 Aug 2002) | 4 lines
+Changed paths:
+ M /trunk/src/css.c
+
+ * ./src/css.c: in case of a region mismatch and when the drive needs to
+ be reset, we read the first sector of the disc instead of closing and
+ reopening it.
+
+------------------------------------------------------------------------
+r56 | sam | 2002-08-09 14:19:46 +0000 (Fri, 09 Aug 2002) | 3 lines
+Changed paths:
+ M /trunk/src/Makefile.am
+ M /trunk/src/Makefile.in
+
+ * ./src/Makefile.am: tell libtool that libdvdcss does not have undefined
+ symbols. Fix for BeOS courtesy of Andrew Bachmann.
+
+------------------------------------------------------------------------
+r55 | sam | 2002-08-09 14:10:43 +0000 (Fri, 09 Aug 2002) | 23 lines
+Changed paths:
+ M /trunk/Makefile.in
+ M /trunk/aclocal.m4
+ M /trunk/configure
+ M /trunk/configure.in
+ M /trunk/debian/Makefile.in
+ M /trunk/src/Makefile.am
+ M /trunk/src/Makefile.in
+ M /trunk/src/bsdi_ioctl.c
+ M /trunk/src/common.h
+ M /trunk/src/config.h.in
+ M /trunk/src/css.c
+ M /trunk/src/css.h
+ A /trunk/src/device.c
+ A /trunk/src/device.h
+ M /trunk/src/dvdcss/Makefile.in
+ A /trunk/src/error.c
+ M /trunk/src/libdvdcss.c
+ M /trunk/src/libdvdcss.h
+ M /trunk/test/Makefile.in
+ M /trunk/test/csstest.c
+
+ * ./src/css.c: when the ReadTitleKey ioctl failed, reopen the device before
+ falling back to the title method.
+
+ Note: on my drive, this fixes the "ioctl_ReadTitleKey failed" error
+ many users have been reporting. Please test!
+
+ Note 2: I could not find any other way to reset the drive after a failed
+ ReadTitleKey ioctl than closing and opening the device again. If
+ I don't do that, read() fails with an Input/output error after a
+ while (but not immediately).
+
+ * ALL: libdvdcss builds with -ansi -pedantic. Yeah I like that :-)
+ * ./src/css.c: renamed a few functions so that they make more sense, added
+ debug messages here and there, fixed typos and speling.
+ * ./src/error.c: moved _dvdcss_error and _dvdcss_debug here.
+ * ./src/device.c: moved device reading functions from libdvdcss.c to here.
+ * ./src/device.c: errors from dvdcss_read are now properly handled; partial
+ reads still aren't though.
+ * ./src/libdvdcss.c: default verbosity is now 0, a library should not be
+ intrusive by default.
+ * ./test/csstest.c: additional error check.
+ * ./configure.in: removed the crap boolean_t detection.
+
+------------------------------------------------------------------------
+r54 | massiot | 2002-07-23 11:43:58 +0000 (Tue, 23 Jul 2002) | 2 lines
+Changed paths:
+ M /trunk/README
+
+Default method is now "key" :p.
+
+------------------------------------------------------------------------
+r53 | sam | 2002-07-16 22:47:40 +0000 (Tue, 16 Jul 2002) | 4 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/Makefile.in
+ M /trunk/aclocal.m4
+ M /trunk/config.guess
+ M /trunk/config.sub
+ M /trunk/configure
+ M /trunk/configure.in
+ M /trunk/debian/Makefile.in
+ M /trunk/debian/changelog
+ M /trunk/libdvdcss.spec
+ M /trunk/ltmain.sh
+ M /trunk/src/Makefile.in
+ M /trunk/src/css.c
+ M /trunk/src/css.h
+ M /trunk/src/dvdcss/Makefile.in
+ M /trunk/src/libdvdcss.c
+ M /trunk/test/Makefile.am
+ M /trunk/test/Makefile.in
+
+ * ./test/Makefile.am: disabled dvd_region.
+ * ./src/css.c: speling fixes.
+ * ALL: re-ran bootstrap with more recent autotools.
+
+------------------------------------------------------------------------
+r52 | hjort | 2002-07-14 11:44:57 +0000 (Sun, 14 Jul 2002) | 3 lines
+Changed paths:
+ A /trunk/test/dvd_region.c
+
+New utility for querying (and eventualy setting) the region of a DVD drive
+using the ioctl wrappers in libdvdcss.
+
+------------------------------------------------------------------------
+r51 | hjort | 2002-07-12 23:28:42 +0000 (Fri, 12 Jul 2002) | 3 lines
+Changed paths:
+ M /trunk/configure.in
+ M /trunk/src/bsdi_ioctl.c
+
+Include config.h before testing defines in the BSDi ioctl code. Add a bug
+fix from the author. Remove the now unused parts from configure.in.
+
+------------------------------------------------------------------------
+r50 | hjort | 2002-07-12 21:06:41 +0000 (Fri, 12 Jul 2002) | 3 lines
+Changed paths:
+ M /trunk/src/Makefile.am
+ M /trunk/src/bsdi_ioctl.c
+ M /trunk/test/Makefile.am
+
+Fix so that the bsdi_*.[hc] files make it into the dist tar-ball.
+Correct the include path for the programs in test/.
+
+------------------------------------------------------------------------
+r49 | hjort | 2002-07-01 13:40:33 +0000 (Mon, 01 Jul 2002) | 3 lines
+Changed paths:
+ M /trunk/src/libdvdcss.c
+
+Typo fix and fix the linked list code to not drop the list when instering
+at the head, from Adam Jones.
+
+------------------------------------------------------------------------
+r48 | hjort | 2002-07-01 10:36:37 +0000 (Mon, 01 Jul 2002) | 2 lines
+Changed paths:
+ M /trunk/src/ioctl.c
+ M /trunk/src/ioctl.h
+
+Patch for OS/2 from Alex Strelnikov.
+
+------------------------------------------------------------------------
+r47 | hjort | 2002-07-01 09:59:09 +0000 (Mon, 01 Jul 2002) | 2 lines
+Changed paths:
+ M /trunk/src/css.c
+
+Typo fix from Adam Jones.
+
+------------------------------------------------------------------------
+r46 | hjort | 2002-07-01 09:02:25 +0000 (Mon, 01 Jul 2002) | 2 lines
+Changed paths:
+ M /trunk/src/ioctl.c
+ M /trunk/src/ioctl.h
+
+Getting ReportRPC for WIN32 a bit closer to working.
+
+------------------------------------------------------------------------
+r45 | sam | 2002-06-04 07:10:07 +0000 (Tue, 04 Jun 2002) | 2 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/src/ioctl.c
+
+ * ./src/ioctl.c: implemented ioctl_ReportKey1 for HP-UX.
+
+------------------------------------------------------------------------
+r44 | sam | 2002-06-04 07:02:57 +0000 (Tue, 04 Jun 2002) | 2 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/src/libdvdcss.c
+
+ * ./src/libdvdcss.c: Win32 compilation fix.
+
+------------------------------------------------------------------------
+r43 | sam | 2002-06-02 16:18:45 +0000 (Sun, 02 Jun 2002) | 2 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/configure
+ M /trunk/configure.in
+ M /trunk/debian/changelog
+ M /trunk/libdvdcss.spec
+
+ * ALL: changed version number to 1.2.1.
+
+------------------------------------------------------------------------
+r42 | sam | 2002-06-02 16:14:48 +0000 (Sun, 02 Jun 2002) | 2 lines
+Changed paths:
+ M /trunk/AUTHORS
+ M /trunk/ChangeLog
+ M /trunk/src/ioctl.c
+ M /trunk/src/ioctl.h
+
+ * ./src/ioctl.c, ./src/ioctl.h: QNX port, courtesy of Pascal Levesque.
+
+------------------------------------------------------------------------
+r41 | sam | 2002-06-02 16:05:34 +0000 (Sun, 02 Jun 2002) | 2 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/src/css.c
+
+ * ./src/css.c: applied Hï¿œkan's fix for the failure on region mismatch.
+
+------------------------------------------------------------------------
+r40 | sam | 2002-06-02 15:54:10 +0000 (Sun, 02 Jun 2002) | 3 lines
+Changed paths:
+ M /trunk/.cvsignore
+ M /trunk/ChangeLog
+ M /trunk/aclocal.m4
+ M /trunk/configure
+ M /trunk/libdvdcss.spec
+ M /trunk/ltmain.sh
+ M /trunk/src/libdvdcss.c
+
+ * ALL: switched to libtool 1.4.2a.
+ * ./src/libdvdcss.c: fixed an uninitialized variable.
+
+------------------------------------------------------------------------
+r39 | sam | 2002-05-26 14:22:23 +0000 (Sun, 26 May 2002) | 2 lines
+Changed paths:
+ M /trunk/src/dvdcss/dvdcss.h
+
+ * ./src/dvdcss/dvdcss.h: C++ compliant public header.
+
+------------------------------------------------------------------------
+r38 | sam | 2002-05-20 17:58:20 +0000 (Mon, 20 May 2002) | 4 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/configure
+ M /trunk/configure.in
+ M /trunk/debian/changelog
+ M /trunk/libdvdcss.spec
+ D /trunk/libtool
+
+ * Everything should be ready for 1.2.0.
+ * Updated ChangeLog.
+ * Removed libtool. It seems to be created automatically anyway.
+
+------------------------------------------------------------------------
+r37 | hjort | 2002-05-16 20:40:54 +0000 (Thu, 16 May 2002) | 4 lines
+Changed paths:
+ M /trunk/src/libdvdcss.c
+
+New function _dvdcss_use_ioctls. Avoid using the ioctl calls when
+they have no chans or working, this in turn avoids a spurious warning
+when they fail.
+
+------------------------------------------------------------------------
+r36 | hjort | 2002-05-16 20:12:04 +0000 (Thu, 16 May 2002) | 2 lines
+Changed paths:
+ M /trunk/src/css.c
+
+Update error message.
+
+------------------------------------------------------------------------
+r35 | hjort | 2002-05-16 12:10:29 +0000 (Thu, 16 May 2002) | 2 lines
+Changed paths:
+ M /trunk/src/libdvdcss.c
+
+Default to 'key', rather than 'title', method.
+
+------------------------------------------------------------------------
+r34 | sam | 2002-05-15 20:27:04 +0000 (Wed, 15 May 2002) | 2 lines
+Changed paths:
+ M /trunk/libdvdcss.spec
+
+ * ./libdvdcss.spec: enhancements by Mandrakesoft.
+
+------------------------------------------------------------------------
+r33 | hjort | 2002-05-13 21:22:22 +0000 (Mon, 13 May 2002) | 3 lines
+Changed paths:
+ M /trunk/src/libdvdcss.c
+
+Correct serious bug in dvdcss_read for titles with all zero key (a unencrypted
+title on a CSS protected disc).
+
+------------------------------------------------------------------------
+r32 | jlj | 2002-05-05 22:21:51 +0000 (Sun, 05 May 2002) | 3 lines
+Changed paths:
+ M /trunk/src/ioctl.c
+ M /trunk/src/ioctl.h
+
+ * ./src/ioctl.[ch]: Darwin changes: Cleaned up the code, fixed
+ ReadTitleKey, and implemented ReportRPC.
+
+------------------------------------------------------------------------
+r31 | gbazin | 2002-04-26 20:47:08 +0000 (Fri, 26 Apr 2002) | 4 lines
+Changed paths:
+ M /trunk/INSTALL
+
+
+
+* updated win32 compilation instructions.
+
+------------------------------------------------------------------------
+r30 | sam | 2002-04-06 01:27:43 +0000 (Sat, 06 Apr 2002) | 3 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/configure
+ M /trunk/configure.in
+ M /trunk/debian/changelog
+ M /trunk/libdvdcss.spec
+
+
+ * libdvdcss-1.1.1 release.
+
+------------------------------------------------------------------------
+r29 | sam | 2002-04-06 01:11:05 +0000 (Sat, 06 Apr 2002) | 3 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/src/ioctl.c
+
+
+ * ./src/ioctl.c: OpenBSD compile fix. Thanks to ex0dus on #videolan.
+
+------------------------------------------------------------------------
+r28 | gbazin | 2002-04-05 00:26:25 +0000 (Fri, 05 Apr 2002) | 5 lines
+Changed paths:
+ M /trunk/INSTALL
+ M /trunk/src/css.c
+
+
+
+* updated INSTALL doc for the win32 build.
+* added small win32 specific error message that was also in the vlc tree.
+
+------------------------------------------------------------------------
+r27 | gbazin | 2002-04-04 23:44:20 +0000 (Thu, 04 Apr 2002) | 10 lines
+Changed paths:
+ M /trunk/src/ioctl.c
+ M /trunk/src/libdvdcss.c
+
+
+
+* added two patches that have been forgot from the vlc tree.
+
+ 1- Under NT/2K/XP try to open the dvd device in read only mode if we don't
+ have right access. With only read access we can't use ioctls but if the
+ disc has already been authenticated, then we can decrypt it with the
+ TITLE method.
+ 2- Small compilation fix for msvc.
+
+------------------------------------------------------------------------
+r26 | sam | 2002-04-04 14:21:25 +0000 (Thu, 04 Apr 2002) | 3 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/src/libdvdcss.h
+
+
+ * ./src/libdvdcss.h: IRIX compile fix by Michael Pruett <michael@68k.org>.
+
+------------------------------------------------------------------------
+r25 | sam | 2002-04-04 01:26:54 +0000 (Thu, 04 Apr 2002) | 4 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/configure
+ M /trunk/configure.in
+ M /trunk/src/config.h.in
+ M /trunk/src/ioctl.c
+
+
+ * ./configure.in: BeOS bug fix. I'm so lame.
+ * ./src/ioctl.c: refuse to build if DVD ioctls weren't found.
+
+------------------------------------------------------------------------
+r24 | sam | 2002-04-03 23:34:30 +0000 (Wed, 03 Apr 2002) | 3 lines
+Changed paths:
+ M /trunk/test/.cvsignore
+
+
+ * Forgot to change test/.cvsignore ...
+
+------------------------------------------------------------------------
+r23 | sam | 2002-04-03 23:33:57 +0000 (Wed, 03 Apr 2002) | 6 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/test/Makefile.am
+ M /trunk/test/Makefile.in
+ A /trunk/test/csstest.c
+ D /trunk/test/test.c
+
+
+ * ./test/csstest.c: renamed test.c to csstest.c.
+
+ I hereby declare libdvdcss 1.1.0 ready to ship; it was successfully tested
+ on Linux, FreeBSD, MacOS X and BeOS, and compiles on Solaris.
+
+------------------------------------------------------------------------
+r22 | jlj | 2002-04-03 23:02:20 +0000 (Wed, 03 Apr 2002) | 3 lines
+Changed paths:
+ M /trunk/src/ioctl.c
+
+
+ * ./src/ioctl.c: Fixed a Darwin typo I recently introduced.
+
+------------------------------------------------------------------------
+r21 | sam | 2002-04-03 22:31:42 +0000 (Wed, 03 Apr 2002) | 3 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/Makefile.in
+ M /trunk/configure
+ M /trunk/debian/Makefile.in
+ M /trunk/src/Makefile.in
+ M /trunk/src/dvdcss/Makefile.in
+ M /trunk/test/Makefile.in
+
+
+ * Run ./bootstrap.
+
+------------------------------------------------------------------------
+r20 | jlj | 2002-04-03 22:17:00 +0000 (Wed, 03 Apr 2002) | 3 lines
+Changed paths:
+ M /trunk/configure.in
+
+
+ * ./configure.in: Darwin compile fix (added -no-cpp-precomp)
+
+------------------------------------------------------------------------
+r19 | sam | 2002-04-03 21:31:52 +0000 (Wed, 03 Apr 2002) | 5 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/configure
+ M /trunk/debian/changelog
+ M /trunk/libdvdcss.spec
+ M /trunk/missing
+
+
+ * ./ChangeLog: everything should be ready for the 1.1.0 release.
+ * ./libdvdcss.spec: updated specfile for RPM generation.
+ * ./missing: commited libtool's latest version of this file.
+
+------------------------------------------------------------------------
+r18 | jlj | 2002-04-03 21:25:13 +0000 (Wed, 03 Apr 2002) | 3 lines
+Changed paths:
+ M /trunk/configure.in
+ M /trunk/src/config.h.in
+ M /trunk/src/ioctl.c
+
+
+ * Fixed a Darwin define problem.
+
+------------------------------------------------------------------------
+r17 | sam | 2002-04-03 15:19:22 +0000 (Wed, 03 Apr 2002) | 5 lines
+Changed paths:
+ M /trunk/ChangeLog
+ M /trunk/Makefile.am
+ M /trunk/config.guess
+ M /trunk/config.sub
+ M /trunk/configure
+ M /trunk/configure.in
+ M /trunk/src/Makefile.am
+ M /trunk/src/Makefile.in
+ M /trunk/src/css.c
+ A /trunk/src/dvdcss
+ A /trunk/src/dvdcss/.cvsignore
+ A /trunk/src/dvdcss/Makefile.am
+ A /trunk/src/dvdcss/Makefile.in
+ A /trunk/src/dvdcss/dvdcss.h
+ D /trunk/src/dvdcss.h
+ M /trunk/src/libdvdcss.c
+ M /trunk/test/Makefile.am
+ M /trunk/test/Makefile.in
+ M /trunk/test/test.c
+
+
+ * ./src/dvdcss/dvdcss.h: moved dvdcss.h in a subdirectory so that we can
+ include <dvdcss/dvdcss.h> without having to make install.
+ * ./test/test.c: removed #ifdef DVDCSS_DIST.
+
+------------------------------------------------------------------------
+r16 | sam | 2002-04-03 06:12:50 +0000 (Wed, 03 Apr 2002) | 9 lines
+Changed paths:
+ M /trunk/AUTHORS
+ M /trunk/ChangeLog
+ M /trunk/Makefile.am
+ M /trunk/Makefile.in
+ M /trunk/configure
+ M /trunk/configure.in
+ M /trunk/debian/.cvsignore
+ A /trunk/debian/Makefile.am
+ A /trunk/debian/Makefile.in
+ M /trunk/debian/changelog
+ M /trunk/debian/rules
+ M /trunk/libtool
+ M /trunk/src/Makefile.am
+ M /trunk/src/Makefile.in
+ M /trunk/src/config.h.in
+ M /trunk/src/css.c
+ M /trunk/src/dvdcss.h
+ M /trunk/src/libdvdcss.c
+ M /trunk/test/Makefile.in
+ M /trunk/test/test.c
+
+
+ * ./ChangeLog: updated changelog.
+ * ./Makefile.am: added the debian dir to the targets.
+ * ./configure.in: switched to a more conventional versioning scheme.
+ * ./src/css.c: removed a useless #ifdef.
+ * ./src/dvdcss.h: added a versioned symbol to the API.
+ * ./src/Makefile.am: use <dvdcss/dvdcss.h> instead of <videolan/dvdcss.h>.
+ * ./test/test.c: test program is now up to date.
+
+------------------------------------------------------------------------
+r15 | hjort | 2002-03-09 17:57:53 +0000 (Sat, 09 Mar 2002) | 7 lines
+Changed paths:
+ M /trunk/src/css.c
+ M /trunk/src/css.h
+ M /trunk/src/libdvdcss.c
+
+Split the code into more functions. The disc and title decryption /
+cracking code is now each in it's own function. Also moved the code that
+looks for a weak block in the VOB to crack the title key from out from
+the loop that reads them. Added another crack method, it's disabled for
+now though. Lowered some limits on the current 'weak' test. Added more
+comments.
+
+------------------------------------------------------------------------
+r14 | hjort | 2002-03-09 17:35:49 +0000 (Sat, 09 Mar 2002) | 3 lines
+Changed paths:
+ M /trunk/configure.in
+
+Add -D_FILE_OFFSET_BITS=64 to the compile line to make off_t / lseek and
+other file access functions used in dvdcss be 64bit.
+
+------------------------------------------------------------------------
+r13 | hjort | 2002-03-09 17:24:28 +0000 (Sat, 09 Mar 2002) | 2 lines
+Changed paths:
+ M /trunk/test/test.c
+
+Tell libdvdcss to get the key for the block before we decrypt it.
+
+------------------------------------------------------------------------
+r12 | hjort | 2002-03-09 17:23:05 +0000 (Sat, 09 Mar 2002) | 2 lines
+Changed paths:
+ M /trunk/test/Makefile.am
+
+Don't link to libdl.
+
+------------------------------------------------------------------------
+r11 | sam | 2002-03-09 17:16:44 +0000 (Sat, 09 Mar 2002) | 3 lines
+Changed paths:
+ M /trunk/configure
+ M /trunk/configure.in
+ M /trunk/test/test.c
+
+
+ * Fixed compilation of test/test.c.
+
+------------------------------------------------------------------------
+r10 | sam | 2002-03-06 00:06:17 +0000 (Wed, 06 Mar 2002) | 3 lines
+Changed paths:
+ M /trunk/test/.cvsignore
+ A /trunk/test/test.c
+
+
+ * Updated misc control files and added the sample program.
+
+------------------------------------------------------------------------
+r9 | sam | 2002-03-06 00:04:41 +0000 (Wed, 06 Mar 2002) | 2 lines
+Changed paths:
+ M /trunk/Makefile.am
+ M /trunk/Makefile.in
+ M /trunk/aclocal.m4
+ M /trunk/config.guess
+ M /trunk/config.sub
+ M /trunk/configure
+ M /trunk/configure.in
+ M /trunk/debian/changelog
+ D /trunk/debian/libdvdcss2.shlibs
+ M /trunk/libtool
+ M /trunk/src/Makefile.am
+ M /trunk/src/Makefile.in
+ M /trunk/src/config.h.in
+ M /trunk/test/Makefile.am
+ M /trunk/test/Makefile.in
+
+*** empty log message ***
+
+------------------------------------------------------------------------
+r8 | hjort | 2002-02-25 18:21:57 +0000 (Mon, 25 Feb 2002) | 2 lines
+Changed paths:
+ M /trunk/src/css.c
+ M /trunk/src/css.h
+
+Cleanup some formating, indentation and types and add a small comment.
+
+------------------------------------------------------------------------
+r7 | hjort | 2002-02-03 14:54:53 +0000 (Sun, 03 Feb 2002) | 2 lines
+Changed paths:
+ M /trunk/src/ioctl.c
+ M /trunk/src/ioctl.h
+
+Add the WIN32 fix to GetTitleKey from the vlc/extra branch.
+
+------------------------------------------------------------------------
+r6 | hjort | 2002-02-03 14:53:10 +0000 (Sun, 03 Feb 2002) | 2 lines
+Changed paths:
+ M /trunk/configure.in
+
+Do check for the unistd.h header file.
+
+------------------------------------------------------------------------
+r5 | hjort | 2002-01-20 17:04:54 +0000 (Sun, 20 Jan 2002) | 7 lines
+Changed paths:
+ M /trunk/src/css.c
+ M /trunk/src/css.h
+
+Make CSSAuth more rubust, should now also work with drives that are not 100%
+compliant to the SFF-8090 standard. AGID invalidation should now work,
+allowing us to recover from hung / failed authentications. Corrected
+CSSGetASF, it does not take an AGID argument. Move several data structures
+from the dvdcss handle to local variables in CSSAuth. Remove CSSAuth as a
+externaly visible function in css.c.
+
+------------------------------------------------------------------------
+r4 | sam | 2001-12-22 00:52:46 +0000 (Sat, 22 Dec 2001) | 3 lines
+Changed paths:
+ M /trunk/configure
+ M /trunk/configure.in
+ M /trunk/libtool
+ A /trunk/src/.cvsignore
+ M /trunk/src/config.h.in
+ M /trunk/src/libdvdcss.c
+
+
+ * Win32 compilation fix.
+
+------------------------------------------------------------------------
+r3 | sam | 2001-12-22 00:26:17 +0000 (Sat, 22 Dec 2001) | 3 lines
+Changed paths:
+ M /trunk/configure
+ M /trunk/configure.in
+ M /trunk/src/config.h.in
+
+
+ * Attempt at fixing the Solaris port.
+
+------------------------------------------------------------------------
+r2 | sam | 2001-12-22 00:10:31 +0000 (Sat, 22 Dec 2001) | 3 lines
+Changed paths:
+ M /trunk/.cvsignore
+ A /trunk/Makefile.in
+ M /trunk/configure
+ M /trunk/configure.in
+ A /trunk/src/Makefile.in
+ M /trunk/test/.cvsignore
+ A /trunk/test/Makefile.in
+
+
+ * Forgot Makefile.in files.
+
+------------------------------------------------------------------------
+r1 | sam | 2001-12-22 00:08:13 +0000 (Sat, 22 Dec 2001) | 3 lines
+Changed paths:
+ A /trunk
+ A /trunk/.cvsignore
+ A /trunk/AUTHORS
+ A /trunk/COPYING
+ A /trunk/ChangeLog
+ A /trunk/INSTALL
+ A /trunk/Makefile.am
+ A /trunk/NEWS
+ A /trunk/README
+ A /trunk/aclocal.m4
+ A /trunk/bootstrap
+ A /trunk/config.guess
+ A /trunk/config.sub
+ A /trunk/configure
+ A /trunk/configure.in
+ A /trunk/debian
+ A /trunk/debian/.cvsignore
+ A /trunk/debian/changelog
+ A /trunk/debian/control
+ A /trunk/debian/libdvdcss2-dev.dirs
+ A /trunk/debian/libdvdcss2.copyright
+ A /trunk/debian/libdvdcss2.dirs
+ A /trunk/debian/libdvdcss2.shlibs
+ A /trunk/debian/rules
+ A /trunk/install-sh
+ A /trunk/libdvdcss.spec
+ A /trunk/libtool
+ A /trunk/ltmain.sh
+ A /trunk/missing
+ A /trunk/mkinstalldirs
+ A /trunk/src
+ A /trunk/src/Makefile.am
+ A /trunk/src/bsdi_dvd.h
+ A /trunk/src/bsdi_ioctl.c
+ A /trunk/src/common.h
+ A /trunk/src/config.h.in
+ A /trunk/src/css.c
+ A /trunk/src/css.h
+ A /trunk/src/csstables.h
+ A /trunk/src/dvdcss.h
+ A /trunk/src/ioctl.c
+ A /trunk/src/ioctl.h
+ A /trunk/src/libdvdcss.c
+ A /trunk/src/libdvdcss.h
+ A /trunk/test
+ A /trunk/test/.cvsignore
+ A /trunk/test/Makefile.am
+
+
+ * Initial commit. Hope it'll work.
+
+------------------------------------------------------------------------
diff --git a/lib/libdvd/libdvdcss/INSTALL b/lib/libdvd/libdvdcss/INSTALL
new file mode 100644
index 0000000000..254758f753
--- /dev/null
+++ b/lib/libdvd/libdvdcss/INSTALL
@@ -0,0 +1,77 @@
+INSTALL file for libdvdcss, a DVD access library
+
+
+Configuring libdvdcss
+=====================
+
+A typical way to configure libdvdcss is:
+
+ ./configure --prefix=/usr
+
+See `./configure --help' for more information.
+
+Building libdvdcss
+==================
+
+Once configured, run `make' to build libdvdcss.
+
+If you have player keys, you need to put them in the file csskeys.h, before
+configuring libdvdcss to enable the "key" method (the one from libcss).
+
+
+Installing libdvdcss
+====================
+
+You can install libdvdcss by typing:
+
+ make install
+
+
+Building libdvdcss for Win32
+============================
+
+You have two alternatives to build libdvdcss for Win32:
+
+- natively on Windows, using MSYS + MINGW (www.mingw.org):
+
+ (MSYS is a minimal build environnement to compile unixish projects under
+ windoze. It provides all the common unix tools like sh, gmake...)
+
+ You will need to download and install the latest MSYS (version 1.0.7 as
+ of now) and MINGW.
+ The installation is really easy. Begin with the MSYS auto-installer and once
+ this is done, extract MINGW into c:\msys\1.0\mingw. You also have to remember
+ to remove the make utility included with MINGW as it conflicts with the one
+ from MSYS (just rename or remove c:\msys\1.0\mingw\bin\make.exe).
+
+ http://www.mingw.org/download.shtml
+ http://prdownloads.sourceforge.net/mingw/MSYS-1.0.7-i686-2002.04.24-1.exe
+ http://prdownloads.sourceforge.net/mingw/MinGW-1.1.tar.gz
+
+ To build libdvdcss you just have to run the following commands:
+ ./configure
+ make
+
+- or on Linux, using the mingw32 cross-compiler:
+
+ You can find a mingw32 cross-compiler on the videolan web site:
+ http://www.videolan.org/vlc/windows.html
+ Or if you are running Debian, there is a mingw32 package you can use.
+
+ If you are cross-compiling from the Debian package, you can use the following
+ commands:
+
+ ./configure --host=i586-mingw32msvc --target=i586-mingw32msvc \
+ --build=i386-linux
+
+ make
+
+ If you are cross-compiling using the mingw32 package provided by
+ www.videolan.org, you have to use something along those lines:
+
+ CC=/usr/local/cross-tools/bin/i586-mingw32msvc-gcc \
+ PATH=/usr/local/cross-tools/bin:$PATH \
+ ./configure --host=i586-mingw32msvc --target=i586-mingw32msvc \
+ --build=i386-linux
+
+ PATH=/usr/local/cross-tools/bin:$PATH make
diff --git a/lib/libdvd/libdvdcss/Makefile.am b/lib/libdvd/libdvdcss/Makefile.am
new file mode 100644
index 0000000000..bc8b81d6d9
--- /dev/null
+++ b/lib/libdvd/libdvdcss/Makefile.am
@@ -0,0 +1,12 @@
+SUBDIRS = src test doc
+DIST_SUBDIRS = $(SUBDIRS)
+
+EXTRA_DIST = libdvdcss.spec bootstrap
+
+AUTOMAKE_OPTIONS = foreign dist-bzip2 subdir-objects
+
+doc-dummy:
+
+doc: doc-dummy
+ $(MAKE) -C doc doc
+
diff --git a/lib/libdvd/libdvdcss/NEWS b/lib/libdvd/libdvdcss/NEWS
new file mode 100644
index 0000000000..87df99944e
--- /dev/null
+++ b/lib/libdvd/libdvdcss/NEWS
@@ -0,0 +1,112 @@
+$Id$
+
+Changes between 1.2.9 and 1.2.10:
+---------------------------------
+
+ * DVD drive autodetection.
+ * new dvdcss_is_scrambled() function.
+ * various failure recovery improvements.
+ * accept "X:\" as a device name, as well as "X:".
+ * various bug fixes.
+
+Changes between 1.2.8 and 1.2.9:
+--------------------------------
+
+ * more robust key caching
+ * support for cache directory tags
+ * improved seeking on win32
+ * support for Solaris libsmedia library
+
+Changes between 1.2.7 and 1.2.8:
+--------------------------------
+
+ * win32 fix for encrypted DVDs.
+ * workaround for strange discs that report read errors seemingly at random.
+
+Changes between 1.2.6 and 1.2.7:
+--------------------------------
+
+ * activated key caching by default.
+ * fix for collisions between cached keys.
+ * packaging improvements for Debian.
+ * packaging improvements for RPM-based distributions.
+
+Changes between 1.2.5 and 1.2.6:
+--------------------------------
+
+ * compilation fix for most UNIXes
+
+Changes between 1.2.4 and 1.2.5:
+--------------------------------
+
+ * key cache support
+ * improved robustness in case of read errors
+ * now builds under Cygwin
+ * now builds under Microsoft Visual C++
+
+Changes between 1.2.3 and 1.2.4:
+--------------------------------
+
+ * administrator rights are no longer required under Windows NT/2000/XP
+
+Changes between 1.2.2 and 1.2.3:
+--------------------------------
+
+ * many Windows bugfixes
+ * workaround for drives which prevent key decryption
+
+Changes between 1.2.1 and 1.2.2:
+--------------------------------
+
+ * fix for the "ioctl_ReadTitleKey failed" bug on RPC2 drives
+ * better error checking
+ * improved documentation
+ * OS/2 port
+
+Changes between 1.2.0 and 1.2.1:
+--------------------------------
+
+ * fix for discs with a mismatched region
+ * QNX port
+
+Changes between 1.1.1 and 1.2.0:
+--------------------------------
+
+ * fix for a crash when an unencrypted sector is found on a scrambled disc
+ * stability enhancements
+
+Changes between 1.1.0 and 1.1.1:
+--------------------------------
+
+ * compilation fixes for BeOS, IRIX, OpenBSD
+
+Changes between 1.0.0 and 1.1.0:
+--------------------------------
+
+ * merged all patches from the Ogle group
+ * lots of bugfixes
+ * HP-UX port
+ * better error recovery
+ * third descrambling implementation
+
+Changes between 0.0.3 and 1.0.0:
+--------------------------------
+
+ * stable API
+ * OpenBSD port
+ * NetBSD port
+ * Mac OS X port
+
+Changes between 0.0.2 and 0.0.3:
+--------------------------------
+
+ * fix to access the whole device under Win32
+ * BSD/OS port
+ * Solaris port
+
+Changes between 0.0.1 and 0.0.2:
+--------------------------------
+
+ * internal key cache mechanism
+ * stability fixes
+
diff --git a/lib/libdvd/libdvdcss/README b/lib/libdvd/libdvdcss/README
new file mode 100644
index 0000000000..5b63385e7b
--- /dev/null
+++ b/lib/libdvd/libdvdcss/README
@@ -0,0 +1,71 @@
+README for libdvdcss, a portable abstraction library for DVD decryption
+$Id$
+
+
+Introduction
+============
+
+libdvdcss is part of the VideoLAN project, a full MPEG2 client/server
+solution. The VideoLAN Client can also be used as a standalone program
+to play MPEG2 streams from a hard disk or a DVD.
+
+
+Building and Installing libdvdcss
+=================================
+
+See the INSTALL or INSTALL.libdvdcss file for this.
+
+Running lidvdcss
+================
+
+The behaviourof the library can be affected by changing two environment
+variables:
+ DVDCSS_METHOD={title|disc|key}: method for key decryption
+ title: decrypted title key is guessed from the encrypted sectors of
+ the stream. Thus it should work with a file as well as the
+ DVD device. But it sometimes takes much time to decrypt a title
+ key and may even fail. With this method, the key is only checked
+ at the beginning of each title, so it won't work if the key
+ changes in the middle of a title.
+ disc: the disc key is first cracked ; then all title keys can be
+ decrypted instantly, which allows us to check them often,
+ key: the same as "disc" if you don't have a file with player keys at
+ compilation time. If you do, the decryption of the disc key
+ will be faster with this method. It is the one that was used by
+ libcss.
+ This is the default method,
+ DVDCSS_VERBOSE={0|1|2}: libdvdcss verbosity
+ 0: no error messages, no debug messages (this is the default)
+ 1: only error messages
+ 2: error and debug messages
+
+
+Troubleshooting
+===============
+
+A mailing-list has been set up for support and discussion about
+libdvdcss. Its address is :
+
+ <libdvdcss@videolan.org>
+
+To subscribe, send a mail to <listar@videolan.org> with the following
+words in the mail body :
+
+ subscribe libdvdcss
+
+To unsubscribe, do the same with the words :
+
+ unsubscribe libdvdcss
+
+
+When reporting bugs, try to be as precise as possible (which OS, which
+distribution, what plugins you were trying, and so on).
+
+
+Resources
+=========
+
+The VideoLAN web site at http://www.videolan.org/ is a good start for
+information about MPEG and DVD playing. Have a look at the documentation
+section, as well as the bookmarks.
+
diff --git a/lib/libdvd/libdvdcss/bootstrap b/lib/libdvd/libdvdcss/bootstrap
new file mode 100755
index 0000000000..434d6e3fca
--- /dev/null
+++ b/lib/libdvd/libdvdcss/bootstrap
@@ -0,0 +1,132 @@
+#! /bin/sh
+# $Id: bootstrap 2005 2008-07-16 20:51:50Z sam $
+
+# bootstrap: generic bootstrap/autogen.sh script for autotools projects
+#
+# Copyright (c) 2002-2008 Sam Hocevar <sam@zoy.org>
+#
+# This program is free software. It comes without any warranty, to
+# the extent permitted by applicable law. You can redistribute it
+# and/or modify it under the terms of the Do What The Fuck You Want
+# To Public License, Version 2, as published by Sam Hocevar. See
+# http://sam.zoy.org/wtfpl/COPYING for more details.
+#
+# The latest version of this script can be found at the following place:
+# http://sam.zoy.org/autotools/
+
+# Die if an error occurs
+set -e
+
+# Guess whether we are using configure.ac or configure.in
+if test -f configure.ac; then
+ conffile="configure.ac"
+elif test -f configure.in; then
+ conffile="configure.in"
+else
+ echo "$0: could not find configure.ac or configure.in"
+ exit 1
+fi
+
+# Check for needed features
+auxdir="`sed -ne 's/^[ \t]*A._CONFIG_AUX_DIR *([[ ]*\([^] )]*\).*/\1/p' $conffile`"
+libtool="`grep '^[ \t]*A._PROG_LIBTOOL' $conffile >/dev/null 2>&1 && echo yes || echo no`"
+header="`grep '^[ \t]*A._CONFIG_HEADER' $conffile >/dev/null 2>&1 && echo yes || echo no`"
+makefile="`[ -f Makefile.am ] && echo yes || echo no`"
+aclocalflags="`sed -ne 's/^[ \t]*ACLOCAL_AMFLAGS[ \t]*=//p' Makefile.am 2>/dev/null || :`"
+
+# Check for automake
+amvers="no"
+for v in 11 10 9 8 7 6 5; do
+ if automake-1.${v} --version >/dev/null 2>&1; then
+ amvers="-1.${v}"
+ break
+ elif automake1.${v} --version >/dev/null 2>&1; then
+ amvers="1.${v}"
+ break
+ fi
+done
+
+if test "${amvers}" = "no" && automake --version > /dev/null 2>&1; then
+ amvers="`automake --version | sed -e '1s/[^0-9]*//' -e q`"
+ if expr "$amvers" "<" "1.5" > /dev/null 2>&1; then
+ amvers="no"
+ else
+ amvers=""
+ fi
+fi
+
+if test "$amvers" = "no"; then
+ echo "$0: you need automake version 1.5 or later"
+ exit 1
+fi
+
+# Check for autoconf
+acvers="no"
+for v in "" "259" "253"; do
+ if autoconf${v} --version >/dev/null 2>&1; then
+ acvers="${v}"
+ break
+ fi
+done
+
+if test "$acvers" = "no"; then
+ echo "$0: you need autoconf"
+ exit 1
+fi
+
+# Check for libtool
+if test "$libtool" = "yes"; then
+ libtoolize="no"
+ if glibtoolize --version >/dev/null 2>&1; then
+ libtoolize="glibtoolize"
+ else
+ for v in "16" "15" "" "14"; do
+ if libtoolize${v} --version >/dev/null 2>&1; then
+ libtoolize="libtoolize${v}"
+ break
+ fi
+ done
+ fi
+
+ if test "$libtoolize" = "no"; then
+ echo "$0: you need libtool"
+ exit 1
+ fi
+fi
+
+# Remove old cruft
+for x in aclocal.m4 configure config.guess config.log config.sub config.cache config.h.in config.h compile libtool.m4 ltoptions.m4 ltsugar.m4 ltversion.m4 ltmain.sh libtool ltconfig missing mkinstalldirs depcomp install-sh; do rm -f $x autotools/$x; if test -n "$auxdir"; then rm -f "$auxdir/$x"; fi; done
+rm -Rf autom4te.cache
+if test -n "$auxdir"; then
+ if test ! -d "$auxdir"; then
+ mkdir "$auxdir"
+ fi
+ aclocalflags="${aclocalflags} -I $auxdir -I ."
+fi
+
+# Explain what we are doing from now
+set -x
+
+# Bootstrap package
+if test "$libtool" = "yes"; then
+ ${libtoolize} --copy --force
+ if test -n "$auxdir" -a ! "$auxdir" = "." -a -f "ltmain.sh"; then
+ echo "$0: working around a minor libtool issue"
+ mv ltmain.sh "$auxdir/"
+ fi
+fi
+
+aclocal${amvers} ${aclocalflags}
+autoconf${acvers}
+if test "$header" = "yes"; then
+ autoheader${acvers}
+fi
+if test "$makefile" = "yes"; then
+ #add --include-deps if you want to bootstrap with any other compiler than gcc
+ #automake${amvers} --add-missing --copy --include-deps
+ automake${amvers} --foreign --add-missing --copy
+fi
+
+# Remove cruft that we no longer want
+rm -Rf autom4te.cache
+
diff --git a/lib/libdvd/libdvdcss/configure.ac b/lib/libdvd/libdvdcss/configure.ac
new file mode 100644
index 0000000000..1b9ff8b7b7
--- /dev/null
+++ b/lib/libdvd/libdvdcss/configure.ac
@@ -0,0 +1,215 @@
+AC_INIT(src/libdvdcss.c)
+
+AC_PREREQ(2.50)
+AC_CONFIG_AUX_DIR(.auto)
+AC_CANONICAL_SYSTEM
+
+AM_INIT_AUTOMAKE(libdvdcss, 1.2.10)
+AM_CONFIG_HEADER(config.h)
+
+AC_PROG_CC
+AC_STDC_HEADERS
+
+AC_LIBTOOL_WIN32_DLL
+AM_PROG_LIBTOOL
+
+AC_C_CONST
+AC_C_INLINE
+AC_TYPE_SIZE_T
+
+AC_CHECK_HEADERS(unistd.h sys/param.h limits.h pwd.h errno.h)
+
+dnl
+dnl Check the operating system
+dnl
+case x"${target_os}" in
+ xdarwin*)
+ CFLAGS="${CFLAGS} -no-cpp-precomp"
+ ;;
+ x*cygwin*)
+ dnl Check if we are using the mno-cygwin mode in which case we are
+ dnl actually dealing with a mingw32 compiler.
+ AC_EGREP_CPP(yes, [#ifndef WIN32
+ yes
+ #endif],
+ AC_DEFINE(SYS_CYGWIN, 1, Have a Cygwin system.))
+ AC_DEFINE(WIN32, 1, Using Win32.)
+ ;;
+ xbeos*)
+ AC_DEFINE(SYS_BEOS, 1, Have a BeOS system.)
+ ;;
+ x*msvc*)
+ SYS_MSVC=1
+ ;;
+ x*)
+ ;;
+esac
+
+dnl
+dnl libdvdcss: check for DVD ioctls
+dnl
+
+dnl default is no
+CAN_BUILD_LIBDVDCSS=0
+
+dnl for windoze
+AC_CHECK_HEADERS(windows.h,[
+ AC_CHECK_HEADERS(direct.h,,,[
+ #include <windows.h>
+ ])
+ AC_CHECK_HEADERS(winioctl.h,[
+ CAN_BUILD_LIBDVDCSS=1
+ ],,[
+ #include <windows.h>
+ ])
+])
+
+dnl for Un*x and BeOS
+AC_CHECK_HEADERS(sys/ioctl.h,[
+ CAN_BUILD_LIBDVDCSS=1
+ AC_CHECK_HEADERS(sys/cdio.h sys/dvdio.h linux/cdrom.h dvd.h)
+ BSD_DVD_STRUCT=0
+ LINUX_DVD_STRUCT=0
+ OPENBSD_DVD_STRUCT=0
+ dnl
+ dnl Old FreeBSD: sys/cdio.h
+ dnl
+ AC_EGREP_HEADER(dvd_struct,sys/cdio.h,[
+ AC_DEFINE(DVD_STRUCT_IN_SYS_CDIO_H, 1,
+ Define if <sys/cdio.h> defines dvd_struct.)
+ AC_EGREP_HEADER(struct dvd_struct,sys/cdio.h,[
+ BSD_DVD_STRUCT=1],[LINUX_DVD_STRUCT=1; OPENBSD_DVD_STRUCT=1])
+ ])
+ dnl
+ dnl Newer FreeBSD: sys/dvdio.h
+ dnl
+ AC_EGREP_HEADER(dvd_struct,sys/dvdio.h,[
+ AC_DEFINE(DVD_STRUCT_IN_SYS_DVDIO_H, 1,
+ Define if <sys/dvdio.h> defines dvd_struct.)
+ AC_EGREP_HEADER(struct dvd_struct,sys/dvdio.h,[
+ BSD_DVD_STRUCT=1],[LINUX_DVD_STRUCT=1])
+ ])
+ dnl
+ dnl Linux: linux/cdrom.h
+ dnl
+ AC_EGREP_HEADER(dvd_struct,linux/cdrom.h,[
+ AC_DEFINE(DVD_STRUCT_IN_LINUX_CDROM_H, 1,
+ Define if <linux/cdrom.h> defines DVD_STRUCT.)
+ LINUX_DVD_STRUCT=1
+ ])
+ dnl
+ dnl BSDI: dvd.h - may require -ldvd IF a local copy of libdvd is installed
+ dnl
+ AC_EGREP_HEADER(dvd_struct,dvd.h,[
+ AC_DEFINE(DVD_STRUCT_IN_DVD_H, 1,
+ Define if <dvd.h> defines DVD_STRUCT.)
+ SYS_BSDI_LIBDVD=1
+ LINUX_DVD_STRUCT=1
+ ],[
+ dnl
+ dnl BSDI: /sys/dev/scsi/scsi_ioctl.h, using our own libdvd
+ dnl
+ AC_CHECK_HEADERS(/sys/dev/scsi/scsi_ioctl.h,[
+ AC_DEFINE(DVD_STRUCT_IN_BSDI_DVDIOCTL_DVD_H, 1,
+ Define if <extras/BSDI_dvdioctl/dvd.h> defines DVD_STRUCT.)
+ SYS_BSDI=1
+ LINUX_DVD_STRUCT=1
+ ])
+ ])
+ dnl
+ dnl Solaris: sys/scsi/scsi_types.h, sys/scsi/impl/uscsi.h
+ dnl
+ AC_CHECK_HEADER(sys/scsi/scsi_types.h,[
+ AC_CHECK_HEADER(sys/scsi/impl/uscsi.h,[
+ AC_DEFINE(SOLARIS_USCSI, 1, Have userspace SCSI headers.)
+ ])
+ ])
+ dnl
+ dnl HP-UX: sys/scsi.h
+ dnl
+ AC_CHECK_HEADER(sys/scsi.h,[
+ AC_EGREP_HEADER(sctl_io,sys/scsi.h,[
+ AC_DEFINE(HPUX_SCTL_IO, 1, Define if <sys/scsi.h> defines sctl_io.)
+ ])
+ ])
+ dnl
+ dnl Darwin
+ dnl
+ AC_CHECK_HEADER(IOKit/storage/IODVDMediaBSDClient.h,[
+ AC_DEFINE(DARWIN_DVD_IOCTL, 1, Have IOKit DVD IOCTL headers)
+ DVDCSS_LDFLAGS="-Wl,-framework -Wl,CoreFoundation -Wl,-framework -Wl,IOKit"
+ ])
+ dnl
+ dnl Final tests to check what was detected
+ dnl
+ if test x$LINUX_DVD_STRUCT = x1; then
+ AC_DEFINE(HAVE_LINUX_DVD_STRUCT, 1,
+ Define if Linux-like dvd_struct is defined.)
+ if test x$OPENBSD_DVD_STRUCT = x1; then
+ AC_DEFINE(HAVE_OPENBSD_DVD_STRUCT, 1,
+ Define if OpenBSD-like dvd_struct is defined.)
+ fi
+ else
+ if test x$BSD_DVD_STRUCT = x1; then
+ AC_DEFINE(HAVE_BSD_DVD_STRUCT, 1,
+ Define if FreeBSD-like dvd_struct is defined.)
+ fi
+ fi
+])
+
+dnl
+dnl Check for available warning flags
+dnl
+CFLAGS_save="${CFLAGS}"
+
+AC_CACHE_CHECK([if \$CC accepts -Wall],
+ [ac_cv_c_Wall],
+ [CFLAGS="-Wall ${CFLAGS_save}"
+ AC_TRY_COMPILE([],,ac_cv_c_Wall=yes, ac_cv_c_Wall=no)])
+if test "${ac_cv_c_Wall}" != "no"; then
+ CFLAGS_save="-Wall ${CFLAGS_save}"
+fi
+
+AC_CACHE_CHECK([if \$CC accepts -Wsign-compare],
+ [ac_cv_c_Wsign_compare],
+ [CFLAGS="-Wsign-compare ${CFLAGS_save}"
+ AC_TRY_COMPILE([],,ac_cv_c_Wsign_compare=yes, ac_cv_c_Wsign_compare=no)])
+if test "${ac_cv_c_Wsign_compare}" != "no"; then
+ CFLAGS_save="-Wsign-compare ${CFLAGS_save}"
+fi
+
+CFLAGS="${CFLAGS_save}"
+
+dnl
+dnl Use 64 bits offsets
+dnl
+CFLAGS="-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -DDVDCSS_DIST ${CFLAGS}"
+
+AM_CONDITIONAL(SYS_BSDI, test "${SYS_BSDI}" = "1")
+AM_CONDITIONAL(SYS_BSDI_LIBDVD, test "${SYS_BSDI_LIBDVD}" = "1")
+AM_CONDITIONAL(SYS_MSVC, test "${SYS_MSVC}" = "1")
+
+dnl
+dnl Shall we build documentation?
+dnl
+AC_ARG_ENABLE([doc], AC_HELP_STRING([--disable-doc], [do not build API documentation with Doxygen]))
+if test "$enable_doc" != "no"; then
+ AC_PATH_PROG(DOXYGEN, doxygen, no)
+ AC_PATH_PROG(LATEX, latex, no)
+else
+ DOXYGEN="no"
+ LATEX="no"
+fi
+AM_CONDITIONAL(DOXYGEN, test "${DOXYGEN}" != "no")
+AM_CONDITIONAL(LATEX, test "${LATEX}" != "no")
+
+AC_SUBST(DVDCSS_LDFLAGS)
+AC_OUTPUT([
+ Makefile
+ doc/Makefile
+ src/Makefile
+ src/dvdcss/Makefile
+ test/Makefile
+ src/libdvdcss.pc
+])
+
diff --git a/lib/libdvd/libdvdcss/doc/Makefile.am b/lib/libdvd/libdvdcss/doc/Makefile.am
new file mode 100644
index 0000000000..2e269b028a
--- /dev/null
+++ b/lib/libdvd/libdvdcss/doc/Makefile.am
@@ -0,0 +1,28 @@
+EXTRA_DIST = doxygen.cfg.in footer.html header.html
+DISTCLEANFILES = doxygen.cfg
+
+all: stamp-doxygen stamp-latex
+
+doxygen.cfg: $(srcdir)/doxygen.cfg.in
+ -rm -f $@
+ sed 's|@SRCDIR@|$(srcdir)|g; s|@TOP_SRCDIR@|$(top_srcdir)|g' $< > $@
+
+stamp-doxygen: doxygen.cfg
+if DOXYGEN
+ doxygen doxygen.cfg
+ touch stamp-doxygen
+endif
+
+stamp-latex: stamp-doxygen
+if DOXYGEN
+if LATEX
+ cd latex && $(MAKE) $(AM_CFLAGS) ps
+ touch stamp-latex
+endif
+endif
+
+clean: clean-local
+clean-local:
+ -rm -f stamp-latex stamp-doxygen
+ -rm -Rf html latex
+
diff --git a/lib/libdvd/libdvdcss/doc/doxygen.cfg.in b/lib/libdvd/libdvdcss/doc/doxygen.cfg.in
new file mode 100644
index 0000000000..c27228a17c
--- /dev/null
+++ b/lib/libdvd/libdvdcss/doc/doxygen.cfg.in
@@ -0,0 +1,1419 @@
+# Doxyfile 1.5.6
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = libdvdcss
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 1.2.5
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,
+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,
+# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
+# and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page. This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = @TOP_SRCDIR@/src/dvdcss/dvdcss.h \
+ @TOP_SRCDIR@/src/libdvdcss.c
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS = *.c \
+ *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE = ../src/config.h
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = *_private.h
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER = @SRCDIR@/header.html
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER = @SRCDIR@/footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = YES
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to FRAME, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature. Other possible values
+# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
+# and Class Hiererachy pages using a tree view instead of an ordered list;
+# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
+# disables this behavior completely. For backwards compatibility with previous
+# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
+# respectively.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = _DOXYGEN_SKIP_ME
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = FreeSans
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS = .
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is enabled by default, which results in a transparent
+# background. Warning: Depending on the platform used, enabling this option
+# may lead to badly anti-aliased labels on the edges of a graph (i.e. they
+# become hard to read).
+
+DOT_TRANSPARENT = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/lib/libdvd/libdvdcss/doc/footer.html b/lib/libdvd/libdvdcss/doc/footer.html
new file mode 100644
index 0000000000..b1f50f56cc
--- /dev/null
+++ b/lib/libdvd/libdvdcss/doc/footer.html
@@ -0,0 +1,3 @@
+<!-- $Id$ -->
+ </body>
+</html>
diff --git a/lib/libdvd/libdvdcss/doc/header.html b/lib/libdvd/libdvdcss/doc/header.html
new file mode 100644
index 0000000000..b6c70da037
--- /dev/null
+++ b/lib/libdvd/libdvdcss/doc/header.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+ <title>libdvdcss documentation</title>
+ <link href="/main.css" rel="stylesheet" type="text/css">
+ <link href="/doxygen.css" rel="stylesheet" type="text/css">
+ </head>
+ <body>
+<!-- $Id$ -->
diff --git a/lib/libdvd/libdvdcss/libdvdcss.spec b/lib/libdvd/libdvdcss/libdvdcss.spec
new file mode 100644
index 0000000000..4276333846
--- /dev/null
+++ b/lib/libdvd/libdvdcss/libdvdcss.spec
@@ -0,0 +1,181 @@
+%define name libdvdcss
+%define version 1.2.9
+%define release 1
+
+%define major 2
+%define libname %{name}%{major}
+
+%define buildfor_rh9 %([[ -e /etc/mandrake-release ]] && echo 0 || echo 1)
+
+%if %buildfor_rh9
+# some mdk macros that do not exist in rh
+%define configure2_5x %configure
+%define make %__make
+%define makeinstall_std %makeinstall
+# adjust define for Redhat.
+%endif
+
+
+Name: %{name}
+Version: %{version}
+Release: %{release}
+Summary: Library for accessing DVDs like block devices with transparent decryption
+Source: %{name}-%{version}.tar.bz2
+License: GPL
+Group: System/Libraries
+URL: http://www.videolan.org/libdvdcss/
+Packager: Yves Duret <yves@zarb.org>
+BuildRoot: %_tmppath/%name-%version-%release-root
+Conflicts: libdvdcss0.0.1, libdvdcss0.0.2
+
+%description
+libdvdcss is a simple library designed for accessing DVDs like a block device
+without having to bother about the decryption. The important features are:
+ * Portability: currently supported platforms are GNU/Linux, FreeBSD, NetBSD,
+ OpenBSD, BSD/OS, BeOS, Windows 95/98/ME, Windows NT/2000/XP, MacOS X,
+ Solaris, HP-UX and OS/2.
+ * Adaptability: unlike most similar projects, libdvdcss doesn't require the
+ region of your drive to be set and will try its best to read from the disc
+ even in the case of a region mismatch.
+ * Simplicity: a DVD player can be built around the libdvdcss API using no
+ more than 6 library calls.
+
+%package -n %{libname}
+Summary: Library for accessing DVDs like block devices with transparent decryption
+Group: System/Libraries
+Provides: %name = %version-%release
+
+%description -n %{libname}
+libdvdcss is a simple library designed for accessing DVDs like a block device
+without having to bother about the decryption. The important features are:
+ * Portability: currently supported platforms are GNU/Linux, FreeBSD, NetBSD,
+ OpenBSD, BSD/OS, BeOS, Windows 95/98/ME, Windows NT/2000/XP, MacOS X,
+ Solaris, HP-UX and OS/2.
+ * Adaptability: unlike most similar projects, libdvdcss doesn't require the
+ region of your drive to be set and will try its best to read from the disc
+ even in the case of a region mismatch.
+ * Simplicity: a DVD player can be built around the libdvdcss API using no
+ more than 6 library calls.
+
+%package -n %{libname}-devel
+Summary: Development tools for programs which will use the %{name} library
+Group: Development/C
+Requires: %{libname} = %version-%release
+Provides: %{name}-devel = %version-%release
+
+%description -n %{libname}-devel
+The %{name}-devel package includes the header files and static libraries
+necessary for developing programs which will manipulate DVDs files using
+the %{name} library.
+
+If you are going to develop programs which will manipulate DVDs, you
+should install %{name}-devel. You'll also need to have the %{name}
+package installed.
+
+%prep
+%setup -q
+
+%build
+%configure2_5x
+%make
+
+%install
+%makeinstall_std
+
+%clean
+[ %buildroot != "/" ] && rm -Rf %buildroot
+
+%post -n %{libname} -p /sbin/ldconfig
+
+%postun -n %{libname} -p /sbin/ldconfig
+
+%files -n %{libname}
+%defattr(-,root,root)
+%doc AUTHORS COPYING NEWS
+%{_libdir}/*.so.*
+
+%files -n %{libname}-devel
+%defattr(-,root,root)
+%doc ChangeLog COPYING
+%{_libdir}/*.a
+%{_libdir}/*.so
+%{_libdir}/*.la
+%{_includedir}/*
+
+%changelog
+* Mon Jul 11 2005 Sam Hocevar <sam@zoy.org> 1.2.9-1
+- new upstream release
+
+* Tue Jul 29 2003 Sam Hocevar <sam@zoy.org> 1.2.8-1
+- new upstream release
+
+* Fri Jun 13 2003 Sam Hocevar <sam@zoy.org> 1.2.7-1
+- new upstream release
+- key cache activated by default
+
+* Mon Mar 10 2003 Alexis de Lattre <alexis@videolan.org> 1.2.6-1
+- new upstream release
+- small bug fixes
+
+* Tue Jan 28 2003 Sam Hocevar <sam@zoy.org> 1.2.5-1
+- new upstream release
+- improved robustness in case of read errors
+- key cache support
+- added more macros to fix RedHat build
+
+* Mon Nov 18 2002 Alexis de Lattre <alexis@videolan.org> 1.2.4-2
+- Changes in .spec file for RedHat and RPM 4.1
+
+* Thu Nov 14 2002 Alexis de Lattre <alexis@videolan.org> 1.2.4-1
+- new upstream release
+- fixes for Win32
+
+* Sun Oct 13 2002 Sam Hocevar <sam@zoy.org> 1.2.3-1
+- new upstream release
+- fix for drives not allowing to read their disc key
+
+* Sat Aug 10 2002 Sam Hocevar <sam@zoy.org> 1.2.2-1
+- new upstream release
+- even more fixes for the disc/drive region mismatch problem
+
+* Sun Jun 02 2002 Sam Hocevar <sam@zoy.org> 1.2.1-1
+- new upstream release
+- fix for a crash on disc/drive region mismatch
+
+* Mon May 20 2002 Sam Hocevar <sam@zoy.org> 1.2.0-1
+- new upstream release
+- weird libxalf dependency is gone
+
+* Sun Apr 07 2002 Yves Duret <yduret@mandrakesoft.com> 1.1.1-2plf
+- major version is 2 (aka guillaume sux).
+- spec clean up: do not rm in %%prep, %%buildroot, %%makeinstall_std, %%provides %%version-%%release
+- added doc in devel
+- sync with cvs's one (%%description,%%files, conflicts).
+- fix url
+
+* Sat Apr 06 2002 Guillaume Rousse <rousse@ccr.jussieu.fr> 1.1.1-1plf
+- 1.1.1
+
+* Wed Jan 30 2002 Guillaume Rousse <rousse@ccr.jussieu.fr> 1.0.0-3plf
+- new plf extension
+
+* Wed Dec 05 2001 Guillaume Rousse <g.rousse@linux-mandrake.com> 1.0.0-3mdk
+- removed conflict
+
+* Tue Dec 04 2001 Guillaume Rousse <g.rousse@linux-mandrake.com> 1.0.0-2mdk
+- contributed to PLF by Yves Duret <yduret@mandrakesoft.com>
+- Conflicts: libdvdcss-ogle
+- more doc files
+- no doc file for devel package
+
+* Fri Nov 30 2001 Yves Duret <yduret@mandrakesoft.com> 1.0.0-1mdk
+- version 1.0.0
+
+* Thu Aug 23 2001 Yves Duret <yduret@mandrakesoft.com> 0.0.3-1mdk
+- version 0.0.3
+
+* Mon Aug 13 2001 Yves Duret <yduret@mandrakesoft.com> 0.0.2-1mdk
+- version 0.0.2
+
+* Tue Jun 19 2001 Yves Duret <yduret@mandrakesoft.com> 0.0.1-1mdk
+- first release and first mdk release
diff --git a/lib/libdvd/libdvdcss/src/Makefile.am b/lib/libdvd/libdvdcss/src/Makefile.am
new file mode 100644
index 0000000000..3823b501d8
--- /dev/null
+++ b/lib/libdvd/libdvdcss/src/Makefile.am
@@ -0,0 +1,37 @@
+SUBDIRS = dvdcss
+
+lib_LTLIBRARIES = libdvdcss.la
+
+libdvdcss_la_SOURCES = \
+ libdvdcss.c libdvdcss.h \
+ device.c device.h \
+ css.c css.h csstables.h \
+ ioctl.c ioctl.h \
+ error.c \
+ common.h \
+ $(bsdi_sources)
+
+EXTRA_libdvdcss_la_SOURCES = \
+ $(bsdi_extras)
+
+libdvdcss_la_LIBADD = $(bsdi_libadd)
+libdvdcss_la_LDFLAGS = -version-info 3:0:1 $(libtool_flags) @DVDCSS_LDFLAGS@
+
+bsdi_extras = bsdi_ioctl.c bsdi_dvd.h
+
+if SYS_BSDI
+bsdi_sources = $(bsdi_extras)
+endif
+
+if SYS_BSDI_LIBDVD
+bsdi_libadd = -ldvd
+endif
+
+if SYS_MSVC
+else
+libtool_flags = -no-undefined
+endif
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libdvdcss.pc
+
diff --git a/lib/libdvd/libdvdcss/src/bsdi_dvd.h b/lib/libdvd/libdvdcss/src/bsdi_dvd.h
new file mode 100644
index 0000000000..f4c8b89f6d
--- /dev/null
+++ b/lib/libdvd/libdvdcss/src/bsdi_dvd.h
@@ -0,0 +1,344 @@
+/*
+ * $Id$
+*/
+
+#ifndef DVDCSS_DVD_H
+#define DVDCSS_DVD_H
+
+#include <sys/cdefs.h>
+#include <machine/endian.h>
+#include <sys/ioctl.h>
+
+__BEGIN_DECLS
+int dvd_cdrom_ioctl(int, unsigned long, void *);
+int cdrom_blocksize(int, int);
+void dvd_cdrom_debug(int);
+__END_DECLS
+
+#define ioctl(a,b,c) dvd_cdrom_ioctl((a),(b),(c))
+
+typedef unsigned char __u8;
+typedef unsigned short __u16;
+typedef unsigned int __u32;
+
+#define DVD_READ_STRUCT 0x5390 /* Read structure */
+#define DVD_WRITE_STRUCT 0x5391 /* Write structure */
+#define DVD_AUTH 0x5392 /* Authentication */
+
+#define DVD_STRUCT_PHYSICAL 0x00
+#define DVD_STRUCT_COPYRIGHT 0x01
+#define DVD_STRUCT_DISCKEY 0x02
+#define DVD_STRUCT_BCA 0x03
+#define DVD_STRUCT_MANUFACT 0x04
+
+struct dvd_layer {
+ __u8 book_version : 4;
+ __u8 book_type : 4;
+ __u8 min_rate : 4;
+ __u8 disc_size : 4;
+ __u8 layer_type : 4;
+ __u8 track_path : 1;
+ __u8 nlayers : 2;
+ __u8 track_density : 4;
+ __u8 linear_density : 4;
+ __u8 bca : 1;
+ __u32 start_sector;
+ __u32 end_sector;
+ __u32 end_sector_l0;
+};
+
+struct dvd_physical {
+ __u8 type;
+ __u8 layer_num;
+ struct dvd_layer layer[4];
+};
+
+struct dvd_copyright {
+ __u8 type;
+
+ __u8 layer_num;
+ __u8 cpst;
+ __u8 rmi;
+};
+
+struct dvd_disckey {
+ __u8 type;
+
+ unsigned agid : 2;
+ __u8 value[2048];
+};
+
+struct dvd_bca {
+ __u8 type;
+
+ int len;
+ __u8 value[188];
+};
+
+struct dvd_manufact {
+ __u8 type;
+
+ __u8 layer_num;
+ int len;
+ __u8 value[2048];
+};
+
+typedef union {
+ __u8 type;
+
+ struct dvd_physical physical;
+ struct dvd_copyright copyright;
+ struct dvd_disckey disckey;
+ struct dvd_bca bca;
+ struct dvd_manufact manufact;
+} dvd_struct;
+
+/*
+ * DVD authentication ioctl
+ */
+
+/* Authentication states */
+#define DVD_LU_SEND_AGID 0
+#define DVD_HOST_SEND_CHALLENGE 1
+#define DVD_LU_SEND_KEY1 2
+#define DVD_LU_SEND_CHALLENGE 3
+#define DVD_HOST_SEND_KEY2 4
+
+/* Termination states */
+#define DVD_AUTH_ESTABLISHED 5
+#define DVD_AUTH_FAILURE 6
+
+/* Other functions */
+#define DVD_LU_SEND_TITLE_KEY 7
+#define DVD_LU_SEND_ASF 8
+#define DVD_INVALIDATE_AGID 9
+#define DVD_LU_SEND_RPC_STATE 10
+#define DVD_HOST_SEND_RPC_STATE 11
+
+/* State data */
+typedef __u8 dvd_key[5]; /* 40-bit value, MSB is first elem. */
+typedef __u8 dvd_challenge[10]; /* 80-bit value, MSB is first elem. */
+
+struct dvd_lu_send_agid {
+ __u8 type;
+ unsigned agid : 2;
+};
+
+struct dvd_host_send_challenge {
+ __u8 type;
+ unsigned agid : 2;
+
+ dvd_challenge chal;
+};
+
+struct dvd_send_key {
+ __u8 type;
+ unsigned agid : 2;
+
+ dvd_key key;
+};
+
+struct dvd_lu_send_challenge {
+ __u8 type;
+ unsigned agid : 2;
+
+ dvd_challenge chal;
+};
+
+#define DVD_CPM_NO_COPYRIGHT 0
+#define DVD_CPM_COPYRIGHTED 1
+
+#define DVD_CP_SEC_NONE 0
+#define DVD_CP_SEC_EXIST 1
+
+#define DVD_CGMS_UNRESTRICTED 0
+#define DVD_CGMS_SINGLE 2
+#define DVD_CGMS_RESTRICTED 3
+
+struct dvd_lu_send_title_key {
+ __u8 type;
+ unsigned agid : 2;
+
+ dvd_key title_key;
+ int lba;
+ unsigned cpm : 1;
+ unsigned cp_sec : 1;
+ unsigned cgms : 2;
+};
+
+struct dvd_lu_send_asf {
+ __u8 type;
+ unsigned agid : 2;
+
+ unsigned asf : 1;
+};
+
+struct dvd_host_send_rpcstate {
+ __u8 type;
+ __u8 pdrc;
+};
+
+struct dvd_lu_send_rpcstate {
+ __u8 type : 2;
+ __u8 vra : 3;
+ __u8 ucca : 3;
+ __u8 region_mask;
+ __u8 rpc_scheme;
+};
+
+typedef union {
+ __u8 type;
+
+ struct dvd_lu_send_agid lsa;
+ struct dvd_host_send_challenge hsc;
+ struct dvd_send_key lsk;
+ struct dvd_lu_send_challenge lsc;
+ struct dvd_send_key hsk;
+ struct dvd_lu_send_title_key lstk;
+ struct dvd_lu_send_asf lsasf;
+ struct dvd_host_send_rpcstate hrpcs;
+ struct dvd_lu_send_rpcstate lrpcs;
+} dvd_authinfo;
+
+
+typedef struct {
+ __u16 report_key_length;
+ __u8 reserved1;
+ __u8 reserved2;
+#if BYTE_ORDER == BIG_ENDIAN
+ __u8 type_code : 2;
+ __u8 vra : 3;
+ __u8 ucca : 3;
+#elif BYTE_ORDER == LITTLE_ENDIAN
+ __u8 ucca : 3;
+ __u8 vra : 3;
+ __u8 type_code : 2;
+#endif
+ __u8 region_mask;
+ __u8 rpc_scheme;
+ __u8 reserved3;
+} rpc_state_t;
+
+/*
+ * Stuff for the CDROM ioctls
+*/
+
+#define CDROMREADTOCHDR 0x5305 /* Read TOC header (cdrom_tochdr) */
+#define CDROMREADTOCENTRY 0x5306 /* Read TOC entry (cdrom_tocentry) */
+#define CDROMEJECT 0x5309 /* Ejects the cdrom media */
+#define CDROMCLOSETRAY 0x5319 /* Reverse of CDROMEJECT */
+#define CDROM_DRIVE_STATUS 0x5326 /* Get tray position, etc. */
+#define CDROM_DISC_STATUS 0x5327 /* Get disc type, etc. */
+#define CDROMREADMODE2 0x530c /* Read CDROM mode 2 data (2336 Bytes) */
+#define CDROMREADMODE1 0x530d /* Read CDROM mode 1 data (2048 Bytes) */
+#define CDROMREADRAW 0x5314 /* read data in raw mode (2352 bytes) */
+
+#define CD_MINS 74 /* max. minutes per CD, not really a limit */
+#define CD_SECS 60 /* seconds per minute */
+#define CD_FRAMES 75 /* frames per second */
+#define CD_MSF_OFFSET 150 /* MSF numbering offset of first frame */
+
+#define CD_HEAD_SIZE 4 /* header (address) bytes per raw data frame */
+#define CD_SYNC_SIZE 12 /* 12 sync bytes per raw data frame */
+#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */
+#define CD_FRAMESIZE_RAW 2352 /* bytes per frame, "raw" mode */
+#define CD_FRAMESIZE_RAW0 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE) /*2336*/
+#define CD_FRAMESIZE_RAW1 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE) /*2340*/
+
+/* CD-ROM address types (cdrom_tocentry.cdte_format) */
+#define CDROM_LBA 0x01 /* logical block: first frame is #0 */
+#define CDROM_MSF 0x02 /* minute-second-frame: binary. not bcd here!*/
+
+/* bit to tell whether track is data or audio (cdrom_tocentry.cdte_ctrl) */
+#define CDROM_DATA_TRACK 0x04
+
+/* The leadout track is always 0xAA, regardless of # of tracks on disc */
+#define CDROM_LEADOUT 0xAA
+
+/* drive status returned by CDROM_DRIVE_STATUS ioctl */
+#define CDS_NO_INFO 0 /* if not implemented */
+#define CDS_NO_DISC 1
+#define CDS_TRAY_OPEN 2
+#define CDS_DRIVE_NOT_READY 3
+#define CDS_DISC_OK 4
+
+/*
+ * Return values for CDROM_DISC_STATUS ioctl.
+ * Can also return CDS_NO_INFO and CDS_NO_DISC from above
+*/
+#define CDS_AUDIO 100
+#define CDS_DATA_1 101
+#define CDS_DATA_2 102
+#define CDS_XA_2_1 103
+#define CDS_XA_2_2 104
+#define CDS_MIXED 105
+
+/* For compile compatibility only - we don't support changers */
+#define CDSL_NONE ((int) (~0U>>1)-1)
+#define CDSL_CURRENT ((int) (~0U>>1))
+
+struct cdrom_msf
+{
+ __u8 cdmsf_min0; /* start minute */
+ __u8 cdmsf_sec0; /* start second */
+ __u8 cdmsf_frame0; /* start frame */
+ __u8 cdmsf_min1; /* end minute */
+ __u8 cdmsf_sec1; /* end second */
+ __u8 cdmsf_frame1; /* end frame */
+};
+
+struct cdrom_tochdr
+ {
+ __u8 cdth_trk0; /* start track */
+ __u8 cdth_trk1; /* end track */
+ };
+
+struct cdrom_msf0
+{
+ __u8 minute;
+ __u8 second;
+ __u8 frame;
+};
+
+union cdrom_addr
+{
+ struct cdrom_msf0 msf;
+ int lba;
+};
+
+struct cdrom_tocentry
+{
+ __u8 cdte_track;
+ __u8 cdte_adr :4;
+ __u8 cdte_ctrl :4;
+ __u8 cdte_format;
+ union cdrom_addr cdte_addr;
+ __u8 cdte_datamode;
+};
+
+struct modesel_head
+{
+ __u8 reserved1;
+ __u8 medium;
+ __u8 reserved2;
+ __u8 block_desc_length;
+ __u8 density;
+ __u8 number_of_blocks_hi;
+ __u8 number_of_blocks_med;
+ __u8 number_of_blocks_lo;
+ __u8 reserved3;
+ __u8 block_length_hi;
+ __u8 block_length_med;
+ __u8 block_length_lo;
+};
+
+typedef struct
+{
+ int data;
+ int audio;
+ int cdi;
+ int xa;
+ int error;
+} tracktype;
+
+#endif /* DVDCSS_DVD_H */
diff --git a/lib/libdvd/libdvdcss/src/bsdi_ioctl.c b/lib/libdvd/libdvdcss/src/bsdi_ioctl.c
new file mode 100644
index 0000000000..ef4c56c30e
--- /dev/null
+++ b/lib/libdvd/libdvdcss/src/bsdi_ioctl.c
@@ -0,0 +1,770 @@
+#include "config.h"
+
+/*
+ * Hacked version of the linux cdrom.c kernel module - everything except the
+ * DVD handling ripped out and the rest rewritten to use raw SCSI commands
+ * on BSD/OS 4.2 (but should work with earlier versions as well).
+*/
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include </sys/dev/scsi/scsi.h>
+#include </sys/dev/scsi/scsi_ioctl.h>
+
+#include "bsdi_dvd.h"
+
+/*
+ * Now get rid of the override/intercept macro so we can call the real ioctl()
+ * routine!
+*/
+#undef ioctl
+
+#define CMD_READ_10 0x28
+#define CMD_READ_TOC_PMA_ATIP 0x43
+#define CMD_READ_CD 0xbe
+#define CMD_START_STOP_UNIT 0x1b
+
+#define CMD_SEND_KEY 0xa3
+#define CMD_REPORT_KEY 0xa4
+#define CMD_READ_DVD_STRUCTURE 0xad
+
+#define copy_key(dest,src) memcpy((dest), (src), sizeof(dvd_key))
+#define copy_chal(dest,src) memcpy((dest), (src), sizeof(dvd_challenge))
+
+/* Define the Cdrom Generic Command structure */
+typedef struct cgc
+ {
+ u_char cdb[12];
+ u_char *buf;
+ int buflen;
+ int rw;
+ int timeout;
+ scsi_user_sense_t *sus;
+ } cgc_t;
+
+static int scsi_cmd(int, cgc_t *);
+static int cdrom_ioctl(int, u_long, void *);
+static int cdrom_tray_move(int, int);
+static void cdrom_count_tracks(int, tracktype *);
+static int dvd_ioctl(int, u_long, void *);
+static int debug = 0;
+
+void dvd_cdrom_debug(int flag)
+ {
+ debug = flag;
+ }
+
+/*
+ * This is the published entry point. Actually applications should simply
+ * include <dvd.h> and not refer to this at all.
+*/
+int dvd_cdrom_ioctl(int fd, unsigned long cmd, void *arg)
+ {
+ switch (cmd)
+ {
+ case DVD_AUTH:
+ case DVD_READ_STRUCT:
+ return(dvd_ioctl(fd, cmd, arg));
+ case CDROMREADTOCHDR:
+ case CDROMREADTOCENTRY:
+ case CDROMEJECT:
+ case CDROMREADRAW:
+ case CDROMREADMODE1:
+ case CDROMREADMODE2:
+ case CDROMCLOSETRAY:
+ case CDROM_DRIVE_STATUS:
+ case CDROM_DISC_STATUS:
+ return(cdrom_ioctl(fd, cmd, arg));
+ default:
+ return(ioctl(fd, cmd, arg));
+ }
+ }
+
+static void setup_report_key(cgc_t *cgc, u_int agid, u_int type)
+ {
+
+ cgc->cdb[0] = CMD_REPORT_KEY;
+ cgc->cdb[10] = type | (agid << 6);
+ switch (type)
+ {
+ case 0:
+ case 5:
+ case 8:
+ cgc->buflen = 8;
+ break;
+ case 1:
+ cgc->buflen = 16;
+ break;
+ case 2:
+ case 4:
+ cgc->buflen = 12;
+ break;
+ }
+ cgc->cdb[9] = cgc->buflen;
+ cgc->rw = SUC_READ;;
+ }
+
+static void setup_send_key(cgc_t *cgc, u_int agid, u_int type)
+ {
+
+ cgc->cdb[0] = CMD_SEND_KEY;
+ cgc->cdb[10] = type | (agid << 6);
+ switch (type)
+ {
+ case 1:
+ cgc->buflen = 16;
+ break;
+ case 3:
+ cgc->buflen = 12;
+ break;
+ case 6:
+ cgc->buflen = 8;
+ break;
+ }
+ cgc->cdb[9] = cgc->buflen;
+ cgc->rw = SUC_WRITE;
+ }
+
+static void cgc_init(cgc_t *cgc, void *buf, int len, int type)
+ {
+
+ memset(cgc, 0, sizeof (*cgc));
+ if (buf)
+ memset(buf, 0, len);
+ cgc->buf = (u_char *)buf;
+ cgc->buflen = len;
+ cgc->rw = type;
+ cgc->timeout = 5; /* 5 second timeout */
+ }
+
+static int dvd_do_auth(int fd, dvd_authinfo *ai)
+ {
+ int ret;
+ u_char buf[20];
+ cgc_t cgc;
+ rpc_state_t rpc_state;
+
+ memset(buf, 0, sizeof(buf));
+ cgc_init(&cgc, buf, 0, SUC_READ);
+
+ switch (ai->type)
+ {
+ case DVD_LU_SEND_AGID: /* LU data send */
+ setup_report_key(&cgc, ai->lsa.agid, 0);
+ if (ret = scsi_cmd(fd, &cgc))
+ return ret;
+ ai->lsa.agid = buf[7] >> 6;
+ break;
+ case DVD_LU_SEND_KEY1:
+ setup_report_key(&cgc, ai->lsk.agid, 2);
+ if (ret = scsi_cmd(fd, &cgc))
+ return ret;
+ copy_key(ai->lsk.key, &buf[4]);
+ break;
+ case DVD_LU_SEND_CHALLENGE:
+ setup_report_key(&cgc, ai->lsc.agid, 1);
+ if (ret = scsi_cmd(fd, &cgc))
+ return ret;
+ copy_chal(ai->lsc.chal, &buf[4]);
+ break;
+ case DVD_LU_SEND_TITLE_KEY: /* Post-auth key */
+ setup_report_key(&cgc, ai->lstk.agid, 4);
+ cgc.cdb[5] = ai->lstk.lba;
+ cgc.cdb[4] = ai->lstk.lba >> 8;
+ cgc.cdb[3] = ai->lstk.lba >> 16;
+ cgc.cdb[2] = ai->lstk.lba >> 24;
+ if (ret = scsi_cmd(fd, &cgc))
+ return ret;
+ ai->lstk.cpm = (buf[4] >> 7) & 1;
+ ai->lstk.cp_sec = (buf[4] >> 6) & 1;
+ ai->lstk.cgms = (buf[4] >> 4) & 3;
+ copy_key(ai->lstk.title_key, &buf[5]);
+ break;
+ case DVD_LU_SEND_ASF:
+ setup_report_key(&cgc, ai->lsasf.agid, 5);
+ if (ret = scsi_cmd(fd, &cgc))
+ return ret;
+ ai->lsasf.asf = buf[7] & 1;
+ break;
+ case DVD_HOST_SEND_CHALLENGE: /* LU data receive (LU changes state) */
+ setup_send_key(&cgc, ai->hsc.agid, 1);
+ buf[1] = 0xe;
+ copy_chal(&buf[4], ai->hsc.chal);
+ if (ret = scsi_cmd(fd, &cgc))
+ return ret;
+ ai->type = DVD_LU_SEND_KEY1;
+ break;
+ case DVD_HOST_SEND_KEY2:
+ setup_send_key(&cgc, ai->hsk.agid, 3);
+ buf[1] = 0xa;
+ copy_key(&buf[4], ai->hsk.key);
+ if (ret = scsi_cmd(fd, &cgc))
+ {
+ ai->type = DVD_AUTH_FAILURE;
+ return ret;
+ }
+ ai->type = DVD_AUTH_ESTABLISHED;
+ break;
+ case DVD_INVALIDATE_AGID:
+ setup_report_key(&cgc, ai->lsa.agid, 0x3f);
+ if (ret = scsi_cmd(fd, &cgc))
+ return ret;
+ break;
+ case DVD_LU_SEND_RPC_STATE: /* Get region settings */
+ setup_report_key(&cgc, 0, 8);
+ memset(&rpc_state, 0, sizeof(rpc_state_t));
+ cgc.buf = (char *) &rpc_state;
+ if (ret = scsi_cmd(fd, &cgc))
+ {
+ ai->lrpcs.type = 0;
+ ai->lrpcs.rpc_scheme = 0;
+ }
+ else
+ {
+ ai->lrpcs.type = rpc_state.type_code;
+ ai->lrpcs.vra = rpc_state.vra;
+ ai->lrpcs.ucca = rpc_state.ucca;
+ ai->lrpcs.region_mask = rpc_state.region_mask;
+ ai->lrpcs.rpc_scheme = rpc_state.rpc_scheme;
+ }
+ break;
+ case DVD_HOST_SEND_RPC_STATE: /* Set region settings */
+ setup_send_key(&cgc, 0, 6);
+ buf[1] = 6;
+ buf[4] = ai->hrpcs.pdrc;
+ if (ret = scsi_cmd(fd, &cgc))
+ return ret;
+ break;
+ default:
+ return EINVAL;
+ }
+ return 0;
+ }
+
+static int dvd_read_physical(int fd, dvd_struct *s)
+ {
+ int ret, i;
+ u_char buf[4 + 4 * 20], *base;
+ struct dvd_layer *layer;
+ cgc_t cgc;
+
+ cgc_init(&cgc, buf, sizeof(buf), SUC_READ);
+ cgc.cdb[0] = CMD_READ_DVD_STRUCTURE;
+ cgc.cdb[6] = s->physical.layer_num;
+ cgc.cdb[7] = s->type;
+ cgc.cdb[9] = cgc.buflen & 0xff;
+
+ if (ret = scsi_cmd(fd, &cgc))
+ return ret;
+
+ base = &buf[4];
+ layer = &s->physical.layer[0];
+
+ /* place the data... really ugly, but at least we won't have to
+ worry about endianess in userspace or here. */
+ for (i = 0; i < 4; ++i, base += 20, ++layer)
+ {
+ memset(layer, 0, sizeof(*layer));
+ layer->book_version = base[0] & 0xf;
+ layer->book_type = base[0] >> 4;
+ layer->min_rate = base[1] & 0xf;
+ layer->disc_size = base[1] >> 4;
+ layer->layer_type = base[2] & 0xf;
+ layer->track_path = (base[2] >> 4) & 1;
+ layer->nlayers = (base[2] >> 5) & 3;
+ layer->track_density = base[3] & 0xf;
+ layer->linear_density = base[3] >> 4;
+ layer->start_sector = base[5] << 16 | base[6] << 8 | base[7];
+ layer->end_sector = base[9] << 16 | base[10] << 8 | base[11];
+ layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15];
+ layer->bca = base[16] >> 7;
+ }
+ return 0;
+ }
+
+static int dvd_read_copyright(int fd, dvd_struct *s)
+ {
+ int ret;
+ u_char buf[8];
+ cgc_t cgc;
+
+ cgc_init(&cgc, buf, sizeof(buf), SUC_READ);
+ cgc.cdb[0] = CMD_READ_DVD_STRUCTURE;
+ cgc.cdb[6] = s->copyright.layer_num;
+ cgc.cdb[7] = s->type;
+ cgc.cdb[8] = cgc.buflen >> 8;
+ cgc.cdb[9] = cgc.buflen & 0xff;
+
+ if (ret = scsi_cmd(fd, &cgc))
+ return ret;
+ s->copyright.cpst = buf[4];
+ s->copyright.rmi = buf[5];
+ return 0;
+ }
+
+static int dvd_read_disckey(int fd, dvd_struct *s)
+ {
+ int ret, size;
+ u_char *buf;
+ cgc_t cgc;
+
+ size = sizeof(s->disckey.value) + 4;
+
+ if ((buf = (u_char *) malloc(size)) == NULL)
+ return ENOMEM;
+
+ cgc_init(&cgc, buf, size, SUC_READ);
+ cgc.cdb[0] = CMD_READ_DVD_STRUCTURE;
+ cgc.cdb[7] = s->type;
+ cgc.cdb[8] = size >> 8;
+ cgc.cdb[9] = size & 0xff;
+ cgc.cdb[10] = s->disckey.agid << 6;
+
+ if (!(ret = scsi_cmd(fd, &cgc)))
+ memcpy(s->disckey.value, &buf[4], sizeof(s->disckey.value));
+ free(buf);
+ return ret;
+ }
+
+static int dvd_read_bca(int fd, dvd_struct *s)
+ {
+ int ret;
+ u_char buf[4 + 188];
+ cgc_t cgc;
+
+ cgc_init(&cgc, buf, sizeof(buf), SUC_READ);
+ cgc.cdb[0] = CMD_READ_DVD_STRUCTURE;
+ cgc.cdb[7] = s->type;
+ cgc.cdb[9] = cgc.buflen = 0xff;
+
+ if (ret = scsi_cmd(fd, &cgc))
+ return ret;
+ s->bca.len = buf[0] << 8 | buf[1];
+ if (s->bca.len < 12 || s->bca.len > 188)
+ return EIO;
+ memcpy(s->bca.value, &buf[4], s->bca.len);
+ return 0;
+ }
+
+static int dvd_read_manufact(int fd, dvd_struct *s)
+ {
+ int ret = 0, size;
+ u_char *buf;
+ cgc_t cgc;
+
+ size = sizeof(s->manufact.value) + 4;
+
+ if ((buf = (u_char *) malloc(size)) == NULL)
+ return ENOMEM;
+
+ cgc_init(&cgc, buf, size, SUC_READ);
+ cgc.cdb[0] = CMD_READ_DVD_STRUCTURE;
+ cgc.cdb[7] = s->type;
+ cgc.cdb[8] = size >> 8;
+ cgc.cdb[9] = size & 0xff;
+
+ if (ret = scsi_cmd(fd, &cgc))
+ {
+ free(buf);
+ return ret;
+ }
+ s->manufact.len = buf[0] << 8 | buf[1];
+ if (s->manufact.len < 0 || s->manufact.len > 2048)
+ ret = -EIO;
+ else
+ memcpy(s->manufact.value, &buf[4], s->manufact.len);
+ free(buf);
+ return ret;
+ }
+
+static int dvd_read_struct(int fd, dvd_struct *s)
+ {
+ switch (s->type)
+ {
+ case DVD_STRUCT_PHYSICAL:
+ return dvd_read_physical(fd, s);
+ case DVD_STRUCT_COPYRIGHT:
+ return dvd_read_copyright(fd, s);
+ case DVD_STRUCT_DISCKEY:
+ return dvd_read_disckey(fd, s);
+ case DVD_STRUCT_BCA:
+ return dvd_read_bca(fd, s);
+ case DVD_STRUCT_MANUFACT:
+ return dvd_read_manufact(fd, s);
+ default:
+ return EINVAL;
+ }
+ }
+
+static u_char scsi_cdblen[8] = {6, 10, 10, 12, 12, 12, 10, 10};
+
+static int scsi_cmd(int fd, cgc_t *cgc)
+ {
+ int i, scsistatus, cdblen;
+ unsigned char *cp;
+ struct scsi_user_cdb suc;
+
+ /* safety checks */
+ if (cgc->rw != SUC_READ && cgc->rw != SUC_WRITE)
+ return(EINVAL);
+
+ suc.suc_flags = cgc->rw;
+ cdblen = scsi_cdblen[(cgc->cdb[0] >> 5) & 7];
+ suc.suc_cdblen = cdblen;
+ bcopy(cgc->cdb, suc.suc_cdb, cdblen);
+ suc.suc_data = cgc->buf;
+ suc.suc_datalen = cgc->buflen;
+ suc.suc_timeout = cgc->timeout;
+ if (ioctl(fd, SCSIRAWCDB, &suc) == -1)
+ return(errno);
+ scsistatus = suc.suc_sus.sus_status;
+
+/*
+ * If the device returns a scsi sense error and debugging is enabled print
+ * some hopefully useful information on stderr.
+*/
+ if (scsistatus && debug)
+ {
+ cp = suc.suc_sus.sus_sense;
+ fprintf(stderr,"scsistatus = %x cdb =",
+ scsistatus);
+ for (i = 0; i < cdblen; i++)
+ fprintf(stderr, " %x", cgc->cdb[i]);
+ fprintf(stderr, "\nsense =");
+ for (i = 0; i < 16; i++)
+ fprintf(stderr, " %x", cp[i]);
+ fprintf(stderr, "\n");
+ }
+ if (cgc->sus)
+ bcopy(&suc.suc_sus, cgc->sus, sizeof (struct scsi_user_sense));
+ if (scsistatus)
+ return(EIO); /* generic i/o error for unsuccessful status */
+ return(0);
+ }
+
+/*
+ * The entry point for the DVDioctls for BSD/OS.
+*/
+static int dvd_ioctl(int fd, u_long cmd, void *arg)
+ {
+ int ret;
+
+ switch (cmd)
+ {
+ case DVD_READ_STRUCT:
+ ret = dvd_read_struct(fd, (dvd_struct *)arg);
+ if (ret)
+ errno = ret;
+ return(ret ? -1 : 0);
+ case DVD_AUTH:
+ ret = dvd_do_auth(fd, (dvd_authinfo *)arg);
+ if (ret)
+ errno = ret;
+ return(ret ? -1 : 0);
+ default:
+ errno = EINVAL;
+ return(-1);
+ }
+ }
+
+/*
+ * The entry point for the CDROMioctls for BSD/OS
+*/
+static int cdrom_read_block(int, cgc_t *, int, int, int, int);
+static int cdrom_read_cd(int, cgc_t *, int, int, int );
+ int cdrom_blocksize(int, int );
+
+static inline
+int msf_to_lba(char m, char s, char f)
+{
+ return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
+}
+
+cdrom_ioctl(int fd, u_long cmd, void *arg)
+ {
+ int ret;
+ cgc_t cgc;
+
+ switch (cmd)
+ {
+ case CDROMREADRAW:
+ case CDROMREADMODE1:
+ case CDROMREADMODE2:
+ {
+ struct cdrom_msf *msf;
+ int blocksize = 0, format = 0, lba;
+
+ switch (cmd)
+ {
+ case CDROMREADRAW:
+ blocksize = CD_FRAMESIZE_RAW;
+ break;
+ case CDROMREADMODE1:
+ blocksize = CD_FRAMESIZE;
+ format = 2;
+ break;
+ case CDROMREADMODE2:
+ blocksize = CD_FRAMESIZE_RAW0;
+ break;
+ }
+ msf = (struct cdrom_msf *)arg;
+ lba = msf_to_lba(msf->cdmsf_min0,msf->cdmsf_sec0,
+ msf->cdmsf_frame0);
+ ret = EINVAL;
+ if (lba < 0)
+ break;
+
+ cgc_init(&cgc, arg, blocksize, SUC_READ);
+ ret = cdrom_read_block(fd, &cgc, lba, 1, format, blocksize);
+ if (ret)
+ {
+/*
+ * SCSI-II devices are not required to support CMD_READ_CD (which specifies
+ * the blocksize to read) so try switching the block size with a mode select,
+ * doing the normal read sector command and then changing the sector size back
+ * to 2048.
+ *
+ * If the program dies before changing the blocksize back sdopen()
+ * in the kernel will fail opens with a message that looks something like:
+ *
+ * "sr1: blksize 2336 not multiple of 512: cannot use"
+ *
+ * At that point the drive has to be power cycled (or reset in some other way).
+*/
+ if (ret = cdrom_blocksize(fd, blocksize))
+ break;
+ ret = cdrom_read_cd(fd, &cgc, lba, blocksize, 1);
+ ret |= cdrom_blocksize(fd, 2048);
+ }
+ break;
+ }
+ case CDROMREADTOCHDR:
+ {
+ struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg;
+ u_char buffer[12];
+
+ cgc_init(&cgc, buffer, sizeof (buffer), SUC_READ);
+ cgc.cdb[0] = CMD_READ_TOC_PMA_ATIP;
+ cgc.cdb[1] = 0x2; /* MSF */
+ cgc.cdb[8] = 12; /* LSB of length */
+
+ ret = scsi_cmd(fd, &cgc);
+ if (!ret)
+ {
+ tochdr->cdth_trk0 = buffer[2];
+ tochdr->cdth_trk1 = buffer[3];
+ }
+ break;
+ }
+ case CDROMREADTOCENTRY:
+ {
+ struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg;
+ u_char buffer[12];
+
+ cgc_init(&cgc, buffer, sizeof (buffer), SUC_READ);
+ cgc.cdb[0] = CMD_READ_TOC_PMA_ATIP;
+ cgc.cdb[1] = (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0;
+ cgc.cdb[6] = tocentry->cdte_track;
+ cgc.cdb[8] = 12; /* LSB of length */
+
+ ret = scsi_cmd(fd, &cgc);
+ if (ret)
+ break;
+
+ tocentry->cdte_ctrl = buffer[5] & 0xf;
+ tocentry->cdte_adr = buffer[5] >> 4;
+ tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04) ? 1 : 0;
+ if (tocentry->cdte_format == CDROM_MSF)
+ {
+ tocentry->cdte_addr.msf.minute = buffer[9];
+ tocentry->cdte_addr.msf.second = buffer[10];
+ tocentry->cdte_addr.msf.frame = buffer[11];
+ }
+ else
+ tocentry->cdte_addr.lba = (((((buffer[8] << 8)
+ + buffer[9]) << 8)
+ + buffer[10]) << 8)
+ + buffer[11];
+ break;
+ }
+ case CDROMEJECT: /* NO-OP for now */
+ ret = cdrom_tray_move(fd, 1);
+ break;
+ case CDROMCLOSETRAY:
+ ret = cdrom_tray_move(fd, 0);
+ break;
+/*
+ * This sucks but emulates the expected behaviour. Instead of the return
+ * value being the actual status a success/fail indicator should have been
+ * returned and the 3rd arg to the ioctl should have been an 'int *' to update
+ * with the actual status. Both the drive and disc status ioctl calls are
+ * similarily braindamaged.
+*/
+ case CDROM_DRIVE_STATUS:
+ return(CDS_NO_INFO); /* XXX */
+ case CDROM_DISC_STATUS:
+ {
+ tracktype tracks;
+ int cnt;
+
+ cdrom_count_tracks(fd, &tracks);
+ if (tracks.error)
+ return(tracks.error);
+ if (tracks.audio > 0)
+ {
+ cnt = tracks.data + tracks.cdi + tracks.xa;
+ if (cnt == 0)
+ return(CDS_AUDIO);
+ else
+ return(CDS_MIXED);
+ }
+ if (tracks.cdi)
+ return(CDS_XA_2_2);
+ if (tracks.xa)
+ return(CDS_XA_2_1);
+ if (tracks.data)
+ return(CDS_DATA_1);
+ return(CDS_NO_INFO);
+ }
+ }
+ errno = ret;
+ return(ret ? -1 : 0);
+ }
+
+static int cdrom_read_cd(int fd, cgc_t *cgc, int lba, int blocksize, int nblocks)
+ {
+
+ memset(&cgc->cdb, 0, sizeof(cgc->cdb));
+ cgc->cdb[0] = CMD_READ_10;
+ cgc->cdb[2] = (lba >> 24) & 0xff;
+ cgc->cdb[3] = (lba >> 16) & 0xff;
+ cgc->cdb[4] = (lba >> 8) & 0xff;
+ cgc->cdb[5] = lba & 0xff;
+ cgc->cdb[6] = (nblocks >> 16) & 0xff;
+ cgc->cdb[7] = (nblocks >> 8) & 0xff;
+ cgc->cdb[8] = nblocks & 0xff;
+ cgc->buflen = blocksize * nblocks;
+ return(scsi_cmd(fd, cgc));
+ }
+
+static int cdrom_read_block(int fd, cgc_t *cgc,
+ int lba, int nblocks, int format, int blksize)
+ {
+
+ memset(&cgc->cdb, 0, sizeof(cgc->cdb));
+ cgc->cdb[0] = CMD_READ_CD;
+ /* expected sector size - cdda,mode1,etc. */
+ cgc->cdb[1] = format << 2;
+ /* starting address */
+ cgc->cdb[2] = (lba >> 24) & 0xff;
+ cgc->cdb[3] = (lba >> 16) & 0xff;
+ cgc->cdb[4] = (lba >> 8) & 0xff;
+ cgc->cdb[5] = lba & 0xff;
+ /* number of blocks */
+ cgc->cdb[6] = (nblocks >> 16) & 0xff;
+ cgc->cdb[7] = (nblocks >> 8) & 0xff;
+ cgc->cdb[8] = nblocks & 0xff;
+ cgc->buflen = blksize * nblocks;
+
+ /* set the header info returned */
+ switch (blksize)
+ {
+ case CD_FRAMESIZE_RAW0:
+ cgc->cdb[9] = 0x58;
+ break;
+ case CD_FRAMESIZE_RAW1:
+ cgc->cdb[9] = 0x78;
+ break;
+ case CD_FRAMESIZE_RAW:
+ cgc->cdb[9] = 0xf8;
+ break;
+ default:
+ cgc->cdb[9] = 0x10;
+ }
+ return(scsi_cmd(fd, cgc));
+ }
+
+static void cdrom_count_tracks(int fd, tracktype *tracks)
+ {
+ struct cdrom_tochdr header;
+ struct cdrom_tocentry entry;
+ int ret, i;
+
+ memset(tracks, 0, sizeof (*tracks));
+ ret = cdrom_ioctl(fd, CDROMREADTOCHDR, &header);
+/*
+ * This whole business is a crock anyhow so we don't bother distinguishing
+ * between no media, drive not ready, etc and on any error just say we have
+ * no info.
+*/
+ if (ret)
+ {
+ tracks->error = CDS_NO_INFO;
+ return;
+ }
+
+ entry.cdte_format = CDROM_MSF;
+ for (i = header.cdth_trk0; i <= header.cdth_trk1; i++)
+ {
+ entry.cdte_track = i;
+ if (cdrom_ioctl(fd, CDROMREADTOCENTRY, &entry))
+ {
+ tracks->error = CDS_NO_INFO;
+ return;
+ }
+ if (entry.cdte_ctrl & CDROM_DATA_TRACK)
+ {
+ if (entry.cdte_format == 0x10)
+ tracks->cdi++;
+ else if (entry.cdte_format == 0x20)
+ tracks->xa++;
+ else
+ tracks->data++;
+ }
+ else
+ tracks->audio++;
+ }
+ return;
+ }
+
+static int cdrom_tray_move(int fd, int flag)
+ {
+ cgc_t cgc;
+
+ cgc_init(&cgc, NULL, 0, SUC_READ);
+ cgc.cdb[0] = CMD_START_STOP_UNIT;
+ cgc.cdb[1] = 1; /* immediate */
+ cgc.cdb[4] = flag ? 0x2 : 0x3; /* eject : close */
+ return(scsi_cmd(fd, &cgc));
+ }
+
+/*
+ * Required when we need to use READ_10 to issue other than 2048 block
+ * reads
+ */
+int cdrom_blocksize(int fd, int size)
+ {
+ cgc_t cgc;
+ struct modesel_head mh;
+
+ memset(&mh, 0, sizeof(mh));
+ mh.block_desc_length = 0x08;
+ mh.block_length_med = (size >> 8) & 0xff;
+ mh.block_length_lo = size & 0xff;
+
+ memset(&cgc, 0, sizeof(cgc));
+ cgc.cdb[0] = 0x15;
+ cgc.cdb[1] = 1 << 4;
+ cgc.cdb[4] = 12;
+ cgc.buflen = sizeof(mh);
+ cgc.buf = (u_char *) &mh;
+ cgc.rw = SUC_WRITE;
+ mh.block_desc_length = 0x08;
+ mh.block_length_med = (size >> 8) & 0xff;
+ mh.block_length_lo = size & 0xff;
+ return(scsi_cmd(fd, &cgc));
+ }
diff --git a/lib/libdvd/libdvdcss/src/common.h b/lib/libdvd/libdvdcss/src/common.h
new file mode 100644
index 0000000000..aff5ccbaa7
--- /dev/null
+++ b/lib/libdvd/libdvdcss/src/common.h
@@ -0,0 +1,81 @@
+/*****************************************************************************
+ * common.h: common definitions
+ * Collection of useful common types and macros definitions
+ *****************************************************************************
+ * Copyright (C) 1998, 1999, 2000 VideoLAN
+ * $Id$
+ *
+ * Authors: Sam Hocevar <sam@via.ecp.fr>
+ * Vincent Seguin <seguin@via.ecp.fr>
+ * Gildas Bazin <gbazin@netcourrier.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Basic types definitions
+ *****************************************************************************/
+#if defined( HAVE_STDINT_H )
+# include <stdint.h>
+#elif defined( HAVE_INTTYPES_H )
+# include <inttypes.h>
+#elif defined( SYS_CYGWIN )
+# include <sys/types.h>
+ /* Cygwin only defines half of these... */
+ typedef u_int8_t uint8_t;
+ typedef u_int32_t uint32_t;
+#else
+ /* Fallback types (very x86-centric, sorry) */
+ typedef unsigned char uint8_t;
+ typedef signed char int8_t;
+ typedef unsigned int uint32_t;
+ typedef signed int int32_t;
+#endif
+
+#if defined( WIN32 )
+
+# ifndef PATH_MAX
+# define PATH_MAX MAX_PATH
+# endif
+
+/* several type definitions */
+# if defined( __MINGW32__ )
+# define lseek _lseeki64
+# if !defined( _OFF_T_ )
+typedef long long _off_t;
+typedef _off_t off_t;
+# define _OFF_T_
+# else
+# define off_t long long
+# endif
+# endif
+
+# if defined( _MSC_VER )
+# define lseek _lseeki64
+# if !defined( _OFF_T_DEFINED )
+typedef __int64 off_t;
+# define _OFF_T_DEFINED
+# else
+# define off_t __int64
+# endif
+# define stat _stati64
+# endif
+
+# ifndef snprintf
+# define snprintf _snprintf /* snprintf not defined in mingw32 (bug?) */
+# endif
+
+#endif
+
diff --git a/lib/libdvd/libdvdcss/src/css.c b/lib/libdvd/libdvdcss/src/css.c
new file mode 100644
index 0000000000..4e24bbf68f
--- /dev/null
+++ b/lib/libdvd/libdvdcss/src/css.c
@@ -0,0 +1,1696 @@
+/*****************************************************************************
+ * css.c: Functions for DVD authentication and descrambling
+ *****************************************************************************
+ * Copyright (C) 1999-2008 VideoLAN
+ * $Id$
+ *
+ * Authors: Stéphane Borel <stef@via.ecp.fr>
+ * HÃ¥kan Hjort <d95hjort@dtek.chalmers.se>
+ *
+ * based on:
+ * - css-auth by Derek Fawcus <derek@spider.com>
+ * - DVD CSS ioctls example program by Andrew T. Veliath <andrewtv@usa.net>
+ * - The Divide and conquer attack by Frank A. Stevenson <frank@funcom.com>
+ * (see http://www-2.cs.cmu.edu/~dst/DeCSS/FrankStevenson/index.html)
+ * - DeCSSPlus by Ethan Hawke
+ * - DecVOB
+ * see http://www.lemuria.org/DeCSS/ by Tom Vogt for more information.
+ *
+ * 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
+ *****************************************************************************/
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <fcntl.h>
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#include "dvdcss/dvdcss.h"
+
+#include "common.h"
+#include "css.h"
+#include "libdvdcss.h"
+#include "csstables.h"
+#include "ioctl.h"
+#include "device.h"
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static void PrintKey ( dvdcss_t, char *, uint8_t const * );
+
+static int GetBusKey ( dvdcss_t );
+static int GetASF ( dvdcss_t );
+
+static void CryptKey ( int, int, uint8_t const *, uint8_t * );
+static void DecryptKey ( uint8_t,
+ uint8_t const *, uint8_t const *, uint8_t * );
+
+static int DecryptDiscKey ( dvdcss_t, uint8_t const *, dvd_key_t );
+static int CrackDiscKey ( dvdcss_t, uint8_t * );
+
+static void DecryptTitleKey ( dvd_key_t, dvd_key_t );
+static int RecoverTitleKey ( int, uint8_t const *,
+ uint8_t const *, uint8_t const *, uint8_t * );
+static int CrackTitleKey ( dvdcss_t, int, int, dvd_key_t );
+
+static int AttackPattern ( uint8_t const[], int, uint8_t * );
+#if 0
+static int AttackPadding ( uint8_t const[], int, uint8_t * );
+#endif
+
+/*****************************************************************************
+ * _dvdcss_test: check if the disc is encrypted or not
+ *****************************************************************************/
+int _dvdcss_test( dvdcss_t dvdcss )
+{
+ int i_ret, i_copyright;
+
+ i_ret = ioctl_ReadCopyright( dvdcss->i_fd, 0 /* i_layer */, &i_copyright );
+
+#ifdef WIN32
+ if( i_ret < 0 )
+ {
+ /* Maybe we didn't have enough privileges to read the copyright
+ * (see ioctl_ReadCopyright comments).
+ * Apparently, on unencrypted DVDs _dvdcss_disckey() always fails, so
+ * we can check this as a workaround. */
+ i_ret = 0;
+ i_copyright = 1;
+ if( _dvdcss_disckey( dvdcss ) < 0 )
+ {
+ i_copyright = 0;
+ }
+ }
+#endif
+
+ if( i_ret < 0 )
+ {
+ /* Since it's the first ioctl we try to issue, we add a notice */
+ print_error( dvdcss, "css error: ioctl_ReadCopyright failed, "
+ "make sure there is a DVD in the drive, and that "
+ "you have used the correct device node." );
+
+ return i_ret;
+ }
+
+ return i_copyright;
+}
+
+/*****************************************************************************
+ * _dvdcss_title: crack or decrypt the current title key if needed
+ *****************************************************************************
+ * This function should only be called by dvdcss->pf_seek and should eventually
+ * not be external if possible.
+ *****************************************************************************/
+int _dvdcss_title ( dvdcss_t dvdcss, int i_block )
+{
+ dvd_title_t *p_title;
+ dvd_title_t *p_newtitle;
+ dvd_key_t p_title_key;
+ int i_fd, i_ret = -1, b_cache = 0;
+
+ if( ! dvdcss->b_scrambled )
+ {
+ return 0;
+ }
+
+ /* Check if we've already cracked this key */
+ p_title = dvdcss->p_titles;
+ while( p_title != NULL
+ && p_title->p_next != NULL
+ && p_title->p_next->i_startlb <= i_block )
+ {
+ p_title = p_title->p_next;
+ }
+
+ if( p_title != NULL
+ && p_title->i_startlb == i_block )
+ {
+ /* We've already cracked this key, nothing to do */
+ memcpy( dvdcss->css.p_title_key, p_title->p_key, sizeof(dvd_key_t) );
+ return 0;
+ }
+
+ /* Check whether the key is in our disk cache */
+ if( dvdcss->psz_cachefile[0] )
+ {
+ /* XXX: be careful, we use sprintf and not snprintf */
+ sprintf( dvdcss->psz_block, "%.10x", i_block );
+ i_fd = open( dvdcss->psz_cachefile, O_RDONLY );
+ b_cache = 1;
+
+ if( i_fd >= 0 )
+ {
+ char psz_key[KEY_SIZE * 3];
+ unsigned int k0, k1, k2, k3, k4;
+
+ psz_key[KEY_SIZE * 3 - 1] = '\0';
+
+ if( read( i_fd, psz_key, KEY_SIZE * 3 - 1 ) == KEY_SIZE * 3 - 1
+ && sscanf( psz_key, "%x:%x:%x:%x:%x",
+ &k0, &k1, &k2, &k3, &k4 ) == 5 )
+ {
+ p_title_key[0] = k0;
+ p_title_key[1] = k1;
+ p_title_key[2] = k2;
+ p_title_key[3] = k3;
+ p_title_key[4] = k4;
+ PrintKey( dvdcss, "title key found in cache ", p_title_key );
+
+ /* Don't try to save it again */
+ b_cache = 0;
+ i_ret = 1;
+ }
+
+ close( i_fd );
+ }
+ }
+
+ /* Crack or decrypt CSS title key for current VTS */
+ if( i_ret < 0 )
+ {
+ i_ret = _dvdcss_titlekey( dvdcss, i_block, p_title_key );
+
+ if( i_ret < 0 )
+ {
+ print_error( dvdcss, "fatal error in vts css key" );
+ return i_ret;
+ }
+
+ if( i_ret == 0 )
+ {
+ print_debug( dvdcss, "unencrypted title" );
+ /* We cache this anyway, so we don't need to check again. */
+ }
+ }
+
+ /* Key is valid, we store it on disk. */
+ if( dvdcss->psz_cachefile[0] && b_cache )
+ {
+ i_fd = open( dvdcss->psz_cachefile, O_RDWR|O_CREAT, 0644 );
+ if( i_fd >= 0 )
+ {
+ char psz_key[KEY_SIZE * 3 + 2];
+
+ sprintf( psz_key, "%02x:%02x:%02x:%02x:%02x\r\n",
+ p_title_key[0], p_title_key[1], p_title_key[2],
+ p_title_key[3], p_title_key[4] );
+
+ write( i_fd, psz_key, KEY_SIZE * 3 + 1 );
+ close( i_fd );
+ }
+ }
+
+ /* Find our spot in the list */
+ p_newtitle = NULL;
+ p_title = dvdcss->p_titles;
+ while( ( p_title != NULL ) && ( p_title->i_startlb < i_block ) )
+ {
+ p_newtitle = p_title;
+ p_title = p_title->p_next;
+ }
+
+ /* Save the found title */
+ p_title = p_newtitle;
+
+ /* Write in the new title and its key */
+ p_newtitle = malloc( sizeof( dvd_title_t ) );
+ p_newtitle->i_startlb = i_block;
+ memcpy( p_newtitle->p_key, p_title_key, KEY_SIZE );
+
+ /* Link it at the head of the (possibly empty) list */
+ if( p_title == NULL )
+ {
+ p_newtitle->p_next = dvdcss->p_titles;
+ dvdcss->p_titles = p_newtitle;
+ }
+ /* Link the new title inside the list */
+ else
+ {
+ p_newtitle->p_next = p_title->p_next;
+ p_title->p_next = p_newtitle;
+ }
+
+ memcpy( dvdcss->css.p_title_key, p_title_key, KEY_SIZE );
+ return 0;
+}
+
+/*****************************************************************************
+ * _dvdcss_disckey: get disc key.
+ *****************************************************************************
+ * This function should only be called if DVD ioctls are present.
+ * It will set dvdcss->i_method = DVDCSS_METHOD_TITLE if it fails to find
+ * a valid disc key.
+ * Two decryption methods are offered:
+ * -disc key hash crack,
+ * -decryption with player keys if they are available.
+ *****************************************************************************/
+int _dvdcss_disckey( dvdcss_t dvdcss )
+{
+ unsigned char p_buffer[ DVD_DISCKEY_SIZE ];
+ dvd_key_t p_disc_key;
+ int i;
+
+ if( GetBusKey( dvdcss ) < 0 )
+ {
+ return -1;
+ }
+
+ /* Get encrypted disc key */
+ if( ioctl_ReadDiscKey( dvdcss->i_fd, &dvdcss->css.i_agid, p_buffer ) < 0 )
+ {
+ print_error( dvdcss, "ioctl ReadDiscKey failed" );
+ return -1;
+ }
+
+ /* This should have invaidated the AGID and got us ASF=1. */
+ if( GetASF( dvdcss ) != 1 )
+ {
+ /* Region mismatch (or region not set) is the most likely source. */
+ print_error( dvdcss,
+ "ASF not 1 after reading disc key (region mismatch?)" );
+ ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
+ return -1;
+ }
+
+ /* Shuffle disc key using bus key */
+ for( i = 0 ; i < DVD_DISCKEY_SIZE ; i++ )
+ {
+ p_buffer[ i ] ^= dvdcss->css.p_bus_key[ 4 - (i % KEY_SIZE) ];
+ }
+
+ /* Decrypt disc key */
+ switch( dvdcss->i_method )
+ {
+ case DVDCSS_METHOD_KEY:
+
+ /* Decrypt disc key with player key. */
+ PrintKey( dvdcss, "decrypting disc key ", p_buffer );
+ if( ! DecryptDiscKey( dvdcss, p_buffer, p_disc_key ) )
+ {
+ PrintKey( dvdcss, "decrypted disc key is ", p_disc_key );
+ break;
+ }
+ print_debug( dvdcss, "failed to decrypt the disc key, "
+ "faulty drive/kernel? "
+ "cracking title keys instead" );
+
+ /* Fallback, but not to DISC as the disc key might be faulty */
+ memset( p_disc_key, 0, KEY_SIZE );
+ dvdcss->i_method = DVDCSS_METHOD_TITLE;
+ break;
+
+ case DVDCSS_METHOD_DISC:
+
+ /* Crack Disc key to be able to use it */
+ memcpy( p_disc_key, p_buffer, KEY_SIZE );
+ PrintKey( dvdcss, "cracking disc key ", p_disc_key );
+ if( ! CrackDiscKey( dvdcss, p_disc_key ) )
+ {
+ PrintKey( dvdcss, "cracked disc key is ", p_disc_key );
+ break;
+ }
+ print_debug( dvdcss, "failed to crack the disc key" );
+ memset( p_disc_key, 0, KEY_SIZE );
+ dvdcss->i_method = DVDCSS_METHOD_TITLE;
+ break;
+
+ default:
+
+ print_debug( dvdcss, "disc key needs not be decrypted" );
+ memset( p_disc_key, 0, KEY_SIZE );
+ break;
+ }
+
+ memcpy( dvdcss->css.p_disc_key, p_disc_key, KEY_SIZE );
+
+ return 0;
+}
+
+
+/*****************************************************************************
+ * _dvdcss_titlekey: get title key.
+ *****************************************************************************/
+int _dvdcss_titlekey( dvdcss_t dvdcss, int i_pos, dvd_key_t p_title_key )
+{
+ static uint8_t p_garbage[ DVDCSS_BLOCK_SIZE ]; /* we never read it back */
+ uint8_t p_key[ KEY_SIZE ];
+ int i, i_ret = 0;
+
+ if( dvdcss->b_ioctls && ( dvdcss->i_method == DVDCSS_METHOD_KEY ||
+ dvdcss->i_method == DVDCSS_METHOD_DISC ) )
+ {
+ /* We have a decrypted Disc key and the ioctls are available,
+ * read the title key and decrypt it.
+ */
+
+ print_debug( dvdcss, "getting title key at block %i the classic way",
+ i_pos );
+
+ /* We need to authenticate again every time to get a new session key */
+ if( GetBusKey( dvdcss ) < 0 )
+ {
+ return -1;
+ }
+
+ /* Get encrypted title key */
+ if( ioctl_ReadTitleKey( dvdcss->i_fd, &dvdcss->css.i_agid,
+ i_pos, p_key ) < 0 )
+ {
+ print_debug( dvdcss,
+ "ioctl ReadTitleKey failed (region mismatch?)" );
+ i_ret = -1;
+ }
+
+ /* Test ASF, it will be reset to 0 if we got a Region error */
+ switch( GetASF( dvdcss ) )
+ {
+ case -1:
+ /* An error getting the ASF status, something must be wrong. */
+ print_debug( dvdcss, "lost ASF requesting title key" );
+ ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
+ i_ret = -1;
+ break;
+
+ case 0:
+ /* This might either be a title that has no key,
+ * or we encountered a region error. */
+ print_debug( dvdcss, "lost ASF requesting title key" );
+ break;
+
+ case 1:
+ /* Drive status is ok. */
+ /* If the title key request failed, but we did not loose ASF,
+ * we might stil have the AGID. Other code assume that we
+ * will not after this so invalidate it(?). */
+ if( i_ret < 0 )
+ {
+ ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
+ }
+ break;
+ }
+
+ if( !( i_ret < 0 ) )
+ {
+ /* Decrypt title key using the bus key */
+ for( i = 0 ; i < KEY_SIZE ; i++ )
+ {
+ p_key[ i ] ^= dvdcss->css.p_bus_key[ 4 - (i % KEY_SIZE) ];
+ }
+
+ /* If p_key is all zero then there really wasn't any key present
+ * even though we got to read it without an error. */
+ if( !( p_key[0] | p_key[1] | p_key[2] | p_key[3] | p_key[4] ) )
+ {
+ i_ret = 0;
+ }
+ else
+ {
+ PrintKey( dvdcss, "initial disc key ", dvdcss->css.p_disc_key );
+ DecryptTitleKey( dvdcss->css.p_disc_key, p_key );
+ PrintKey( dvdcss, "decrypted title key ", p_key );
+ i_ret = 1;
+ }
+
+ /* All went well either there wasn't a key or we have it now. */
+ memcpy( p_title_key, p_key, KEY_SIZE );
+ PrintKey( dvdcss, "title key is ", p_title_key );
+
+ return i_ret;
+ }
+
+ /* The title key request failed */
+ print_debug( dvdcss, "resetting drive and cracking title key" );
+
+ /* Read an unscrambled sector and reset the drive */
+ dvdcss->pf_seek( dvdcss, 0 );
+ dvdcss->pf_read( dvdcss, p_garbage, 1 );
+ dvdcss->pf_seek( dvdcss, 0 );
+ _dvdcss_disckey( dvdcss );
+
+ /* Fallback */
+ }
+
+ /* METHOD is TITLE, we can't use the ioctls or requesting the title key
+ * failed above. For these cases we try to crack the key instead. */
+
+ /* For now, the read limit is 9Gb / 2048 = 4718592 sectors. */
+ i_ret = CrackTitleKey( dvdcss, i_pos, 4718592, p_key );
+
+ memcpy( p_title_key, p_key, KEY_SIZE );
+ PrintKey( dvdcss, "title key is ", p_title_key );
+
+ return i_ret;
+}
+
+/*****************************************************************************
+ * _dvdcss_unscramble: does the actual descrambling of data
+ *****************************************************************************
+ * sec : sector to unscramble
+ * key : title key for this sector
+ *****************************************************************************/
+int _dvdcss_unscramble( dvd_key_t p_key, uint8_t *p_sec )
+{
+ unsigned int i_t1, i_t2, i_t3, i_t4, i_t5, i_t6;
+ uint8_t *p_end = p_sec + DVDCSS_BLOCK_SIZE;
+
+ /* PES_scrambling_control */
+ if( !(p_sec[0x14] & 0x30) )
+ {
+ return 0;
+ }
+
+ i_t1 = (p_key[0] ^ p_sec[0x54]) | 0x100;
+ i_t2 = p_key[1] ^ p_sec[0x55];
+ i_t3 = (p_key[2] | (p_key[3] << 8) |
+ (p_key[4] << 16)) ^ (p_sec[0x56] |
+ (p_sec[0x57] << 8) | (p_sec[0x58] << 16));
+ i_t4 = i_t3 & 7;
+ i_t3 = i_t3 * 2 + 8 - i_t4;
+ p_sec += 0x80;
+ i_t5 = 0;
+
+ while( p_sec != p_end )
+ {
+ i_t4 = p_css_tab2[i_t2] ^ p_css_tab3[i_t1];
+ i_t2 = i_t1>>1;
+ i_t1 = ( ( i_t1 & 1 ) << 8 ) ^ i_t4;
+ i_t4 = p_css_tab5[i_t4];
+ i_t6 = ((((((( i_t3 >> 3 ) ^ i_t3 ) >> 1 ) ^
+ i_t3 ) >> 8 ) ^ i_t3 ) >> 5 ) & 0xff;
+ i_t3 = (i_t3 << 8 ) | i_t6;
+ i_t6 = p_css_tab4[i_t6];
+ i_t5 += i_t6 + i_t4;
+ *p_sec = p_css_tab1[*p_sec] ^ ( i_t5 & 0xff );
+ p_sec++;
+ i_t5 >>= 8;
+ }
+
+ return 0;
+}
+
+/* Following functions are local */
+
+/*****************************************************************************
+ * GetBusKey : Go through the CSS Authentication process
+ *****************************************************************************
+ * It simulates the mutual authentication between logical unit and host,
+ * and stops when a session key (called bus key) has been established.
+ * Always do the full auth sequence. Some drives seem to lie and always
+ * respond with ASF=1. For instance the old DVD roms on Compaq Armada says
+ * that ASF=1 from the start and then later fail with a 'read of scrambled
+ * block without authentication' error.
+ *****************************************************************************/
+static int GetBusKey( dvdcss_t dvdcss )
+{
+ uint8_t p_buffer[10];
+ uint8_t p_challenge[2*KEY_SIZE];
+ dvd_key_t p_key1;
+ dvd_key_t p_key2;
+ dvd_key_t p_key_check;
+ uint8_t i_variant = 0;
+ int i_ret = -1;
+ int i;
+
+ print_debug( dvdcss, "requesting AGID" );
+ i_ret = ioctl_ReportAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
+
+ /* We might have to reset hung authentication processes in the drive
+ * by invalidating the corresponding AGID'. As long as we haven't got
+ * an AGID, invalidate one (in sequence) and try again. */
+ for( i = 0; i_ret == -1 && i < 4 ; ++i )
+ {
+ print_debug( dvdcss, "ioctl ReportAgid failed, "
+ "invalidating AGID %d", i );
+
+ /* This is really _not good_, should be handled by the OS.
+ * Invalidating an AGID could make another process fail somewhere
+ * in its authentication process. */
+ dvdcss->css.i_agid = i;
+ ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
+
+ print_debug( dvdcss, "requesting AGID" );
+ i_ret = ioctl_ReportAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
+ }
+
+ /* Unable to authenticate without AGID */
+ if( i_ret == -1 )
+ {
+ print_error( dvdcss, "ioctl ReportAgid failed, fatal" );
+ return -1;
+ }
+
+ /* Setup a challenge, any values should work */
+ for( i = 0 ; i < 10; ++i )
+ {
+ p_challenge[i] = i;
+ }
+
+ /* Get challenge from host */
+ for( i = 0 ; i < 10 ; ++i )
+ {
+ p_buffer[9-i] = p_challenge[i];
+ }
+
+ /* Send challenge to LU */
+ if( ioctl_SendChallenge( dvdcss->i_fd,
+ &dvdcss->css.i_agid, p_buffer ) < 0 )
+ {
+ print_error( dvdcss, "ioctl SendChallenge failed" );
+ ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
+ return -1;
+ }
+
+ /* Get key1 from LU */
+ if( ioctl_ReportKey1( dvdcss->i_fd, &dvdcss->css.i_agid, p_buffer ) < 0)
+ {
+ print_error( dvdcss, "ioctl ReportKey1 failed" );
+ ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
+ return -1;
+ }
+
+ /* Send key1 to host */
+ for( i = 0 ; i < KEY_SIZE ; i++ )
+ {
+ p_key1[i] = p_buffer[4-i];
+ }
+
+ for( i = 0 ; i < 32 ; ++i )
+ {
+ CryptKey( 0, i, p_challenge, p_key_check );
+
+ if( memcmp( p_key_check, p_key1, KEY_SIZE ) == 0 )
+ {
+ print_debug( dvdcss, "drive authenticated, using variant %d", i );
+ i_variant = i;
+ break;
+ }
+ }
+
+ if( i == 32 )
+ {
+ print_error( dvdcss, "drive would not authenticate" );
+ ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
+ return -1;
+ }
+
+ /* Get challenge from LU */
+ if( ioctl_ReportChallenge( dvdcss->i_fd,
+ &dvdcss->css.i_agid, p_buffer ) < 0 )
+ {
+ print_error( dvdcss, "ioctl ReportKeyChallenge failed" );
+ ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
+ return -1;
+ }
+
+ /* Send challenge to host */
+ for( i = 0 ; i < 10 ; ++i )
+ {
+ p_challenge[i] = p_buffer[9-i];
+ }
+
+ CryptKey( 1, i_variant, p_challenge, p_key2 );
+
+ /* Get key2 from host */
+ for( i = 0 ; i < KEY_SIZE ; ++i )
+ {
+ p_buffer[4-i] = p_key2[i];
+ }
+
+ /* Send key2 to LU */
+ if( ioctl_SendKey2( dvdcss->i_fd, &dvdcss->css.i_agid, p_buffer ) < 0 )
+ {
+ print_error( dvdcss, "ioctl SendKey2 failed" );
+ ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
+ return -1;
+ }
+
+ /* The drive has accepted us as authentic. */
+ print_debug( dvdcss, "authentication established" );
+
+ memcpy( p_challenge, p_key1, KEY_SIZE );
+ memcpy( p_challenge + KEY_SIZE, p_key2, KEY_SIZE );
+
+ CryptKey( 2, i_variant, p_challenge, dvdcss->css.p_bus_key );
+
+ return 0;
+}
+
+/*****************************************************************************
+ * PrintKey : debug function that dumps a key value
+ *****************************************************************************/
+static void PrintKey( dvdcss_t dvdcss, char *prefix, uint8_t const *data )
+{
+ print_debug( dvdcss, "%s%02x:%02x:%02x:%02x:%02x", prefix,
+ data[0], data[1], data[2], data[3], data[4] );
+}
+
+/*****************************************************************************
+ * GetASF : Get Authentication success flag
+ *****************************************************************************
+ * Returns :
+ * -1 on ioctl error,
+ * 0 if the device needs to be authenticated,
+ * 1 either.
+ *****************************************************************************/
+static int GetASF( dvdcss_t dvdcss )
+{
+ int i_asf = 0;
+
+ if( ioctl_ReportASF( dvdcss->i_fd, NULL, &i_asf ) != 0 )
+ {
+ /* The ioctl process has failed */
+ print_error( dvdcss, "GetASF fatal error" );
+ return -1;
+ }
+
+ if( i_asf )
+ {
+ print_debug( dvdcss, "GetASF authenticated, ASF=1" );
+ }
+ else
+ {
+ print_debug( dvdcss, "GetASF not authenticated, ASF=0" );
+ }
+
+ return i_asf;
+}
+
+/*****************************************************************************
+ * CryptKey : shuffles bits and unencrypt keys.
+ *****************************************************************************
+ * Used during authentication and disc key negociation in GetBusKey.
+ * i_key_type : 0->key1, 1->key2, 2->buskey.
+ * i_variant : between 0 and 31.
+ *****************************************************************************/
+static void CryptKey( int i_key_type, int i_variant,
+ uint8_t const *p_challenge, uint8_t *p_key )
+{
+ /* Permutation table for challenge */
+ uint8_t pp_perm_challenge[3][10] =
+ { { 1, 3, 0, 7, 5, 2, 9, 6, 4, 8 },
+ { 6, 1, 9, 3, 8, 5, 7, 4, 0, 2 },
+ { 4, 0, 3, 5, 7, 2, 8, 6, 1, 9 } };
+
+ /* Permutation table for variant table for key2 and buskey */
+ uint8_t pp_perm_variant[2][32] =
+ { { 0x0a, 0x08, 0x0e, 0x0c, 0x0b, 0x09, 0x0f, 0x0d,
+ 0x1a, 0x18, 0x1e, 0x1c, 0x1b, 0x19, 0x1f, 0x1d,
+ 0x02, 0x00, 0x06, 0x04, 0x03, 0x01, 0x07, 0x05,
+ 0x12, 0x10, 0x16, 0x14, 0x13, 0x11, 0x17, 0x15 },
+ { 0x12, 0x1a, 0x16, 0x1e, 0x02, 0x0a, 0x06, 0x0e,
+ 0x10, 0x18, 0x14, 0x1c, 0x00, 0x08, 0x04, 0x0c,
+ 0x13, 0x1b, 0x17, 0x1f, 0x03, 0x0b, 0x07, 0x0f,
+ 0x11, 0x19, 0x15, 0x1d, 0x01, 0x09, 0x05, 0x0d } };
+
+ uint8_t p_variants[32] =
+ { 0xB7, 0x74, 0x85, 0xD0, 0xCC, 0xDB, 0xCA, 0x73,
+ 0x03, 0xFE, 0x31, 0x03, 0x52, 0xE0, 0xB7, 0x42,
+ 0x63, 0x16, 0xF2, 0x2A, 0x79, 0x52, 0xFF, 0x1B,
+ 0x7A, 0x11, 0xCA, 0x1A, 0x9B, 0x40, 0xAD, 0x01 };
+
+ /* The "secret" key */
+ uint8_t p_secret[5] = { 0x55, 0xD6, 0xC4, 0xC5, 0x28 };
+
+ uint8_t p_bits[30], p_scratch[10], p_tmp1[5], p_tmp2[5];
+ uint8_t i_lfsr0_o; /* 1 bit used */
+ uint8_t i_lfsr1_o; /* 1 bit used */
+ uint8_t i_css_variant, i_cse, i_index, i_combined, i_carry;
+ uint8_t i_val = 0;
+ uint32_t i_lfsr0, i_lfsr1;
+ int i_term = 0;
+ int i_bit;
+ int i;
+
+ for (i = 9; i >= 0; --i)
+ p_scratch[i] = p_challenge[pp_perm_challenge[i_key_type][i]];
+
+ i_css_variant = ( i_key_type == 0 ) ? i_variant :
+ pp_perm_variant[i_key_type-1][i_variant];
+
+ /*
+ * This encryption engine implements one of 32 variations
+ * one the same theme depending upon the choice in the
+ * variant parameter (0 - 31).
+ *
+ * The algorithm itself manipulates a 40 bit input into
+ * a 40 bit output.
+ * The parameter 'input' is 80 bits. It consists of
+ * the 40 bit input value that is to be encrypted followed
+ * by a 40 bit seed value for the pseudo random number
+ * generators.
+ */
+
+ /* Feed the secret into the input values such that
+ * we alter the seed to the LFSR's used above, then
+ * generate the bits to play with.
+ */
+ for( i = 5 ; --i >= 0 ; )
+ {
+ p_tmp1[i] = p_scratch[5 + i] ^ p_secret[i] ^ p_crypt_tab2[i];
+ }
+
+ /*
+ * We use two LFSR's (seeded from some of the input data bytes) to
+ * generate two streams of pseudo-random bits. These two bit streams
+ * are then combined by simply adding with carry to generate a final
+ * sequence of pseudo-random bits which is stored in the buffer that
+ * 'output' points to the end of - len is the size of this buffer.
+ *
+ * The first LFSR is of degree 25, and has a polynomial of:
+ * x^13 + x^5 + x^4 + x^1 + 1
+ *
+ * The second LSFR is of degree 17, and has a (primitive) polynomial of:
+ * x^15 + x^1 + 1
+ *
+ * I don't know if these polynomials are primitive modulo 2, and thus
+ * represent maximal-period LFSR's.
+ *
+ *
+ * Note that we take the output of each LFSR from the new shifted in
+ * bit, not the old shifted out bit. Thus for ease of use the LFSR's
+ * are implemented in bit reversed order.
+ *
+ */
+
+ /* In order to ensure that the LFSR works we need to ensure that the
+ * initial values are non-zero. Thus when we initialise them from
+ * the seed, we ensure that a bit is set.
+ */
+ i_lfsr0 = ( p_tmp1[0] << 17 ) | ( p_tmp1[1] << 9 ) |
+ (( p_tmp1[2] & ~7 ) << 1 ) | 8 | ( p_tmp1[2] & 7 );
+ i_lfsr1 = ( p_tmp1[3] << 9 ) | 0x100 | p_tmp1[4];
+
+ i_index = sizeof(p_bits);
+ i_carry = 0;
+
+ do
+ {
+ for( i_bit = 0, i_val = 0 ; i_bit < 8 ; ++i_bit )
+ {
+
+ i_lfsr0_o = ( ( i_lfsr0 >> 24 ) ^ ( i_lfsr0 >> 21 ) ^
+ ( i_lfsr0 >> 20 ) ^ ( i_lfsr0 >> 12 ) ) & 1;
+ i_lfsr0 = ( i_lfsr0 << 1 ) | i_lfsr0_o;
+
+ i_lfsr1_o = ( ( i_lfsr1 >> 16 ) ^ ( i_lfsr1 >> 2 ) ) & 1;
+ i_lfsr1 = ( i_lfsr1 << 1 ) | i_lfsr1_o;
+
+ i_combined = !i_lfsr1_o + i_carry + !i_lfsr0_o;
+ /* taking bit 1 */
+ i_carry = ( i_combined >> 1 ) & 1;
+ i_val |= ( i_combined & 1 ) << i_bit;
+ }
+
+ p_bits[--i_index] = i_val;
+ } while( i_index > 0 );
+
+ /* This term is used throughout the following to
+ * select one of 32 different variations on the
+ * algorithm.
+ */
+ i_cse = p_variants[i_css_variant] ^ p_crypt_tab2[i_css_variant];
+
+ /* Now the actual blocks doing the encryption. Each
+ * of these works on 40 bits at a time and are quite
+ * similar.
+ */
+ i_index = 0;
+ for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_scratch[i] )
+ {
+ i_index = p_bits[25 + i] ^ p_scratch[i];
+ i_index = p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse;
+
+ p_tmp1[i] = p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term;
+ }
+ p_tmp1[4] ^= p_tmp1[0];
+
+ for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp1[i] )
+ {
+ i_index = p_bits[20 + i] ^ p_tmp1[i];
+ i_index = p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse;
+
+ p_tmp2[i] = p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term;
+ }
+ p_tmp2[4] ^= p_tmp2[0];
+
+ for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp2[i] )
+ {
+ i_index = p_bits[15 + i] ^ p_tmp2[i];
+ i_index = p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse;
+ i_index = p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term;
+
+ p_tmp1[i] = p_crypt_tab0[i_index] ^ p_crypt_tab2[i_index];
+ }
+ p_tmp1[4] ^= p_tmp1[0];
+
+ for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp1[i] )
+ {
+ i_index = p_bits[10 + i] ^ p_tmp1[i];
+ i_index = p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse;
+
+ i_index = p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term;
+
+ p_tmp2[i] = p_crypt_tab0[i_index] ^ p_crypt_tab2[i_index];
+ }
+ p_tmp2[4] ^= p_tmp2[0];
+
+ for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp2[i] )
+ {
+ i_index = p_bits[5 + i] ^ p_tmp2[i];
+ i_index = p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse;
+
+ p_tmp1[i] = p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term;
+ }
+ p_tmp1[4] ^= p_tmp1[0];
+
+ for(i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp1[i] )
+ {
+ i_index = p_bits[i] ^ p_tmp1[i];
+ i_index = p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse;
+
+ p_key[i] = p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term;
+ }
+
+ return;
+}
+
+/*****************************************************************************
+ * DecryptKey: decrypt p_crypted with p_key.
+ *****************************************************************************
+ * Used to decrypt the disc key, with a player key, after requesting it
+ * in _dvdcss_disckey and to decrypt title keys, with a disc key, requested
+ * in _dvdcss_titlekey.
+ * The player keys and the resulting disc key are only used as KEKs
+ * (key encryption keys).
+ * Decryption is slightly dependant on the type of key:
+ * -for disc key, invert is 0x00,
+ * -for title key, invert if 0xff.
+ *****************************************************************************/
+static void DecryptKey( uint8_t invert, uint8_t const *p_key,
+ uint8_t const *p_crypted, uint8_t *p_result )
+{
+ unsigned int i_lfsr1_lo;
+ unsigned int i_lfsr1_hi;
+ unsigned int i_lfsr0;
+ unsigned int i_combined;
+ uint8_t o_lfsr0;
+ uint8_t o_lfsr1;
+ uint8_t k[5];
+ int i;
+
+ i_lfsr1_lo = p_key[0] | 0x100;
+ i_lfsr1_hi = p_key[1];
+
+ i_lfsr0 = ( ( p_key[4] << 17 )
+ | ( p_key[3] << 9 )
+ | ( p_key[2] << 1 ) )
+ + 8 - ( p_key[2] & 7 );
+ i_lfsr0 = ( p_css_tab4[i_lfsr0 & 0xff] << 24 ) |
+ ( p_css_tab4[( i_lfsr0 >> 8 ) & 0xff] << 16 ) |
+ ( p_css_tab4[( i_lfsr0 >> 16 ) & 0xff] << 8 ) |
+ p_css_tab4[( i_lfsr0 >> 24 ) & 0xff];
+
+ i_combined = 0;
+ for( i = 0 ; i < KEY_SIZE ; ++i )
+ {
+ o_lfsr1 = p_css_tab2[i_lfsr1_hi] ^ p_css_tab3[i_lfsr1_lo];
+ i_lfsr1_hi = i_lfsr1_lo >> 1;
+ i_lfsr1_lo = ( ( i_lfsr1_lo & 1 ) << 8 ) ^ o_lfsr1;
+ o_lfsr1 = p_css_tab4[o_lfsr1];
+
+ o_lfsr0 = ((((((( i_lfsr0 >> 8 ) ^ i_lfsr0 ) >> 1 )
+ ^ i_lfsr0 ) >> 3 ) ^ i_lfsr0 ) >> 7 );
+ i_lfsr0 = ( i_lfsr0 >> 8 ) | ( o_lfsr0 << 24 );
+
+ i_combined += ( o_lfsr0 ^ invert ) + o_lfsr1;
+ k[i] = i_combined & 0xff;
+ i_combined >>= 8;
+ }
+
+ p_result[4] = k[4] ^ p_css_tab1[p_crypted[4]] ^ p_crypted[3];
+ p_result[3] = k[3] ^ p_css_tab1[p_crypted[3]] ^ p_crypted[2];
+ p_result[2] = k[2] ^ p_css_tab1[p_crypted[2]] ^ p_crypted[1];
+ p_result[1] = k[1] ^ p_css_tab1[p_crypted[1]] ^ p_crypted[0];
+ p_result[0] = k[0] ^ p_css_tab1[p_crypted[0]] ^ p_result[4];
+
+ p_result[4] = k[4] ^ p_css_tab1[p_result[4]] ^ p_result[3];
+ p_result[3] = k[3] ^ p_css_tab1[p_result[3]] ^ p_result[2];
+ p_result[2] = k[2] ^ p_css_tab1[p_result[2]] ^ p_result[1];
+ p_result[1] = k[1] ^ p_css_tab1[p_result[1]] ^ p_result[0];
+ p_result[0] = k[0] ^ p_css_tab1[p_result[0]];
+
+ return;
+}
+
+/*****************************************************************************
+ * player_keys: alternate DVD player keys
+ *****************************************************************************
+ * These player keys were generated using Frank A. Stevenson's PlayerKey
+ * cracker. A copy of his article can be found here:
+ * http://www-2.cs.cmu.edu/~dst/DeCSS/FrankStevenson/mail2.txt
+ *****************************************************************************/
+static const dvd_key_t player_keys[] =
+{
+ { 0x01, 0xaf, 0xe3, 0x12, 0x80 },
+ { 0x12, 0x11, 0xca, 0x04, 0x3b },
+ { 0x14, 0x0c, 0x9e, 0xd0, 0x09 },
+ { 0x14, 0x71, 0x35, 0xba, 0xe2 },
+ { 0x1a, 0xa4, 0x33, 0x21, 0xa6 },
+ { 0x26, 0xec, 0xc4, 0xa7, 0x4e },
+ { 0x2c, 0xb2, 0xc1, 0x09, 0xee },
+ { 0x2f, 0x25, 0x9e, 0x96, 0xdd },
+ { 0x33, 0x2f, 0x49, 0x6c, 0xe0 },
+ { 0x35, 0x5b, 0xc1, 0x31, 0x0f },
+ { 0x36, 0x67, 0xb2, 0xe3, 0x85 },
+ { 0x39, 0x3d, 0xf1, 0xf1, 0xbd },
+ { 0x3b, 0x31, 0x34, 0x0d, 0x91 },
+ { 0x45, 0xed, 0x28, 0xeb, 0xd3 },
+ { 0x48, 0xb7, 0x6c, 0xce, 0x69 },
+ { 0x4b, 0x65, 0x0d, 0xc1, 0xee },
+ { 0x4c, 0xbb, 0xf5, 0x5b, 0x23 },
+ { 0x51, 0x67, 0x67, 0xc5, 0xe0 },
+ { 0x53, 0x94, 0xe1, 0x75, 0xbf },
+ { 0x57, 0x2c, 0x8b, 0x31, 0xae },
+ { 0x63, 0xdb, 0x4c, 0x5b, 0x4a },
+ { 0x7b, 0x1e, 0x5e, 0x2b, 0x57 },
+ { 0x85, 0xf3, 0x85, 0xa0, 0xe0 },
+ { 0xab, 0x1e, 0xe7, 0x7b, 0x72 },
+ { 0xab, 0x36, 0xe3, 0xeb, 0x76 },
+ { 0xb1, 0xb8, 0xf9, 0x38, 0x03 },
+ { 0xb8, 0x5d, 0xd8, 0x53, 0xbd },
+ { 0xbf, 0x92, 0xc3, 0xb0, 0xe2 },
+ { 0xcf, 0x1a, 0xb2, 0xf8, 0x0a },
+ { 0xec, 0xa0, 0xcf, 0xb3, 0xff },
+ { 0xfc, 0x95, 0xa9, 0x87, 0x35 }
+};
+
+/*****************************************************************************
+ * DecryptDiscKey
+ *****************************************************************************
+ * Decryption of the disc key with player keys: try to decrypt the disc key
+ * from every position with every player key.
+ * p_struct_disckey: the 2048 byte DVD_STRUCT_DISCKEY data
+ * p_disc_key: result, the 5 byte disc key
+ *****************************************************************************/
+static int DecryptDiscKey( dvdcss_t dvdcss, uint8_t const *p_struct_disckey,
+ dvd_key_t p_disc_key )
+{
+ uint8_t p_verify[KEY_SIZE];
+ unsigned int i, n = 0;
+
+ /* Decrypt disc key with the above player keys */
+ for( n = 0; n < sizeof(player_keys) / sizeof(dvd_key_t); n++ )
+ {
+ PrintKey( dvdcss, "trying player key ", player_keys[n] );
+
+ for( i = 1; i < 409; i++ )
+ {
+ /* Check if player key n is the right key for position i. */
+ DecryptKey( 0, player_keys[n], p_struct_disckey + 5 * i,
+ p_disc_key );
+
+ /* The first part in the struct_disckey block is the
+ * 'disc key' encrypted with itself. Using this we
+ * can check if we decrypted the correct key. */
+ DecryptKey( 0, p_disc_key, p_struct_disckey, p_verify );
+
+ /* If the position / player key pair worked then return. */
+ if( memcmp( p_disc_key, p_verify, KEY_SIZE ) == 0 )
+ {
+ return 0;
+ }
+ }
+ }
+
+ /* Have tried all combinations of positions and keys,
+ * and we still didn't succeed. */
+ memset( p_disc_key, 0, KEY_SIZE );
+ return -1;
+}
+
+/*****************************************************************************
+ * DecryptTitleKey
+ *****************************************************************************
+ * Decrypt the title key using the disc key.
+ * p_disc_key: result, the 5 byte disc key
+ * p_titlekey: the encrypted title key, gets overwritten by the decrypted key
+ *****************************************************************************/
+static void DecryptTitleKey( dvd_key_t p_disc_key, dvd_key_t p_titlekey )
+{
+ DecryptKey( 0xff, p_disc_key, p_titlekey, p_titlekey );
+}
+
+/*****************************************************************************
+ * CrackDiscKey: brute force disc key
+ * CSS hash reversal function designed by Frank Stevenson
+ *****************************************************************************
+ * This function uses a big amount of memory to crack the disc key from the
+ * disc key hash, if player keys are not available.
+ *****************************************************************************/
+#define K1TABLEWIDTH 10
+
+/*
+ * Simple function to test if a candidate key produces the given hash
+ */
+static int investigate( unsigned char *hash, unsigned char *ckey )
+{
+ unsigned char key[KEY_SIZE];
+
+ DecryptKey( 0, ckey, hash, key );
+
+ return memcmp( key, ckey, KEY_SIZE );
+}
+
+static int CrackDiscKey( dvdcss_t dvdcss, uint8_t *p_disc_key )
+{
+ unsigned char B[5] = { 0,0,0,0,0 }; /* Second Stage of mangle cipher */
+ unsigned char C[5] = { 0,0,0,0,0 }; /* Output Stage of mangle cipher
+ * IntermediateKey */
+ unsigned char k[5] = { 0,0,0,0,0 }; /* Mangling cipher key
+ * Also output from CSS( C ) */
+ unsigned char out1[5]; /* five first output bytes of LFSR1 */
+ unsigned char out2[5]; /* five first output bytes of LFSR2 */
+ unsigned int lfsr1a; /* upper 9 bits of LFSR1 */
+ unsigned int lfsr1b; /* lower 8 bits of LFSR1 */
+ unsigned int tmp, tmp2, tmp3, tmp4,tmp5;
+ int i,j;
+ unsigned int nStepA; /* iterator for LFSR1 start state */
+ unsigned int nStepB; /* iterator for possible B[0] */
+ unsigned int nTry; /* iterator for K[1] possibilities */
+ unsigned int nPossibleK1; /* #of possible K[1] values */
+ unsigned char* K1table; /* Lookup table for possible K[1] */
+ unsigned int* BigTable; /* LFSR2 startstate indexed by
+ * 1,2,5 output byte */
+
+ /*
+ * Prepare tables for hash reversal
+ */
+
+ /* initialize lookup tables for k[1] */
+ K1table = malloc( 65536 * K1TABLEWIDTH );
+ memset( K1table, 0 , 65536 * K1TABLEWIDTH );
+ if( K1table == NULL )
+ {
+ return -1;
+ }
+
+ tmp = p_disc_key[0] ^ p_css_tab1[ p_disc_key[1] ];
+ for( i = 0 ; i < 256 ; i++ ) /* k[1] */
+ {
+ tmp2 = p_css_tab1[ tmp ^ i ]; /* p_css_tab1[ B[1] ]*/
+
+ for( j = 0 ; j < 256 ; j++ ) /* B[0] */
+ {
+ tmp3 = j ^ tmp2 ^ i; /* C[1] */
+ tmp4 = K1table[ K1TABLEWIDTH * ( 256 * j + tmp3 ) ]; /* count of entries here */
+ tmp4++;
+/*
+ if( tmp4 == K1TABLEWIDTH )
+ {
+ print_debug( dvdcss, "Table disaster %d", tmp4 );
+ }
+*/
+ if( tmp4 < K1TABLEWIDTH )
+ {
+ K1table[ K1TABLEWIDTH * ( 256 * j + tmp3 ) + tmp4 ] = i;
+ }
+ K1table[ K1TABLEWIDTH * ( 256 * j + tmp3 ) ] = tmp4;
+ }
+ }
+
+ /* Initing our Really big table */
+ BigTable = malloc( 16777216 * sizeof(int) );
+ memset( BigTable, 0 , 16777216 * sizeof(int) );
+ if( BigTable == NULL )
+ {
+ return -1;
+ }
+
+ tmp3 = 0;
+
+ print_debug( dvdcss, "initializing the big table" );
+
+ for( i = 0 ; i < 16777216 ; i++ )
+ {
+ tmp = (( i + i ) & 0x1fffff0 ) | 0x8 | ( i & 0x7 );
+
+ for( j = 0 ; j < 5 ; j++ )
+ {
+ tmp2=((((((( tmp >> 3 ) ^ tmp ) >> 1 ) ^ tmp ) >> 8 )
+ ^ tmp ) >> 5 ) & 0xff;
+ tmp = ( tmp << 8) | tmp2;
+ out2[j] = p_css_tab4[ tmp2 ];
+ }
+
+ j = ( out2[0] << 16 ) | ( out2[1] << 8 ) | out2[4];
+ BigTable[j] = i;
+ }
+
+ /*
+ * We are done initing, now reverse hash
+ */
+ tmp5 = p_disc_key[0] ^ p_css_tab1[ p_disc_key[1] ];
+
+ for( nStepA = 0 ; nStepA < 65536 ; nStepA ++ )
+ {
+ lfsr1a = 0x100 | ( nStepA >> 8 );
+ lfsr1b = nStepA & 0xff;
+
+ /* Generate 5 first output bytes from lfsr1 */
+ for( i = 0 ; i < 5 ; i++ )
+ {
+ tmp = p_css_tab2[ lfsr1b ] ^ p_css_tab3[ lfsr1a ];
+ lfsr1b = lfsr1a >> 1;
+ lfsr1a = ((lfsr1a&1)<<8) ^ tmp;
+ out1[ i ] = p_css_tab4[ tmp ];
+ }
+
+ /* cumpute and cache some variables */
+ C[0] = nStepA >> 8;
+ C[1] = nStepA & 0xff;
+ tmp = p_disc_key[3] ^ p_css_tab1[ p_disc_key[4] ];
+ tmp2 = p_css_tab1[ p_disc_key[0] ];
+
+ /* Search through all possible B[0] */
+ for( nStepB = 0 ; nStepB < 256 ; nStepB++ )
+ {
+ /* reverse parts of the mangling cipher */
+ B[0] = nStepB;
+ k[0] = p_css_tab1[ B[0] ] ^ C[0];
+ B[4] = B[0] ^ k[0] ^ tmp2;
+ k[4] = B[4] ^ tmp;
+ nPossibleK1 = K1table[ K1TABLEWIDTH * (256 * B[0] + C[1]) ];
+
+ /* Try out all possible values for k[1] */
+ for( nTry = 0 ; nTry < nPossibleK1 ; nTry++ )
+ {
+ k[1] = K1table[ K1TABLEWIDTH * (256 * B[0] + C[1]) + nTry + 1 ];
+ B[1] = tmp5 ^ k[1];
+
+ /* reconstruct output from LFSR2 */
+ tmp3 = ( 0x100 + k[0] - out1[0] );
+ out2[0] = tmp3 & 0xff;
+ tmp3 = tmp3 & 0x100 ? 0x100 : 0xff;
+ tmp3 = ( tmp3 + k[1] - out1[1] );
+ out2[1] = tmp3 & 0xff;
+ tmp3 = ( 0x100 + k[4] - out1[4] );
+ out2[4] = tmp3 & 0xff; /* Can be 1 off */
+
+ /* test first possible out2[4] */
+ tmp4 = ( out2[0] << 16 ) | ( out2[1] << 8 ) | out2[4];
+ tmp4 = BigTable[ tmp4 ];
+ C[2] = tmp4 & 0xff;
+ C[3] = ( tmp4 >> 8 ) & 0xff;
+ C[4] = ( tmp4 >> 16 ) & 0xff;
+ B[3] = p_css_tab1[ B[4] ] ^ k[4] ^ C[4];
+ k[3] = p_disc_key[2] ^ p_css_tab1[ p_disc_key[3] ] ^ B[3];
+ B[2] = p_css_tab1[ B[3] ] ^ k[3] ^ C[3];
+ k[2] = p_disc_key[1] ^ p_css_tab1[ p_disc_key[2] ] ^ B[2];
+
+ if( ( B[1] ^ p_css_tab1[ B[2] ] ^ k[ 2 ] ) == C[ 2 ] )
+ {
+ if( ! investigate( &p_disc_key[0] , &C[0] ) )
+ {
+ goto end;
+ }
+ }
+
+ /* Test second possible out2[4] */
+ out2[4] = ( out2[4] + 0xff ) & 0xff;
+ tmp4 = ( out2[0] << 16 ) | ( out2[1] << 8 ) | out2[4];
+ tmp4 = BigTable[ tmp4 ];
+ C[2] = tmp4 & 0xff;
+ C[3] = ( tmp4 >> 8 ) & 0xff;
+ C[4] = ( tmp4 >> 16 ) & 0xff;
+ B[3] = p_css_tab1[ B[4] ] ^ k[4] ^ C[4];
+ k[3] = p_disc_key[2] ^ p_css_tab1[ p_disc_key[3] ] ^ B[3];
+ B[2] = p_css_tab1[ B[3] ] ^ k[3] ^ C[3];
+ k[2] = p_disc_key[1] ^ p_css_tab1[ p_disc_key[2] ] ^ B[2];
+
+ if( ( B[1] ^ p_css_tab1[ B[2] ] ^ k[ 2 ] ) == C[ 2 ] )
+ {
+ if( ! investigate( &p_disc_key[0] , &C[0] ) )
+ {
+ goto end;
+ }
+ }
+ }
+ }
+ }
+
+end:
+
+ memcpy( p_disc_key, &C[0], KEY_SIZE );
+
+ free( K1table );
+ free( BigTable );
+
+ return 0;
+}
+
+/*****************************************************************************
+ * RecoverTitleKey: (title) key recovery from cipher and plain text
+ * Function designed by Frank Stevenson
+ *****************************************************************************
+ * Called from Attack* which are in turn called by CrackTitleKey. Given
+ * a guessed(?) plain text and the cipher text. Returns -1 on failure.
+ *****************************************************************************/
+static int RecoverTitleKey( int i_start, uint8_t const *p_crypted,
+ uint8_t const *p_decrypted,
+ uint8_t const *p_sector_seed, uint8_t *p_key )
+{
+ uint8_t p_buffer[10];
+ unsigned int i_t1, i_t2, i_t3, i_t4, i_t5, i_t6;
+ unsigned int i_try;
+ unsigned int i_candidate;
+ unsigned int i, j;
+ int i_exit = -1;
+
+ for( i = 0 ; i < 10 ; i++ )
+ {
+ p_buffer[i] = p_css_tab1[p_crypted[i]] ^ p_decrypted[i];
+ }
+
+ for( i_try = i_start ; i_try < 0x10000 ; i_try++ )
+ {
+ i_t1 = i_try >> 8 | 0x100;
+ i_t2 = i_try & 0xff;
+ i_t3 = 0; /* not needed */
+ i_t5 = 0;
+
+ /* iterate cipher 4 times to reconstruct LFSR2 */
+ for( i = 0 ; i < 4 ; i++ )
+ {
+ /* advance LFSR1 normaly */
+ i_t4 = p_css_tab2[i_t2] ^ p_css_tab3[i_t1];
+ i_t2 = i_t1 >> 1;
+ i_t1 = ( ( i_t1 & 1 ) << 8 ) ^ i_t4;
+ i_t4 = p_css_tab5[i_t4];
+ /* deduce i_t6 & i_t5 */
+ i_t6 = p_buffer[i];
+ if( i_t5 )
+ {
+ i_t6 = ( i_t6 + 0xff ) & 0x0ff;
+ }
+ if( i_t6 < i_t4 )
+ {
+ i_t6 += 0x100;
+ }
+ i_t6 -= i_t4;
+ i_t5 += i_t6 + i_t4;
+ i_t6 = p_css_tab4[ i_t6 ];
+ /* feed / advance i_t3 / i_t5 */
+ i_t3 = ( i_t3 << 8 ) | i_t6;
+ i_t5 >>= 8;
+ }
+
+ i_candidate = i_t3;
+
+ /* iterate 6 more times to validate candidate key */
+ for( ; i < 10 ; i++ )
+ {
+ i_t4 = p_css_tab2[i_t2] ^ p_css_tab3[i_t1];
+ i_t2 = i_t1 >> 1;
+ i_t1 = ( ( i_t1 & 1 ) << 8 ) ^ i_t4;
+ i_t4 = p_css_tab5[i_t4];
+ i_t6 = ((((((( i_t3 >> 3 ) ^ i_t3 ) >> 1 ) ^
+ i_t3 ) >> 8 ) ^ i_t3 ) >> 5 ) & 0xff;
+ i_t3 = ( i_t3 << 8 ) | i_t6;
+ i_t6 = p_css_tab4[i_t6];
+ i_t5 += i_t6 + i_t4;
+ if( ( i_t5 & 0xff ) != p_buffer[i] )
+ {
+ break;
+ }
+
+ i_t5 >>= 8;
+ }
+
+ if( i == 10 )
+ {
+ /* Do 4 backwards steps of iterating t3 to deduce initial state */
+ i_t3 = i_candidate;
+ for( i = 0 ; i < 4 ; i++ )
+ {
+ i_t1 = i_t3 & 0xff;
+ i_t3 = ( i_t3 >> 8 );
+ /* easy to code, and fast enough bruteforce
+ * search for byte shifted in */
+ for( j = 0 ; j < 256 ; j++ )
+ {
+ i_t3 = ( i_t3 & 0x1ffff ) | ( j << 17 );
+ i_t6 = ((((((( i_t3 >> 3 ) ^ i_t3 ) >> 1 ) ^
+ i_t3 ) >> 8 ) ^ i_t3 ) >> 5 ) & 0xff;
+ if( i_t6 == i_t1 )
+ {
+ break;
+ }
+ }
+ }
+
+ i_t4 = ( i_t3 >> 1 ) - 4;
+ for( i_t5 = 0 ; i_t5 < 8; i_t5++ )
+ {
+ if( ( ( i_t4 + i_t5 ) * 2 + 8 - ( (i_t4 + i_t5 ) & 7 ) )
+ == i_t3 )
+ {
+ p_key[0] = i_try>>8;
+ p_key[1] = i_try & 0xFF;
+ p_key[2] = ( ( i_t4 + i_t5 ) >> 0 ) & 0xFF;
+ p_key[3] = ( ( i_t4 + i_t5 ) >> 8 ) & 0xFF;
+ p_key[4] = ( ( i_t4 + i_t5 ) >> 16 ) & 0xFF;
+ i_exit = i_try + 1;
+ }
+ }
+ }
+ }
+
+ if( i_exit >= 0 )
+ {
+ p_key[0] ^= p_sector_seed[0];
+ p_key[1] ^= p_sector_seed[1];
+ p_key[2] ^= p_sector_seed[2];
+ p_key[3] ^= p_sector_seed[3];
+ p_key[4] ^= p_sector_seed[4];
+ }
+
+ return i_exit;
+}
+
+
+/******************************************************************************
+ * Various pieces for the title crack engine.
+ ******************************************************************************
+ * The length of the PES packet is located at 0x12-0x13.
+ * The the copyrigth protection bits are located at 0x14 (bits 0x20 and 0x10).
+ * The data of the PES packet begins at 0x15 (if there isn't any PTS/DTS)
+ * or at 0x?? if there are both PTS and DTS's.
+ * The seed value used with the unscrambling key is the 5 bytes at 0x54-0x58.
+ * The scrabled part of a sector begins at 0x80.
+ *****************************************************************************/
+
+/* Statistics */
+static int i_tries = 0, i_success = 0;
+
+/*****************************************************************************
+ * CrackTitleKey: try to crack title key from the contents of a VOB.
+ *****************************************************************************
+ * This function is called by _dvdcss_titlekey to find a title key, if we've
+ * chosen to crack title key instead of decrypting it with the disc key.
+ * The DVD should have been opened and be in an authenticated state.
+ * i_pos is the starting sector, i_len is the maximum number of sectors to read
+ *****************************************************************************/
+static int CrackTitleKey( dvdcss_t dvdcss, int i_pos, int i_len,
+ dvd_key_t p_titlekey )
+{
+ uint8_t p_buf[ DVDCSS_BLOCK_SIZE ];
+ const uint8_t p_packstart[4] = { 0x00, 0x00, 0x01, 0xba };
+ int i_reads = 0;
+ int i_encrypted = 0;
+ int b_stop_scanning = 0;
+ int b_read_error = 0;
+ int i_ret;
+
+ print_debug( dvdcss, "cracking title key at block %i", i_pos );
+
+ i_tries = 0;
+ i_success = 0;
+
+ do
+ {
+ i_ret = dvdcss->pf_seek( dvdcss, i_pos );
+
+ if( i_ret != i_pos )
+ {
+ print_error( dvdcss, "seek failed" );
+ }
+
+ i_ret = dvdcss_read( dvdcss, p_buf, 1, DVDCSS_NOFLAGS );
+
+ /* Either we are at the end of the physical device or the auth
+ * have failed / were not done and we got a read error. */
+ if( i_ret <= 0 )
+ {
+ if( i_ret == 0 )
+ {
+ print_debug( dvdcss, "read returned 0 (end of device?)" );
+ }
+ else if( !b_read_error )
+ {
+ print_debug( dvdcss, "read error at block %i, resorting to "
+ "secret arcanes to recover", i_pos );
+
+ /* Reset the drive before trying to continue */
+ _dvdcss_close( dvdcss );
+ _dvdcss_open( dvdcss );
+
+ b_read_error = 1;
+ continue;
+ }
+ break;
+ }
+
+ /* Stop when we find a non MPEG stream block.
+ * (We must have reached the end of the stream).
+ * For now, allow all blocks that begin with a start code. */
+ if( memcmp( p_buf, p_packstart, 3 ) )
+ {
+ print_debug( dvdcss, "non MPEG block found at block %i "
+ "(end of title)", i_pos );
+ break;
+ }
+
+ if( p_buf[0x0d] & 0x07 )
+ print_debug( dvdcss, "stuffing in pack header" );
+
+ /* PES_scrambling_control does not exist in a system_header,
+ * a padding_stream or a private_stream2 (and others?). */
+ if( p_buf[0x14] & 0x30 && ! ( p_buf[0x11] == 0xbb
+ || p_buf[0x11] == 0xbe
+ || p_buf[0x11] == 0xbf ) )
+ {
+ i_encrypted++;
+
+ if( AttackPattern(p_buf, i_reads, p_titlekey) > 0 )
+ {
+ b_stop_scanning = 1;
+ }
+#if 0
+ if( AttackPadding(p_buf, i_reads, p_titlekey) > 0 )
+ {
+ b_stop_scanning = 1;
+ }
+#endif
+ }
+
+ i_pos++;
+ i_len--;
+ i_reads++;
+
+ /* Emit a progress indication now and then. */
+ if( !( i_reads & 0xfff ) )
+ {
+ print_debug( dvdcss, "at block %i, still cracking...", i_pos );
+ }
+
+ /* Stop after 2000 blocks if we haven't seen any encrypted blocks. */
+ if( i_reads >= 2000 && i_encrypted == 0 ) break;
+
+ } while( !b_stop_scanning && i_len > 0);
+
+ if( !b_stop_scanning )
+ {
+ print_debug( dvdcss, "end of title reached" );
+ }
+
+ /* Print some statistics. */
+ print_debug( dvdcss, "successful attempts %d/%d, scrambled blocks %d/%d",
+ i_success, i_tries, i_encrypted, i_reads );
+
+ if( i_success > 0 /* b_stop_scanning */ )
+ {
+ print_debug( dvdcss, "vts key initialized" );
+ return 1;
+ }
+
+ if( i_encrypted == 0 && i_reads > 0 )
+ {
+ memset( p_titlekey, 0, KEY_SIZE );
+ print_debug( dvdcss, "no scrambled sectors found" );
+ return 0;
+ }
+
+ memset( p_titlekey, 0, KEY_SIZE );
+ return -1;
+}
+
+
+/******************************************************************************
+ * The original Ethan Hawke (DeCSSPlus) attack (modified).
+ ******************************************************************************
+ * Tries to find a repeating pattern just before the encrypted part starts.
+ * Then it guesses that the plain text for first encrypted bytes are
+ * a contiuation of that pattern.
+ *****************************************************************************/
+static int AttackPattern( uint8_t const p_sec[ DVDCSS_BLOCK_SIZE ],
+ int i_pos, uint8_t *p_key )
+{
+ unsigned int i_best_plen = 0;
+ unsigned int i_best_p = 0;
+ unsigned int i, j;
+
+ /* For all cycle length from 2 to 48 */
+ for( i = 2 ; i < 0x30 ; i++ )
+ {
+ /* Find the number of bytes that repeats in cycles. */
+ for( j = i + 1;
+ j < 0x80 && ( p_sec[0x7F - (j%i)] == p_sec[0x7F - j] );
+ j++ )
+ {
+ /* We have found j repeating bytes with a cycle length i. */
+ if( j > i_best_plen )
+ {
+ i_best_plen = j;
+ i_best_p = i;
+ }
+ }
+ }
+
+ /* We need at most 10 plain text bytes?, so a make sure that we
+ * have at least 20 repeated bytes and that they have cycled at
+ * least one time. */
+ if( ( i_best_plen > 3 ) && ( i_best_plen / i_best_p >= 2) )
+ {
+ int res;
+
+ i_tries++;
+ memset( p_key, 0, KEY_SIZE );
+ res = RecoverTitleKey( 0, &p_sec[0x80],
+ &p_sec[ 0x80 - (i_best_plen / i_best_p) * i_best_p ],
+ &p_sec[0x54] /* key_seed */, p_key );
+ i_success += ( res >= 0 );
+#if 0
+ if( res >= 0 )
+ {
+ fprintf( stderr, "key is %02x:%02x:%02x:%02x:%02x ",
+ p_key[0], p_key[1], p_key[2], p_key[3], p_key[4] );
+ fprintf( stderr, "at block %5d pattern len %3d period %3d %s\n",
+ i_pos, i_best_plen, i_best_p, (res>=0?"y":"n") );
+ }
+#endif
+ return ( res >= 0 );
+ }
+
+ return 0;
+}
+
+
+#if 0
+/******************************************************************************
+ * Encrypted Padding_stream attack.
+ ******************************************************************************
+ * DVD specifies that there must only be one type of data in every sector.
+ * Every sector is one pack and so must obviously be 2048 bytes long.
+ * For the last pice of video data before a VOBU boundary there might not
+ * be exactly the right amount of data to fill a sector. Then one has to
+ * pad the pack to 2048 bytes. For just a few bytes this is done in the
+ * header but for any large amount you insert a PES packet from the
+ * Padding stream. This looks like 0x00 00 01 be xx xx ff ff ...
+ * where xx xx is the length of the padding stream.
+ *****************************************************************************/
+static int AttackPadding( uint8_t const p_sec[ DVDCSS_BLOCK_SIZE ],
+ int i_pos, uint8_t *p_key )
+{
+ unsigned int i_pes_length;
+ /*static int i_tries = 0, i_success = 0;*/
+
+ i_pes_length = (p_sec[0x12]<<8) | p_sec[0x13];
+
+ /* Coverd by the test below but usfull for debuging. */
+ if( i_pes_length == DVDCSS_BLOCK_SIZE - 0x14 ) return 0;
+
+ /* There must be room for at least 4? bytes of padding stream,
+ * and it must be encrypted.
+ * sector size - pack/pes header - padding startcode - padding length */
+ if( ( DVDCSS_BLOCK_SIZE - 0x14 - 4 - 2 - i_pes_length < 4 ) ||
+ ( p_sec[0x14 + i_pes_length + 0] == 0x00 &&
+ p_sec[0x14 + i_pes_length + 1] == 0x00 &&
+ p_sec[0x14 + i_pes_length + 2] == 0x01 ) )
+ {
+ fprintf( stderr, "plain %d %02x:%02x:%02x:%02x (type %02x sub %02x)\n",
+ DVDCSS_BLOCK_SIZE - 0x14 - 4 - 2 - i_pes_length,
+ p_sec[0x14 + i_pes_length + 0],
+ p_sec[0x14 + i_pes_length + 1],
+ p_sec[0x14 + i_pes_length + 2],
+ p_sec[0x14 + i_pes_length + 3],
+ p_sec[0x11], p_sec[0x17 + p_sec[0x16]]);
+ return 0;
+ }
+
+ /* If we are here we know that there is a where in the pack a
+ encrypted PES header is (startcode + length). It's never more
+ than two packets in the pack, so we 'know' the length. The
+ plaintext at offset (0x14 + i_pes_length) will then be
+ 00 00 01 e0/bd/be xx xx, in the case of be the following bytes
+ are also known. */
+
+ /* An encrypted SPU PES packet with another encrypted PES packet following.
+ Normaly if the following was a padding stream that would be in plain
+ text. So it will be another SPU PES packet. */
+ if( p_sec[0x11] == 0xbd &&
+ p_sec[0x17 + p_sec[0x16]] >= 0x20 &&
+ p_sec[0x17 + p_sec[0x16]] <= 0x3f )
+ {
+ i_tries++;
+ }
+
+ /* A Video PES packet with another encrypted PES packet following.
+ * No reason execpt for time stamps to break the data into two packets.
+ * So it's likely that the following PES packet is a padding stream. */
+ if( p_sec[0x11] == 0xe0 )
+ {
+ i_tries++;
+ }
+
+ if( 1 )
+ {
+ /*fprintf( stderr, "key is %02x:%02x:%02x:%02x:%02x ",
+ p_key[0], p_key[1], p_key[2], p_key[3], p_key[4] );*/
+ fprintf( stderr, "at block %5d padding len %4d "
+ "type %02x sub %02x\n", i_pos, i_pes_length,
+ p_sec[0x11], p_sec[0x17 + p_sec[0x16]]);
+ }
+
+ return 0;
+}
+#endif
diff --git a/lib/libdvd/libdvdcss/src/css.h b/lib/libdvd/libdvdcss/src/css.h
new file mode 100644
index 0000000000..03becda17c
--- /dev/null
+++ b/lib/libdvd/libdvdcss/src/css.h
@@ -0,0 +1,56 @@
+/*****************************************************************************
+ * css.h: Structures for DVD authentication and unscrambling
+ *****************************************************************************
+ * Copyright (C) 1999-2001 VideoLAN
+ * $Id$
+ *
+ * Author: Stéphane Borel <stef@via.ecp.fr>
+ *
+ * based on:
+ * - css-auth by Derek Fawcus <derek@spider.com>
+ * - DVD CSS ioctls example program by Andrew T. Veliath <andrewtv@usa.net>
+ * - DeCSSPlus by Ethan Hawke
+ * - The Divide and conquer attack by Frank A. Stevenson <frank@funcom.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ *****************************************************************************/
+#define KEY_SIZE 5
+
+typedef uint8_t dvd_key_t[KEY_SIZE];
+
+typedef struct dvd_title_s
+{
+ int i_startlb;
+ dvd_key_t p_key;
+ struct dvd_title_s *p_next;
+} dvd_title_t;
+
+typedef struct css_s
+{
+ int i_agid; /* Current Authenication Grant ID. */
+ dvd_key_t p_bus_key; /* Current session key. */
+ dvd_key_t p_disc_key; /* This DVD disc's key. */
+ dvd_key_t p_title_key; /* Current title key. */
+} css_t;
+
+/*****************************************************************************
+ * Prototypes in css.c
+ *****************************************************************************/
+int _dvdcss_test ( dvdcss_t );
+int _dvdcss_title ( dvdcss_t, int );
+int _dvdcss_disckey ( dvdcss_t );
+int _dvdcss_titlekey ( dvdcss_t, int , dvd_key_t );
+int _dvdcss_unscramble ( uint8_t *, uint8_t * );
+
diff --git a/lib/libdvd/libdvdcss/src/csstables.h b/lib/libdvd/libdvdcss/src/csstables.h
new file mode 100644
index 0000000000..bd0fc3a706
--- /dev/null
+++ b/lib/libdvd/libdvdcss/src/csstables.h
@@ -0,0 +1,392 @@
+/*****************************************************************************
+ * csstables.h: CSS Tables for DVD unscrambling
+ *****************************************************************************
+ * Copyright (C) 1999-2001 VideoLAN
+ * $Id$
+ *
+ * Author: Stéphane Borel <stef@via.ecp.fr>
+ *
+ * based on:
+ * - css-auth by Derek Fawcus <derek@spider.com>
+ * - DVD CSS ioctls example program by Andrew T. Veliath <andrewtv@usa.net>
+ * - The Divide and conquer attack by Frank A. Stevenson <frank@funcom.com>
+ * - DeCSSPlus by Ethan Hawke
+ * - DecVOB
+ * see http://www.lemuria.org/DeCSS/ by Tom Vogt for more information.
+ *
+ * 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.
+ *****************************************************************************/
+
+
+static uint8_t p_css_tab1[ 256 ] =
+{
+ 0x33, 0x73, 0x3b, 0x26, 0x63, 0x23, 0x6b, 0x76,
+ 0x3e, 0x7e, 0x36, 0x2b, 0x6e, 0x2e, 0x66, 0x7b,
+ 0xd3, 0x93, 0xdb, 0x06, 0x43, 0x03, 0x4b, 0x96,
+ 0xde, 0x9e, 0xd6, 0x0b, 0x4e, 0x0e, 0x46, 0x9b,
+ 0x57, 0x17, 0x5f, 0x82, 0xc7, 0x87, 0xcf, 0x12,
+ 0x5a, 0x1a, 0x52, 0x8f, 0xca, 0x8a, 0xc2, 0x1f,
+ 0xd9, 0x99, 0xd1, 0x00, 0x49, 0x09, 0x41, 0x90,
+ 0xd8, 0x98, 0xd0, 0x01, 0x48, 0x08, 0x40, 0x91,
+ 0x3d, 0x7d, 0x35, 0x24, 0x6d, 0x2d, 0x65, 0x74,
+ 0x3c, 0x7c, 0x34, 0x25, 0x6c, 0x2c, 0x64, 0x75,
+ 0xdd, 0x9d, 0xd5, 0x04, 0x4d, 0x0d, 0x45, 0x94,
+ 0xdc, 0x9c, 0xd4, 0x05, 0x4c, 0x0c, 0x44, 0x95,
+ 0x59, 0x19, 0x51, 0x80, 0xc9, 0x89, 0xc1, 0x10,
+ 0x58, 0x18, 0x50, 0x81, 0xc8, 0x88, 0xc0, 0x11,
+ 0xd7, 0x97, 0xdf, 0x02, 0x47, 0x07, 0x4f, 0x92,
+ 0xda, 0x9a, 0xd2, 0x0f, 0x4a, 0x0a, 0x42, 0x9f,
+ 0x53, 0x13, 0x5b, 0x86, 0xc3, 0x83, 0xcb, 0x16,
+ 0x5e, 0x1e, 0x56, 0x8b, 0xce, 0x8e, 0xc6, 0x1b,
+ 0xb3, 0xf3, 0xbb, 0xa6, 0xe3, 0xa3, 0xeb, 0xf6,
+ 0xbe, 0xfe, 0xb6, 0xab, 0xee, 0xae, 0xe6, 0xfb,
+ 0x37, 0x77, 0x3f, 0x22, 0x67, 0x27, 0x6f, 0x72,
+ 0x3a, 0x7a, 0x32, 0x2f, 0x6a, 0x2a, 0x62, 0x7f,
+ 0xb9, 0xf9, 0xb1, 0xa0, 0xe9, 0xa9, 0xe1, 0xf0,
+ 0xb8, 0xf8, 0xb0, 0xa1, 0xe8, 0xa8, 0xe0, 0xf1,
+ 0x5d, 0x1d, 0x55, 0x84, 0xcd, 0x8d, 0xc5, 0x14,
+ 0x5c, 0x1c, 0x54, 0x85, 0xcc, 0x8c, 0xc4, 0x15,
+ 0xbd, 0xfd, 0xb5, 0xa4, 0xed, 0xad, 0xe5, 0xf4,
+ 0xbc, 0xfc, 0xb4, 0xa5, 0xec, 0xac, 0xe4, 0xf5,
+ 0x39, 0x79, 0x31, 0x20, 0x69, 0x29, 0x61, 0x70,
+ 0x38, 0x78, 0x30, 0x21, 0x68, 0x28, 0x60, 0x71,
+ 0xb7, 0xf7, 0xbf, 0xa2, 0xe7, 0xa7, 0xef, 0xf2,
+ 0xba, 0xfa, 0xb2, 0xaf, 0xea, 0xaa, 0xe2, 0xff
+};
+
+static uint8_t p_css_tab2[ 256 ] =
+{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e,
+ 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
+ 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c,
+ 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23,
+ 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a,
+ 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31,
+ 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
+ 0x49, 0x48, 0x4b, 0x4a, 0x4d, 0x4c, 0x4f, 0x4e,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x5b, 0x5a, 0x59, 0x58, 0x5f, 0x5e, 0x5d, 0x5c,
+ 0x52, 0x53, 0x50, 0x51, 0x56, 0x57, 0x54, 0x55,
+ 0x6d, 0x6c, 0x6f, 0x6e, 0x69, 0x68, 0x6b, 0x6a,
+ 0x64, 0x65, 0x66, 0x67, 0x60, 0x61, 0x62, 0x63,
+ 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78,
+ 0x76, 0x77, 0x74, 0x75, 0x72, 0x73, 0x70, 0x71,
+ 0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95,
+ 0x9b, 0x9a, 0x99, 0x98, 0x9f, 0x9e, 0x9d, 0x9c,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x89, 0x88, 0x8b, 0x8a, 0x8d, 0x8c, 0x8f, 0x8e,
+ 0xb6, 0xb7, 0xb4, 0xb5, 0xb2, 0xb3, 0xb0, 0xb1,
+ 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
+ 0xa4, 0xa5, 0xa6, 0xa7, 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xad, 0xac, 0xaf, 0xae, 0xa9, 0xa8, 0xab, 0xaa,
+ 0xdb, 0xda, 0xd9, 0xd8, 0xdf, 0xde, 0xdd, 0xdc,
+ 0xd2, 0xd3, 0xd0, 0xd1, 0xd6, 0xd7, 0xd4, 0xd5,
+ 0xc9, 0xc8, 0xcb, 0xca, 0xcd, 0xcc, 0xcf, 0xce,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
+ 0xf6, 0xf7, 0xf4, 0xf5, 0xf2, 0xf3, 0xf0, 0xf1,
+ 0xed, 0xec, 0xef, 0xee, 0xe9, 0xe8, 0xeb, 0xea,
+ 0xe4, 0xe5, 0xe6, 0xe7, 0xe0, 0xe1, 0xe2, 0xe3
+};
+
+static uint8_t p_css_tab3[ 512 ] =
+{
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
+ 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff
+};
+
+static uint8_t p_css_tab4[ 256 ] =
+{
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+
+static uint8_t p_css_tab5[ 256 ] =
+{
+ 0xff, 0x7f, 0xbf, 0x3f, 0xdf, 0x5f, 0x9f, 0x1f,
+ 0xef, 0x6f, 0xaf, 0x2f, 0xcf, 0x4f, 0x8f, 0x0f,
+ 0xf7, 0x77, 0xb7, 0x37, 0xd7, 0x57, 0x97, 0x17,
+ 0xe7, 0x67, 0xa7, 0x27, 0xc7, 0x47, 0x87, 0x07,
+ 0xfb, 0x7b, 0xbb, 0x3b, 0xdb, 0x5b, 0x9b, 0x1b,
+ 0xeb, 0x6b, 0xab, 0x2b, 0xcb, 0x4b, 0x8b, 0x0b,
+ 0xf3, 0x73, 0xb3, 0x33, 0xd3, 0x53, 0x93, 0x13,
+ 0xe3, 0x63, 0xa3, 0x23, 0xc3, 0x43, 0x83, 0x03,
+ 0xfd, 0x7d, 0xbd, 0x3d, 0xdd, 0x5d, 0x9d, 0x1d,
+ 0xed, 0x6d, 0xad, 0x2d, 0xcd, 0x4d, 0x8d, 0x0d,
+ 0xf5, 0x75, 0xb5, 0x35, 0xd5, 0x55, 0x95, 0x15,
+ 0xe5, 0x65, 0xa5, 0x25, 0xc5, 0x45, 0x85, 0x05,
+ 0xf9, 0x79, 0xb9, 0x39, 0xd9, 0x59, 0x99, 0x19,
+ 0xe9, 0x69, 0xa9, 0x29, 0xc9, 0x49, 0x89, 0x09,
+ 0xf1, 0x71, 0xb1, 0x31, 0xd1, 0x51, 0x91, 0x11,
+ 0xe1, 0x61, 0xa1, 0x21, 0xc1, 0x41, 0x81, 0x01,
+ 0xfe, 0x7e, 0xbe, 0x3e, 0xde, 0x5e, 0x9e, 0x1e,
+ 0xee, 0x6e, 0xae, 0x2e, 0xce, 0x4e, 0x8e, 0x0e,
+ 0xf6, 0x76, 0xb6, 0x36, 0xd6, 0x56, 0x96, 0x16,
+ 0xe6, 0x66, 0xa6, 0x26, 0xc6, 0x46, 0x86, 0x06,
+ 0xfa, 0x7a, 0xba, 0x3a, 0xda, 0x5a, 0x9a, 0x1a,
+ 0xea, 0x6a, 0xaa, 0x2a, 0xca, 0x4a, 0x8a, 0x0a,
+ 0xf2, 0x72, 0xb2, 0x32, 0xd2, 0x52, 0x92, 0x12,
+ 0xe2, 0x62, 0xa2, 0x22, 0xc2, 0x42, 0x82, 0x02,
+ 0xfc, 0x7c, 0xbc, 0x3c, 0xdc, 0x5c, 0x9c, 0x1c,
+ 0xec, 0x6c, 0xac, 0x2c, 0xcc, 0x4c, 0x8c, 0x0c,
+ 0xf4, 0x74, 0xb4, 0x34, 0xd4, 0x54, 0x94, 0x14,
+ 0xe4, 0x64, 0xa4, 0x24, 0xc4, 0x44, 0x84, 0x04,
+ 0xf8, 0x78, 0xb8, 0x38, 0xd8, 0x58, 0x98, 0x18,
+ 0xe8, 0x68, 0xa8, 0x28, 0xc8, 0x48, 0x88, 0x08,
+ 0xf0, 0x70, 0xb0, 0x30, 0xd0, 0x50, 0x90, 0x10,
+ 0xe0, 0x60, 0xa0, 0x20, 0xc0, 0x40, 0x80, 0x00
+};
+
+static uint8_t p_crypt_tab0[ 256 ] =
+{
+ 0xB7, 0xF4, 0x82, 0x57, 0xDA, 0x4D, 0xDB, 0xE2,
+ 0x2F, 0x52, 0x1A, 0xA8, 0x68, 0x5A, 0x8A, 0xFF,
+ 0xFB, 0x0E, 0x6D, 0x35, 0xF7, 0x5C, 0x76, 0x12,
+ 0xCE, 0x25, 0x79, 0x29, 0x39, 0x62, 0x08, 0x24,
+ 0xA5, 0x85, 0x7B, 0x56, 0x01, 0x23, 0x68, 0xCF,
+ 0x0A, 0xE2, 0x5A, 0xED, 0x3D, 0x59, 0xB0, 0xA9,
+ 0xB0, 0x2C, 0xF2, 0xB8, 0xEF, 0x32, 0xA9, 0x40,
+ 0x80, 0x71, 0xAF, 0x1E, 0xDE, 0x8F, 0x58, 0x88,
+ 0xB8, 0x3A, 0xD0, 0xFC, 0xC4, 0x1E, 0xB5, 0xA0,
+ 0xBB, 0x3B, 0x0F, 0x01, 0x7E, 0x1F, 0x9F, 0xD9,
+ 0xAA, 0xB8, 0x3D, 0x9D, 0x74, 0x1E, 0x25, 0xDB,
+ 0x37, 0x56, 0x8F, 0x16, 0xBA, 0x49, 0x2B, 0xAC,
+ 0xD0, 0xBD, 0x95, 0x20, 0xBE, 0x7A, 0x28, 0xD0,
+ 0x51, 0x64, 0x63, 0x1C, 0x7F, 0x66, 0x10, 0xBB,
+ 0xC4, 0x56, 0x1A, 0x04, 0x6E, 0x0A, 0xEC, 0x9C,
+ 0xD6, 0xE8, 0x9A, 0x7A, 0xCF, 0x8C, 0xDB, 0xB1,
+ 0xEF, 0x71, 0xDE, 0x31, 0xFF, 0x54, 0x3E, 0x5E,
+ 0x07, 0x69, 0x96, 0xB0, 0xCF, 0xDD, 0x9E, 0x47,
+ 0xC7, 0x96, 0x8F, 0xE4, 0x2B, 0x59, 0xC6, 0xEE,
+ 0xB9, 0x86, 0x9A, 0x64, 0x84, 0x72, 0xE2, 0x5B,
+ 0xA2, 0x96, 0x58, 0x99, 0x50, 0x03, 0xF5, 0x38,
+ 0x4D, 0x02, 0x7D, 0xE7, 0x7D, 0x75, 0xA7, 0xB8,
+ 0x67, 0x87, 0x84, 0x3F, 0x1D, 0x11, 0xE5, 0xFC,
+ 0x1E, 0xD3, 0x83, 0x16, 0xA5, 0x29, 0xF6, 0xC7,
+ 0x15, 0x61, 0x29, 0x1A, 0x43, 0x4F, 0x9B, 0xAF,
+ 0xC5, 0x87, 0x34, 0x6C, 0x0F, 0x3B, 0xA8, 0x1D,
+ 0x45, 0x58, 0x25, 0xDC, 0xA8, 0xA3, 0x3B, 0xD1,
+ 0x79, 0x1B, 0x48, 0xF2, 0xE9, 0x93, 0x1F, 0xFC,
+ 0xDB, 0x2A, 0x90, 0xA9, 0x8A, 0x3D, 0x39, 0x18,
+ 0xA3, 0x8E, 0x58, 0x6C, 0xE0, 0x12, 0xBB, 0x25,
+ 0xCD, 0x71, 0x22, 0xA2, 0x64, 0xC6, 0xE7, 0xFB,
+ 0xAD, 0x94, 0x77, 0x04, 0x9A, 0x39, 0xCF, 0x7C
+};
+
+static uint8_t p_crypt_tab1[ 256 ] =
+{
+ 0x8C, 0x47, 0xB0, 0xE1, 0xEB, 0xFC, 0xEB, 0x56,
+ 0x10, 0xE5, 0x2C, 0x1A, 0x5D, 0xEF, 0xBE, 0x4F,
+ 0x08, 0x75, 0x97, 0x4B, 0x0E, 0x25, 0x8E, 0x6E,
+ 0x39, 0x5A, 0x87, 0x53, 0xC4, 0x1F, 0xF4, 0x5C,
+ 0x4E, 0xE6, 0x99, 0x30, 0xE0, 0x42, 0x88, 0xAB,
+ 0xE5, 0x85, 0xBC, 0x8F, 0xD8, 0x3C, 0x54, 0xC9,
+ 0x53, 0x47, 0x18, 0xD6, 0x06, 0x5B, 0x41, 0x2C,
+ 0x67, 0x1E, 0x41, 0x74, 0x33, 0xE2, 0xB4, 0xE0,
+ 0x23, 0x29, 0x42, 0xEA, 0x55, 0x0F, 0x25, 0xB4,
+ 0x24, 0x2C, 0x99, 0x13, 0xEB, 0x0A, 0x0B, 0xC9,
+ 0xF9, 0x63, 0x67, 0x43, 0x2D, 0xC7, 0x7D, 0x07,
+ 0x60, 0x89, 0xD1, 0xCC, 0xE7, 0x94, 0x77, 0x74,
+ 0x9B, 0x7E, 0xD7, 0xE6, 0xFF, 0xBB, 0x68, 0x14,
+ 0x1E, 0xA3, 0x25, 0xDE, 0x3A, 0xA3, 0x54, 0x7B,
+ 0x87, 0x9D, 0x50, 0xCA, 0x27, 0xC3, 0xA4, 0x50,
+ 0x91, 0x27, 0xD4, 0xB0, 0x82, 0x41, 0x97, 0x79,
+ 0x94, 0x82, 0xAC, 0xC7, 0x8E, 0xA5, 0x4E, 0xAA,
+ 0x78, 0x9E, 0xE0, 0x42, 0xBA, 0x28, 0xEA, 0xB7,
+ 0x74, 0xAD, 0x35, 0xDA, 0x92, 0x60, 0x7E, 0xD2,
+ 0x0E, 0xB9, 0x24, 0x5E, 0x39, 0x4F, 0x5E, 0x63,
+ 0x09, 0xB5, 0xFA, 0xBF, 0xF1, 0x22, 0x55, 0x1C,
+ 0xE2, 0x25, 0xDB, 0xC5, 0xD8, 0x50, 0x03, 0x98,
+ 0xC4, 0xAC, 0x2E, 0x11, 0xB4, 0x38, 0x4D, 0xD0,
+ 0xB9, 0xFC, 0x2D, 0x3C, 0x08, 0x04, 0x5A, 0xEF,
+ 0xCE, 0x32, 0xFB, 0x4C, 0x92, 0x1E, 0x4B, 0xFB,
+ 0x1A, 0xD0, 0xE2, 0x3E, 0xDA, 0x6E, 0x7C, 0x4D,
+ 0x56, 0xC3, 0x3F, 0x42, 0xB1, 0x3A, 0x23, 0x4D,
+ 0x6E, 0x84, 0x56, 0x68, 0xF4, 0x0E, 0x03, 0x64,
+ 0xD0, 0xA9, 0x92, 0x2F, 0x8B, 0xBC, 0x39, 0x9C,
+ 0xAC, 0x09, 0x5E, 0xEE, 0xE5, 0x97, 0xBF, 0xA5,
+ 0xCE, 0xFA, 0x28, 0x2C, 0x6D, 0x4F, 0xEF, 0x77,
+ 0xAA, 0x1B, 0x79, 0x8E, 0x97, 0xB4, 0xC3, 0xF4
+};
+
+static uint8_t p_crypt_tab2[ 256 ] =
+{
+ 0xB7, 0x75, 0x81, 0xD5, 0xDC, 0xCA, 0xDE, 0x66,
+ 0x23, 0xDF, 0x15, 0x26, 0x62, 0xD1, 0x83, 0x77,
+ 0xE3, 0x97, 0x76, 0xAF, 0xE9, 0xC3, 0x6B, 0x8E,
+ 0xDA, 0xB0, 0x6E, 0xBF, 0x2B, 0xF1, 0x19, 0xB4,
+ 0x95, 0x34, 0x48, 0xE4, 0x37, 0x94, 0x5D, 0x7B,
+ 0x36, 0x5F, 0x65, 0x53, 0x07, 0xE2, 0x89, 0x11,
+ 0x98, 0x85, 0xD9, 0x12, 0xC1, 0x9D, 0x84, 0xEC,
+ 0xA4, 0xD4, 0x88, 0xB8, 0xFC, 0x2C, 0x79, 0x28,
+ 0xD8, 0xDB, 0xB3, 0x1E, 0xA2, 0xF9, 0xD0, 0x44,
+ 0xD7, 0xD6, 0x60, 0xEF, 0x14, 0xF4, 0xF6, 0x31,
+ 0xD2, 0x41, 0x46, 0x67, 0x0A, 0xE1, 0x58, 0x27,
+ 0x43, 0xA3, 0xF8, 0xE0, 0xC8, 0xBA, 0x5A, 0x5C,
+ 0x80, 0x6C, 0xC6, 0xF2, 0xE8, 0xAD, 0x7D, 0x04,
+ 0x0D, 0xB9, 0x3C, 0xC2, 0x25, 0xBD, 0x49, 0x63,
+ 0x8C, 0x9F, 0x51, 0xCE, 0x20, 0xC5, 0xA1, 0x50,
+ 0x92, 0x2D, 0xDD, 0xBC, 0x8D, 0x4F, 0x9A, 0x71,
+ 0x2F, 0x30, 0x1D, 0x73, 0x39, 0x13, 0xFB, 0x1A,
+ 0xCB, 0x24, 0x59, 0xFE, 0x05, 0x96, 0x57, 0x0F,
+ 0x1F, 0xCF, 0x54, 0xBE, 0xF5, 0x06, 0x1B, 0xB2,
+ 0x6D, 0xD3, 0x4D, 0x32, 0x56, 0x21, 0x33, 0x0B,
+ 0x52, 0xE7, 0xAB, 0xEB, 0xA6, 0x74, 0x00, 0x4C,
+ 0xB1, 0x7F, 0x82, 0x99, 0x87, 0x0E, 0x5E, 0xC0,
+ 0x8F, 0xEE, 0x6F, 0x55, 0xF3, 0x7E, 0x08, 0x90,
+ 0xFA, 0xB6, 0x64, 0x70, 0x47, 0x4A, 0x17, 0xA7,
+ 0xB5, 0x40, 0x8A, 0x38, 0xE5, 0x68, 0x3E, 0x8B,
+ 0x69, 0xAA, 0x9B, 0x42, 0xA5, 0x10, 0x01, 0x35,
+ 0xFD, 0x61, 0x9E, 0xE6, 0x16, 0x9C, 0x86, 0xED,
+ 0xCD, 0x2E, 0xFF, 0xC4, 0x5B, 0xA0, 0xAE, 0xCC,
+ 0x4B, 0x3B, 0x03, 0xBB, 0x1C, 0x2A, 0xAC, 0x0C,
+ 0x3F, 0x93, 0xC7, 0x72, 0x7A, 0x09, 0x22, 0x3D,
+ 0x45, 0x78, 0xA9, 0xA8, 0xEA, 0xC9, 0x6A, 0xF7,
+ 0x29, 0x91, 0xF0, 0x02, 0x18, 0x3A, 0x4E, 0x7C
+};
+
+static uint8_t p_crypt_tab3[ 288 ] =
+{
+ 0x73, 0x51, 0x95, 0xE1, 0x12, 0xE4, 0xC0, 0x58,
+ 0xEE, 0xF2, 0x08, 0x1B, 0xA9, 0xFA, 0x98, 0x4C,
+ 0xA7, 0x33, 0xE2, 0x1B, 0xA7, 0x6D, 0xF5, 0x30,
+ 0x97, 0x1D, 0xF3, 0x02, 0x60, 0x5A, 0x82, 0x0F,
+ 0x91, 0xD0, 0x9C, 0x10, 0x39, 0x7A, 0x83, 0x85,
+ 0x3B, 0xB2, 0xB8, 0xAE, 0x0C, 0x09, 0x52, 0xEA,
+ 0x1C, 0xE1, 0x8D, 0x66, 0x4F, 0xF3, 0xDA, 0x92,
+ 0x29, 0xB9, 0xD5, 0xC5, 0x77, 0x47, 0x22, 0x53,
+ 0x14, 0xF7, 0xAF, 0x22, 0x64, 0xDF, 0xC6, 0x72,
+ 0x12, 0xF3, 0x75, 0xDA, 0xD7, 0xD7, 0xE5, 0x02,
+ 0x9E, 0xED, 0xDA, 0xDB, 0x4C, 0x47, 0xCE, 0x91,
+ 0x06, 0x06, 0x6D, 0x55, 0x8B, 0x19, 0xC9, 0xEF,
+ 0x8C, 0x80, 0x1A, 0x0E, 0xEE, 0x4B, 0xAB, 0xF2,
+ 0x08, 0x5C, 0xE9, 0x37, 0x26, 0x5E, 0x9A, 0x90,
+ 0x00, 0xF3, 0x0D, 0xB2, 0xA6, 0xA3, 0xF7, 0x26,
+ 0x17, 0x48, 0x88, 0xC9, 0x0E, 0x2C, 0xC9, 0x02,
+ 0xE7, 0x18, 0x05, 0x4B, 0xF3, 0x39, 0xE1, 0x20,
+ 0x02, 0x0D, 0x40, 0xC7, 0xCA, 0xB9, 0x48, 0x30,
+ 0x57, 0x67, 0xCC, 0x06, 0xBF, 0xAC, 0x81, 0x08,
+ 0x24, 0x7A, 0xD4, 0x8B, 0x19, 0x8E, 0xAC, 0xB4,
+ 0x5A, 0x0F, 0x73, 0x13, 0xAC, 0x9E, 0xDA, 0xB6,
+ 0xB8, 0x96, 0x5B, 0x60, 0x88, 0xE1, 0x81, 0x3F,
+ 0x07, 0x86, 0x37, 0x2D, 0x79, 0x14, 0x52, 0xEA,
+ 0x73, 0xDF, 0x3D, 0x09, 0xC8, 0x25, 0x48, 0xD8,
+ 0x75, 0x60, 0x9A, 0x08, 0x27, 0x4A, 0x2C, 0xB9,
+ 0xA8, 0x8B, 0x8A, 0x73, 0x62, 0x37, 0x16, 0x02,
+ 0xBD, 0xC1, 0x0E, 0x56, 0x54, 0x3E, 0x14, 0x5F,
+ 0x8C, 0x8F, 0x6E, 0x75, 0x1C, 0x07, 0x39, 0x7B,
+ 0x4B, 0xDB, 0xD3, 0x4B, 0x1E, 0xC8, 0x7E, 0xFE,
+ 0x3E, 0x72, 0x16, 0x83, 0x7D, 0xEE, 0xF5, 0xCA,
+ 0xC5, 0x18, 0xF9, 0xD8, 0x68, 0xAB, 0x38, 0x85,
+ 0xA8, 0xF0, 0xA1, 0x73, 0x9F, 0x5D, 0x19, 0x0B,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x33, 0x72, 0x39, 0x25, 0x67, 0x26, 0x6D, 0x71,
+ 0x36, 0x77, 0x3C, 0x20, 0x62, 0x23, 0x68, 0x74,
+ 0xC3, 0x82, 0xC9, 0x15, 0x57, 0x16, 0x5D, 0x81
+};
+
diff --git a/lib/libdvd/libdvdcss/src/device.c b/lib/libdvd/libdvdcss/src/device.c
new file mode 100644
index 0000000000..45d6f0d3d2
--- /dev/null
+++ b/lib/libdvd/libdvdcss/src/device.c
@@ -0,0 +1,1086 @@
+/*****************************************************************************
+ * device.h: DVD device access
+ *****************************************************************************
+ * Copyright (C) 1998-2006 VideoLAN
+ * $Id$
+ *
+ * Authors: Stéphane Borel <stef@via.ecp.fr>
+ * Sam Hocevar <sam@zoy.org>
+ * 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, USA.
+ *****************************************************************************/
+
+/*
+ Modifications for XBMC are all contained within _XBOX (real xbox hardware) or WITH_CACHE
+*/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_ERRNO_H
+# include <errno.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+#include <fcntl.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#if defined( WIN32 ) && !defined( SYS_CYGWIN )
+# include <io.h> /* read() */
+#else
+# include <sys/uio.h> /* struct iovec */
+#endif
+
+#ifdef DARWIN_DVD_IOCTL
+# include <paths.h>
+# include <CoreFoundation/CoreFoundation.h>
+# include <IOKit/IOKitLib.h>
+# include <IOKit/IOBSD.h>
+# include <IOKit/storage/IOMedia.h>
+# include <IOKit/storage/IOCDMedia.h>
+# include <IOKit/storage/IODVDMedia.h>
+#endif
+
+#include "dvdcss/dvdcss.h"
+
+#include "common.h"
+#include "css.h"
+#include "libdvdcss.h"
+#include "ioctl.h"
+#include "device.h"
+
+/*****************************************************************************
+ * Device reading prototypes
+ *****************************************************************************/
+static int libc_open ( dvdcss_t, char const * );
+static int libc_seek ( dvdcss_t, int );
+static int libc_read ( dvdcss_t, void *, int );
+static int libc_readv ( dvdcss_t, struct iovec *, int );
+
+#ifdef WIN32
+static int win2k_open ( dvdcss_t, char const * );
+static int aspi_open ( dvdcss_t, char const * );
+static int win2k_seek ( dvdcss_t, int );
+static int aspi_seek ( dvdcss_t, int );
+static int win2k_read ( dvdcss_t, void *, int );
+static int aspi_read ( dvdcss_t, void *, int );
+static int win_readv ( dvdcss_t, struct iovec *, int );
+
+static int aspi_read_internal ( int, void *, int );
+#endif
+
+int _dvdcss_use_ioctls( dvdcss_t dvdcss )
+{
+#if defined( WIN32 )
+ if( dvdcss->b_file )
+ {
+ return 0;
+ }
+
+ /* FIXME: implement this for Windows */
+ if( WIN2K )
+ {
+ return 1;
+ }
+ else
+ {
+ return 1;
+ }
+#else
+ struct stat fileinfo;
+ int ret;
+
+ ret = fstat( dvdcss->i_fd, &fileinfo );
+ if( ret < 0 )
+ {
+ return 1; /* What to do? Be conservative and try to use the ioctls */
+ }
+
+ /* Complete this list and check that we test for the right things
+ * (I've assumed for all OSs that 'r', (raw) device, are char devices
+ * and those that don't contain/use an 'r' in the name are block devices)
+ *
+ * Linux needs a block device
+ * Solaris needs a char device
+ * Darwin needs a char device
+ * OpenBSD needs a char device
+ * NetBSD needs a char device
+ * FreeBSD can use either the block or the char device
+ * BSD/OS can use either the block or the char device
+ */
+
+ /* Check if this is a block/char device */
+ if( S_ISBLK( fileinfo.st_mode ) ||
+ S_ISCHR( fileinfo.st_mode ) )
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+#endif
+}
+
+void _dvdcss_check ( dvdcss_t dvdcss )
+{
+#if defined( WIN32 )
+ DWORD drives;
+ int i;
+#elif defined( DARWIN_DVD_IOCTL )
+ io_object_t next_media;
+ mach_port_t master_port;
+ kern_return_t kern_result;
+ io_iterator_t media_iterator;
+ CFMutableDictionaryRef classes_to_match;
+#else
+ char *ppsz_devices[] = { "/dev/dvd", "/dev/cdrom", "/dev/hdc", NULL };
+ int i, i_fd;
+#endif
+
+ /* If the device name is non-null, return */
+ if( dvdcss->psz_device[0] )
+ {
+ return;
+ }
+
+#if defined( WIN32 )
+ drives = GetLogicalDrives();
+
+ for( i = 0; drives; i++ )
+ {
+ char psz_device[5];
+ DWORD cur = 1 << i;
+ UINT i_ret;
+
+ if( (drives & cur) == 0 )
+ {
+ continue;
+ }
+ drives &= ~cur;
+
+ sprintf( psz_device, "%c:\\", 'A' + i );
+ i_ret = GetDriveType( psz_device );
+ if( i_ret != DRIVE_CDROM )
+ {
+ continue;
+ }
+
+ /* Remove trailing backslash */
+ psz_device[2] = '\0';
+
+ /* FIXME: we want to differenciate between CD and DVD drives
+ * using DeviceIoControl() */
+ print_debug( dvdcss, "defaulting to drive `%s'", psz_device );
+ free( dvdcss->psz_device );
+ dvdcss->psz_device = strdup( psz_device );
+ return;
+ }
+#elif defined( DARWIN_DVD_IOCTL )
+
+ kern_result = IOMasterPort( MACH_PORT_NULL, &master_port );
+ if( kern_result != KERN_SUCCESS )
+ {
+ return;
+ }
+
+ classes_to_match = IOServiceMatching( kIODVDMediaClass );
+ if( classes_to_match == NULL )
+ {
+ return;
+ }
+
+ CFDictionarySetValue( classes_to_match, CFSTR( kIOMediaEjectableKey ),
+ kCFBooleanTrue );
+
+ kern_result = IOServiceGetMatchingServices( master_port, classes_to_match,
+ &media_iterator );
+ if( kern_result != KERN_SUCCESS )
+ {
+ return;
+ }
+
+ next_media = IOIteratorNext( media_iterator );
+ for( ; ; )
+ {
+ char psz_buf[0x32];
+ size_t i_pathlen;
+ CFTypeRef psz_path;
+
+ next_media = IOIteratorNext( media_iterator );
+ if( next_media == 0 )
+ {
+ break;
+ }
+
+ psz_path = IORegistryEntryCreateCFProperty( next_media,
+ CFSTR( kIOBSDNameKey ),
+ kCFAllocatorDefault,
+ 0 );
+ if( psz_path == NULL )
+ {
+ IOObjectRelease( next_media );
+ continue;
+ }
+
+ snprintf( psz_buf, sizeof(psz_buf), "%s%c", _PATH_DEV, 'r' );
+ i_pathlen = strlen( psz_buf );
+
+ if( CFStringGetCString( psz_path,
+ (char*)&psz_buf + i_pathlen,
+ sizeof(psz_buf) - i_pathlen,
+ kCFStringEncodingASCII ) )
+ {
+ print_debug( dvdcss, "defaulting to drive `%s'", psz_buf );
+ CFRelease( psz_path );
+ IOObjectRelease( next_media );
+ IOObjectRelease( media_iterator );
+ free( dvdcss->psz_device );
+ dvdcss->psz_device = strdup( psz_buf );
+ return;
+ }
+
+ CFRelease( psz_path );
+
+ IOObjectRelease( next_media );
+ }
+
+ IOObjectRelease( media_iterator );
+#else
+ for( i = 0; ppsz_devices[i]; i++ )
+ {
+ i_fd = open( ppsz_devices[i], 0 );
+ if( i_fd != -1 )
+ {
+ print_debug( dvdcss, "defaulting to drive `%s'", ppsz_devices[i] );
+ close( i_fd );
+ free( dvdcss->psz_device );
+ dvdcss->psz_device = strdup( ppsz_devices[i] );
+ return;
+ }
+ }
+#endif
+
+ print_error( dvdcss, "could not find a suitable default drive" );
+}
+
+int _dvdcss_open ( dvdcss_t dvdcss )
+{
+ char const *psz_device = dvdcss->psz_device;
+
+ print_debug( dvdcss, "opening target `%s'", psz_device );
+
+#if defined( WIN32 )
+ dvdcss->b_file = 1;
+#if defined( _XBOX )
+ // If we've passed over the device string make sure we don't try
+ // to use file based handling (libc) - we want Win2k routines ...
+ if (!stricmp(psz_device, "\\Device\\Cdrom0"))
+ dvdcss->b_file = 0;
+ else
+ dvdcss->b_file = stricmp(psz_device, "D:");
+#else
+ /* If device is "X:" or "X:\", we are not actually opening a file. */
+ if (psz_device[0] && psz_device[1] == ':' &&
+ (!psz_device[2] || (psz_device[2] == '\\' && !psz_device[3])))
+ dvdcss->b_file = 0;
+
+#endif // _XBOX
+ /* Initialize readv temporary buffer */
+ dvdcss->p_readv_buffer = NULL;
+ dvdcss->i_readv_buf_size = 0;
+
+ if( !dvdcss->b_file && WIN2K )
+ {
+ print_debug( dvdcss, "using Win2K API for access" );
+ dvdcss->pf_seek = win2k_seek;
+ dvdcss->pf_read = win2k_read;
+ dvdcss->pf_readv = win_readv;
+ return win2k_open( dvdcss, psz_device );
+ }
+ else if( !dvdcss->b_file )
+ {
+ print_debug( dvdcss, "using ASPI for access" );
+ dvdcss->pf_seek = aspi_seek;
+ dvdcss->pf_read = aspi_read;
+ dvdcss->pf_readv = win_readv;
+ return aspi_open( dvdcss, psz_device );
+ }
+ else
+#endif
+ {
+ print_debug( dvdcss, "using libc for access" );
+ dvdcss->pf_seek = libc_seek;
+ dvdcss->pf_read = libc_read;
+ dvdcss->pf_readv = libc_readv;
+ return libc_open( dvdcss, psz_device );
+ }
+}
+
+#ifndef WIN32
+int _dvdcss_raw_open ( dvdcss_t dvdcss, char const *psz_device )
+{
+ dvdcss->i_raw_fd = open( psz_device, 0 );
+
+ if( dvdcss->i_raw_fd == -1 )
+ {
+ print_debug( dvdcss, "cannot open %s (%s)",
+ psz_device, strerror(errno) );
+ print_error( dvdcss, "failed to open raw device, but continuing" );
+ return -1;
+ }
+ else
+ {
+ dvdcss->i_read_fd = dvdcss->i_raw_fd;
+ }
+
+ return 0;
+}
+#endif
+
+int _dvdcss_close ( dvdcss_t dvdcss )
+{
+#if defined( WIN32 )
+ if( dvdcss->b_file )
+ {
+ close( dvdcss->i_fd );
+ }
+ else if( WIN2K )
+ {
+ CloseHandle( (HANDLE) dvdcss->i_fd );
+ }
+ else /* ASPI */
+ {
+#if !defined(_XBOX)
+ struct w32_aspidev *fd = (struct w32_aspidev *) dvdcss->i_fd;
+
+ /* Unload aspi and free w32_aspidev structure */
+ FreeLibrary( (HMODULE) fd->hASPI );
+ free( (void*) dvdcss->i_fd );
+#endif // !_XBOX
+ }
+
+ /* Free readv temporary buffer */
+ if( dvdcss->p_readv_buffer )
+ {
+ free( dvdcss->p_readv_buffer );
+ dvdcss->p_readv_buffer = NULL;
+ dvdcss->i_readv_buf_size = 0;
+ }
+
+ return 0;
+#else
+ close( dvdcss->i_fd );
+
+ if( dvdcss->i_raw_fd >= 0 )
+ {
+ close( dvdcss->i_raw_fd );
+ dvdcss->i_raw_fd = -1;
+ }
+
+ return 0;
+#endif
+}
+
+/* Following functions are local */
+
+/*****************************************************************************
+ * Open commands.
+ *****************************************************************************/
+static int libc_open ( dvdcss_t dvdcss, char const *psz_device )
+{
+#if !defined( WIN32 )
+ dvdcss->i_fd = dvdcss->i_read_fd = open( psz_device, 0 );
+#else
+ dvdcss->i_fd = dvdcss->i_read_fd = open( psz_device, O_BINARY );
+#endif
+
+ if( dvdcss->i_fd == -1 )
+ {
+ print_debug( dvdcss, "cannot open %s (%s)",
+ psz_device, strerror(errno) );
+ print_error( dvdcss, "failed to open device" );
+ return -1;
+ }
+
+ dvdcss->i_pos = 0;
+
+ return 0;
+}
+
+#if defined( WIN32 )
+static int win2k_open ( dvdcss_t dvdcss, char const *psz_device )
+{
+#ifdef _XBOX
+ char psz_dvd[70];
+ strcpy(psz_dvd, "cdrom0:");
+#else
+ char psz_dvd[7];
+ _snprintf( psz_dvd, 7, "\\\\.\\%c:", psz_device[0] );
+
+#endif
+ /* To work around an M$ bug in IOCTL_DVD_READ_STRUCTURE, we need read
+ * _and_ write access to the device (so we can make SCSI Pass Through
+ * Requests). Unfortunately this is only allowed if you have
+ * administrator priviledges so we allow for a fallback method with
+ * only read access to the device (in this case ioctl_ReadCopyright()
+ * won't send back the right result).
+ * (See Microsoft Q241374: Read and Write Access Required for SCSI
+ * Pass Through Requests) */
+
+#ifdef WITH_CACHE
+ DWORD flags = FILE_FLAG_NO_BUFFERING; /* we handle buffering ourself */
+#else
+ DWORD flags = FILE_FLAG_RANDOM_ACCESS;
+#endif //!_XBOX
+
+ dvdcss->i_fd = (int)
+ CreateFile( psz_dvd, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING,
+ flags, NULL );
+
+ if( (HANDLE) dvdcss->i_fd == INVALID_HANDLE_VALUE )
+ dvdcss->i_fd = (int)
+ CreateFile( psz_dvd, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING,
+ flags, NULL );
+
+ if( (HANDLE) dvdcss->i_fd == INVALID_HANDLE_VALUE )
+ {
+ print_error( dvdcss, "failed opening device" );
+ return -1;
+ }
+
+ dvdcss->i_pos = 0;
+
+ return 0;
+}
+
+static int aspi_open( dvdcss_t dvdcss, char const * psz_device )
+{
+ HMODULE hASPI;
+ DWORD dwSupportInfo;
+ struct w32_aspidev *fd;
+ int i, j, i_hostadapters;
+ GETASPI32SUPPORTINFO lpGetSupport;
+ SENDASPI32COMMAND lpSendCommand;
+ char c_drive = psz_device[0];
+
+ /* load aspi and init w32_aspidev structure */
+ hASPI = LoadLibrary( "wnaspi32.dll" );
+ if( hASPI == NULL )
+ {
+ print_error( dvdcss, "unable to load wnaspi32.dll" );
+ return -1;
+ }
+
+ lpGetSupport = (GETASPI32SUPPORTINFO) GetProcAddress( hASPI, "GetASPI32SupportInfo" );
+ lpSendCommand = (SENDASPI32COMMAND) GetProcAddress( hASPI, "SendASPI32Command" );
+
+ if(lpGetSupport == NULL || lpSendCommand == NULL )
+ {
+ print_error( dvdcss, "unable to get aspi function pointers" );
+ FreeLibrary( hASPI );
+ return -1;
+ }
+
+ dwSupportInfo = lpGetSupport();
+
+ if( HIBYTE( LOWORD ( dwSupportInfo ) ) == SS_NO_ADAPTERS )
+ {
+ print_error( dvdcss, "no ASPI adapters found" );
+ FreeLibrary( hASPI );
+ return -1;
+ }
+
+ if( HIBYTE( LOWORD ( dwSupportInfo ) ) != SS_COMP )
+ {
+ print_error( dvdcss, "unable to initalize aspi layer" );
+ FreeLibrary( hASPI );
+ return -1;
+ }
+
+ i_hostadapters = LOBYTE( LOWORD( dwSupportInfo ) );
+ if( i_hostadapters == 0 )
+ {
+ print_error( dvdcss, "no ASPI adapters ready" );
+ FreeLibrary( hASPI );
+ return -1;
+ }
+
+ fd = malloc( sizeof( struct w32_aspidev ) );
+ if( fd == NULL )
+ {
+ print_error( dvdcss, "not enough memory" );
+ FreeLibrary( hASPI );
+ return -1;
+ }
+
+ fd->i_blocks = 0;
+ fd->hASPI = (long) hASPI;
+ fd->lpSendCommand = lpSendCommand;
+
+ c_drive = c_drive > 'Z' ? c_drive - 'a' : c_drive - 'A';
+
+ for( i = 0; i < i_hostadapters; i++ )
+ {
+ for( j = 0; j < 15; j++ )
+ {
+ struct SRB_GetDiskInfo srbDiskInfo;
+
+ srbDiskInfo.SRB_Cmd = SC_GET_DISK_INFO;
+ srbDiskInfo.SRB_HaId = i;
+ srbDiskInfo.SRB_Flags = 0;
+ srbDiskInfo.SRB_Hdr_Rsvd = 0;
+ srbDiskInfo.SRB_Target = j;
+ srbDiskInfo.SRB_Lun = 0;
+
+ lpSendCommand( (void*) &srbDiskInfo );
+
+ if( (srbDiskInfo.SRB_Status == SS_COMP) &&
+ (srbDiskInfo.SRB_Int13HDriveInfo == c_drive) )
+ {
+ /* Make sure this is a cdrom device */
+ struct SRB_GDEVBlock srbGDEVBlock;
+
+ memset( &srbGDEVBlock, 0, sizeof(struct SRB_GDEVBlock) );
+ srbGDEVBlock.SRB_Cmd = SC_GET_DEV_TYPE;
+ srbGDEVBlock.SRB_HaId = i;
+ srbGDEVBlock.SRB_Target = j;
+
+ lpSendCommand( (void*) &srbGDEVBlock );
+
+ if( ( srbGDEVBlock.SRB_Status == SS_COMP ) &&
+ ( srbGDEVBlock.SRB_DeviceType == DTYPE_CDROM ) )
+ {
+ fd->i_sid = MAKEWORD( i, j );
+ dvdcss->i_fd = (int) fd;
+ dvdcss->i_pos = 0;
+ return 0;
+ }
+ else
+ {
+ free( (void*) fd );
+ FreeLibrary( hASPI );
+ print_error( dvdcss,"this is not a cdrom drive" );
+ return -1;
+ }
+ }
+ }
+ }
+
+ free( (void*) fd );
+ FreeLibrary( hASPI );
+ print_error( dvdcss, "unable to get haid and target (aspi)" );
+ return -1;
+}
+#endif
+
+/*****************************************************************************
+ * Seek commands.
+ *****************************************************************************/
+static int libc_seek( dvdcss_t dvdcss, int i_blocks )
+{
+ off_t i_seek;
+
+ if( dvdcss->i_pos == i_blocks )
+ {
+ /* We are already in position */
+ return i_blocks;
+ }
+
+ i_seek = (off_t)i_blocks * (off_t)DVDCSS_BLOCK_SIZE;
+ i_seek = lseek( dvdcss->i_read_fd, i_seek, SEEK_SET );
+
+ if( i_seek < 0 )
+ {
+ print_error( dvdcss, "seek error" );
+ dvdcss->i_pos = -1;
+ return i_seek;
+ }
+
+ dvdcss->i_pos = i_seek / DVDCSS_BLOCK_SIZE;
+
+ return dvdcss->i_pos;
+}
+
+#if defined( WIN32 )
+static int win2k_seek( dvdcss_t dvdcss, int i_blocks )
+{
+ LARGE_INTEGER li_seek;
+#ifdef WITH_CACHE
+ int iBytesToSkip;
+#endif
+
+#ifndef INVALID_SET_FILE_POINTER
+# define INVALID_SET_FILE_POINTER ((DWORD)-1)
+#endif
+
+ if( dvdcss->i_pos == i_blocks )
+ {
+ /* We are already in position */
+ return i_blocks;
+ }
+
+#ifdef WITH_CACHE
+
+ // if our buffer contains the position which we want to seek too, we can
+ // just decrease dwCacheBufferSize
+ iBytesToSkip = (i_blocks - dvdcss->i_pos) * DVDCSS_BLOCK_SIZE;
+ if (iBytesToSkip > 0 && iBytesToSkip < dvdcss->buffer_size)
+ {
+ dvdcss->buffer_size -= iBytesToSkip;
+ dvdcss->i_pos = i_blocks;
+ return dvdcss->i_pos;
+ }
+ else if (iBytesToSkip < 0 && (DISC_CACHE_SIZE - dvdcss->buffer_size) >= -iBytesToSkip)
+ {
+ // we want to seek backwards, and we have enough old data in our buffer
+ dvdcss->buffer_size -= iBytesToSkip; // since iBytesToSkip is negative, dwCacheBufferSize will get bigger
+ dvdcss->i_pos = i_blocks;
+ return dvdcss->i_pos;
+ }
+ else dvdcss->buffer_size = 0;
+
+#endif
+
+ li_seek.QuadPart = (LONGLONG)i_blocks * DVDCSS_BLOCK_SIZE;
+
+ li_seek.LowPart = SetFilePointer( (HANDLE) dvdcss->i_fd,
+ li_seek.LowPart,
+ &li_seek.HighPart, FILE_BEGIN );
+ if( (li_seek.LowPart == INVALID_SET_FILE_POINTER)
+ && GetLastError() != NO_ERROR)
+ {
+ dvdcss->i_pos = -1;
+ return -1;
+ }
+
+ dvdcss->i_pos = li_seek.QuadPart / DVDCSS_BLOCK_SIZE;
+
+ return dvdcss->i_pos;
+}
+
+static int aspi_seek( dvdcss_t dvdcss, int i_blocks )
+{
+ int i_old_blocks;
+ char sz_buf[ DVDCSS_BLOCK_SIZE ];
+ struct w32_aspidev *fd = (struct w32_aspidev *) dvdcss->i_fd;
+
+ if( dvdcss->i_pos == i_blocks )
+ {
+ /* We are already in position */
+ return i_blocks;
+ }
+
+ i_old_blocks = fd->i_blocks;
+ fd->i_blocks = i_blocks;
+
+ if( aspi_read_internal( dvdcss->i_fd, sz_buf, 1 ) == -1 )
+ {
+ fd->i_blocks = i_old_blocks;
+ dvdcss->i_pos = -1;
+ return -1;
+ }
+
+ (fd->i_blocks)--;
+
+ dvdcss->i_pos = fd->i_blocks;
+
+ return dvdcss->i_pos;
+}
+#endif
+
+/*****************************************************************************
+ * Read commands.
+ *****************************************************************************/
+static int libc_read ( dvdcss_t dvdcss, void *p_buffer, int i_blocks )
+{
+ off_t i_size, i_ret;
+
+ i_size = (off_t)i_blocks * (off_t)DVDCSS_BLOCK_SIZE;
+ i_ret = read( dvdcss->i_read_fd, p_buffer, i_size );
+
+ if( i_ret < 0 )
+ {
+ print_error( dvdcss, "read error" );
+ dvdcss->i_pos = -1;
+ return i_ret;
+ }
+
+ /* Handle partial reads */
+ if( i_ret != i_size )
+ {
+ int i_seek;
+
+ dvdcss->i_pos = -1;
+ i_seek = libc_seek( dvdcss, i_ret / DVDCSS_BLOCK_SIZE );
+ if( i_seek < 0 )
+ {
+ return i_seek;
+ }
+
+ /* We have to return now so that i_pos isn't clobbered */
+ return i_ret / DVDCSS_BLOCK_SIZE;
+ }
+
+ dvdcss->i_pos += i_ret / DVDCSS_BLOCK_SIZE;
+ return i_ret / DVDCSS_BLOCK_SIZE;
+}
+
+#if defined( WIN32 )
+static int win2k_read ( dvdcss_t dvdcss, void *p_buffer, int i_blocks )
+{
+ int i_bytes;
+
+#ifdef WITH_CACHE
+
+ if (dvdcss->buffer_size < i_blocks * DVDCSS_BLOCK_SIZE)
+ {
+ // we don't have enough data in our buffer
+ int iRemaining = i_blocks * DVDCSS_BLOCK_SIZE;
+ int iCopied = 0;
+ // copy data we already have and read again into the cache
+ if (dvdcss->buffer_size > 0) memcpy(p_buffer, dvdcss->buffer + (DISC_CACHE_SIZE - dvdcss->buffer_size), dvdcss->buffer_size);
+ iCopied = dvdcss->buffer_size;
+ iRemaining -= dvdcss->buffer_size;
+ (BYTE*)p_buffer += iCopied;
+ dvdcss->buffer_size = 0;
+
+ // if remaining size is bigger >= DISC_CACHE_SIZE, don't cache it. Just read
+ if (iRemaining >= DISC_CACHE_SIZE)
+ {
+ if (!ReadFile((HANDLE)dvdcss->i_fd, p_buffer, iRemaining, (LPDWORD)&i_bytes, NULL))
+ {
+ dvdcss->i_pos = -1;
+ return -1;
+ }
+ dvdcss->i_pos += (i_bytes + iCopied) / DVDCSS_BLOCK_SIZE;
+ return (i_bytes + iCopied) / DVDCSS_BLOCK_SIZE;
+ }
+ else
+ {
+ // read a chunk into the cache and copy the needed bytes into p_buffer
+ if (!ReadFile((HANDLE)dvdcss->i_fd, dvdcss->buffer, DISC_CACHE_SIZE, &dvdcss->buffer_size, NULL))
+ {
+ // read error, maybe we tried to read to much. Try again but now without cache
+ if (!ReadFile((HANDLE)dvdcss->i_fd, p_buffer, iRemaining, (LPDWORD)&i_bytes, NULL))
+ {
+ dvdcss->i_pos = -1;
+ return -1;
+ }
+ dvdcss->i_pos += (i_bytes + iCopied) / DVDCSS_BLOCK_SIZE;
+ return (i_bytes + iCopied) / DVDCSS_BLOCK_SIZE;
+ }
+ // copy bytes into the buffer
+ memcpy(p_buffer, dvdcss->buffer, iRemaining);
+ dvdcss->buffer_size -= iRemaining;
+ dvdcss->i_pos += (iRemaining + iCopied) / DVDCSS_BLOCK_SIZE;
+ return (iRemaining + iCopied) / DVDCSS_BLOCK_SIZE;
+ }
+ }
+ else
+ {
+ // we have enough data in our cache, just copy it
+ memcpy(p_buffer, dvdcss->buffer + (DISC_CACHE_SIZE - dvdcss->buffer_size), i_blocks * DVDCSS_BLOCK_SIZE);
+ dvdcss->buffer_size -= i_blocks * DVDCSS_BLOCK_SIZE;
+ dvdcss->i_pos += i_blocks;
+ return i_blocks;
+ }
+
+ dvdcss->i_pos = -1;
+ return -1;
+
+#else // WITH_CACHE
+
+ if( !ReadFile( (HANDLE) dvdcss->i_fd, p_buffer,
+ i_blocks * DVDCSS_BLOCK_SIZE,
+ (LPDWORD)&i_bytes, NULL ) )
+ {
+ dvdcss->i_pos = -1;
+ return -1;
+ }
+
+ dvdcss->i_pos += i_bytes / DVDCSS_BLOCK_SIZE;
+ return i_bytes / DVDCSS_BLOCK_SIZE;
+#endif // WITH_CACHE
+}
+
+static int aspi_read ( dvdcss_t dvdcss, void *p_buffer, int i_blocks )
+{
+ int i_read = aspi_read_internal( dvdcss->i_fd, p_buffer, i_blocks );
+
+ if( i_read < 0 )
+ {
+ dvdcss->i_pos = -1;
+ return i_read;
+ }
+
+ dvdcss->i_pos += i_read;
+ return i_read;
+}
+#endif
+
+/*****************************************************************************
+ * Readv commands.
+ *****************************************************************************/
+static int libc_readv ( dvdcss_t dvdcss, struct iovec *p_iovec, int i_blocks )
+{
+#if defined( WIN32 )
+ int i_index, i_len, i_total = 0;
+ unsigned char *p_base;
+ int i_bytes;
+
+ for( i_index = i_blocks;
+ i_index;
+ i_index--, p_iovec++ )
+ {
+ i_len = p_iovec->iov_len;
+ p_base = p_iovec->iov_base;
+
+ if( i_len <= 0 )
+ {
+ continue;
+ }
+
+ i_bytes = read( dvdcss->i_fd, p_base, i_len );
+
+ if( i_bytes < 0 )
+ {
+ /* One of the reads failed, too bad.
+ * We won't even bother returning the reads that went ok,
+ * and as in the posix spec the file postition is left
+ * unspecified after a failure */
+ dvdcss->i_pos = -1;
+ return -1;
+ }
+
+ i_total += i_bytes;
+
+ if( i_bytes != i_len )
+ {
+ /* We reached the end of the file or a signal interrupted
+ * the read. Return a partial read. */
+ int i_seek;
+
+ dvdcss->i_pos = -1;
+ i_seek = libc_seek( dvdcss, i_total / DVDCSS_BLOCK_SIZE );
+ if( i_seek < 0 )
+ {
+ return i_seek;
+ }
+
+ /* We have to return now so that i_pos isn't clobbered */
+ return i_total / DVDCSS_BLOCK_SIZE;
+ }
+ }
+
+ dvdcss->i_pos += i_total / DVDCSS_BLOCK_SIZE;
+ return i_total / DVDCSS_BLOCK_SIZE;
+#else
+ int i_read = readv( dvdcss->i_read_fd, p_iovec, i_blocks );
+
+ if( i_read < 0 )
+ {
+ dvdcss->i_pos = -1;
+ return i_read;
+ }
+
+ dvdcss->i_pos += i_read / DVDCSS_BLOCK_SIZE;
+ return i_read / DVDCSS_BLOCK_SIZE;
+#endif
+}
+
+#if defined( WIN32 )
+/*****************************************************************************
+ * win_readv: vectored read using ReadFile for Win2K and ASPI for win9x
+ *****************************************************************************/
+static int win_readv ( dvdcss_t dvdcss, struct iovec *p_iovec, int i_blocks )
+{
+ int i_index;
+ int i_blocks_read, i_blocks_total = 0;
+
+ /* Check the size of the readv temp buffer, just in case we need to
+ * realloc something bigger */
+ if( dvdcss->i_readv_buf_size < i_blocks * DVDCSS_BLOCK_SIZE )
+ {
+ dvdcss->i_readv_buf_size = i_blocks * DVDCSS_BLOCK_SIZE;
+
+ if( dvdcss->p_readv_buffer ) free( dvdcss->p_readv_buffer );
+
+ /* Allocate a buffer which will be used as a temporary storage
+ * for readv */
+ dvdcss->p_readv_buffer = malloc( dvdcss->i_readv_buf_size );
+ if( !dvdcss->p_readv_buffer )
+ {
+ print_error( dvdcss, " failed (readv)" );
+ dvdcss->i_pos = -1;
+ return -1;
+ }
+ }
+
+ for( i_index = i_blocks; i_index; i_index-- )
+ {
+ i_blocks_total += p_iovec[i_index-1].iov_len;
+ }
+
+ if( i_blocks_total <= 0 ) return 0;
+
+ i_blocks_total /= DVDCSS_BLOCK_SIZE;
+
+ if( WIN2K )
+ {
+ unsigned long int i_bytes;
+ if( !ReadFile( (HANDLE)dvdcss->i_fd, dvdcss->p_readv_buffer,
+ i_blocks_total * DVDCSS_BLOCK_SIZE, &i_bytes, NULL ) )
+ {
+ /* The read failed... too bad.
+ * As in the posix spec the file postition is left
+ * unspecified after a failure */
+ dvdcss->i_pos = -1;
+ return -1;
+ }
+ i_blocks_read = i_bytes / DVDCSS_BLOCK_SIZE;
+ }
+ else /* Win9x */
+ {
+ i_blocks_read = aspi_read_internal( dvdcss->i_fd,
+ dvdcss->p_readv_buffer,
+ i_blocks_total );
+ if( i_blocks_read < 0 )
+ {
+ /* See above */
+ dvdcss->i_pos = -1;
+ return -1;
+ }
+ }
+
+ /* We just have to copy the content of the temp buffer into the iovecs */
+ for( i_index = 0, i_blocks_total = i_blocks_read;
+ i_blocks_total > 0;
+ i_index++ )
+ {
+ memcpy( p_iovec[i_index].iov_base,
+ dvdcss->p_readv_buffer + (i_blocks_read - i_blocks_total)
+ * DVDCSS_BLOCK_SIZE,
+ p_iovec[i_index].iov_len );
+ /* if we read less blocks than asked, we'll just end up copying
+ * garbage, this isn't an issue as we return the number of
+ * blocks actually read */
+ i_blocks_total -= ( p_iovec[i_index].iov_len / DVDCSS_BLOCK_SIZE );
+ }
+
+ dvdcss->i_pos += i_blocks_read;
+ return i_blocks_read;
+}
+
+static int aspi_read_internal( int i_fd, void *p_data, int i_blocks )
+{
+ HANDLE hEvent;
+ struct SRB_ExecSCSICmd ssc;
+ struct w32_aspidev *fd = (struct w32_aspidev *) i_fd;
+
+ /* Create the transfer completion event */
+ hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+ if( hEvent == NULL )
+ {
+ return -1;
+ }
+
+ memset( &ssc, 0, sizeof( ssc ) );
+
+ ssc.SRB_Cmd = SC_EXEC_SCSI_CMD;
+ ssc.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
+ ssc.SRB_HaId = LOBYTE( fd->i_sid );
+ ssc.SRB_Target = HIBYTE( fd->i_sid );
+ ssc.SRB_SenseLen = SENSE_LEN;
+
+ ssc.SRB_PostProc = (LPVOID) hEvent;
+ ssc.SRB_BufPointer = p_data;
+ ssc.SRB_CDBLen = 12;
+
+ ssc.CDBByte[0] = 0xA8; /* RAW */
+ ssc.CDBByte[2] = (UCHAR) (fd->i_blocks >> 24);
+ ssc.CDBByte[3] = (UCHAR) (fd->i_blocks >> 16) & 0xff;
+ ssc.CDBByte[4] = (UCHAR) (fd->i_blocks >> 8) & 0xff;
+ ssc.CDBByte[5] = (UCHAR) (fd->i_blocks) & 0xff;
+
+ /* We have to break down the reads into 64kb pieces (ASPI restriction) */
+ if( i_blocks > 32 )
+ {
+ ssc.SRB_BufLen = 32 * DVDCSS_BLOCK_SIZE;
+ ssc.CDBByte[9] = 32;
+ fd->i_blocks += 32;
+
+ /* Initiate transfer */
+ ResetEvent( hEvent );
+ fd->lpSendCommand( (void*) &ssc );
+
+ /* transfer the next 64kb (aspi_read_internal is called recursively)
+ * We need to check the status of the read on return */
+ if( aspi_read_internal( i_fd,
+ (uint8_t*) p_data + 32 * DVDCSS_BLOCK_SIZE,
+ i_blocks - 32) < 0 )
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ /* This is the last transfer */
+ ssc.SRB_BufLen = i_blocks * DVDCSS_BLOCK_SIZE;
+ ssc.CDBByte[9] = (UCHAR) i_blocks;
+ fd->i_blocks += i_blocks;
+
+ /* Initiate transfer */
+ ResetEvent( hEvent );
+ fd->lpSendCommand( (void*) &ssc );
+
+ }
+
+ /* If the command has still not been processed, wait until it's finished */
+ if( ssc.SRB_Status == SS_PENDING )
+ {
+ WaitForSingleObject( hEvent, INFINITE );
+ }
+ CloseHandle( hEvent );
+
+ /* check that the transfer went as planned */
+ if( ssc.SRB_Status != SS_COMP )
+ {
+ return -1;
+ }
+
+ return i_blocks;
+}
+#endif
+
diff --git a/lib/libdvd/libdvdcss/src/device.h b/lib/libdvd/libdvdcss/src/device.h
new file mode 100644
index 0000000000..d8a73f0d4e
--- /dev/null
+++ b/lib/libdvd/libdvdcss/src/device.h
@@ -0,0 +1,58 @@
+/*****************************************************************************
+ * device.h: DVD device access
+ *****************************************************************************
+ * Copyright (C) 1998-2002 VideoLAN
+ * $Id$
+ *
+ * Authors: Stéphane Borel <stef@via.ecp.fr>
+ * Sam Hocevar <sam@zoy.org>
+ * 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, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * iovec structure: vectored data entry
+ *****************************************************************************/
+#if defined( WIN32 ) && !defined( SYS_CYGWIN )
+# include <io.h> /* read() */
+#else
+# include <sys/types.h>
+# include <sys/uio.h> /* struct iovec */
+#endif
+
+#if defined( WIN32 ) && !defined( SYS_CYGWIN )
+struct iovec
+{
+ void *iov_base; /* Pointer to data. */
+ size_t iov_len; /* Length of data. */
+};
+#endif
+
+/*****************************************************************************
+ * Device reading prototypes
+ *****************************************************************************/
+int _dvdcss_use_ioctls ( dvdcss_t );
+void _dvdcss_check ( dvdcss_t );
+int _dvdcss_open ( dvdcss_t );
+int _dvdcss_close ( dvdcss_t );
+
+/*****************************************************************************
+ * Device reading prototypes, raw-device specific
+ *****************************************************************************/
+#ifndef WIN32
+int _dvdcss_raw_open ( dvdcss_t, char const * );
+#endif
+
diff --git a/lib/libdvd/libdvdcss/src/dvdcss/Makefile.am b/lib/libdvd/libdvdcss/src/dvdcss/Makefile.am
new file mode 100644
index 0000000000..46746964cb
--- /dev/null
+++ b/lib/libdvd/libdvdcss/src/dvdcss/Makefile.am
@@ -0,0 +1,3 @@
+pkgincludedir = $(includedir)/dvdcss
+
+pkginclude_HEADERS = dvdcss.h
diff --git a/lib/libdvd/libdvdcss/src/dvdcss/dvdcss.h b/lib/libdvd/libdvdcss/src/dvdcss/dvdcss.h
new file mode 100644
index 0000000000..c97f996824
--- /dev/null
+++ b/lib/libdvd/libdvdcss/src/dvdcss/dvdcss.h
@@ -0,0 +1,107 @@
+/**
+ * \file dvdcss.h
+ * \author Stéphane Borel <stef@via.ecp.fr>
+ * \author Sam Hocevar <sam@zoy.org>
+ * \brief The \e libdvdcss public header.
+ *
+ * This header contains the public types and functions that applications
+ * using \e libdvdcss may use.
+ */
+
+/*
+ * Copyright (C) 1998-2008 VideoLAN
+ * $Id$
+ *
+ * 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.
+ */
+
+#ifndef DVDCSS_DVDCSS_H
+#ifndef _DOXYGEN_SKIP_ME
+#define DVDCSS_DVDCSS_H 1
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Library instance handle, to be used for each library call. */
+typedef struct dvdcss_s* dvdcss_t;
+
+
+/** The block size of a DVD. */
+#define DVDCSS_BLOCK_SIZE 2048
+
+/** The default flag to be used by \e libdvdcss functions. */
+#define DVDCSS_NOFLAGS 0
+
+/** Flag to ask dvdcss_read() to decrypt the data it reads. */
+#define DVDCSS_READ_DECRYPT (1 << 0)
+
+/** Flag to tell dvdcss_seek() it is seeking in MPEG data. */
+#define DVDCSS_SEEK_MPEG (1 << 0)
+
+/** Flag to ask dvdcss_seek() to check the current title key. */
+#define DVDCSS_SEEK_KEY (1 << 1)
+
+
+#if defined(LIBDVDCSS_EXPORTS)
+#define LIBDVDCSS_EXPORT __declspec(dllexport) extern
+#elif defined(LIBDVDCSS_IMPORTS)
+#define LIBDVDCSS_EXPORT __declspec(dllimport) extern
+#else
+#define LIBDVDCSS_EXPORT extern
+#endif
+
+/*
+ * Our version number. The variable name contains the interface version.
+ */
+LIBDVDCSS_EXPORT char * dvdcss_interface_2;
+
+
+/*
+ * Exported prototypes.
+ */
+LIBDVDCSS_EXPORT dvdcss_t dvdcss_open ( char *psz_target );
+LIBDVDCSS_EXPORT int dvdcss_close ( dvdcss_t );
+LIBDVDCSS_EXPORT int dvdcss_seek ( dvdcss_t,
+ int i_blocks,
+ int i_flags );
+LIBDVDCSS_EXPORT int dvdcss_read ( dvdcss_t,
+ void *p_buffer,
+ int i_blocks,
+ int i_flags );
+LIBDVDCSS_EXPORT int dvdcss_readv ( dvdcss_t,
+ void *p_iovec,
+ int i_blocks,
+ int i_flags );
+LIBDVDCSS_EXPORT char * dvdcss_error ( dvdcss_t );
+
+LIBDVDCSS_EXPORT int dvdcss_is_scrambled ( dvdcss_t );
+
+
+/*
+ * Deprecated stuff.
+ */
+#ifndef _DOXYGEN_SKIP_ME
+#define dvdcss_title(a,b) dvdcss_seek(a,b,DVDCSS_SEEK_KEY)
+#define dvdcss_handle dvdcss_t
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DVDCSS_DVDCSS_H */
diff --git a/lib/libdvd/libdvdcss/src/error.c b/lib/libdvd/libdvdcss/src/error.c
new file mode 100644
index 0000000000..66d2b67ad4
--- /dev/null
+++ b/lib/libdvd/libdvdcss/src/error.c
@@ -0,0 +1,68 @@
+/*****************************************************************************
+ * error.c: error management functions
+ *****************************************************************************
+ * Copyright (C) 1998-2002 VideoLAN
+ * $Id$
+ *
+ * Author: Sam 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.
+ *****************************************************************************/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#include "dvdcss/dvdcss.h"
+
+#include "common.h"
+#include "css.h"
+#include "libdvdcss.h"
+
+/*****************************************************************************
+ * Error messages
+ *****************************************************************************/
+void _print_error( dvdcss_t dvdcss, char *psz_string )
+{
+ if( dvdcss->b_errors )
+ {
+ fprintf( stderr, "libdvdcss error: %s\n", psz_string );
+ }
+
+ dvdcss->psz_error = psz_string;
+}
+
+/*****************************************************************************
+ * Debug messages
+ *****************************************************************************/
+#if 0
+void _print_debug( dvdcss_t dvdcss, char *psz_string )
+{
+ if( dvdcss->b_debug )
+ {
+ fprintf( stderr, "libdvdcss debug: %s\n", psz_string );
+ }
+}
+#endif
+
diff --git a/lib/libdvd/libdvdcss/src/ioctl.c b/lib/libdvd/libdvdcss/src/ioctl.c
new file mode 100644
index 0000000000..1e5ebead8f
--- /dev/null
+++ b/lib/libdvd/libdvdcss/src/ioctl.c
@@ -0,0 +1,2183 @@
+/*****************************************************************************
+ * ioctl.c: DVD ioctl replacement function
+ *****************************************************************************
+ * Copyright (C) 1999-2001 VideoLAN
+ * $Id$
+ *
+ * Authors: Markus Kuespert <ltlBeBoy@beosmail.com>
+ * Sam Hocevar <sam@zoy.org>
+ * Jon Lech Johansen <jon-vl@nanocrew.net>
+ * HÃ¥kan Hjort <d95hjort@dtek.chalmers.se>
+ * Eugenio Jarosiewicz <ej0@cise.ufl.edu>
+ * David Siebörger <drs-videolan@rucus.ru.ac.za>
+ * Alex Strelnikov <lelik@os2.ru>
+ * Gildas Bazin <gbazin@netcourrier.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include "config.h"
+
+#include <stdio.h>
+
+#include <string.h> /* memcpy(), memset() */
+#include <sys/types.h>
+
+#if defined( WIN32 )
+# include <windows.h>
+# include <winioctl.h>
+#elif defined ( SYS_OS2 )
+# define INCL_DOSFILEMGR
+# define INCL_DOSDEVICES
+# define INCL_DOSDEVIOCTL
+# define INCL_DOSERRORS
+# include <os2.h>
+# include <sys/ioctl.h>
+#else
+# include <netinet/in.h>
+# include <sys/ioctl.h>
+#endif
+
+#ifdef DVD_STRUCT_IN_SYS_CDIO_H
+# include <sys/cdio.h>
+#endif
+#ifdef DVD_STRUCT_IN_SYS_DVDIO_H
+# include <sys/dvdio.h>
+#endif
+#ifdef DVD_STRUCT_IN_LINUX_CDROM_H
+# include <linux/cdrom.h>
+#endif
+#ifdef DVD_STRUCT_IN_DVD_H
+# include <dvd.h>
+#endif
+#ifdef DVD_STRUCT_IN_BSDI_DVDIOCTL_DVD_H
+# include "bsdi_dvd.h"
+#endif
+#ifdef SYS_BEOS
+# include <malloc.h>
+# include <scsi.h>
+#endif
+#ifdef HPUX_SCTL_IO
+# include <sys/scsi.h>
+#endif
+#ifdef SOLARIS_USCSI
+# include <dlfcn.h>
+# include <unistd.h>
+# include <stropts.h>
+# include <sys/scsi/scsi_types.h>
+# include <sys/scsi/impl/uscsi.h>
+#endif
+#ifdef DARWIN_DVD_IOCTL
+# include <IOKit/storage/IODVDMediaBSDClient.h>
+#endif
+#ifdef __QNXNTO__
+# include <sys/mman.h>
+# include <sys/dcmd_cam.h>
+#endif
+
+#include "common.h"
+
+#include "ioctl.h"
+
+/*****************************************************************************
+ * Local prototypes, BeOS specific
+ *****************************************************************************/
+#if defined( SYS_BEOS )
+static void BeInitRDC ( raw_device_command *, int );
+#endif
+
+/*****************************************************************************
+ * Local prototypes, HP-UX specific
+ *****************************************************************************/
+#if defined( HPUX_SCTL_IO )
+static void HPUXInitSCTL ( struct sctl_io *sctl_io, int i_type );
+#endif
+
+/*****************************************************************************
+ * Local prototypes, Solaris specific
+ *****************************************************************************/
+#if defined( SOLARIS_USCSI )
+static void SolarisInitUSCSI( struct uscsi_cmd *p_sc, int i_type );
+static int SolarisSendUSCSI( int fd, struct uscsi_cmd *p_sc );
+#endif
+
+/*****************************************************************************
+ * Local prototypes, win32 (aspi) specific
+ *****************************************************************************/
+#if defined( WIN32 )
+static void WinInitSPTD ( SCSI_PASS_THROUGH_DIRECT *, int );
+static void WinInitSSC ( struct SRB_ExecSCSICmd *, int );
+static int WinSendSSC ( int, struct SRB_ExecSCSICmd * );
+#endif
+
+/*****************************************************************************
+ * Local prototypes, QNX specific
+ *****************************************************************************/
+#if defined( __QNXNTO__ )
+static void QNXInitCPT ( CAM_PASS_THRU *, int );
+#endif
+
+/*****************************************************************************
+ * Local prototypes, OS2 specific
+ *****************************************************************************/
+#if defined( SYS_OS2 )
+static void OS2InitSDC( struct OS2_ExecSCSICmd *, int );
+#endif
+
+/*****************************************************************************
+ * ioctl_ReadCopyright: check whether the disc is encrypted or not
+ *****************************************************************************/
+int ioctl_ReadCopyright( int i_fd, int i_layer, int *pi_copyright )
+{
+ int i_ret;
+
+#if defined( HAVE_LINUX_DVD_STRUCT )
+ dvd_struct dvd;
+
+ memset( &dvd, 0, sizeof( dvd ) );
+ dvd.type = DVD_STRUCT_COPYRIGHT;
+ dvd.copyright.layer_num = i_layer;
+
+ i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
+
+ *pi_copyright = dvd.copyright.cpst;
+
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_struct dvd;
+
+ memset( &dvd, 0, sizeof( dvd ) );
+ dvd.format = DVD_STRUCT_COPYRIGHT;
+ dvd.layer_num = i_layer;
+
+ i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
+
+ *pi_copyright = dvd.cpst;
+
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 8 );
+
+ rdc.command[ 6 ] = i_layer;
+ rdc.command[ 7 ] = DVD_STRUCT_COPYRIGHT;
+
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
+
+ *pi_copyright = p_buffer[ 4 ];
+
+#elif defined( HPUX_SCTL_IO )
+ INIT_SCTL_IO( GPCMD_READ_DVD_STRUCTURE, 8 );
+
+ sctl_io.cdb[ 6 ] = i_layer;
+ sctl_io.cdb[ 7 ] = DVD_STRUCT_COPYRIGHT;
+
+ i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
+
+ *pi_copyright = p_buffer[ 4 ];
+
+#elif defined( SOLARIS_USCSI )
+ INIT_USCSI( GPCMD_READ_DVD_STRUCTURE, 8 );
+
+ rs_cdb.cdb_opaque[ 6 ] = i_layer;
+ rs_cdb.cdb_opaque[ 7 ] = DVD_STRUCT_COPYRIGHT;
+
+ i_ret = SolarisSendUSCSI(i_fd, &sc);
+
+ if( i_ret < 0 || sc.uscsi_status ) {
+ i_ret = -1;
+ }
+
+ *pi_copyright = p_buffer[ 4 ];
+ /* s->copyright.rmi = p_buffer[ 5 ]; */
+
+#elif defined( DARWIN_DVD_IOCTL )
+ INIT_DVDIOCTL( dk_dvd_read_structure_t, DVDCopyrightInfo,
+ kDVDStructureFormatCopyrightInfo );
+
+ dvd.layer = i_layer;
+
+ i_ret = ioctl( i_fd, DKIOCDVDREADSTRUCTURE, &dvd );
+
+ *pi_copyright = dvdbs.copyrightProtectionSystemType;
+
+#elif defined( WIN32 )
+ if( WIN2K ) /* NT/2k/XP */
+ {
+ INIT_SPTD( GPCMD_READ_DVD_STRUCTURE, 8 );
+
+ /* When using IOCTL_DVD_READ_STRUCTURE and
+ DVD_COPYRIGHT_DESCRIPTOR, CopyrightProtectionType
+ seems to be always 6 ???
+ To work around this MS bug we try to send a raw scsi command
+ instead (if we've got enough privileges to do so). */
+
+ sptd.Cdb[ 6 ] = i_layer;
+ sptd.Cdb[ 7 ] = DVD_STRUCT_COPYRIGHT;
+
+ i_ret = SEND_SPTD( i_fd, &sptd, &tmp );
+
+ if( i_ret == 0 )
+ {
+ *pi_copyright = p_buffer[ 4 ];
+ }
+ }
+ else
+ {
+ INIT_SSC( GPCMD_READ_DVD_STRUCTURE, 8 );
+
+ ssc.CDBByte[ 6 ] = i_layer;
+ ssc.CDBByte[ 7 ] = DVD_STRUCT_COPYRIGHT;
+
+ i_ret = WinSendSSC( i_fd, &ssc );
+
+ *pi_copyright = p_buffer[ 4 ];
+ }
+
+#elif defined( __QNXNTO__ )
+
+ INIT_CPT( GPCMD_READ_DVD_STRUCTURE, 8 );
+
+ p_cpt->cam_cdb[ 6 ] = i_layer;
+ p_cpt->cam_cdb[ 7 ] = DVD_STRUCT_COPYRIGHT;
+
+ i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
+
+ *pi_copyright = p_buffer[4];
+
+#elif defined( SYS_OS2 )
+ INIT_SSC( GPCMD_READ_DVD_STRUCTURE, 8 );
+
+ sdc.command[ 6 ] = i_layer;
+ sdc.command[ 7 ] = DVD_STRUCT_COPYRIGHT;
+
+ i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
+ &sdc, sizeof(sdc), &ulParamLen,
+ p_buffer, sizeof(p_buffer), &ulDataLen);
+
+ *pi_copyright = p_buffer[ 4 ];
+
+#else
+# error "DVD ioctls are unavailable on this system"
+
+#endif
+ return i_ret;
+}
+
+/*****************************************************************************
+ * ioctl_ReadDiscKey: get the disc key
+ *****************************************************************************/
+int ioctl_ReadDiscKey( int i_fd, int *pi_agid, uint8_t *p_key )
+{
+ int i_ret;
+
+#if defined( HAVE_LINUX_DVD_STRUCT )
+ dvd_struct dvd;
+
+ memset( &dvd, 0, sizeof( dvd ) );
+ dvd.type = DVD_STRUCT_DISCKEY;
+ dvd.disckey.agid = *pi_agid;
+ memset( dvd.disckey.value, 0, DVD_DISCKEY_SIZE );
+
+ i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
+
+ if( i_ret < 0 )
+ {
+ return i_ret;
+ }
+
+ memcpy( p_key, dvd.disckey.value, DVD_DISCKEY_SIZE );
+
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_struct dvd;
+
+ memset( &dvd, 0, sizeof( dvd ) );
+ dvd.format = DVD_STRUCT_DISCKEY;
+ dvd.agid = *pi_agid;
+ memset( dvd.data, 0, DVD_DISCKEY_SIZE );
+
+ i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
+
+ if( i_ret < 0 )
+ {
+ return i_ret;
+ }
+
+ memcpy( p_key, dvd.data, DVD_DISCKEY_SIZE );
+
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_READ_DVD_STRUCTURE, DVD_DISCKEY_SIZE + 4 );
+
+ rdc.command[ 7 ] = DVD_STRUCT_DISCKEY;
+ rdc.command[ 10 ] = *pi_agid << 6;
+
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
+
+ if( i_ret < 0 )
+ {
+ return i_ret;
+ }
+
+ memcpy( p_key, p_buffer + 4, DVD_DISCKEY_SIZE );
+
+#elif defined( HPUX_SCTL_IO )
+ INIT_SCTL_IO( GPCMD_READ_DVD_STRUCTURE, DVD_DISCKEY_SIZE + 4 );
+
+ sctl_io.cdb[ 7 ] = DVD_STRUCT_DISCKEY;
+ sctl_io.cdb[ 10 ] = *pi_agid << 6;
+
+ i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
+
+ if( i_ret < 0 )
+ {
+ return i_ret;
+ }
+
+ memcpy( p_key, p_buffer + 4, DVD_DISCKEY_SIZE );
+
+#elif defined( SOLARIS_USCSI )
+ INIT_USCSI( GPCMD_READ_DVD_STRUCTURE, DVD_DISCKEY_SIZE + 4 );
+
+ rs_cdb.cdb_opaque[ 7 ] = DVD_STRUCT_DISCKEY;
+ rs_cdb.cdb_opaque[ 10 ] = *pi_agid << 6;
+
+ i_ret = SolarisSendUSCSI( i_fd, &sc );
+
+ if( i_ret < 0 || sc.uscsi_status )
+ {
+ i_ret = -1;
+ return i_ret;
+ }
+
+ memcpy( p_key, p_buffer + 4, DVD_DISCKEY_SIZE );
+
+#elif defined( DARWIN_DVD_IOCTL )
+ INIT_DVDIOCTL( dk_dvd_read_structure_t, DVDDiscKeyInfo,
+ kDVDStructureFormatDiscKeyInfo );
+
+ dvd.grantID = *pi_agid;
+
+ i_ret = ioctl( i_fd, DKIOCDVDREADSTRUCTURE, &dvd );
+
+ memcpy( p_key, dvdbs.discKeyStructures, DVD_DISCKEY_SIZE );
+
+#elif defined( _XBOX )
+ // the next piece of code will read the disc key on the xbox for all drives (samsung included)
+ // but for some reason it takes 15 - 20 seconds longer to load a dvd if mplayer has the dvd key
+ // so we let this part fail and will only use the modified ioctl_ReadTitleKey code.
+ // don't get this delay, and i'm surprised it worked as the ReadTitleKey function didn't work.
+
+ DWORD dwBytesRead;
+ DVD_READ_STRUCTURE st;
+ char buffer[DVD_DISCKEY_SIZE];
+
+ memset( &buffer, 0, sizeof( buffer ) );
+ memset( &st, 0, sizeof( st ) );
+
+ st.BlockByteOffset.QuadPart = 0;
+ st.SessionId = *pi_agid;
+ st.Format = DvdDiskKeyDescriptor;
+
+ i_ret = DeviceIoControl((HANDLE) i_fd, IOCTL_DVD_READ_STRUCTURE, &st,
+ sizeof(st), buffer, DVD_DISCKEY_SIZE, &dwBytesRead, NULL ) ? 0 : -1;
+
+ if (i_ret < 0) // didn't work
+ {
+ printf("Failed to read disc key\n");
+ return i_ret;
+ }
+
+ // copy the returned key into our key buffer
+ int i;
+ for (i = 0; i < DVD_DISCKEY_SIZE; i++)
+ p_key[i] = buffer[i+4];
+
+#elif defined( WIN32 )
+ if( WIN2K ) /* NT/2k/XP */
+ {
+ DWORD tmp;
+ uint8_t buffer[DVD_DISK_KEY_LENGTH];
+ PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
+
+ memset( &buffer, 0, sizeof( buffer ) );
+
+ key->KeyLength = DVD_DISK_KEY_LENGTH;
+ key->SessionId = *pi_agid;
+ key->KeyType = DvdDiskKey;
+ key->KeyFlags = 0;
+
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
+ key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
+
+ if( i_ret < 0 )
+ {
+ return i_ret;
+ }
+
+ memcpy( p_key, key->KeyData, DVD_DISCKEY_SIZE );
+ }
+ else
+ {
+ INIT_SSC( GPCMD_READ_DVD_STRUCTURE, DVD_DISCKEY_SIZE + 4 );
+
+ ssc.CDBByte[ 7 ] = DVD_STRUCT_DISCKEY;
+ ssc.CDBByte[ 10 ] = *pi_agid << 6;
+
+ i_ret = WinSendSSC( i_fd, &ssc );
+
+ if( i_ret < 0 )
+ {
+ return i_ret;
+ }
+
+ memcpy( p_key, p_buffer + 4, DVD_DISCKEY_SIZE );
+ }
+
+#elif defined( __QNXNTO__ )
+
+ INIT_CPT( GPCMD_READ_DVD_STRUCTURE, DVD_DISCKEY_SIZE + 4 );
+
+ p_cpt->cam_cdb[ 7 ] = DVD_STRUCT_DISCKEY;
+ p_cpt->cam_cdb[ 10 ] = *pi_agid << 6;
+
+ i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
+
+ memcpy( p_key, p_buffer + 4, DVD_DISCKEY_SIZE );
+
+#elif defined ( SYS_OS2 )
+ INIT_SSC( GPCMD_READ_DVD_STRUCTURE, DVD_DISCKEY_SIZE + 4 );
+
+ sdc.command[ 7 ] = DVD_STRUCT_DISCKEY;
+ sdc.command[ 10 ] = *pi_agid << 6;
+
+ i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
+ &sdc, sizeof(sdc), &ulParamLen,
+ p_buffer, sizeof(p_buffer), &ulDataLen);
+
+ if( i_ret < 0 )
+ {
+ return i_ret;
+ }
+
+ memcpy( p_key, p_buffer + 4, DVD_DISCKEY_SIZE );
+
+#else
+# error "DVD ioctls are unavailable on this system"
+
+#endif
+ return i_ret;
+}
+
+/*****************************************************************************
+ * ioctl_ReadTitleKey: get the title key
+ *****************************************************************************/
+int ioctl_ReadTitleKey( int i_fd, int *pi_agid, int i_pos, uint8_t *p_key )
+{
+ int i_ret;
+
+#if defined( HAVE_LINUX_DVD_STRUCT )
+ dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.type = DVD_LU_SEND_TITLE_KEY;
+ auth_info.lstk.agid = *pi_agid;
+ auth_info.lstk.lba = i_pos;
+
+ i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
+
+ memcpy( p_key, auth_info.lstk.title_key, DVD_KEY_SIZE );
+
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.format = DVD_REPORT_TITLE_KEY;
+ auth_info.agid = *pi_agid;
+ auth_info.lba = i_pos;
+
+ i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
+
+ memcpy( p_key, auth_info.keychal, DVD_KEY_SIZE );
+
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_REPORT_KEY, 12 );
+
+ rdc.command[ 2 ] = ( i_pos >> 24 ) & 0xff;
+ rdc.command[ 3 ] = ( i_pos >> 16 ) & 0xff;
+ rdc.command[ 4 ] = ( i_pos >> 8 ) & 0xff;
+ rdc.command[ 5 ] = ( i_pos ) & 0xff;
+ rdc.command[ 10 ] = DVD_REPORT_TITLE_KEY | (*pi_agid << 6);
+
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
+
+ memcpy( p_key, p_buffer + 5, DVD_KEY_SIZE );
+
+#elif defined( HPUX_SCTL_IO )
+ INIT_SCTL_IO( GPCMD_REPORT_KEY, 12 );
+
+ sctl_io.cdb[ 2 ] = ( i_pos >> 24 ) & 0xff;
+ sctl_io.cdb[ 3 ] = ( i_pos >> 16 ) & 0xff;
+ sctl_io.cdb[ 4 ] = ( i_pos >> 8 ) & 0xff;
+ sctl_io.cdb[ 5 ] = ( i_pos ) & 0xff;
+ sctl_io.cdb[ 10 ] = DVD_REPORT_TITLE_KEY | (*pi_agid << 6);
+
+ i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
+
+ memcpy( p_key, p_buffer + 5, DVD_KEY_SIZE );
+
+#elif defined( SOLARIS_USCSI )
+ INIT_USCSI( GPCMD_REPORT_KEY, 12 );
+
+ rs_cdb.cdb_opaque[ 2 ] = ( i_pos >> 24 ) & 0xff;
+ rs_cdb.cdb_opaque[ 3 ] = ( i_pos >> 16 ) & 0xff;
+ rs_cdb.cdb_opaque[ 4 ] = ( i_pos >> 8 ) & 0xff;
+ rs_cdb.cdb_opaque[ 5 ] = ( i_pos ) & 0xff;
+ rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_TITLE_KEY | (*pi_agid << 6);
+
+ i_ret = SolarisSendUSCSI( i_fd, &sc );
+
+ if( i_ret < 0 || sc.uscsi_status )
+ {
+ i_ret = -1;
+ }
+
+ /* Do we want to return the cp_sec flag perhaps? */
+ /* a->lstk.cpm = (buf[ 4 ] >> 7) & 1; */
+ /* a->lstk.cp_sec = (buf[ 4 ] >> 6) & 1; */
+ /* a->lstk.cgms = (buf[ 4 ] >> 4) & 3; */
+
+ memcpy( p_key, p_buffer + 5, DVD_KEY_SIZE );
+
+#elif defined( DARWIN_DVD_IOCTL )
+ INIT_DVDIOCTL( dk_dvd_report_key_t, DVDTitleKeyInfo,
+ kDVDKeyFormatTitleKey );
+
+ dvd.address = i_pos;
+ dvd.grantID = *pi_agid;
+ dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
+
+ i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
+
+ memcpy( p_key, dvdbs.titleKeyValue, DVD_KEY_SIZE );
+
+#elif defined( _XBOX ) && 0 //Faulty wrong key returned, original for WIN32 works thou so use it instead
+ DWORD dwBytesRead;
+ DVD_READ_STRUCTURE st;
+ char buffer[2048+4];
+
+ memset( &buffer, 0, sizeof( buffer ) );
+
+ st.BlockByteOffset.QuadPart = (LONGLONG) i_pos * 2048 /*DVDCSS_BLOCK_SIZE*/;
+ st.SessionId = *pi_agid;
+ st.Format = DvdDiskKeyDescriptor;
+
+ i_ret = DeviceIoControl((HANDLE) i_fd, IOCTL_DVD_READ_STRUCTURE, &st, sizeof(st), buffer, 2048+4, &dwBytesRead, NULL ) ? 0 : -1;
+ if( i_ret < 0 )
+ {
+ return i_ret;
+ }
+
+ memcpy( p_key, &(buffer[4]), 2048);
+
+#elif defined( WIN32 )
+ if( WIN2K ) /* NT/2k/XP */
+ {
+ DWORD tmp;
+ uint8_t buffer[DVD_TITLE_KEY_LENGTH];
+ PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
+
+ memset( &buffer, 0, sizeof( buffer ) );
+
+ key->KeyLength = DVD_TITLE_KEY_LENGTH;
+ key->SessionId = *pi_agid;
+ key->KeyType = DvdTitleKey;
+ key->KeyFlags = 0;
+ key->Parameters.TitleOffset.QuadPart = (LONGLONG) i_pos *
+ 2048 /*DVDCSS_BLOCK_SIZE*/;
+
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
+ key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
+
+ memcpy( p_key, key->KeyData, DVD_KEY_SIZE );
+ }
+ else
+ {
+ INIT_SSC( GPCMD_REPORT_KEY, 12 );
+
+ ssc.CDBByte[ 2 ] = ( i_pos >> 24 ) & 0xff;
+ ssc.CDBByte[ 3 ] = ( i_pos >> 16 ) & 0xff;
+ ssc.CDBByte[ 4 ] = ( i_pos >> 8 ) & 0xff;
+ ssc.CDBByte[ 5 ] = ( i_pos ) & 0xff;
+ ssc.CDBByte[ 10 ] = DVD_REPORT_TITLE_KEY | (*pi_agid << 6);
+
+ i_ret = WinSendSSC( i_fd, &ssc );
+
+ memcpy( p_key, p_buffer + 5, DVD_KEY_SIZE );
+ }
+
+#elif defined( __QNXNTO__ )
+
+ INIT_CPT( GPCMD_REPORT_KEY, 12 );
+
+ p_cpt->cam_cdb[ 2 ] = ( i_pos >> 24 ) & 0xff;
+ p_cpt->cam_cdb[ 3 ] = ( i_pos >> 16 ) & 0xff;
+ p_cpt->cam_cdb[ 4 ] = ( i_pos >> 8 ) & 0xff;
+ p_cpt->cam_cdb[ 5 ] = ( i_pos ) & 0xff;
+ p_cpt->cam_cdb[ 10 ] = DVD_REPORT_TITLE_KEY | (*pi_agid << 6);
+
+ i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
+
+ memcpy( p_key, p_buffer + 5, DVD_KEY_SIZE );
+
+#elif defined( SYS_OS2 )
+ INIT_SSC( GPCMD_REPORT_KEY, 12 );
+
+ sdc.command[ 2 ] = ( i_pos >> 24 ) & 0xff;
+ sdc.command[ 3 ] = ( i_pos >> 16 ) & 0xff;
+ sdc.command[ 4 ] = ( i_pos >> 8 ) & 0xff;
+ sdc.command[ 5 ] = ( i_pos ) & 0xff;
+ sdc.command[ 10 ] = DVD_REPORT_TITLE_KEY | (*pi_agid << 6);
+
+ i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
+ &sdc, sizeof(sdc), &ulParamLen,
+ p_buffer, sizeof(p_buffer), &ulDataLen);
+
+ memcpy( p_key, p_buffer + 5, DVD_KEY_SIZE );
+
+#else
+# error "DVD ioctls are unavailable on this system"
+
+#endif
+
+ return i_ret;
+}
+
+
+/*****************************************************************************
+ * ioctl_ReportAgid: get AGID from the drive
+ *****************************************************************************/
+int ioctl_ReportAgid( int i_fd, int *pi_agid )
+{
+ int i_ret;
+
+#if defined( HAVE_LINUX_DVD_STRUCT )
+ dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.type = DVD_LU_SEND_AGID;
+ auth_info.lsa.agid = *pi_agid;
+
+ i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
+
+ *pi_agid = auth_info.lsa.agid;
+
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.format = DVD_REPORT_AGID;
+ auth_info.agid = *pi_agid;
+
+ i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
+
+ *pi_agid = auth_info.agid;
+
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_REPORT_KEY, 8 );
+
+ rdc.command[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
+
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
+
+ *pi_agid = p_buffer[ 7 ] >> 6;
+
+#elif defined( HPUX_SCTL_IO )
+ INIT_SCTL_IO( GPCMD_REPORT_KEY, 8 );
+
+ sctl_io.cdb[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
+
+ i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
+
+ *pi_agid = p_buffer[ 7 ] >> 6;
+
+#elif defined( SOLARIS_USCSI )
+ INIT_USCSI( GPCMD_REPORT_KEY, 8 );
+
+ rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
+
+ i_ret = SolarisSendUSCSI( i_fd, &sc );
+
+ if( i_ret < 0 || sc.uscsi_status )
+ {
+ i_ret = -1;
+ }
+
+ *pi_agid = p_buffer[ 7 ] >> 6;
+
+#elif defined( DARWIN_DVD_IOCTL )
+ INIT_DVDIOCTL( dk_dvd_report_key_t, DVDAuthenticationGrantIDInfo,
+ kDVDKeyFormatAGID_CSS );
+
+ dvd.grantID = *pi_agid;
+ dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
+
+ i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
+
+ *pi_agid = dvdbs.grantID;
+
+#elif defined( WIN32 )
+ if( WIN2K ) /* NT/2k/XP */
+ {
+ ULONG id;
+ DWORD tmp;
+
+#if defined( _XBOX)
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_START_SESSION,
+ NULL, 0, &id, sizeof(id), &tmp, NULL ) ? 0 : -1;
+#else
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_START_SESSION,
+ &tmp, 4, &id, sizeof( id ), &tmp, NULL ) ? 0 : -1;
+#endif
+
+ *pi_agid = id;
+ }
+ else
+ {
+ INIT_SSC( GPCMD_REPORT_KEY, 8 );
+
+ ssc.CDBByte[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
+
+ i_ret = WinSendSSC( i_fd, &ssc );
+
+ *pi_agid = p_buffer[ 7 ] >> 6;
+ }
+
+#elif defined( __QNXNTO__ )
+
+ INIT_CPT( GPCMD_REPORT_KEY, 8 );
+
+ p_cpt->cam_cdb[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
+
+ i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
+
+ *pi_agid = p_buffer[ 7 ] >> 6;
+
+#elif defined( SYS_OS2 )
+ INIT_SSC( GPCMD_REPORT_KEY, 8 );
+
+ sdc.command[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
+
+ i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
+ &sdc, sizeof(sdc), &ulParamLen,
+ p_buffer, sizeof(p_buffer), &ulDataLen);
+
+ *pi_agid = p_buffer[ 7 ] >> 6;
+
+#else
+# error "DVD ioctls are unavailable on this system"
+
+#endif
+ return i_ret;
+}
+
+/*****************************************************************************
+ * ioctl_ReportChallenge: get challenge from the drive
+ *****************************************************************************/
+int ioctl_ReportChallenge( int i_fd, int *pi_agid, uint8_t *p_challenge )
+{
+ int i_ret;
+
+#if defined( HAVE_LINUX_DVD_STRUCT )
+ dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.type = DVD_LU_SEND_CHALLENGE;
+ auth_info.lsc.agid = *pi_agid;
+
+ i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
+
+ memcpy( p_challenge, auth_info.lsc.chal, DVD_CHALLENGE_SIZE );
+
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.format = DVD_REPORT_CHALLENGE;
+ auth_info.agid = *pi_agid;
+
+ i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
+
+ memcpy( p_challenge, auth_info.keychal, DVD_CHALLENGE_SIZE );
+
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_REPORT_KEY, 16 );
+
+ rdc.command[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
+
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
+
+ memcpy( p_challenge, p_buffer + 4, DVD_CHALLENGE_SIZE );
+
+#elif defined( HPUX_SCTL_IO )
+ INIT_SCTL_IO( GPCMD_REPORT_KEY, 16 );
+
+ sctl_io.cdb[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
+
+ i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
+
+ memcpy( p_challenge, p_buffer + 4, DVD_CHALLENGE_SIZE );
+
+#elif defined( SOLARIS_USCSI )
+ INIT_USCSI( GPCMD_REPORT_KEY, 16 );
+
+ rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
+
+ i_ret = SolarisSendUSCSI( i_fd, &sc );
+
+ if( i_ret < 0 || sc.uscsi_status )
+ {
+ i_ret = -1;
+ }
+
+ memcpy( p_challenge, p_buffer + 4, DVD_CHALLENGE_SIZE );
+
+#elif defined( DARWIN_DVD_IOCTL )
+ INIT_DVDIOCTL( dk_dvd_report_key_t, DVDChallengeKeyInfo,
+ kDVDKeyFormatChallengeKey );
+
+ dvd.grantID = *pi_agid;
+
+ i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
+
+ memcpy( p_challenge, dvdbs.challengeKeyValue, DVD_CHALLENGE_SIZE );
+
+#elif defined( WIN32 )
+ if( WIN2K ) /* NT/2k/XP */
+ {
+ DWORD tmp;
+ uint8_t buffer[DVD_CHALLENGE_KEY_LENGTH];
+ PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
+
+ memset( &buffer, 0, sizeof( buffer ) );
+
+ key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
+ key->SessionId = *pi_agid;
+ key->KeyType = DvdChallengeKey;
+ key->KeyFlags = 0;
+
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
+ key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
+
+ if( i_ret < 0 )
+ {
+ return i_ret;
+ }
+
+ memcpy( p_challenge, key->KeyData, DVD_CHALLENGE_SIZE );
+ }
+ else
+ {
+ INIT_SSC( GPCMD_REPORT_KEY, 16 );
+
+ ssc.CDBByte[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
+
+ i_ret = WinSendSSC( i_fd, &ssc );
+
+ memcpy( p_challenge, p_buffer + 4, DVD_CHALLENGE_SIZE );
+ }
+
+#elif defined( __QNXNTO__ )
+
+ INIT_CPT( GPCMD_REPORT_KEY, 16 );
+
+ p_cpt->cam_cdb[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
+
+ i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
+
+ memcpy( p_challenge, p_buffer + 4, DVD_CHALLENGE_SIZE );
+
+#elif defined( SYS_OS2 )
+ INIT_SSC( GPCMD_REPORT_KEY, 16 );
+
+ sdc.command[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
+
+ i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
+ &sdc, sizeof(sdc), &ulParamLen,
+ p_buffer, sizeof(p_buffer), &ulDataLen);
+
+ memcpy( p_challenge, p_buffer + 4, DVD_CHALLENGE_SIZE );
+
+#else
+# error "DVD ioctls are unavailable on this system"
+
+#endif
+ return i_ret;
+}
+
+/*****************************************************************************
+ * ioctl_ReportASF: get ASF from the drive
+ *****************************************************************************/
+int ioctl_ReportASF( int i_fd, int *pi_remove_me, int *pi_asf )
+{
+ int i_ret;
+
+#if defined( HAVE_LINUX_DVD_STRUCT )
+ dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.type = DVD_LU_SEND_ASF;
+ auth_info.lsasf.asf = *pi_asf;
+
+ i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
+
+ *pi_asf = auth_info.lsasf.asf;
+
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.format = DVD_REPORT_ASF;
+ auth_info.asf = *pi_asf;
+
+ i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
+
+ *pi_asf = auth_info.asf;
+
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_REPORT_KEY, 8 );
+
+ rdc.command[ 10 ] = DVD_REPORT_ASF;
+
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
+
+ *pi_asf = p_buffer[ 7 ] & 1;
+
+#elif defined( HPUX_SCTL_IO )
+ INIT_SCTL_IO( GPCMD_REPORT_KEY, 8 );
+
+ sctl_io.cdb[ 10 ] = DVD_REPORT_ASF;
+
+ i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
+
+ *pi_asf = p_buffer[ 7 ] & 1;
+
+#elif defined( SOLARIS_USCSI )
+ INIT_USCSI( GPCMD_REPORT_KEY, 8 );
+
+ rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_ASF;
+
+ i_ret = SolarisSendUSCSI( i_fd, &sc );
+
+ if( i_ret < 0 || sc.uscsi_status )
+ {
+ i_ret = -1;
+ }
+
+ *pi_asf = p_buffer[ 7 ] & 1;
+
+#elif defined( DARWIN_DVD_IOCTL )
+ INIT_DVDIOCTL( dk_dvd_report_key_t, DVDAuthenticationSuccessFlagInfo,
+ kDVDKeyFormatASF );
+
+ i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
+
+ *pi_asf = dvdbs.successFlag;
+
+#elif defined( WIN32 )
+ if( WIN2K ) /* NT/2k/XP */
+ {
+ DWORD tmp;
+ uint8_t buffer[DVD_ASF_LENGTH];
+ PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
+
+ memset( &buffer, 0, sizeof( buffer ) );
+
+ key->KeyLength = DVD_ASF_LENGTH;
+ key->KeyType = DvdAsf;
+ key->KeyFlags = 0;
+
+ ((PDVD_ASF)key->KeyData)->SuccessFlag = *pi_asf;
+
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
+ key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
+
+ if( i_ret < 0 )
+ {
+ return i_ret;
+ }
+
+ *pi_asf = ((PDVD_ASF)key->KeyData)->SuccessFlag;
+ }
+ else
+ {
+ INIT_SSC( GPCMD_REPORT_KEY, 8 );
+
+ ssc.CDBByte[ 10 ] = DVD_REPORT_ASF;
+
+ i_ret = WinSendSSC( i_fd, &ssc );
+
+ *pi_asf = p_buffer[ 7 ] & 1;
+ }
+
+#elif defined( __QNXNTO__ )
+
+ INIT_CPT( GPCMD_REPORT_KEY, 8 );
+
+ p_cpt->cam_cdb[ 10 ] = DVD_REPORT_ASF;
+
+ i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
+
+ *pi_asf = p_buffer[ 7 ] & 1;
+
+#elif defined( SYS_OS2 )
+ INIT_SSC( GPCMD_REPORT_KEY, 8 );
+
+ sdc.command[ 10 ] = DVD_REPORT_ASF;
+
+ i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
+ &sdc, sizeof(sdc), &ulParamLen,
+ p_buffer, sizeof(p_buffer), &ulDataLen);
+
+ *pi_asf = p_buffer[ 7 ] & 1;
+
+#else
+# error "DVD ioctls are unavailable on this system"
+
+#endif
+ return i_ret;
+}
+
+/*****************************************************************************
+ * ioctl_ReportKey1: get the first key from the drive
+ *****************************************************************************/
+int ioctl_ReportKey1( int i_fd, int *pi_agid, uint8_t *p_key )
+{
+ int i_ret;
+
+#if defined( HAVE_LINUX_DVD_STRUCT )
+ dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.type = DVD_LU_SEND_KEY1;
+ auth_info.lsk.agid = *pi_agid;
+
+ i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
+
+ memcpy( p_key, auth_info.lsk.key, DVD_KEY_SIZE );
+
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.format = DVD_REPORT_KEY1;
+ auth_info.agid = *pi_agid;
+
+ i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
+
+ memcpy( p_key, auth_info.keychal, DVD_KEY_SIZE );
+
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_REPORT_KEY, 12 );
+
+ rdc.command[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
+
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
+
+ memcpy( p_key, p_buffer + 4, DVD_KEY_SIZE );
+
+#elif defined( HPUX_SCTL_IO )
+ INIT_SCTL_IO( GPCMD_REPORT_KEY, 12 );
+
+ sctl_io.cdb[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
+
+ i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
+
+ memcpy( p_key, p_buffer + 4, DVD_KEY_SIZE );
+
+#elif defined( SOLARIS_USCSI )
+ INIT_USCSI( GPCMD_REPORT_KEY, 12 );
+
+ rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
+
+ i_ret = SolarisSendUSCSI( i_fd, &sc );
+
+ if( i_ret < 0 || sc.uscsi_status )
+ {
+ i_ret = -1;
+ }
+
+ memcpy( p_key, p_buffer + 4, DVD_KEY_SIZE );
+
+#elif defined( DARWIN_DVD_IOCTL )
+ INIT_DVDIOCTL( dk_dvd_report_key_t, DVDKey1Info,
+ kDVDKeyFormatKey1 );
+
+ dvd.grantID = *pi_agid;
+
+ i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
+
+ memcpy( p_key, dvdbs.key1Value, DVD_KEY_SIZE );
+
+#elif defined( WIN32 )
+ if( WIN2K ) /* NT/2k/XP */
+ {
+ DWORD tmp;
+ uint8_t buffer[DVD_BUS_KEY_LENGTH];
+ PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
+
+ memset( &buffer, 0, sizeof( buffer ) );
+
+ key->KeyLength = DVD_BUS_KEY_LENGTH;
+ key->SessionId = *pi_agid;
+ key->KeyType = DvdBusKey1;
+ key->KeyFlags = 0;
+
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
+ key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
+
+ memcpy( p_key, key->KeyData, DVD_KEY_SIZE );
+ }
+ else
+ {
+ INIT_SSC( GPCMD_REPORT_KEY, 12 );
+
+ ssc.CDBByte[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
+
+ i_ret = WinSendSSC( i_fd, &ssc );
+
+ memcpy( p_key, p_buffer + 4, DVD_KEY_SIZE );
+ }
+
+#elif defined( __QNXNTO__ )
+
+ INIT_CPT( GPCMD_REPORT_KEY, 12 );
+
+ p_cpt->cam_cdb[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
+
+ i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
+
+ memcpy( p_key, p_buffer + 4, DVD_KEY_SIZE );
+
+#elif defined( SYS_OS2 )
+ INIT_SSC( GPCMD_REPORT_KEY, 12 );
+
+ sdc.command[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
+
+ i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
+ &sdc, sizeof(sdc), &ulParamLen,
+ p_buffer, sizeof(p_buffer), &ulDataLen);
+
+ memcpy( p_key, p_buffer + 4, DVD_KEY_SIZE );
+
+#else
+# error "DVD ioctls are unavailable on this system"
+
+#endif
+ return i_ret;
+}
+
+/*****************************************************************************
+ * ioctl_InvalidateAgid: invalidate the current AGID
+ *****************************************************************************/
+int ioctl_InvalidateAgid( int i_fd, int *pi_agid )
+{
+ int i_ret;
+
+#if defined( HAVE_LINUX_DVD_STRUCT )
+ dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.type = DVD_INVALIDATE_AGID;
+ auth_info.lsa.agid = *pi_agid;
+
+ i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
+
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.format = DVD_INVALIDATE_AGID;
+ auth_info.agid = *pi_agid;
+
+ i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
+
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_REPORT_KEY, 0 );
+
+ rdc.command[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
+
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
+
+#elif defined( HPUX_SCTL_IO )
+ INIT_SCTL_IO( GPCMD_REPORT_KEY, 0 );
+
+ sctl_io.cdb[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
+
+ i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
+
+#elif defined( SOLARIS_USCSI )
+ INIT_USCSI( GPCMD_REPORT_KEY, 0 );
+
+ rs_cdb.cdb_opaque[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
+
+ i_ret = SolarisSendUSCSI( i_fd, &sc );
+
+ if( i_ret < 0 || sc.uscsi_status )
+ {
+ i_ret = -1;
+ }
+
+#elif defined( DARWIN_DVD_IOCTL )
+ INIT_DVDIOCTL( dk_dvd_send_key_t, DVDAuthenticationGrantIDInfo,
+ kDVDKeyFormatAGID_Invalidate );
+
+ dvd.grantID = *pi_agid;
+
+ i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
+
+#elif defined( WIN32 )
+ if( WIN2K ) /* NT/2k/XP */
+ {
+ DWORD tmp;
+
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_END_SESSION,
+ pi_agid, sizeof( *pi_agid ), NULL, 0, &tmp, NULL ) ? 0 : -1;
+ }
+ else
+ {
+#if defined( __MINGW32__ )
+ INIT_SSC( GPCMD_REPORT_KEY, 0 );
+#else
+ INIT_SSC( GPCMD_REPORT_KEY, 1 );
+
+ ssc.SRB_BufLen = 0;
+ ssc.CDBByte[ 8 ] = 0;
+ ssc.CDBByte[ 9 ] = 0;
+#endif
+
+ ssc.CDBByte[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
+
+ i_ret = WinSendSSC( i_fd, &ssc );
+ }
+
+#elif defined( __QNXNTO__ )
+
+ INIT_CPT( GPCMD_REPORT_KEY, 0 );
+
+ p_cpt->cam_cdb[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
+
+ i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
+
+#elif defined( SYS_OS2 )
+ INIT_SSC( GPCMD_REPORT_KEY, 1 );
+
+ sdc.data_length = 0;
+ sdc.command[ 8 ] = 0;
+ sdc.command[ 9 ] = 0;
+
+ sdc.command[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
+
+ i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
+ &sdc, sizeof(sdc), &ulParamLen,
+ NULL, 0, &ulDataLen);
+#else
+# error "DVD ioctls are unavailable on this system"
+
+#endif
+ return i_ret;
+}
+
+/*****************************************************************************
+ * ioctl_SendChallenge: send challenge to the drive
+ *****************************************************************************/
+int ioctl_SendChallenge( int i_fd, int *pi_agid, uint8_t *p_challenge )
+{
+ int i_ret;
+
+#if defined( HAVE_LINUX_DVD_STRUCT )
+ dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.type = DVD_HOST_SEND_CHALLENGE;
+ auth_info.hsc.agid = *pi_agid;
+
+ memcpy( auth_info.hsc.chal, p_challenge, DVD_CHALLENGE_SIZE );
+
+ i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
+
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.format = DVD_SEND_CHALLENGE;
+ auth_info.agid = *pi_agid;
+
+ memcpy( auth_info.keychal, p_challenge, DVD_CHALLENGE_SIZE );
+
+ i_ret = ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
+
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_SEND_KEY, 16 );
+
+ rdc.command[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
+
+ p_buffer[ 1 ] = 0xe;
+ memcpy( p_buffer + 4, p_challenge, DVD_CHALLENGE_SIZE );
+
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
+
+#elif defined( HPUX_SCTL_IO )
+ INIT_SCTL_IO( GPCMD_SEND_KEY, 16 );
+
+ sctl_io.cdb[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
+
+ p_buffer[ 1 ] = 0xe;
+ memcpy( p_buffer + 4, p_challenge, DVD_CHALLENGE_SIZE );
+
+ i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
+
+#elif defined( SOLARIS_USCSI )
+ INIT_USCSI( GPCMD_SEND_KEY, 16 );
+
+ rs_cdb.cdb_opaque[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
+
+ p_buffer[ 1 ] = 0xe;
+ memcpy( p_buffer + 4, p_challenge, DVD_CHALLENGE_SIZE );
+
+ if( SolarisSendUSCSI( i_fd, &sc ) < 0 || sc.uscsi_status )
+ {
+ return -1;
+ }
+
+ i_ret = 0;
+
+#elif defined( DARWIN_DVD_IOCTL )
+ INIT_DVDIOCTL( dk_dvd_send_key_t, DVDChallengeKeyInfo,
+ kDVDKeyFormatChallengeKey );
+
+ dvd.grantID = *pi_agid;
+ dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
+
+ dvdbs.dataLength[ 1 ] = 0xe;
+ memcpy( dvdbs.challengeKeyValue, p_challenge, DVD_CHALLENGE_SIZE );
+
+ i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
+
+#elif defined( WIN32 )
+ if( WIN2K ) /* NT/2k/XP */
+ {
+ DWORD tmp;
+ uint8_t buffer[DVD_CHALLENGE_KEY_LENGTH];
+ PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
+
+ memset( &buffer, 0, sizeof( buffer ) );
+
+ key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
+ key->SessionId = *pi_agid;
+ key->KeyType = DvdChallengeKey;
+ key->KeyFlags = 0;
+
+ memcpy( key->KeyData, p_challenge, DVD_CHALLENGE_SIZE );
+
+#if defined(_XBOX)
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key,
+ key->KeyLength, NULL, 0, &tmp, NULL ) ? 0 : -1;
+#else
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key,
+ key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
+#endif
+ }
+ else
+ {
+ INIT_SSC( GPCMD_SEND_KEY, 16 );
+
+ ssc.CDBByte[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
+
+ p_buffer[ 1 ] = 0xe;
+ memcpy( p_buffer + 4, p_challenge, DVD_CHALLENGE_SIZE );
+
+ i_ret = WinSendSSC( i_fd, &ssc );
+ }
+
+#elif defined( __QNXNTO__ )
+
+ INIT_CPT( GPCMD_SEND_KEY, 16 );
+
+ p_cpt->cam_cdb[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
+
+ p_buffer[ 1 ] = 0xe;
+ memcpy( p_buffer + 4, p_challenge, DVD_CHALLENGE_SIZE );
+
+ i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
+
+#elif defined( SYS_OS2 )
+ INIT_SSC( GPCMD_SEND_KEY, 16 );
+
+ sdc.command[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
+
+ p_buffer[ 1 ] = 0xe;
+ memcpy( p_buffer + 4, p_challenge, DVD_CHALLENGE_SIZE );
+
+ i_ret = DosDevIOCtl( i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
+ &sdc, sizeof(sdc), &ulParamLen,
+ p_buffer, sizeof(p_buffer), &ulDataLen );
+
+#else
+# error "DVD ioctls are unavailable on this system"
+
+#endif
+ return i_ret;
+}
+
+/*****************************************************************************
+ * ioctl_SendKey2: send the second key to the drive
+ *****************************************************************************/
+int ioctl_SendKey2( int i_fd, int *pi_agid, uint8_t *p_key )
+{
+ int i_ret;
+
+#if defined( HAVE_LINUX_DVD_STRUCT )
+ dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.type = DVD_HOST_SEND_KEY2;
+ auth_info.hsk.agid = *pi_agid;
+
+ memcpy( auth_info.hsk.key, p_key, DVD_KEY_SIZE );
+
+ i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
+
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.format = DVD_SEND_KEY2;
+ auth_info.agid = *pi_agid;
+
+ memcpy( auth_info.keychal, p_key, DVD_KEY_SIZE );
+
+ i_ret = ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
+
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_SEND_KEY, 12 );
+
+ rdc.command[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
+
+ p_buffer[ 1 ] = 0xa;
+ memcpy( p_buffer + 4, p_key, DVD_KEY_SIZE );
+
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
+
+#elif defined( HPUX_SCTL_IO )
+ INIT_SCTL_IO( GPCMD_SEND_KEY, 12 );
+
+ sctl_io.cdb[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
+
+ p_buffer[ 1 ] = 0xa;
+ memcpy( p_buffer + 4, p_key, DVD_KEY_SIZE );
+
+ i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
+
+#elif defined( SOLARIS_USCSI )
+ INIT_USCSI( GPCMD_SEND_KEY, 12 );
+
+ rs_cdb.cdb_opaque[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
+
+ p_buffer[ 1 ] = 0xa;
+ memcpy( p_buffer + 4, p_key, DVD_KEY_SIZE );
+
+ if( SolarisSendUSCSI( i_fd, &sc ) < 0 || sc.uscsi_status )
+ {
+ return -1;
+ }
+
+ i_ret = 0;
+
+#elif defined( DARWIN_DVD_IOCTL )
+ INIT_DVDIOCTL( dk_dvd_send_key_t, DVDKey2Info,
+ kDVDKeyFormatKey2 );
+
+ dvd.grantID = *pi_agid;
+ dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
+
+ dvdbs.dataLength[ 1 ] = 0xa;
+ memcpy( dvdbs.key2Value, p_key, DVD_KEY_SIZE );
+
+ i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
+
+#elif defined( WIN32 )
+ if( WIN2K ) /* NT/2k/XP */
+ {
+ DWORD tmp;
+ uint8_t buffer[DVD_BUS_KEY_LENGTH];
+ PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
+
+ memset( &buffer, 0, sizeof( buffer ) );
+
+ key->KeyLength = DVD_BUS_KEY_LENGTH;
+ key->SessionId = *pi_agid;
+ key->KeyType = DvdBusKey2;
+ key->KeyFlags = 0;
+
+ memcpy( key->KeyData, p_key, DVD_KEY_SIZE );
+
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key,
+ key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
+ }
+ else
+ {
+ INIT_SSC( GPCMD_SEND_KEY, 12 );
+
+ ssc.CDBByte[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
+
+ p_buffer[ 1 ] = 0xa;
+ memcpy( p_buffer + 4, p_key, DVD_KEY_SIZE );
+
+ i_ret = WinSendSSC( i_fd, &ssc );
+ }
+
+#elif defined( __QNXNTO__ )
+
+ INIT_CPT( GPCMD_SEND_KEY, 12 );
+
+ p_cpt->cam_cdb[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
+
+ p_buffer[ 1 ] = 0xa;
+ memcpy( p_buffer + 4, p_key, DVD_KEY_SIZE );
+
+ i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
+
+#elif defined( SYS_OS2 )
+ INIT_SSC( GPCMD_SEND_KEY, 12 );
+
+ sdc.command[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
+
+ p_buffer[ 1 ] = 0xa;
+ memcpy( p_buffer + 4, p_key, DVD_KEY_SIZE );
+
+ i_ret = DosDevIOCtl( i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
+ &sdc, sizeof(sdc), &ulParamLen,
+ p_buffer, sizeof(p_buffer), &ulDataLen );
+
+#else
+# error "DVD ioctls are unavailable on this system"
+
+#endif
+ return i_ret;
+}
+
+/*****************************************************************************
+ * ioctl_ReportRPC: get RPC status for the drive
+ *****************************************************************************/
+int ioctl_ReportRPC( int i_fd, int *p_type, int *p_mask, int *p_scheme )
+{
+ int i_ret;
+
+#if defined( HAVE_LINUX_DVD_STRUCT ) && defined( DVD_LU_SEND_RPC_STATE )
+ dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.type = DVD_LU_SEND_RPC_STATE;
+
+ i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
+
+ *p_type = auth_info.lrpcs.type;
+ *p_mask = auth_info.lrpcs.region_mask;
+ *p_scheme = auth_info.lrpcs.rpc_scheme;
+
+#elif defined( HAVE_LINUX_DVD_STRUCT )
+ /* FIXME: OpenBSD doesn't know this */
+ i_ret = -1;
+
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.format = DVD_REPORT_RPC;
+
+ i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
+
+ *p_type = auth_info.reg_type;
+ *p_mask = auth_info.region; // ??
+ *p_scheme = auth_info.rpc_scheme;
+
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_REPORT_KEY, 8 );
+
+ rdc.command[ 10 ] = DVD_REPORT_RPC;
+
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
+
+ *p_type = p_buffer[ 4 ] >> 6;
+ *p_mask = p_buffer[ 5 ];
+ *p_scheme = p_buffer[ 6 ];
+
+#elif defined( HPUX_SCTL_IO )
+ INIT_SCTL_IO( GPCMD_REPORT_KEY, 8 );
+
+ sctl_io.cdb[ 10 ] = DVD_REPORT_RPC;
+
+ i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
+
+ *p_type = p_buffer[ 4 ] >> 6;
+ *p_mask = p_buffer[ 5 ];
+ *p_scheme = p_buffer[ 6 ];
+
+#elif defined( SOLARIS_USCSI )
+ INIT_USCSI( GPCMD_REPORT_KEY, 8 );
+
+ rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_RPC;
+
+ i_ret = SolarisSendUSCSI( i_fd, &sc );
+
+ if( i_ret < 0 || sc.uscsi_status )
+ {
+ i_ret = -1;
+ }
+
+ *p_type = p_buffer[ 4 ] >> 6;
+ *p_mask = p_buffer[ 5 ];
+ *p_scheme = p_buffer[ 6 ];
+
+#elif defined( DARWIN_DVD_IOCTL )
+ INIT_DVDIOCTL( dk_dvd_report_key_t, DVDRegionPlaybackControlInfo,
+ kDVDKeyFormatRegionState );
+
+ dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
+
+ i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
+
+ *p_type = dvdbs.typeCode;
+ *p_mask = dvdbs.driveRegion;
+ *p_scheme = dvdbs.rpcScheme;
+
+#elif defined( WIN32 )
+ if( WIN2K ) /* NT/2k/XP */
+ {
+ DWORD tmp;
+ uint8_t buffer[DVD_RPC_KEY_LENGTH];
+ PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
+
+ memset( &buffer, 0, sizeof( buffer ) );
+
+ key->KeyLength = DVD_RPC_KEY_LENGTH;
+ key->KeyType = DvdGetRpcKey;
+ key->KeyFlags = 0;
+
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
+ key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
+
+ if( i_ret < 0 )
+ {
+ return i_ret;
+ }
+
+ *p_type = ((PDVD_RPC_KEY)key->KeyData)->TypeCode;
+ *p_mask = ((PDVD_RPC_KEY)key->KeyData)->RegionMask;
+ *p_scheme = ((PDVD_RPC_KEY)key->KeyData)->RpcScheme;
+ }
+ else
+ {
+ INIT_SSC( GPCMD_REPORT_KEY, 8 );
+
+ ssc.CDBByte[ 10 ] = DVD_REPORT_RPC;
+
+ i_ret = WinSendSSC( i_fd, &ssc );
+
+ *p_type = p_buffer[ 4 ] >> 6;
+ *p_mask = p_buffer[ 5 ];
+ *p_scheme = p_buffer[ 6 ];
+ }
+
+#elif defined( __QNXNTO__ )
+
+ INIT_CPT( GPCMD_REPORT_KEY, 8 );
+
+ p_cpt->cam_cdb[ 10 ] = DVD_REPORT_RPC;
+
+ i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
+
+ *p_type = p_buffer[ 4 ] >> 6;
+ *p_mask = p_buffer[ 5 ];
+ *p_scheme = p_buffer[ 6 ];
+
+#elif defined( SYS_OS2 )
+ INIT_SSC( GPCMD_REPORT_KEY, 8 );
+
+ sdc.command[ 10 ] = DVD_REPORT_RPC;
+
+ i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
+ &sdc, sizeof(sdc), &ulParamLen,
+ p_buffer, sizeof(p_buffer), &ulDataLen);
+
+ *p_type = p_buffer[ 4 ] >> 6;
+ *p_mask = p_buffer[ 5 ];
+ *p_scheme = p_buffer[ 6 ];
+
+#else
+# error "DVD ioctls are unavailable on this system"
+
+#endif
+ return i_ret;
+}
+
+/*****************************************************************************
+ * ioctl_SendRPC: set RPC status for the drive
+ *****************************************************************************/
+int ioctl_SendRPC( int i_fd, int i_pdrc )
+{
+ int i_ret;
+
+#if defined( HAVE_LINUX_DVD_STRUCT ) && defined( DVD_HOST_SEND_RPC_STATE )
+ dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.type = DVD_HOST_SEND_RPC_STATE;
+ auth_info.hrpcs.pdrc = i_pdrc;
+
+ i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
+
+#elif defined( HAVE_LINUX_DVD_STRUCT )
+ /* FIXME: OpenBSD doesn't know this */
+ i_ret = -1;
+
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_authinfo auth_info;
+
+ memset( &auth_info, 0, sizeof( auth_info ) );
+ auth_info.format = DVD_SEND_RPC;
+ auth_info.region = i_pdrc;
+
+ i_ret = ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
+
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_SEND_KEY, 8 );
+
+ rdc.command[ 10 ] = DVD_SEND_RPC;
+
+ p_buffer[ 1 ] = 6;
+ p_buffer[ 4 ] = i_pdrc;
+
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
+
+#elif defined( HPUX_SCTL_IO )
+ INIT_SCTL_IO( GPCMD_SEND_KEY, 8 );
+
+ sctl_io.cdb[ 10 ] = DVD_SEND_RPC;
+
+ p_buffer[ 1 ] = 6;
+ p_buffer[ 4 ] = i_pdrc;
+
+ i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
+
+#elif defined( SOLARIS_USCSI )
+ INIT_USCSI( GPCMD_SEND_KEY, 8 );
+
+ rs_cdb.cdb_opaque[ 10 ] = DVD_SEND_RPC;
+
+ p_buffer[ 1 ] = 6;
+ p_buffer[ 4 ] = i_pdrc;
+
+ i_ret = SolarisSendUSCSI( i_fd, &sc );
+
+ if( i_ret < 0 || sc.uscsi_status )
+ {
+ i_ret = -1;
+ }
+
+#elif defined( DARWIN_DVD_IOCTL )
+ INIT_DVDIOCTL( dk_dvd_send_key_t, DVDRegionPlaybackControlInfo,
+ kDVDKeyFormatSetRegion );
+
+ dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
+ dvdbs.driveRegion = i_pdrc;
+
+ i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
+
+#elif defined( WIN32 )
+ if( WIN2K ) /* NT/2k/XP */
+ {
+ INIT_SPTD( GPCMD_SEND_KEY, 8 );
+
+ sptd.Cdb[ 10 ] = DVD_SEND_RPC;
+
+ p_buffer[ 1 ] = 6;
+ p_buffer[ 4 ] = i_pdrc;
+
+ i_ret = SEND_SPTD( i_fd, &sptd, &tmp );
+ }
+ else
+ {
+ INIT_SSC( GPCMD_SEND_KEY, 8 );
+
+ ssc.CDBByte[ 10 ] = DVD_SEND_RPC;
+
+ p_buffer[ 1 ] = 6;
+ p_buffer[ 4 ] = i_pdrc;
+
+ i_ret = WinSendSSC( i_fd, &ssc );
+ }
+
+#elif defined( __QNXNTO__ )
+
+ INIT_CPT( GPCMD_SEND_KEY, 8 );
+
+ p_cpt->cam_cdb[ 10 ] = DVD_SEND_RPC;
+
+ p_buffer[ 1 ] = 6;
+ p_buffer[ 4 ] = i_pdrc;
+
+ i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
+
+#elif defined( SYS_OS2 )
+ INIT_SSC( GPCMD_SEND_KEY, 8 );
+
+ sdc.command[ 10 ] = DVD_SEND_RPC;
+
+ p_buffer[ 1 ] = 6;
+ p_buffer[ 4 ] = i_pdrc;
+
+ i_ret = DosDevIOCtl( i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
+ &sdc, sizeof(sdc), &ulParamLen,
+ p_buffer, sizeof(p_buffer), &ulDataLen );
+
+#else
+# error "DVD ioctls are unavailable on this system"
+
+#endif
+ return i_ret;
+}
+
+/* Local prototypes */
+
+#if defined( SYS_BEOS )
+/*****************************************************************************
+ * BeInitRDC: initialize a RDC structure for the BeOS kernel
+ *****************************************************************************
+ * This function initializes a BeOS raw device command structure for future
+ * use, either a read command or a write command.
+ *****************************************************************************/
+static void BeInitRDC( raw_device_command *p_rdc, int i_type )
+{
+ memset( p_rdc->data, 0, p_rdc->data_length );
+
+ switch( i_type )
+ {
+ case GPCMD_SEND_KEY:
+ /* leave the flags to 0 */
+ break;
+
+ case GPCMD_READ_DVD_STRUCTURE: case GPCMD_REPORT_KEY:
+ p_rdc->flags = B_RAW_DEVICE_DATA_IN; break; }
+
+ p_rdc->command[ 0 ] = i_type;
+
+ p_rdc->command[ 8 ] = (p_rdc->data_length >> 8) & 0xff;
+ p_rdc->command[ 9 ] = p_rdc->data_length & 0xff;
+ p_rdc->command_length = 12;
+
+ p_rdc->sense_data = NULL;
+ p_rdc->sense_data_length = 0;
+
+ p_rdc->timeout = 1000000;
+}
+#endif
+
+#if defined( HPUX_SCTL_IO )
+/*****************************************************************************
+ * HPUXInitSCTL: initialize a sctl_io structure for the HP-UX kernel
+ *****************************************************************************
+ * This function initializes a HP-UX command structure for future
+ * use, either a read command or a write command.
+ *****************************************************************************/
+static void HPUXInitSCTL( struct sctl_io *sctl_io, int i_type )
+{
+ memset( sctl_io->data, 0, sctl_io->data_length );
+
+ switch( i_type )
+ {
+ case GPCMD_SEND_KEY:
+ /* leave the flags to 0 */
+ break;
+
+ case GPCMD_READ_DVD_STRUCTURE:
+ case GPCMD_REPORT_KEY:
+ sctl_io->flags = SCTL_READ;
+ break;
+ }
+
+ sctl_io->cdb[ 0 ] = i_type;
+
+ sctl_io->cdb[ 8 ] = (sctl_io->data_length >> 8) & 0xff;
+ sctl_io->cdb[ 9 ] = sctl_io->data_length & 0xff;
+ sctl_io->cdb_length = 12;
+
+ sctl_io->max_msecs = 1000000;
+}
+#endif
+
+#if defined( SOLARIS_USCSI )
+/*****************************************************************************
+ * SolarisInitUSCSI: initialize a USCSICMD structure for the Solaris kernel
+ *****************************************************************************
+ * This function initializes a Solaris userspace scsi command structure for
+ * future use, either a read command or a write command.
+ *****************************************************************************/
+static void SolarisInitUSCSI( struct uscsi_cmd *p_sc, int i_type )
+{
+ union scsi_cdb *rs_cdb;
+ memset( p_sc->uscsi_cdb, 0, sizeof( union scsi_cdb ) );
+ memset( p_sc->uscsi_bufaddr, 0, p_sc->uscsi_buflen );
+
+ switch( i_type )
+ {
+ case GPCMD_SEND_KEY:
+ p_sc->uscsi_flags = USCSI_ISOLATE | USCSI_WRITE;
+ break;
+
+ case GPCMD_READ_DVD_STRUCTURE:
+ case GPCMD_REPORT_KEY:
+ p_sc->uscsi_flags = USCSI_ISOLATE | USCSI_READ;
+ break;
+ }
+
+ rs_cdb = (union scsi_cdb *)p_sc->uscsi_cdb;
+
+ rs_cdb->scc_cmd = i_type;
+
+ rs_cdb->cdb_opaque[ 8 ] = (p_sc->uscsi_buflen >> 8) & 0xff;
+ rs_cdb->cdb_opaque[ 9 ] = p_sc->uscsi_buflen & 0xff;
+ p_sc->uscsi_cdblen = 12;
+
+ USCSI_TIMEOUT( p_sc, 15 );
+}
+
+/*****************************************************************************
+ * SolarisSendUSCSI: send a USCSICMD structure to the Solaris kernel
+ * for execution
+ *****************************************************************************
+ * When available, this function uses the function smedia_uscsi_cmd()
+ * from Solaris' libsmedia library (Solaris 9 or newer) to execute the
+ * USCSI command. smedia_uscsi_cmd() allows USCSI commands for
+ * non-root users on removable media devices on Solaris 9; sending the
+ * USCSI command directly to the device using the USCSICMD ioctl fails
+ * with an EPERM error on Solaris 9.
+ *
+ * The code will fall back to the USCSICMD ioctl method, when
+ * libsmedia.so is not available or does not export the
+ * smedia_uscsi_cmd() function (on Solaris releases upto and including
+ * Solaris 8). Fortunatelly, on these old releases non-root users are
+ * allowed to perform USCSICMD ioctls on removable media devices.
+ *****************************************************************************/
+static int SolarisSendUSCSI( int i_fd, struct uscsi_cmd *p_sc )
+{
+ void *p_handle;
+
+ /* We use static variables to keep track of the libsmedia symbols, which
+ * is harmless even in a multithreaded program because the library and
+ * its symbols will always be mapped at the same address. */
+ static int b_tried = 0;
+ static int b_have_sm = 0;
+ static void * (*p_get_handle) ( int32_t );
+ static int (*p_uscsi_cmd) ( void *, struct uscsi_cmd * );
+ static int (*p_release_handle) ( void * );
+
+ if( !b_tried )
+ {
+ void *p_lib;
+
+ p_lib = dlopen( "libsmedia.so", RTLD_NOW );
+ if( p_lib )
+ {
+ p_get_handle = dlsym( p_lib, "smedia_get_handle" );
+ p_uscsi_cmd = dlsym( p_lib, "smedia_uscsi_cmd" );
+ p_release_handle = dlsym( p_lib, "smedia_release_handle" );
+
+ if( p_get_handle && p_uscsi_cmd && p_release_handle )
+ {
+ b_have_sm = 1;
+ }
+ else
+ {
+ dlclose( p_lib );
+ }
+ }
+
+ b_tried = 1;
+ }
+
+ if( b_have_sm && (p_handle = p_get_handle(i_fd)) )
+ {
+ int i_ret = p_uscsi_cmd( p_handle, p_sc );
+ p_release_handle( p_handle );
+ return i_ret;
+ }
+
+ return ioctl( i_fd, USCSICMD, p_sc );
+}
+#endif
+
+#if defined( WIN32 )
+/*****************************************************************************
+ * WinInitSPTD: initialize a sptd structure
+ *****************************************************************************
+ * This function initializes a SCSI pass through command structure for future
+ * use, either a read command or a write command.
+ *****************************************************************************/
+static void WinInitSPTD( SCSI_PASS_THROUGH_DIRECT *p_sptd, int i_type )
+{
+ memset( p_sptd->DataBuffer, 0, p_sptd->DataTransferLength );
+
+ switch( i_type )
+ {
+ case GPCMD_SEND_KEY:
+ p_sptd->DataIn = SCSI_IOCTL_DATA_OUT;
+ break;
+
+ case GPCMD_READ_DVD_STRUCTURE:
+ case GPCMD_REPORT_KEY:
+ p_sptd->DataIn = SCSI_IOCTL_DATA_IN;
+ break;
+ }
+
+ p_sptd->Cdb[ 0 ] = i_type;
+ p_sptd->Cdb[ 8 ] = (uint8_t)(p_sptd->DataTransferLength >> 8) & 0xff;
+ p_sptd->Cdb[ 9 ] = (uint8_t) p_sptd->DataTransferLength & 0xff;
+ p_sptd->CdbLength = 12;
+
+ p_sptd->TimeOutValue = 2;
+}
+
+/*****************************************************************************
+ * WinInitSSC: initialize a ssc structure for the win32 aspi layer
+ *****************************************************************************
+ * This function initializes a ssc raw device command structure for future
+ * use, either a read command or a write command.
+ *****************************************************************************/
+static void WinInitSSC( struct SRB_ExecSCSICmd *p_ssc, int i_type )
+{
+ memset( p_ssc->SRB_BufPointer, 0, p_ssc->SRB_BufLen );
+
+ switch( i_type )
+ {
+ case GPCMD_SEND_KEY:
+ p_ssc->SRB_Flags = SRB_DIR_OUT;
+ break;
+
+ case GPCMD_READ_DVD_STRUCTURE:
+ case GPCMD_REPORT_KEY:
+ p_ssc->SRB_Flags = SRB_DIR_IN;
+ break;
+ }
+
+ p_ssc->SRB_Cmd = SC_EXEC_SCSI_CMD;
+ p_ssc->SRB_Flags |= SRB_EVENT_NOTIFY;
+
+ p_ssc->CDBByte[ 0 ] = i_type;
+
+ p_ssc->CDBByte[ 8 ] = (uint8_t)(p_ssc->SRB_BufLen >> 8) & 0xff;
+ p_ssc->CDBByte[ 9 ] = (uint8_t) p_ssc->SRB_BufLen & 0xff;
+ p_ssc->SRB_CDBLen = 12;
+
+ p_ssc->SRB_SenseLen = SENSE_LEN;
+}
+
+/*****************************************************************************
+ * WinSendSSC: send a ssc structure to the aspi layer
+ *****************************************************************************/
+static int WinSendSSC( int i_fd, struct SRB_ExecSCSICmd *p_ssc )
+{
+ HANDLE hEvent = NULL;
+ struct w32_aspidev *fd = (struct w32_aspidev *) i_fd;
+
+ hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+ if( hEvent == NULL )
+ {
+ return -1;
+ }
+
+ p_ssc->SRB_PostProc = hEvent;
+ p_ssc->SRB_HaId = LOBYTE( fd->i_sid );
+ p_ssc->SRB_Target = HIBYTE( fd->i_sid );
+
+ ResetEvent( hEvent );
+ if( fd->lpSendCommand( (void*) p_ssc ) == SS_PENDING )
+ WaitForSingleObject( hEvent, INFINITE );
+
+ CloseHandle( hEvent );
+
+ return p_ssc->SRB_Status == SS_COMP ? 0 : -1;
+}
+#endif
+
+#if defined( __QNXNTO__ )
+/*****************************************************************************
+ * QNXInitCPT: initialize a CPT structure for QNX Neutrino
+ *****************************************************************************
+ * This function initializes a cpt command structure for future use,
+ * either a read command or a write command.
+ *****************************************************************************/
+static void QNXInitCPT( CAM_PASS_THRU * p_cpt, int i_type )
+{
+ switch( i_type )
+ {
+ case GPCMD_SEND_KEY:
+ p_cpt->cam_flags = CAM_DIR_OUT;
+ break;
+
+ case GPCMD_READ_DVD_STRUCTURE:
+ case GPCMD_REPORT_KEY:
+ p_cpt->cam_flags = CAM_DIR_IN;
+ break;
+ }
+
+ p_cpt->cam_cdb[0] = i_type;
+
+ p_cpt->cam_cdb[ 8 ] = (p_cpt->cam_dxfer_len >> 8) & 0xff;
+ p_cpt->cam_cdb[ 9 ] = p_cpt->cam_dxfer_len & 0xff;
+ p_cpt->cam_cdb_len = 12;
+
+ p_cpt->cam_timeout = CAM_TIME_DEFAULT;
+}
+#endif
+
+#if defined( SYS_OS2 )
+/*****************************************************************************
+ * OS2InitSDC: initialize a SDC structure for the Execute SCSI-command
+ *****************************************************************************
+ * This function initializes a OS2 'execute SCSI command' structure for
+ * future use, either a read command or a write command.
+ *****************************************************************************/
+static void OS2InitSDC( struct OS2_ExecSCSICmd *p_sdc, int i_type )
+{
+ switch( i_type )
+ {
+ case GPCMD_SEND_KEY:
+ p_sdc->flags = 0;
+ break;
+
+ case GPCMD_READ_DVD_STRUCTURE:
+ case GPCMD_REPORT_KEY:
+ p_sdc->flags = EX_DIRECTION_IN;
+ break;
+ }
+
+ p_sdc->command[ 0 ] = i_type;
+ p_sdc->command[ 8 ] = (p_sdc->data_length >> 8) & 0xff;
+ p_sdc->command[ 9 ] = p_sdc->data_length & 0xff;
+ p_sdc->id_code = 0x31304443; // 'CD01'
+ p_sdc->cmd_length = 12;
+}
+#endif
diff --git a/lib/libdvd/libdvdcss/src/ioctl.h b/lib/libdvd/libdvdcss/src/ioctl.h
new file mode 100644
index 0000000000..b1ea287b0a
--- /dev/null
+++ b/lib/libdvd/libdvdcss/src/ioctl.h
@@ -0,0 +1,433 @@
+/*****************************************************************************
+ * ioctl.h: DVD ioctl replacement function
+ *****************************************************************************
+ * Copyright (C) 1999-2001 VideoLAN
+ * $Id$
+ *
+ * Authors: Sam 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.
+ *****************************************************************************/
+
+int ioctl_ReadCopyright ( int, int, int * );
+int ioctl_ReadDiscKey ( int, int *, uint8_t * );
+int ioctl_ReadTitleKey ( int, int *, int, uint8_t * );
+int ioctl_ReportAgid ( int, int * );
+int ioctl_ReportChallenge ( int, int *, uint8_t * );
+int ioctl_ReportKey1 ( int, int *, uint8_t * );
+int ioctl_ReportASF ( int, int *, int * );
+int ioctl_InvalidateAgid ( int, int * );
+int ioctl_SendChallenge ( int, int *, uint8_t * );
+int ioctl_SendKey2 ( int, int *, uint8_t * );
+int ioctl_ReportRPC ( int, int *, int *, int * );
+int ioctl_SendRPC ( int, int );
+
+#define DVD_KEY_SIZE 5
+#define DVD_CHALLENGE_SIZE 10
+#define DVD_DISCKEY_SIZE 2048
+
+/*****************************************************************************
+ * Common macro, BeOS specific
+ *****************************************************************************/
+#if defined( SYS_BEOS )
+#define INIT_RDC( TYPE, SIZE ) \
+ raw_device_command rdc; \
+ uint8_t p_buffer[ (SIZE)+1 ]; \
+ memset( &rdc, 0, sizeof( raw_device_command ) ); \
+ rdc.data = (char *)p_buffer; \
+ rdc.data_length = (SIZE); \
+ BeInitRDC( &rdc, (TYPE) );
+#endif
+
+/*****************************************************************************
+ * Common macro, HP-UX specific
+ *****************************************************************************/
+#if defined( HPUX_SCTL_IO )
+#define INIT_SCTL_IO( TYPE, SIZE ) \
+ struct sctl_io sctl_io; \
+ uint8_t p_buffer[ (SIZE)+1 ]; \
+ memset( &sctl_io, 0, sizeof( sctl_io ) ); \
+ sctl_io.data = (void *)p_buffer; \
+ sctl_io.data_length = (SIZE); \
+ HPUXInitSCTL( &sctl_io, (TYPE) );
+#endif
+
+/*****************************************************************************
+ * Common macro, Solaris specific
+ *****************************************************************************/
+#if defined( SOLARIS_USCSI )
+#define USCSI_TIMEOUT( SC, TO ) ( (SC)->uscsi_timeout = (TO) )
+#define USCSI_RESID( SC ) ( (SC)->uscsi_resid )
+#define INIT_USCSI( TYPE, SIZE ) \
+ struct uscsi_cmd sc; \
+ union scsi_cdb rs_cdb; \
+ uint8_t p_buffer[ (SIZE)+1 ]; \
+ memset( &sc, 0, sizeof( struct uscsi_cmd ) ); \
+ sc.uscsi_cdb = (caddr_t)&rs_cdb; \
+ sc.uscsi_bufaddr = (caddr_t)p_buffer; \
+ sc.uscsi_buflen = (SIZE); \
+ SolarisInitUSCSI( &sc, (TYPE) );
+#endif
+
+/*****************************************************************************
+ * Common macro, Darwin specific
+ *****************************************************************************/
+#if defined( DARWIN_DVD_IOCTL )
+#define INIT_DVDIOCTL( DKDVD_TYPE, BUFFER_TYPE, FORMAT ) \
+ DKDVD_TYPE dvd; \
+ BUFFER_TYPE dvdbs; \
+ memset( &dvd, 0, sizeof(dvd) ); \
+ memset( &dvdbs, 0, sizeof(dvdbs) ); \
+ dvd.format = FORMAT; \
+ dvd.buffer = &dvdbs; \
+ dvd.bufferLength = sizeof(dvdbs);
+#endif
+
+/*****************************************************************************
+ * Common macro, win32 specific
+ *****************************************************************************/
+#if defined( WIN32 )
+#define INIT_SPTD( TYPE, SIZE ) \
+ DWORD tmp; \
+ SCSI_PASS_THROUGH_DIRECT sptd; \
+ uint8_t p_buffer[ (SIZE) ]; \
+ memset( &sptd, 0, sizeof( SCSI_PASS_THROUGH_DIRECT ) ); \
+ sptd.Length = sizeof( SCSI_PASS_THROUGH_DIRECT ); \
+ sptd.DataBuffer = p_buffer; \
+ sptd.DataTransferLength = (SIZE); \
+ WinInitSPTD( &sptd, (TYPE) );
+#define SEND_SPTD( DEV, SPTD, TMP ) \
+ (DeviceIoControl( (HANDLE)(DEV), IOCTL_SCSI_PASS_THROUGH_DIRECT, \
+ (SPTD), sizeof( SCSI_PASS_THROUGH_DIRECT ), \
+ (SPTD), sizeof( SCSI_PASS_THROUGH_DIRECT ), \
+ (TMP), NULL ) ? 0 : -1)
+#define INIT_SSC( TYPE, SIZE ) \
+ struct SRB_ExecSCSICmd ssc; \
+ uint8_t p_buffer[ (SIZE)+1 ]; \
+ memset( &ssc, 0, sizeof( struct SRB_ExecSCSICmd ) ); \
+ ssc.SRB_BufPointer = (char *)p_buffer; \
+ ssc.SRB_BufLen = (SIZE); \
+ WinInitSSC( &ssc, (TYPE) );
+#endif
+
+/*****************************************************************************
+ * Common macro, QNX specific
+ *****************************************************************************/
+#if defined( __QNXNTO__ )
+#define INIT_CPT( TYPE, SIZE ) \
+ CAM_PASS_THRU * p_cpt; \
+ uint8_t * p_buffer; \
+ int structSize = sizeof( CAM_PASS_THRU ) + (SIZE); \
+ p_cpt = (CAM_PASS_THRU *) malloc ( structSize ); \
+ p_buffer = (uint8_t *) p_cpt + sizeof( CAM_PASS_THRU ); \
+ memset( p_cpt, 0, structSize ); \
+ p_cpt->cam_data_ptr = sizeof( CAM_PASS_THRU ); \
+ p_cpt->cam_dxfer_len = (SIZE); \
+ QNXInitCPT( p_cpt, (TYPE) );
+#endif
+
+/*****************************************************************************
+ * Common macro, OS2 specific
+ *****************************************************************************/
+#if defined( SYS_OS2 )
+#define INIT_SSC( TYPE, SIZE ) \
+ struct OS2_ExecSCSICmd sdc; \
+ uint8_t p_buffer[ (SIZE)+1 ]; \
+ unsigned long ulParamLen; \
+ unsigned long ulDataLen; \
+ memset( &sdc, 0, sizeof( OS2_ExecSCSICmd ) ); \
+ memset( &p_buffer, 0, SIZE ); \
+ sdc.data_length = (SIZE); \
+ ulParamLen = sizeof(sdc); \
+ OS2InitSDC( &sdc, (TYPE) )
+#endif
+
+/*****************************************************************************
+ * Additional types, OpenBSD specific
+ *****************************************************************************/
+#if defined( HAVE_OPENBSD_DVD_STRUCT )
+typedef union dvd_struct dvd_struct;
+typedef union dvd_authinfo dvd_authinfo;
+#endif
+
+/*****************************************************************************
+ * Various DVD I/O tables
+ *****************************************************************************/
+#if defined( SYS_BEOS ) || defined( WIN32 ) || defined ( SOLARIS_USCSI ) || defined ( HPUX_SCTL_IO ) || defined ( __QNXNTO__ ) || defined ( SYS_OS2 )
+ /* The generic packet command opcodes for CD/DVD Logical Units,
+ * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+# define GPCMD_READ_DVD_STRUCTURE 0xad
+# define GPCMD_REPORT_KEY 0xa4
+# define GPCMD_SEND_KEY 0xa3
+ /* DVD struct types */
+# define DVD_STRUCT_PHYSICAL 0x00
+# define DVD_STRUCT_COPYRIGHT 0x01
+# define DVD_STRUCT_DISCKEY 0x02
+# define DVD_STRUCT_BCA 0x03
+# define DVD_STRUCT_MANUFACT 0x04
+ /* Key formats */
+# define DVD_REPORT_AGID 0x00
+# define DVD_REPORT_CHALLENGE 0x01
+# define DVD_SEND_CHALLENGE 0x01
+# define DVD_REPORT_KEY1 0x02
+# define DVD_SEND_KEY2 0x03
+# define DVD_REPORT_TITLE_KEY 0x04
+# define DVD_REPORT_ASF 0x05
+# define DVD_SEND_RPC 0x06
+# define DVD_REPORT_RPC 0x08
+# define DVD_INVALIDATE_AGID 0x3f
+#endif
+
+/*****************************************************************************
+ * win32 ioctl specific
+ *****************************************************************************/
+#if defined( WIN32 )
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#define IOCTL_DVD_START_SESSION CTL_CODE(FILE_DEVICE_DVD, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DVD_READ_KEY CTL_CODE(FILE_DEVICE_DVD, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DVD_SEND_KEY CTL_CODE(FILE_DEVICE_DVD, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DVD_END_SESSION CTL_CODE(FILE_DEVICE_DVD, 0x0403, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DVD_GET_REGION CTL_CODE(FILE_DEVICE_DVD, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DVD_SEND_KEY2 CTL_CODE(FILE_DEVICE_DVD, 0x0406, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_DVD_READ_STRUCTURE CTL_CODE(FILE_DEVICE_DVD, 0x0450, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(FILE_DEVICE_CONTROLLER, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define DVD_CHALLENGE_KEY_LENGTH (12 + sizeof(DVD_COPY_PROTECT_KEY))
+#define DVD_BUS_KEY_LENGTH (8 + sizeof(DVD_COPY_PROTECT_KEY))
+#define DVD_TITLE_KEY_LENGTH (8 + sizeof(DVD_COPY_PROTECT_KEY))
+#define DVD_DISK_KEY_LENGTH (2048 + sizeof(DVD_COPY_PROTECT_KEY))
+#define DVD_RPC_KEY_LENGTH (sizeof(DVD_RPC_KEY) + sizeof(DVD_COPY_PROTECT_KEY))
+#define DVD_ASF_LENGTH (sizeof(DVD_ASF) + sizeof(DVD_COPY_PROTECT_KEY))
+
+#define DVD_COPYRIGHT_MASK 0x00000040
+#define DVD_NOT_COPYRIGHTED 0x00000000
+#define DVD_COPYRIGHTED 0x00000040
+
+#define DVD_SECTOR_PROTECT_MASK 0x00000020
+#define DVD_SECTOR_NOT_PROTECTED 0x00000000
+#define DVD_SECTOR_PROTECTED 0x00000020
+
+#define SCSI_IOCTL_DATA_OUT 0
+#define SCSI_IOCTL_DATA_IN 1
+
+typedef ULONG DVD_SESSION_ID, *PDVD_SESSION_ID;
+
+typedef enum DVD_STRUCTURE_FORMAT {
+ DvdPhysicalDescriptor,
+ DvdCopyrightDescriptor,
+ DvdDiskKeyDescriptor,
+ DvdBCADescriptor,
+ DvdManufacturerDescriptor,
+ DvdMaxDescriptor
+} DVD_STRUCTURE_FORMAT, *PDVD_STRUCTURE_FORMAT;
+
+typedef struct DVD_READ_STRUCTURE {
+ LARGE_INTEGER BlockByteOffset;
+ DVD_STRUCTURE_FORMAT Format;
+ DVD_SESSION_ID SessionId;
+ UCHAR LayerNumber;
+} DVD_READ_STRUCTURE, *PDVD_READ_STRUCTURE;
+
+typedef struct DVD_COPYRIGHT_DESCRIPTOR {
+ UCHAR CopyrightProtectionType;
+ UCHAR RegionManagementInformation;
+ USHORT Reserved;
+} DVD_COPYRIGHT_DESCRIPTOR, *PDVD_COPYRIGHT_DESCRIPTOR;
+
+typedef enum
+{
+ DvdChallengeKey = 0x01,
+ DvdBusKey1,
+ DvdBusKey2,
+ DvdTitleKey,
+ DvdAsf,
+ DvdSetRpcKey = 0x6,
+ DvdGetRpcKey = 0x8,
+ DvdDiskKey = 0x80,
+ DvdInvalidateAGID = 0x3f
+} DVD_KEY_TYPE;
+
+typedef struct DVD_COPY_PROTECT_KEY
+{
+ ULONG KeyLength;
+ DVD_SESSION_ID SessionId;
+ DVD_KEY_TYPE KeyType;
+ ULONG KeyFlags;
+ union
+ {
+ struct
+ {
+ ULONG FileHandle;
+ ULONG Reserved; // used for NT alignment
+ };
+ LARGE_INTEGER TitleOffset;
+ } Parameters;
+ UCHAR KeyData[0];
+} DVD_COPY_PROTECT_KEY, *PDVD_COPY_PROTECT_KEY;
+
+typedef struct DVD_ASF
+{
+ UCHAR Reserved0[3];
+ UCHAR SuccessFlag:1;
+ UCHAR Reserved1:7;
+} DVD_ASF, * PDVD_ASF;
+
+typedef struct DVD_RPC_KEY
+{
+ UCHAR UserResetsAvailable:3;
+ UCHAR ManufacturerResetsAvailable:3;
+ UCHAR TypeCode:2;
+ UCHAR RegionMask;
+ UCHAR RpcScheme;
+ UCHAR Reserved2[1];
+} DVD_RPC_KEY, * PDVD_RPC_KEY;
+
+typedef struct SCSI_PASS_THROUGH_DIRECT
+{
+ USHORT Length;
+ UCHAR ScsiStatus;
+ UCHAR PathId;
+ UCHAR TargetId;
+ UCHAR Lun;
+ UCHAR CdbLength;
+ UCHAR SenseInfoLength;
+ UCHAR DataIn;
+ ULONG DataTransferLength;
+ ULONG TimeOutValue;
+ PVOID DataBuffer;
+ ULONG SenseInfoOffset;
+ UCHAR Cdb[16];
+} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;
+
+/*****************************************************************************
+ * win32 aspi specific
+ *****************************************************************************/
+
+typedef DWORD (CALLBACK *GETASPI32SUPPORTINFO)(VOID);
+typedef DWORD (CALLBACK *SENDASPI32COMMAND)(LPVOID);
+
+#if defined(_XBOX) || defined(WIN32)
+#define WIN2K 1
+#else
+#define WIN2K ( GetVersion() < 0x80000000 )
+#endif // _XBOX
+#define ASPI_HAID 0
+#define ASPI_TARGET 0
+#define DTYPE_CDROM 0x05
+
+#define SENSE_LEN 0x0E
+#define SC_GET_DEV_TYPE 0x01
+#define SC_EXEC_SCSI_CMD 0x02
+#define SC_GET_DISK_INFO 0x06
+#define SS_COMP 0x01
+#define SS_PENDING 0x00
+#define SS_NO_ADAPTERS 0xE8
+#define SRB_DIR_IN 0x08
+#define SRB_DIR_OUT 0x10
+#define SRB_EVENT_NOTIFY 0x40
+
+struct w32_aspidev
+{
+ long hASPI;
+ short i_sid;
+ int i_blocks;
+ SENDASPI32COMMAND lpSendCommand;
+};
+
+#pragma pack(1)
+
+struct SRB_GetDiskInfo
+{
+ unsigned char SRB_Cmd;
+ unsigned char SRB_Status;
+ unsigned char SRB_HaId;
+ unsigned char SRB_Flags;
+ unsigned long SRB_Hdr_Rsvd;
+ unsigned char SRB_Target;
+ unsigned char SRB_Lun;
+ unsigned char SRB_DriveFlags;
+ unsigned char SRB_Int13HDriveInfo;
+ unsigned char SRB_Heads;
+ unsigned char SRB_Sectors;
+ unsigned char SRB_Rsvd1[22];
+};
+
+struct SRB_GDEVBlock
+{
+ unsigned char SRB_Cmd;
+ unsigned char SRB_Status;
+ unsigned char SRB_HaId;
+ unsigned char SRB_Flags;
+ unsigned long SRB_Hdr_Rsvd;
+ unsigned char SRB_Target;
+ unsigned char SRB_Lun;
+ unsigned char SRB_DeviceType;
+ unsigned char SRB_Rsvd1;
+};
+
+struct SRB_ExecSCSICmd
+{
+ unsigned char SRB_Cmd;
+ unsigned char SRB_Status;
+ unsigned char SRB_HaId;
+ unsigned char SRB_Flags;
+ unsigned long SRB_Hdr_Rsvd;
+ unsigned char SRB_Target;
+ unsigned char SRB_Lun;
+ unsigned short SRB_Rsvd1;
+ unsigned long SRB_BufLen;
+ unsigned char *SRB_BufPointer;
+ unsigned char SRB_SenseLen;
+ unsigned char SRB_CDBLen;
+ unsigned char SRB_HaStat;
+ unsigned char SRB_TargStat;
+ unsigned long *SRB_PostProc;
+ unsigned char SRB_Rsvd2[20];
+ unsigned char CDBByte[16];
+ unsigned char SenseArea[SENSE_LEN+2];
+};
+
+#pragma pack()
+
+#endif
+
+/*****************************************************************************
+ * OS2 ioctl specific
+ *****************************************************************************/
+#if defined( SYS_OS2 )
+
+#define CDROMDISK_EXECMD 0x7A
+
+#define EX_DIRECTION_IN 0x01
+#define EX_PLAYING_CHK 0x02
+
+#pragma pack(1)
+
+struct OS2_ExecSCSICmd
+{
+ unsigned long id_code; // 'CD01'
+ unsigned short data_length; // length of the Data Packet
+ unsigned short cmd_length; // length of the Command Buffer
+ unsigned short flags; // flags
+ unsigned char command[16]; // Command Buffer for SCSI command
+
+} OS2_ExecSCSICmd;
+
+#pragma pack()
+
+#endif
diff --git a/lib/libdvd/libdvdcss/src/libdvdcss.c b/lib/libdvd/libdvdcss/src/libdvdcss.c
new file mode 100644
index 0000000000..0f6524176d
--- /dev/null
+++ b/lib/libdvd/libdvdcss/src/libdvdcss.c
@@ -0,0 +1,835 @@
+/* libdvdcss.c: DVD reading library.
+ *
+ * Authors: Stéphane Borel <stef@via.ecp.fr>
+ * Sam Hocevar <sam@zoy.org>
+ * HÃ¥kan Hjort <d95hjort@dtek.chalmers.se>
+ *
+ * Copyright (C) 1998-2008 VideoLAN
+ * $Id$
+ *
+ * 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.
+ */
+
+/**
+ * \mainpage libdvdcss developer documentation
+ *
+ * \section intro Introduction
+ *
+ * \e libdvdcss is a simple library designed for accessing DVDs like a block
+ * device without having to bother about the decryption. The important features
+ * are:
+ * \li portability: currently supported platforms are GNU/Linux, FreeBSD,
+ * NetBSD, OpenBSD, BSD/OS, BeOS, Windows 95/98, Windows NT/2000, MacOS X,
+ * Solaris, HP-UX and OS/2.
+ * \li adaptability: unlike most similar projects, libdvdcss doesn't require
+ * the region of your drive to be set and will try its best to read from
+ * the disc even in the case of a region mismatch.
+ * \li simplicity: a DVD player can be built around the \e libdvdcss API using
+ * no more than 4 or 5 library calls.
+ *
+ * \e libdvdcss is free software, released under the General Public License.
+ * This ensures that \e libdvdcss remains free and used only with free
+ * software.
+ *
+ * \section api The libdvdcss API
+ *
+ * The complete \e libdvdcss programming interface is documented in the
+ * dvdcss.h file.
+ *
+ * \section env Environment variables
+ *
+ * Some environment variables can be used to change the behaviour of
+ * \e libdvdcss without having to modify the program which uses it. These
+ * variables are:
+ *
+ * \li \b DVDCSS_VERBOSE: sets the verbosity level.
+ * - \c 0 outputs no messages at all.
+ * - \c 1 outputs error messages to stderr.
+ * - \c 2 outputs error messages and debug messages to stderr.
+ *
+ * \li \b DVDCSS_METHOD: sets the authentication and decryption method
+ * that \e libdvdcss will use to read scrambled discs. Can be one
+ * of \c title, \c key or \c disc.
+ * - \c key is the default method. \e libdvdcss will use a set of
+ * calculated player keys to try and get the disc key. This can fail
+ * if the drive does not recognize any of the player keys.
+ * - \c disc is a fallback method when \c key has failed. Instead of
+ * using player keys, \e libdvdcss will crack the disc key using
+ * a brute force algorithm. This process is CPU intensive and requires
+ * 64 MB of memory to store temporary data.
+ * - \c title is the fallback when all other methods have failed. It does
+ * not rely on a key exchange with the DVD drive, but rather uses a
+ * crypto attack to guess the title key. On rare cases this may fail
+ * because there is not enough encrypted data on the disc to perform
+ * a statistical attack, but in the other hand it is the only way to
+ * decrypt a DVD stored on a hard disc, or a DVD with the wrong region
+ * on an RPC2 drive.
+ *
+ * \li \b DVDCSS_RAW_DEVICE: specify the raw device to use. Exact usage will
+ * depend on your operating system, the Linux utility to set up raw devices
+ * is \c raw(8) for instance. Please note that on most operating systems,
+ * using a raw device requires highly aligned buffers: Linux requires a
+ * 2048 bytes alignment (which is the size of a DVD sector).
+ *
+ * \li \b DVDCSS_CACHE: specify a directory in which to store title key
+ * values. This will speed up descrambling of DVDs which are in the
+ * cache. The DVDCSS_CACHE directory is created if it does not exist,
+ * and a subdirectory is created named after the DVD's title or
+ * manufacturing date. If DVDCSS_CACHE is not set or is empty, \e libdvdcss
+ * will use the default value which is "${HOME}/.dvdcss/" under Unix and
+ * "C:\Documents and Settings\$USER\Application Data\dvdcss\" under Win32.
+ * The special value "off" disables caching.
+ */
+
+/*
+ * Preamble
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+#include <fcntl.h>
+#include <errno.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#ifdef HAVE_DIRECT_H
+# include <direct.h>
+#endif
+
+#include "dvdcss/dvdcss.h"
+
+#include "common.h"
+#include "css.h"
+#include "libdvdcss.h"
+#include "ioctl.h"
+#include "device.h"
+
+/**
+ * \brief Symbol for version checks.
+ *
+ * The name of this symbol contains the library major number, which makes it
+ * easy to check which \e libdvdcss development headers are installed on the
+ * system with tools such as autoconf.
+ *
+ * The variable itself contains the exact version number of the library,
+ * which can be useful for specific feature needs.
+ */
+char * dvdcss_interface_2 = VERSION;
+
+/**
+ * \brief Open a DVD device or directory and return a dvdcss instance.
+ *
+ * \param psz_target a string containing the target name, for instance
+ * "/dev/hdc" or "E:".
+ * \return a handle to a dvdcss instance or NULL on error.
+ *
+ * Initialize the \e libdvdcss library and open the requested DVD device or
+ * directory. \e libdvdcss checks whether ioctls can be performed on the disc,
+ * and when possible, the disc key is retrieved.
+ *
+ * dvdcss_open() returns a handle to be used for all subsequent \e libdvdcss
+ * calls. If an error occurred, NULL is returned.
+ */
+LIBDVDCSS_EXPORT dvdcss_t dvdcss_open ( char *psz_target )
+{
+ char psz_buffer[PATH_MAX];
+ int i_ret;
+
+ char *psz_method = getenv( "DVDCSS_METHOD" );
+ char *psz_verbose = getenv( "DVDCSS_VERBOSE" );
+ char *psz_cache = getenv( "DVDCSS_CACHE" );
+#ifndef WIN32
+ char *psz_raw_device = getenv( "DVDCSS_RAW_DEVICE" );
+#endif
+
+ dvdcss_t dvdcss;
+
+ /*
+ * Allocate the library structure
+ */
+ dvdcss = malloc( sizeof( struct dvdcss_s ) );
+ if( dvdcss == NULL )
+ {
+ return NULL;
+ }
+
+ /*
+ * Initialize structure with default values
+ */
+#ifndef WIN32
+ dvdcss->i_raw_fd = -1;
+#endif
+ dvdcss->p_titles = NULL;
+ dvdcss->psz_device = (char *)strdup( psz_target );
+ dvdcss->psz_error = "no error";
+ dvdcss->i_method = DVDCSS_METHOD_KEY;
+ dvdcss->psz_cachefile[0] = '\0';
+ dvdcss->b_debug = 0;
+ dvdcss->b_errors = 0;
+
+#ifdef WITH_CACHE
+ dvdcss->buffer_size = 0;
+#endif
+
+ /*
+ * Find verbosity from DVDCSS_VERBOSE environment variable
+ */
+ if( psz_verbose != NULL )
+ {
+ int i = atoi( psz_verbose );
+
+ if( i >= 2 ) dvdcss->b_debug = i;
+ if( i >= 1 ) dvdcss->b_errors = 1;
+ }
+
+ /*
+ * Find method from DVDCSS_METHOD environment variable
+ */
+ if( psz_method != NULL )
+ {
+ if( !strncmp( psz_method, "key", 4 ) )
+ {
+ dvdcss->i_method = DVDCSS_METHOD_KEY;
+ }
+ else if( !strncmp( psz_method, "disc", 5 ) )
+ {
+ dvdcss->i_method = DVDCSS_METHOD_DISC;
+ }
+ else if( !strncmp( psz_method, "title", 5 ) )
+ {
+ dvdcss->i_method = DVDCSS_METHOD_TITLE;
+ }
+ else
+ {
+ print_error( dvdcss, "unknown decrypt method, please choose "
+ "from 'title', 'key' or 'disc'" );
+ free( dvdcss->psz_device );
+ free( dvdcss );
+ return NULL;
+ }
+ }
+
+ /*
+ * If DVDCSS_CACHE was not set, try to guess a default value
+ */
+ if( psz_cache == NULL || psz_cache[0] == '\0' )
+ {
+#ifdef HAVE_DIRECT_H
+ typedef HRESULT( WINAPI *SHGETFOLDERPATH )
+ ( HWND, int, HANDLE, DWORD, LPTSTR );
+
+# define CSIDL_FLAG_CREATE 0x8000
+# define CSIDL_APPDATA 0x1A
+# define SHGFP_TYPE_CURRENT 0
+
+ char psz_home[MAX_PATH];
+ HINSTANCE p_dll;
+ SHGETFOLDERPATH p_getpath;
+
+ *psz_home = '\0';
+
+ /* Load the shfolder dll to retrieve SHGetFolderPath */
+ p_dll = LoadLibrary( "shfolder.dll" );
+ if( p_dll )
+ {
+ p_getpath = (void*)GetProcAddress( p_dll, "SHGetFolderPathA" );
+ if( p_getpath )
+ {
+ /* Get the "Application Data" folder for the current user */
+ if( p_getpath( NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE,
+ NULL, SHGFP_TYPE_CURRENT, psz_home ) == S_OK )
+ {
+ FreeLibrary( p_dll );
+ }
+ else
+ {
+ *psz_home = '\0';
+ }
+ }
+ FreeLibrary( p_dll );
+ }
+
+ /* Cache our keys in
+ * C:\Documents and Settings\$USER\Application Data\dvdcss\ */
+ if( *psz_home )
+ {
+ snprintf( psz_buffer, PATH_MAX, "%s/dvdcss", psz_home );
+ psz_buffer[PATH_MAX-1] = '\0';
+ psz_cache = psz_buffer;
+ }
+#else
+ char *psz_home = NULL;
+# ifdef HAVE_PWD_H
+ struct passwd *p_pwd;
+
+ /* Try looking in password file for home dir. */
+ p_pwd = getpwuid(getuid());
+ if( p_pwd )
+ {
+ psz_home = p_pwd->pw_dir;
+ }
+# endif
+
+ if( psz_home == NULL )
+ {
+ psz_home = getenv( "HOME" );
+ }
+ if( psz_home == NULL )
+ {
+ psz_home = getenv( "USERPROFILE" );
+ }
+
+ /* Cache our keys in ${HOME}/.dvdcss/ */
+ if( psz_home )
+ {
+ snprintf( psz_buffer, PATH_MAX, "%s/.dvdcss", psz_home );
+ psz_buffer[PATH_MAX-1] = '\0';
+ psz_cache = psz_buffer;
+ }
+#endif
+ }
+
+ /*
+ * Find cache dir from the DVDCSS_CACHE environment variable
+ */
+ if( psz_cache != NULL )
+ {
+ if( psz_cache[0] == '\0' || !strcmp( psz_cache, "off" ) )
+ {
+ psz_cache = NULL;
+ }
+ /* Check that we can add the ID directory and the block filename */
+ else if( strlen( psz_cache ) + 1 + 32 + 1 + (KEY_SIZE * 2) + 10 + 1
+ > PATH_MAX )
+ {
+ print_error( dvdcss, "cache directory name is too long" );
+ psz_cache = NULL;
+ }
+ }
+
+ /*
+ * Open device
+ */
+ _dvdcss_check( dvdcss );
+ i_ret = _dvdcss_open( dvdcss );
+ if( i_ret < 0 )
+ {
+ free( dvdcss->psz_device );
+ free( dvdcss );
+ return NULL;
+ }
+
+ dvdcss->b_scrambled = 1; /* Assume the worst */
+ dvdcss->b_ioctls = _dvdcss_use_ioctls( dvdcss );
+
+ if( dvdcss->b_ioctls )
+ {
+ i_ret = _dvdcss_test( dvdcss );
+ if( i_ret < 0 )
+ {
+ /* Disable the CSS ioctls and hope that it works? */
+ print_debug( dvdcss,
+ "could not check whether the disc was scrambled" );
+ dvdcss->b_ioctls = 0;
+ }
+ else
+ {
+ print_debug( dvdcss, i_ret ? "disc is scrambled"
+ : "disc is unscrambled" );
+ dvdcss->b_scrambled = i_ret;
+ }
+ }
+ /* if wo don't have b_ioctls, we don't have a disk key, make sure area is nulled */
+ memset( dvdcss->css.p_disc_key, 0, KEY_SIZE );
+
+ /* If disc is CSS protected and the ioctls work, authenticate the drive */
+ if( dvdcss->b_scrambled && dvdcss->b_ioctls )
+ {
+ i_ret = _dvdcss_disckey( dvdcss );
+
+ if( i_ret < 0 )
+ {
+ print_debug( dvdcss, "could not get disc key" );
+ }
+ }
+ else
+ {
+ memset( dvdcss->css.p_disc_key, 0, KEY_SIZE );
+ }
+
+ /* If the cache is enabled, write the cache directory tag */
+ if( psz_cache )
+ {
+ char *psz_tag = "Signature: 8a477f597d28d172789f06886806bc55\r\n"
+ "# This file is a cache directory tag created by libdvdcss.\r\n"
+ "# For information about cache directory tags, see:\r\n"
+ "# http://www.brynosaurus.com/cachedir/\r\n";
+ char psz_tagfile[PATH_MAX + 1 + 12 + 1];
+ int i_fd;
+
+ sprintf( psz_tagfile, "%s/CACHEDIR.TAG", psz_cache );
+ i_fd = open( psz_tagfile, O_RDWR|O_CREAT, 0644 );
+ if( i_fd >= 0 )
+ {
+ write( i_fd, psz_tag, strlen(psz_tag) );
+ close( i_fd );
+ }
+ }
+
+ /* If the cache is enabled, extract a unique disc ID */
+ if( psz_cache )
+ {
+ uint8_t p_sector[DVDCSS_BLOCK_SIZE];
+ char psz_debug[PATH_MAX + 30];
+ char psz_key[1 + KEY_SIZE * 2 + 1];
+ char *psz_title;
+ uint8_t *psz_serial;
+ int i;
+
+ /* We read sector 0. If it starts with 0x000001ba (BE), we are
+ * reading a VOB file, and we should not cache anything. */
+
+ i_ret = dvdcss->pf_seek( dvdcss, 0 );
+ if( i_ret != 0 )
+ {
+ goto nocache;
+ }
+
+ i_ret = dvdcss->pf_read( dvdcss, p_sector, 1 );
+ if( i_ret != 1 )
+ {
+ goto nocache;
+ }
+
+ if( p_sector[0] == 0x00 && p_sector[1] == 0x00
+ && p_sector[2] == 0x01 && p_sector[3] == 0xba )
+ {
+ goto nocache;
+ }
+
+ /* The data we are looking for is at sector 16 (32768 bytes):
+ * - offset 40: disc title (32 uppercase chars)
+ * - offset 813: manufacturing date + serial no (16 digits) */
+
+ i_ret = dvdcss->pf_seek( dvdcss, 16 );
+ if( i_ret != 16 )
+ {
+ goto nocache;
+ }
+
+ i_ret = dvdcss->pf_read( dvdcss, p_sector, 1 );
+ if( i_ret != 1 )
+ {
+ goto nocache;
+ }
+
+ /* Get the disc title */
+ psz_title = (char *)p_sector + 40;
+ psz_title[32] = '\0';
+
+ for( i = 0 ; i < 32 ; i++ )
+ {
+ if( psz_title[i] <= ' ' )
+ {
+ psz_title[i] = '\0';
+ break;
+ }
+ else if( psz_title[i] == '/' || psz_title[i] == '\\' )
+ {
+ psz_title[i] = '-';
+ }
+ }
+
+ /* Get the date + serial */
+ psz_serial = p_sector + 813;
+ psz_serial[16] = '\0';
+
+ /* Check that all characters are digits, otherwise convert. */
+ for( i = 0 ; i < 16 ; i++ )
+ {
+ if( psz_serial[i] < '0' || psz_serial[i] > '9' )
+ {
+ char psz_tmp[16 + 1];
+ sprintf( psz_tmp,
+ "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
+ psz_serial[0], psz_serial[1], psz_serial[2],
+ psz_serial[3], psz_serial[4], psz_serial[5],
+ psz_serial[6], psz_serial[7] );
+ memcpy( psz_serial, psz_tmp, 16 );
+ break;
+ }
+ }
+
+ /* Get disk key, since some discs have got same title, manufacturing
+ * date and serial number, but different keys */
+ if( dvdcss->b_scrambled )
+ {
+ psz_key[0] = '-';
+ for( i = 0; i < KEY_SIZE; i++ )
+ {
+ sprintf( &psz_key[1+i*2], "%.2x", dvdcss->css.p_disc_key[i] );
+ }
+ psz_key[1 + KEY_SIZE * 2] = '\0';
+ }
+ else
+ {
+ psz_key[0] = 0;
+ }
+
+ /* We have a disc name or ID, we can create the cache dir */
+ i = sprintf( dvdcss->psz_cachefile, "%s", psz_cache );
+#if !defined( WIN32 ) || defined( SYS_CYGWIN )
+ i_ret = mkdir( dvdcss->psz_cachefile, 0755 );
+#else
+ i_ret = mkdir( dvdcss->psz_cachefile );
+#endif
+ if( i_ret < 0 && errno != EEXIST )
+ {
+ print_error( dvdcss, "failed creating cache directory" );
+ dvdcss->psz_cachefile[0] = '\0';
+ goto nocache;
+ }
+
+#ifdef _XBOX
+ //due to xbox file system having a limited length on folders/files,
+ //make separate folder for disk name first
+ if(psz_title[0] == '\0')
+ strcat(psz_title, "NONAME");
+
+ i += sprintf( dvdcss->psz_cachefile + i, "/%s", psz_title);
+
+ i_ret = mkdir( dvdcss->psz_cachefile );
+ if( i_ret < 0 && errno != EEXIST )
+ {
+ print_error( dvdcss, "failed creating cache titledirectory" );
+ dvdcss->psz_cachefile[0] = '\0';
+ goto nocache;
+ }
+ i += sprintf( dvdcss->psz_cachefile + i, "/%s%s", psz_serial, psz_key );
+#else
+ i += sprintf( dvdcss->psz_cachefile + i, "/%s-%s%s", psz_title,
+ psz_serial, psz_key );
+#endif
+#if !defined( WIN32 ) || defined( SYS_CYGWIN )
+ i_ret = mkdir( dvdcss->psz_cachefile, 0755 );
+#else
+ i_ret = mkdir( dvdcss->psz_cachefile );
+#endif
+ if( i_ret < 0 && errno != EEXIST )
+ {
+ print_error( dvdcss, "failed creating cache subdirectory" );
+ dvdcss->psz_cachefile[0] = '\0';
+ goto nocache;
+ }
+ i += sprintf( dvdcss->psz_cachefile + i, "/");
+
+ /* Pointer to the filename we will use. */
+ dvdcss->psz_block = dvdcss->psz_cachefile + i;
+
+ sprintf( psz_debug, "using CSS key cache dir: %s",
+ dvdcss->psz_cachefile );
+ print_debug( dvdcss, psz_debug );
+ }
+ nocache:
+
+#ifndef WIN32
+ if( psz_raw_device != NULL )
+ {
+ _dvdcss_raw_open( dvdcss, psz_raw_device );
+ }
+#endif
+
+ /* Seek at the beginning, just for safety. */
+ dvdcss->pf_seek( dvdcss, 0 );
+
+ return dvdcss;
+}
+
+/**
+ * \brief Return a string containing the latest error that occurred in the
+ * given \e libdvdcss instance.
+ *
+ * \param dvdcss a \e libdvdcss instance.
+ * \return a null-terminated string containing the latest error message.
+ *
+ * This function returns a constant string containing the latest error that
+ * occurred in \e libdvdcss. It can be used to format error messages at your
+ * convenience in your application.
+ */
+LIBDVDCSS_EXPORT char * dvdcss_error ( dvdcss_t dvdcss )
+{
+ return dvdcss->psz_error;
+}
+
+/**
+ * \brief Seek in the disc and change the current key if requested.
+ *
+ * \param dvdcss a \e libdvdcss instance.
+ * \param i_blocks an absolute block offset to seek to.
+ * \param i_flags #DVDCSS_NOFLAGS, optionally ored with one of #DVDCSS_SEEK_KEY
+ * or #DVDCSS_SEEK_MPEG.
+ * \return the new position in blocks, or a negative value in case an error
+ * happened.
+ *
+ * This function seeks to the requested position, in logical blocks.
+ *
+ * You typically set \p i_flags to #DVDCSS_NOFLAGS when seeking in a .IFO.
+ *
+ * If #DVDCSS_SEEK_MPEG is specified in \p i_flags and if \e libdvdcss finds it
+ * reasonable to do so (ie, if the dvdcss method is not "title"), the current
+ * title key will be checked and a new one will be calculated if necessary.
+ * This flag is typically used when reading data from a VOB.
+ *
+ * If #DVDCSS_SEEK_KEY is specified, the title key will be always checked,
+ * even with the "title" method. This is equivalent to using the now
+ * deprecated dvdcss_title() call. This flag is typically used when seeking
+ * in a new title.
+ */
+LIBDVDCSS_EXPORT int dvdcss_seek ( dvdcss_t dvdcss, int i_blocks, int i_flags )
+{
+ /* title cracking method is too slow to be used at each seek */
+ if( ( ( i_flags & DVDCSS_SEEK_MPEG )
+ && ( dvdcss->i_method != DVDCSS_METHOD_TITLE ) )
+ || ( i_flags & DVDCSS_SEEK_KEY ) )
+ {
+ /* check the title key */
+ if( _dvdcss_title( dvdcss, i_blocks ) )
+ {
+ return -1;
+ }
+ }
+
+ return dvdcss->pf_seek( dvdcss, i_blocks );
+}
+
+/**
+ * \brief Read from the disc and decrypt data if requested.
+ *
+ * \param dvdcss a \e libdvdcss instance.
+ * \param p_buffer a buffer that will contain the data read from the disc.
+ * \param i_blocks the amount of blocks to read.
+ * \param i_flags #DVDCSS_NOFLAGS, optionally ored with #DVDCSS_READ_DECRYPT.
+ * \return the amount of blocks read, or a negative value in case an
+ * error happened.
+ *
+ * This function reads \p i_blocks logical blocks from the DVD.
+ *
+ * You typically set \p i_flags to #DVDCSS_NOFLAGS when reading data from a
+ * .IFO file on the DVD.
+ *
+ * If #DVDCSS_READ_DECRYPT is specified in \p i_flags, dvdcss_read() will
+ * automatically decrypt scrambled sectors. This flag is typically used when
+ * reading data from a .VOB file on the DVD. It has no effect on unscrambled
+ * discs or unscrambled sectors, and can be safely used on those.
+ *
+ * \warning dvdcss_read() expects to be able to write \p i_blocks *
+ * #DVDCSS_BLOCK_SIZE bytes in \p p_buffer.
+ */
+LIBDVDCSS_EXPORT int dvdcss_read ( dvdcss_t dvdcss, void *p_buffer,
+ int i_blocks,
+ int i_flags )
+{
+ int i_ret, i_index;
+
+ i_ret = dvdcss->pf_read( dvdcss, p_buffer, i_blocks );
+
+ if( i_ret <= 0
+ || !dvdcss->b_scrambled
+ || !(i_flags & DVDCSS_READ_DECRYPT) )
+ {
+ return i_ret;
+ }
+
+ if( ! memcmp( dvdcss->css.p_title_key, "\0\0\0\0\0", 5 ) )
+ {
+ /* For what we believe is an unencrypted title,
+ * check that there are no encrypted blocks */
+ for( i_index = i_ret; i_index; i_index-- )
+ {
+ if( ((uint8_t*)p_buffer)[0x14] & 0x30 )
+ {
+ print_error( dvdcss, "no key but found encrypted block" );
+ /* Only return the initial range of unscrambled blocks? */
+ /* or fail completely? return 0; */
+ break;
+ }
+ p_buffer = (void *) ((uint8_t *)p_buffer + DVDCSS_BLOCK_SIZE);
+ }
+ }
+ else
+ {
+ /* Decrypt the blocks we managed to read */
+ for( i_index = i_ret; i_index; i_index-- )
+ {
+ _dvdcss_unscramble( dvdcss->css.p_title_key, p_buffer );
+ ((uint8_t*)p_buffer)[0x14] &= 0x8f;
+ p_buffer = (void *) ((uint8_t *)p_buffer + DVDCSS_BLOCK_SIZE);
+ }
+ }
+
+ return i_ret;
+}
+
+/**
+ * \brief Read from the disc into multiple buffers and decrypt data if
+ * requested.
+ *
+ * \param dvdcss a \e libdvdcss instance.
+ * \param p_iovec a pointer to an array of iovec structures that will contain
+ * the data read from the disc.
+ * \param i_blocks the amount of blocks to read.
+ * \param i_flags #DVDCSS_NOFLAGS, optionally ored with #DVDCSS_READ_DECRYPT.
+ * \return the amount of blocks read, or a negative value in case an
+ * error happened.
+ *
+ * This function reads \p i_blocks logical blocks from the DVD and writes them
+ * to an array of iovec structures.
+ *
+ * You typically set \p i_flags to #DVDCSS_NOFLAGS when reading data from a
+ * .IFO file on the DVD.
+ *
+ * If #DVDCSS_READ_DECRYPT is specified in \p i_flags, dvdcss_readv() will
+ * automatically decrypt scrambled sectors. This flag is typically used when
+ * reading data from a .VOB file on the DVD. It has no effect on unscrambled
+ * discs or unscrambled sectors, and can be safely used on those.
+ *
+ * \warning dvdcss_readv() expects to be able to write \p i_blocks *
+ * #DVDCSS_BLOCK_SIZE bytes in the buffers pointed by \p p_iovec.
+ * Moreover, all iov_len members of the iovec structures should be
+ * multiples of #DVDCSS_BLOCK_SIZE.
+ */
+LIBDVDCSS_EXPORT int dvdcss_readv ( dvdcss_t dvdcss, void *p_iovec,
+ int i_blocks,
+ int i_flags )
+{
+ struct iovec *_p_iovec = (struct iovec *)p_iovec;
+ int i_ret, i_index;
+ void *iov_base;
+ size_t iov_len;
+
+ i_ret = dvdcss->pf_readv( dvdcss, _p_iovec, i_blocks );
+
+ if( i_ret <= 0
+ || !dvdcss->b_scrambled
+ || !(i_flags & DVDCSS_READ_DECRYPT) )
+ {
+ return i_ret;
+ }
+
+ /* Initialize loop for decryption */
+ iov_base = _p_iovec->iov_base;
+ iov_len = _p_iovec->iov_len;
+
+ /* Decrypt the blocks we managed to read */
+ for( i_index = i_ret; i_index; i_index-- )
+ {
+ /* Check that iov_len is a multiple of 2048 */
+ if( iov_len & 0x7ff )
+ {
+ return -1;
+ }
+
+ while( iov_len == 0 )
+ {
+ _p_iovec++;
+ iov_base = _p_iovec->iov_base;
+ iov_len = _p_iovec->iov_len;
+ }
+
+ _dvdcss_unscramble( dvdcss->css.p_title_key, iov_base );
+ ((uint8_t*)iov_base)[0x14] &= 0x8f;
+
+ iov_base = (void *) ((uint8_t*)iov_base + DVDCSS_BLOCK_SIZE);
+ iov_len -= DVDCSS_BLOCK_SIZE;
+ }
+
+ return i_ret;
+}
+
+/**
+ * \brief Close the DVD and clean up the library.
+ *
+ * \param dvdcss a \e libdvdcss instance.
+ * \return zero in case of success, a negative value otherwise.
+ *
+ * This function closes the DVD device and frees all the memory allocated
+ * by \e libdvdcss. On return, the #dvdcss_t is invalidated and may not be
+ * used again.
+ */
+LIBDVDCSS_EXPORT int dvdcss_close ( dvdcss_t dvdcss )
+{
+ dvd_title_t *p_title;
+ int i_ret;
+
+ /* Free our list of keys */
+ p_title = dvdcss->p_titles;
+ while( p_title )
+ {
+ dvd_title_t *p_tmptitle = p_title->p_next;
+ free( p_title );
+ p_title = p_tmptitle;
+ }
+
+ i_ret = _dvdcss_close( dvdcss );
+
+ if( i_ret < 0 )
+ {
+ return i_ret;
+ }
+
+ free( dvdcss->psz_device );
+ free( dvdcss );
+
+ return 0;
+}
+
+/*
+ * Deprecated. See dvdcss_seek().
+ */
+#undef dvdcss_title
+LIBDVDCSS_EXPORT int dvdcss_title ( dvdcss_t dvdcss, int i_block )
+{
+ return _dvdcss_title( dvdcss, i_block );
+}
+
+/**
+ * \brief Return 1 if the DVD is scrambled, 0 otherwise.
+ *
+ * \param dvdcss a \e libdvdcss instance.
+ * \return 1 if the DVD is scrambled, 0 otherwise.
+ *
+ * This function returns whether the DVD is scrambled.
+ */
+LIBDVDCSS_EXPORT int dvdcss_is_scrambled ( dvdcss_t dvdcss )
+{
+ return dvdcss->b_scrambled;
+}
+
diff --git a/lib/libdvd/libdvdcss/src/libdvdcss.h b/lib/libdvd/libdvdcss/src/libdvdcss.h
new file mode 100644
index 0000000000..80f78c3062
--- /dev/null
+++ b/lib/libdvd/libdvdcss/src/libdvdcss.h
@@ -0,0 +1,104 @@
+/*****************************************************************************
+ * libdvdcss.h: private DVD reading library data
+ *****************************************************************************
+ * Copyright (C) 1998-2001 VideoLAN
+ * $Id$
+ *
+ * Authors: Stéphane Borel <stef@via.ecp.fr>
+ * Sam 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.
+ *****************************************************************************/
+
+struct iovec;
+
+/*****************************************************************************
+ * The libdvdcss structure
+ *****************************************************************************/
+struct dvdcss_s
+{
+ /* File descriptor */
+ char * psz_device;
+ int i_fd;
+ int i_read_fd;
+ int i_pos;
+
+ /* File handling */
+ int ( * pf_seek ) ( dvdcss_t, int );
+ int ( * pf_read ) ( dvdcss_t, void *, int );
+ int ( * pf_readv ) ( dvdcss_t, struct iovec *, int );
+
+ /* Decryption stuff */
+ int i_method;
+ css_t css;
+ int b_ioctls;
+ int b_scrambled;
+ dvd_title_t *p_titles;
+
+ /* Key cache directory and pointer to the filename */
+ char psz_cachefile[PATH_MAX];
+ char * psz_block;
+
+ /* Error management */
+ char * psz_error;
+ int b_errors;
+ int b_debug;
+
+#ifdef WIN32
+ int b_file;
+ char * p_readv_buffer;
+ int i_readv_buf_size;
+#endif
+
+#ifndef WIN32
+ int i_raw_fd;
+#endif
+};
+
+/*****************************************************************************
+ * libdvdcss method: used like init flags
+ *****************************************************************************/
+#define DVDCSS_METHOD_KEY 0
+#define DVDCSS_METHOD_DISC 1
+#define DVDCSS_METHOD_TITLE 2
+
+/*****************************************************************************
+ * Functions used across the library
+ *****************************************************************************/
+#define print_error(dvdcss,msg) _print_error(dvdcss,msg)
+#if defined( _MSC_VER )
+#include <stdarg.h>
+__forceinline void print_debug(dvdcss_t dvdcss, const char *msg,...)
+{
+ va_list args;
+
+ fprintf( stderr, "libdvdcss debug: " );
+ va_start( args, msg );
+ vfprintf( stderr, msg, args );
+ va_end( args );
+ fprintf( stderr, "\n" );
+}
+#else
+#define print_debug(dvdcss,msg,args...) \
+ if( dvdcss->b_debug ) \
+ { \
+ fprintf( stderr, "libdvdcss debug: " ); \
+ fprintf( stderr, msg, ##args ); \
+ fprintf( stderr, "\n" ); \
+ }
+#endif
+
+void _print_error ( dvdcss_t, char * );
+
diff --git a/lib/libdvd/libdvdcss/src/libdvdcss.pc.in b/lib/libdvd/libdvdcss/src/libdvdcss.pc.in
new file mode 100644
index 0000000000..9d2516787f
--- /dev/null
+++ b/lib/libdvd/libdvdcss/src/libdvdcss.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libdvdcss
+Description: DVD access and decryption library.
+Version: @VERSION@
+Libs: -L${libdir} -ldvdcss
+Cflags: -I{includedir} -I${includedir}/@PACKAGE@
diff --git a/lib/libdvd/libdvdcss/test/Makefile.am b/lib/libdvd/libdvdcss/test/Makefile.am
new file mode 100644
index 0000000000..f1c5a631e0
--- /dev/null
+++ b/lib/libdvd/libdvdcss/test/Makefile.am
@@ -0,0 +1,15 @@
+
+noinst_PROGRAMS = csstest #dvd_region
+
+csstest_SOURCES = csstest.c
+csstest_LDADD = $(top_builddir)/src/libdvdcss.la $(bsdi_libadd)
+csstest_CFLAGS = -I$(top_srcdir)/src
+
+#dvd_region_SOURCES = dvd_region.c
+#dvd_region_LDADD = $(top_builddir)/src/libdvdcss.la
+#dvd_region_CFLAGS = -I$(top_srcdir)/src
+
+if SYS_BSDI_LIBDVD
+bsdi_libadd = -ldvd
+endif
+
diff --git a/lib/libdvd/libdvdcss/test/csstest.c b/lib/libdvd/libdvdcss/test/csstest.c
new file mode 100644
index 0000000000..70f3b4d8f9
--- /dev/null
+++ b/lib/libdvd/libdvdcss/test/csstest.c
@@ -0,0 +1,130 @@
+/* csstest.c - test program for libdvdcss
+ *
+ * Sam Hocevar <sam@zoy.org> - June 2001
+ * Updated on Nov 13th 2001 for libdvdcss version 1.0.0
+ * Additional error checks on Aug 9th 2002
+ * Aligned data reads on Jan 28th 2003
+ *
+ * This piece of code is public domain */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <dvdcss/dvdcss.h>
+
+static int isscrambled( unsigned char * );
+static void dumpsector ( unsigned char * );
+
+int main( int i_argc, char *ppsz_argv[] )
+{
+ dvdcss_t dvdcss;
+ unsigned char p_data[ DVDCSS_BLOCK_SIZE * 2 ];
+ unsigned char *p_buffer;
+ unsigned int i_sector;
+ int i_ret;
+
+ /* Print version number */
+ printf( "cool, I found libdvdcss version %s\n", dvdcss_interface_2 );
+
+ /* Check for 2 arguments */
+ if( i_argc != 3 )
+ {
+ printf( "usage: %s <target> <sector>\n", ppsz_argv[0] );
+ printf( "examples:\n" );
+ printf( " %s /dev/hdc 1024\n", ppsz_argv[0] );
+ printf( " %s D: 1024\n", ppsz_argv[0] );
+ printf( " %s scrambledfile.vob 1024\n", ppsz_argv[0] );
+ return -1;
+ }
+
+ /* Save the requested sector */
+ i_sector = atoi( ppsz_argv[2] );
+
+ /* Initialize libdvdcss */
+ dvdcss = dvdcss_open( ppsz_argv[1] );
+ if( dvdcss == NULL )
+ {
+ printf( "argh ! couldn't open DVD (%s)\n", ppsz_argv[1] );
+ return -1;
+ }
+
+ /* Align our read buffer */
+ p_buffer = p_data + DVDCSS_BLOCK_SIZE
+ - ((long int)p_data & (DVDCSS_BLOCK_SIZE-1));
+
+ /* Set the file descriptor at sector i_sector and read one sector */
+ i_ret = dvdcss_seek( dvdcss, i_sector, DVDCSS_NOFLAGS );
+ if( i_ret != (int)i_sector )
+ {
+ printf( "seek failed (%s)\n", dvdcss_error( dvdcss ) );
+ dvdcss_close( dvdcss );
+ return i_ret;
+ }
+
+ i_ret = dvdcss_read( dvdcss, p_buffer, 1, DVDCSS_NOFLAGS );
+ if( i_ret != 1 )
+ {
+ printf( "read failed (%s)\n", dvdcss_error( dvdcss ) );
+ dvdcss_close( dvdcss );
+ return i_ret;
+ }
+
+ /* Print the sector */
+ printf( "requested sector: " );
+ dumpsector( p_buffer );
+
+ /* Check if sector was encrypted */
+ if( isscrambled( p_buffer ) )
+ {
+ /* Set the file descriptor position to the previous location */
+ /* ... and get the appropriate key for this sector */
+ i_ret = dvdcss_seek( dvdcss, i_sector, DVDCSS_SEEK_KEY );
+ if( i_ret != (int)i_sector )
+ {
+ printf( "seek failed (%s)\n", dvdcss_error( dvdcss ) );
+ dvdcss_close( dvdcss );
+ return i_ret;
+ }
+
+ /* Read sector again, and decrypt it on the fly */
+ i_ret = dvdcss_read( dvdcss, p_buffer, 1, DVDCSS_READ_DECRYPT );
+ if( i_ret != 1 )
+ {
+ printf( "read failed (%s)\n", dvdcss_error( dvdcss ) );
+ dvdcss_close( dvdcss );
+ return i_ret;
+ }
+
+ /* Print the decrypted sector */
+ printf( "unscrambled sector: " );
+ dumpsector( p_buffer );
+ }
+ else
+ {
+ printf( "sector is not scrambled\n" );
+ }
+
+ /* Close the device */
+ i_ret = dvdcss_close( dvdcss );
+
+ return i_ret;
+}
+
+/* Check if a sector is scrambled */
+static int isscrambled( unsigned char *p_buffer )
+{
+ return p_buffer[ 0x14 ] & 0x30;
+}
+
+/* Print parts of a 2048 bytes buffer */
+static void dumpsector( unsigned char *p_buffer )
+{
+ int i_amount = 4;
+ for( ; i_amount ; i_amount--, p_buffer++ ) printf( "%.2x", *p_buffer );
+ printf( "..." );
+ i_amount = 22;
+ p_buffer += 200;
+ for( ; i_amount ; i_amount--, p_buffer++ ) printf( "%.2x", *p_buffer );
+ printf( "...\n" );
+}
+
diff --git a/lib/libdvd/libdvdnav/.relignore b/lib/libdvd/libdvdnav/.relignore
new file mode 100644
index 0000000000..2f2f41fa9c
--- /dev/null
+++ b/lib/libdvd/libdvdnav/.relignore
@@ -0,0 +1,2 @@
+autom4te.cache
+config.status
diff --git a/lib/libdvd/libdvdnav/AUTHORS b/lib/libdvd/libdvdnav/AUTHORS
new file mode 100644
index 0000000000..cb528af0dd
--- /dev/null
+++ b/lib/libdvd/libdvdnav/AUTHORS
@@ -0,0 +1,6 @@
+Daniel Caujolle-Bert <segfault@club-internet.fr>
+Thomas Vander Stichele <thomas@apestaart.org>
+Rich Wareham <richwareham@users.sourceforge.net>
+Kees Cook <kees@outflux.net>
+Michael Roitzsch <mroi@users.sourceforge.net>
+Frantisek Dvorak <valtri@users.sourceforge.net>
diff --git a/lib/libdvd/libdvdnav/COPYING b/lib/libdvd/libdvdnav/COPYING
new file mode 100644
index 0000000000..d60c31a97a
--- /dev/null
+++ b/lib/libdvd/libdvdnav/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/lib/libdvd/libdvdnav/ChangeLog b/lib/libdvd/libdvdnav/ChangeLog
new file mode 100644
index 0000000000..46b43d0fa7
--- /dev/null
+++ b/lib/libdvd/libdvdnav/ChangeLog
@@ -0,0 +1,134 @@
+libdvdnav (4.1.3)
+ * an embarassing amount of fixes regarding potential memory and resource leaks
+ (patches contributed by Erik Hovland)
+ * added dvdread-config (dvdnav-config's younger brother)
+ * added pkg-config support
+ * split dvdread to a separate tree; now you need to check it out
+ and install it before building libdvdnav.
+ In order to configure libdvdnav We need the executable dvdread-config
+ somewhere in the PATH or explicitly specified to configure[2] with
+ --with-dvdread-config=~/bin/dvdread-config
+
+libdvdnav (4.1.2)
+ * multiple build system fixes
+ * added dvdnav_describe_title_chapters(title) to get title and chapters
+ duration
+
+libdvdnav (4.1.1)
+ * added dvdnav_audio_stream_channels() to return number of channels
+ * fixed dvdnav_time_search() in multi-angle dvds (but it still needs
+ improvements)
+ * added dvdnav_audio_stream_format() to identify the codec used
+ in audio streams
+ * starting DVD playback at specific title/part positions with
+ dvdnav_{title,part}_play() works again
+ * removed wrong SPU stream change event filter
+ (fixes unwanted subtitles in the trailer of "Girl, interrupted", RC2)
+ * fixed error "Expected NAV packet but none found." occuring sometimes
+ on resume from menu
+
+libdvdnav (0.1.10)
+ * filter the symbols that we export.
+ * fix LinkNextC assertion failure (fixes LotR-SEE bonus disc image gallery)
+ * detect zero stilltime still cells inside PGCs, not only at the end
+ (fixes "Red Dragon" RC2 scene selection)
+ * PGC stills seem to work, assertion removed
+ * fix rare race condition after Exit commands
+ * fix wrong JumpSS_VTSM execution in German RC2 "Anatomie"
+ (fix ported from Ogle)
+
+libdvdnav (0.1.9)
+ * libdvdnav does not depend on libdvdread any more. It has it's own version.
+ * fix some situations where an unlucky user could trigger assertions
+
+libdvdnav (0.1.8)
+ * more timing info in cell change event struct
+ * documentation review
+
+libdvdnav (0.1.7)
+ * fixed a bug in title jumping, where the title number would not be
+ converted from TTN to VTS_TTN properly
+ * some minor sanity checks added to prevent segfaults
+
+libdvdnav (0.1.6) unstable; urgency=low
+ * new event DVDNAV_WAIT to fix consistency problems in applications with fifos
+ where libdvdnav is always a bit ahead in the stream, the event forces
+ the application to wait for its fifos to get empty
+ * correct HIGHLIGHT reporting when a button is activated
+ * method to try-run VM operations, now used for safer chapter skipping and menu jumps
+ * fixed detection of current PTT to not assume a 1:1 mapping between PTTs and PGs
+ * releasing stills when jumping to menu fixes some state inconsistencies
+ * do not assume PGs to be physically layed out in sequence on the disc
+ * optional PGC based seeking
+ * new event on cell changes for timing info
+
+libdvdnav (0.1.5) unstable; urgency=low
+ * some bugfixes
+ * code cleanup
+ * build process polishing
+ * more sensible event order in get_next_block to ensure useful event delivery
+ * VOBU level resume
+ * fixed: seeking in a multiangle feature briefly showed the wrong angle
+
+libdvdnav (0.1.4) unstable; urgency=low
+ * more read cache improvements
+ * minor fixes for some problematic DVDs
+
+libdvdnav (0.1.3-1) unstable; urgency=low
+ * Zero-copy read cache.
+ * More support for alternative Menu languages.
+
+ -- Rich Wareham <richwareham@users.sourceforge.net> Fri, 2 Aug 2002 08:52:24 +0100
+
+libdvdnav (0.1.2-1) unstable; urgency=low
+ * Read Cache changes. Recommended setting for read_cache is OFF.
+ Unless one's DVD drive has too small a buffer.
+ * Should work with xine 0.9.10 or above.
+
+ -- James Courtier-Dutton <jcdutton@users.sourceforge.net> Sun, 3 Jul 2002 15:30:00 +0000
+
+libdvdnav (0.1.1-1) unstable; urgency=low
+
+ * New upstream version. (closes: #148495)
+ * Include TODO
+ * Fix config.h problem
+ * Threaded cache
+
+ -- Philipp Matthias Hahn <pmhahn@titan.lahn.de> Sat, 1 Jun 2002 17:47:59 +0200
+
+libdvdnav (0.1.0-2) unstable; urgency=low
+
+ * Add manual page dvdnav-config.1
+ * Add bug-presubj on Daniel's request
+ * Get dvdnav.c:1.17 from CVS to fix angle support
+ * Merge patch from Jamie Wilkinson (#146699)
+ * Rerun automake to fix dependencies
+ * Ack NMU from siggi
+ * Fix include in examples/menus.c
+
+ -- Philipp Hahn <pmhahn@titan.lahn.de> Thu, 23 May 2002 09:41:15 +0200
+
+libdvdnav (0.1.0-1.1) unstable; urgency=low
+
+ * Prepared for first 'real' release.
+ * Bug fixes
+ * Changes to allow apps to 'roll-their-own' dvdnav_get_next_block functions.
+ * NMU in order to get xine-dvdnav running again
+ - changed package name to libdvdnav0
+ (see patch from Jamie Wilkinson for a better solution)
+
+ -- Siggi Langauf <siggi@debian.org> Mon, 20 May 2002 15:57:40 +0200
+
+libdvdnav (0.0.1-1) unstable; urgency=low
+
+ * Repackaged using dh-make.
+
+ -- Philipp Matthias Hahn <pmhahn@titan.lahn.de> Sun, 7 Apr 2002 16:29:35 +0200
+
+libdvdnav (0.0.1) unstable; urgency=low
+
+ * Initial release.
+ * Split from xine-dvdnav
+
+ -- rjw57 <rjw57@hermes.cam.ac.uk> Tue, 12 Mar 2002 19:41:13 +0000
+
diff --git a/lib/libdvd/libdvdnav/DEVELOPMENT-POLICY.txt b/lib/libdvd/libdvdnav/DEVELOPMENT-POLICY.txt
new file mode 100644
index 0000000000..20c73e5005
--- /dev/null
+++ b/lib/libdvd/libdvdnav/DEVELOPMENT-POLICY.txt
@@ -0,0 +1,25 @@
+This fork of dvdnav was created to overcome the lack of responsiveness
+of the official development channel, not to bastardize this library in
+something for specific usage by mplayer, so these are the rules to follow
+when developing code:
+- don't remove pre-existing code that mplayer doesn't need
+- don't add code to expose the internals of dvdnav
+- don't add code that binds applications to side-effects of the library
+- don't alter the API in an incompatible manner
+
+
+When committing code to the repository always follow these rules:
+- don't break the compilability of the library - always keep svn checkouts usable
+- never mix cosmetical and functional changes
+- don't commit unrelated changes as a single transaction
+- don't split strictly related changes over multiple commits
+- never alter the indentation / bracing / prototyping style of existing files
+- if you break something by accident fix it as soon as possible using the appropriate
+ svn tools to revert your commit(s). If in doubt ask explanations to the
+ mailing list
+- trivial patches such as spell fixes, prototype mismatch, missing includes,
+ more proper variable typization and similar should be committed without asking
+ prior authorization
+
+
+If in reiterated violation of these rules your account will be deleted.
diff --git a/lib/libdvd/libdvdnav/Makefile b/lib/libdvd/libdvdnav/Makefile
new file mode 100644
index 0000000000..85245b7a4d
--- /dev/null
+++ b/lib/libdvd/libdvdnav/Makefile
@@ -0,0 +1,166 @@
+include config.mak
+
+.SUFFIXES: .so
+
+AR=ar
+LD=ld
+RANLIB=ranlib
+
+VPATH+= $(SRC_PATH_BARE)/src
+SRCS = dvdnav.c highlight.c navigation.c read_cache.c remap.c searching.c settings.c
+
+VPATH+= $(SRC_PATH_BARE)/src/vm
+SRCS+= decoder.c vm.c vmcmd.c
+
+HEADERS = src/dvd_types.h src/dvdnav.h src/dvdnav_events.h
+
+CFLAGS += $(USEDEBUG) -Wall -funsigned-char
+CFLAGS += -I$(CURDIR) -I$(SRC_PATH)/src -I$(SRC_PATH)/src/vm
+CFLAGS += -DDVDNAV_COMPILE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
+CFLAGS += -DHAVE_CONFIG_H -DHAVE_DLFCN_H
+
+L=libdvdnav
+MINI_L=libdvdnavmini
+CFLAGS += $(DVDREAD_CFLAGS)
+
+LIB = $(L).a
+SHLIB = $(L).so
+MINI_SHLIB = $(MINI_L).so
+
+.OBJDIR= obj
+DEPFLAG = -M
+
+OBJS = $(patsubst %.c,%.o, $(SRCS))
+SHOBJS = $(patsubst %.c,%.so, $(SRCS))
+DEPS= ${OBJS:%.o=%.d}
+
+BUILDDEPS = Makefile config.mak
+
+ifeq ($(BUILD_SHARED),yes)
+all: $(SHLIB) $(MINI_SHLIB) dvdnav-config pkgconfig
+install: $(SHLIB) install-shared install-dvdnav-config install-pkgconfig
+endif
+
+ifeq ($(BUILD_STATIC),yes)
+all: $(LIB) dvdnav-config pkgconfig
+install: $(LIB) install-static install-dvdnav-config install-pkgconfig
+endif
+
+install: install-headers
+
+# Let version.sh create version.h
+
+SVN_ENTRIES = $(SRC_PATH_BARE)/.svn/entries
+ifeq ($(wildcard $(SVN_ENTRIES)),$(SVN_ENTRIES))
+version.h: $(SVN_ENTRIES)
+endif
+
+version.h:
+ sh $(SRC_PATH)/version.sh $(SRC_PATH) "$(SHLIB_VERSION)"
+
+$(SRCS): version.h
+
+
+# General targets
+
+${LIB}: version.h $(OBJS) $(BUILDDEPS)
+ cd $(.OBJDIR) && $(AR) rc $@ $(OBJS)
+ cd $(.OBJDIR) && $(RANLIB) $@
+
+${SHLIB}: version.h $(SHOBJS) $(BUILDDEPS)
+ cd $(.OBJDIR) && $(CC) $(SHLDFLAGS) -Wl,-soname=$(SHLIB).$(SHLIB_MAJOR) -o $@ $(SHOBJS) $(DVDREAD_LIBS) $(THREADLIB)
+${MINI_SHLIB}: version.h $(.OBJDIR) $(SHOBJS) $(BUILDDEPS)
+ cd $(.OBJDIR) && $(CC) $(SHLDFLAGS) -Wl,-soname=$(MINI_SHLIB).$(SHLIB_MAJOR) -o $@ $(SHOBJS) $(THREADLIB)
+
+.c.so: $(BUILDDEPS)
+ cd $(.OBJDIR) && $(CC) -fPIC -DPIC -MD $(CFLAGS) -c -o $@ $<
+
+.c.o: $(BUILDDEPS)
+ cd $(.OBJDIR) && $(CC) -MD $(CFLAGS) -c -o $@ $<
+
+
+# Install targets
+
+install-headers:
+ install -d $(DESTDIR)$(incdir)
+ install -m 644 $(HEADERS) $(DESTDIR)$(incdir)
+
+install-shared: $(SHLIB)
+ install -d $(DESTDIR)$(shlibdir)
+
+ install $(INSTALLSTRIP) -m 755 $(.OBJDIR)/$(SHLIB) \
+ $(DESTDIR)$(shlibdir)/$(SHLIB).$(SHLIB_VERSION)
+ install $(INSTALLSTRIP) -m 755 $(.OBJDIR)/$(MINI_SHLIB) \
+ $(DESTDIR)$(shlibdir)/$(MINI_SHLIB).$(SHLIB_VERSION)
+
+ cd $(DESTDIR)$(shlibdir) && \
+ ln -sf $(SHLIB).$(SHLIB_VERSION) $(SHLIB).$(SHLIB_MAJOR)
+ cd $(DESTDIR)$(shlibdir) && \
+ ln -sf $(MINI_SHLIB).$(SHLIB_VERSION) $(MINI_SHLIB).$(SHLIB_MAJOR)
+ cd $(DESTDIR)$(shlibdir) && \
+ ln -sf $(SHLIB).$(SHLIB_MAJOR) $(SHLIB)
+ cd $(DESTDIR)$(shlibdir) && \
+ ln -sf $(MINI_SHLIB).$(SHLIB_MAJOR) $(MINI_SHLIB)
+
+
+install-static: $(LIB)
+ install -d $(DESTDIR)$(libdir)
+
+ install $(INSTALLSTRIP) -m 755 $(.OBJDIR)/$(LIB) $(DESTDIR)$(libdir)/$(LIB)
+
+
+# Clean targets
+
+clean:
+ rm -rf *~ $(.OBJDIR)/*
+
+pcedit = sed \
+ -e 's,@prefix@,$(PREFIX),' \
+ -e 's,@exec_prefix@,$(PREFIX),' \
+ -e 's,@libdir@,$(shlibdir),' \
+ -e 's,@includedir@,$(PREFIX)/include,' \
+ -e 's,@VERSION@,$(SHLIB_VERSION),' \
+ -e 's,@THREAD_CFLAGS@,,' \
+ -e 's,@THREAD_LIBS@,$(THREADLIB),' \
+ -e 's,@DVDREAD_CFLAGS@,$(DVDREAD_CFLAGS),'
+
+pkgconfig: $(.OBJDIR)/dvdnav.pc $(.OBJDIR)/dvdnavmini.pc
+$(.OBJDIR)/dvdnav.pc: misc/dvdnav.pc.in $(BUILDDEPS)
+ $(pcedit) $< > $@
+$(.OBJDIR)/dvdnavmini.pc: misc/dvdnavmini.pc.in $(BUILDDEPS)
+ $(pcedit) $< > $@
+
+install-pkgconfig: $(.OBJDIR)/dvdnav.pc $(.OBJDIR)/dvdnavmini.pc
+ install -d $(DESTDIR)$(libdir)/pkgconfig
+ install -m 0644 $(.OBJDIR)/dvdnav.pc $(DESTDIR)$(libdir)/pkgconfig
+ install -m 0644 $(.OBJDIR)/dvdnavmini.pc \
+ $(DESTDIR)$(libdir)/pkgconfig
+
+distclean: clean
+ find . -name "*~" | xargs rm -rf
+ rm -rf config.mak $(.OBJDIR)
+
+dvdnav-config: $(.OBJDIR)/dvdnav-config
+$(.OBJDIR)/dvdnav-config: $(BUILDDEPS)
+ @echo '#!/bin/sh' > $(.OBJDIR)/dvdnav-config
+ @echo 'prefix='$(PREFIX) >> $(.OBJDIR)/dvdnav-config
+ @echo 'libdir='$(shlibdir) >> $(.OBJDIR)/dvdnav-config
+ @echo 'version='$(SHLIB_VERSION) >> $(.OBJDIR)/dvdnav-config
+ @echo 'dvdread_cflags="'$(DVDREAD_CFLAGS)'"' >> $(.OBJDIR)/dvdnav-config
+ @echo 'dvdread_libs="'$(DVDREAD_LIBS)'"' >> $(.OBJDIR)/dvdnav-config
+ @echo 'threadlib='$(THREADLIB) >> $(.OBJDIR)/dvdnav-config
+ @echo >> $(.OBJDIR)/dvdnav-config
+ cat $(SRC_PATH_BARE)/misc/dvdnav-config2.sh >> $(.OBJDIR)/dvdnav-config
+ chmod 0755 $(.OBJDIR)/dvdnav-config
+
+install-dvdnav-config: dvdnav-config
+ install -d $(DESTDIR)$(PREFIX)/bin
+ install -m 0755 $(.OBJDIR)/dvdnav-config $(DESTDIR)$(PREFIX)/bin/dvdnav-config
+
+vpath %.so ${.OBJDIR}
+vpath %.o ${.OBJDIR}
+vpath ${LIB} ${.OBJDIR}
+
+# include dependency files if they exist
+$(addprefix ${.OBJDIR}/, ${DEPS}): ;
+-include $(addprefix ${.OBJDIR}/, ${DEPS})
diff --git a/lib/libdvd/libdvdnav/Makefile.am b/lib/libdvd/libdvdnav/Makefile.am
new file mode 100644
index 0000000000..f03ecaaeff
--- /dev/null
+++ b/lib/libdvd/libdvdnav/Makefile.am
@@ -0,0 +1,42 @@
+include $(top_srcdir)/misc/Makefile.common
+
+
+SUBDIRS = src examples doc misc m4
+
+EXTRA_DIST = autogen.sh \
+ AUTHORS \
+ ChangeLog \
+ configure \
+ config.guess \
+ config.sub \
+ COPYING \
+ INSTALL \
+ install-sh \
+ libtool \
+ ltmain.sh \
+ missing \
+ mkinstalldirs \
+ README \
+ TODO
+
+MOSTLYCLEANFILES += $(PACKAGE)_$(VERSION).tar.gz \
+ $(distdir).tar.gz $(PACKAGE).tgz package_descriptions
+
+MAINTAINERCLEANFILES += configure $(ACLOCAL_M4) config.h.in \
+ ltmain.sh config.guess config.sub install-sh missing \
+ mkinstalldirs
+
+world:
+ @$(MAKE) clean all install 2> warnings.log
+ test -s warnings.log || rm warnings.log
+
+prune-cache:
+ -rm -f config.cache
+
+release-check:
+ @./config.status misc/relchk.sh
+ @./autogen.sh noconfig && $(SHELL) misc/relchk.sh
+
+dist-hook:
+ cp -r $(srcdir)/msvc $(distdir)/msvc
+ rm -rf `find $(distdir)/msvc -name CVS`
diff --git a/lib/libdvd/libdvdnav/NEWS b/lib/libdvd/libdvdnav/NEWS
new file mode 100644
index 0000000000..7aa22b1545
--- /dev/null
+++ b/lib/libdvd/libdvdnav/NEWS
@@ -0,0 +1,2 @@
+This file is unused.
+The ChangeLog file lists changes for new versions.
diff --git a/lib/libdvd/libdvdnav/README b/lib/libdvd/libdvdnav/README
new file mode 100644
index 0000000000..d7f78d48a2
--- /dev/null
+++ b/lib/libdvd/libdvdnav/README
@@ -0,0 +1,57 @@
+What is this all about?
+-----------------------
+
+libdvdnav is a library that allows easy use of sophisticated DVD navigation
+features such as DVD menus, multiangle playback and even interactive DVD games.
+All this functionality is provided through a simple API which provides the
+DVD playback as a single logical stream of blocks, intermitted by special
+dvdnav events to report certain conditions. The main usage of libdvdnav is a
+loop regularly calling a function to get the next block, surrounded by
+additional calls to tell the library of user interaction.
+The whole DVD virtual machine and internal playback states are completely
+encapsulated.
+
+Where does it come from?
+------------------------
+
+This library is based on a lot of code and expertise from the Ogle project.
+Ogle was the first DVD player who implemented free DVD navigation. The
+libdvdnav developers wish to express their gratitude to the Ogle people
+for all the valuable research work they have done.
+
+Initially, the dvdnav code was part of a plugin to the xine media player
+called xine-dvdnav. Later on, the DVD VM specific code was split
+from xine-dvdnav and went into the first version of libdvdnav.
+
+Where is it now?
+----------------
+
+libdvdnav is hosted on http://www.mplayerhq.hu/MPlayer/releases/dvdnav/ .
+Please report bugs to the developers mailinglist at
+mailto:dvdnav-discuss@mplayerhq.hu .
+
+We are still in beta stage, but libdvdnav is already quite usable. With
+regular DVD playback, there should not be any serious issues. The library
+also makes some limited effort to handle error situations gracefully, but
+there are still assertions in the code that may trigger on some DVDs. Please
+send a report to the developer mailinglist, if you encounter such problems.
+
+How can I use it?
+-----------------
+
+libdvdnav is completely licensed under GPL. You may use it at wish within the
+bounds of this license. See the file "COPYING" for a copy of the GPL.
+
+Sources for documentation on libdvdnav are:
+* the examples directory contains a simple program using libdvdnav
+ this one is well-commented and therefore a good starting point
+* the public header dvdnav.h documents the API
+* the public header dvdnav_events.h documents the dvdnav events
+* doc/library_layout contains some info on the internal working of libdvdnav
+
+Sources for documentation on DVD terminology, structure and surrounding concepts:
+* doc/dvd_structures briefly explains DVD terms and organization
+* a more detailed description of DVD structures is available at
+ http://www.mpucoder.com/dvd/
+* the ifo_types.h and nav_types.h headers are also interesting if you
+ are already used to the sometimes cryptical abbreviations
diff --git a/lib/libdvd/libdvdnav/TODO b/lib/libdvd/libdvdnav/TODO
new file mode 100644
index 0000000000..3fe2eed5af
--- /dev/null
+++ b/lib/libdvd/libdvdnav/TODO
@@ -0,0 +1,12 @@
+* Support DVDs with errors on them. So we can recover from corrupt sectors in the .VOB. Also, handle corrupt .IFO files by using the backup .BUP files.
+* Support Random and Shuffle Titles. Only sequencial Titles are currently supported.
+* rework documentation
+* implement restriction levels:
+ 0 - execute everything as the app commands
+ 1 - do some sensible sanity checking
+ 2 - be more careful, when operations are prohibited (like not seeking/jumping in the presence of stills or cell commands)
+ 3 - fully respect user prohibitions
+* cleanup public API and fix libtool versioning
+* Update decoder.c with some of the more rare commands. Update already done to vmcmd.c
+* RELEASE! (maybe it's time for libdvdnav 0.5?)
+* Replace the auto* build system with a custom and clean one based on ffmpeg's (partly done)
diff --git a/lib/libdvd/libdvdnav/autogen.sh b/lib/libdvd/libdvdnav/autogen.sh
new file mode 100755
index 0000000000..6ffc84e710
--- /dev/null
+++ b/lib/libdvd/libdvdnav/autogen.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# $Id: autogen.sh 1091 2008-06-08 06:37:22Z nicodvb $
+#
+# run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname "$0"`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd "$srcdir"
+
+AUTORECONF=${AUTORECONF-autoreconf}
+
+if ! type $AUTORECONF >/dev/null 2>&1; then
+ echo "**Error**: Missing \`autoreconf' program." >&2
+ echo "You will need the autoconf and automake packages." >&2
+ echo "You can download them from ftp://ftp.gnu.org/pub/gnu/." >&2
+ exit 1
+fi
+
+$AUTORECONF -v --install || exit $?
+cd "$ORIGDIR" || exit $?
+
+test "$1" = noconfig && NOCONFIGURE=1
+
+if test -z "$NOCONFIGURE"; then
+ "$srcdir"/configure "$@"
+fi
diff --git a/lib/libdvd/libdvdnav/configure.ac b/lib/libdvd/libdvdnav/configure.ac
new file mode 100644
index 0000000000..e76fa25b8f
--- /dev/null
+++ b/lib/libdvd/libdvdnav/configure.ac
@@ -0,0 +1,253 @@
+dnl --------------------------------------------------------------
+dnl Configure.ac for libdvdnav
+dnl --------------------------------------------------------------
+
+dnl --------------------------------------------------------------
+dnl Require autoconf version 2.53
+dnl --------------------------------------------------------------
+AC_PREREQ([2.53])
+
+dnl --------------------------------------------------------------
+dnl Making releases: dvdnav_sub += 1; change DVDNAV_LT_* accordingly
+dnl
+dnl These are defined in m4 so they can be passed to AC_INIT
+dnl --------------------------------------------------------------
+m4_define([dvdnav_major], [4])
+m4_define([dvdnav_minor], [1])
+m4_define([dvdnav_sub], [3])
+m4_define([dvdnav_pre], [])
+
+AC_INIT([libdvdnav], [dvdnav_major.dvdnav_minor.dvdnav_sub[]dvdnav_pre])
+AC_CONFIG_SRCDIR([src/dvdnav.c])
+AM_INIT_AUTOMAKE([1.6])
+
+dnl create a config.h file (Automake will add -DHAVE_CONFIG_H)
+AC_CONFIG_HEADERS([config.h])
+AC_CANONICAL_HOST
+
+DVDNAV_MAJOR="dvdnav_major"
+DVDNAV_MINOR="dvdnav_minor"
+DVDNAV_SUB="dvdnav_sub"
+DVDNAV_PRE="dvdnav_pre"
+
+AC_SUBST(DVDNAV_MAJOR)
+AC_SUBST(DVDNAV_MINOR)
+AC_SUBST(DVDNAV_SUB)
+
+dnl The libtool version numbers (DVDNAV_LT_*); Don't even think about faking this!
+dnl
+dnl immediately before every release do:
+dnl ===================================
+dnl if (the interface is totally unchanged from previous release)
+dnl DVDNAV_LT_REVISION ++;
+dnl else { /* interfaces have been added, removed or changed */
+dnl DVDNAV_LT_REVISION = 0;
+dnl DVDNAV_LT_CURRENT ++;
+dnl if (any interfaces have been _added_ since last release)
+dnl AGE ++;
+dnl if (any interfaces have been _removed_ or _incompatibly changed_)
+dnl AGE = 0;
+dnl }
+dnl
+dnl If you want to know more about what you are doing, here are some details:
+dnl * DVDNAV_LT_CURRENT is the current API version
+dnl * DVDNAV_LT_REVISION is an internal revision number which is increased when the API
+dnl itself did not change
+dnl * DVDNAV_LT_AGE is the number of previous API versions still supported by this library
+dnl * libtool has its own numbering scheme, because local library numbering schemes
+dnl are platform dependent
+dnl * in Linux, the library will be named
+dnl libname.so.(DVDNAV_LT_CURRENT - DVDNAV_LT_AGE).DVDNAV_LT_AGE.DVDNAV_LT_REVISION
+
+DVDNAV_LT_CURRENT=5
+DVDNAV_LT_AGE=1
+DVDNAV_LT_REVISION=2
+
+AC_SUBST(DVDNAV_LT_CURRENT)
+AC_SUBST(DVDNAV_LT_AGE)
+AC_SUBST(DVDNAV_LT_REVISION)
+
+dnl --------------------------------------------------------------
+dnl Make possible to build for another arch.
+dnl --------------------------------------------------------------
+if test x$DVDNAV_BUILD != "x"; then
+ AC_MSG_RESULT(*** build forced to $DVDNAV_BUILD ***)
+ build=$DVDNAV_BUILD
+ host=$DVDNAV_BUILD
+else
+ check_athlon=yes
+fi
+
+dnl --------------------------------------------------------------
+dnl Checks for programs.
+dnl --------------------------------------------------------------
+dnl Save CFLAGS, AC_ISC_POSIX set some unwanted default CFLAGS
+saved_CFLAGS="$CFLAGS"
+AC_ISC_POSIX
+CFLAGS="$saved_CFLAGS"
+AC_PROG_CC
+AC_PROG_MAKE_SET
+AC_PROG_INSTALL
+AC_PROG_LN_S
+
+dnl --------------------------------------------------------------
+dnl Libtool
+dnl --------------------------------------------------------------
+dnl LT_PREREQ only available in libtool-2.2+
+dnl LT_PREREQ([1.4.0])
+AC_LIBTOOL_DLOPEN
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
+AC_SUBST(LIBTOOL_DEPS)
+if ${CONFIG_SHELL} ./libtool --features | grep "enable static" >/dev/null; then
+ STATIC="-static"
+else
+ STATIC=
+fi
+AC_SUBST(STATIC)
+
+dnl --------------------------------------------------------------
+dnl Checks for header files.
+dnl --------------------------------------------------------------
+AC_HEADER_STDC
+AC_CHECK_HEADER(unistd.h)
+AC_CHECK_HEADER(string.h)
+
+dnl --------------------------------------------------------------
+dnl Checks for typedefs, structures, and compiler characteristics.
+dnl --------------------------------------------------------------
+AC_C_CONST
+AC_C_INLINE
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+dnl AC_CHECK_TYPES([ptrdiff_t])
+AC_C_BIGENDIAN
+
+dnl -------------------------------------------------------------
+dnl Check for basic *nix fonction that we may emulate on windows.
+dnl -------------------------------------------------------------
+case $host in
+ *mingw32* | *cygwin*)
+ AC_CHECK_FUNCS(gettimeofday)
+ ;;
+ *)
+ ;;
+esac
+
+dnl ---------------------------------------------
+dnl threads
+dnl ---------------------------------------------
+case $host in
+ *-*-freebsd*)
+ THREAD_LIBS="-L/usr/local/lib -pthread"
+ THREAD_CFLAGS="-I/usr/local/include -D_THREAD_SAFE"
+ CFLAGS="$THREAD_CFLAGS $CFLAGS"
+ ;;
+ *mingw32* | *cygwin*)
+ ;;
+ *)
+ AC_CHECK_LIB(pthread, pthread_create,
+ [THREAD_LIBS="-lpthread"],
+ AC_MSG_ERROR(pthread needed))
+ ;;
+esac
+AC_SUBST(THREAD_LIBS)
+AC_SUBST(THREAD_CFLAGS)
+
+dnl ---------------------------------------------
+dnl dynamic linker
+dnl ---------------------------------------------
+case $host in
+ *mingw32*)
+ CFLAGS="-idirafter \$(top_srcdir)/msvc/include $CFLAGS"
+ LDFLAGS="-no-undefined $LDFLAGS"
+ ;;
+ *cygwin*)
+ LDFLAGS="-no-undefined $LDFLAGS"
+ ;;
+ *)
+ AC_CHECK_LIB(c, dlopen,
+ DYNAMIC_LD_LIBS="",
+ AC_CHECK_LIB(dl, dlopen,
+ DYNAMIC_LD_LIBS="-ldl",
+ AC_MSG_ERROR(dynamic linker needed)))
+ AC_SUBST(DYNAMIC_LD_LIBS)
+ ;;
+esac
+
+dnl ---------------------------------------------
+dnl libdvdread
+dnl ---------------------------------------------
+AC_ARG_WITH([dvdread-config],
+ [AS_HELP_STRING([--with-dvdread-config=PROG],
+ [dvdread-config program to use @<:@default=from PATH@:>@])],
+ [DVDREAD_CONFIG="$withval"],
+ [dnl User didn't specify program, search PATH
+ AC_PATH_PROG([DVDREAD_CONFIG], [dvdread-config], [no])
+ test "x$DVDREAD_CONFIG" = xno && \
+ AC_MSG_ERROR([dvdread-config required to link with libdvdread])
+ ])
+DVDREAD_CFLAGS=`$DVDREAD_CONFIG --cflags` || \
+ AC_MSG_ERROR([Could not get libdvdread CFLAGS from $DVDREAD_CONFIG])
+DVDREAD_LIBS=`$DVDREAD_CONFIG --libs` || \
+ AC_MSG_ERROR([Could not get libdvdread LIBS from $DVDREAD_CONFIG])
+AC_SUBST([DVDREAD_CFLAGS])
+AC_SUBST([DVDREAD_LIBS])
+
+dnl ---------------------------------------------
+dnl cflags
+dnl ---------------------------------------------
+dnl Common cflags for all platforms
+CFLAGS="-O3 -Wall -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE $CFLAGS"
+DEBUG_CFLAGS="-g -DDEBUG $CFLAGS"
+
+AC_SUBST(DEBUG_CFLAGS)
+
+dnl ---------------------------------------------
+dnl Get where .m4 should be installed.
+dnl ---------------------------------------------
+case "`id`" in
+ uid=0\(* )
+ AC_MSG_CHECKING(for aclocal directory)
+ if (aclocal --version) < /dev/null > /dev/null 2>&1; then
+ ACLOCAL_DIR="`eval $ACLOCAL --print-ac-dir`"
+ AC_MSG_RESULT($ACLOCAL_DIR)
+ else
+ ACLOCAL_DIR="/usr/local/share/aclocal"
+ AC_MSG_RESULT(none - will be installed in $ACLOCAL_DIR)
+ fi
+ escapedprefix="`echo $prefix | sed -e 's/\\//\\\\\//g'`"
+ ACLOCAL_DIR="`echo $ACLOCAL_DIR|sed -e 's/^'$escapedprefix/'\${prefix}'/`"
+ AC_SUBST(ACLOCAL_DIR)
+ ;;
+esac
+AM_CONDITIONAL(INSTALL_M4, test x"$ACLOCAL_DIR" != "x")
+
+dnl ---------------------------------------------
+dnl Check for doxygen (dynamic documentation generator)
+dnl ---------------------------------------------
+AC_CHECK_PROG(DOXYGEN, doxygen, doxygen, no)
+
+dnl ---------------------------------------------
+dnl Some include paths ( !!! DO NOT REMOVE !!! )
+dnl ---------------------------------------------
+INCLUDES='-I$(top_srcdir) $(DVDNAV_CFLAGS)'
+AC_SUBST(INCLUDES)
+
+dnl ---------------------------------------------
+dnl Output configuration files
+dnl ---------------------------------------------
+AC_OUTPUT([
+Makefile
+src/Makefile
+src/vm/Makefile
+misc/Makefile
+misc/dvdnav-config
+misc/dvdnav.pc
+misc/dvdnavmini.pc
+misc/libdvdnav.spec
+misc/relchk.sh
+m4/Makefile
+doc/Makefile
+examples/Makefile
+])
diff --git a/lib/libdvd/libdvdnav/configure2 b/lib/libdvd/libdvdnav/configure2
new file mode 100755
index 0000000000..5767a5ab94
--- /dev/null
+++ b/lib/libdvd/libdvdnav/configure2
@@ -0,0 +1,172 @@
+#!/bin/sh
+
+dvdnav_sh_version=4.1.3
+dvdnav_sh_major=`echo $dvdnav_sh_version | awk -F. '{print $1}'`
+
+cc=gcc
+make=make
+
+# find source path
+source_path="`dirname \"$0\"`"
+source_path_used="yes"
+if test -z "$source_path" -o "$source_path" = "." ; then
+ source_path="`pwd`"
+ source_path_used="no"
+else
+ source_path="`cd \"$source_path\" && pwd`"
+ echo "$source_path" | grep -q '[[:blank:]]' &&
+ die "Out of tree builds are impossible with whitespace in source path."
+fi
+
+show_help(){
+ echo "Usage: configure [options]"
+ echo "Options: [defaults in brackets after descriptions]"
+ echo
+ echo "Standard options:"
+ echo " --help print this message"
+ echo " --prefix=PREFIX install in PREFIX [$PREFIX]"
+ echo " --libdir=DIR install libs in DIR [PREFIX/lib]"
+ echo " --shlibdir=DIR install shared libs in DIR [PREFIX/lib]"
+ echo " --incdir=DIR install includes in DIR [PREFIX/include/dvdnav]"
+ echo " --enable-static build static libraries [default=yes]"
+ echo " --disable-static do not build static libraries [default=no]"
+ echo " --enable-shared build shared libraries [default=no]"
+ echo " --disable-shared do not build shared libraries [default=yes]"
+ echo " --enable-debug compile with debug symbols [default=yes]"
+ echo " --disable-debug compile without debug symbols [default=no]"
+ echo " --with-dvdread=PATH compile libdvdnav with an external libdvdread"
+ echo "Advanced options (experts only):"
+ echo " --cc=CC use C compiler CC [$cc]"
+ echo " --make=MAKE use specified make [$make]"
+ echo " --extra-cflags=ECFLAGS add ECFLAGS to CFLAGS"
+ echo " --extra-ldflags=ELDFLAGS add ELDFLAGS to LDFLAGS"
+ echo "Developer options:"
+ echo " --disable-strip disable stripping of executables and shared libraries"
+ echo " --disable-opts disable compiler optimizations"
+ exit 1
+}
+
+SHARED=yes
+STATIC=yes
+DVDREAD_CONFIG=dvdread-config
+PREFIX=/usr/local/
+INSTALLSTRIP=-s
+USEDEBUG=-g
+optimizations="-O3"
+threadlib="-lpthread"
+
+for opt do
+ optval=`echo $opt | cut -d '=' -f 2-`
+ case "$opt" in
+ --enable-shared) SHARED=yes
+ ;;
+ --disable-shared) SHARED=no
+ ;;
+ --enable-static) STATIC=yes
+ ;;
+ --disable-static) STATIC=no
+ ;;
+ --with-dvdread-config=*) DVDREAD_CONFIG="$optval"
+ ;;
+ --prefix=*) PREFIX="$optval"
+ ;;
+ --libdir=*) libdir="$optval"
+ ;;
+ --shlibdir=*) shlibdir="$optval"
+ ;;
+ --incdir=*) incdir="$optval"
+ ;;
+ --cc=*) cc="$optval"
+ ;;
+ --make=*) make="$optval"
+ ;;
+ --extra-cflags=*) cflags="$cflags $optval"
+ ;;
+ --extra-ldflags=*) ldflags="$ldflags $optval"
+ ;;
+ --disable-strip) INSTALLSTRIP=
+ ;;
+ --disable-opts) optimizations=""
+ ;;
+ --disable-debug) USEDEBUG=""
+ ;;
+ --enable-debug) USEDEBUG="-g"
+ ;;
+ --help) show_help
+ ;;
+ esac
+done
+
+PREFIX=`cd $PREFIX && pwd`
+
+test -z "$libdir" && libdir=$PREFIX/lib
+test -z "$shlibdir" && shlibdir=$PREFIX/lib
+test -z "$incdir" && incdir=$PREFIX/include/dvdnav
+
+dvdread=no
+$DVDREAD_CONFIG --prefix >> /dev/null 2>&1 && dvdread=yes
+test "$dvdread" != "yes" && $DVDREAD_CONFIG --exists >> /dev/null 2>&1 && dvdread=yes
+if test "$dvdread" != "yes" ; then
+ echo "$DVDREAD_CONFIG returned an error. Can't proceed"
+ exit 1
+fi
+dvdread_cflags=`$DVDREAD_CONFIG --cflags`
+dvdread_libs=`$DVDREAD_CONFIG --libs`
+
+targetos=`uname -s`
+case $targetos in
+ Darwin)
+ SHLDFLAGS="-dynamiclib -Wl,-single_module -Wl,-read_only_relocs,suppress"
+ ;;
+ *)
+ SHLDFLAGS="-shared"
+ ;;
+esac
+
+cat > config.mak << EOF
+# Automatically generated by configure, do not edit
+PREFIX=$PREFIX
+libdir=$libdir
+shlibdir=$shlibdir
+incdir=$incdir
+THREADLIB=$threadlib
+BUILD_SHARED=$SHARED
+BUILD_STATIC=$STATIC
+SHLIB_VERSION=$dvdnav_sh_version
+SHLIB_MAJOR=$dvdnav_sh_major
+CC=$cc
+MAKE=$make
+CFLAGS=$optimizations $cflags
+LDFLAGS=$ldflags
+SHLDFLAGS=$SHLDFLAGS
+INSTALLSTRIP=$INSTALLSTRIP
+USEDEBUG=$USEDEBUG
+DVDREAD_CFLAGS=$dvdread_cflags
+DVDREAD_LIBS=$dvdread_libs
+
+SRC_PATH="$source_path"
+SRC_PATH_BARE=$source_path
+
+EOF
+
+cat > config.h << EOF
+/* Automatically generated by configure, do not edit */
+#include "version.h"
+EOF
+
+# build tree in object directory if source path is different from current one
+if test "$source_path_used" != "no"; then
+ FILES="\
+ Makefile \
+ misc \
+ "
+ for f in $FILES ; do
+ ln -sf "$source_path/$f" $f
+ done
+fi
+
+[ -d obj ] || mkdir -p obj
+
+echo
+echo "Done, type 'make install' to build and install"
+
diff --git a/lib/libdvd/libdvdnav/doc/Makefile.am b/lib/libdvd/libdvdnav/doc/Makefile.am
new file mode 100644
index 0000000000..205f055b1a
--- /dev/null
+++ b/lib/libdvd/libdvdnav/doc/Makefile.am
@@ -0,0 +1,8 @@
+include $(top_srcdir)/misc/Makefile.common
+
+EXTRA_DIST = doxy.conf mainpage.cpp tutorial.cpp dvd_structures library_layout
+
+docs: doxy.conf
+ @if test x"$(DOXYGEN)" != "xno"; then \
+ $(DOXYGEN) doxy.conf > /dev/null 2> /dev/null; \
+ fi
diff --git a/lib/libdvd/libdvdnav/doc/doxy.conf b/lib/libdvd/libdvdnav/doc/doxy.conf
new file mode 100644
index 0000000000..a55f262943
--- /dev/null
+++ b/lib/libdvd/libdvdnav/doc/doxy.conf
@@ -0,0 +1,947 @@
+# Doxyfile 1.2.16
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = libdvdnav
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY =
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch,
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Korean,
+# Norwegian, Polish, Portuguese, Romanian, Russian, Slovak, Slovene,
+# Spanish, Swedish and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these class will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
+# members of a class in the documentation of that class as if those members were
+# ordinary class members. Constructors, destructors and assignment operators of
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH =
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower case letters. If set to YES upper case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# users are adviced to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explict @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# reimplements.
+
+INHERIT_DOCS = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consist of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C.
+# For instance some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = .
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
+# *.h++ *.idl *.odl
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH = examples
+
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+
+INPUT_FILTER =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse.
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the Html help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript and frames is required (for instance Mozilla, Netscape 4.0+,
+# or Internet explorer 4.0+). Note that for large projects the tree generation
+# can take a very long time. In such cases it is better to disable this feature.
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimised for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assigments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_XML = NO
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line and do not end with a semicolon. Such function macros are typically
+# used for boiler-plate code, and will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tagfiles.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or
+# super classes. Setting the tag to NO turns the diagrams off. Note that this
+# option is superceded by the HAVE_DOT option below. This is only a fallback. It is
+# recommended to install and use dot, since it yield more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermedate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
+
+# The CGI_NAME tag should be the name of the CGI script that
+# starts the search engine (doxysearch) with the correct parameters.
+# A script with this name will be generated by doxygen.
+
+CGI_NAME = search.cgi
+
+# The CGI_URL tag should be the absolute URL to the directory where the
+# cgi binaries are located. See the documentation of your http daemon for
+# details.
+
+CGI_URL =
+
+# The DOC_URL tag should be the absolute URL to the directory where the
+# documentation is located. If left blank the absolute path to the
+# documentation, with file:// prepended to it, will be used.
+
+DOC_URL =
+
+# The DOC_ABSPATH tag should be the absolute path to the directory where the
+# documentation is located. If left blank the directory on the local machine
+# will be used.
+
+DOC_ABSPATH =
+
+# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
+# is installed.
+
+BIN_ABSPATH = /usr/local/bin/
+
+# The EXT_DOC_PATHS tag can be used to specify one or more paths to
+# documentation generated for other projects. This allows doxysearch to search
+# the documentation for these projects as well.
+
+EXT_DOC_PATHS =
diff --git a/lib/libdvd/libdvdnav/doc/dvd_structures b/lib/libdvd/libdvdnav/doc/dvd_structures
new file mode 100644
index 0000000000..9d8569bab7
--- /dev/null
+++ b/lib/libdvd/libdvdnav/doc/dvd_structures
@@ -0,0 +1,107 @@
+This is some rather basic information on the organizational structures of
+a DVD. I collected this info over time from various sources, the most
+valuable being an article in the German c't computer magazine.
+Some of the info might be wrong according to the DVD standard (which I do
+not know), but they are practically proven in libdvdnav.
+
+ Michael Roitzsch
+
+
+0. storage structure
+ - sector
+ * smallest addressable unit on disc
+ * data is stored on disc with a Reed-Solomon error correction
+ - file
+ * the storage entity in the underlying filesystem (usually UDF)
+ * on DVD-Video, files are stored consecutively
+1. MPEG stream structure
+ - blocks
+ * a file system driver (usually UDF) is needed to map the VOBS-local
+ block numbers to global disc sectors
+ - GOP (group of pictures)
+ * contains multiple sectors
+ * smallest self-contained MPEG unit
+ - VOBU (video object unit)
+ * contains multiple GOPs + audio and SPU blocks + NAV packet
+ * smallest unit in seek and resume operations, always starts with a
+ NAV packet used for menu button highlight and command information
+ and to detect PTS discontinuities
+ - ILVU (interleaved video unit)
+ * contains multiple VOBUs (ususally only one)
+ * blocking multiple VOBUs of multiple interleaved MPEG streams for
+ multiangle features
+ - VOB (video object)
+ * contains multiple ILVUs (usually quite a lot)
+ * each NAV packet has a CellID, so VOBs are divided into stream Cells
+ which do not necessarily correspond to the navigation Cells below
+ - VOBS (video object set)
+ * contains multiple VOBs (addressed by VOB_ID)
+ * a VOBS is the storage analogy to the playback domains below,
+ therefore, a VMGM_VOBS, a VTSM_VOBS and a VTS_VOBS exist
+ * all block addressing is done within the scope of the VOBS
+2. navigational structure - logical playback control
+ - Cell
+ * smallest unit which is layed out in sequence
+ * points to a first and last VOBU (by sector)
+ * also points to the corresponding CellID and VOB_ID
+ * smallest unit to execute VM commands (cell_post commands)
+ * smallest unit accesible by VM commands (apart from LinkRSM)
+ - PG (program)
+ * points to a Cell
+ * usually the mapping between PG and Cells is 1:1, but not always
+ (multiple Cells inside one PG can occur when special VM commands
+ have to be executed in the middle of a PG, for example to switch
+ SPU channels or to provide a branching target for special
+ features that need access to parts of the movie)
+ * unit for user skip operations
+ * libdvdnav's default unit for seeking
+ - PGC (program chain)
+ * contains multiple programs and cells
+ * logical playback chain
+ * VM commands at start and stop (PGC_pre and PGC_post commands)
+ * might be used for seeking (see dvdnav_set_PGC_positioning())
+3. title structure - high level navigation
+ - PTT (part of title track)
+ * points to a PG in a PGC
+ * usually what you select in a "chapter menu" are parts
+ * usually the mapping between PTT and PG is 1:1, but not always
+ (this is similar to the distinction between track and index marks
+ on audio CDs: PTT = track mark, PG = index mark)
+ - TT (title track)
+ * contains multiple PTTs
+ * logical partitioning of the content
+ (multiple episodes of a TV series on one DVD: one TT per episode)
+ * the display of DVD players show title and part number
+ - VTS (video title set)
+ * contains multiple TTs with a local numbering (to emphasize the
+ local scope of the number, these are also called VTS_TT)
+ * high level partitioning of the content (movie / bonus material)
+ * video, audio and spu attributes are common inside a whole VTS
+4. domain structure - bringing it all together
+ - FP (first play)
+ * one special PGC in the VMGM domain run on start of the disc
+ - VMGM (video manager menu) - files video_ts.{vob,ifo,bup}
+ * the menu which allows you to select between title sets
+ * corresponds to the VMGM_VOBS (video_ts.vob) and
+ the VMGI (video_ts.ifo)
+ * contains sets of PGCs, differentiated by language
+ * contains a global table of TTs each pointing to a VTS and a local VTS_TT
+ * contains parental management information
+ * contains attribute lists for the VTS'es
+ * contains text data (?)
+ * contains a Cell and a VOBU lists with local sector info (for seeking)
+ - VTSM (video title set menu) - files vts_<vtsN>_0.{vob,ifo,bup}
+ * the menu which allows you to select between the TTs of a VTS
+ * corresponds to the VTSM_VOBS (vts_<vtsN>_0.vob) and
+ the VTSI (vts_<vtsN>_0.ifo)
+ * contains sets of PGCs, differentiated by language
+ * contains a Cell and a VOBU lists with local sector info (for seeking)
+ - VTS (video title set) - files vts_<vtsN>_[1-x].vob, vts_<vtsN>_0.{ifo,bup}
+ * regular playback domain
+ * corresponds to the VTS_VOBS (vts_<vtsN>_[1-x].vob) and
+ the VTSI (vts_<vtsN>_0.ifo)
+ * contains one VTS with its VTS_TTs and PGCs
+ * contains a time map (for time-based seeking)
+ * contains a Cell and a VOBU lists with local sector info (for seeking)
+ - STOP
+ * 'nuff said
diff --git a/lib/libdvd/libdvdnav/doc/library_layout b/lib/libdvd/libdvdnav/doc/library_layout
new file mode 100644
index 0000000000..74116a9682
--- /dev/null
+++ b/lib/libdvd/libdvdnav/doc/library_layout
@@ -0,0 +1,53 @@
+This is information on what the various files in libdvdnav/src are for:
+
+public API
+----------
+
+dvdnav.h main public header
+dvdnav_events.h events returned by get_next_block()
+dvd_types.h some additional convenience types, mostly unused yet
+
+dvd_reader.h libdvdread API
+ifo_types.h IFO structures translated into C
+ifo_read.h reading and parsing of IFO structures
+nav_types.h NAV structures translated into C
+nav_read.h reading and parsing of NAV structures
+nav_print.h print NAV structures in a human readable form
+
+client interaction
+------------------
+
+dvdnav.c the big get_next_block() function and some basic housekeeping
+dvdnav_internal.h internal structure of libdvdnav library handle
+navigation.c basic Title/Part navigation
+searching.c PGC/PG navigation and seeking, position reporting
+highlight.c DVD menu highlight handling
+settings.c libdvdnav customizing
+remap.[ch] user defined reorganization of VOBU playback order
+
+DVD virtual machine (subdirectory vm)
+-------------------
+
+vm.[ch] the logic surrounding the DVD VM
+decoder.[ch] decodes and executes DVD VM commands
+
+DVD reading (subdirectory dvdread, a modified copy of libdvdread)
+-----------
+
+dvd_reader.c reading data from DVD sources
+dvd_udf.[ch] handles the UDF filesystem
+dvd_input.[ch] lowlevel input abstraction, libdvdcss glue code
+md5.[ch] md5 hashing to provide unique disc IDs
+
+ifo_read.c reading and parsing of IFO structures
+nav_read.c reading and parsing of NAV structures
+nav_print.c output NAV structures in a human readable form
+
+read_cache.[ch] caching
+
+debugging and utilities
+-----------------------
+
+bswap.h endianness helper macros
+dvdread_internal.h CHECK_VALUE() helper macro
+vmcmd.[ch] print DVD VM commands and registers in a human readable form
diff --git a/lib/libdvd/libdvdnav/doc/mainpage.cpp b/lib/libdvd/libdvdnav/doc/mainpage.cpp
new file mode 100644
index 0000000000..3f5e88c5bc
--- /dev/null
+++ b/lib/libdvd/libdvdnav/doc/mainpage.cpp
@@ -0,0 +1,51 @@
+/*!
+
+\mainpage The libdvdnav Reference Documentation
+
+\section intro Introduction
+
+This reference is not maintained. See the README file for pointers on
+current documentation.
+
+This reference documentation is intended to both provide a comprehensive reference to
+the <tt>libdvdnav</tt> DVD navigation library and a brief introduction to the library
+for new users.
+
+This documentation is automatically generated from the <tt>libdvdnav</tt> code so
+should remain somewhat relevant but as always be wary that <tt>libdvdnav</tt>
+is currently in heavy development and the API is not yet frozen.
+
+\subsection feedback Feedback
+
+All comments, error reports, additional information and criticism of all sorts
+should be directed to <tt>dvd-devel@lists.sf.net</tt>.
+
+\subsection disclaimer Disclaimer
+
+No liability for the contents of this documents can be accepted. Use the concepts,
+examples and other content at your own risk. Additionally, this is an early version,
+with many possibilities for inaccuracies and errors.
+
+As far as I know, all of the programmes mentioned here and example code quoted are
+released under the GNU General Public License or the Lesser GNU Public License.
+
+\subsection copyright Copyright information
+
+This document is copyrighted &copy;2002 by Richard Wareham and the <tt>libdvdnav</tt>
+project. It is distributed under the following terms:
+
+ - This document may be reproduced and distributed in whole or in part, in any medium
+ physical or electronic, as long as this copyright notice is retained on all copies.
+ Commercial redistribution is allowed and encouraged; however, the author would like
+ to be notified of any such distributions.
+ - All translations, derivative works, or aggregate works incorporating any parts of
+ this document must be covered under this copyright notice. That is, you may not produce
+ a derivative work from this manual and impose additional restrictions on its distribution.
+
+\section sections Section
+
+ - A tutorial is in section \ref tutorial .
+ - A complete reference may be found in the <A HREF="modules.html">modules</a> section.
+
+*/
+
diff --git a/lib/libdvd/libdvdnav/doc/tutorial.cpp b/lib/libdvd/libdvdnav/doc/tutorial.cpp
new file mode 100644
index 0000000000..5306eb8749
--- /dev/null
+++ b/lib/libdvd/libdvdnav/doc/tutorial.cpp
@@ -0,0 +1,253 @@
+/*! \page tutorial A libdvdnav Tutorial
+
+The <tt>libdvdnav</tt> library provides a powerful API allowing your
+programs to take advantage of the sophisticated navigation features
+on DVDs.
+
+\subsection wherenow Tutorial sections
+
+ - For an introduction to the navigation features of DVDs look in section
+ \ref dvdnavissues . This also provides an overview of the concepts
+ required to understand DVD navigation.
+ - For a step-by step walkthrough of a simple program look in
+ section \ref firstprog .
+ - FIXME: More sections :)
+
+*/
+
+/*! \page dvdnavissues An introduction to DVD navigation
+
+The DVD format represents a radical departure from the traditional
+form of video home-entertainment. Instead of just being a linear
+programme which is watched from beginning to end like a novel
+DVD allows the user to jump about at will (much like those
+'Choose your own adventure' or 'Which Way' books which were
+popular a while back).
+
+Such features are usually referred to under the moniker
+'interactive' by marketting people but you aren't in marketting
+since you are reading the <tt>libdvdnav</tt> tutorial. We'll
+assume you actually want to know precisely what DVD can do.
+
+\subsection layout DVD logical layout
+
+A DVD is logically structured into titles, chapters (also
+known as 'parts'), cells and VOBUS, much like the
+filesystem on your hard disc. The structure is heirachical.
+A typical DVD might have the following structure:
+
+\verbatim
+ .
+ |-- Title 1
+ | |-- Chapter 1
+ | | |-- Cell 1
+ | | | |-- VOBU 1
+ | | | |-- ...
+ | | | `-- VOBU n
+ | | |-- ...
+ | | `-- Cell n
+ | |-- ...
+ | `-- Chapter 2
+ | |-- Cell 1
+ | | |-- VOBU 1
+ | | |-- ...
+ | | `-- VOBU n
+ | |-- ...
+ | `-- Cell n
+ |-- ...
+ `-- Title m
+ |-- Chapter 1
+ | |-- Cell 1
+ | | |-- VOBU 1
+ | | |-- ...
+ | | `-- VOBU n
+ | |-- ...
+ | `-- Cell n
+ |-- ...
+ `-- Chapter 2
+ |-- Cell 1
+ | |-- VOBU 1
+ | |-- ...
+ | `-- VOBU n
+ |-- ...
+ `-- Cell n
+\endverbatim
+
+A DVD 'Title' is generally a logically distinct section of video. For example the main
+feature film on a DVD might be Title 1, a behind-the-scenes documentary might be Title 2
+and a selection of cast interviews might be Title 3. There can be up to 99 Titles on
+any DVD.
+
+A DVD 'Chapter' (somewhat confusingly referred to as a 'Part' in the parlence of
+DVD authors) is generally a logical segment of a Title such as a scene in a film
+or one interview in a set of cast interviews. There can be up to 999 Parts in
+one Title.
+
+A 'Cell' is a small segment of a Part. It is the smallest resolution at which
+DVD navigation commands can act (e.g. 'Jump to Cell 3 of Part 4 of Title 2').
+Typically one Part contains one Cell but on complex DVDs it may be useful to have
+multiple Cells per Part.
+
+A VOBU (<I>V</I>ideo <I>OB</I>ject <I>U</I>nit) is a small (typically a few
+seconds) of video. It must be a self contained 'Group of Pictures' which
+can be understood by the MPEG decoder. All seeking, jumping, etc is guaranteed
+to occurr at a VOBU boundary so that the decoder need not be restarted and that
+the location jumped to is always the start of a valid MPEG stream. For multiple-angle
+DVDs VOBUs for each angle can be interleaved into one Interleaved Video Unit (ILVU).
+In this case when the player get to the end of the VOBU for angle <i>n</i> instead of
+jumping to the next VOBU the player will move forward to the VOBU for angle <i>n</i>
+in the next ILVU.
+
+This is summarised in the following diagram showing how the VOBUs are actually
+laid out on disc.
+
+\verbatim
+ ,---------------------------. ,---------------------------.
+ | ILVU 1 | | ILVU m |
+ | ,--------. ,--------. | | ,--------. ,--------. |
+ | | VOBU 1 | ... | VOBU 1 | | ... | | VOBU m | ... | VOBU m | |
+ | |Angle 1 | |Angle n | | | |Angle 1 | |Angle n | |
+ | `--------' `--------' | | `--------' `--------' |
+ `---------------------------' `---------------------------'
+\endverbatim
+
+\subsection vm The DVD Virtual Machine
+
+If the layout of the DVD were the only feature of the format the DVD
+would only have a limited amount of interactivity, you could jump
+around between Titles, Parts and Cells but not much else.
+
+The feature most people associate with DVDs is its ability to
+present the user with full-motion interactive menus. To provide
+these features the DVD format includes a specification for a
+DVD 'virtual machine'.
+
+To a first order approximation x86 programs can only be run on
+x86-based machines, PowerPC programs on PowerPC-based machines and so on.
+Java, however, is an exception in that programs are compiled into
+a special code which is designed for a 'Java Virtual Machine'.
+Programmes exist which take this code and convert it into code which
+can run on real processors.
+
+Similarly the DVD virtual machine is a hypothetical processor
+which has commands useful for DVD navigation (e.g. Jump to Title
+4 or Jump to Cell 2) along with the ability to perform
+simple arithmetic and save values in a number of special
+variables (in processor speak, they are known as 'registers').
+
+When a button is pressed on a DVD menu, a specified machine instruction
+can be executed (e.g. to jump to a particular Title). Similarly
+commands can be executed at the beginning and end of Cells and
+Parts to, for example, return to the menu at the end of a film.
+
+Return to the \ref tutorial.
+
+*/
+
+/*! \page firstprog A first libdvdnav program
+
+\section compiling Compiling a libdvdnav program
+
+Below is a simple <tt>libdvdnav</tt> program. Type/copy it and save it
+into the file 'dvdtest.c'.
+
+\verbatim
+#include <stdio.h>
+#include <dvdnav/dvdnav.h>
+#include <dvdnav/dvdnav_events.h>
+#include <sys/types.h>
+
+int main(int argc, char **argv) {
+ dvdnav_t *dvdnav;
+ int finished, len, event;
+ uint8_t buf[2050];
+
+ /* Open the DVD */
+ dvdnav_open(&dvdnav, "/dev/dvd");
+
+ fprintf(stderr, "Reading...\n");
+ finished = 0;
+ while(!finished) {
+ int result = dvdnav_get_next_block(dvdnav, buf,
+ &event, &len);
+
+ if(result == DVDNAV_STATUS_ERR) {
+ fprintf(stderr, "Error getting next block (%s)\n",
+ dvdnav_err_to_string(dvdnav));
+ exit(1);
+ }
+
+ switch(event) {
+ case DVDNAV_BLOCK_OK:
+ /* Write output to stdout */
+ fwrite(buf, len, 1, stdout);
+ break;
+ case DVDNAV_STILL_FRAME:
+ {
+ fprintf(stderr, "Skipping still frame\n");
+ dvdnav_still_skip(dvdnav);
+ }
+ break;
+ case DVDNAV_STOP:
+ {
+ finished = 1;
+ }
+ default:
+ fprintf(stderr, "Unhandled event (%i)\n", event);
+ finished = 1;
+ break;
+ }
+ }
+
+ dvdnav_close(dvdnav);
+
+ return 0;
+}
+\endverbatim
+
+If you have correctly installled <tt>libdvdnav</tt>, you should have the
+command 'dvdnav-config' in your path. If so you can compile this program
+with
+\verbatim
+ gcc -o dvdtest dvdtest.c `dvdnav-config --cflags --libs`
+\endverbatim
+
+If all goes well, this should generate the 'dvdtest' program in your current working
+directory. You can now start saving a MPEG 2 stream directly off your DVD
+with
+\verbatim
+ ./dvdtest 2>error.log >out.mpeg
+\endverbatim
+
+If the command fails, check the error.log file for details.
+
+\section walkthrorugh Line-by-line walk through
+
+\verbatim
+ include <stdio.h>
+ include <dvdnav/dvdnav.h>
+ include <dvdnav/dvdnav_events.h>
+ include <sys/types.h>
+\endverbatim
+
+These lines include the necessary headers. Almost all <tt>libdvdnav</tt> programs
+will only need to include the dvdnav.h and dvdnav_events.h header files from
+the dvdnav directory.
+
+\verbatim
+ dvdnav_open(&dvdnav, "/dev/dvd");
+\endverbatim
+
+The <tt>libdvdnav</tt> uses <tt>libdvdread</tt> for its DVD I/O. <tt>libdvdread</tt>
+accesses the DVD-device directly so dvdnav_open() needs to be passed the location
+of the DVD device. <tt>libdvdread</tt> can also open DVD images/mounted DVDs. Read
+the <tt>libdvdread</tt> documentation for more information.
+
+\verbatim
+ int result = dvdnav_get_next_block(dvdnav, buf,
+ &event, &len);
+\endverbatim
+
+Return to \ref tutorial.
+
+*/
diff --git a/lib/libdvd/libdvdnav/examples/Makefile.am b/lib/libdvd/libdvdnav/examples/Makefile.am
new file mode 100644
index 0000000000..c4540f51e0
--- /dev/null
+++ b/lib/libdvd/libdvdnav/examples/Makefile.am
@@ -0,0 +1,13 @@
+include $(top_srcdir)/misc/Makefile.common
+
+AM_CPPFLAGS = -DDVDNAV_COMPILE $(DVDREAD_CFLAGS) -I$(top_srcdir)/src
+
+DVDNAV_LIB = $(top_builddir)/src/libdvdnav.la
+
+noinst_PROGRAMS = menus
+
+menus_SOURCES = menus.c
+menus_LDADD = $(DVDNAV_LIB) $(DVDREAD_LIBS)
+
+$(DVDNAV_LIB):
+ @cd $(top_builddir)/src/ && $(MAKE) libdvdnav.la
diff --git a/lib/libdvd/libdvdnav/examples/menus.c b/lib/libdvd/libdvdnav/examples/menus.c
new file mode 100644
index 0000000000..5f83005576
--- /dev/null
+++ b/lib/libdvd/libdvdnav/examples/menus.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2003 by the libdvdnav project
+ *
+ * This file is part of libdvdnav, a DVD navigation library.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: menus.c 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "dvd_types.h"
+#include <dvdread/dvd_reader.h>
+#include <dvdread/nav_types.h>
+#include <dvdread/ifo_types.h> /* For vm_cmd_t */
+#include "dvdnav.h"
+#include "dvdnav_events.h"
+
+/* shall we use libdvdnav's read ahead cache? */
+#define DVD_READ_CACHE 1
+
+/* which is the default language for menus/audio/subpictures? */
+#define DVD_LANGUAGE "en"
+
+#ifdef WIN32
+#define S_IRWXG 0
+#endif
+
+int main(int argc, char **argv) {
+ dvdnav_t *dvdnav;
+ uint8_t mem[DVD_VIDEO_LB_LEN];
+ int finished = 0;
+ int output_fd = 0;
+ int dump = 0, tt_dump = 0;
+
+ /* open dvdnav handle */
+ printf("Opening DVD...\n");
+ if (dvdnav_open(&dvdnav, "/dev/dvd") != DVDNAV_STATUS_OK) {
+ printf("Error on dvdnav_open\n");
+ return 1;
+ }
+
+ /* set read ahead cache usage */
+ if (dvdnav_set_readahead_flag(dvdnav, DVD_READ_CACHE) != DVDNAV_STATUS_OK) {
+ printf("Error on dvdnav_set_readahead_flag: %s\n", dvdnav_err_to_string(dvdnav));
+ return 2;
+ }
+
+ /* set the language */
+ if (dvdnav_menu_language_select(dvdnav, DVD_LANGUAGE) != DVDNAV_STATUS_OK ||
+ dvdnav_audio_language_select(dvdnav, DVD_LANGUAGE) != DVDNAV_STATUS_OK ||
+ dvdnav_spu_language_select(dvdnav, DVD_LANGUAGE) != DVDNAV_STATUS_OK) {
+ printf("Error on setting languages: %s\n", dvdnav_err_to_string(dvdnav));
+ return 2;
+ }
+
+ /* set the PGC positioning flag to have position information relatively to the
+ * whole feature instead of just relatively to the current chapter */
+ if (dvdnav_set_PGC_positioning_flag(dvdnav, 1) != DVDNAV_STATUS_OK) {
+ printf("Error on dvdnav_set_PGC_positioning_flag: %s\n", dvdnav_err_to_string(dvdnav));
+ return 2;
+ }
+
+
+ /* the read loop which regularly calls dvdnav_get_next_block
+ * and handles the returned events */
+ printf("Reading...\n");
+ while (!finished) {
+ int result, event, len;
+ uint8_t *buf = mem;
+
+ /* the main reading function */
+#if DVD_READ_CACHE
+ result = dvdnav_get_next_cache_block(dvdnav, &buf, &event, &len);
+#else
+ result = dvdnav_get_next_block(dvdnav, buf, &event, &len);
+#endif
+
+ if (result == DVDNAV_STATUS_ERR) {
+ printf("Error getting next block: %s\n", dvdnav_err_to_string(dvdnav));
+ return 3;
+ }
+
+ switch (event) {
+ case DVDNAV_BLOCK_OK:
+ /* We have received a regular block of the currently playing MPEG stream.
+ * A real player application would now pass this block through demuxing
+ * and decoding. We simply write it to disc here. */
+
+ if (!output_fd) {
+ printf("Opening output...\n");
+ output_fd = open("libdvdnav.mpg", O_CREAT | O_WRONLY, S_IRWXU | S_IRWXG);
+ if (output_fd == -1) {
+ printf("Error opening output\n");
+ return 4;
+ }
+ }
+
+ if (dump || tt_dump)
+ write(output_fd, buf, len);
+
+ break;
+ case DVDNAV_NOP:
+ /* Nothing to do here. */
+ break;
+ case DVDNAV_STILL_FRAME:
+ /* We have reached a still frame. A real player application would wait
+ * the amount of time specified by the still's length while still handling
+ * user input to make menus and other interactive stills work.
+ * A length of 0xff means an indefinite still which has to be skipped
+ * indirectly by some user interaction. */
+ {
+ dvdnav_still_event_t *still_event = (dvdnav_still_event_t *)buf;
+ if (still_event->length < 0xff)
+ printf("Skipping %d seconds of still frame\n", still_event->length);
+ else
+ printf("Skipping indefinite length still frame\n");
+ dvdnav_still_skip(dvdnav);
+ }
+ break;
+ case DVDNAV_WAIT:
+ /* We have reached a point in DVD playback, where timing is critical.
+ * Player application with internal fifos can introduce state
+ * inconsistencies, because libdvdnav is always the fifo's length
+ * ahead in the stream compared to what the application sees.
+ * Such applications should wait until their fifos are empty
+ * when they receive this type of event. */
+ printf("Skipping wait condition\n");
+ dvdnav_wait_skip(dvdnav);
+ break;
+ case DVDNAV_SPU_CLUT_CHANGE:
+ /* Player applications should pass the new colour lookup table to their
+ * SPU decoder */
+ break;
+ case DVDNAV_SPU_STREAM_CHANGE:
+ /* Player applications should inform their SPU decoder to switch channels */
+ break;
+ case DVDNAV_AUDIO_STREAM_CHANGE:
+ /* Player applications should inform their audio decoder to switch channels */
+ break;
+ case DVDNAV_HIGHLIGHT:
+ /* Player applications should inform their overlay engine to highlight the
+ * given button */
+ {
+ dvdnav_highlight_event_t *highlight_event = (dvdnav_highlight_event_t *)buf;
+ printf("Selected button %d\n", highlight_event->buttonN);
+ }
+ break;
+ case DVDNAV_VTS_CHANGE:
+ /* Some status information like video aspect and video scale permissions do
+ * not change inside a VTS. Therefore this event can be used to query such
+ * information only when necessary and update the decoding/displaying
+ * accordingly. */
+ break;
+ case DVDNAV_CELL_CHANGE:
+ /* Some status information like the current Title and Part numbers do not
+ * change inside a cell. Therefore this event can be used to query such
+ * information only when necessary and update the decoding/displaying
+ * accordingly. */
+ {
+ int32_t tt = 0, ptt = 0;
+ uint32_t pos, len;
+ char input = '\0';
+
+ dvdnav_current_title_info(dvdnav, &tt, &ptt);
+ dvdnav_get_position(dvdnav, &pos, &len);
+ printf("Cell change: Title %d, Chapter %d\n", tt, ptt);
+ printf("At position %.0f%% inside the feature\n", 100 * (double)pos / (double)len);
+
+ dump = 0;
+ if (tt_dump && tt != tt_dump)
+ tt_dump = 0;
+
+ if (!dump && !tt_dump) {
+ fflush(stdin);
+ while ((input != 'a') && (input != 's') && (input != 'q') && (input != 't')) {
+ printf("(a)ppend cell to output\n(s)kip cell\nappend until end of (t)itle\n(q)uit\n");
+ scanf("%c", &input);
+ }
+
+ switch (input) {
+ case 'a':
+ dump = 1;
+ break;
+ case 't':
+ tt_dump = tt;
+ break;
+ case 'q':
+ finished = 1;
+ }
+ }
+ }
+ break;
+ case DVDNAV_NAV_PACKET:
+ /* A NAV packet provides PTS discontinuity information, angle linking information and
+ * button definitions for DVD menus. Angles are handled completely inside libdvdnav.
+ * For the menus to work, the NAV packet information has to be passed to the overlay
+ * engine of the player so that it knows the dimensions of the button areas. */
+ {
+ pci_t *pci;
+
+ /* Applications with fifos should not use these functions to retrieve NAV packets,
+ * they should implement their own NAV handling, because the packet you get from these
+ * functions will already be ahead in the stream which can cause state inconsistencies.
+ * Applications with fifos should therefore pass the NAV packet through the fifo
+ * and decoding pipeline just like any other data. */
+ pci = dvdnav_get_current_nav_pci(dvdnav);
+ dvdnav_get_current_nav_dsi(dvdnav);
+
+ if(pci->hli.hl_gi.btn_ns > 0) {
+ int button;
+
+ printf("Found %i DVD menu buttons...\n", pci->hli.hl_gi.btn_ns);
+
+ for (button = 0; button < pci->hli.hl_gi.btn_ns; button++) {
+ btni_t *btni = &(pci->hli.btnit[button]);
+ printf("Button %i top-left @ (%i,%i), bottom-right @ (%i,%i)\n",
+ button + 1, btni->x_start, btni->y_start,
+ btni->x_end, btni->y_end);
+ }
+
+ button = 0;
+ while ((button <= 0) || (button > pci->hli.hl_gi.btn_ns)) {
+ printf("Which button (1 to %i): ", pci->hli.hl_gi.btn_ns);
+ scanf("%i", &button);
+ }
+
+ printf("Selecting button %i...\n", button);
+ /* This is the point where applications with fifos have to hand in a NAV packet
+ * which has traveled through the fifos. See the notes above. */
+ dvdnav_button_select_and_activate(dvdnav, pci, button);
+ }
+ }
+ break;
+ case DVDNAV_HOP_CHANNEL:
+ /* This event is issued whenever a non-seamless operation has been executed.
+ * Applications with fifos should drop the fifos content to speed up responsiveness. */
+ break;
+ case DVDNAV_STOP:
+ /* Playback should end here. */
+ {
+ finished = 1;
+ }
+ break;
+ default:
+ printf("Unknown event (%i)\n", event);
+ finished = 1;
+ break;
+ }
+#if DVD_READ_CACHE
+ dvdnav_free_cache_block(dvdnav, buf);
+#endif
+ }
+
+ /* destroy dvdnav handle */
+ if (dvdnav_close(dvdnav) != DVDNAV_STATUS_OK) {
+ printf("Error on dvdnav_close: %s\n", dvdnav_err_to_string(dvdnav));
+ return 5;
+ }
+ close(output_fd);
+
+ return 0;
+}
diff --git a/lib/libdvd/libdvdnav/m4/Makefile.am b/lib/libdvd/libdvdnav/m4/Makefile.am
new file mode 100644
index 0000000000..fdcb9410e4
--- /dev/null
+++ b/lib/libdvd/libdvdnav/m4/Makefile.am
@@ -0,0 +1,11 @@
+include $(top_srcdir)/misc/Makefile.common
+
+EXTRA_DIST = dvdnav.m4
+
+if INSTALL_M4
+m4datadir = @ACLOCAL_DIR@
+else
+m4datadir = $(datadir)/aclocal
+endif
+
+m4data_DATA = dvdnav.m4
diff --git a/lib/libdvd/libdvdnav/m4/dvdnav.m4 b/lib/libdvd/libdvdnav/m4/dvdnav.m4
new file mode 100644
index 0000000000..aa4a2b0f96
--- /dev/null
+++ b/lib/libdvd/libdvdnav/m4/dvdnav.m4
@@ -0,0 +1,181 @@
+dnl Configure paths for DVDNAV
+dnl
+dnl Copyright (C) 2001 Daniel Caujolle-Bert <segfault@club-internet.fr>
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+dnl
+dnl
+dnl As a special exception to the GNU General Public License, if you
+dnl distribute this file as part of a program that contains a configuration
+dnl script generated by Autoconf, you may include it under the same
+dnl distribution terms that you use for the rest of that program.
+dnl
+
+dnl AM_PATH_DVDNAV([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
+dnl Test for DVDNAV, and define DVDNAV_CFLAGS and DVDNAV_LIBS
+dnl
+AC_DEFUN([AM_PATH_DVDNAV],
+[dnl
+dnl Get the cflags and libraries from the dvdnav-config script
+dnl
+AC_ARG_WITH(dvdnav-prefix,
+ AC_HELP_STRING([--with-dvdnav-prefix=DIR], [prefix where DVDNAV is installed (optional)]),
+ dvdnav_config_prefix="$withval", dvdnav_config_prefix="")
+AC_ARG_WITH(dvdnav-exec-prefix,
+ AC_HELP_STRING([--with-dvdnav-exec-prefix=DIR], [exec prefix where DVDNAV is installed (optional)]),
+ dvdnav_config_exec_prefix="$withval", dvdnav_config_exec_prefix="")
+AC_ARG_ENABLE(dvdnavtest,
+ AC_HELP_STRING([--disable-dvdnavtest], [do not try to compile and run a test DVDNAV program]),
+ enable_dvdnavtest=$enableval, enable_dvdnavtest=yes)
+
+ if test x$dvdnav_config_exec_prefix != x ; then
+ dvdnav_config_args="$dvdnav_config_args --exec-prefix=$dvdnav_config_exec_prefix"
+ if test x${DVDNAV_CONFIG+set} != xset ; then
+ DVDNAV_CONFIG=$dvdnav_config_exec_prefix/bin/dvdnav-config
+ fi
+ fi
+ if test x$dvdnav_config_prefix != x ; then
+ dvdnav_config_args="$dvdnav_config_args --prefix=$dvdnav_config_prefix"
+ if test x${DVDNAV_CONFIG+set} != xset ; then
+ DVDNAV_CONFIG=$dvdnav_config_prefix/bin/dvdnav-config
+ fi
+ fi
+
+ min_dvdnav_version=ifelse([$1], ,0.0.0,$1)
+ if test "x$enable_dvdnavtest" != "xyes" ; then
+ AC_MSG_CHECKING([for DVDNAV-LIB version >= $min_dvdnav_version])
+ else
+ AC_PATH_PROG(DVDNAV_CONFIG, dvdnav-config, no)
+ AC_MSG_CHECKING([for DVDNAV-LIB version >= $min_dvdnav_version])
+ no_dvdnav=""
+ if test "$DVDNAV_CONFIG" = "no" ; then
+ no_dvdnav=yes
+ else
+ DVDNAV_CFLAGS=`$DVDNAV_CONFIG $dvdnav_config_args --cflags`
+ DVDNAV_LIBS=`$DVDNAV_CONFIG $dvdnav_config_args --libs`
+ dvdnav_config_major_version=`$DVDNAV_CONFIG $dvdnav_config_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+ dvdnav_config_minor_version=`$DVDNAV_CONFIG $dvdnav_config_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+ dvdnav_config_sub_version=`$DVDNAV_CONFIG $dvdnav_config_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+ dnl if test "x$enable_dvdnavtest" = "xyes" ; then
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $DVDNAV_CFLAGS"
+ LIBS="$DVDNAV_LIBS $LIBS"
+dnl
+dnl Now check if the installed DVDNAV is sufficiently new. (Also sanity
+dnl checks the results of dvdnav-config to some extent
+dnl
+ AC_LANG_SAVE()
+ AC_LANG_C()
+ rm -f conf.dvdnavtest
+ AC_TRY_RUN([
+#include <dvdnav.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main ()
+{
+ int major, minor, sub;
+ char *tmp_version;
+
+ system ("touch conf.dvdnavtest");
+
+ /* HP/UX 9 (%@#!) writes to sscanf strings */
+ tmp_version = (char *) strdup("$min_dvdnav_version");
+ if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &sub) != 3) {
+ printf("%s, bad version string\n", "$min_dvdnav_version");
+ exit(1);
+ }
+
+ if (($dvdnav_config_major_version > major) ||
+ (($dvdnav_config_major_version == major) && ($dvdnav_config_minor_version > minor)) ||
+ (($dvdnav_config_major_version == major) && ($dvdnav_config_minor_version == minor) && ($dvdnav_config_sub_version >= sub))) {
+ return 0;
+ } else {
+ printf("\n*** An old version of libdvdnav (%d.%d.%d) was found.\n",
+ $dvdnav_config_major_version, $dvdnav_config_minor_version, $dvdnav_config_sub_version);
+ printf("*** You need a version of libdvdnav newer than %d.%d.%d. The latest version of\n",
+ major, minor, sub);
+ printf("*** libdvdnav is always available from:\n");
+ printf("*** http://dvd.sourceforge.net\n");
+ printf("***\n");
+ printf("*** If you have already installed a sufficiently new version, this error\n");
+ printf("*** probably means that the wrong copy of the dvdnav-config shell script is\n");
+ printf("*** being found. The easiest way to fix this is to remove the old version\n");
+ printf("*** of libdvdnav, but you can also set the DVDNAV_CONFIG environment to point to the\n");
+ printf("*** correct copy of dvdnav-config. (In this case, you will have to\n");
+ printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
+ printf("*** so that the correct libraries are found at run-time))\n");
+ }
+ return 1;
+}
+],, no_dvdnav=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ if test "x$no_dvdnav" = x ; then
+ AC_MSG_RESULT(yes)
+ ifelse([$2], , :, [$2])
+ else
+ AC_MSG_RESULT(no)
+ if test "$DVDNAV_CONFIG" = "no" ; then
+ echo "*** The dvdnav-config script installed by DVDNAV could not be found"
+ echo "*** If DVDNAV was installed in PREFIX, make sure PREFIX/bin is in"
+ echo "*** your path, or set the DVDNAV_CONFIG environment variable to the"
+ echo "*** full path to dvdnav-config."
+ else
+ if test -f conf.dvdnavtest ; then
+ :
+ else
+ echo "*** Could not run DVDNAV test program, checking why..."
+ CFLAGS="$CFLAGS $DVDNAV_CFLAGS"
+ LIBS="$LIBS $DVDNAV_LIBS"
+ AC_TRY_LINK([
+#include <dvdnav.h>
+#include <stdio.h>
+], [ return 0; ],
+ [ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding DVDNAV or finding the wrong"
+ echo "*** version of DVDNAV. If it is not finding DVDNAV, you'll need to set your"
+ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+ echo "*** to the installed location Also, make sure you have run ldconfig if that"
+ echo "*** is required on your system"
+ echo "***"
+ echo "*** If you have an old version installed, it is best to remove it, although"
+ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"
+ echo "***"],
+ [ echo "*** The test program failed to compile or link. See the file config.log for the"
+ echo "*** exact error that occured. This usually means DVDNAV was incorrectly installed"
+ echo "*** or that you have moved DVDNAV since it was installed. In the latter case, you"
+ echo "*** may want to edit the dvdnav-config script: $DVDNAV_CONFIG" ])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ DVDNAV_CFLAGS=""
+ DVDNAV_LIBS=""
+ ifelse([$3], , :, [$3])
+ fi
+ AC_SUBST(DVDNAV_CFLAGS)
+ AC_SUBST(DVDNAV_LIBS)
+ AC_LANG_RESTORE()
+ rm -f conf.dvdnavtest
+])
diff --git a/lib/libdvd/libdvdnav/misc/Makefile.am b/lib/libdvd/libdvdnav/misc/Makefile.am
new file mode 100644
index 0000000000..86726307c5
--- /dev/null
+++ b/lib/libdvd/libdvdnav/misc/Makefile.am
@@ -0,0 +1,8 @@
+include $(top_srcdir)/misc/Makefile.common
+
+EXTRA_DIST = dvdnav-config.in libdvdnav.spec.in libdvdnav.spec Makefile.common relchk.sh relchk.sh.in
+
+bin_SCRIPTS = dvdnav-config
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = dvdnav.pc dvdnavmini.pc
diff --git a/lib/libdvd/libdvdnav/misc/Makefile.common b/lib/libdvd/libdvdnav/misc/Makefile.common
new file mode 100644
index 0000000000..6faa23f2c7
--- /dev/null
+++ b/lib/libdvd/libdvdnav/misc/Makefile.common
@@ -0,0 +1,10 @@
+MOSTLYCLEANFILES = *~ \\\#* .*~ .\\\#*
+MAINTAINERCLEANFILES = Makefile.in
+
+debug:
+ @$(MAKE) CFLAGS="$(DEBUG_CFLAGS)"
+
+debug-install: install-debug
+
+install-debug:
+ @$(MAKE) CFLAGS="$(DEBUG_CFLAGS)" install
diff --git a/lib/libdvd/libdvdnav/misc/dvdnav-config.in b/lib/libdvd/libdvdnav/misc/dvdnav-config.in
new file mode 100644
index 0000000000..4e65cc1c65
--- /dev/null
+++ b/lib/libdvd/libdvdnav/misc/dvdnav-config.in
@@ -0,0 +1,88 @@
+#!/bin/sh
+#
+#
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+exec_prefix_set=no
+
+usage()
+{
+ cat <<EOF
+Usage: dvdnav-config [OPTIONS] [LIBRARIES]
+Options:
+ [--prefix[=DIR]]
+ [--exec-prefix[=DIR]]
+ [--version]
+ [--libs]
+ [--minilibs]
+ [--cflags]
+EOF
+ exit $1
+}
+
+if test $# -eq 0; then
+ usage 1 1>&2
+fi
+
+while test $# -gt 0; do
+ case "$1" in
+ -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ case $1 in
+ --prefix=*)
+ prefix=$optarg
+ if test $exec_prefix_set = no ; then
+ exec_prefix=$optarg
+ fi
+ ;;
+ --prefix)
+ echo_prefix=yes
+ ;;
+ --exec-prefix=*)
+ exec_prefix=$optarg
+ exec_prefix_set=yes
+ ;;
+ --exec-prefix)
+ echo_exec_prefix=yes
+ ;;
+ --version)
+ echo @DVDNAV_MAJOR@.@DVDNAV_MINOR@.@DVDNAV_SUB@
+ ;;
+ --cflags)
+ echo_cflags=yes
+ ;;
+ --libs)
+ echo_libs=yes
+ ;;
+ --minilibs)
+ echo_minilibs=yes
+ ;;
+ *)
+ usage 1 1>&2
+ ;;
+ esac
+ shift
+done
+
+if test "$echo_prefix" = "yes"; then
+ echo $prefix
+fi
+
+if test "$echo_exec_prefix" = "yes"; then
+ echo $exec_prefix
+fi
+
+if test "$echo_cflags" = "yes"; then
+ echo -I@includedir@ -I@includedir@/libdvdread @THREAD_CFLAGS@
+fi
+
+if test "$echo_libs" = "yes"; then
+ echo -L@libdir@ -ldvdnav -ldvdread @THREAD_LIBS@
+fi
+
+if test "$echo_minilibs" = "yes"; then
+ echo -L@libdir@ -ldvdnavmini @THREAD_LIBS@
+fi
diff --git a/lib/libdvd/libdvdnav/misc/dvdnav-config2.sh b/lib/libdvd/libdvdnav/misc/dvdnav-config2.sh
new file mode 100644
index 0000000000..c8cdd05391
--- /dev/null
+++ b/lib/libdvd/libdvdnav/misc/dvdnav-config2.sh
@@ -0,0 +1,72 @@
+ extracflags="-DDVDNAV_USES_EXTERNAL_DVDREAD"
+
+usage()
+{
+ cat <<EOF
+Usage: dvdnav-config [OPTIONS] [LIBRARIES]
+Options:
+ [--prefix[=DIR]]
+ [--version]
+ [--libs]
+ [--cflags]
+ [--minilibs]
+ [--minicflags]
+EOF
+ exit $1
+}
+
+if test $# -eq 0; then
+ usage 1 1>&2
+fi
+
+while test $# -gt 0; do
+ case "$1" in
+ -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ case $1 in
+ --prefix)
+ echo_prefix=yes
+ ;;
+ --version)
+ echo $version
+ ;;
+ --cflags)
+ echo_cflags=yes
+ ;;
+ --minicflags)
+ echo_minicflags=yes
+ ;;
+ --libs)
+ echo_libs=yes
+ ;;
+ --minilibs)
+ echo_minilibs=yes
+ ;;
+ *)
+ usage 1 1>&2
+ ;;
+ esac
+ shift
+done
+
+if test "$echo_prefix" = "yes"; then
+ echo $prefix
+fi
+
+if test "$echo_cflags" = "yes"; then
+ echo -I$prefix/include $dvdread_cflags $extracflags $threadcflags
+fi
+
+if test "$echo_minicflags" = "yes"; then
+ echo -I$prefix/include -I$prefix/include/dvdnav $extracflags $threadcflags
+fi
+
+if test "$echo_libs" = "yes"; then
+ echo -L$libdir -ldvdnav $dvdread_libs $threadlib
+fi
+
+if test "$echo_minilibs" = "yes"; then
+ echo -L$libdir -ldvdnavmini $threadlib
+fi
diff --git a/lib/libdvd/libdvdnav/misc/dvdnav.pc.in b/lib/libdvd/libdvdnav/misc/dvdnav.pc.in
new file mode 100644
index 0000000000..7ed56d3752
--- /dev/null
+++ b/lib/libdvd/libdvdnav/misc/dvdnav.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libdvdnav
+Description: DVD Navigation library
+Version: @VERSION@
+
+Requires.private: dvdread >= 4.1.2
+Cflags: -I${includedir} @THREAD_CFLAGS@
+Libs: -L${libdir} -ldvdnav @THREAD_LIBS@
diff --git a/lib/libdvd/libdvdnav/misc/dvdnavmini.pc.in b/lib/libdvd/libdvdnav/misc/dvdnavmini.pc.in
new file mode 100644
index 0000000000..52945b3b93
--- /dev/null
+++ b/lib/libdvd/libdvdnav/misc/dvdnavmini.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libdvdnavmini
+Description: DVD Navigation mini library
+Version: @VERSION@
+
+Cflags: -I${includedir} @DVDREAD_CFLAGS@ @THREAD_CFLAGS@
+Libs: -L${libdir} -ldvdnav @THREAD_LIBS@
diff --git a/lib/libdvd/libdvdnav/misc/libdvdnav.spec.in b/lib/libdvd/libdvdnav/misc/libdvdnav.spec.in
new file mode 100644
index 0000000000..43b2c3932b
--- /dev/null
+++ b/lib/libdvd/libdvdnav/misc/libdvdnav.spec.in
@@ -0,0 +1,50 @@
+%define prefix @prefix@
+%define name @PACKAGE_NAME@
+%define ver @PACKAGE_VERSION@
+%define rel 0
+
+Name: %{name}
+Summary: DVD Navigation library
+Version: %{ver}
+Release: %{rel}
+Group: Development/Libraries
+Copyright: GPL
+Url: http://dvd.sourceforge.net/
+Source: %{name}-%{version}.tar.gz
+Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root
+
+%description
+libdvdnav provides support to applications wishing to make use of advanced
+DVD navigation features.
+
+%prep
+%setup
+
+%build
+CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{prefix}
+make
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install-strip DESTDIR=$RPM_BUILD_ROOT
+
+%clean
+rm -r $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+%doc AUTHORS ChangeLog COPYING INSTALL README
+%{prefix}/bin/dvdnav-config
+%{prefix}/lib/libdvdnav*.la
+%{prefix}/lib/libdvdnav*.so.*
+%{prefix}/lib/libdvdnav*.so
+%{prefix}/include/dvdnav/*
+@INSTALL_M4_TRUE@@ACLOCAL_DIR@/dvdnav.m4
+
+%changelog
+* Sun Mar 18 2002 Daniel Caujolle-Bert <f1rmb@users.sourceforge.net>
+- Add missing files. Fix rpm generation.
+* Tue Mar 12 2002 Rich Wareham <richwareham@users.sourceforge.net>
+- Canabalisation to form libdvdnav spec file.
+* Sun Sep 09 2001 Thomas Vander Stichele <thomas@apestaart.org>
+- first spec file
diff --git a/lib/libdvd/libdvdnav/misc/relchk.sh.in b/lib/libdvd/libdvdnav/misc/relchk.sh.in
new file mode 100755
index 0000000000..8251874692
--- /dev/null
+++ b/lib/libdvd/libdvdnav/misc/relchk.sh.in
@@ -0,0 +1,66 @@
+#!/bin/sh
+##
+## A simple compare directory content utility.
+##
+
+topdir="`pwd`"
+distdir="@PACKAGE_NAME@-@PACKAGE_VERSION@"
+log="$topdir/dist-log"
+logerror="$topdir/dist-errors"
+
+getdir() {
+ if test -r .relignore; then
+ filelist=`ls | grep -Fxvf .relignore`
+ else
+ filelist=`ls`
+ fi
+
+ for file in $filelist; do
+
+ if test -d $file -a $file != "CVS" -a $file != $distdir; then
+ (cd $file && getdir) || (cd ..)
+ else
+ if test ! -d $file -a \
+ $file != $log -a \
+ $file != $logerror -a \
+ $file != "$distdir.tar.gz"; then
+
+ orifile=`pwd`/$file
+
+ distfile=$topdir/$distdir${orifile##*$topdir}
+
+ echo -e "check:\t$orifile\nand\t$distfile" >> $log
+
+ if test ! -e $distfile; then
+ missingfile=${orifile##$topdir}
+ echo "${missingfile#/} is missing in tarball" >> $logerror
+ fi
+
+ fi
+ fi
+
+ done
+}
+
+main() {
+ rm -f $log $logerror
+
+ make config.status && make dist && mv $distdir.tar.gz $distdir.tmp.tar.gz && \
+ cp config.status config.tmp.status && make clean && make distclean && \
+ mv $distdir.tmp.tar.gz $distdir.tar.gz && mv config.tmp.status config.status && \
+ tar -xzf $distdir.tar.gz
+
+ echo "Check is running, be patient..."
+ getdir
+
+ rm -rf $distdir
+ rm -f $distdir.tar.gz
+ ./config.status --recheck
+ ./config.status
+
+ echo " * Log is ${log##*/}"
+ echo " * Error log is ${logerror##*/}"
+
+}
+
+main
diff --git a/lib/libdvd/libdvdnav/msvc/config.h b/lib/libdvd/libdvdnav/msvc/config.h
new file mode 100755
index 0000000000..c6c6f94dc3
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/config.h
@@ -0,0 +1,51 @@
+/* config.h. Generated by hand. */
+
+#define HAVE_DLFCN_H 1
+/* #undef HAVE_DVDCSS_DVDCSS_H*/
+/* #undef HAVE_INTTYPES_H */
+#define HAVE_MEMORY_H 1
+/* #undef HAVE_STDINT_H */
+#define HAVE_STDLIB_H 1
+#define HAVE_STRINGS_H 1
+#define HAVE_STRING_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TYPES_H 1
+/* #undef HAVE_UNISTD_H */
+#define PACKAGE "libdvdread"
+#define PACKAGE_BUGREPORT ""
+#define PACKAGE_NAME ""
+#define PACKAGE_STRING ""
+#define PACKAGE_TARNAME ""
+#define PACKAGE_VERSION ""
+#define STDC_HEADERS 1
+#define VERSION "1.2.6"
+/* #undef WORDS_BIGENDIAN */
+/* #undef __DARWIN__ */
+/* #undef const */
+#define inline __inline
+/* #undef size_t */
+
+#define ssize_t __int64
+
+#ifndef PATH_MAX
+#define PATH_MAX MAX_PATH
+#endif
+
+#define strcasecmp stricmp
+#define strncasecmp strnicmp
+
+#define S_ISDIR(m) ((m) & _S_IFDIR)
+#define S_ISREG(m) ((m) & _S_IFREG)
+#define S_ISBLK(m) 0
+#define S_ISCHR(m) 0
+
+/* Fallback types (very x86-centric, sorry) */
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+typedef unsigned int uint32_t;
+typedef signed int int32_t;
+typedef unsigned __int64 uint64_t;
+typedef signed __int64 int64_t;
+typedef unsigned int uintptr_t;
diff --git a/lib/libdvd/libdvdnav/msvc/contrib/bcopy.c b/lib/libdvd/libdvdnav/msvc/contrib/bcopy.c
new file mode 100755
index 0000000000..21be364aef
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/contrib/bcopy.c
@@ -0,0 +1,8 @@
+#include <string.h>
+
+void bcopy(const void *IN, void *OUT, size_t N);
+
+void bcopy(const void *IN, void *OUT, size_t N)
+{
+ memcpy(OUT, IN, N);
+}
diff --git a/lib/libdvd/libdvdnav/msvc/contrib/dirent/dirent.c b/lib/libdvd/libdvdnav/msvc/contrib/dirent/dirent.c
new file mode 100755
index 0000000000..00289ed57f
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/contrib/dirent/dirent.c
@@ -0,0 +1,135 @@
+/*
+
+ Implementation of POSIX directory browsing functions and types for Win32.
+
+ Kevlin Henney (mailto:kevlin@acm.org), March 1997.
+
+ Copyright Kevlin Henney, 1997. All rights reserved.
+
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose is hereby granted without fee, provided
+ that this copyright and permissions notice appear in all copies and
+ derivatives, and that no charge may be made for the software and its
+ documentation except to cover cost of distribution.
+
+ This software is supplied "as is" without express or implied warranty.
+
+ But that said, if there are any problems please get in touch.
+
+*/
+
+#include <dirent.h>
+#include <errno.h>
+#include <io.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef DIR
+
+struct DIR
+{
+ long handle; /* -1 for failed rewind */
+ struct _finddata_t info;
+ struct dirent result; /* d_name null iff first time */
+ char *name; /* NTBS */
+};
+
+#endif
+
+DIR *opendir(const char *name)
+{
+ DIR *dir = 0;
+
+ if(name && name[0])
+ {
+ size_t base_length = strlen(name);
+ const char *all = /* the root directory is a special case... */
+ strchr("/\\", name[base_length - 1]) ? "*" : "/*";
+
+ if((dir = (DIR *) malloc(sizeof *dir)) != 0 &&
+ (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0)
+ {
+ strcat(strcpy(dir->name, name), all);
+
+ if((dir->handle = _findfirst(dir->name, &dir->info)) != -1)
+ {
+ dir->result.d_name = 0;
+ }
+ else /* rollback */
+ {
+ free(dir->name);
+ free(dir);
+ dir = 0;
+ }
+ }
+ else /* rollback */
+ {
+ free(dir);
+ dir = 0;
+ errno = ENOMEM;
+ }
+ }
+ else
+ {
+ errno = EINVAL;
+ }
+
+ return dir;
+}
+
+int closedir(DIR *dir)
+{
+ int result = -1;
+
+ if(dir)
+ {
+ if(dir->handle != -1)
+ {
+ result = _findclose(dir->handle);
+ }
+
+ free(dir->name);
+ free(dir);
+ }
+
+ if(result == -1) /* map all errors to EBADF */
+ {
+ errno = EBADF;
+ }
+
+ return result;
+}
+
+struct dirent *readdir(DIR *dir)
+{
+ struct dirent *result = 0;
+
+ if(dir && dir->handle != -1)
+ {
+ if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
+ {
+ result = &dir->result;
+ result->d_name = dir->info.name;
+ }
+ }
+ else
+ {
+ errno = EBADF;
+ }
+
+ return result;
+}
+
+void rewinddir(DIR *dir)
+{
+ if(dir && dir->handle != -1)
+ {
+ _findclose(dir->handle);
+ dir->handle = _findfirst(dir->name, &dir->info);
+ dir->result.d_name = 0;
+ }
+ else
+ {
+ errno = EBADF;
+ }
+}
diff --git a/lib/libdvd/libdvdnav/msvc/contrib/dirent/dirent.h b/lib/libdvd/libdvdnav/msvc/contrib/dirent/dirent.h
new file mode 100755
index 0000000000..28a17731ab
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/contrib/dirent/dirent.h
@@ -0,0 +1,32 @@
+/*
+
+ Declaration of POSIX directory browsing functions and types for Win32.
+
+ Kevlin Henney (mailto:kevlin@acm.org), March 1997.
+
+ Copyright Kevlin Henney, 1997. All rights reserved.
+
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose is hereby granted without fee, provided
+ that this copyright and permissions notice appear in all copies and
+ derivatives, and that no charge may be made for the software and its
+ documentation except to cover cost of distribution.
+
+*/
+
+#ifndef DIRENT_INCLUDED
+#define DIRENT_INCLUDED
+
+typedef struct DIR DIR;
+
+struct dirent
+{
+ char *d_name;
+};
+
+DIR *opendir(const char *);
+int closedir(DIR *);
+struct dirent *readdir(DIR *);
+void rewinddir(DIR *);
+
+#endif
diff --git a/lib/libdvd/libdvdnav/msvc/contrib/dlfcn.c b/lib/libdvd/libdvdnav/msvc/contrib/dlfcn.c
new file mode 100755
index 0000000000..3eb996bd13
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/contrib/dlfcn.c
@@ -0,0 +1,97 @@
+/*
+ * $Id: dlfcn.c 1135 2008-09-06 21:55:51Z rathann $
+ * $Name$
+ *
+ * Adopted from Apache DSO code.
+ * Portions copyright Apache Software Foundation
+ *
+ * Structures and types used to implement dlopen, dlsym, etc.
+ * on Windows 95/NT.
+ */
+#include <windows.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "dlfcn.h"
+#include "os_types.h"
+
+void *dlopen(const char *module_name, int mode)
+{
+ UINT em;
+ HINSTANCE dsoh;
+ char path[MAX_PATH], *p;
+ /* Load the module...
+ * per PR2555, the LoadLibraryEx function is very picky about slashes.
+ * Debugging on NT 4 SP 6a reveals First Chance Exception within NTDLL.
+ * LoadLibrary in the MS PSDK also reveals that it -explicitly- states
+ * that backslashes must be used.
+ *
+ * Transpose '\' for '/' in the filename.
+ */
+ (void)strncpy(path, module_name, MAX_PATH);
+ p = path;
+ while (p = strchr(p, '/'))
+ *p = '\\';
+
+ /* First assume the dso/dll's required by -this- dso are sitting in the
+ * same path or can be found in the usual places. Failing that, let's
+ * let that dso look in the apache root.
+ */
+ em = SetErrorMode(SEM_FAILCRITICALERRORS);
+ dsoh = LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (!dsoh)
+ {
+ SetLastError(0); // clear the last error
+ dsoh = LoadLibraryEx(path, NULL, 0);
+ }
+ SetErrorMode(em);
+ SetLastError(0); // clear the last error
+ return (void *)dsoh;
+}
+
+char *dlerror(void)
+{
+ int len, nErrorCode;
+ static char errstr[120];
+ /* This is -not- threadsafe code, but it's about the best we can do.
+ * mostly a potential problem for isapi modules, since LoadModule
+ * errors are handled within a single config thread.
+ */
+
+ if((nErrorCode = GetLastError()) == 0)
+ return((char *)0);
+
+ SetLastError(0); // clear the last error
+ len = snprintf(errstr, sizeof(errstr), "(%d) ", nErrorCode);
+
+ len += FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ nErrorCode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
+ (LPTSTR) errstr + len,
+ sizeof(errstr) - len,
+ NULL
+ );
+ /* FormatMessage may have appended a newline (\r\n). So remove it
+ * and use ": " instead like the Unix errors. The error may also
+ * end with a . before the return - if so, trash it.
+ */
+ if (len > 1 && errstr[len-2] == '\r' && errstr[len-1] == '\n') {
+ if (len > 2 && errstr[len-3] == '.')
+ len--;
+ errstr[len-2] = ':';
+ errstr[len-1] = ' ';
+ }
+ return errstr;
+}
+
+int dlclose(void *handle)
+{
+ return FreeLibrary(handle);
+}
+
+void *dlsym(void *handle, const char *name)
+{
+ return GetProcAddress(handle, name);
+}
diff --git a/lib/libdvd/libdvdnav/msvc/contrib/getopt.c b/lib/libdvd/libdvdnav/msvc/contrib/getopt.c
new file mode 100755
index 0000000000..4b3ce3db40
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/contrib/getopt.c
@@ -0,0 +1,1009 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97
+ Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library. Its master source is NOT part of
+ the C library, however. The master source lives in /gd/gnu/lib.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+ Ditto for AIX 3.2 and <stdlib.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#include <unistd.h>
+#endif /* GNU C library. */
+
+#ifdef VMS
+#include <unixlib.h>
+#if HAVE_STRING_H - 0
+#include <string.h>
+#ifdef STRNCASECMP_IN_STRINGS_H
+# include <strings.h>
+#endif
+#endif
+#endif
+
+#if defined (WIN32) && !defined (__CYGWIN32__) || defined(UNDER_CE)
+/* It's not Unix, really. See? Capital letters. */
+#include <windows.h>
+#define getpid() GetCurrentProcessId()
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.
+ When compiling libc, the _ macro is predefined. */
+#ifdef HAVE_LIBINTL_H
+#include <libintl.h>
+#define _(msgid) gettext (msgid)
+#else
+#define _(msgid) (msgid)
+#endif
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* 1003.2 says this must be 1 before any call. */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+ causes problems with re-calling getopt as programs generally don't
+ know that. */
+
+int __getopt_initialized = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return -1 with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+}
+ordering;
+
+/* Value of POSIXLY_CORRECT environment variable. */
+static char *posixly_correct;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv();
+
+static char *
+ my_index(str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it. */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+ That was relevant to code that was here before. */
+#if !defined (__STDC__) || !__STDC__
+/* gcc with -traditional declares the built-in strlen to return int,
+ and has done so at least since version 2.4.5. -- rms. */
+extern int strlen(const char *);
+
+#endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+ indicating ARGV elements that should not be considered arguments. */
+
+static const char *nonoption_flags;
+static int nonoption_flags_len;
+
+static int original_argc;
+static char *const *original_argv;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+ is valid for the getopt call we must make sure that the ARGV passed
+ to getopt is that one passed to the process. */
+static void store_args(int argc, char *const *argv) __attribute__((unused));
+ static void
+ store_args(int argc, char *const *argv)
+{
+ /* XXX This is no good solution. We should rather copy the args so
+ that we can compare them later. But we must not use malloc(3). */
+ original_argc = argc;
+ original_argv = argv;
+}
+text_set_element(__libc_subinit, store_args);
+#endif
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+#if defined (__STDC__) && __STDC__
+static void exchange(char **);
+
+#endif
+
+static void
+ exchange(argv)
+ char **argv;
+{
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = optind;
+ char *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
+
+ while (top > middle && middle > bottom)
+ {
+ if (top - middle > middle - bottom)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
+
+ /* Swap it with the top part of the top segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[top - (middle - bottom) + i];
+ argv[top - (middle - bottom) + i] = tem;
+ }
+ /* Exclude the moved bottom segment from further swapping. */
+ top -= len;
+ }
+ else
+ {
+ /* Top segment is the short one. */
+ int len = top - middle;
+ register int i;
+
+ /* Swap it with the bottom part of the bottom segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[middle + i];
+ argv[middle + i] = tem;
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made. */
+
+#if defined (__STDC__) && __STDC__
+static const char *_getopt_initialize(int, char *const *, const char *);
+
+#endif
+static const char *
+ _getopt_initialize(argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ /* Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ posixly_correct = getenv("POSIXLY_CORRECT");
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (posixly_correct != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+
+#ifdef _LIBC
+ if (posixly_correct == NULL
+ && argc == original_argc && argv == original_argv)
+ {
+ /* Bash 2.0 puts a special variable in the environment for each
+ command it runs, specifying which ARGV elements are the results of
+ file name wildcard expansion and therefore should not be
+ considered as options. */
+ char var[100];
+
+ sprintf(var, "_%d_GNU_nonoption_argv_flags_", getpid());
+ nonoption_flags = getenv(var);
+ if (nonoption_flags == NULL)
+ nonoption_flags_len = 0;
+ else
+ nonoption_flags_len = strlen(nonoption_flags);
+ }
+ else
+ nonoption_flags_len = 0;
+#endif
+
+ return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns -1.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+ _getopt_internal(argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ optarg = NULL;
+
+ if (!__getopt_initialized || optind == 0)
+ {
+ optstring = _getopt_initialize(argc, argv, optstring);
+ optind = 1; /* Don't scan ARGV[0], the program name. */
+ __getopt_initialized = 1;
+ }
+
+ /* Test whether ARGV[optind] points to a non-option argument.
+ Either it does not have option syntax, or there is an environment flag
+ from the shell indicating it is not an option. The later information
+ is only used when the used in the GNU libc. */
+#ifdef _LIBC
+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \
+ || (optind < nonoption_flags_len \
+ && nonoption_flags[optind] == '1'))
+#else
+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ /* Advance to the next ARGV-element. */
+
+ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+ moved back by the user (who may also have changed the arguments). */
+ if (last_nonopt > optind)
+ last_nonopt = optind;
+ if (first_nonopt > optind)
+ first_nonopt = optind;
+
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc && NONOPTION_P)
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* The special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp(argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return -1;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if (NONOPTION_P)
+ {
+ if (ordering == REQUIRE_ORDER)
+ return -1;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Skip the initial punctuation. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ /* Decode the current option-ARGV-element. */
+
+ /* Check whether the ARGV-element is a long option.
+
+ If long_only and the ARGV-element has the form "-f", where f is
+ a valid short option, don't consider it an abbreviated form of
+ a long option that starts with f. Otherwise there would be no
+ way to give the -f short option.
+
+ On the other hand, if there's a long option "fubar" and
+ the ARGV-element is "-fu", do consider that an abbreviation of
+ the long option, just like "--fu", and not "-f" with arg "u".
+
+ This distinction seems to be the most useful approach. */
+
+ if (longopts != NULL
+ && (argv[optind][1] == '-'
+ || (long_only && (argv[optind][2] || !my_index(optstring, argv[optind][1])))))
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = -1;
+ int option_index;
+
+ for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp(p->name, nextchar, nameend - nextchar))
+ {
+ if ((unsigned int) (nameend - nextchar)
+ == (unsigned int) strlen(p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf(stderr, _("%s: option `%s' is ambiguous\n"),
+ argv[0], argv[optind]);
+ nextchar += strlen(nextchar);
+ optind++;
+ optopt = 0;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (opterr)
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf(stderr,
+ _("%s: option `--%s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf(stderr,
+ _("%s: option `%c%s' doesn't allow an argument\n"),
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+
+ nextchar += strlen(nextchar);
+
+ optopt = pfound->val;
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf(stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[optind - 1]);
+ nextchar += strlen(nextchar);
+ optopt = pfound->val;
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen(nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+ || my_index(optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf(stderr, _("%s: unrecognized option `--%s'\n"),
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf(stderr, _("%s: unrecognized option `%c%s'\n"),
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ optopt = 0;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next short option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index(optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+ if (posixly_correct)
+ /* 1003.2 specifies the format of this message. */
+ fprintf(stderr, _("%s: illegal option -- %c\n"),
+ argv[0], c);
+ else
+ fprintf(stderr, _("%s: invalid option -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ return '?';
+ }
+ /* Convenience. Treat POSIX -W foo same as long option --foo */
+ if (temp[0] == 'W' && temp[1] == ';')
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = 0;
+ int option_index;
+
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf(stderr, _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ return c;
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+
+ /* optarg is now the argument, see if it's in the
+ table of longopts. */
+
+ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp(p->name, nextchar, nameend - nextchar))
+ {
+ if ((unsigned int) (nameend - nextchar) == strlen(p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf(stderr, _("%s: option `-W %s' is ambiguous\n"),
+ argv[0], argv[optind]);
+ nextchar += strlen(nextchar);
+ optind++;
+ return '?';
+ }
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (opterr)
+ fprintf(stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+
+ nextchar += strlen(nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf(stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[optind - 1]);
+ nextchar += strlen(nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen(nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ nextchar = NULL;
+ return 'W'; /* Let the application handle it. */
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = NULL;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf(stderr,
+ _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+ getopt(argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal(argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* Not ELIDE_CODE. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+ main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt(argc, argv, "abc:d:0123456789");
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf("option %c\n", c);
+ break;
+
+ case 'a':
+ printf("option a\n");
+ break;
+
+ case 'b':
+ printf("option b\n");
+ break;
+
+ case 'c':
+ printf("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf("%s ", argv[optind++]);
+ printf("\n");
+ }
+
+ exit(0);
+}
+
+#endif /* TEST */
diff --git a/lib/libdvd/libdvdnav/msvc/contrib/timer/timer.c b/lib/libdvd/libdvdnav/msvc/contrib/timer/timer.c
new file mode 100755
index 0000000000..60efe86db9
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/contrib/timer/timer.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2000-2001 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine 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.
+ *
+ * xine 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
+ *
+ * WIN32 PORT,
+ * by Matthew Grooms <elon@altavista.com>
+ *
+ * timer.c - Missing unix timer functions
+ *
+ */
+
+#include "stdio.h"
+#include "timer.h"
+
+/*
+ this function returns somewhat
+ accurate unix time with the data
+ accurate to the first call to get
+ of day and the resolution accurate
+ to ~ miliseconds.
+*/
+
+static time_t startseconds = 0;
+
+int gettimeofday( struct timeval *tp, struct timezone *tzp )
+{
+ MMTIME mmtime;
+
+ // clock() returns time in miliseconds
+
+ if( !startseconds )
+ startseconds = time( 0 );
+
+ timeGetSystemTime( &mmtime, sizeof( mmtime ) );
+
+ tp->tv_sec = ( mmtime.u.ms / 1000 ) + startseconds;
+ tp->tv_usec = ( mmtime.u.ms % 1000 ) * 1000;
+
+ return 0;
+};
+
+/*
+ These functions are designed to mimick
+ a subset of itimer for use with the
+ alarm signal on win32. This is just
+ enough for xine to work.
+*/
+
+static HANDLE sigalarm = 0;
+
+int setitimer( int which, struct itimerval * value, struct itimerval *ovalue )
+{
+ long int miliseconds;
+
+ if( !sigalarm )
+ sigalarm = CreateEvent( 0, FALSE, TRUE, "SIGALARM" );
+
+ miliseconds = value->it_value.tv_usec / 1000;
+
+ timeSetEvent( miliseconds, 0, ( LPTIMECALLBACK ) sigalarm, 0, TIME_PERIODIC | TIME_CALLBACK_EVENT_PULSE );
+
+ return 0;
+}
+
+/*
+ Wait for sigalarm to wake the thread
+*/
+
+int pause( void )
+{
+ WaitForSingleObject( sigalarm, INFINITE );
+
+ return 0;
+}
+
+int nanosleep( const struct timespec * rqtp, struct timespec * rmtp )
+{
+ Sleep( rqtp->tv_nsec / 1000000 );
+
+ return 0;
+}
+
+unsigned int sleep( unsigned int seconds )
+{
+ Sleep( seconds * 1000 );
+ return 0;
+} \ No newline at end of file
diff --git a/lib/libdvd/libdvdnav/msvc/contrib/timer/timer.h b/lib/libdvd/libdvdnav/msvc/contrib/timer/timer.h
new file mode 100755
index 0000000000..efab6f4e18
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/contrib/timer/timer.h
@@ -0,0 +1,39 @@
+#include <time.h>
+#include <winsock.h>
+#include "pthread.h"
+
+#ifndef _ITIMER_
+#define _ITIMER_
+
+#define ITIMER_REAL 0
+#define ITIMER_VIRTUAL 1
+
+// time reference
+// ----------------------------------
+//
+// 1,000 milliseconds / sec
+// 1,000,000 microseconds / sec
+// 1,000,000,000 nanoseconds / sec
+//
+// timeval.time_sec = seconds
+// timeval.time_usec = microseconds
+
+struct itimerval
+{
+ struct timeval it_interval; /* timer interval */
+ struct timeval it_value; /* current value */
+};
+
+struct timezone {
+ int tz_minuteswest; /* minutes west of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+};
+
+int gettimeofday( struct timeval *tp, struct timezone *tzp );
+int setitimer( int which, struct itimerval * value, struct itimerval *ovalue );
+int pause( void );
+
+unsigned int sleep( unsigned int seconds );
+int nanosleep( const struct timespec *rqtp, struct timespec *rmtp );
+
+#endif \ No newline at end of file
diff --git a/lib/libdvd/libdvdnav/msvc/ifo_dump.dsp b/lib/libdvd/libdvdnav/msvc/ifo_dump.dsp
new file mode 100755
index 0000000000..fc39837296
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/ifo_dump.dsp
@@ -0,0 +1,110 @@
+# Microsoft Developer Studio Project File - Name="ifo_dump" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=ifo_dump - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "ifo_dump.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "ifo_dump.mak" CFG="ifo_dump - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "ifo_dump - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "ifo_dump - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "ifo_dump - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "." /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "ifo_dump - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "ifo_dump___Win32_Debug"
+# PROP BASE Intermediate_Dir "ifo_dump___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug\ifo_dump"
+# PROP Intermediate_Dir "Debug\ifo_dump"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "include" /I "." /I "include/pthreads" /I "install/include" /I ".." /I "../src" /I "contrib/timer" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "DVDNAV_COMPILE" /FR /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/bin/ifo_dump.exe" /pdbtype:sept
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "ifo_dump - Win32 Release"
+# Name "ifo_dump - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\src\ifo_dump.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\ifo_print.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\vmcmd.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/lib/libdvd/libdvdnav/msvc/include/dlfcn.h b/lib/libdvd/libdvdnav/msvc/include/dlfcn.h
new file mode 100755
index 0000000000..7a2416c843
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/include/dlfcn.h
@@ -0,0 +1,23 @@
+#ifndef __DLFCN_H__
+# define __DLFCN_H__
+/*
+ * $Id: dlfcn.h 1135 2008-09-06 21:55:51Z rathann $
+ * $Name$
+ *
+ *
+ */
+extern void *dlopen (const char *file, int mode);
+extern int dlclose (void *handle);
+extern void *dlsym (void * handle, const char * name);
+extern char *dlerror (void);
+
+/* These don't mean anything on windows */
+#define RTLD_NEXT ((void *) -1l)
+#define RTLD_DEFAULT ((void *) 0)
+#define RTLD_LAZY -1
+#define RTLD_NOW -1
+#define RTLD_BINDING_MASK -1
+#define RTLD_NOLOAD -1
+#define RTLD_GLOBAL -1
+
+#endif /* __DLFCN_H__ */
diff --git a/lib/libdvd/libdvdnav/msvc/include/dvdnav_internal.h b/lib/libdvd/libdvdnav/msvc/include/dvdnav_internal.h
new file mode 100644
index 0000000000..cee785472e
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/include/dvdnav_internal.h
@@ -0,0 +1,185 @@
+/* !! DO NO EDIT THIS FILE, it is automatically generated */
+/*
+ * Copyright (C) 2001 Rich Wareham <richwareham@users.sourceforge.net>
+ *
+ * This file is part of libdvdnav, a DVD navigation library.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: dvdnav_internal.h 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+#ifndef DVDNAV_INTERNAL_H_INCLUDED
+#define DVDNAV_INTERNAL_H_INCLUDED
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+#include <pthread.h>
+
+#undef WORDS_BIGENDIAN
+
+#include "dvd_reader.h"
+#include "ifo_read.h"
+#include "ifo_types.h"
+
+/* Uncomment for VM command tracing */
+/* #define TRACE */
+
+#include "decoder.h"
+#include "dvdnav.h"
+#include "vm.h"
+#include "vmcmd.h"
+
+/* where should libdvdnav write its messages (stdout/stderr) */
+#define MSG_OUT stdout
+
+/* Maximum length of an error string */
+#define MAX_ERR_LEN 255
+
+/* Use the POSIX PATH_MAX if available */
+#ifdef PATH_MAX
+#define MAX_PATH_LEN PATH_MAX
+#else
+#define MAX_PATH_LEN 255 /* Arbitrary */
+#endif
+
+#ifndef DVD_VIDEO_LB_LEN
+#define DVD_VIDEO_LB_LEN 2048
+#endif
+
+typedef struct read_cache_s read_cache_t;
+
+/*
+ * These are defined here because they are
+ * not in ifo_types.h, they maybe one day
+ */
+
+#ifndef audio_status_t
+typedef struct {
+#ifdef WORDS_BIGENDIAN
+ unsigned int available : 1;
+ unsigned int zero1 : 4;
+ unsigned int stream_number : 3;
+ uint8_t zero2;
+#else
+ uint8_t zero2;
+ unsigned int stream_number : 3;
+ unsigned int zero1 : 4;
+ unsigned int available : 1;
+#endif
+} ATTRIBUTE_PACKED audio_status_t;
+#endif
+
+#ifndef spu_status_t
+typedef struct {
+#ifdef WORDS_BIGENDIAN
+ unsigned int available : 1;
+ unsigned int zero1 : 2;
+ unsigned int stream_number_4_3 : 5;
+ unsigned int zero2 : 3;
+ unsigned int stream_number_wide : 5;
+ unsigned int zero3 : 3;
+ unsigned int stream_number_letterbox : 5;
+ unsigned int zero4 : 3;
+ unsigned int stream_number_pan_scan : 5;
+#else
+ unsigned int stream_number_pan_scan : 5;
+ unsigned int zero4 : 3;
+ unsigned int stream_number_letterbox : 5;
+ unsigned int zero3 : 3;
+ unsigned int stream_number_wide : 5;
+ unsigned int zero2 : 3;
+ unsigned int stream_number_4_3 : 5;
+ unsigned int zero1 : 2;
+ unsigned int available : 1;
+#endif
+} ATTRIBUTE_PACKED spu_status_t;
+#endif
+
+typedef struct dvdnav_vobu_s {
+ int32_t vobu_start; /* Logical Absolute. MAX needed is 0x300000 */
+ int32_t vobu_length;
+ int32_t blockN; /* Relative offset */
+ int32_t vobu_next; /* Relative offset */
+} dvdnav_vobu_t;
+
+/** The main DVDNAV type **/
+
+struct dvdnav_s {
+ /* General data */
+ char path[MAX_PATH_LEN]; /* Path to DVD device/dir */
+ dvd_file_t *file; /* Currently opened file */
+ int open_vtsN; /* The domain and number of the... */
+ int open_domain; /* ..currently opened VOB */
+
+ /* Position data */
+ vm_position_t position_next;
+ vm_position_t position_current;
+ dvdnav_vobu_t vobu;
+
+ /* NAV data */
+ pci_t pci;
+ dsi_t dsi;
+ uint32_t last_cmd_nav_lbn; /* detects when a command is issued on an already left NAV */
+
+ /* Flags */
+ int skip_still; /* Set when skipping a still */
+ int sync_wait; /* applications should wait till they are in sync with us */
+ int sync_wait_skip; /* Set when skipping wait state */
+ int spu_clut_changed; /* The SPU CLUT changed */
+ int started; /* vm_start has been called? */
+ int use_read_ahead; /* 1 - use read-ahead cache, 0 - don't */
+ int pgc_based; /* positioning works PGC based instead of PG based */
+
+ /* VM */
+ vm_t *vm;
+ pthread_mutex_t vm_lock;
+
+ /* Read-ahead cache */
+ read_cache_t *cache;
+
+ /* Errors */
+ char err_str[MAX_ERR_LEN];
+};
+
+/** USEFUL MACROS **/
+
+#ifdef __GNUC__
+#define printerrf(format, args...) snprintf(this->err_str, MAX_ERR_LEN, format, ## args);
+#else
+#ifdef _MSC_VER
+#define printerrf(str) snprintf(this->err_str, MAX_ERR_LEN, str);
+#else
+#define printerrf(...) snprintf(this->err_str, MAX_ERR_LEN, __VA_ARGS__);
+#endif /* WIN32 */
+#endif
+#define printerr(str) strncpy(this->err_str, str, MAX_ERR_LEN);
+
+/* Save my typing */
+#define S_ERR DVDNAV_STATUS_ERR
+
+#ifndef _MSC_VER
+#define S_OK DVDNAV_STATUS_OK
+#endif /* MSC_VER */
+
+#endif /* DVDNAV_INTERNAL_H_INCLUDED */
diff --git a/lib/libdvd/libdvdnav/msvc/include/getopt.h b/lib/libdvd/libdvdnav/msvc/include/getopt.h
new file mode 100755
index 0000000000..2fa12f7baf
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/include/getopt.h
@@ -0,0 +1,134 @@
+/* Declarations for getopt.
+ Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library. Its master source is NOT part of
+ the C library, however. The master source lives in /gd/gnu/lib.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+ extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+ extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+ extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+ extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+ struct option
+ {
+#if defined (__STDC__) && __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+ };
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if defined (__STDC__) && __STDC__
+#ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+ extern int getopt(int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+ extern int getopt();
+#endif /* __GNU_LIBRARY__ */
+ extern int getopt_long(int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+ extern int getopt_long_only(int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+ extern int _getopt_internal(int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+ extern int getopt();
+ extern int getopt_long();
+ extern int getopt_long_only();
+
+ extern int _getopt_internal();
+#endif /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/lib/libdvd/libdvdnav/msvc/include/inttypes.h b/lib/libdvd/libdvdnav/msvc/include/inttypes.h
new file mode 100755
index 0000000000..55fd6a33e0
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/include/inttypes.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2000-2001 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine 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.
+ *
+ * xine 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
+ *
+ * WIN32 PORT,
+ * by Matthew Grooms <elon@altavista.com>
+ *
+ * inttypes.h - Standard integer definitions.
+ *
+ */
+
+#ifndef _SYS_INTTYPES_H_
+#define _SYS_INTTYPES_H_
+
+#include <config.h>
+
+#endif
diff --git a/lib/libdvd/libdvdnav/msvc/include/os_types.h b/lib/libdvd/libdvdnav/msvc/include/os_types.h
new file mode 100755
index 0000000000..69f05a8d93
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/include/os_types.h
@@ -0,0 +1,27 @@
+#ifndef __OS_TYPES_H__
+#define __OS_TYPES_H__
+/*
+ * $Id: os_types.h 1135 2008-09-06 21:55:51Z rathann $
+ * $Name$
+ *
+ * win32 types
+ * 04 Sept 2001 - Chris Wolf create.
+ */
+
+typedef unsigned char uint_8;
+typedef unsigned short uint_16;
+typedef unsigned int uint_32;
+typedef signed char sint_32;
+typedef signed short sint_16;
+typedef signed int sint_8;
+
+#define snprintf _snprintf
+#define M_PI 3.14159265358979323846 /* pi */
+#define DLLENTRY __declspec(dllexport)
+
+ // Temporarily hardcode this location
+#define AO_PLUGIN_PATH "c:\\Program Files\\Common Files\\Xiphophorus\\ao"
+
+#define SHARED_LIB_EXT ".dll"
+
+#endif /* __OS_TYPES_H__ */
diff --git a/lib/libdvd/libdvdnav/msvc/include/pthreads/pthread.h b/lib/libdvd/libdvdnav/msvc/include/pthreads/pthread.h
new file mode 100755
index 0000000000..7b89ca8401
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/include/pthreads/pthread.h
@@ -0,0 +1,1077 @@
+/* This is the POSIX thread API (POSIX 1003).
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#if !defined( PTHREAD_H )
+#define PTHREAD_H
+
+#ifdef _UWIN
+# define HAVE_STRUCT_TIMESPEC 1
+# define HAVE_SIGNAL_H 1
+# undef HAVE_CONFIG_H
+# pragma comment(lib, "pthread")
+#endif
+
+/*
+ * -------------------------------------------------------------
+ *
+ *
+ * Module: pthread.h
+ *
+ * Purpose:
+ * Provides an implementation of PThreads based upon the
+ * standard:
+ *
+ * POSIX 1003.1c-1995 (POSIX.1c)
+ *
+ * Parts of the implementation also comply with the
+ * Open Group Unix 98 specification in order to enhance
+ * code portability between Windows, various commercial
+ * Unix implementations, and Linux.
+ *
+ * Authors:
+ * There have been many contributors to this library.
+ * The initial implementation was contributed by
+ * John Bossom, and several others have provided major
+ * sections or revisions of parts of the implementation.
+ * Often significant effort has been contributed to
+ * find and fix important bugs and other problems to
+ * improve the reliability of the library, which sometimes
+ * is not reflected in the amount of code which changed as
+ * result.
+ * As much as possible, the contributors are acknowledged
+ * in the ChangeLog file in the source code distribution
+ * where their changes are noted in detail.
+ *
+ * Contributors are listed in the MAINTAINERS file.
+ *
+ * As usual, all bouquets go to the contributors, and all
+ * brickbats go to the project maintainer.
+ *
+ * Maintainer:
+ * The code base for this project is coordinated and
+ * eventually pre-tested, packaged, and made available by
+ *
+ * Ross Johnson <rpj@ise.canberra.edu.au>
+ *
+ * QA Testers:
+ * Ultimately, the library is tested in the real world by
+ * a host of competent and demanding scientists and
+ * engineers who report bugs and/or provide solutions
+ * which are then fixed or incorporated into subsequent
+ * versions of the library. Each time a bug is fixed, a
+ * test case is written to prove the fix and ensure
+ * that later changes to the code don't reintroduce the
+ * same error. The number of test cases is slowly growing
+ * and therefore so is the code reliability.
+ *
+ * Compliance:
+ * See the file ANNOUNCE for the list of implemented
+ * and not-implemented routines and defined options.
+ * Of course, these are all defined is this file as well.
+ *
+ * Web site:
+ * The source code and other information about this library
+ * are available from
+ *
+ * http://sources.redhat.com/pthreads-win32/
+ *
+ * -------------------------------------------------------------
+ */
+
+/*
+ * -----------------
+ * autoconf switches
+ * -----------------
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <windows.h>
+
+#ifndef NEED_FTIME
+#include <time.h>
+#else /* NEED_FTIME */
+/* use native WIN32 time API */
+#endif /* NEED_FTIME */
+
+#if HAVE_SIGNAL_H
+#include <signal.h>
+#endif /* HAVE_SIGNAL_H */
+
+#include <setjmp.h>
+
+#ifndef HAVE_STRUCT_TIMESPEC
+struct timespec {
+ long tv_sec;
+ long tv_nsec;
+};
+#endif /* HAVE_STRUCT_TIMESPEC */
+
+#ifndef SIG_BLOCK
+#define SIG_BLOCK 0
+#endif /* SIG_BLOCK */
+
+#ifndef SIG_UNBLOCK
+#define SIG_UNBLOCK 1
+#endif /* SIG_UNBLOCK */
+
+#ifndef SIG_SETMASK
+#define SIG_SETMASK 2
+#endif /* SIG_SETMASK */
+
+/*
+ * note: ETIMEDOUT is correctly defined in winsock.h
+ */
+#include <winsock.h>
+
+#ifdef NEED_ERRNO
+# include "need_errno.h"
+#else
+# include <errno.h>
+#endif
+
+#include <sched.h>
+
+/*
+ * In case ETIMEDOUT hasn't been defined above somehow.
+ */
+#ifndef ETIMEDOUT
+# define ETIMEDOUT 10060 /* This is the value in winsock.h. */
+#endif
+
+/*
+ * Several systems don't define ENOTSUP. If not, we use
+ * the same value as Solaris.
+ */
+#ifndef ENOTSUP
+# define ENOTSUP 48
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * -------------------------------------------------------------
+ *
+ * POSIX 1003.1c-1995 Options
+ * ===========================
+ *
+ * _POSIX_THREADS (set)
+ * If set, you can use threads
+ *
+ * _POSIX_THREAD_ATTR_STACKSIZE (set)
+ * If set, you can control the size of a thread's
+ * stack
+ * pthread_attr_getstacksize
+ * pthread_attr_setstacksize
+ *
+ * _POSIX_THREAD_ATTR_STACKADDR (not set)
+ * If set, you can allocate and control a thread's
+ * stack. If not supported, the following functions
+ * will return ENOSYS, indicating they are not
+ * supported:
+ * pthread_attr_getstackaddr
+ * pthread_attr_setstackaddr
+ *
+ * _POSIX_THREAD_PRIORITY_SCHEDULING (set)
+ * If set, you can use realtime scheduling.
+ * Indicates the availability of:
+ * pthread_attr_getinheritsched
+ * pthread_attr_getschedparam
+ * pthread_attr_getschedpolicy
+ * pthread_attr_getscope
+ * pthread_attr_setinheritsched
+ * pthread_attr_setschedparam
+ * pthread_attr_setschedpolicy
+ * pthread_attr_setscope
+ * pthread_getschedparam
+ * pthread_setschedparam
+ * sched_get_priority_max
+ * sched_get_priority_min
+ * sched_rr_set_interval
+ *
+ * _POSIX_THREAD_PRIO_INHERIT (not set)
+ * If set, you can create priority inheritance
+ * mutexes.
+ * pthread_mutexattr_getprotocol +
+ * pthread_mutexattr_setprotocol +
+ *
+ * _POSIX_THREAD_PRIO_PROTECT (not set)
+ * If set, you can create priority ceiling mutexes
+ * Indicates the availability of:
+ * pthread_mutex_getprioceiling
+ * pthread_mutex_setprioceiling
+ * pthread_mutexattr_getprioceiling
+ * pthread_mutexattr_getprotocol +
+ * pthread_mutexattr_setprioceiling
+ * pthread_mutexattr_setprotocol +
+ *
+ * _POSIX_THREAD_PROCESS_SHARED (not set)
+ * If set, you can create mutexes and condition
+ * variables that can be shared with another
+ * process.If set, indicates the availability
+ * of:
+ * pthread_mutexattr_getpshared
+ * pthread_mutexattr_setpshared
+ * pthread_condattr_getpshared
+ * pthread_condattr_setpshared
+ *
+ * _POSIX_THREAD_SAFE_FUNCTIONS (set)
+ * If set you can use the special *_r library
+ * functions that provide thread-safe behaviour
+ *
+ * + These functions provide both 'inherit' and/or
+ * 'protect' protocol, based upon these macro
+ * settings.
+ *
+ * POSIX 1003.1c-1995 Limits
+ * ===========================
+ *
+ * PTHREAD_DESTRUCTOR_ITERATIONS
+ * Maximum number of attempts to destroy
+ * a thread's thread-specific data on
+ * termination (must be at least 4)
+ *
+ * PTHREAD_KEYS_MAX
+ * Maximum number of thread-specific data keys
+ * available per process (must be at least 128)
+ *
+ * PTHREAD_STACK_MIN
+ * Minimum supported stack size for a thread
+ *
+ * PTHREAD_THREADS_MAX
+ * Maximum number of threads supported per
+ * process (must be at least 64).
+ *
+ *
+ * POSIX 1003.1j/D10-1999 Options
+ * ==============================
+ *
+ * _POSIX_READER_WRITER_LOCKS (set)
+ * If set, you can use read/write locks
+ *
+ * _POSIX_SPIN_LOCKS (set)
+ * If set, you can use spin locks
+ *
+ * _POSIX_BARRIERS (set)
+ * If set, you can use barriers
+ *
+ * -------------------------------------------------------------
+ */
+
+/*
+ * POSIX Options
+ */
+#ifndef _POSIX_THREADS
+#define _POSIX_THREADS
+#endif
+
+#ifndef _POSIX_READER_WRITER_LOCKS
+#define _POSIX_READER_WRITER_LOCKS
+#endif
+
+#ifndef _POSIX_SPIN_LOCKS
+#define _POSIX_SPIN_LOCKS
+#endif
+
+#ifndef _POSIX_BARRIERS
+#define _POSIX_BARRIERS
+#endif
+
+#define _POSIX_THREAD_SAFE_FUNCTIONS
+#define _POSIX_THREAD_ATTR_STACKSIZE
+#define _POSIX_THREAD_PRIORITY_SCHEDULING
+
+#if defined( KLUDGE )
+/*
+ * The following are not supported
+ */
+#define _POSIX_THREAD_ATTR_STACKADDR
+#define _POSIX_THREAD_PRIO_INHERIT
+#define _POSIX_THREAD_PRIO_PROTECT
+#define _POSIX_THREAD_PROCESS_SHARED
+
+#endif /* KLUDGE */
+
+/*
+ * POSIX Limits
+ *
+ * PTHREAD_DESTRUCTOR_ITERATIONS
+ * Standard states this must be at least
+ * 4.
+ *
+ * PTHREAD_KEYS_MAX
+ * WIN32 permits only 64 TLS keys per process.
+ * This limitation could be worked around by
+ * simply simulating keys.
+ *
+ * PTHREADS_STACK_MIN
+ * POSIX specifies 0 which is also the value WIN32
+ * interprets as allowing the system to
+ * set the size to that of the main thread. The
+ * maximum stack size in Win32 is 1Meg. WIN32
+ * allocates more stack as required up to the 1Meg
+ * limit.
+ *
+ * PTHREAD_THREADS_MAX
+ * Not documented by WIN32. Wrote a test program
+ * that kept creating threads until it failed
+ * revealed this approximate number.
+ *
+ */
+#define PTHREAD_DESTRUCTOR_ITERATIONS 4
+#define PTHREAD_KEYS_MAX 64
+#define PTHREAD_STACK_MIN 0
+#define PTHREAD_THREADS_MAX 2019
+
+
+#ifdef _UWIN
+# include <sys/types.h>
+#else
+typedef struct pthread_t_ *pthread_t;
+typedef struct pthread_attr_t_ *pthread_attr_t;
+typedef struct pthread_once_t_ pthread_once_t;
+typedef struct pthread_key_t_ *pthread_key_t;
+typedef struct pthread_mutex_t_ *pthread_mutex_t;
+typedef struct pthread_mutexattr_t_ *pthread_mutexattr_t;
+typedef struct pthread_cond_t_ *pthread_cond_t;
+typedef struct pthread_condattr_t_ *pthread_condattr_t;
+#endif
+typedef struct pthread_rwlock_t_ *pthread_rwlock_t;
+typedef struct pthread_rwlockattr_t_ *pthread_rwlockattr_t;
+typedef struct pthread_spinlock_t_ *pthread_spinlock_t;
+typedef struct pthread_barrier_t_ *pthread_barrier_t;
+typedef struct pthread_barrierattr_t_ *pthread_barrierattr_t;
+
+/*
+ * ====================
+ * ====================
+ * POSIX Threads
+ * ====================
+ * ====================
+ */
+
+enum {
+/*
+ * pthread_attr_{get,set}detachstate
+ */
+ PTHREAD_CREATE_JOINABLE = 0, /* Default */
+ PTHREAD_CREATE_DETACHED = 1,
+
+/*
+ * pthread_attr_{get,set}inheritsched
+ */
+ PTHREAD_INHERIT_SCHED = 0,
+ PTHREAD_EXPLICIT_SCHED = 1, /* Default */
+
+/*
+ * pthread_{get,set}scope
+ */
+ PTHREAD_SCOPE_PROCESS = 0,
+ PTHREAD_SCOPE_SYSTEM = 1, /* Default */
+
+/*
+ * pthread_setcancelstate paramters
+ */
+ PTHREAD_CANCEL_ENABLE = 0, /* Default */
+ PTHREAD_CANCEL_DISABLE = 1,
+
+/*
+ * pthread_setcanceltype parameters
+ */
+ PTHREAD_CANCEL_ASYNCHRONOUS = 0,
+ PTHREAD_CANCEL_DEFERRED = 1, /* Default */
+
+/*
+ * pthread_mutexattr_{get,set}pshared
+ * pthread_condattr_{get,set}pshared
+ */
+ PTHREAD_PROCESS_PRIVATE = 0,
+ PTHREAD_PROCESS_SHARED = 1,
+
+/*
+ * pthread_barrier_wait
+ */
+ PTHREAD_BARRIER_SERIAL_THREAD = -1
+};
+
+/*
+ * ====================
+ * ====================
+ * Cancelation
+ * ====================
+ * ====================
+ */
+#define PTHREAD_CANCELED ((void *) -1)
+
+
+/*
+ * ====================
+ * ====================
+ * Once Key
+ * ====================
+ * ====================
+ */
+#define PTHREAD_ONCE_INIT { FALSE, -1 }
+
+struct pthread_once_t_
+{
+ int done; /* indicates if user function executed */
+ long started; /* First thread to increment this value */
+ /* to zero executes the user function */
+};
+
+
+/*
+ * ====================
+ * ====================
+ * Object initialisers
+ * ====================
+ * ====================
+ */
+#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) -1)
+
+#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) -1)
+
+#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) -1)
+
+#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t) -1)
+
+enum
+{
+ PTHREAD_MUTEX_FAST_NP,
+ PTHREAD_MUTEX_RECURSIVE_NP,
+ PTHREAD_MUTEX_ERRORCHECK_NP,
+ PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP,
+ PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
+ PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
+ PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
+};
+
+
+/* There are three implementations of cancel cleanup.
+ * Note that pthread.h is included in both application
+ * compilation units and also internally for the library.
+ * The code here and within the library aims to work
+ * for all reasonable combinations of environments.
+ *
+ * The three implementations are:
+ *
+ * WIN32 SEH
+ * C
+ * C++
+ *
+ * Please note that exiting a push/pop block via
+ * "return", "exit", "break", or "continue" will
+ * lead to different behaviour amongst applications
+ * depending upon whether the library was built
+ * using SEH, C++, or C. For example, a library built
+ * with SEH will call the cleanup routine, while both
+ * C++ and C built versions will not.
+ */
+
+/*
+ * define defaults for cleanup code
+ */
+#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C )
+
+#if defined(_MSC_VER)
+#define __CLEANUP_SEH
+#elif defined(__cplusplus)
+#define __CLEANUP_CXX
+#else
+#define __CLEANUP_C
+#endif
+
+#endif
+
+#if defined( __CLEANUP_SEH ) && defined(__GNUC__)
+#error ERROR [__FILE__, line __LINE__]: GNUC does not support SEH.
+#endif
+
+typedef struct ptw32_cleanup_t ptw32_cleanup_t;
+typedef void (__cdecl *ptw32_cleanup_callback_t)(void *);
+
+struct ptw32_cleanup_t
+{
+ ptw32_cleanup_callback_t routine;
+ void *arg;
+ struct ptw32_cleanup_t *prev;
+};
+
+#ifdef __CLEANUP_SEH
+ /*
+ * WIN32 SEH version of cancel cleanup.
+ */
+
+#define pthread_cleanup_push( _rout, _arg ) \
+ { \
+ ptw32_cleanup_t _cleanup; \
+ \
+ _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \
+ _cleanup.arg = (_arg); \
+ __try \
+ { \
+
+#define pthread_cleanup_pop( _execute ) \
+ } \
+ __finally \
+ { \
+ if( _execute || AbnormalTermination()) \
+ { \
+ (*(_cleanup.routine))( _cleanup.arg ); \
+ } \
+ } \
+ }
+
+#else /* __CLEANUP_SEH */
+
+#ifdef __CLEANUP_C
+
+ /*
+ * C implementation of PThreads cancel cleanup
+ */
+
+#define pthread_cleanup_push( _rout, _arg ) \
+ { \
+ ptw32_cleanup_t _cleanup; \
+ \
+ ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \
+
+#define pthread_cleanup_pop( _execute ) \
+ (void) ptw32_pop_cleanup( _execute ); \
+ }
+
+#else /* __CLEANUP_C */
+
+#ifdef __CLEANUP_CXX
+
+ /*
+ * C++ version of cancel cleanup.
+ * - John E. Bossom.
+ */
+
+ class PThreadCleanup {
+ /*
+ * PThreadCleanup
+ *
+ * Purpose
+ * This class is a C++ helper class that is
+ * used to implement pthread_cleanup_push/
+ * pthread_cleanup_pop.
+ * The destructor of this class automatically
+ * pops the pushed cleanup routine regardless
+ * of how the code exits the scope
+ * (i.e. such as by an exception)
+ */
+ ptw32_cleanup_callback_t cleanUpRout;
+ void * obj;
+ int executeIt;
+
+ public:
+ PThreadCleanup() :
+ cleanUpRout( NULL ),
+ obj( NULL ),
+ executeIt( 0 )
+ /*
+ * No cleanup performed
+ */
+ {
+ }
+
+ PThreadCleanup(
+ ptw32_cleanup_callback_t routine,
+ void * arg ) :
+ cleanUpRout( routine ),
+ obj( arg ),
+ executeIt( 1 )
+ /*
+ * Registers a cleanup routine for 'arg'
+ */
+ {
+ }
+
+ ~PThreadCleanup()
+ {
+ if ( executeIt && ((void *) cleanUpRout != NULL) )
+ {
+ (void) (*cleanUpRout)( obj );
+ }
+ }
+
+ void execute( int exec )
+ {
+ executeIt = exec;
+ }
+ };
+
+ /*
+ * C++ implementation of PThreads cancel cleanup;
+ * This implementation takes advantage of a helper
+ * class who's destructor automatically calls the
+ * cleanup routine if we exit our scope weirdly
+ */
+#define pthread_cleanup_push( _rout, _arg ) \
+ { \
+ PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \
+ (void *) (_arg) );
+
+#define pthread_cleanup_pop( _execute ) \
+ cleanup.execute( _execute ); \
+ }
+
+#else
+
+#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined.
+
+#endif /* __CLEANUP_CXX */
+
+#endif /* __CLEANUP_C */
+
+#endif /* __CLEANUP_SEH */
+
+/*
+ * ===============
+ * ===============
+ * Methods
+ * ===============
+ * ===============
+ */
+
+/*
+ * PThread Attribute Functions
+ */
+int pthread_attr_init (pthread_attr_t * attr);
+
+int pthread_attr_destroy (pthread_attr_t * attr);
+
+int pthread_attr_getdetachstate (const pthread_attr_t * attr,
+ int *detachstate);
+
+int pthread_attr_getstackaddr (const pthread_attr_t * attr,
+ void **stackaddr);
+
+int pthread_attr_getstacksize (const pthread_attr_t * attr,
+ size_t * stacksize);
+
+int pthread_attr_setdetachstate (pthread_attr_t * attr,
+ int detachstate);
+
+int pthread_attr_setstackaddr (pthread_attr_t * attr,
+ void *stackaddr);
+
+int pthread_attr_setstacksize (pthread_attr_t * attr,
+ size_t stacksize);
+
+int pthread_attr_getschedparam (const pthread_attr_t *attr,
+ struct sched_param *param);
+
+int pthread_attr_setschedparam (pthread_attr_t *attr,
+ const struct sched_param *param);
+
+int pthread_attr_setschedpolicy (pthread_attr_t *,
+ int);
+
+int pthread_attr_getschedpolicy (pthread_attr_t *,
+ int *);
+
+int pthread_attr_setinheritsched(pthread_attr_t * attr,
+ int inheritsched);
+
+int pthread_attr_getinheritsched(pthread_attr_t * attr,
+ int * inheritsched);
+
+int pthread_attr_setscope (pthread_attr_t *,
+ int);
+
+int pthread_attr_getscope (const pthread_attr_t *,
+ int *);
+
+/*
+ * PThread Functions
+ */
+int pthread_create (pthread_t * tid,
+ const pthread_attr_t * attr,
+ void *(*start) (void *),
+ void *arg);
+
+int pthread_detach (pthread_t tid);
+
+int pthread_equal (pthread_t t1,
+ pthread_t t2);
+
+void pthread_exit (void *value_ptr);
+
+int pthread_join (pthread_t thread,
+ void **value_ptr);
+
+pthread_t pthread_self (void);
+
+int pthread_cancel (pthread_t thread);
+
+int pthread_setcancelstate (int state,
+ int *oldstate);
+
+int pthread_setcanceltype (int type,
+ int *oldtype);
+
+void pthread_testcancel (void);
+
+int pthread_once (pthread_once_t * once_control,
+ void (*init_routine) (void));
+
+ptw32_cleanup_t *ptw32_pop_cleanup (int execute);
+
+void ptw32_push_cleanup (ptw32_cleanup_t * cleanup,
+ void (*routine) (void *),
+ void *arg);
+
+/*
+ * Thread Specific Data Functions
+ */
+int pthread_key_create (pthread_key_t * key,
+ void (*destructor) (void *));
+
+int pthread_key_delete (pthread_key_t key);
+
+int pthread_setspecific (pthread_key_t key,
+ const void *value);
+
+void *pthread_getspecific (pthread_key_t key);
+
+
+/*
+ * Mutex Attribute Functions
+ */
+int pthread_mutexattr_init (pthread_mutexattr_t * attr);
+
+int pthread_mutexattr_destroy (pthread_mutexattr_t * attr);
+
+int pthread_mutexattr_getpshared (const pthread_mutexattr_t
+ * attr,
+ int *pshared);
+
+int pthread_mutexattr_setpshared (pthread_mutexattr_t * attr,
+ int pshared);
+
+int pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind);
+int pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind);
+
+/*
+ * Barrier Attribute Functions
+ */
+int pthread_barrierattr_init (pthread_barrierattr_t * attr);
+
+int pthread_barrierattr_destroy (pthread_barrierattr_t * attr);
+
+int pthread_barrierattr_getpshared (const pthread_barrierattr_t
+ * attr,
+ int *pshared);
+
+int pthread_barrierattr_setpshared (pthread_barrierattr_t * attr,
+ int pshared);
+
+/*
+ * Mutex Functions
+ */
+int pthread_mutex_init (pthread_mutex_t * mutex,
+ const pthread_mutexattr_t * attr);
+
+int pthread_mutex_destroy (pthread_mutex_t * mutex);
+
+int pthread_mutex_lock (pthread_mutex_t * mutex);
+
+int pthread_mutex_trylock (pthread_mutex_t * mutex);
+
+int pthread_mutex_unlock (pthread_mutex_t * mutex);
+
+/*
+ * Spinlock Functions
+ */
+int pthread_spin_init (pthread_spinlock_t * lock, int pshared);
+
+int pthread_spin_destroy (pthread_spinlock_t * lock);
+
+int pthread_spin_lock (pthread_spinlock_t * lock);
+
+int pthread_spin_trylock (pthread_spinlock_t * lock);
+
+int pthread_spin_unlock (pthread_spinlock_t * lock);
+
+/*
+ * Barrier Functions
+ */
+int pthread_barrier_init (pthread_barrier_t * barrier,
+ const pthread_barrierattr_t * attr,
+ unsigned int count);
+
+int pthread_barrier_destroy (pthread_barrier_t * barrier);
+
+int pthread_barrier_wait (pthread_barrier_t * barrier);
+
+/*
+ * Condition Variable Attribute Functions
+ */
+int pthread_condattr_init (pthread_condattr_t * attr);
+
+int pthread_condattr_destroy (pthread_condattr_t * attr);
+
+int pthread_condattr_getpshared (const pthread_condattr_t * attr,
+ int *pshared);
+
+int pthread_condattr_setpshared (pthread_condattr_t * attr,
+ int pshared);
+
+/*
+ * Condition Variable Functions
+ */
+int pthread_cond_init (pthread_cond_t * cond,
+ const pthread_condattr_t * attr);
+
+int pthread_cond_destroy (pthread_cond_t * cond);
+
+int pthread_cond_wait (pthread_cond_t * cond,
+ pthread_mutex_t * mutex);
+
+int pthread_cond_timedwait (pthread_cond_t * cond,
+ pthread_mutex_t * mutex,
+ const struct timespec *abstime);
+
+int pthread_cond_signal (pthread_cond_t * cond);
+
+int pthread_cond_broadcast (pthread_cond_t * cond);
+
+/*
+ * Scheduling
+ */
+int pthread_setschedparam (pthread_t thread,
+ int policy,
+ const struct sched_param *param);
+
+int pthread_getschedparam (pthread_t thread,
+ int *policy,
+ struct sched_param *param);
+
+int pthread_setconcurrency (int);
+
+int pthread_getconcurrency (void);
+
+/*
+ * Read-Write Lock Functions
+ */
+int pthread_rwlock_init(pthread_rwlock_t *lock,
+ const pthread_rwlockattr_t *attr);
+
+int pthread_rwlock_destroy(pthread_rwlock_t *lock);
+
+int pthread_rwlock_tryrdlock(pthread_rwlock_t *);
+
+int pthread_rwlock_trywrlock(pthread_rwlock_t *);
+
+int pthread_rwlock_rdlock(pthread_rwlock_t *lock);
+
+int pthread_rwlock_wrlock(pthread_rwlock_t *lock);
+
+int pthread_rwlock_unlock(pthread_rwlock_t *lock);
+
+
+/*
+ * Non-portable functions
+ */
+
+/*
+ * Compatibility with Linux.
+ */
+int pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, int kind);
+int pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, int *kind);
+
+/*
+ * Possibly supported by other POSIX threads implementations
+ */
+int pthread_delay_np (struct timespec * interval);
+
+/*
+ * Returns the Win32 HANDLE for the POSIX thread.
+ */
+HANDLE pthread_getw32threadhandle_np(pthread_t thread);
+
+/*
+ * Returns the number of CPUs available to the process.
+ */
+int pthread_getprocessors_np(int * count);
+
+/*
+ * Useful if an application wants to statically link
+ * the lib rather than load the DLL at run-time.
+ */
+int pthread_win32_process_attach_np(void);
+int pthread_win32_process_detach_np(void);
+int pthread_win32_thread_attach_np(void);
+int pthread_win32_thread_detach_np(void);
+
+
+/*
+ * Protected Methods
+ *
+ * This function blocks until the given WIN32 handle
+ * is signaled or pthread_cancel had been called.
+ * This function allows the caller to hook into the
+ * PThreads cancel mechanism. It is implemented using
+ *
+ * WaitForMultipleObjects
+ *
+ * on 'waitHandle' and a manually reset WIN32 Event
+ * used to implement pthread_cancel. The 'timeout'
+ * argument to TimedWait is simply passed to
+ * WaitForMultipleObjects.
+ */
+int pthreadCancelableWait (HANDLE waitHandle);
+int pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout);
+
+/*
+ * Thread-Safe C Runtime Library Mappings.
+ */
+#ifndef _UWIN
+#if 1
+#if (! defined(HAVE_ERRNO)) && (! defined(_REENTRANT)) && (! defined(_MT))
+int * _errno( void );
+#endif
+#else
+#if (! defined(NEED_ERRNO)) || (! defined( _REENTRANT ) && (! defined( _MT ) || ! defined( _MD )))
+#if defined(PTW32_BUILD)
+__declspec( dllexport ) int * _errno( void );
+#else
+int * _errno( void );
+#endif
+#endif
+#endif
+#endif
+
+/*
+ * WIN32 C runtime library had been made thread-safe
+ * without affecting the user interface. Provide
+ * mappings from the UNIX thread-safe versions to
+ * the standard C runtime library calls.
+ * Only provide function mappings for functions that
+ * actually exist on WIN32.
+ */
+
+#if !defined(__MINGW32__)
+#define strtok_r( _s, _sep, _lasts ) \
+ ( *(_lasts) = strtok( (_s), (_sep) ) )
+#endif /* !__MINGW32__ */
+
+#define asctime_r( _tm, _buf ) \
+ ( strcpy( (_buf), asctime( (_tm) ) ), \
+ (_buf) )
+
+#define ctime_r( _clock, _buf ) \
+ ( strcpy( (_buf), ctime( (_clock) ) ), \
+ (_buf) )
+
+#define gmtime_r( _clock, _result ) \
+ ( *(_result) = *gmtime( (_clock) ), \
+ (_result) )
+
+#define localtime_r( _clock, _result ) \
+ ( *(_result) = *localtime( (_clock) ), \
+ (_result) )
+
+#define rand_r( _seed ) \
+ ( _seed == _seed? rand() : rand() )
+
+
+#ifdef __cplusplus
+
+/*
+ * Internal exceptions
+ */
+class ptw32_exception {};
+class ptw32_exception_cancel : public ptw32_exception {};
+class ptw32_exception_exit : public ptw32_exception {};
+
+#endif
+
+/* FIXME: This is only required if the library was built using SEH */
+/*
+ * Get internal SEH tag
+ */
+DWORD ptw32_get_exception_services_code(void);
+
+#ifndef PTW32_BUILD
+
+#ifdef __CLEANUP_SEH
+
+/*
+ * Redefine the SEH __except keyword to ensure that applications
+ * propagate our internal exceptions up to the library's internal handlers.
+ */
+#define __except( E ) \
+ __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \
+ ? EXCEPTION_CONTINUE_SEARCH : ( E ) )
+
+#endif /* __CLEANUP_SEH */
+
+#ifdef __cplusplus
+
+/*
+ * Redefine the C++ catch keyword to ensure that applications
+ * propagate our internal exceptions up to the library's internal handlers.
+ */
+#ifdef _MSC_VER
+ /*
+ * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll'
+ * if you want Pthread-Win32 cancelation and pthread_exit to work.
+ */
+
+#ifndef PtW32NoCatchWarn
+
+#pragma message("When compiling applications with MSVC++ and C++ exception handling:")
+#pragma message(" Replace any 'catch( ... )' with 'PtW32CatchAll' in POSIX threads")
+#pragma message(" if you want POSIX thread cancelation and pthread_exit to work.")
+
+#endif
+
+#define PtW32CatchAll \
+ catch( ptw32_exception & ) { throw; } \
+ catch( ... )
+
+#else /* _MSC_VER */
+
+#define catch( E ) \
+ catch( ptw32_exception & ) { throw; } \
+ catch( E )
+
+#endif /* _MSC_VER */
+
+#endif /* __cplusplus */
+
+#endif /* ! PTW32_BUILD */
+
+#ifdef __cplusplus
+} /* End of extern "C" */
+#endif /* __cplusplus */
+
+#endif /* PTHREAD_H */
diff --git a/lib/libdvd/libdvdnav/msvc/include/pthreads/sched.h b/lib/libdvd/libdvdnav/msvc/include/pthreads/sched.h
new file mode 100755
index 0000000000..ab277920e0
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/include/pthreads/sched.h
@@ -0,0 +1,89 @@
+/*
+ * Module: sched.h
+ *
+ * Purpose:
+ * Provides an implementation of POSIX realtime extensions
+ * as defined in
+ *
+ * POSIX 1003.1b-1993 (POSIX.1b)
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+#ifndef _SCHED_H
+#define _SCHED_H
+
+#if defined(__MINGW32__) || defined(_UWIN)
+/* For pid_t */
+# include <sys/types.h>
+/* Required by Unix 98 */
+# include <time.h>
+#else
+typedef int pid_t;
+#endif
+
+/* Thread scheduling policies */
+
+enum {
+ SCHED_OTHER = 0,
+ SCHED_FIFO,
+ SCHED_RR,
+ SCHED_MIN = SCHED_OTHER,
+ SCHED_MAX = SCHED_RR
+};
+
+struct sched_param {
+ int sched_priority;
+};
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+int sched_yield (void);
+
+int sched_get_priority_min (int policy);
+
+int sched_get_priority_max (int policy);
+
+int sched_setscheduler (pid_t pid, int policy);
+
+int sched_getscheduler (pid_t pid);
+
+/*
+ * Note that this macro returns ENOTSUP rather than
+ * ENOSYS as might be expected. However, returning ENOSYS
+ * should mean that sched_get_priority_{min,max} are
+ * not implemented as well as sched_rr_get_interval.
+ * This is not the case, since we just don't support
+ * round-robin scheduling. Therefore I have chosen to
+ * return the same value as sched_setscheduler when
+ * SCHED_RR is passed to it.
+ */
+#define sched_rr_get_interval(_pid, _interval) \
+ ( errno = ENOTSUP, (int) -1 )
+
+
+#ifdef __cplusplus
+} /* End of extern "C" */
+#endif /* __cplusplus */
+
+
+#endif /* !_SCHED_H */
+
diff --git a/lib/libdvd/libdvdnav/msvc/include/sys/time.h b/lib/libdvd/libdvdnav/msvc/include/sys/time.h
new file mode 100755
index 0000000000..f874fa655f
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/include/sys/time.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2000-2001 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine 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.
+ *
+ * xine 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
+ *
+ * WIN32 PORT,
+ * by Matthew Grooms <elon@altavista.com>
+ *
+ * sys/time.h - There is no seperate sys/time.h for win32 so we simply
+ * include the standard time header as well as our xine
+ * timer functions.
+ */
+
+#include <time.h>
diff --git a/lib/libdvd/libdvdnav/msvc/include/timer.h b/lib/libdvd/libdvdnav/msvc/include/timer.h
new file mode 100755
index 0000000000..efab6f4e18
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/include/timer.h
@@ -0,0 +1,39 @@
+#include <time.h>
+#include <winsock.h>
+#include "pthread.h"
+
+#ifndef _ITIMER_
+#define _ITIMER_
+
+#define ITIMER_REAL 0
+#define ITIMER_VIRTUAL 1
+
+// time reference
+// ----------------------------------
+//
+// 1,000 milliseconds / sec
+// 1,000,000 microseconds / sec
+// 1,000,000,000 nanoseconds / sec
+//
+// timeval.time_sec = seconds
+// timeval.time_usec = microseconds
+
+struct itimerval
+{
+ struct timeval it_interval; /* timer interval */
+ struct timeval it_value; /* current value */
+};
+
+struct timezone {
+ int tz_minuteswest; /* minutes west of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+};
+
+int gettimeofday( struct timeval *tp, struct timezone *tzp );
+int setitimer( int which, struct itimerval * value, struct itimerval *ovalue );
+int pause( void );
+
+unsigned int sleep( unsigned int seconds );
+int nanosleep( const struct timespec *rqtp, struct timespec *rmtp );
+
+#endif \ No newline at end of file
diff --git a/lib/libdvd/libdvdnav/msvc/include/unistd.h b/lib/libdvd/libdvdnav/msvc/include/unistd.h
new file mode 100755
index 0000000000..7e4c63f3a5
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/include/unistd.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2000-2001 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine 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.
+ *
+ * xine 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
+ *
+ * WIN32 PORT,
+ * by Matthew Grooms <elon@altavista.com>
+ *
+ * unistd.h - This is mostly a catch all header that maps standard unix
+ * libc calls to the equivelent win32 functions.
+ *
+ */
+
+#include <windows.h>
+#include <malloc.h>
+#include <errno.h>
+#include <direct.h>
+
+#include <config.h>
+
+#ifndef _SYS_UNISTD_H_
+#define _SYS_UNISTD_H_
+
+#define inline __inline
+
+#define mkdir( A, B ) _mkdir( A )
+#define lstat stat
+
+#ifndef S_ISDIR
+#define S_ISDIR(A) ( S_IFDIR & A )
+#endif
+
+#define S_IXUSR S_IEXEC
+#define S_IXGRP S_IEXEC
+#define S_IXOTH S_IEXEC
+
+#define M_PI 3.14159265358979323846 /* pi */
+
+#define bzero( A, B ) memset( A, 0, B )
+
+#ifndef strcasecmp
+#define strcasecmp _stricmp
+#endif
+
+#ifndef strncasecmp
+#define strncasecmp _strnicmp
+#endif
+
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+
+// FIXME : I dont remember why this is here
+#define readlink
+
+#endif
diff --git a/lib/libdvd/libdvdnav/msvc/install/README b/lib/libdvd/libdvdnav/msvc/install/README
new file mode 100755
index 0000000000..5e6ba4ae9f
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/install/README
@@ -0,0 +1,7 @@
+MSVC Help
+---------
+
+In order to build using any application that requires libdvdnav using MSVC the
+following directories (lib and include) must be copied to the msvc directory of
+the particular application.
+
diff --git a/lib/libdvd/libdvdnav/msvc/libdvdcss.def b/lib/libdvd/libdvdnav/msvc/libdvdcss.def
new file mode 100755
index 0000000000..0a6e2fd997
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/libdvdcss.def
@@ -0,0 +1,12 @@
+;------------------------------------------------------------
+; LIBDVDCSS DLL DEFINITIONS FILE
+
+EXPORTS
+
+dvdcss_interface_2
+dvdcss_open
+dvdcss_error
+dvdcss_seek
+dvdcss_read
+dvdcss_close
+dvdcss_title \ No newline at end of file
diff --git a/lib/libdvd/libdvdnav/msvc/libdvdcss.dsp b/lib/libdvd/libdvdnav/msvc/libdvdcss.dsp
new file mode 100755
index 0000000000..bb91b6a3eb
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/libdvdcss.dsp
@@ -0,0 +1,139 @@
+# Microsoft Developer Studio Project File - Name="libdvdcss" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=libdvdcss - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libdvdcss.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libdvdcss.mak" CFG="libdvdcss - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libdvdcss - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "libdvdcss - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libdvdcss - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_USRDLL" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "." /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_USRDLL" /D PATH_MAX=2048 /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 /machine:IX86
+# ADD LINK32 /machine:IX86
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Desc=Create libdvdcss Install
+PostBuild_Cmds=scripts\libdvdcss_intstall.bat Release
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "libdvdcss - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_USRDLL" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "." /I "../libdvdcss/dvdcss" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_USRDLL" /D MAX_PATH=2048 /YX /FD /GZ ./ "../libdvdcss" /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 /machine:IX86
+# ADD LINK32 /dll /machine:IX86 /out:"Debug/bin/libdvdcss.dll"
+# SUBTRACT LINK32 /pdb:none
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Desc=Create libdvdcss Install
+PostBuild_Cmds=scripts\libdvdcss_intstall.bat Debug
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "libdvdcss - Win32 Release"
+# Name "libdvdcss - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\libdvdcss\css.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\libdvdcss\device.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\libdvdcss\error.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\libdvdcss\ioctl.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\libdvdcss\libdvdcss.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "DLL Defs"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\libdvdcss.def
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/lib/libdvd/libdvdnav/msvc/libdvdnav.def b/lib/libdvd/libdvdnav/msvc/libdvdnav.def
new file mode 100755
index 0000000000..7f633d18d2
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/libdvdnav.def
@@ -0,0 +1,82 @@
+;------------------------------------------------------------
+; LIBDVDNAV DLL DEFINITIONS FILE
+
+EXPORTS
+
+DVDOpen
+DVDClose
+DVDOpenFile
+DVDCloseFile
+DVDReadBlocks
+
+navRead_DSI
+navRead_PCI
+
+ifoClose
+ifoRead_VOBU_ADMAP
+ifoRead_VTS_ATRT
+ifoRead_PTL_MAIT
+ifoRead_PGCI_UT
+ifoRead_TT_SRPT
+ifoRead_FP_PGC
+ifoOpenVMGI
+ifoRead_TITLE_VOBU_ADMAP
+ifoRead_PGCIT
+ifoRead_VTS_PTT_SRPT
+ifoOpenVTSI
+ifoPrint
+
+dvdnav_set_readahead_flag
+dvdnav_set_region_mask
+dvdnav_spu_language_select
+dvdnav_audio_language_select
+dvdnav_menu_language_select
+dvdnav_get_angle_info
+dvdnav_current_title_info
+dvdnav_title_play
+dvdnav_part_play
+dvdnav_get_number_of_titles
+dvdnav_get_title_string
+dvdnav_open
+dvdnav_close
+dvdnav_wait_skip
+dvdnav_get_video_scale_permission
+dvdnav_get_video_aspect
+dvdnav_still_skip
+dvdnav_err_to_string
+dvdnav_get_next_cache_block
+dvdnav_free_cache_block
+dvdnav_get_position
+dvdnav_sector_search
+dvdnav_get_current_highlight
+dvdnav_button_select_and_activate
+dvdnav_right_button_select
+dvdnav_left_button_select
+dvdnav_lower_button_select
+dvdnav_upper_button_select
+dvdnav_mouse_select
+dvdnav_button_select
+dvdnav_mouse_activate
+dvdnav_button_activate
+dvdnav_angle_change
+dvdnav_prev_pg_search
+dvdnav_next_pg_search
+dvdnav_menu_call
+dvdnav_spu_stream_to_lang
+dvdnav_get_spu_logical_stream
+dvdnav_audio_stream_to_lang
+dvdnav_get_audio_logical_stream
+dvdnav_is_domain_vts
+
+dvdnav_set_PGC_positioning_flag
+dvdnav_get_number_of_parts
+dvdnav_reset
+
+;------------------------------------------------------------
+; timer exports
+
+gettimeofday
+setitimer
+pause
+sleep
+nanosleep
diff --git a/lib/libdvd/libdvdnav/msvc/libdvdnav.dsp b/lib/libdvd/libdvdnav/msvc/libdvdnav.dsp
new file mode 100755
index 0000000000..c1dd747df1
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/libdvdnav.dsp
@@ -0,0 +1,156 @@
+# Microsoft Developer Studio Project File - Name="libdvdnav" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=libdvdnav - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libdvdnav.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libdvdnav.mak" CFG="libdvdnav - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libdvdnav - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "libdvdnav - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libdvdnav - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+LINK32=link.exe
+# ADD BASE LINK32 /machine:IX86
+# ADD LINK32 /machine:IX86
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "..\..\libdvdcss\src" /I "." /I "include" /I "contrib/dirent" /I "include/pthreads" /I "../../libdvdcss" /I ".." /I "../src" /I "../src/vm" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "DVDNAV_COMPILE" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"Release\libdvdnav\libdvdnav.lib"
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Desc=Create libdvdnav Install Files
+PostBuild_Cmds=scripts\libdvdnav_install.bat Release
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "libdvdnav - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+LINK32=link.exe
+# ADD BASE LINK32 /machine:IX86
+# ADD LINK32 /debug /machine:IX86 /out:"Debug/libdvdnav.lib" /implib:"Debug/libdvdnav.lib"
+# SUBTRACT LINK32 /pdb:none /nodefaultlib
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "include" /I "contrib/dirent" /I "include/pthreads" /I "../../libdvdcss" /I "../src" /I "." /I ".." /I "../src/vm" /D "WIN32" /D "_DEBUG" /D "_LIB" /D "DVDNAV_COMPILE" /D "HAVE_CONFIG_H" /FR"Debug/libdvdnav/" /Fp"Debug/libdvdnav/libdvdnav.pch" /YX /Fo"Debug/libdvdnav/" /Fd"Debug/libdvdnav/" /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 libwin32utils.lib /nologo /out:"Debug\libdvdnav\libdvdnav.lib"
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Desc=Create libdvdnav Install Files
+PostBuild_Cmds=scripts\libdvdnav_install.bat Debug
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "libdvdnav - Win32 Release"
+# Name "libdvdnav - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\src\vm\decoder.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\dvdnav.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\highlight.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\navigation.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\read_cache.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\remap.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\searching.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\settings.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\vm\vm.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\vm\vmcmd.c
+# End Source File
+# End Group
+# Begin Group "DLL Defs"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\libdvdnav.def
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/lib/libdvd/libdvdnav/msvc/libdvdnav.dsw b/lib/libdvd/libdvdnav/msvc/libdvdnav.dsw
new file mode 100755
index 0000000000..8974efbee6
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/libdvdnav.dsw
@@ -0,0 +1,101 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "ifo_dump"=.\ifo_dump.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libdvdnav
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "libdvdcss"=.\libdvdcss.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libdvdnav"=.\libdvdnav.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libwin32utils
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "libwin32utils"=.\libwin32utils.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "play_title"=.\play_title.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libdvdnav
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "title_info"=.\title_info.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libdvdnav
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lib/libdvd/libdvdnav/msvc/libwin32utils.def b/lib/libdvd/libdvdnav/msvc/libwin32utils.def
new file mode 100755
index 0000000000..1277cc8b7b
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/libwin32utils.def
@@ -0,0 +1,229 @@
+;------------------------------------------------------------
+; LIBWIN32UTILS DLL DEFINITIONS FILE
+
+EXPORTS
+
+;------------------------------------------------------------
+; dirent exports
+
+opendir
+closedir
+readdir
+rewinddir
+
+;------------------------------------------------------------
+; pthread exports
+
+;pthread_atfork
+pthread_attr_destroy
+pthread_attr_getdetachstate
+pthread_attr_getinheritsched
+pthread_attr_getschedparam
+pthread_attr_getschedpolicy
+pthread_attr_getscope
+pthread_attr_getstackaddr
+pthread_attr_getstacksize
+pthread_attr_init
+pthread_attr_setdetachstate
+pthread_attr_setinheritsched
+pthread_attr_setschedparam
+pthread_attr_setschedpolicy
+pthread_attr_setscope
+pthread_attr_setstackaddr
+pthread_attr_setstacksize
+pthread_cancel
+;
+; These two are implemented as macros in pthread.h
+;
+;pthread_cleanup_pop
+;pthread_cleanup_push
+;
+pthread_condattr_destroy
+pthread_condattr_getpshared
+pthread_condattr_init
+pthread_condattr_setpshared
+pthread_cond_broadcast
+pthread_cond_destroy
+pthread_cond_init
+pthread_cond_signal
+pthread_cond_timedwait
+pthread_cond_wait
+pthread_create
+pthread_detach
+pthread_equal
+pthread_exit
+pthread_getconcurrency
+pthread_getschedparam
+pthread_getspecific
+pthread_join
+pthread_key_create
+pthread_key_delete
+;pthread_kill
+pthread_mutexattr_destroy
+;pthread_mutexattr_getprioceiling
+;pthread_mutexattr_getprotocol
+pthread_mutexattr_getpshared
+pthread_mutexattr_gettype
+pthread_mutexattr_init
+;pthread_mutexattr_setprioceiling
+;pthread_mutexattr_setprotocol
+pthread_mutexattr_setpshared
+pthread_mutexattr_settype
+pthread_mutexattr_destroy
+pthread_mutex_init
+pthread_mutex_destroy
+pthread_mutex_lock
+pthread_mutex_trylock
+pthread_mutex_unlock
+pthread_once
+pthread_self
+pthread_setcancelstate
+pthread_setcanceltype
+pthread_setconcurrency
+pthread_setschedparam
+pthread_setspecific
+;pthread_sigmask
+pthread_testcancel
+;
+; POSIX 1.b
+;
+sched_get_priority_min
+sched_get_priority_max
+sched_getscheduler
+sched_setscheduler
+sched_yield
+sem_init
+sem_destroy
+sem_trywait
+sem_wait
+sem_post
+sem_open
+sem_close
+sem_unlink
+sem_getvalue
+;
+; This next one is a macro
+;sched_rr_get_interval
+;
+;
+; Read/Write Locks
+;
+pthread_rwlock_init
+pthread_rwlock_destroy
+pthread_rwlock_tryrdlock
+pthread_rwlock_trywrlock
+pthread_rwlock_rdlock
+pthread_rwlock_wrlock
+pthread_rwlock_unlock
+;
+; Spin locks
+;
+pthread_spin_init
+pthread_spin_destroy
+pthread_spin_lock
+pthread_spin_unlock
+pthread_spin_trylock
+;
+; Barriers
+;
+pthread_barrier_init
+pthread_barrier_destroy
+pthread_barrier_wait
+pthread_barrierattr_init
+pthread_barrierattr_destroy
+pthread_barrierattr_getpshared
+pthread_barrierattr_setpshared
+;
+; Non-portable/compatibility with other implementations
+;
+pthread_delay_np
+pthread_mutexattr_getkind_np
+pthread_mutexattr_setkind_np
+;
+; Non-portable local implementation only
+;
+pthread_getw32threadhandle_np
+pthread_getprocessors_np
+pthreadCancelableWait
+pthreadCancelableTimedWait
+;
+; For use when linking statically
+;
+pthread_win32_process_attach_np
+pthread_win32_process_detach_np
+pthread_win32_thread_attach_np
+pthread_win32_thread_detach_np
+;
+; Needed if !defined(_MSC_VER) && !defined(__cplusplus)
+;
+ptw32_push_cleanup
+ptw32_pop_cleanup
+;
+; Not for use directly. Needed by macros in pthread.h
+; to return internal SEH code.
+;
+ptw32_get_exception_services_code
+
+;------------------------------------------------------------
+; timer exports
+
+adler32
+compress
+crc32
+deflate
+deflateCopy
+deflateEnd
+deflateInit2_
+deflateInit_
+deflateParams
+deflateReset
+deflateSetDictionary
+gzclose
+gzdopen
+gzerror
+gzflush
+gzopen
+gzread
+gzwrite
+inflate
+inflateEnd
+inflateInit2_
+inflateInit_
+inflateReset
+inflateSetDictionary
+inflateSync
+uncompress
+zlibVersion
+gzprintf
+gzputc
+gzgetc
+gzseek
+gzrewind
+gztell
+gzeof
+gzsetparams
+zError
+inflateSyncPoint
+get_crc_table
+compress2
+gzputs
+gzgets
+
+;------------------------------------------------------------
+; timer exports
+
+gettimeofday
+setitimer
+pause
+sleep
+nanosleep
+
+;------------------------------------------------------------
+; other exports
+bcopy
+dlclose
+dlsym
+dlopen
+dlerror
+
+optind \ No newline at end of file
diff --git a/lib/libdvd/libdvdnav/msvc/libwin32utils.dsp b/lib/libdvd/libdvdnav/msvc/libwin32utils.dsp
new file mode 100755
index 0000000000..f94af8f493
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/libwin32utils.dsp
@@ -0,0 +1,136 @@
+# Microsoft Developer Studio Project File - Name="libwin32utils" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=libwin32utils - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libwin32utils.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libwin32utils.mak" CFG="libwin32utils - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libwin32utils - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "libwin32utils - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libwin32utils - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release/libwin32utils"
+# PROP Intermediate_Dir "Release/libwin32utils"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /machine:I386
+# ADD LINK32 winmm.lib /nologo /machine:I386 /out:"Release/libwin32utils.lib"
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_LIB" /D "LIBWIN32UTILS_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "include" /I "contrib/dirent" /I "include/pthreads" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_LIB" /D "LIBWIN32UTILS_EXPORTS" /D "__CLEANUP_C" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD LIB32 /out:"libwin32utils.lib"
+
+!ELSEIF "$(CFG)" == "libwin32utils - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug/libwin32utils"
+# PROP Intermediate_Dir "Debug/libwin32utils"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 winmm.lib /nologo /debug /machine:I386 /out:"Debug/libwin32utils.lib" /pdbtype:sept
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_LIB" /D "LIBWIN32UTILS_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "include/pthreads" /I "include" /I "contrib/dirent" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_LIB" /D "LIBWIN32UTILS_EXPORTS" /D "__CLEANUP_C" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD LIB32 winmm.lib /out:"libwin32utils.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "libwin32utils - Win32 Release"
+# Name "libwin32utils - Win32 Debug"
+# Begin Group "Source Files ( dirent )"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\contrib\dirent\dirent.c
+# End Source File
+# End Group
+# Begin Group "Source Files ( timer )"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\contrib\timer\timer.c
+# End Source File
+# End Group
+# Begin Group "DLL Defs"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\libwin32utils.def
+# End Source File
+# End Group
+# Begin Group "Source Files ( other )"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\contrib\bcopy.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\contrib\dlfcn.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\contrib\getopt.c
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/lib/libdvd/libdvdnav/msvc/play_title.dsp b/lib/libdvd/libdvdnav/msvc/play_title.dsp
new file mode 100755
index 0000000000..8a3efdf587
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/play_title.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="play_title" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=play_title - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "play_title.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "play_title.mak" CFG="play_title - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "play_title - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "play_title - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "play_title - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "." /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "play_title - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "play_title___Win32_Debug"
+# PROP BASE Intermediate_Dir "play_title___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug\play_title"
+# PROP Intermediate_Dir "Debug\play_title"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "include" /I "contrib/dirent" /I "../../libdvdcss" /I "install/include" /I "." /I ".." /I "../src" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/bin/play_title.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "play_title - Win32 Release"
+# Name "play_title - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\src\play_title.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/lib/libdvd/libdvdnav/msvc/scripts/libdvdcss_install.bat b/lib/libdvd/libdvdnav/msvc/scripts/libdvdcss_install.bat
new file mode 100755
index 0000000000..84712b122b
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/scripts/libdvdcss_install.bat
@@ -0,0 +1,8 @@
+
+ECHO mkdir dll ...
+rmdir /s install\dll
+mkdir install\dll
+
+ECHO libvdvcss dll ...
+xcopy /Y %1\bin\libdvdcss.dll install\dll
+
diff --git a/lib/libdvd/libdvdnav/msvc/scripts/libdvdnav_install.bat b/lib/libdvd/libdvdnav/msvc/scripts/libdvdnav_install.bat
new file mode 100755
index 0000000000..f49f2f2294
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/scripts/libdvdnav_install.bat
@@ -0,0 +1,21 @@
+
+ECHO mkdir install ...
+rmdir /s install\include
+rmdir /s install\lib
+mkdir install\include\dvdnav
+mkdir install\lib
+
+ECHO includes ...
+xcopy /Y ..\src\dvdnav.h install\include\dvdnav
+xcopy /Y ..\src\dvdnav_events.h install\include\dvdnav
+xcopy /Y ..\src\dvd_types.h install\include\dvdnav
+xcopy /Y ..\src\dvdread\dvd_reader.h install\include\dvdnav
+xcopy /Y ..\src\dvdread\nav_read.h install\include\dvdnav
+xcopy /Y ..\src\dvdread\ifo_read.h install\include\dvdnav
+xcopy /Y ..\src\dvdread\nav_print.h install\include\dvdnav
+xcopy /Y ..\src\dvdread\ifo_print.h install\include\dvdnav
+xcopy /Y ..\src\dvdread\ifo_types.h install\include\dvdnav
+xcopy /Y ..\src\dvdread\nav_types.h install\include\dvdnav
+
+ECHO lib ...
+xcopy /Y %1\libdvdnav\libdvdnav.lib install\lib
diff --git a/lib/libdvd/libdvdnav/msvc/title_info.dsp b/lib/libdvd/libdvdnav/msvc/title_info.dsp
new file mode 100755
index 0000000000..39d3768d56
--- /dev/null
+++ b/lib/libdvd/libdvdnav/msvc/title_info.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="title_info" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=title_info - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "title_info.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "title_info.mak" CFG="title_info - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "title_info - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "title_info - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "title_info - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "." /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "title_info - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "title_info___Win32_Debug"
+# PROP BASE Intermediate_Dir "title_info___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "title_info___Win32_Debug"
+# PROP Intermediate_Dir "title_info___Win32_Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "include" /I "contrib/dirent" /I "../../libdvdcss" /I "install/include" /I "." /I ".." /I "../src" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"Debug/title_info/title_info.pch" /YX /Fo"Debug/title_info/" /Fd"Debug/title_info/" /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/bin/title_info.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "title_info - Win32 Release"
+# Name "title_info - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\src\title_info.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/lib/libdvd/libdvdnav/src/FELLOWSHIP.map b/lib/libdvd/libdvdnav/src/FELLOWSHIP.map
new file mode 100644
index 0000000000..2d0a3f03cf
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/FELLOWSHIP.map
@@ -0,0 +1,163 @@
+# The Lord of the Rings: Fellowship of the Ring (Widescreen Theatrical Release)
+domain 8, title 1, program 1, start 0x0000, end 0x1f0a # Introduction
+
+# history of middle earth
+#domain 2, title 1, program 1, start 0x9cba, end 0xcea4 # violence/war
+#domain 2, title 1, program 1, start 0xf018, end 0x1272c # violence/war
+domain 2, title 1, program 1, start 0x11ff3, end 0x1272c # gore
+#domain 2, title 1, program 1, start 0x173f1, end 0x185d6 # violence/death
+
+# hobbiton
+domain 2, title 1, program 2, start 0x30373, end 0x31946 # vices/smoking
+domain 2, title 1, program 2, start 0x32942, end 0x34426 # vices/smoking
+domain 2, title 1, program 2, start 0x34895, end 0x34ad1 # vices/smoking
+domain 2, title 1, program 2, start 0x3965c, end 0x39d7c # vices/smoking
+
+# bag end
+domain 2, title 1, program 3, start 0x40288, end 0x412de # vices/drinking/talk
+domain 2, title 1, program 3, start 0x4cfbe, end 0x4f955 # vices/smoking
+
+# party
+domain 2, title 1, program 4, start 0x53ee0, end 0x54396 # vices/drinking
+domain 2, title 1, program 4, start 0x58851, end 0x5ae3d # imitative/theft
+domain 2, title 1, program 4, start 0x5cd0a, end 0x5e216 # jump
+
+# gandalf departs
+domain 2, title 1, program 6, start 0x7f05d, end 0x7f1b3 # jump
+domain 2, title 1, program 6, start 0x7f51a, end 0x834a7 # vices/smoking
+
+# research
+domain 2, title 1, program 7, start 0x8e6e8, end 0x8e9d7 # vices/smoking
+
+# hobbiton
+domain 2, title 1, program 8, start 0x98f49, end 0x990ba # jump
+domain 2, title 1, program 8, start 0xa0ad1, end 0xa17ac # jump
+domain 2, title 1, program 8, start 0xa9e32, end 0xaaa70 # violence/torture
+domain 2, title 1, program 8, start 0xabc6c, end 0xabd92 # violence
+
+# orthanc
+domain 2, title 1, program 9, start 0xd50b7, end 0xd87f9 # violence
+domain 2, title 1, program 9, start 0xd8e49, end 0xda611 # violence
+
+# farmer maggot
+domain 2, title 1, program 10, start 0xde856, end 0xdeb07 # jump
+domain 2, title 1, program 10, start 0xe4cfe, end 0xe50b3 # gore/excrement
+domain 2, title 1, program 10, start 0xebba3, end 0xebf93 # gore/blood
+domain 2, title 1, program 10, start 0xed222, end 0xeda7e # gore/insects
+
+# buckleberry ferry
+domain 2, title 1, program 11, start 0xf6d77, end 0xf83f8 # jump
+
+# prancing pony in bree
+domain 2, title 1, program 12, start 0x10945e, end 0x10a2f2 # vices/drinking/rolemodel
+domain 2, title 1, program 12, start 0x10c103, end 0x10c417 # vices/smoking
+domain 2, title 1, program 12, start 0x10c934, end 0x10cb44 # vices/smoking
+# 10c934
+# 10c9b4
+# 10ca3c
+# 10cad6
+# 10cb44
+# 10cbb4
+domain 2, title 1, program 12, start 0x10ddab, end 0x10e0f2 # vices/smoking
+domain 2, title 1, program 12, start 0x10e1df, end 0x10e411 # vices/drinking
+
+# ring wraiths in bree
+domain 2, title 1, program 13, start 0x117853, end 0x117f6e # violence
+domain 2, title 1, program 13, start 0x117853, end 0x117f6e # gore/crushing
+domain 2, title 1, program 13, start 0x11b2b3, end 0x11bffc # violence
+
+# weathertop
+#domain 2, title 1, program 15, start 0x13b85b, end 0x141b38 # violence
+domain 2, title 1, program 15, start 0x14093a, end 0x141063 # gore/stabbing
+domain 2, title 1, program 15, start 0x142555, end 0x1466e9 # violence
+
+# isengard
+domain 2, title 1, program 16, start 0x152a28, end 0x1549fb # violence
+domain 2, title 1, program 16, start 0x152a28, end 0x1549fb # gore
+
+# the ford
+domain 2, title 1, program 17, start 0x173dbe, end 0x1748a6 # violence
+
+# rivendell
+domain 2, title 1, program 18, start 0x179793, end 0x17a667 # vices/smoking
+domain 2, title 1, program 18, start 0x17c452, end 0x17eab6 # violence
+
+# rivendell
+domain 2, title 1, program 20, start 0x19caaf, end 0x19db12 # violence
+
+# tomb of isildur
+domain 2, title 1, program 21, start 0x1a69ae, end 0x1a6a3d # gore/blood
+
+# rivendell
+domain 2, title 1, program 22, start 0x1b298b, end 0x1b2bae # kiss
+
+# rivendell
+domain 2, title 1, program 24, start 0x1d8253, end 0x1d8f5d # horror/posession
+
+# on the road south
+domain 2, title 1, program 25, start 0x1e2fc2, end 0x1e31b8 # vices/smoking
+
+# at the entrance to moria
+domain 2, title 1, program 27, start 0x214bdd, end 0x214fcc # gore/skeletons
+domain 2, title 1, program 27, start 0x2157d9, end 0x216731 # gore/skeletons
+domain 2, title 1, program 27, start 0x217ba6, end 0x21cdb4 # violence
+
+# moria
+#domain 2, title 1, program 28, start 0x22173d, end 0x221e58 # gore/skeletons
+#domain 2, title 1, program 28, start 0x222e0b, end 0x223345 # gore/skeletons
+domain 2, title 1, program 28, start 0x22173d, end 0x223345 # gore/skeletons
+domain 2, title 1, program 28, start 0x2239e2, end 0x223e8c # gore/skeletons
+domain 2, title 1, program 28, start 0x22589f, end 0x2259bf # vices/smoking
+
+# balin's tomb
+domain 2, title 1, program 29, start 0x234abb, end 0x234dd0 # gore/skeletons
+domain 2, title 1, program 29, start 0x2352ed, end 0x2361d7 # gore/skeletons
+domain 2, title 1, program 29, start 0x23898b, end 0x23955c # gore/skeletons
+domain 2, title 1, program 29, start 0x23b467, end 0x23db2b # gore/skeletons
+#domain 2, title 1, program 29, start 0x247360, end 0x25e24b # violence
+domain 2, title 1, program 29, start 0x2483b6, end 0x248b62 # gore/impalement
+domain 2, title 1, program 29, start 0x24a606, end 0x24a9f3 # gore/headshot
+domain 2, title 1, program 29, start 0x24acd8, end 0x24ae7e # gore/decapitation
+domain 2, title 1, program 29, start 0x24d708, end 0x24d88f # gore/bashing
+domain 2, title 1, program 29, start 0x25013a, end 0x250501 # gore/impalement
+domain 2, title 1, program 29, start 0x2540a0, end 0x254507 # jump
+domain 2, title 1, program 29, start 0x2560b3, end 0x256423 # gore/impalement
+domain 2, title 1, program 29, start 0x258152, end 0x258459 # gore/impalement
+domain 2, title 1, program 29, start 0x258152, end 0x258459 # gore/impalement
+
+# the bridge
+#domain 2, title 1, program 30, start 0x274235, end 0x275e59 # violence
+domain 2, title 1, program 30, start 0x2744c6, end 0x274a5e # gore/headshot
+domain 2, title 1, program 30, start 0x275661, end 0x275e59 # violence/death
+domain 2, title 1, program 30, start 0x289d2a, end 0x28a066 # gore/falling
+
+# lothlorien
+domain 2, title 1, program 32, start 0x2be304, end 0x2beb1d # violence
+domain 2, title 1, program 32, start 0x2c5d59, end 0x2c9a40 # horror/posession
+#domain 2, title 1, program 32, start 0x2c5d59, end 0x2c9e41 # horror/posession
+
+# parth galen
+domain 2, title 1, program 36, start 0x2fa317, end 0x2fb0b0 # violence
+
+# parth galen w/ orcs
+domain 2, title 1, program 37, start 0x30c8cb, end 0x313054 # violence
+domain 2, title 1, program 37, start 0x310428, end 0x313054 # gore/impalement
+#domain 2, title 1, program 37, start 0x317f45, end 0x332a52 # violence
+domain 2, title 1, program 37, start 0x322d8b, end 0x328f4d # gore/impalement
+domain 2, title 1, program 37, start 0x32f2a4, end 0x330731 # gore/impalement
+domain 2, title 1, program 37, start 0x330b3b, end 0x330c4d # gore/blood
+domain 2, title 1, program 37, start 0x331c4e, end 0x332a52 # gore/dismemberment
+domain 2, title 1, program 37, start 0x331c4e, end 0x332a52 # gore/decapitation
+
+# death of boromir
+domain 2, title 1, program 38, start 0x33322f, end 0x33c10c # gore/bodies
+domain 2, title 1, program 38, start 0x33b558, end 0x33c10c # horror/death
+
+# to the eastern shore
+domain 2, title 1, program 39, start 0x34a25b, end 0x34c1e3 # horror/drowning
+
+
+
+
+
+
diff --git a/lib/libdvd/libdvdnav/src/Makefile.am b/lib/libdvd/libdvdnav/src/Makefile.am
new file mode 100644
index 0000000000..c39b2e7bec
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/Makefile.am
@@ -0,0 +1,34 @@
+include $(top_srcdir)/misc/Makefile.common
+
+SUBDIRS = vm
+
+includedir = ${prefix}/include/dvdnav
+
+AM_CPPFLAGS = -DDVDNAV_COMPILE $(THREAD_CFLAGS) $(DVDREAD_CFLAGS) \
+ -I$(top_srcdir)/src/vm
+
+EXTRA_DIST = README.MAP FELLOWSHIP.map
+
+lib_LTLIBRARIES = libdvdnav.la libdvdnavmini.la
+
+libdvdnav_la_SOURCES = dvdnav.c \
+ read_cache.c navigation.c highlight.c \
+ searching.c settings.c remap.c \
+ dvdnav_internal.h read_cache.h remap.h
+
+libdvdnav_la_LIBADD = $(THREAD_LIBS) $(DVDREAD_LIBS) \
+ $(top_builddir)/src/vm/libdvdvm.la
+
+libdvdnav_la_LDFLAGS = \
+ -version-info $(DVDNAV_LT_CURRENT):$(DVDNAV_LT_REVISION):$(DVDNAV_LT_AGE) \
+ -export-symbols-regex "(^dvdnav.*|^nav.*|^ifo.*|^DVD.*)"
+# -release $(DVDNAV_MAJOR).$(DVDNAV_MINOR).$(DVDNAV_SUB)
+
+libdvdnavmini_la_SOURCES = $(libdvdnav_la_SOURCES)
+
+libdvdnavmini_la_LIBADD = $(THREAD_LIBS) \
+ $(top_builddir)/src/vm/libdvdvm.la
+
+libdvdnavmini_la_LDFLAGS = $(libdvdnav_la_LDFLAGS)
+
+include_HEADERS = dvdnav.h dvdnav_events.h dvd_types.h
diff --git a/lib/libdvd/libdvdnav/src/README.MAP b/lib/libdvd/libdvdnav/src/README.MAP
new file mode 100644
index 0000000000..2181a03d65
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/README.MAP
@@ -0,0 +1,105 @@
+Contents
+
+WHAT ARE MAP FILES
+HOWTO
+FINDING MAP FILES
+WHOM TO BLAME
+
+WHAT ARE MAP FILES
+==================
+
+Map files are an experimental feature that lets you customize the way
+you watch DVDs. If you are opposed to violence, are sickened by gore,
+or would rather your two year old didn't ask you just yet why that
+woman in the movie was naked, you might want to create a map file.
+
+Map files identify sections of the movie that will be skipped during
+playback. You can skip any section you like with the only restriction
+(right now) that the movie player must play at least the last VOBU
+(about a fifth of a second) of each chapter in the movie in order
+to detect chapter changes correctly.
+
+Included with this patch is an example map file that describes most
+of the potentially objectionable content in the new "The Lord of the
+Rings" DVD. I've added a comment after each block that identifies
+what content it contains so that you can customize the file to your
+preferences. The map file looks something like this:
+
+ # The Lord of the Rings: Fellowship of the Ring
+ # (Widescreen Theatrical Release)
+ debug
+ domain 8, title 1, program 1, start 0x0000, end 0x1f0a # Introduction
+
+ # history of middle earth
+ #domain 2, title 1, program 1, start 0x9cba, end 0xcea4 # violence/war
+ #domain 2, title 1, program 1, start 0xf018, end 0x1272c # violence/war
+ domain 2, title 1, program 1, start 0x11ff3, end 0x1272c # gore
+ #domain 2, title 1, program 1, start 0x173f1, end 0x185d6 # violence/death
+
+Place the map file in your .xine directory to enable the selected
+cuts as follows:
+
+ cp FELLOWSHIP.map ~/.xine
+
+The debug command tells the map code that you would like to see the
+VOBU numbers as the movie is playing. Comment out this line to hide
+this output. The remaining lines are all either comments or blocks.
+Each block has a start and an end, and whenever Xine tries to load
+a VOBU between the start and end, it will be redirected to the end
+block instead.
+
+
+HOWTO
+=====
+
+To create your own map files you would create a new map file using the
+title of the disk as the filename, and add the debug line to it. The
+map file should be placed in your '.xine' directory and have a '.map'
+extension added. For example "The Lord Of The Rings" map must be stored
+in the file ~/.xine/FELLOWSHIP.map
+
+After you create the file with the DEBUG line you will see output that
+looks like this in window where you started Xine:
+
+ FELLOWSHIP: domain 8, title 1, program 1, start 2205, next 22a8
+ FELLOWSHIP: domain 8, title 1, program 1, start 22a8, next 234b
+ FELLOWSHIP: domain 8, title 1, program 1, start 234b, next 23eb
+ FELLOWSHIP: domain 8, title 1, program 1, start 23eb, next 248a
+
+Each line represents one VOBU, and the start and end addresses match
+the start and end addresses that you should place in the map file
+if you want to skip that block. If you want to skip multiple blocks
+you would just add one line with the start address of the first block
+to skip, and the end address of the last block to skip. For example
+to skip these four blocks you would add the following line to your
+map file:
+
+ domain 8, title 1, program 1, start 0x2205, end 0x248a # 4 blocks
+
+Xine uses a buffered input chain so that if you pause the viewer you
+won't find the same VOBU being displayed on the terminal as is
+currently on the screen. In my testing the correct VOBU to use if
+you pause exactly on the section you want to cut will be about five
+or six lines above the last one printed to the screen. Replay the
+scene with the deletion to see if you caught the correct blocks.
+
+
+WHERE TO FIND MAP FILES
+=======================
+
+If you create a map file for a new movie, please send it to me. If
+there is widespread interest I'll put up a site where map files can
+be located and downloaded.
+
+
+WHOM TO BLAME
+=============
+
+If the patch doesn't work for you (and you want it to) you can contact
+me at 'kevin_smathers@hp.com'.
+
+If the patch works for you and you don't want it to, remember that
+not everyone in the world has the same needs. The freedom to censor
+movies in our own homes is quite different from the government
+interfering into libraries and other public forums to censor movies
+for us.
diff --git a/lib/libdvd/libdvdnav/src/dvd_types.h b/lib/libdvd/libdvdnav/src/dvd_types.h
new file mode 100644
index 0000000000..43c21c9674
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/dvd_types.h
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2000, 2001 Björn Englund, Håkan Hjort
+ *
+ * This file is part of libdvdnav, a DVD navigation library. It is a modified
+ * file originally part of the Ogle DVD player project.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: dvd_types.h 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+/*
+ * Various useful structs and enums for DVDs.
+ */
+
+#ifndef DVD_H_INCLUDED
+#define DVD_H_INCLUDED
+
+/*
+ * DVD Menu ID
+ * (see dvdnav_menu_call())
+ */
+typedef enum {
+ /* When used in VTS domain, DVD_MENU_Escape behaves like DVD_MENU_Root,
+ * but from within a menu domain, DVD_MENU_Escape resumes playback. */
+ DVD_MENU_Escape = 0,
+ DVD_MENU_Title = 2,
+ DVD_MENU_Root = 3,
+ DVD_MENU_Subpicture = 4,
+ DVD_MENU_Audio = 5,
+ DVD_MENU_Angle = 6,
+ DVD_MENU_Part = 7
+} DVDMenuID_t;
+
+
+/*
+ * Structure containing info on highlight areas
+ * (see dvdnav_get_highlight_area())
+ */
+typedef struct {
+ uint32_t palette; /* The CLUT entries for the highlight palette
+ (4-bits per entry -> 4 entries) */
+ uint16_t sx,sy,ex,ey; /* The start/end x,y positions */
+ uint32_t pts; /* Highlight PTS to match with SPU */
+
+ /* button number for the SPU decoder/overlaying engine */
+ uint32_t buttonN;
+} dvdnav_highlight_area_t;
+
+
+/* the following types are currently unused */
+
+#if 0
+
+/* Domain */
+typedef enum {
+ DVD_DOMAIN_FirstPlay, /* First Play Domain */
+ DVD_DOMAIN_VMG, /* Video Manager Domain */
+ DVD_DOMAIN_VTSMenu, /* Video Title Set Menu Domain */
+ DVD_DOMAIN_VTSTitle, /* Video Title Set Domain */
+ DVD_DOMAIN_Stop /* Stop Domain */
+} DVDDomain_t;
+
+/* User operation permissions */
+typedef enum {
+ UOP_FLAG_TitleOrTimePlay = 0x00000001,
+ UOP_FLAG_ChapterSearchOrPlay = 0x00000002,
+ UOP_FLAG_TitlePlay = 0x00000004,
+ UOP_FLAG_Stop = 0x00000008,
+ UOP_FLAG_GoUp = 0x00000010,
+ UOP_FLAG_TimeOrChapterSearch = 0x00000020,
+ UOP_FLAG_PrevOrTopPGSearch = 0x00000040,
+ UOP_FLAG_NextPGSearch = 0x00000080,
+ UOP_FLAG_ForwardScan = 0x00000100,
+ UOP_FLAG_BackwardScan = 0x00000200,
+ UOP_FLAG_TitleMenuCall = 0x00000400,
+ UOP_FLAG_RootMenuCall = 0x00000800,
+ UOP_FLAG_SubPicMenuCall = 0x00001000,
+ UOP_FLAG_AudioMenuCall = 0x00002000,
+ UOP_FLAG_AngleMenuCall = 0x00004000,
+ UOP_FLAG_ChapterMenuCall = 0x00008000,
+ UOP_FLAG_Resume = 0x00010000,
+ UOP_FLAG_ButtonSelectOrActivate = 0x00020000,
+ UOP_FLAG_StillOff = 0x00040000,
+ UOP_FLAG_PauseOn = 0x00080000,
+ UOP_FLAG_AudioStreamChange = 0x00100000,
+ UOP_FLAG_SubPicStreamChange = 0x00200000,
+ UOP_FLAG_AngleChange = 0x00400000,
+ UOP_FLAG_KaraokeAudioPresModeChange = 0x00800000,
+ UOP_FLAG_VideoPresModeChange = 0x01000000
+} DVDUOP_t;
+
+/* Parental Level */
+typedef enum {
+ DVD_PARENTAL_LEVEL_1 = 1,
+ DVD_PARENTAL_LEVEL_2 = 2,
+ DVD_PARENTAL_LEVEL_3 = 3,
+ DVD_PARENTAL_LEVEL_4 = 4,
+ DVD_PARENTAL_LEVEL_5 = 5,
+ DVD_PARENTAL_LEVEL_6 = 6,
+ DVD_PARENTAL_LEVEL_7 = 7,
+ DVD_PARENTAL_LEVEL_8 = 8,
+ DVD_PARENTAL_LEVEL_None = 15
+} DVDParentalLevel_t;
+
+/* Language ID (ISO-639 language code) */
+typedef uint16_t DVDLangID_t;
+
+/* Country ID (ISO-3166 country code) */
+typedef uint16_t DVDCountryID_t;
+
+/* Register */
+typedef uint16_t DVDRegister_t;
+typedef enum {
+ DVDFalse = 0,
+ DVDTrue = 1
+} DVDBool_t;
+typedef DVDRegister_t DVDGPRMArray_t[16];
+typedef DVDRegister_t DVDSPRMArray_t[24];
+
+/* Navigation */
+typedef int DVDStream_t;
+typedef int DVDPTT_t;
+typedef int DVDTitle_t;
+
+/* Angle number (1-9 or default?) */
+typedef int DVDAngle_t;
+
+/* Timecode */
+typedef struct {
+ uint8_t Hours;
+ uint8_t Minutes;
+ uint8_t Seconds;
+ uint8_t Frames;
+} DVDTimecode_t;
+
+/* Subpicture stream number (0-31,62,63) */
+typedef int DVDSubpictureStream_t;
+
+/* Audio stream number (0-7, 15(none)) */
+typedef int DVDAudioStream_t;
+
+/* The audio application mode */
+typedef enum {
+ DVD_AUDIO_APP_MODE_None = 0,
+ DVD_AUDIO_APP_MODE_Karaoke = 1,
+ DVD_AUDIO_APP_MODE_Surround = 2,
+ DVD_AUDIO_APP_MODE_Other = 3
+} DVDAudioAppMode_t;
+
+/* The audio format */
+typedef enum {
+ DVD_AUDIO_FORMAT_AC3 = 0,
+ DVD_AUDIO_FORMAT_MPEG1 = 1,
+ DVD_AUDIO_FORMAT_MPEG1_DRC = 2,
+ DVD_AUDIO_FORMAT_MPEG2 = 3,
+ DVD_AUDIO_FORMAT_MPEG2_DRC = 4,
+ DVD_AUDIO_FORMAT_LPCM = 5,
+ DVD_AUDIO_FORMAT_DTS = 6,
+ DVD_AUDIO_FORMAT_SDDS = 7,
+ DVD_AUDIO_FORMAT_Other = 8
+} DVDAudioFormat_t;
+
+/* Audio language extension */
+typedef enum {
+ DVD_AUDIO_LANG_EXT_NotSpecified = 0,
+ DVD_AUDIO_LANG_EXT_NormalCaptions = 1,
+ DVD_AUDIO_LANG_EXT_VisuallyImpaired = 2,
+ DVD_AUDIO_LANG_EXT_DirectorsComments1 = 3,
+ DVD_AUDIO_LANG_EXT_DirectorsComments2 = 4
+} DVDAudioLangExt_t;
+
+/* Subpicture language extension */
+typedef enum {
+ DVD_SUBPICTURE_LANG_EXT_NotSpecified = 0,
+ DVD_SUBPICTURE_LANG_EXT_NormalCaptions = 1,
+ DVD_SUBPICTURE_LANG_EXT_BigCaptions = 2,
+ DVD_SUBPICTURE_LANG_EXT_ChildrensCaptions = 3,
+ DVD_SUBPICTURE_LANG_EXT_NormalCC = 5,
+ DVD_SUBPICTURE_LANG_EXT_BigCC = 6,
+ DVD_SUBPICTURE_LANG_EXT_ChildrensCC = 7,
+ DVD_SUBPICTURE_LANG_EXT_Forced = 9,
+ DVD_SUBPICTURE_LANG_EXT_NormalDirectorsComments = 13,
+ DVD_SUBPICTURE_LANG_EXT_BigDirectorsComments = 14,
+ DVD_SUBPICTURE_LANG_EXT_ChildrensDirectorsComments = 15,
+} DVDSubpictureLangExt_t;
+
+/* Karaoke Downmix mode */
+typedef enum {
+ DVD_KARAOKE_DOWNMIX_0to0 = 0x0001,
+ DVD_KARAOKE_DOWNMIX_1to0 = 0x0002,
+ DVD_KARAOKE_DOWNMIX_2to0 = 0x0004,
+ DVD_KARAOKE_DOWNMIX_3to0 = 0x0008,
+ DVD_KARAOKE_DOWNMIX_4to0 = 0x0010,
+ DVD_KARAOKE_DOWNMIX_Lto0 = 0x0020,
+ DVD_KARAOKE_DOWNMIX_Rto0 = 0x0040,
+ DVD_KARAOKE_DOWNMIX_0to1 = 0x0100,
+ DVD_KARAOKE_DOWNMIX_1to1 = 0x0200,
+ DVD_KARAOKE_DOWNMIX_2to1 = 0x0400,
+ DVD_KARAOKE_DOWNMIX_3to1 = 0x0800,
+ DVD_KARAOKE_DOWNMIX_4to1 = 0x1000,
+ DVD_KARAOKE_DOWNMIX_Lto1 = 0x2000,
+ DVD_KARAOKE_DOWNMIX_Rto1 = 0x4000
+} DVDKaraokeDownmix_t;
+typedef int DVDKaraokeDownmixMask_t;
+
+/* Display mode */
+typedef enum {
+ DVD_DISPLAY_MODE_ContentDefault = 0,
+ DVD_DISPLAY_MODE_16x9 = 1,
+ DVD_DISPLAY_MODE_4x3PanScan = 2,
+ DVD_DISPLAY_MODE_4x3Letterboxed = 3
+} DVDDisplayMode_t;
+
+/* Audio attributes */
+typedef struct {
+ DVDAudioAppMode_t AppMode;
+ DVDAudioFormat_t AudioFormat;
+ DVDLangID_t Language;
+ DVDAudioLangExt_t LanguageExtension;
+ DVDBool_t HasMultichannelInfo;
+ DVDAudioSampleFreq_t SampleFrequency;
+ DVDAudioSampleQuant_t SampleQuantization;
+ DVDChannelNumber_t NumberOfChannels;
+} DVDAudioAttributes_t;
+typedef int DVDAudioSampleFreq_t;
+typedef int DVDAudioSampleQuant_t;
+typedef int DVDChannelNumber_t;
+
+/* Subpicture attributes */
+typedef enum {
+ DVD_SUBPICTURE_TYPE_NotSpecified = 0,
+ DVD_SUBPICTURE_TYPE_Language = 1,
+ DVD_SUBPICTURE_TYPE_Other = 2
+} DVDSubpictureType_t;
+typedef enum {
+ DVD_SUBPICTURE_CODING_RunLength = 0,
+ DVD_SUBPICTURE_CODING_Extended = 1,
+ DVD_SUBPICTURE_CODING_Other = 2
+} DVDSubpictureCoding_t;
+typedef struct {
+ DVDSubpictureType_t Type;
+ DVDSubpictureCoding_t CodingMode;
+ DVDLangID_t Language;
+ DVDSubpictureLangExt_t LanguageExtension;
+} DVDSubpictureAttributes_t;
+
+/* Video attributes */
+typedef struct {
+ DVDBool_t PanscanPermitted;
+ DVDBool_t LetterboxPermitted;
+ int AspectX;
+ int AspectY;
+ int FrameRate;
+ int FrameHeight;
+ DVDVideoCompression_t Compression;
+ DVDBool_t Line21Field1InGop;
+ DVDBool_t Line21Field2InGop;
+ int more_to_come;
+} DVDVideoAttributes_t;
+typedef int DVDVideoCompression_t;
+
+#endif
+
+#endif /* DVD_H_INCLUDED */
diff --git a/lib/libdvd/libdvdnav/src/dvdnav.c b/lib/libdvd/libdvdnav/src/dvdnav.c
new file mode 100644
index 0000000000..5af111ca06
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/dvdnav.c
@@ -0,0 +1,1451 @@
+/*
+ * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
+ *
+ * This file is part of libdvdnav, a DVD navigation library.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: dvdnav.c 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/*
+#define LOG_DEBUG
+*/
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/time.h>
+#include "dvd_types.h"
+#include <dvdread/dvd_reader.h>
+#include <dvdread/nav_types.h>
+#include <dvdread/ifo_types.h> /* For vm_cmd_t */
+#include "remap.h"
+#include "vm/decoder.h"
+#include "vm/vm.h"
+#include "dvdnav.h"
+#include "dvdnav_events.h"
+#include "dvdnav_internal.h"
+#include "read_cache.h"
+#include <dvdread/nav_read.h>
+#include "remap.h"
+
+static dvdnav_status_t dvdnav_clear(dvdnav_t * this) {
+ /* clear everything except file, vm, mutex, readahead */
+
+ pthread_mutex_lock(&this->vm_lock);
+ if (this->file) DVDCloseFile(this->file);
+ this->file = NULL;
+
+ memset(&this->pci,0,sizeof(this->pci));
+ memset(&this->dsi,0,sizeof(this->dsi));
+ this->last_cmd_nav_lbn = SRI_END_OF_CELL;
+
+ /* Set initial values of flags */
+ this->position_current.still = 0;
+ this->skip_still = 0;
+ this->sync_wait = 0;
+ this->sync_wait_skip = 0;
+ this->spu_clut_changed = 0;
+ this->started = 0;
+ this->cur_cell_time = 0;
+
+ dvdnav_read_cache_clear(this->cache);
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_open(dvdnav_t** dest, const char *path) {
+ dvdnav_t *this;
+ struct timeval time;
+
+ /* Create a new structure */
+ fprintf(MSG_OUT, "libdvdnav: Using dvdnav version %s\n", VERSION);
+
+ (*dest) = NULL;
+ this = (dvdnav_t*)malloc(sizeof(dvdnav_t));
+ if(!this)
+ return DVDNAV_STATUS_ERR;
+ memset(this, 0, (sizeof(dvdnav_t) ) ); /* Make sure this structure is clean */
+
+ pthread_mutex_init(&this->vm_lock, NULL);
+ /* Initialise the error string */
+ printerr("");
+
+ /* Initialise the VM */
+ this->vm = vm_new_vm();
+ if(!this->vm) {
+ printerr("Error initialising the DVD VM.");
+ pthread_mutex_destroy(&this->vm_lock);
+ free(this);
+ return DVDNAV_STATUS_ERR;
+ }
+ if(!vm_reset(this->vm, path)) {
+ printerr("Error starting the VM / opening the DVD device.");
+ pthread_mutex_destroy(&this->vm_lock);
+ vm_free_vm(this->vm);
+ free(this);
+ return DVDNAV_STATUS_ERR;
+ }
+
+ /* Set the path. FIXME: Is a deep copy 'right' */
+ strncpy(this->path, path, MAX_PATH_LEN - 1);
+ this->path[MAX_PATH_LEN - 1] = '\0';
+
+ /* Pre-open and close a file so that the CSS-keys are cached. */
+ this->file = DVDOpenFile(vm_get_dvd_reader(this->vm), 0, DVD_READ_MENU_VOBS);
+
+ /* Start the read-ahead cache. */
+ this->cache = dvdnav_read_cache_new(this);
+
+ /* Seed the random numbers. So that the DVD VM Command rand()
+ * gives a different start value each time a DVD is played. */
+ gettimeofday(&time, NULL);
+ srand(time.tv_usec);
+
+ dvdnav_clear(this);
+
+ (*dest) = this;
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_close(dvdnav_t *this) {
+
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: close:called\n");
+#endif
+
+ if (this->file) {
+ pthread_mutex_lock(&this->vm_lock);
+ DVDCloseFile(this->file);
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: close:file closing\n");
+#endif
+ this->file = NULL;
+ pthread_mutex_unlock(&this->vm_lock);
+ }
+
+ /* Free the VM */
+ if(this->vm)
+ vm_free_vm(this->vm);
+
+ pthread_mutex_destroy(&this->vm_lock);
+
+ /* We leave the final freeing of the entire structure to the cache,
+ * because we don't know, if there are still buffers out in the wild,
+ * that must return first. */
+ if(this->cache)
+ dvdnav_read_cache_free(this->cache);
+ else
+ free(this);
+
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_reset(dvdnav_t *this) {
+ dvdnav_status_t result;
+
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: reset:called\n");
+#endif
+
+ pthread_mutex_lock(&this->vm_lock);
+
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: reseting vm\n");
+#endif
+ if(!vm_reset(this->vm, NULL)) {
+ printerr("Error restarting the VM.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: clearing dvdnav\n");
+#endif
+ result = dvdnav_clear(this);
+
+ pthread_mutex_unlock(&this->vm_lock);
+ return result;
+}
+
+dvdnav_status_t dvdnav_path(dvdnav_t *this, const char** path) {
+ (*path) = this->path;
+
+ return DVDNAV_STATUS_OK;
+}
+
+const char* dvdnav_err_to_string(dvdnav_t *this) {
+
+ if(!this)
+ return "Hey! You gave me a NULL pointer you naughty person!";
+
+ return this->err_str;
+}
+
+/* converts a dvd_time_t to PTS ticks */
+int64_t dvdnav_convert_time(dvd_time_t *time) {
+ int64_t result;
+ int64_t frames;
+
+ result = (time->hour >> 4 ) * 10 * 60 * 60 * 90000;
+ result += (time->hour & 0x0f) * 60 * 60 * 90000;
+ result += (time->minute >> 4 ) * 10 * 60 * 90000;
+ result += (time->minute & 0x0f) * 60 * 90000;
+ result += (time->second >> 4 ) * 10 * 90000;
+ result += (time->second & 0x0f) * 90000;
+
+ frames = ((time->frame_u & 0x30) >> 4) * 10;
+ frames += ((time->frame_u & 0x0f) ) ;
+
+ if (time->frame_u & 0x80)
+ result += frames * 3000;
+ else
+ result += frames * 3600;
+
+ return result;
+}
+
+/*
+ * Returns 1 if block contains NAV packet, 0 otherwise.
+ * Processes said NAV packet if present.
+ *
+ * Most of the code in here is copied from xine's MPEG demuxer
+ * so any bugs which are found in that should be corrected here also.
+ */
+static int32_t dvdnav_decode_packet(dvdnav_t *this, uint8_t *p, dsi_t *nav_dsi, pci_t *nav_pci) {
+ int32_t bMpeg1 = 0;
+ uint32_t nHeaderLen;
+ uint32_t nPacketLen;
+ uint32_t nStreamID;
+
+ if (p[3] == 0xBA) { /* program stream pack header */
+ int32_t nStuffingBytes;
+
+ bMpeg1 = (p[4] & 0x40) == 0;
+
+ if (bMpeg1) {
+ p += 12;
+ } else { /* mpeg2 */
+ nStuffingBytes = p[0xD] & 0x07;
+ p += 14 + nStuffingBytes;
+ }
+ }
+
+ if (p[3] == 0xbb) { /* program stream system header */
+ nHeaderLen = (p[4] << 8) | p[5];
+ p += 6 + nHeaderLen;
+ }
+
+ /* we should now have a PES packet here */
+ if (p[0] || p[1] || (p[2] != 1)) {
+ fprintf(MSG_OUT, "libdvdnav: demux error! %02x %02x %02x (should be 0x000001) \n",p[0],p[1],p[2]);
+ return 0;
+ }
+
+ nPacketLen = p[4] << 8 | p[5];
+ nStreamID = p[3];
+
+ nHeaderLen = 6;
+ p += nHeaderLen;
+
+ if (nStreamID == 0xbf) { /* Private stream 2 */
+#if 0
+ int32_t i;
+ fprintf(MSG_OUT, "libdvdnav: nav packet=%u\n",p-p_start-6);
+ for(i=0;i<80;i++)
+ fprintf(MSG_OUT, "%02x ",p[i-6]);
+ fprintf(MSG_OUT, "\n");
+#endif
+
+ if(p[0] == 0x00) {
+ navRead_PCI(nav_pci, p+1);
+ }
+
+ p += nPacketLen;
+
+ /* We should now have a DSI packet. */
+ if(p[6] == 0x01) {
+ nPacketLen = p[4] << 8 | p[5];
+ p += 6;
+ navRead_DSI(nav_dsi, p+1);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/* DSI is used for most angle stuff.
+ * PCI is used for only non-seemless angle stuff
+ */
+static int32_t dvdnav_get_vobu(dvdnav_t *this, dsi_t *nav_dsi, pci_t *nav_pci, dvdnav_vobu_t *vobu) {
+ uint32_t next;
+ int32_t angle, num_angle;
+
+ vobu->vobu_start = nav_dsi->dsi_gi.nv_pck_lbn; /* Absolute offset from start of disk */
+ vobu->vobu_length = nav_dsi->dsi_gi.vobu_ea; /* Relative offset from vobu_start */
+
+ /*
+ * 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.
+ *
+ * vobu_next is an offset value, 0x3fffffff = SRI_END_OF_CELL
+ * DVDs are about 6 Gigs, which is only up to 0x300000 blocks
+ * Should really assert if bit 31 != 1
+ */
+
+#if 0
+ /* Old code -- may still be useful one day */
+ if(nav_dsi->vobu_sri.next_vobu != SRI_END_OF_CELL ) {
+ vobu->vobu_next = ( nav_dsi->vobu_sri.next_vobu & 0x3fffffff );
+ } else {
+ vobu->vobu_next = vobu->vobu_length;
+ }
+#else
+ /* Relative offset from vobu_start */
+ vobu->vobu_next = ( nav_dsi->vobu_sri.next_vobu & 0x3fffffff );
+#endif
+
+ vm_get_angle_info(this->vm, &angle, &num_angle);
+
+ /* FIMXE: The angle reset doesn't work for some reason for the moment */
+#if 0
+ if((num_angle < angle) && (angle != 1)) {
+ fprintf(MSG_OUT, "libdvdnav: angle ends!\n");
+
+ /* This is to switch back to angle one when we
+ * finish with angles. */
+ dvdnav_angle_change(this, 1);
+ }
+#endif
+
+ /* only use ILVU information if we are at the last vobunit in ILVU */
+ /* otherwise we will miss nav packets from vobunits inbetween */
+ if(num_angle != 0 && (nav_dsi->sml_pbi.category & 0x5000) == 0x5000 ) {
+
+ if((next = nav_pci->nsml_agli.nsml_agl_dsta[angle-1]) != 0) {
+ if((next & 0x3fffffff) != 0) {
+ if(next & 0x80000000)
+ vobu->vobu_next = - (int32_t)(next & 0x3fffffff);
+ else
+ vobu->vobu_next = + (int32_t)(next & 0x3fffffff);
+ }
+ } else if((next = nav_dsi->sml_agli.data[angle-1].address) != 0) {
+ vobu->vobu_length = nav_dsi->sml_pbi.ilvu_ea;
+
+ if((next & 0x80000000) && (next != 0x7fffffff))
+ vobu->vobu_next = - (int32_t)(next & 0x3fffffff);
+ else
+ vobu->vobu_next = + (int32_t)(next & 0x3fffffff);
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * These are the main get_next_block function which actually get the media stream video and audio etc.
+ *
+ * There are two versions: The second one is using the zero-copy read ahead cache and therefore
+ * hands out pointers targetting directly into the cache.
+ * The first one uses a memcopy to fill this cache block into the application provided memory.
+ * The benefit of this first one is that no special memory management is needed. The application is
+ * the only one responsible of allocating and freeing the memory associated with the pointer.
+ * The drawback is the additional memcopy.
+ */
+
+dvdnav_status_t dvdnav_get_next_block(dvdnav_t *this, uint8_t *buf,
+ int32_t *event, int32_t *len) {
+ unsigned char *block;
+ dvdnav_status_t status;
+
+ block = buf;
+ status = dvdnav_get_next_cache_block(this, &block, event, len);
+ if (status == DVDNAV_STATUS_OK && block != buf) {
+ /* we received a block from the cache, copy it, so we can give it back */
+ memcpy(buf, block, DVD_VIDEO_LB_LEN);
+ dvdnav_free_cache_block(this, block);
+ }
+ return status;
+}
+
+int64_t dvdnav_get_current_time(dvdnav_t *this) {
+ int i;
+ int64_t tm=0;
+ dvd_state_t *state = &this->vm->state;
+
+ for(i=0; i<state->cellN-1; i++) {
+ if(!
+ (state->pgc->cell_playback[i].block_type == BLOCK_TYPE_ANGLE_BLOCK &&
+ state->pgc->cell_playback[i].block_mode != BLOCK_MODE_FIRST_CELL)
+ )
+ tm += dvdnav_convert_time(&state->pgc->cell_playback[i].playback_time);
+ }
+ tm += this->cur_cell_time;
+
+ return tm;
+}
+
+dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t *this, uint8_t **buf,
+ int32_t *event, int32_t *len) {
+ dvd_state_t *state;
+ int32_t result;
+
+ pthread_mutex_lock(&this->vm_lock);
+
+ if(!this->started) {
+ /* Start the VM */
+ if (!vm_start(this->vm)) {
+ printerr("Encrypted or faulty DVD");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ this->started = 1;
+ }
+
+ state = &(this->vm->state);
+ (*event) = DVDNAV_NOP;
+ (*len) = 0;
+
+ /* Check the STOP flag */
+ if(this->vm->stopped) {
+ vm_stop(this->vm);
+ (*event) = DVDNAV_STOP;
+ this->started = 0;
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+ }
+
+ vm_position_get(this->vm, &this->position_next);
+
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: POS-NEXT ");
+ vm_position_print(this->vm, &this->position_next);
+ fprintf(MSG_OUT, "libdvdnav: POS-CUR ");
+ vm_position_print(this->vm, &this->position_current);
+#endif
+
+ /* did we hop? */
+ if(this->position_current.hop_channel != this->position_next.hop_channel) {
+ (*event) = DVDNAV_HOP_CHANNEL;
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: HOP_CHANNEL\n");
+#endif
+ if (this->position_next.hop_channel - this->position_current.hop_channel >= HOP_SEEK) {
+ int32_t num_angles = 0, current;
+
+ /* we seeked -> check for multiple angles */
+ vm_get_angle_info(this->vm, &current, &num_angles);
+ if (num_angles > 1) {
+ int32_t result, block;
+ /* we have to skip the first VOBU when seeking in a multiangle feature,
+ * because it might belong to the wrong angle */
+ block = this->position_next.cell_start + this->position_next.block;
+ result = dvdnav_read_cache_block(this->cache, block, 1, buf);
+ if(result <= 0) {
+ printerr("Error reading NAV packet.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ /* Decode nav into pci and dsi. Then get next VOBU info. */
+ if(!dvdnav_decode_packet(this, *buf, &this->dsi, &this->pci)) {
+ printerr("Expected NAV packet but none found.");
+#ifdef _XBMC
+ /* skip this cell as we won't recover from this*/
+ vm_get_next_cell(this->vm);
+#endif
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ dvdnav_get_vobu(this, &this->dsi, &this->pci, &this->vobu);
+ /* skip to next, if there is a next */
+ if (this->vobu.vobu_next != SRI_END_OF_CELL) {
+ this->vobu.vobu_start += this->vobu.vobu_next;
+ this->vobu.vobu_next = 0;
+ }
+ /* update VM state */
+ this->vm->state.blockN = this->vobu.vobu_start - this->position_next.cell_start;
+ }
+ }
+ this->position_current.hop_channel = this->position_next.hop_channel;
+ /* update VOBU info */
+ this->vobu.vobu_start = this->position_next.cell_start + this->position_next.block;
+ this->vobu.vobu_next = 0;
+ /* Make blockN == vobu_length to do expected_nav */
+ this->vobu.vobu_length = 0;
+ this->vobu.blockN = 0;
+ this->sync_wait = 0;
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+ }
+
+ /* Check the HIGHLIGHT flag */
+ if(this->position_current.button != this->position_next.button) {
+ dvdnav_highlight_event_t *hevent = (dvdnav_highlight_event_t *)*buf;
+
+ (*event) = DVDNAV_HIGHLIGHT;
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: HIGHLIGHT\n");
+#endif
+ (*len) = sizeof(dvdnav_highlight_event_t);
+ hevent->display = 1;
+ hevent->buttonN = this->position_next.button;
+ this->position_current.button = this->position_next.button;
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+ }
+
+ /* Check the WAIT flag */
+ if(this->sync_wait) {
+ (*event) = DVDNAV_WAIT;
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: WAIT\n");
+#endif
+ (*len) = 0;
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+ }
+
+ /* Check to see if we need to change the currently opened VOB */
+ if((this->position_current.vts != this->position_next.vts) ||
+ (this->position_current.domain != this->position_next.domain)) {
+ dvd_read_domain_t domain;
+ int32_t vtsN;
+ dvdnav_vts_change_event_t *vts_event = (dvdnav_vts_change_event_t *)*buf;
+
+ if(this->file) {
+ DVDCloseFile(this->file);
+ this->file = NULL;
+ }
+
+ vts_event->old_vtsN = this->position_current.vts;
+ vts_event->old_domain = this->position_current.domain;
+
+ /* Use the DOMAIN to find whether to open menu or title VOBs */
+ switch(this->position_next.domain) {
+ case FP_DOMAIN:
+ case VMGM_DOMAIN:
+ domain = DVD_READ_MENU_VOBS;
+ vtsN = 0;
+ break;
+ case VTSM_DOMAIN:
+ domain = DVD_READ_MENU_VOBS;
+ vtsN = this->position_next.vts;
+ break;
+ case VTS_DOMAIN:
+ domain = DVD_READ_TITLE_VOBS;
+ vtsN = this->position_next.vts;
+ break;
+ default:
+ printerr("Unknown domain when changing VTS.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+
+ this->position_current.vts = this->position_next.vts;
+ this->position_current.domain = this->position_next.domain;
+ dvdnav_read_cache_clear(this->cache);
+ this->file = DVDOpenFile(vm_get_dvd_reader(this->vm), vtsN, domain);
+ vts_event->new_vtsN = this->position_next.vts;
+ vts_event->new_domain = this->position_next.domain;
+
+ /* If couldn't open the file for some reason, moan */
+ if(this->file == NULL) {
+ printerrf("Error opening vtsN=%i, domain=%i.", vtsN, domain);
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+
+ /* File opened successfully so return a VTS change event */
+ (*event) = DVDNAV_VTS_CHANGE;
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: VTS_CHANGE\n");
+#endif
+ (*len) = sizeof(dvdnav_vts_change_event_t);
+
+ this->spu_clut_changed = 1;
+ this->position_current.cell = -1; /* Force an update */
+ this->position_current.spu_channel = -1; /* Force an update */
+ this->position_current.audio_channel = -1; /* Force an update */;
+
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+ }
+
+ /* Check if the cell changed */
+ if( (this->position_current.cell != this->position_next.cell) ||
+ (this->position_current.cell_restart != this->position_next.cell_restart) ||
+ (this->position_current.cell_start != this->position_next.cell_start) ) {
+ dvdnav_cell_change_event_t *cell_event = (dvdnav_cell_change_event_t *)*buf;
+ int32_t first_cell_nr, last_cell_nr, i;
+ dvd_state_t *state = &this->vm->state;
+
+ this->cur_cell_time = 0;
+ (*event) = DVDNAV_CELL_CHANGE;
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: CELL_CHANGE\n");
+#endif
+ (*len) = sizeof(dvdnav_cell_change_event_t);
+
+ cell_event->cellN = state->cellN;
+ cell_event->pgN = state->pgN;
+ cell_event->cell_length =
+ dvdnav_convert_time(&state->pgc->cell_playback[state->cellN-1].playback_time);
+
+ cell_event->pg_length = 0;
+ /* Find start cell of program. */
+ first_cell_nr = state->pgc->program_map[state->pgN-1];
+ /* Find end cell of program */
+ if(state->pgN < state->pgc->nr_of_programs)
+ last_cell_nr = state->pgc->program_map[state->pgN] - 1;
+ else
+ last_cell_nr = state->pgc->nr_of_cells;
+ for (i = first_cell_nr; i <= last_cell_nr; i++)
+ cell_event->pg_length +=
+ dvdnav_convert_time(&state->pgc->cell_playback[i - 1].playback_time);
+ cell_event->pgc_length = dvdnav_convert_time(&state->pgc->playback_time);
+
+ cell_event->cell_start = 0;
+ for (i = 0; i < state->cellN; i++)
+ {
+ /* only count the first angle cell */
+ if( state->pgc->cell_playback[i].block_type == BLOCK_TYPE_ANGLE_BLOCK
+ && state->pgc->cell_playback[i].block_mode != BLOCK_MODE_FIRST_CELL )
+ continue;
+
+ cell_event->cell_start +=
+ dvdnav_convert_time(&state->pgc->cell_playback[i].playback_time);
+ }
+ cell_event->cell_start-= dvdnav_convert_time(&state->pgc->cell_playback[state->cellN-1].playback_time);
+
+ cell_event->pg_start = 0;
+ for (i = 1; i < state->pgc->program_map[state->pgN-1]; i++)
+ cell_event->pg_start +=
+ dvdnav_convert_time(&state->pgc->cell_playback[i - 1].playback_time);
+
+ this->position_current.cell = this->position_next.cell;
+ this->position_current.cell_restart = this->position_next.cell_restart;
+ this->position_current.cell_start = this->position_next.cell_start;
+ this->position_current.block = this->position_next.block;
+
+ /* vobu info is used for mid cell resumes */
+ this->vobu.vobu_start = this->position_next.cell_start + this->position_next.block;
+ this->vobu.vobu_next = 0;
+ /* Make blockN == vobu_length to do expected_nav */
+ this->vobu.vobu_length = 0;
+ this->vobu.blockN = 0;
+
+ /* update the spu palette at least on PGC changes */
+ this->spu_clut_changed = 1;
+ this->position_current.spu_channel = -1; /* Force an update */
+ this->position_current.audio_channel = -1; /* Force an update */
+
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+ }
+
+ /* has the CLUT changed? */
+ if(this->spu_clut_changed) {
+ (*event) = DVDNAV_SPU_CLUT_CHANGE;
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: SPU_CLUT_CHANGE\n");
+#endif
+ (*len) = 16 * sizeof(uint32_t);
+ memcpy(*buf, state->pgc->palette, 16 * sizeof(uint32_t));
+ this->spu_clut_changed = 0;
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+ }
+
+ /* has the SPU channel changed? */
+ if(this->position_current.spu_channel != this->position_next.spu_channel) {
+ dvdnav_spu_stream_change_event_t *stream_change = (dvdnav_spu_stream_change_event_t *)*buf;
+
+ (*event) = DVDNAV_SPU_STREAM_CHANGE;
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE\n");
+#endif
+ (*len) = sizeof(dvdnav_spu_stream_change_event_t);
+ stream_change->physical_wide = vm_get_subp_active_stream(this->vm, 0);
+ stream_change->physical_letterbox = vm_get_subp_active_stream(this->vm, 1);
+ stream_change->physical_pan_scan = vm_get_subp_active_stream(this->vm, 2);
+ this->position_current.spu_channel = this->position_next.spu_channel;
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_wide=%d\n",stream_change->physical_wide);
+ fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_letterbox=%d\n",stream_change->physical_letterbox);
+ fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_pan_scan=%d\n",stream_change->physical_pan_scan);
+ fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE returning DVDNAV_STATUS_OK\n");
+#endif
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+ }
+
+ /* has the audio channel changed? */
+ if(this->position_current.audio_channel != this->position_next.audio_channel) {
+ dvdnav_audio_stream_change_event_t *stream_change = (dvdnav_audio_stream_change_event_t *)*buf;
+
+ (*event) = DVDNAV_AUDIO_STREAM_CHANGE;
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: AUDIO_STREAM_CHANGE\n");
+#endif
+ (*len) = sizeof(dvdnav_audio_stream_change_event_t);
+ stream_change->physical = vm_get_audio_active_stream( this->vm );
+ stream_change->logical = this->position_next.audio_channel;
+ this->position_current.audio_channel = this->position_next.audio_channel;
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: AUDIO_STREAM_CHANGE stream_id=%d returning DVDNAV_STATUS_OK\n",stream_change->physical);
+#endif
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+ }
+
+ /* Check the STILLFRAME flag */
+ if(this->position_current.still != 0) {
+ dvdnav_still_event_t *still_event = (dvdnav_still_event_t *)*buf;
+
+ (*event) = DVDNAV_STILL_FRAME;
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: STILL_FRAME\n");
+#endif
+ (*len) = sizeof(dvdnav_still_event_t);
+ still_event->length = this->position_current.still;
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+ }
+
+ /* Have we reached the end of a VOBU? */
+ if (this->vobu.blockN >= this->vobu.vobu_length) {
+
+ /* Have we reached the end of a cell? */
+ if(this->vobu.vobu_next == SRI_END_OF_CELL) {
+ /* End of Cell from NAV DSI info */
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: Still set to %x\n", this->position_next.still);
+#endif
+ this->position_current.still = this->position_next.still;
+
+ /* we are about to leave a cell, so a lot of state changes could occur;
+ * under certain conditions, the application should get in sync with us before this,
+ * otherwise it might show stills or menus too shortly */
+ if ((this->position_current.still || this->pci.hli.hl_gi.hli_ss) && !this->sync_wait_skip) {
+ this->sync_wait = 1;
+ } else {
+ if( this->position_current.still == 0 || this->skip_still ) {
+ /* no active cell still -> get us to the next cell */
+ vm_get_next_cell(this->vm);
+ this->position_current.still = 0; /* still gets activated at end of cell */
+ this->skip_still = 0;
+ this->sync_wait_skip = 0;
+ }
+ }
+ /* handle related state changes in next iteration */
+ (*event) = DVDNAV_NOP;
+ (*len) = 0;
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+ }
+
+ /* Perform remapping jump if necessary (this is always a
+ * VOBU boundary). */
+ if (this->vm->map) {
+ this->vobu.vobu_next = remap_block( this->vm->map,
+ this->vm->state.domain, this->vm->state.TTN_REG,
+ this->vm->state.pgN,
+ this->vobu.vobu_start, this->vobu.vobu_next);
+ }
+
+ /* at the start of the next VOBU -> expecting NAV packet */
+ result = dvdnav_read_cache_block(this->cache, this->vobu.vobu_start + this->vobu.vobu_next, 1, buf);
+
+ if(result <= 0) {
+ printerr("Error reading NAV packet.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ /* Decode nav into pci and dsi. Then get next VOBU info. */
+ if(!dvdnav_decode_packet(this, *buf, &this->dsi, &this->pci)) {
+ printerr("Expected NAV packet but none found.");
+#ifdef _XBMC
+ /* skip this cell as we won't recover from this */
+ vm_get_next_cell(this->vm);
+#endif
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ /* We need to update the vm state->blockN with which VOBU we are in.
+ * This is so RSM resumes to the VOBU level and not just the CELL level.
+ */
+ this->vm->state.blockN = this->vobu.vobu_start - this->position_current.cell_start;
+
+ dvdnav_get_vobu(this, &this->dsi, &this->pci, &this->vobu);
+ this->vobu.blockN = 0;
+ /* Give the cache a hint about the size of next VOBU.
+ * This improves pre-caching, because the VOBU will almost certainly be read entirely.
+ */
+ dvdnav_pre_cache_blocks(this->cache, this->vobu.vobu_start+1, this->vobu.vobu_length+1);
+
+ /* release NAV menu filter, when we reach the same NAV packet again */
+ if (this->last_cmd_nav_lbn == this->pci.pci_gi.nv_pck_lbn)
+ this->last_cmd_nav_lbn = SRI_END_OF_CELL;
+
+ /* Successfully got a NAV packet */
+ (*event) = DVDNAV_NAV_PACKET;
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: NAV_PACKET\n");
+#endif
+ (*len) = 2048;
+ this->cur_cell_time = dvdnav_convert_time(&this->dsi.dsi_gi.c_eltm);
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+ }
+
+ /* If we've got here, it must just be a normal block. */
+ if(!this->file) {
+ printerr("Attempting to read without opening file.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+
+ this->vobu.blockN++;
+ result = dvdnav_read_cache_block(this->cache, this->vobu.vobu_start + this->vobu.blockN, 1, buf);
+ if(result <= 0) {
+ printerr("Error reading from DVD.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ (*event) = DVDNAV_BLOCK_OK;
+ (*len) = 2048;
+
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_get_title_string(dvdnav_t *this, const char **title_str) {
+ (*title_str) = this->vm->dvd_name;
+ return DVDNAV_STATUS_OK;
+}
+
+uint8_t dvdnav_get_video_aspect(dvdnav_t *this) {
+ uint8_t retval;
+
+ if(!this->started) {
+ printerr("Virtual DVD machine not started.");
+ return -1;
+ }
+
+ pthread_mutex_lock(&this->vm_lock);
+ retval = (uint8_t)vm_get_video_aspect(this->vm);
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return retval;
+}
+
+uint8_t dvdnav_get_video_scale_permission(dvdnav_t *this) {
+ uint8_t retval;
+
+ if(!this->started) {
+ printerr("Virtual DVD machine not started.");
+ return -1;
+ }
+
+ pthread_mutex_lock(&this->vm_lock);
+ retval = (uint8_t)vm_get_video_scale_permission(this->vm);
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return retval;
+}
+
+uint16_t dvdnav_audio_stream_to_lang(dvdnav_t *this, uint8_t stream) {
+ audio_attr_t attr;
+
+ if(!this->started) {
+ printerr("Virtual DVD machine not started.");
+ return -1;
+ }
+
+ pthread_mutex_lock(&this->vm_lock);
+ attr = vm_get_audio_attr(this->vm, stream);
+ pthread_mutex_unlock(&this->vm_lock);
+
+ if(attr.lang_type != 1)
+ return 0xffff;
+
+ return attr.lang_code;
+}
+
+uint16_t dvdnav_audio_stream_format(dvdnav_t *this, uint8_t stream) {
+ audio_attr_t attr;
+ uint16_t format;
+
+ if(!this->started) {
+ printerr("Virtual DVD machine not started.");
+ return -1; /* 0xffff */
+ }
+
+ pthread_mutex_lock(&this->vm_lock);
+ attr = vm_get_audio_attr(this->vm, stream);
+ pthread_mutex_unlock(&this->vm_lock);
+
+ switch(attr.audio_format) {
+ case 0:
+ format = DVDNAV_FORMAT_AC3;
+ break;
+ case 2: /* MPEG-1 or MPEG-2 without extension bitstream. */
+ case 3: /* MPEG-2 with extension bitstream. */
+ format = DVDNAV_FORMAT_MPEGAUDIO;
+ break;
+ case 4:
+ format = DVDNAV_FORMAT_LPCM;
+ break;
+ case 6:
+ format = DVDNAV_FORMAT_DTS;
+ break;
+ case 7:
+ format = DVDNAV_FORMAT_SDDS;
+ break;
+ default:
+ format = 0xffff;
+ break;
+ }
+
+ return format;
+}
+
+uint16_t dvdnav_audio_stream_channels(dvdnav_t *this, uint8_t stream) {
+ audio_attr_t attr;
+
+ if(!this->started) {
+ printerr("Virtual DVD machine not started.");
+ return -1; /* 0xffff */
+ }
+
+ pthread_mutex_lock(&this->vm_lock);
+ attr = vm_get_audio_attr(this->vm, stream);
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return attr.channels + 1;
+}
+
+uint16_t dvdnav_spu_stream_to_lang(dvdnav_t *this, uint8_t stream) {
+ subp_attr_t attr;
+
+ if(!this->started) {
+ printerr("Virtual DVD machine not started.");
+ return -1;
+ }
+
+ pthread_mutex_lock(&this->vm_lock);
+ attr = vm_get_subp_attr(this->vm, stream);
+ pthread_mutex_unlock(&this->vm_lock);
+
+ if(attr.type != 1)
+ return 0xffff;
+
+ return attr.lang_code;
+}
+
+int8_t dvdnav_get_audio_logical_stream(dvdnav_t *this, uint8_t audio_num) {
+ int8_t retval;
+
+ if(!this->started) {
+ printerr("Virtual DVD machine not started.");
+ return -1;
+ }
+
+ pthread_mutex_lock(&this->vm_lock);
+ if (!this->vm->state.pgc) {
+ printerr("No current PGC.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return -1;
+ }
+ retval = vm_get_audio_stream(this->vm, audio_num);
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return retval;
+}
+
+dvdnav_status_t dvdnav_get_audio_attr(dvdnav_t *this, uint8_t audio_num, audio_attr_t *audio_attr) {
+ if(!this->started) {
+ printerr("Virtual DVD machine not started.");
+ return -1;
+ }
+ pthread_mutex_lock(&this->vm_lock);
+ if (!this->vm->state.pgc) {
+ printerr("No current PGC.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return -1;
+ }
+ *audio_attr=vm_get_audio_attr(this->vm, audio_num);
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return DVDNAV_STATUS_OK;
+}
+
+int8_t dvdnav_get_spu_logical_stream(dvdnav_t *this, uint8_t subp_num) {
+ int8_t retval;
+
+ if(!this->started) {
+ printerr("Virtual DVD machine not started.");
+ return -1;
+ }
+
+ pthread_mutex_lock(&this->vm_lock);
+ if (!this->vm->state.pgc) {
+ printerr("No current PGC.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return -1;
+ }
+ retval = vm_get_subp_stream(this->vm, subp_num, 0);
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return retval;
+}
+
+dvdnav_status_t dvdnav_get_spu_attr(dvdnav_t *this, uint8_t audio_num, subp_attr_t *subp_attr) {
+ if(!this->started) {
+ printerr("Virtual DVD machine not started.");
+ return -1;
+ }
+ pthread_mutex_lock(&this->vm_lock);
+ if (!this->vm->state.pgc) {
+ printerr("No current PGC.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return -1;
+ }
+ *subp_attr=vm_get_subp_attr(this->vm, audio_num);
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+}
+
+int8_t dvdnav_get_active_audio_stream(dvdnav_t *this) {
+ int8_t retval;
+
+ if(!this->started) {
+ printerr("Virtual DVD machine not started.");
+ return -1;
+ }
+
+ pthread_mutex_lock(&this->vm_lock);
+ if (!this->vm->state.pgc) {
+ printerr("No current PGC.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return -1;
+ }
+ retval = vm_get_audio_active_stream(this->vm);
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return retval;
+}
+
+int8_t dvdnav_get_active_spu_stream(dvdnav_t *this) {
+ int8_t retval;
+
+ if(!this->started) {
+ printerr("Virtual DVD machine not started.");
+ return -1;
+ }
+
+ pthread_mutex_lock(&this->vm_lock);
+ if (!this->vm->state.pgc) {
+ printerr("No current PGC.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return -1;
+ }
+ retval = vm_get_subp_active_stream(this->vm, 0);
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return retval;
+}
+
+static int8_t dvdnav_is_domain(dvdnav_t *this, domain_t domain) {
+ int8_t retval;
+
+ if(!this->started) {
+ printerr("Virtual DVD machine not started.");
+ return -1;
+ }
+
+ pthread_mutex_lock(&this->vm_lock);
+ retval = (this->vm->state.domain == domain);
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return retval;
+}
+
+/* First Play domain. (Menu) */
+int8_t dvdnav_is_domain_fp(dvdnav_t *this) {
+ return dvdnav_is_domain(this, FP_DOMAIN);
+}
+/* Video management Menu domain. (Menu) */
+int8_t dvdnav_is_domain_vmgm(dvdnav_t *this) {
+ return dvdnav_is_domain(this, VMGM_DOMAIN);
+}
+/* Video Title Menu domain (Menu) */
+int8_t dvdnav_is_domain_vtsm(dvdnav_t *this) {
+ return dvdnav_is_domain(this, VTSM_DOMAIN);
+}
+/* Video Title domain (playing movie). */
+int8_t dvdnav_is_domain_vts(dvdnav_t *this) {
+ return dvdnav_is_domain(this, VTS_DOMAIN);
+}
+
+/* Generally delegate angle information handling to VM */
+dvdnav_status_t dvdnav_angle_change(dvdnav_t *this, int32_t angle) {
+ int32_t num, current;
+
+ pthread_mutex_lock(&this->vm_lock);
+ vm_get_angle_info(this->vm, &current, &num);
+ /* Set angle SPRM if valid */
+ if((angle > 0) && (angle <= num)) {
+ this->vm->state.AGL_REG = angle;
+ } else {
+ printerr("Passed an invalid angle number.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_get_angle_info(dvdnav_t *this, int32_t *current_angle,
+ int32_t *number_of_angles) {
+ pthread_mutex_lock(&this->vm_lock);
+ vm_get_angle_info(this->vm, current_angle, number_of_angles);
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return DVDNAV_STATUS_OK;
+}
+
+pci_t* dvdnav_get_current_nav_pci(dvdnav_t *this) {
+ if(!this) return 0;
+ return &this->pci;
+}
+
+dsi_t* dvdnav_get_current_nav_dsi(dvdnav_t *this) {
+ if(!this) return 0;
+ return &this->dsi;
+}
+
+uint32_t dvdnav_get_next_still_flag(dvdnav_t *this) {
+ if(!this) return -1;
+ return this->position_next.still;
+}
+
+user_ops_t dvdnav_get_restrictions(dvdnav_t* this) {
+ /*
+ * user_ops_t is a structure of 32 bits. We want to compute
+ * the union of two of those bitfields so to make this quicker
+ * than performing 32 ORs, we will access them as 32bits words.
+ */
+ union {
+ user_ops_t ops_struct;
+ uint32_t ops_int;
+ } ops, tmp;
+
+ ops.ops_int = 0;
+
+ if(!this) {
+ printerr("Passed a NULL pointer.");
+ return ops.ops_struct;
+ }
+ if(!this->started) {
+ printerr("Virtual DVD machine not started.");
+ return ops.ops_struct;
+ }
+
+ pthread_mutex_lock(&this->vm_lock);
+ tmp.ops_struct = this->pci.pci_gi.vobu_uop_ctl;
+ ops.ops_int |= tmp.ops_int;
+
+ if(this->vm && this->vm->state.pgc) {
+ tmp.ops_struct = this->vm->state.pgc->prohibited_ops;
+ ops.ops_int |= tmp.ops_int;
+ }
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return ops.ops_struct;
+}
+
+#ifdef _XBMC
+
+vm_t* dvdnav_get_vm(dvdnav_t *this) {
+ if(!this) return 0;
+ return this->vm;
+}
+
+int dvdnav_get_nr_of_subtitle_streams(dvdnav_t *this)
+{
+ int i;
+ int count = 0;
+
+ if (this && this->vm && this->vm->state.pgc)
+ {
+ for (i = 0; i < 32; i++)
+ {
+ if (this->vm->state.pgc->subp_control[i] & (1<<31)) count++;
+ }
+ }
+ return count;
+
+ /* old code
+ if(!this || !this->vm || !this->vm->vtsi || !this->vm->vtsi->vtsi_mat) return 0;
+
+ switch ((this->vm->state).domain) {
+ case VTS_DOMAIN:
+ return this->vm->vtsi->vtsi_mat->nr_of_vts_subp_streams;
+ case VTSM_DOMAIN:
+ return this->vm->vtsi->vtsi_mat->nr_of_vtsm_subp_streams; // 1
+ case VMGM_DOMAIN:
+ case FP_DOMAIN:
+ return this->vm->vmgi->vmgi_mat->nr_of_vmgm_subp_streams; // 1
+ }
+
+ return 0;
+ */
+}
+
+int dvdnav_get_nr_of_audio_streams(dvdnav_t *this)
+{
+ int i;
+ int count = 0;
+
+ if (this && this->vm && this->vm->state.pgc)
+ {
+ for (i = 0; i < 8; i++)
+ {
+ if (this->vm->state.pgc->audio_control[i] & (1<<15)) count++;
+ }
+ }
+ return count;
+
+ /* old code
+ if(!this || !this->vm || !this->vm->vtsi || !this->vm->vtsi->vtsi_mat) return 0;
+
+ switch ((this->vm->state).domain) {
+ case VTS_DOMAIN:
+ return this->vm->vtsi->vtsi_mat->nr_of_vts_audio_streams;
+ case VTSM_DOMAIN:
+ return this->vm->vtsi->vtsi_mat->nr_of_vtsm_audio_streams; // 1
+ case VMGM_DOMAIN:
+ case FP_DOMAIN:
+ return this->vm->vmgi->vmgi_mat->nr_of_vmgm_audio_streams; // 1
+ }
+
+ return 0;
+ */
+}
+
+/* return the alpha and color for the current active button
+ * color, alpha [0][] = selection
+ * color, alpha = color
+ *
+ * argsize = [2][4]
+ */
+int dvdnav_get_button_info(dvdnav_t* this, int alpha[2][4], int color[2][4])
+{
+ int current_button, current_button_color, i;
+ pci_t* pci;
+
+ if (!this) return -1;
+
+ pci = dvdnav_get_current_nav_pci(this);
+ if (!pci) return -1;
+
+ dvdnav_get_current_highlight(this, &current_button);
+ current_button_color = pci->hli.btnit[current_button - 1].btn_coln;
+
+ for (i = 0; i < 2; i++)
+ {
+ alpha[i][0] = pci->hli.btn_colit.btn_coli[current_button_color - 1][i] >> 0 & 0xf;
+ alpha[i][1] = pci->hli.btn_colit.btn_coli[current_button_color - 1][i] >> 4 & 0xf;
+ alpha[i][2] = pci->hli.btn_colit.btn_coli[current_button_color - 1][i] >> 8 & 0xf;
+ alpha[i][3] = pci->hli.btn_colit.btn_coli[current_button_color - 1][i] >> 12 & 0xf;
+
+ color[i][0] = pci->hli.btn_colit.btn_coli[current_button_color - 1][i] >> 16 & 0xf;
+ color[i][1] = pci->hli.btn_colit.btn_coli[current_button_color - 1][i] >> 20 & 0xf;
+ color[i][2] = pci->hli.btn_colit.btn_coli[current_button_color - 1][i] >> 24 & 0xf;
+ color[i][3] = pci->hli.btn_colit.btn_coli[current_button_color - 1][i] >> 28 & 0xf;
+ }
+
+ return 0;
+}
+
+/*
+ * the next stuff is taken from ratdvd
+ */
+
+#undef printerr
+#define printerr(str) strncpy(self->err_str, str, MAX_ERR_LEN);
+
+dvdnav_status_t dvdnav_get_audio_info(dvdnav_t * self, int32_t streamid, audio_attr_t* audio_attributes)
+{
+ if(!self) {
+ printerr("Passed a NULL pointer.");
+ return -1;
+ }
+ if(!self->started) {
+ printerr("Virtual DVD machine not started.");
+ return -1;
+ }
+
+ pthread_mutex_lock(&self->vm_lock);
+ audio_attr_t attributes = vm_get_audio_attr(self->vm,streamid);
+ pthread_mutex_unlock(&self->vm_lock);
+ audio_attributes->audio_format = attributes.audio_format;
+ audio_attributes->multichannel_extension = attributes.multichannel_extension;
+ audio_attributes->lang_type = attributes.lang_type;
+ audio_attributes->application_mode = attributes.application_mode;
+ audio_attributes->quantization = attributes.quantization;
+ audio_attributes->sample_frequency = attributes.sample_frequency;
+ audio_attributes->channels = attributes.channels;
+ audio_attributes->lang_code = attributes.lang_code;
+ audio_attributes->lang_extension = attributes.lang_extension;
+ audio_attributes->code_extension = attributes.code_extension;
+ audio_attributes->unknown3 = attributes.unknown3;
+ audio_attributes->app_info = attributes.app_info;
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_get_stitle_info(dvdnav_t * self
+ , int32_t streamid, subp_attr_t* stitle_attributes)
+{
+ if(!self) {
+ printerr("Passed a NULL pointer.");
+ return -1;
+ }
+ if(!self->started) {
+ printerr("Virtual DVD machine not started.");
+ return -1;
+ }
+
+ pthread_mutex_lock(&self->vm_lock);
+ subp_attr_t attributes = vm_get_subp_attr(self->vm,streamid);
+ pthread_mutex_unlock(&self->vm_lock);
+ stitle_attributes->code_mode = attributes.code_mode;
+ stitle_attributes->zero1 = attributes.zero1;
+ stitle_attributes->type = attributes.type;
+ stitle_attributes->zero2 = attributes.zero2;
+ stitle_attributes->lang_code = attributes.lang_code;
+ stitle_attributes->lang_extension = attributes.lang_extension;
+ stitle_attributes->code_extension = attributes.code_extension;
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_get_video_info(dvdnav_t * self, video_attr_t* video_attributes)
+{
+ if(!self) {
+ printerr("Passed a NULL pointer.");
+ return -1;
+ }
+ if(!self->started) {
+ printerr("Virtual DVD machine not started.");
+ return -1;
+ }
+
+ pthread_mutex_lock(&self->vm_lock);
+ video_attr_t attributes = vm_get_video_attr(self->vm);
+ pthread_mutex_unlock(&self->vm_lock);
+
+ video_attributes->video_format = attributes.video_format;
+ video_attributes->permitted_df = attributes.permitted_df;
+ video_attributes->display_aspect_ratio = attributes.display_aspect_ratio;
+ video_attributes->mpeg_version = attributes.mpeg_version;
+ video_attributes->film_mode = attributes.film_mode;
+ video_attributes->letterboxed = attributes.letterboxed;
+ video_attributes->picture_size = attributes.picture_size;
+ video_attributes->bit_rate = attributes.bit_rate;
+ video_attributes->unknown1 = attributes.unknown1;
+ video_attributes->line21_cc_2 = attributes.line21_cc_2;
+ video_attributes->line21_cc_1 = attributes.line21_cc_1;
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_audio_change(dvdnav_t *self, int32_t audio)
+{
+ int32_t num;
+
+ if(!self) {
+ printerr("Passed a NULL pointer.");
+ return DVDNAV_STATUS_ERR;
+ }
+
+ num = dvdnav_get_nr_of_audio_streams(self);
+ pthread_mutex_lock(&self->vm_lock);
+ /* Set subp AUDIO if valid */
+ if((audio >= 0) && (audio <= num)) {
+ self->vm->state.AST_REG = audio;
+ } else {
+ //printerr("Passed an invalid audio number.");
+ pthread_mutex_unlock(&self->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ pthread_mutex_unlock(&self->vm_lock);
+
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_subpicture_change(dvdnav_t *self, int32_t subpicture)
+{
+ int32_t num;
+
+ if(!self) {
+ printerr("Passed a NULL pointer.");
+ return DVDNAV_STATUS_ERR;
+ }
+
+ num = dvdnav_get_nr_of_subtitle_streams(self);
+ pthread_mutex_lock(&self->vm_lock);
+ /* Set subp SPRM if valid */
+ if((subpicture >= 0) && (subpicture <= num)) {
+ self->vm->state.SPST_REG = subpicture | 0x40;
+ } else if (subpicture & 0x80) {
+ self->vm->state.SPST_REG = subpicture & ~0x80;
+ } else {
+ self->vm->state.SPST_REG = subpicture;
+ //printerr("Passed an invalid subpicture number.");
+ //pthread_mutex_unlock(&self->vm_lock);
+ //return DVDNAV_STATUS_ERR;
+ }
+ pthread_mutex_unlock(&self->vm_lock);
+
+ return DVDNAV_STATUS_OK;
+}
+
+void dvdnav_lock(dvdnav_t *self)
+{
+ // we do not check for null pointer problems
+ pthread_mutex_lock(&self->vm_lock);
+}
+
+void dvdnav_unlock(dvdnav_t *self)
+{
+ // we do not check for null pointer problems
+ pthread_mutex_unlock(&self->vm_lock);
+}
+
+#endif // _XBMC
+
diff --git a/lib/libdvd/libdvdnav/src/dvdnav.h b/lib/libdvd/libdvdnav/src/dvdnav.h
new file mode 100644
index 0000000000..0a6d5db2cc
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/dvdnav.h
@@ -0,0 +1,720 @@
+/*
+ * Copyright (C) 2001 Rich Wareham <richwareham@users.sourceforge.net>
+ *
+ * This file is part of libdvdnav, a DVD navigation library.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: dvdnav.h 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+/*
+ * This is the main header file applications should include if they want
+ * to access dvdnav functionality.
+ */
+
+#ifndef DVDNAV_H_INCLUDED
+#define DVDNAV_H_INCLUDED
+
+#define MP_DVDNAV 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef DVDNAV_COMPILE
+# include <dvdnav/dvd_types.h>
+# include <dvdread/dvd_reader.h>
+# include <dvdread/nav_types.h>
+# include <dvdread/ifo_types.h> /* For vm_cmd_t */
+# include <dvdnav/dvdnav_events.h>
+#endif
+
+
+
+/*********************************************************************
+ * dvdnav data types *
+ *********************************************************************/
+
+/*
+ * Opaque data-type can be viewed as a 'DVD handle'. You should get
+ * a pointer to a dvdnav_t from the dvdnav_open() function.
+ * Never call free() on the pointer, you have to give it back with
+ * dvdnav_close().
+ */
+typedef struct dvdnav_s dvdnav_t;
+
+/* Status as reported by most of libdvdnav's functions */
+typedef int32_t dvdnav_status_t;
+
+/*
+ * Unless otherwise stated, all functions return DVDNAV_STATUS_OK if
+ * they succeeded, otherwise DVDNAV_STATUS_ERR is returned and the error may
+ * be obtained by calling dvdnav_err_to_string().
+ */
+#define DVDNAV_STATUS_ERR 0
+#define DVDNAV_STATUS_OK 1
+
+#define DVDNAV_FORMAT_AC3 0
+#define DVDNAV_FORMAT_MPEGAUDIO 3
+#define DVDNAV_FORMAT_LPCM 4
+#define DVDNAV_FORMAT_DTS 5
+#define DVDNAV_FORMAT_SDDS 6
+
+/*********************************************************************
+ * initialisation & housekeeping functions *
+ *********************************************************************/
+
+/*
+ * These functions allow you to open a DVD device and associate it
+ * with a dvdnav_t.
+ */
+
+/*
+ * Attempts to open the DVD drive at the specified path and pre-cache
+ * the CSS-keys. libdvdread is used to access the DVD, so any source
+ * supported by libdvdread can be given with "path". Currently,
+ * libdvdread can access: DVD drives, DVD image files, DVD file-by-file
+ * copies.
+ *
+ * The resulting dvdnav_t handle will be written to *dest.
+ */
+dvdnav_status_t dvdnav_open(dvdnav_t **dest, const char *path);
+
+/*
+ * Closes a dvdnav_t previously opened with dvdnav_open(), freeing any
+ * memory associated with it.
+ */
+dvdnav_status_t dvdnav_close(dvdnav_t *self);
+
+/*
+ * Resets the DVD virtual machine and cache buffers.
+ */
+dvdnav_status_t dvdnav_reset(dvdnav_t *self);
+
+/*
+ * Fills a pointer with a value pointing to a string describing
+ * the path associated with an open dvdnav_t. It assigns *path to NULL
+ * on error.
+ */
+dvdnav_status_t dvdnav_path(dvdnav_t *self, const char **path);
+
+/*
+ * Returns a human-readable string describing the last error.
+ */
+const char* dvdnav_err_to_string(dvdnav_t *self);
+
+
+/*********************************************************************
+ * changing and reading DVD player characteristics *
+ *********************************************************************/
+
+/*
+ * These functions allow you to manipulate the various global characteristics
+ * of the DVD playback engine.
+ */
+
+/*
+ * Sets the region mask (bit 0 set implies region 1, bit 1 set implies
+ * region 2, etc) of the virtual machine. Generally you will only need to set
+ * this if you are playing RCE discs which query the virtual machine as to its
+ * region setting.
+ *
+ * This has _nothing_ to do with the region setting of the DVD drive.
+ */
+dvdnav_status_t dvdnav_set_region_mask(dvdnav_t *self, int32_t region_mask);
+
+/*
+ * Returns the region mask (bit 0 set implies region 1, bit 1 set implies
+ * region 2, etc) of the virtual machine.
+ *
+ * This has _nothing_ to do with the region setting of the DVD drive.
+ */
+dvdnav_status_t dvdnav_get_region_mask(dvdnav_t *self, int32_t *region_mask);
+
+/*
+ * Specify whether read-ahead caching should be used. You may not want this if your
+ * decoding engine does its own buffering.
+ *
+ * The default read-ahead cache does not use an additional thread for the reading
+ * (see read_cache.c for a threaded cache, but note that this code is currently
+ * unmaintained). It prebuffers on VOBU level by reading ahead several buffers
+ * on every read request. The speed of this prebuffering has been optimized to
+ * also work on slow DVD drives.
+ *
+ * If in addition you want to prevent memcpy's to improve performance, have a look
+ * at dvdnav_get_next_cache_block().
+ */
+dvdnav_status_t dvdnav_set_readahead_flag(dvdnav_t *self, int32_t read_ahead_flag);
+
+/*
+ * Query whether read-ahead caching/buffering will be used.
+ */
+dvdnav_status_t dvdnav_get_readahead_flag(dvdnav_t *self, int32_t *read_ahead_flag);
+
+/*
+ * Specify whether the positioning works PGC or PG based.
+ * Programs (PGs) on DVDs are similar to Chapters and a program chain (PGC)
+ * usually covers a whole feature. This affects the behaviour of the
+ * functions dvdnav_get_position() and dvdnav_sector_search(). See there.
+ * Default is PG based positioning.
+ */
+dvdnav_status_t dvdnav_set_PGC_positioning_flag(dvdnav_t *self, int32_t pgc_based_flag);
+
+/*
+ * Query whether positioning is PG or PGC based.
+ */
+dvdnav_status_t dvdnav_get_PGC_positioning_flag(dvdnav_t *self, int32_t *pgc_based_flag);
+
+
+/*********************************************************************
+ * reading data *
+ *********************************************************************/
+
+/*
+ * These functions are used to poll the playback enginge and actually get data
+ * off the DVD.
+ */
+
+/*
+ * Attempts to get the next block off the DVD and copies it into the buffer 'buf'.
+ * If there is any special actions that may need to be performed, the value
+ * pointed to by 'event' gets set accordingly.
+ *
+ * If 'event' is DVDNAV_BLOCK_OK then 'buf' is filled with the next block
+ * (note that means it has to be at /least/ 2048 bytes big). 'len' is
+ * then set to 2048.
+ *
+ * Otherwise, buf is filled with an appropriate event structure and
+ * len is set to the length of that structure.
+ *
+ * See the dvdnav_events.h header for information on the various events.
+ */
+dvdnav_status_t dvdnav_get_next_block(dvdnav_t *self, uint8_t *buf,
+ int32_t *event, int32_t *len);
+
+/*
+ * This basically does the same as dvdnav_get_next_block. The only difference is
+ * that it avoids a memcopy, when the requested block was found in the cache.
+ * I such a case (cache hit) this function will return a different pointer than
+ * the one handed in, pointing directly into the relevant block in the cache.
+ * Those pointers must _never_ be freed but instead returned to the library via
+ * dvdnav_free_cache_block().
+ */
+dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t *self, uint8_t **buf,
+ int32_t *event, int32_t *len);
+
+/*
+ * All buffers which came from the internal cache (when dvdnav_get_next_cache_block()
+ * returned a buffer different from the one handed in) have to be freed with this
+ * function. Although handing in other buffers not from the cache doesn't cause any harm.
+ */
+dvdnav_status_t dvdnav_free_cache_block(dvdnav_t *self, unsigned char *buf);
+
+/*
+ * If we are currently in a still-frame this function skips it.
+ *
+ * See also the DVDNAV_STILL_FRAME event.
+ */
+dvdnav_status_t dvdnav_still_skip(dvdnav_t *self);
+
+/*
+ * If we are currently in WAIT state, that is: the application is required to
+ * wait for its fifos to become empty, calling this signals libdvdnav that this
+ * is achieved and that it can continue.
+ *
+ * See also the DVDNAV_WAIT event.
+ */
+dvdnav_status_t dvdnav_wait_skip(dvdnav_t *self);
+
+/*
+ * Returns the still time from the currently playing cell.
+ * The still time is given in seconds with 0xff meaning an indefinite still.
+ *
+ * This function can be used to detect still frames before they are reached.
+ * Some players might need this to prepare for a frame to be shown for a
+ * longer time than usual.
+ */
+uint32_t dvdnav_get_next_still_flag(dvdnav_t *self);
+
+/*
+ * Stops playback. The next event obtained with one of the get_next_block
+ * functions will be a DVDNAV_STOP event.
+ *
+ * It is not required to call this before dvdnav_close().
+ */
+dvdnav_status_t dvdnav_stop(dvdnav_t *self);
+
+
+/*********************************************************************
+ * title/part navigation *
+ *********************************************************************/
+
+/*
+ * Returns the number of titles on the disk.
+ */
+dvdnav_status_t dvdnav_get_number_of_titles(dvdnav_t *self, int32_t *titles);
+
+/*
+ * Returns the number of parts within the given title.
+ */
+dvdnav_status_t dvdnav_get_number_of_parts(dvdnav_t *self, int32_t title, int32_t *parts);
+
+/*
+ * Plays the specified title of the DVD from its beginning (that is: part 1).
+ */
+dvdnav_status_t dvdnav_title_play(dvdnav_t *self, int32_t title);
+
+/*
+ * Plays the specified title, starting from the specified part.
+ */
+dvdnav_status_t dvdnav_part_play(dvdnav_t *self, int32_t title, int32_t part);
+
+/*
+ * Stores in *times an array (that the application *must* free) of
+ * dvdtimes corresponding to the chapter times for the chosen title.
+ * *duration will have the duration of the title
+ * The number of entries in *times is the result of the function.
+ * On error *times is NULL and the output is 0
+ */
+uint32_t dvdnav_describe_title_chapters(dvdnav_t *self, int32_t title, uint64_t **times, uint64_t *duration);
+
+/*
+ * Play the specified amount of parts of the specified title of
+ * the DVD then STOP.
+ *
+ * Currently unimplemented!
+ */
+dvdnav_status_t dvdnav_part_play_auto_stop(dvdnav_t *self, int32_t title,
+ int32_t part, int32_t parts_to_play);
+
+/*
+ * Play the specified title starting from the specified time.
+ *
+ * Currently unimplemented!
+ */
+dvdnav_status_t dvdnav_time_play(dvdnav_t *self, int32_t title,
+ uint64_t time);
+
+/*
+ * Stop playing the current position and jump to the specified menu.
+ *
+ * See also DVDMenuID_t from libdvdread
+ */
+dvdnav_status_t dvdnav_menu_call(dvdnav_t *self, DVDMenuID_t menu);
+
+/*
+ * Return the title number and part currently being played.
+ * A title of 0 indicates, we are in a menu. In this case, part
+ * is set to the current menu's ID.
+ */
+dvdnav_status_t dvdnav_current_title_info(dvdnav_t *self, int32_t *title,
+ int32_t *part);
+
+/*
+ * Return the current position (in blocks) within the current
+ * title and the length (in blocks) of said title.
+ *
+ * Current implementation is wrong and likely to behave unpredictably!
+ * Use is discouraged!
+ */
+dvdnav_status_t dvdnav_get_position_in_title(dvdnav_t *self,
+ uint32_t *pos,
+ uint32_t *len);
+
+/*
+ * This function is only available for compatibility reasons.
+ *
+ * Stop playing the current position and start playback of the current title
+ * from the specified part.
+ */
+dvdnav_status_t dvdnav_part_search(dvdnav_t *self, int32_t part);
+
+
+/*********************************************************************
+ * program chain/program navigation *
+ *********************************************************************/
+
+/*
+ * Stop playing the current position and start playback from the last
+ * VOBU boundary before the given sector. The sector number is not
+ * meant to be an absolute physical DVD sector, but a relative sector
+ * in the current program. This function cannot leave the current
+ * program and will fail, if asked to do so.
+ *
+ * If program chain based positioning is enabled
+ * (see dvdnav_set_PGC_positioning_flag()), this will seek to the relative
+ * sector inside the current program chain.
+ *
+ * 'origin' can be one of SEEK_SET, SEEK_CUR, SEEK_END as defined in
+ * fcntl.h.
+ */
+dvdnav_status_t dvdnav_sector_search(dvdnav_t *self,
+ uint64_t offset, int32_t origin);
+
+/*
+ returns the current stream time in PTS ticks as reported by the IFO structures
+ divide it by 90000 to get the current play time in seconds
+ */
+int64_t dvdnav_get_current_time(dvdnav_t *self);
+
+/*
+ * Stop playing the current position and start playback of the title
+ * from the specified timecode.
+ *
+ * Currently unimplemented!
+ */
+dvdnav_status_t dvdnav_time_search(dvdnav_t *self,
+ uint64_t time);
+
+/*
+ * Stop playing current position and play the "GoUp"-program chain.
+ * (which generally leads to the title menu or a higer-level menu).
+ */
+dvdnav_status_t dvdnav_go_up(dvdnav_t *self);
+
+/*
+ * Stop playing the current position and start playback at the
+ * previous program (if it exists).
+ */
+dvdnav_status_t dvdnav_prev_pg_search(dvdnav_t *self);
+
+/*
+ * Stop playing the current position and start playback at the
+ * first program.
+ */
+dvdnav_status_t dvdnav_top_pg_search(dvdnav_t *self);
+
+/*
+ * Stop playing the current position and start playback at the
+ * next program (if it exists).
+ */
+dvdnav_status_t dvdnav_next_pg_search(dvdnav_t *self);
+
+/*
+ * Return the current position (in blocks) within the current
+ * program and the length (in blocks) of current program.
+ *
+ * If program chain based positioning is enabled
+ * (see dvdnav_set_PGC_positioning_flag()), this will return the
+ * relative position in and the length of the current program chain.
+ */
+dvdnav_status_t dvdnav_get_position(dvdnav_t *self, uint32_t *pos,
+ uint32_t *len);
+
+
+/*********************************************************************
+ * menu highlights *
+ *********************************************************************/
+
+/*
+ * Most functions related to highlights take a NAV PCI packet as a parameter.
+ * While you can get the such a packet from libdvdnav, for players with internal
+ * FIFOs, this will result in errors, because due to the FIFO length, libdvdnav will
+ * be ahead in the stream compared to what the user is seeing on screen.
+ * Therefore, player applications who have a NAV packet available, which is
+ * better in sync with the actual playback should always pass this one to these
+ * functions.
+ */
+
+/*
+ * Get the currently highlighted button
+ * number (1..36) or 0 if no button is highlighted.
+ */
+dvdnav_status_t dvdnav_get_current_highlight(dvdnav_t *self, int32_t *button);
+
+/*
+ * Returns the Presentation Control Information (PCI) structure associated
+ * with the current position.
+ *
+ * Read the general notes above.
+ * See also libdvdreads nav_types.h for definition of pci_t.
+ */
+pci_t* dvdnav_get_current_nav_pci(dvdnav_t *self);
+
+/*
+ * Returns the DSI (data search information) structure associated
+ * with the current position.
+ *
+ * Read the general notes above.
+ * See also libdvdreads nav_types.h for definition of dsi_t.
+ */
+dsi_t* dvdnav_get_current_nav_dsi(dvdnav_t *self);
+
+/*
+ * Get the area associated with a certain button.
+ */
+dvdnav_status_t dvdnav_get_highlight_area(pci_t *nav_pci , int32_t button, int32_t mode,
+ dvdnav_highlight_area_t *highlight);
+
+/*
+ * Move button highlight around as suggested by function name (e.g. with arrow keys).
+ */
+dvdnav_status_t dvdnav_upper_button_select(dvdnav_t *self, pci_t *pci);
+dvdnav_status_t dvdnav_lower_button_select(dvdnav_t *self, pci_t *pci);
+dvdnav_status_t dvdnav_right_button_select(dvdnav_t *self, pci_t *pci);
+dvdnav_status_t dvdnav_left_button_select(dvdnav_t *self, pci_t *pci);
+
+/*
+ * Activate ("press") the currently highlighted button.
+ */
+dvdnav_status_t dvdnav_button_activate(dvdnav_t *self, pci_t *pci);
+
+/*
+ * Highlight a specific button.
+ */
+dvdnav_status_t dvdnav_button_select(dvdnav_t *self, pci_t *pci, int32_t button);
+
+/*
+ * Activate ("press") specified button.
+ */
+dvdnav_status_t dvdnav_button_select_and_activate(dvdnav_t *self, pci_t *pci, int32_t button);
+
+/*
+ * Activate (press) a button and execute specified command.
+ */
+dvdnav_status_t dvdnav_button_activate_cmd(dvdnav_t *self, int32_t button, vm_cmd_t *cmd);
+
+/*
+ * Select button at specified video frame coordinates.
+ */
+dvdnav_status_t dvdnav_mouse_select(dvdnav_t *self, pci_t *pci, int32_t x, int32_t y);
+
+/*
+ * Activate ("press") button at specified video frame coordinates.
+ */
+dvdnav_status_t dvdnav_mouse_activate(dvdnav_t *self, pci_t *pci, int32_t x, int32_t y);
+
+
+/*********************************************************************
+ * languages *
+ *********************************************************************/
+
+/*
+ * The language codes expected by these functions are two character
+ * codes as defined in ISO639.
+ */
+
+/*
+ * Set which menu language we should use per default.
+ */
+dvdnav_status_t dvdnav_menu_language_select(dvdnav_t *self,
+ char *code);
+
+/*
+ * Set which audio language we should use per default.
+ */
+dvdnav_status_t dvdnav_audio_language_select(dvdnav_t *self,
+ char *code);
+
+/*
+ * Set which spu language we should use per default.
+ */
+dvdnav_status_t dvdnav_spu_language_select(dvdnav_t *self,
+ char *code);
+
+
+/*********************************************************************
+ * obtaining stream attributes *
+ *********************************************************************/
+
+/*
+ * Return a string describing the title of the DVD.
+ * This is an ID string encoded on the disc by the author. In many cases
+ * this is a descriptive string such as `THE_MATRIX' but sometimes is sigularly
+ * uninformative such as `PDVD-011421'. Some DVD authors even forget to set this,
+ * so you may also read the default of the authoring software they used, like
+ * `DVDVolume'.
+ */
+dvdnav_status_t dvdnav_get_title_string(dvdnav_t *self, const char **title_str);
+
+/*
+ * Get video aspect code.
+ * The aspect code does only change on VTS boundaries.
+ * See the DVDNAV_VTS_CHANGE event.
+ *
+ * 0 -- 4:3, 2 -- 16:9
+ */
+uint8_t dvdnav_get_video_aspect(dvdnav_t *self);
+
+/*
+ * Get video scaling permissions.
+ * The scaling permission does only change on VTS boundaries.
+ * See the DVDNAV_VTS_CHANGE event.
+ *
+ * bit0 set = deny letterboxing, bit1 set = deny pan&scan
+ */
+uint8_t dvdnav_get_video_scale_permission(dvdnav_t *self);
+
+/*
+ * Converts a *logical* audio stream id into language code
+ * (returns 0xffff if no such stream).
+ */
+uint16_t dvdnav_audio_stream_to_lang(dvdnav_t *self, uint8_t stream);
+
+/*
+ * Returns the format of *logical* audio stream 'stream'
+ * (returns 0xffff if no such stream).
+ */
+uint16_t dvdnav_audio_stream_format(dvdnav_t *self, uint8_t stream);
+
+/*
+ * Returns number of channelsn in *logical* audio stream 'stream'
+ * (returns 0xffff if no such stream).
+ */
+uint16_t dvdnav_audio_stream_channels(dvdnav_t *self, uint8_t stream);
+
+/*
+ * Converts a *logical* subpicture stream id into country code
+ * (returns 0xffff if no such stream).
+ */
+uint16_t dvdnav_spu_stream_to_lang(dvdnav_t *self, uint8_t stream);
+
+/*
+ * Converts a *physical* (MPEG) audio stream id into a logical stream number.
+ */
+int8_t dvdnav_get_audio_logical_stream(dvdnav_t *self, uint8_t audio_num);
+
+#define HAVE_GET_AUDIO_ATTR
+/*
+ * Get audio attr
+ */
+dvdnav_status_t dvdnav_get_audio_attr(dvdnav_t *self, uint8_t audio_mum, audio_attr_t *audio_attr);
+
+/*
+ * Converts a *physical* (MPEG) subpicture stream id into a logical stream number.
+ */
+int8_t dvdnav_get_spu_logical_stream(dvdnav_t *self, uint8_t subp_num);
+
+#define HAVE_GET_SPU_ATTR
+/*
+ * Get spu attr
+ */
+dvdnav_status_t dvdnav_get_spu_attr(dvdnav_t *self, uint8_t audio_mum, subp_attr_t *subp_attr);
+
+/*
+ * Get active audio stream.
+ */
+int8_t dvdnav_get_active_audio_stream(dvdnav_t *self);
+
+/*
+ * Get active spu stream.
+ */
+int8_t dvdnav_get_active_spu_stream(dvdnav_t *self);
+
+/*
+ * Get the set of user operations that are currently prohibited.
+ * There are potentially new restrictions right after
+ * DVDNAV_CHANNEL_HOP and DVDNAV_NAV_PACKET.
+ */
+user_ops_t dvdnav_get_restrictions(dvdnav_t *self);
+
+
+/*********************************************************************
+ * multiple angles *
+ *********************************************************************/
+
+/*
+ * The libdvdnav library abstracts away the difference between seamless and
+ * non-seamless angles. From the point of view of the programmer you just set the
+ * angle number and all is well in the world. You will always see only the
+ * selected angle coming from the get_next_block functions.
+ *
+ * Note:
+ * It is quite possible that some tremendously strange DVD feature might change the
+ * angle number from under you. Generally you should always view the results from
+ * dvdnav_get_angle_info() as definitive only up to the next time you call
+ * dvdnav_get_next_block().
+ */
+
+/*
+ * Sets the current angle. If you try to follow a non existant angle
+ * the call fails.
+ */
+dvdnav_status_t dvdnav_angle_change(dvdnav_t *self, int32_t angle);
+
+/*
+ * Returns the current angle and number of angles present.
+ */
+dvdnav_status_t dvdnav_get_angle_info(dvdnav_t *self, int32_t *current_angle,
+ int32_t *number_of_angles);
+
+/*********************************************************************
+ * domain queries *
+ *********************************************************************/
+
+/*
+ * Are we in the First Play domain?
+ */
+int8_t dvdnav_is_domain_fp(dvdnav_t *self);
+
+/*
+ * Are we in the Video management Menu domain?
+ */
+int8_t dvdnav_is_domain_vmgm(dvdnav_t *self);
+
+/*
+ * Are we in the Video Title Menu domain?
+ */
+int8_t dvdnav_is_domain_vtsm(dvdnav_t *self);
+
+/*
+ * Are we in the Video Title Set domain?
+ */
+int8_t dvdnav_is_domain_vts(dvdnav_t *self);
+
+////////// RATDVD stuff ///////////////
+
+/*
+ * Get the number of audio streams.
+ */
+int32_t dvdnav_get_audio_stream_count(dvdnav_t * self);
+
+/*
+ * Get the number of subpicture streams.
+ */
+int32_t dvdnav_get_subpicture_stream_count(dvdnav_t * self);
+
+/*
+ * Get attributes of the current audio stream.
+ */
+dvdnav_status_t dvdnav_get_audio_info(dvdnav_t * self, int32_t streamid, audio_attr_t* audio_attributes);
+
+/*
+ * Get attributes of the current subpicture stream.
+ */
+dvdnav_status_t dvdnav_get_stitle_info(dvdnav_t * self, int32_t streamid, subp_attr_t* stitle_attributes);
+
+/*
+ * Get information about the current video stream
+ */
+dvdnav_status_t dvdnav_get_video_info(dvdnav_t * self, video_attr_t* video_attributes);
+
+/*
+ * Select the audio stream to be played
+ */
+dvdnav_status_t dvdnav_audio_change(dvdnav_t *self, int32_t audio);
+
+/*
+ * Select the spu stream to be displayed
+ */
+dvdnav_status_t dvdnav_subpicture_change(dvdnav_t *self, int32_t subpicture);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DVDNAV_H_INCLUDED */
diff --git a/lib/libdvd/libdvdnav/src/dvdnav_events.h b/lib/libdvd/libdvdnav/src/dvdnav_events.h
new file mode 100644
index 0000000000..a4d460eeca
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/dvdnav_events.h
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2001 Rich Wareham <richwareham@users.sourceforge.net>
+ *
+ * This file is part of libdvdnav, a DVD navigation library.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: dvdnav_events.h 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+/*
+ * This header defines events and event types
+ */
+
+#ifndef DVDNAV_EVENTS_H_INCLUDED
+#define DVDNAV_EVENTS_H_INCLUDED
+
+/*
+ * DVDNAV_BLOCK_OK
+ *
+ * A regular data block from the DVD has been returned.
+ * This one should be demuxed and decoded for playback.
+ */
+#define DVDNAV_BLOCK_OK 0
+
+
+/*
+ * DVDNAV_NOP
+ *
+ * Just ignore this.
+ */
+#define DVDNAV_NOP 1
+
+
+/*
+ * DVDNAV_STILL_FRAME
+ *
+ * We have reached a still frame. The player application should wait
+ * the amount of time specified by the still's length while still handling
+ * user input to make menus and other interactive stills work.
+ * The last delivered frame should be kept showing.
+ * Once the still has timed out, call dvdnav_skip_still().
+ * A length of 0xff means an infinite still which has to be skipped
+ * indirectly by some user interaction.
+ */
+#define DVDNAV_STILL_FRAME 2
+
+typedef struct {
+ /* The length (in seconds) the still frame should be displayed for,
+ * or 0xff if infinite. */
+ int length;
+} dvdnav_still_event_t;
+
+
+/*
+ * DVDNAV_SPU_STREAM_CHANGE
+ *
+ * Inform the SPU decoding/overlaying engine to switch SPU channels.
+ */
+#define DVDNAV_SPU_STREAM_CHANGE 3
+
+typedef struct {
+ /* The physical (MPEG) stream number for widescreen SPU display.
+ * Use this, if you blend the SPU on an anamorphic image before
+ * unsqueezing it. */
+ int physical_wide;
+
+ /* The physical (MPEG) stream number for letterboxed display.
+ * Use this, if you blend the SPU on an anamorphic image after
+ * unsqueezing it. */
+ int physical_letterbox;
+
+ /* The physical (MPEG) stream number for pan&scan display.
+ * Use this, if you blend the SPU on an anamorphic image after
+ * unsqueezing it the pan&scan way. */
+ int physical_pan_scan;
+
+ /* The logical (DVD) stream number. */
+ int logical;
+} dvdnav_spu_stream_change_event_t;
+
+
+/*
+ * DVDNAV_AUDIO_STREAM_CHANGE
+ *
+ * Inform the audio decoder to switch channels.
+ */
+#define DVDNAV_AUDIO_STREAM_CHANGE 4
+
+typedef struct {
+ /* The physical (MPEG) stream number. */
+ int physical;
+
+ /* The logical (DVD) stream number. */
+ int logical;
+} dvdnav_audio_stream_change_event_t;
+
+
+/*
+ * DVDNAV_VTS_CHANGE
+ *
+ * Some status information like video aspect and video scale permissions do
+ * not change inside a VTS. Therefore this event can be used to query such
+ * information only when necessary and update the decoding/displaying
+ * accordingly.
+ */
+#define DVDNAV_VTS_CHANGE 5
+
+typedef struct {
+ int old_vtsN; /* the old VTS number */
+ dvd_read_domain_t old_domain; /* the old domain */
+ int new_vtsN; /* the new VTS number */
+ dvd_read_domain_t new_domain; /* the new domain */
+} dvdnav_vts_change_event_t;
+
+
+/*
+ * DVDNAV_CELL_CHANGE
+ *
+ * Some status information like the current Title and Part numbers do not
+ * change inside a cell. Therefore this event can be used to query such
+ * information only when necessary and update the decoding/displaying
+ * accordingly.
+ * Some useful information for accurate time display is also reported
+ * together with this event.
+ */
+#define DVDNAV_CELL_CHANGE 6
+
+typedef struct {
+ int cellN; /* the new cell number */
+ int pgN; /* the current program number */
+ int64_t cell_length; /* the length of the current cell in PTS ticks */
+ int64_t pg_length; /* the length of the current program in PTS ticks */
+ int64_t pgc_length; /* the length of the current program chain in PTS ticks */
+ int64_t cell_start; /* the start time of the current cell relatively to the PGC in PTS ticks */
+ int64_t pg_start; /* the start time of the current PG relatively to the PGC in PTS ticks */
+} dvdnav_cell_change_event_t;
+
+
+/*
+ * DVDNAV_NAV_PACKET
+ *
+ * NAV packets are useful for various purposes. They define the button
+ * highlight areas and VM commands of DVD menus, so they should in any
+ * case be sent to the SPU decoder/overlaying engine for the menus to work.
+ * NAV packets also provide a way to detect PTS discontinuities, because
+ * they carry the start and end PTS values for the current VOBU.
+ * (pci.vobu_s_ptm and pci.vobu_e_ptm) Whenever the start PTS of the
+ * current NAV does not match the end PTS of the previous NAV, a PTS
+ * discontinuity has occured.
+ * NAV packets can also be used for time display, because they are
+ * timestamped relatively to the current Cell.
+ */
+#define DVDNAV_NAV_PACKET 7
+
+
+/*
+ * DVDNAV_STOP
+ *
+ * Applications should end playback here. A subsequent dvdnav_get_next_block()
+ * call will restart the VM from the beginning of the DVD.
+ */
+#define DVDNAV_STOP 8
+
+
+/*
+ * DVDNAV_HIGHLIGHT
+ *
+ * The current button highlight changed. Inform the overlaying engine to
+ * highlight a different button. Please note, that at the moment only mode 1
+ * highlights are reported this way. That means, when the button highlight
+ * has been moved around by some function call, you will receive an event
+ * telling you the new button. But when a button gets activated, you have
+ * to handle the mode 2 highlighting (that is some different colour the
+ * button turns to on activation) in your application.
+ */
+#define DVDNAV_HIGHLIGHT 9
+
+typedef struct {
+ /* highlight mode: 0 - hide, 1 - show, 2 - activate, currently always 1 */
+ int display;
+
+ /* FIXME: these fields are currently not set */
+ uint32_t palette; /* The CLUT entries for the highlight palette
+ (4-bits per entry -> 4 entries) */
+ uint16_t sx,sy,ex,ey; /* The start/end x,y positions */
+ uint32_t pts; /* Highlight PTS to match with SPU */
+
+ /* button number for the SPU decoder/overlaying engine */
+ uint32_t buttonN;
+} dvdnav_highlight_event_t;
+
+
+/*
+ * DVDNAV_SPU_CLUT_CHANGE
+ *
+ * Inform the SPU decoder/overlaying engine to update its colour lookup table.
+ * The CLUT is given as 16 uint32_t's in the buffer.
+ */
+#define DVDNAV_SPU_CLUT_CHANGE 10
+
+
+/*
+ * DVDNAV_HOP_CHANNEL
+ *
+ * A non-seamless operation has been performed. Applications can drop all
+ * their internal fifo's content, which will speed up the response.
+ */
+#define DVDNAV_HOP_CHANNEL 12
+
+
+/*
+ * DVDNAV_WAIT
+ *
+ * We have reached a point in DVD playback, where timing is critical.
+ * Player application with internal fifos can introduce state
+ * inconsistencies, because libdvdnav is always the fifo's length
+ * ahead in the stream compared to what the application sees.
+ * Such applications should wait until their fifos are empty
+ * when they receive this type of event.
+ * Once this is achieved, call dvdnav_skip_wait().
+ */
+#define DVDNAV_WAIT 13
+
+
+#endif /* DVDNAV_EVENTS_H_INCLUDED */
diff --git a/lib/libdvd/libdvdnav/src/dvdnav_internal.h b/lib/libdvd/libdvdnav/src/dvdnav_internal.h
new file mode 100644
index 0000000000..996723ea7e
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/dvdnav_internal.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2001-2004 Rich Wareham <richwareham@users.sourceforge.net>
+ *
+ * This file is part of libdvdnav, a DVD navigation library.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: dvdnav_internal.h 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+#ifndef DVDNAV_INTERNAL_H_INCLUDED
+#define DVDNAV_INTERNAL_H_INCLUDED
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* Uncomment for VM command tracing */
+/* #define TRACE */
+
+#include "decoder.h"
+#include "dvdnav.h"
+#include "vm.h"
+#include "vmcmd.h"
+
+#ifdef WIN32
+
+/* pthread_mutex_* wrapper for win32 */
+#include <windows.h>
+#include <process.h>
+typedef CRITICAL_SECTION pthread_mutex_t;
+#define pthread_mutex_init(a, b) InitializeCriticalSection(a)
+#define pthread_mutex_lock(a) EnterCriticalSection(a)
+#define pthread_mutex_unlock(a) LeaveCriticalSection(a)
+#define pthread_mutex_destroy(a)
+
+#ifndef HAVE_GETTIMEOFDAY
+/* replacement gettimeofday implementation */
+#include <sys/timeb.h>
+static inline int _private_gettimeofday( struct timeval *tv, void *tz )
+{
+ struct timeb t;
+ ftime( &t );
+ tv->tv_sec = t.time;
+ tv->tv_usec = t.millitm * 1000;
+ return 0;
+}
+#define gettimeofday(TV, TZ) _private_gettimeofday((TV), (TZ))
+#endif
+
+#include <io.h> /* read() */
+#define lseek64 _lseeki64
+
+#else
+
+#include <pthread.h>
+
+#endif /* WIN32 */
+
+/* where should libdvdnav write its messages (stdout/stderr) */
+#define MSG_OUT stdout
+
+/* Maximum length of an error string */
+#define MAX_ERR_LEN 255
+
+/* Use the POSIX PATH_MAX if available */
+#ifdef PATH_MAX
+#define MAX_PATH_LEN PATH_MAX
+#else
+#define MAX_PATH_LEN 255 /* Arbitrary */
+#endif
+
+#ifndef DVD_VIDEO_LB_LEN
+#define DVD_VIDEO_LB_LEN 2048
+#endif
+
+typedef struct read_cache_s read_cache_t;
+
+/*
+ * These are defined here because they are
+ * not in ifo_types.h, they maybe one day
+ */
+
+#ifndef audio_status_t
+typedef struct {
+#ifdef WORDS_BIGENDIAN
+ unsigned int available : 1;
+ unsigned int zero1 : 4;
+ unsigned int stream_number : 3;
+ uint8_t zero2;
+#else
+ uint8_t zero2;
+ unsigned int stream_number : 3;
+ unsigned int zero1 : 4;
+ unsigned int available : 1;
+#endif
+} ATTRIBUTE_PACKED audio_status_t;
+#endif
+
+#ifndef spu_status_t
+typedef struct {
+#ifdef WORDS_BIGENDIAN
+ unsigned int available : 1;
+ unsigned int zero1 : 2;
+ unsigned int stream_number_4_3 : 5;
+ unsigned int zero2 : 3;
+ unsigned int stream_number_wide : 5;
+ unsigned int zero3 : 3;
+ unsigned int stream_number_letterbox : 5;
+ unsigned int zero4 : 3;
+ unsigned int stream_number_pan_scan : 5;
+#else
+ unsigned int stream_number_pan_scan : 5;
+ unsigned int zero4 : 3;
+ unsigned int stream_number_letterbox : 5;
+ unsigned int zero3 : 3;
+ unsigned int stream_number_wide : 5;
+ unsigned int zero2 : 3;
+ unsigned int stream_number_4_3 : 5;
+ unsigned int zero1 : 2;
+ unsigned int available : 1;
+#endif
+} ATTRIBUTE_PACKED spu_status_t;
+#endif
+
+typedef struct dvdnav_vobu_s {
+ int32_t vobu_start; /* Logical Absolute. MAX needed is 0x300000 */
+ int32_t vobu_length;
+ int32_t blockN; /* Relative offset */
+ int32_t vobu_next; /* Relative offset */
+} dvdnav_vobu_t;
+
+/** The main DVDNAV type **/
+
+struct dvdnav_s {
+ /* General data */
+ char path[MAX_PATH_LEN]; /* Path to DVD device/dir */
+ dvd_file_t *file; /* Currently opened file */
+
+ /* Position data */
+ vm_position_t position_next;
+ vm_position_t position_current;
+ dvdnav_vobu_t vobu;
+
+ /* NAV data */
+ pci_t pci;
+ dsi_t dsi;
+ uint32_t last_cmd_nav_lbn; /* detects when a command is issued on an already left NAV */
+
+ /* Flags */
+ int skip_still; /* Set when skipping a still */
+ int sync_wait; /* applications should wait till they are in sync with us */
+ int sync_wait_skip; /* Set when skipping wait state */
+ int spu_clut_changed; /* The SPU CLUT changed */
+ int started; /* vm_start has been called? */
+ int use_read_ahead; /* 1 - use read-ahead cache, 0 - don't */
+ int pgc_based; /* positioning works PGC based instead of PG based */
+ int cur_cell_time; /* time expired since the beginning of the current cell, read from the dsi */
+
+ /* VM */
+ vm_t *vm;
+ pthread_mutex_t vm_lock;
+
+ /* Read-ahead cache */
+ read_cache_t *cache;
+
+ /* Errors */
+ char err_str[MAX_ERR_LEN];
+};
+
+/** HELPER FUNCTIONS **/
+
+/* converts a dvd_time_t to PTS ticks */
+int64_t dvdnav_convert_time(dvd_time_t *time);
+
+/*
+ * Get current playback state
+ */
+dvdnav_status_t dvdnav_get_state(dvdnav_t *this, dvd_state_t *save_state);
+
+/*
+ * Resume playback state
+ */
+dvdnav_status_t dvdnav_set_state(dvdnav_t *this, dvd_state_t *save_state);
+
+
+
+/** USEFUL MACROS **/
+
+#ifdef __GNUC__
+#define printerrf(format, args...) \
+ do { if (this) snprintf(this->err_str, MAX_ERR_LEN, format, ## args); } while (0)
+#else
+#ifdef _MSC_VER
+#define printerrf(str) \
+ do { if (this) snprintf(this->err_str, MAX_ERR_LEN, str); } while (0)
+#else
+#define printerrf(...) \
+ do { if (this) snprintf(this->err_str, MAX_ERR_LEN, __VA_ARGS__); } while (0)
+#endif /* WIN32 */
+#endif
+#define printerr(str) \
+ do { if (this) strncpy(this->err_str, str, MAX_ERR_LEN - 1); } while (0)
+
+#endif /* DVDNAV_INTERNAL_H_INCLUDED */
diff --git a/lib/libdvd/libdvdnav/src/highlight.c b/lib/libdvd/libdvdnav/src/highlight.c
new file mode 100644
index 0000000000..bdf652a5b2
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/highlight.c
@@ -0,0 +1,497 @@
+/*
+ * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
+ *
+ * This file is part of libdvdnav, a DVD navigation library.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: highlight.c 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/time.h>
+#include <dvdread/nav_types.h>
+#include "dvd_types.h"
+#include "remap.h"
+#include "vm/decoder.h"
+#include "vm/vm.h"
+#include "vm/vmcmd.h"
+#include "dvdnav_internal.h"
+#include "dvdnav.h"
+
+/*
+#define BUTTON_TESTING
+*/
+
+#ifdef BUTTON_TESTING
+
+#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);
+
+ fprintf(MSG_OUT,"%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;
+ }
+ fprintf(MSG_OUT," @ %s fps", rate);
+}
+
+static void nav_print_PCI_GI(pci_gi_t *pci_gi) {
+ int32_t i;
+
+ fprintf(MSG_OUT,"libdvdnav: pci_gi:\n");
+ fprintf(MSG_OUT,"libdvdnav: nv_pck_lbn 0x%08x\n", pci_gi->nv_pck_lbn);
+ fprintf(MSG_OUT,"libdvdnav: vobu_cat 0x%04x\n", pci_gi->vobu_cat);
+ fprintf(MSG_OUT,"libdvdnav: vobu_uop_ctl 0x%08x\n", *(uint32_t*)&pci_gi->vobu_uop_ctl);
+ fprintf(MSG_OUT,"libdvdnav: vobu_s_ptm 0x%08x\n", pci_gi->vobu_s_ptm);
+ fprintf(MSG_OUT,"libdvdnav: vobu_e_ptm 0x%08x\n", pci_gi->vobu_e_ptm);
+ fprintf(MSG_OUT,"libdvdnav: vobu_se_e_ptm 0x%08x\n", pci_gi->vobu_se_e_ptm);
+ fprintf(MSG_OUT,"libdvdnav: e_eltm ");
+ print_time(&pci_gi->e_eltm);
+ fprintf(MSG_OUT,"\n");
+
+ fprintf(MSG_OUT,"libdvdnav: vobu_isrc \"");
+ for(i = 0; i < 32; i++) {
+ char c = pci_gi->vobu_isrc[i];
+ if((c >= ' ') && (c <= '~'))
+ fprintf(MSG_OUT,"%c", c);
+ else
+ fprintf(MSG_OUT,".");
+ }
+ fprintf(MSG_OUT,"\"\n");
+}
+
+static void nav_print_NSML_AGLI(nsml_agli_t *nsml_agli) {
+ int32_t i, j = 0;
+
+ for(i = 0; i < 9; i++)
+ j |= nsml_agli->nsml_agl_dsta[i];
+ if(j == 0)
+ return;
+
+ fprintf(MSG_OUT,"libdvdnav: nsml_agli:\n");
+ for(i = 0; i < 9; i++)
+ if(nsml_agli->nsml_agl_dsta[i])
+ fprintf(MSG_OUT,"libdvdnav: nsml_agl_c%d_dsta 0x%08x\n", i + 1,
+ nsml_agli->nsml_agl_dsta[i]);
+}
+
+static void nav_print_HL_GI(hl_gi_t *hl_gi, int32_t *btngr_ns, int32_t *btn_ns) {
+
+ if((hl_gi->hli_ss & 0x03) == 0)
+ return;
+
+ fprintf(MSG_OUT,"libdvdnav: hl_gi:\n");
+ fprintf(MSG_OUT,"libdvdnav: hli_ss 0x%01x\n", hl_gi->hli_ss & 0x03);
+ fprintf(MSG_OUT,"libdvdnav: hli_s_ptm 0x%08x\n", hl_gi->hli_s_ptm);
+ fprintf(MSG_OUT,"libdvdnav: hli_e_ptm 0x%08x\n", hl_gi->hli_e_ptm);
+ fprintf(MSG_OUT,"libdvdnav: btn_se_e_ptm 0x%08x\n", hl_gi->btn_se_e_ptm);
+
+ *btngr_ns = hl_gi->btngr_ns;
+ fprintf(MSG_OUT,"libdvdnav: btngr_ns %d\n", hl_gi->btngr_ns);
+ fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty 0x%02x\n", 1, hl_gi->btngr1_dsp_ty);
+ fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty 0x%02x\n", 2, hl_gi->btngr2_dsp_ty);
+ fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty 0x%02x\n", 3, hl_gi->btngr3_dsp_ty);
+
+ fprintf(MSG_OUT,"libdvdnav: btn_ofn %d\n", hl_gi->btn_ofn);
+ *btn_ns = hl_gi->btn_ns;
+ fprintf(MSG_OUT,"libdvdnav: btn_ns %d\n", hl_gi->btn_ns);
+ fprintf(MSG_OUT,"libdvdnav: nsl_btn_ns %d\n", hl_gi->nsl_btn_ns);
+ fprintf(MSG_OUT,"libdvdnav: fosl_btnn %d\n", hl_gi->fosl_btnn);
+ fprintf(MSG_OUT,"libdvdnav: foac_btnn %d\n", hl_gi->foac_btnn);
+}
+
+static void nav_print_BTN_COLIT(btn_colit_t *btn_colit) {
+ int32_t i, j;
+
+ j = 0;
+ for(i = 0; i < 6; i++)
+ j |= btn_colit->btn_coli[i/2][i&1];
+ if(j == 0)
+ return;
+
+ fprintf(MSG_OUT,"libdvdnav: btn_colit:\n");
+ for(i = 0; i < 3; i++)
+ for(j = 0; j < 2; j++)
+ fprintf(MSG_OUT,"libdvdnav: btn_cqoli %d %s_coli: %08x\n",
+ i, (j == 0) ? "sl" : "ac",
+ btn_colit->btn_coli[i][j]);
+}
+
+static void nav_print_BTNIT(btni_t *btni_table, int32_t btngr_ns, int32_t btn_ns) {
+ int32_t i, j, k;
+
+ fprintf(MSG_OUT,"libdvdnav: btnit:\n");
+ fprintf(MSG_OUT,"libdvdnav: btngr_ns: %i\n", btngr_ns);
+ fprintf(MSG_OUT,"libdvdnav: 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];
+
+ fprintf(MSG_OUT,"libdvdnav: group %d btni %d: ", i+1, j+1);
+ fprintf(MSG_OUT,"btn_coln %d, auto_action_mode %d\n",
+ btni->btn_coln, btni->auto_action_mode);
+ fprintf(MSG_OUT,"libdvdnav: coords (%d, %d) .. (%d, %d)\n",
+ btni->x_start, btni->y_start, btni->x_end, btni->y_end);
+
+ fprintf(MSG_OUT,"libdvdnav: up %d, ", btni->up);
+ fprintf(MSG_OUT,"down %d, ", btni->down);
+ fprintf(MSG_OUT,"left %d, ", btni->left);
+ fprintf(MSG_OUT,"right %d\n", btni->right);
+ for(k = 0; k < 8; k++) {
+ fprintf(MSG_OUT, "libdvdnav: %02x ", btni->cmd.bytes[k]);
+ }
+ fprintf(MSG_OUT, "| ");
+#ifdef TRACE
+ vm_print_mnemonic(&btni->cmd);
+#endif
+ fprintf(MSG_OUT, "\n");
+ }
+ }
+ }
+}
+
+static void nav_print_HLI(hli_t *hli) {
+ int32_t btngr_ns = 0, btn_ns = 0;
+
+ fprintf(MSG_OUT,"libdvdnav: hli:\n");
+ nav_print_HL_GI(&hli->hl_gi, & btngr_ns, & btn_ns);
+ nav_print_BTN_COLIT(&hli->btn_colit);
+ nav_print_BTNIT(hli->btnit, btngr_ns, btn_ns);
+}
+
+void nav_print_PCI(pci_t *pci) {
+ fprintf(MSG_OUT,"libdvdnav: pci packet:\n");
+ nav_print_PCI_GI(&pci->pci_gi);
+ nav_print_NSML_AGLI(&pci->nsml_agli);
+ nav_print_HLI(&pci->hli);
+}
+
+#endif
+
+
+/* Highlighting API calls */
+
+dvdnav_status_t dvdnav_get_current_highlight(dvdnav_t *this, int32_t *button) {
+ /* Simply return the appropriate value based on the SPRM */
+ if(((*button) = this->position_current.button) == -1)
+ (*button) = this->vm->state.HL_BTNN_REG >> 10;
+
+ return DVDNAV_STATUS_OK;
+}
+
+static btni_t *get_current_button(dvdnav_t *this, pci_t *pci) {
+ int32_t button = 0;
+
+ if(!pci->hli.hl_gi.hli_ss) {
+ printerr("Not in a menu.");
+ return NULL;
+ }
+ if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
+ printerr("This NAV has already been left.");
+ return NULL;
+ }
+
+ button = this->vm->state.HL_BTNN_REG >> 10;
+#ifdef BUTTON_TESTING
+ nav_print_PCI(pci);
+#endif
+
+ return &(pci->hli.btnit[button-1]);
+}
+
+static dvdnav_status_t button_auto_action(dvdnav_t *this, pci_t *pci) {
+ if (get_current_button(this, pci)->auto_action_mode)
+ return dvdnav_button_activate(this, pci);
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_upper_button_select(dvdnav_t *this, pci_t *pci) {
+ btni_t *button_ptr;
+
+ if(!(button_ptr = get_current_button(this, pci)))
+ return DVDNAV_STATUS_ERR;
+
+ dvdnav_button_select(this, pci, button_ptr->up);
+ return button_auto_action(this, pci);
+}
+
+dvdnav_status_t dvdnav_lower_button_select(dvdnav_t *this, pci_t *pci) {
+ btni_t *button_ptr;
+
+ if(!(button_ptr = get_current_button(this, pci)))
+ return DVDNAV_STATUS_ERR;
+
+ dvdnav_button_select(this, pci, button_ptr->down);
+ return button_auto_action(this, pci);
+}
+
+dvdnav_status_t dvdnav_right_button_select(dvdnav_t *this, pci_t *pci) {
+ btni_t *button_ptr;
+
+ if(!(button_ptr = get_current_button(this, pci)))
+ return DVDNAV_STATUS_ERR;
+
+ dvdnav_button_select(this, pci, button_ptr->right);
+ return button_auto_action(this, pci);
+}
+
+dvdnav_status_t dvdnav_left_button_select(dvdnav_t *this, pci_t *pci) {
+ btni_t *button_ptr;
+
+ if(!(button_ptr = get_current_button(this, pci)))
+ return DVDNAV_STATUS_ERR;
+
+ dvdnav_button_select(this, pci, button_ptr->left);
+ return button_auto_action(this, pci);
+}
+
+dvdnav_status_t dvdnav_get_highlight_area(pci_t *nav_pci , int32_t button, int32_t mode,
+ dvdnav_highlight_area_t *highlight) {
+ btni_t *button_ptr;
+
+#ifdef BUTTON_TESTING
+ fprintf(MSG_OUT, "libdvdnav: Button get_highlight_area %i\n", button);
+#endif
+
+ if(!nav_pci->hli.hl_gi.hli_ss)
+ return DVDNAV_STATUS_ERR;
+ if((button <= 0) || (button > nav_pci->hli.hl_gi.btn_ns))
+ return DVDNAV_STATUS_ERR;
+
+
+ button_ptr = &nav_pci->hli.btnit[button-1];
+
+ highlight->sx = button_ptr->x_start;
+ highlight->sy = button_ptr->y_start;
+ highlight->ex = button_ptr->x_end;
+ highlight->ey = button_ptr->y_end;
+ if(button_ptr->btn_coln != 0) {
+ highlight->palette = nav_pci->hli.btn_colit.btn_coli[button_ptr->btn_coln-1][mode];
+ } else {
+ highlight->palette = 0;
+ }
+ highlight->pts = nav_pci->hli.hl_gi.hli_s_ptm;
+ highlight->buttonN = button;
+#ifdef BUTTON_TESTING
+ fprintf(MSG_OUT, "libdvdnav: highlight: Highlight area is (%u,%u)-(%u,%u), display = %i, button = %u\n",
+ button_ptr->x_start, button_ptr->y_start,
+ button_ptr->x_end, button_ptr->y_end,
+ 1,
+ button);
+#endif
+
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_button_activate(dvdnav_t *this, pci_t *pci) {
+ int32_t button;
+ btni_t *button_ptr = NULL;
+
+ if(!pci->hli.hl_gi.hli_ss) {
+ printerr("Not in a menu.");
+ return DVDNAV_STATUS_ERR;
+ }
+ if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
+ printerr("This NAV has already been left.");
+ return DVDNAV_STATUS_ERR;
+ }
+ pthread_mutex_lock(&this->vm_lock);
+
+ button = this->vm->state.HL_BTNN_REG >> 10;
+
+ if((button <= 0) || (button > pci->hli.hl_gi.btn_ns)) {
+ /* Special code to handle still menus with no buttons.
+ * The navigation is expected to report to the application that a STILL is
+ * underway. In turn, the application is supposed to report to the user
+ * that the playback is paused. The user is then expected to undo the pause,
+ * ie: hit play. At that point, the navigation should release the still and
+ * go to the next Cell.
+ * Explanation by Mathieu Lacage <mathieu_lacage@realmagic.fr>
+ * Code added by jcdutton.
+ */
+ if (this->position_current.still != 0) {
+ /* In still, but no buttons. */
+ vm_get_next_cell(this->vm);
+ this->position_current.still = 0;
+ this->sync_wait = 0;
+ this->last_cmd_nav_lbn = pci->pci_gi.nv_pck_lbn;
+ pthread_mutex_unlock(&this->vm_lock);
+ /* clear error message */
+ printerr("");
+ return DVDNAV_STATUS_OK;
+ }
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+
+ button_ptr = get_current_button(this, pci);
+ /* Finally, make the VM execute the appropriate code and probably
+ * scedule a jump */
+#ifdef BUTTON_TESTING
+ fprintf(MSG_OUT, "libdvdnav: Evaluating Button Activation commands.\n");
+#endif
+ if(vm_exec_cmd(this->vm, &(button_ptr->cmd)) == 1) {
+ /* Command caused a jump */
+ this->vm->hop_channel++;
+ this->position_current.still = 0;
+ this->last_cmd_nav_lbn = pci->pci_gi.nv_pck_lbn;
+ }
+
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_button_activate_cmd(dvdnav_t *this, int32_t button, vm_cmd_t *cmd)
+{
+ pthread_mutex_lock(&this->vm_lock);
+ /* make the VM execute the appropriate code and probably
+ * schedule a jump */
+#ifdef BUTTON_TESTING
+ fprintf(MSG_OUT, "libdvdnav: dvdnav_button_activate_cmd: Evaluating Button Activation commands.\n");
+#endif
+ if(button > 0) {
+ this->vm->state.HL_BTNN_REG = (button << 10);
+ if(vm_exec_cmd(this->vm, cmd) == 1) {
+ /* Command caused a jump */
+ this->vm->hop_channel++;
+ }
+ }
+ /* Always remove still, because some still menus have no buttons. */
+ this->position_current.still = 0;
+ this->sync_wait = 0;
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_button_select(dvdnav_t *this, pci_t *pci, int32_t button) {
+ if(!pci->hli.hl_gi.hli_ss) {
+ printerr("Not in a menu.");
+ return DVDNAV_STATUS_ERR;
+ }
+ if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
+ printerr("This NAV has already been left.");
+ return DVDNAV_STATUS_ERR;
+ }
+
+#ifdef BUTTON_TESTING
+ fprintf(MSG_OUT, "libdvdnav: Button select %i\n", button);
+#endif
+
+ if((button <= 0) || (button > pci->hli.hl_gi.btn_ns)) {
+ printerr("Button does not exist.");
+ return DVDNAV_STATUS_ERR;
+ }
+
+ this->vm->state.HL_BTNN_REG = (button << 10);
+ this->position_current.button = -1; /* Force Highligh change */
+
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_button_select_and_activate(dvdnav_t *this, pci_t *pci,
+ int32_t button) {
+ /* A trivial function */
+ if(dvdnav_button_select(this, pci, button) != DVDNAV_STATUS_ERR)
+ return dvdnav_button_activate(this, pci);
+ return DVDNAV_STATUS_ERR;
+}
+
+dvdnav_status_t dvdnav_mouse_select(dvdnav_t *this, pci_t *pci, int32_t x, int32_t y) {
+ int32_t button, cur_button;
+ int32_t best,dist,d;
+ int32_t mx,my,dx,dy;
+
+ if(!pci->hli.hl_gi.hli_ss) {
+ printerr("Not in a menu.");
+ return DVDNAV_STATUS_ERR;
+ }
+ if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
+ printerr("This NAV has already been left.");
+ return DVDNAV_STATUS_ERR;
+ }
+
+ cur_button = this->vm->state.HL_BTNN_REG >> 10;
+
+ best = 0;
+ dist = 0x08000000; /* >> than (720*720)+(567*567); */
+
+ /* Loop through all buttons */
+ for(button = 1; button <= pci->hli.hl_gi.btn_ns; button++) {
+ btni_t *button_ptr = &(pci->hli.btnit[button-1]);
+
+ if((x >= button_ptr->x_start) && (x <= button_ptr->x_end) &&
+ (y >= button_ptr->y_start) && (y <= button_ptr->y_end)) {
+ mx = (button_ptr->x_start + button_ptr->x_end)/2;
+ my = (button_ptr->y_start + button_ptr->y_end)/2;
+ dx = mx - x;
+ dy = my - y;
+ d = (dx*dx) + (dy*dy);
+ /* If the mouse is within the button and the mouse is closer
+ * to the center of this button then it is the best choice. */
+ if(d < dist) {
+ dist = d;
+ best = button;
+ }
+ }
+ }
+ /* As an efficiency measure, only re-select the button
+ * if it is different to the previously selected one. */
+ if (best != 0 && best != cur_button)
+ dvdnav_button_select(this, pci, best);
+
+ /* return DVDNAV_STATUS_OK only if we actually found a matching button */
+ return best ? DVDNAV_STATUS_OK : DVDNAV_STATUS_ERR;
+}
+
+dvdnav_status_t dvdnav_mouse_activate(dvdnav_t *this, pci_t *pci, int32_t x, int32_t y) {
+ /* A trivial function */
+ if(dvdnav_mouse_select(this, pci, x,y) != DVDNAV_STATUS_ERR)
+ return dvdnav_button_activate(this, pci);
+ return DVDNAV_STATUS_ERR;
+}
diff --git a/lib/libdvd/libdvdnav/src/navigation.c b/lib/libdvd/libdvdnav/src/navigation.c
new file mode 100644
index 0000000000..e28cb640bb
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/navigation.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
+ *
+ * This file is part of libdvdnav, a DVD navigation library.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: navigation.c 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <inttypes.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/time.h>
+#include "dvd_types.h"
+#include <dvdread/nav_types.h>
+#include <dvdread/ifo_types.h>
+#include "remap.h"
+#include "vm/decoder.h"
+#include "vm/vm.h"
+#include "dvdnav.h"
+#include "dvdnav_internal.h"
+
+/* Navigation API calls */
+
+dvdnav_status_t dvdnav_still_skip(dvdnav_t *this) {
+ pthread_mutex_lock(&this->vm_lock);
+ this->position_current.still = 0;
+ pthread_mutex_unlock(&this->vm_lock);
+ this->skip_still = 1;
+ this->sync_wait = 0;
+ this->sync_wait_skip = 1;
+
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_wait_skip(dvdnav_t *this) {
+ this->sync_wait = 0;
+ this->sync_wait_skip = 1;
+
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_get_number_of_titles(dvdnav_t *this, int32_t *titles) {
+ if (!this->vm->vmgi) {
+ printerr("Bad VM state.");
+ return DVDNAV_STATUS_ERR;
+ }
+
+ (*titles) = vm_get_vmgi(this->vm)->tt_srpt->nr_of_srpts;
+
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_get_number_of_parts(dvdnav_t *this, int32_t title, int32_t *parts) {
+ if (!this->vm->vmgi) {
+ printerr("Bad VM state.");
+ return DVDNAV_STATUS_ERR;
+ }
+ if ((title < 1) || (title > vm_get_vmgi(this->vm)->tt_srpt->nr_of_srpts) ) {
+ printerr("Passed a title number out of range.");
+ return DVDNAV_STATUS_ERR;
+ }
+
+ (*parts) = vm_get_vmgi(this->vm)->tt_srpt->title[title-1].nr_of_ptts;
+
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_current_title_info(dvdnav_t *this, int32_t *title, int32_t *part) {
+ int32_t retval;
+
+ pthread_mutex_lock(&this->vm_lock);
+ if (!this->vm->vtsi || !this->vm->vmgi) {
+ printerr("Bad VM state.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ if (!this->started) {
+ printerr("Virtual DVD machine not started.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ if (!this->vm->state.pgc) {
+ printerr("No current PGC.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ if ( (this->vm->state.domain == VTSM_DOMAIN)
+ || (this->vm->state.domain == VMGM_DOMAIN) ) {
+ /* Get current Menu ID: into *part. */
+ if(! vm_get_current_menu(this->vm, part)) {
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ if (*part > -1) {
+ *title = 0;
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+ }
+ }
+ if (this->vm->state.domain == VTS_DOMAIN) {
+ retval = vm_get_current_title_part(this->vm, title, part);
+ pthread_mutex_unlock(&this->vm_lock);
+ return retval ? DVDNAV_STATUS_OK : DVDNAV_STATUS_ERR;
+ }
+ printerr("Not in a title or menu.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+}
+
+dvdnav_status_t dvdnav_title_play(dvdnav_t *this, int32_t title) {
+ return dvdnav_part_play(this, title, 1);
+}
+
+dvdnav_status_t dvdnav_part_play(dvdnav_t *this, int32_t title, int32_t part) {
+ int32_t retval;
+
+ pthread_mutex_lock(&this->vm_lock);
+ if (!this->vm->vmgi) {
+ printerr("Bad VM state.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ if (!this->started) {
+ /* don't report an error but be nice */
+ vm_start(this->vm);
+ this->started = 1;
+ }
+ if (!this->vm->state.pgc) {
+ printerr("No current PGC.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ if((title < 1) || (title > this->vm->vmgi->tt_srpt->nr_of_srpts)) {
+ printerr("Title out of range.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ if((part < 1) || (part > this->vm->vmgi->tt_srpt->title[title-1].nr_of_ptts)) {
+ printerr("Part out of range.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+
+ retval = vm_jump_title_part(this->vm, title, part);
+ if (retval)
+ this->vm->hop_channel++;
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return retval ? DVDNAV_STATUS_OK : DVDNAV_STATUS_ERR;
+}
+
+dvdnav_status_t dvdnav_part_play_auto_stop(dvdnav_t *this, int32_t title,
+ int32_t part, int32_t parts_to_play) {
+ /* FIXME: Implement auto-stop */
+ if (dvdnav_part_play(this, title, part) == DVDNAV_STATUS_OK)
+ printerr("Not implemented yet.");
+ return DVDNAV_STATUS_ERR;
+}
+
+dvdnav_status_t dvdnav_time_play(dvdnav_t *this, int32_t title,
+ uint64_t time) {
+ /* FIXME: Implement */
+ printerr("Not implemented yet.");
+ return DVDNAV_STATUS_ERR;
+}
+
+dvdnav_status_t dvdnav_stop(dvdnav_t *this) {
+ pthread_mutex_lock(&this->vm_lock);
+ this->vm->stopped = 1;
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_go_up(dvdnav_t *this) {
+ /* A nice easy function... delegate to the VM */
+ pthread_mutex_lock(&this->vm_lock);
+ vm_jump_up(this->vm);
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return DVDNAV_STATUS_OK;
+}
diff --git a/lib/libdvd/libdvdnav/src/read_cache.c b/lib/libdvd/libdvdnav/src/read_cache.c
new file mode 100644
index 0000000000..b5e16f0784
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/read_cache.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
+ * 2001-2004 the dvdnav project
+ *
+ * This file is part of libdvdnav, a DVD navigation library.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: read_cache.c 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+/*
+ * There was a multithreaded read ahead cache in here for some time, but
+ * it had only been used for a short time. If you want to have a look at it,
+ * search the CVS attic.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <sys/time.h>
+#include <time.h>
+#include "dvd_types.h"
+#include <dvdread/nav_types.h>
+#include <dvdread/ifo_types.h>
+#include "remap.h"
+#include "vm/decoder.h"
+#include "vm/vm.h"
+#include "dvdnav.h"
+#include "dvdnav_internal.h"
+#include "read_cache.h"
+
+#define READ_CACHE_CHUNKS 10
+
+/* all cache chunks must be memory aligned to allow use of raw devices */
+#define ALIGNMENT 2048
+
+#define READ_AHEAD_SIZE_MIN 4
+#define READ_AHEAD_SIZE_MAX 512
+
+typedef struct read_cache_chunk_s {
+ uint8_t *cache_buffer;
+ uint8_t *cache_buffer_base; /* used in malloc and free for alignment */
+ int32_t cache_start_sector; /* -1 means cache invalid */
+ int32_t cache_read_count; /* this many sectors are already read */
+ size_t cache_block_count; /* this many sectors will go in this chunk */
+ size_t cache_malloc_size;
+ int cache_valid;
+ int usage_count; /* counts how many buffers where issued from this chunk */
+} read_cache_chunk_t;
+
+struct read_cache_s {
+ read_cache_chunk_t chunk[READ_CACHE_CHUNKS];
+ int current;
+ int freeing; /* is set to one when we are about to dispose the cache */
+ uint32_t read_ahead_size;
+ int read_ahead_incr;
+ int last_sector;
+ pthread_mutex_t lock;
+
+ /* Bit of strange cross-linking going on here :) -- Gotta love C :) */
+ dvdnav_t *dvd_self;
+};
+
+/*
+#define READ_CACHE_TRACE 0
+*/
+
+#ifdef __GNUC__
+# if READ_CACHE_TRACE
+# define dprintf(fmt, args...) fprintf(MSG_OUT, "libdvdnav: %s: "fmt, __func__ , ## args)
+# else
+# define dprintf(fmt, args...) /* Nowt */
+# endif
+#else
+# if READ_CACHE_TRACE
+# define dprintf(fmt, ...) fprintf(MSG_OUT, "libdvdnav: %s: "fmt, __func__ , __VA_ARGS__)
+# else
+#ifdef _MSC_VER
+# define dprintf(fmt, str) /* Nowt */
+#else
+# define dprintf(fmt, ...) /* Nowt */
+#endif /* _MSC_VER */
+# endif
+#endif
+
+
+read_cache_t *dvdnav_read_cache_new(dvdnav_t* dvd_self) {
+ read_cache_t *self;
+ int i;
+
+ self = (read_cache_t *)malloc(sizeof(read_cache_t));
+
+ if(self) {
+ self->current = 0;
+ self->freeing = 0;
+ self->dvd_self = dvd_self;
+ self->last_sector = 0;
+ self->read_ahead_size = READ_AHEAD_SIZE_MIN;
+ self->read_ahead_incr = 0;
+ pthread_mutex_init(&self->lock, NULL);
+ dvdnav_read_cache_clear(self);
+ for (i = 0; i < READ_CACHE_CHUNKS; i++) {
+ self->chunk[i].cache_buffer = NULL;
+ self->chunk[i].usage_count = 0;
+ }
+ }
+
+ return self;
+}
+
+void dvdnav_read_cache_free(read_cache_t* self) {
+ dvdnav_t *tmp;
+ int i;
+
+ pthread_mutex_lock(&self->lock);
+ self->freeing = 1;
+ for (i = 0; i < READ_CACHE_CHUNKS; i++)
+ if (self->chunk[i].cache_buffer && self->chunk[i].usage_count == 0) {
+ free(self->chunk[i].cache_buffer_base);
+ self->chunk[i].cache_buffer = NULL;
+ }
+ pthread_mutex_unlock(&self->lock);
+
+ for (i = 0; i < READ_CACHE_CHUNKS; i++)
+ if (self->chunk[i].cache_buffer) return;
+
+ /* all buffers returned, free everything */
+ tmp = self->dvd_self;
+ pthread_mutex_destroy(&self->lock);
+ free(self);
+ free(tmp);
+}
+
+/* This function MUST be called whenever self->file changes. */
+void dvdnav_read_cache_clear(read_cache_t *self) {
+ int i;
+
+ if(!self)
+ return;
+
+ pthread_mutex_lock(&self->lock);
+ for (i = 0; i < READ_CACHE_CHUNKS; i++)
+ self->chunk[i].cache_valid = 0;
+ pthread_mutex_unlock(&self->lock);
+}
+
+/* This function is called just after reading the NAV packet. */
+void dvdnav_pre_cache_blocks(read_cache_t *self, int sector, size_t block_count) {
+ int i, use;
+
+ if(!self)
+ return;
+
+ if(!self->dvd_self->use_read_ahead)
+ return;
+
+ pthread_mutex_lock(&self->lock);
+
+ /* find a free cache chunk that best fits the required size */
+ use = -1;
+ for (i = 0; i < READ_CACHE_CHUNKS; i++)
+ if (self->chunk[i].usage_count == 0 && self->chunk[i].cache_buffer &&
+ self->chunk[i].cache_malloc_size >= block_count &&
+ (use == -1 || self->chunk[use].cache_malloc_size > self->chunk[i].cache_malloc_size))
+ use = i;
+
+ if (use == -1) {
+ /* we haven't found a cache chunk, so we try to reallocate an existing one */
+ for (i = 0; i < READ_CACHE_CHUNKS; i++)
+ if (self->chunk[i].usage_count == 0 && self->chunk[i].cache_buffer &&
+ (use == -1 || self->chunk[use].cache_malloc_size < self->chunk[i].cache_malloc_size))
+ use = i;
+ if (use >= 0) {
+ self->chunk[use].cache_buffer_base = realloc(self->chunk[use].cache_buffer_base,
+ block_count * DVD_VIDEO_LB_LEN + ALIGNMENT);
+ self->chunk[use].cache_buffer =
+ (uint8_t *)(((uintptr_t)self->chunk[use].cache_buffer_base & ~((uintptr_t)(ALIGNMENT - 1))) + ALIGNMENT);
+ dprintf("pre_cache DVD read realloc happened\n");
+ self->chunk[use].cache_malloc_size = block_count;
+ } else {
+ /* we still haven't found a cache chunk, let's allocate a new one */
+ for (i = 0; i < READ_CACHE_CHUNKS; i++)
+ if (!self->chunk[i].cache_buffer) {
+ use = i;
+ break;
+ }
+ if (use >= 0) {
+ /* We start with a sensible figure for the first malloc of 500 blocks.
+ * Some DVDs I have seen venture to 450 blocks.
+ * This is so that fewer realloc's happen if at all.
+ */
+ self->chunk[i].cache_buffer_base =
+ malloc((block_count > 500 ? block_count : 500) * DVD_VIDEO_LB_LEN + ALIGNMENT);
+ self->chunk[i].cache_buffer =
+ (uint8_t *)(((uintptr_t)self->chunk[i].cache_buffer_base & ~((uintptr_t)(ALIGNMENT - 1))) + ALIGNMENT);
+ self->chunk[i].cache_malloc_size = block_count > 500 ? block_count : 500;
+ dprintf("pre_cache DVD read malloc %d blocks\n",
+ (block_count > 500 ? block_count : 500 ));
+ }
+ }
+ }
+
+ if (use >= 0) {
+ self->chunk[use].cache_start_sector = sector;
+ self->chunk[use].cache_block_count = block_count;
+ self->chunk[use].cache_read_count = 0;
+ self->chunk[use].cache_valid = 1;
+ self->current = use;
+ } else {
+ dprintf("pre_caching was impossible, no cache chunk available\n");
+ }
+ pthread_mutex_unlock(&self->lock);
+}
+
+int dvdnav_read_cache_block(read_cache_t *self, int sector, size_t block_count, uint8_t **buf) {
+ int i, use;
+ int start;
+ int size;
+ int incr;
+ uint8_t *read_ahead_buf;
+ int32_t res;
+
+ if(!self)
+ return 0;
+
+ use = -1;
+
+ if(self->dvd_self->use_read_ahead) {
+ /* first check, if sector is in current chunk */
+ read_cache_chunk_t cur = self->chunk[self->current];
+ if (cur.cache_valid && sector >= cur.cache_start_sector &&
+ sector <= (cur.cache_start_sector + cur.cache_read_count) &&
+ sector + block_count <= cur.cache_start_sector + cur.cache_block_count)
+ use = self->current;
+ else
+ for (i = 0; i < READ_CACHE_CHUNKS; i++)
+ if (self->chunk[i].cache_valid &&
+ sector >= self->chunk[i].cache_start_sector &&
+ sector <= (self->chunk[i].cache_start_sector + self->chunk[i].cache_read_count) &&
+ sector + block_count <= self->chunk[i].cache_start_sector + self->chunk[i].cache_block_count)
+ use = i;
+ }
+
+ if (use >= 0) {
+ read_cache_chunk_t *chunk;
+
+ /* Increment read-ahead size if sector follows the last sector */
+ if (sector == (self->last_sector + 1)) {
+ if (self->read_ahead_incr < READ_AHEAD_SIZE_MAX)
+ self->read_ahead_incr++;
+ } else {
+ self->read_ahead_size = READ_AHEAD_SIZE_MIN;
+ self->read_ahead_incr = 0;
+ }
+ self->last_sector = sector;
+
+ /* The following resources need to be protected by a mutex :
+ * self->chunk[*].cache_buffer
+ * self->chunk[*].cache_malloc_size
+ * self->chunk[*].usage_count
+ */
+ pthread_mutex_lock(&self->lock);
+ chunk = &self->chunk[use];
+ read_ahead_buf = chunk->cache_buffer + chunk->cache_read_count * DVD_VIDEO_LB_LEN;
+ *buf = chunk->cache_buffer + (sector - chunk->cache_start_sector) * DVD_VIDEO_LB_LEN;
+ chunk->usage_count++;
+ pthread_mutex_unlock(&self->lock);
+
+ dprintf("libdvdnav: sector=%d, start_sector=%d, last_sector=%d\n", sector, chunk->cache_start_sector, chunk->cache_start_sector + chunk->cache_block_count);
+
+ /* read_ahead_size */
+ incr = self->read_ahead_incr >> 1;
+ if ((self->read_ahead_size + incr) > READ_AHEAD_SIZE_MAX) {
+ self->read_ahead_size = READ_AHEAD_SIZE_MAX;
+ } else {
+ self->read_ahead_size += incr;
+ }
+
+ /* real read size */
+ start = chunk->cache_start_sector + chunk->cache_read_count;
+ if (chunk->cache_read_count + self->read_ahead_size > chunk->cache_block_count) {
+ size = chunk->cache_block_count - chunk->cache_read_count;
+ } else {
+ size = self->read_ahead_size;
+ /* ensure that the sector we want will be read */
+ if (sector >= chunk->cache_start_sector + chunk->cache_read_count + size)
+ size = sector - chunk->cache_start_sector - chunk->cache_read_count;
+ }
+ dprintf("libdvdnav: read_ahead_size=%d, size=%d\n", self->read_ahead_size, size);
+
+ if (size)
+ chunk->cache_read_count += DVDReadBlocks(self->dvd_self->file,
+ start,
+ size,
+ read_ahead_buf);
+
+ res = DVD_VIDEO_LB_LEN * block_count;
+
+ } else {
+
+ if (self->dvd_self->use_read_ahead)
+ dprintf("cache miss on sector %d\n", sector);
+
+ res = DVDReadBlocks(self->dvd_self->file,
+ sector,
+ block_count,
+ *buf) * DVD_VIDEO_LB_LEN;
+ }
+
+ return res;
+
+}
+
+dvdnav_status_t dvdnav_free_cache_block(dvdnav_t *self, unsigned char *buf) {
+ read_cache_t *cache;
+ int i;
+
+ if (!self)
+ return DVDNAV_STATUS_ERR;
+
+ cache = self->cache;
+ if (!cache)
+ return DVDNAV_STATUS_ERR;
+
+ pthread_mutex_lock(&cache->lock);
+ for (i = 0; i < READ_CACHE_CHUNKS; i++) {
+ if (cache->chunk[i].cache_buffer && buf >= cache->chunk[i].cache_buffer &&
+ buf < cache->chunk[i].cache_buffer + cache->chunk[i].cache_malloc_size * DVD_VIDEO_LB_LEN && cache->chunk[i].usage_count > 0) {
+ cache->chunk[i].usage_count--;
+ }
+ }
+ pthread_mutex_unlock(&cache->lock);
+
+ if (cache->freeing)
+ /* when we want to dispose the cache, try freeing it now */
+ dvdnav_read_cache_free(cache);
+
+ return DVDNAV_STATUS_OK;
+}
diff --git a/lib/libdvd/libdvdnav/src/read_cache.h b/lib/libdvd/libdvdnav/src/read_cache.h
new file mode 100644
index 0000000000..92f9c5caba
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/read_cache.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
+ *
+ * This file is part of libdvdnav, a DVD navigation library.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: read_cache.h 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+#ifndef __DVDNAV_READ_CACHE_H
+#define __DVDNAV_READ_CACHE_H
+
+/* Opaque cache type -- defined in dvdnav_internal.h */
+/* typedef struct read_cache_s read_cache_t; */
+
+/* EXPERIMENTAL: Setting the following to 1 will use an experimental multi-threaded
+ * read-ahead cache.
+ */
+#define _MULTITHREAD_ 0
+
+/* Constructor/destructors */
+read_cache_t *dvdnav_read_cache_new(dvdnav_t* dvd_self);
+void dvdnav_read_cache_free(read_cache_t* self);
+
+/* This function MUST be called whenever self->file changes. */
+void dvdnav_read_cache_clear(read_cache_t *self);
+/* This function is called just after reading the NAV packet. */
+void dvdnav_pre_cache_blocks(read_cache_t *self, int sector, size_t block_count);
+/* This function will do the cache read.
+ * The buffer handed in must be malloced to take one dvd block.
+ * On a cache hit, a different buffer will be returned though.
+ * Those buffers must _never_ be freed. */
+int dvdnav_read_cache_block(read_cache_t *self, int sector, size_t block_count, uint8_t **buf);
+
+#endif /* __DVDNAV_READ_CACHE_H */
diff --git a/lib/libdvd/libdvdnav/src/remap.c b/lib/libdvd/libdvdnav/src/remap.c
new file mode 100644
index 0000000000..5601605dba
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/remap.c
@@ -0,0 +1,269 @@
+/*
+ * This file is part of libdvdnav, a DVD navigation library.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: remap.c 1135 2008-09-06 21:55:51Z rathann $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef _MSC_VER
+#include <sys/param.h>
+#include <sys/fcntl.h>
+#else
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 255
+#endif
+#endif /* _MSC_VER */
+
+#include <inttypes.h>
+#include <limits.h>
+#include <sys/time.h>
+#include "dvd_types.h"
+#include <dvdread/nav_types.h>
+#include <dvdread/ifo_types.h>
+#include "remap.h"
+#include "vm/decoder.h"
+#include "vm/vm.h"
+#include "dvdnav.h"
+#include "dvdnav_internal.h"
+
+struct block_s {
+ int domain;
+ int title;
+ int program;
+ unsigned long start_block;
+ unsigned long end_block;
+};
+
+struct remap_s {
+ char *title;
+ int maxblocks;
+ int nblocks;
+ int debug;
+ struct block_s *blocks;
+};
+
+static remap_t* remap_new( char *title) {
+ remap_t *map = malloc( sizeof(remap_t));
+ map->title = strdup(title);
+ map->maxblocks = 0;
+ map->nblocks = 0;
+ map->blocks = NULL;
+ map->debug = 0;
+ return map;
+}
+
+static int compare_block( block_t *a, block_t *b) {
+ /* returns -1 if a precedes b, 1 if a follows b, and 0 if a and b overlap */
+ if (a->domain < b->domain) {
+ return -1;
+ } else if (a->domain > b->domain) {
+ return 1;
+ }
+
+ if (a->title < b->title) {
+ return -1;
+ } else if (a->title > b->title) {
+ return 1;
+ }
+
+ if (a->program < b->program) {
+ return -1;
+ } else if (a->program > b->program) {
+ return 1;
+ }
+
+ if (a->end_block < b->start_block) {
+ return -1;
+ } else if (a->start_block > b->end_block) {
+ /*
+ * if a->start_block == b->end_block then the two regions
+ * aren't strictly overlapping, but they should be merged
+ * anyway since there are zero blocks between them
+ */
+ return 1;
+ }
+
+ return 0;
+}
+
+static block_t *findblock( remap_t *map, block_t *key) {
+ int lb = 0;
+ int ub = map->nblocks - 1;
+ int mid;
+ int res;
+
+ while (lb <= ub) {
+ mid = lb + (ub - lb)/2;
+ res = compare_block( key, &map->blocks[mid]);
+ if (res < 0) {
+ ub = mid-1;
+ } else if (res > 0) {
+ lb = mid+1;
+ } else {
+ return &map->blocks[mid];
+ }
+ }
+ return NULL;
+}
+
+static void mergeblock( block_t *b, block_t tmp) {
+ if (tmp.start_block < b->start_block) b->start_block = tmp.start_block;
+ if (tmp.end_block > b->end_block) b->end_block = tmp.end_block;
+}
+
+static void remap_add_node( remap_t *map, block_t block) {
+ block_t *b;
+ int n;
+ b = findblock( map, &block);
+ if (b) {
+ /* overlaps an existing block */
+ mergeblock( b, block);
+ } else {
+ /* new block */
+ if (map->nblocks >= map->maxblocks) {
+ map->maxblocks += 20;
+ map->blocks = realloc( map->blocks, sizeof( block_t)*map->maxblocks);
+ }
+ n = map->nblocks++;
+ while (n > 0 && compare_block( &block, &map->blocks[ n-1]) < 0) {
+ map->blocks[ n] = map->blocks[ n-1];
+ n--;
+ }
+ map->blocks[ n] = block;
+ }
+}
+
+static int parseblock(char *buf, int *dom, int *tt, int *pg,
+ unsigned long *start, unsigned long *end) {
+ long tmp;
+ char *tok;
+ char *epos;
+ char *marker[]={"domain", "title", "program", "start", "end"};
+ int st = 0;
+ tok = strtok( buf, " ");
+ while (st < 5) {
+ if (strcmp(tok, marker[st])) return -st-1000;
+ tok = strtok( NULL, " ");
+ if (!tok) return -st-2000;
+ tmp = strtol( tok, &epos, 0);
+ if (*epos != 0 && *epos != ',') return -st-3000;
+ switch (st) {
+ case 0:
+ *dom = (int)tmp;
+ break;
+ case 1:
+ *tt = (int)tmp;
+ break;
+ case 2:
+ *pg = (int)tmp;
+ break;
+ case 3:
+ *start = tmp;
+ break;
+ case 4:
+ *end = tmp;
+ break;
+ }
+ st++;
+ tok = strtok( NULL, " ");
+ }
+ return st;
+}
+
+remap_t* remap_loadmap( char *title) {
+ char buf[160];
+ char fname[MAXPATHLEN];
+ char *home;
+ int res;
+ FILE *fp;
+ block_t tmp;
+ remap_t *map;
+
+ memset(&tmp, 0, sizeof(tmp));
+ /* Build the map filename */
+ home = getenv("HOME");
+ if(!home) {
+ fprintf(MSG_OUT, "libdvdnav: Unable to find home directory" );
+ return NULL;
+ }
+ snprintf(fname, sizeof(fname), "%s/.dvdnav/%s.map", home, title);
+
+ /* Open the map file */
+ fp = fopen( fname, "r");
+ if (!fp) {
+ fprintf(MSG_OUT, "libdvdnav: Unable to find map file '%s'\n", fname);
+ return NULL;
+ }
+
+ /* Load the map file */
+ map = remap_new( title);
+ while (fgets( buf, sizeof(buf), fp) != NULL) {
+ if (buf[0] == '\n' || buf[0] == '#' || buf[0] == 0) continue;
+ if (strncasecmp( buf, "debug", 5) == 0) {
+ map->debug = 1;
+ } else {
+ res = parseblock( buf,
+ &tmp.domain, &tmp.title, &tmp.program, &tmp.start_block, &tmp.end_block);
+ if (res != 5) {
+ fprintf(MSG_OUT, "libdvdnav: Ignoring map line (%d): %s\n", res, buf);
+ continue;
+ }
+ remap_add_node( map, tmp);
+ }
+ }
+ fclose(fp);
+
+ if (map->nblocks == 0 && map->debug == 0) {
+ free(map);
+ return NULL;
+ }
+ return map;
+}
+
+unsigned long remap_block(
+ remap_t *map, int domain, int title, int program,
+ unsigned long cblock, unsigned long offset)
+{
+ block_t key;
+ block_t *b;
+
+ if (map->debug) {
+ fprintf(MSG_OUT, "libdvdnav: %s: domain %d, title %d, program %d, start %lx, next %lx\n",
+ map->title, domain, title, program, cblock, cblock+offset);
+ }
+
+ key.domain = domain;
+ key.title = title;
+ key.program = program;
+ key.start_block = key.end_block = cblock + offset;
+ b = findblock( map, &key);
+
+ if (b) {
+ if (map->debug) {
+ fprintf(MSG_OUT, "libdvdnav: Redirected to %lx\n", b->end_block);
+ }
+ return b->end_block - cblock;
+ }
+ return offset;
+}
diff --git a/lib/libdvd/libdvdnav/src/remap.h b/lib/libdvd/libdvdnav/src/remap.h
new file mode 100644
index 0000000000..0a8a81636b
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/remap.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of libdvdnav, a DVD navigation library.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: remap.h 1135 2008-09-06 21:55:51Z rathann $
+ */
+
+#ifndef __REMAP__H
+#define __REMAP__H
+typedef struct block_s block_t;
+
+typedef struct remap_s remap_t;
+
+remap_t* remap_loadmap( char *title);
+
+unsigned long remap_block(
+ remap_t *map, int domain, int title, int program,
+ unsigned long cblock, unsigned long offset);
+
+#endif
diff --git a/lib/libdvd/libdvdnav/src/searching.c b/lib/libdvd/libdvdnav/src/searching.c
new file mode 100644
index 0000000000..0d3475ed1c
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/searching.c
@@ -0,0 +1,782 @@
+/*
+ * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
+ *
+ * This file is part of libdvdnav, a DVD navigation library.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: searching.c 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include "dvd_types.h"
+#include <dvdread/nav_types.h>
+#include <dvdread/ifo_types.h>
+#include "remap.h"
+#include "vm/decoder.h"
+#include "vm/vm.h"
+#include "dvdnav.h"
+#include "dvdnav_internal.h"
+
+/*
+#define LOG_DEBUG
+*/
+
+/* Searching API calls */
+
+/* Scan the ADMAP for a particular block number. */
+/* Return placed in vobu. */
+/* Returns error status */
+/* FIXME: Maybe need to handle seeking outside current cell. */
+static dvdnav_status_t dvdnav_scan_admap(dvdnav_t *this, int32_t domain, uint32_t seekto_block, uint32_t *vobu) {
+ vobu_admap_t *admap = NULL;
+
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: Seeking to target %u ...\n", seekto_block);
+#endif
+ *vobu = -1;
+
+ /* Search through the VOBU_ADMAP for the nearest VOBU
+ * to the target block */
+ switch(domain) {
+ case FP_DOMAIN:
+ case VMGM_DOMAIN:
+ admap = this->vm->vmgi->menu_vobu_admap;
+ break;
+ case VTSM_DOMAIN:
+ admap = this->vm->vtsi->menu_vobu_admap;
+ break;
+ case VTS_DOMAIN:
+ admap = this->vm->vtsi->vts_vobu_admap;
+ break;
+ default:
+ fprintf(MSG_OUT, "libdvdnav: Error: Unknown domain for seeking.\n");
+ }
+ if(admap) {
+ uint32_t address = 0;
+ uint32_t vobu_start, next_vobu;
+ int admap_entries = (admap->last_byte + 1 - VOBU_ADMAP_SIZE)/VOBU_ADMAP_SIZE;
+
+ /* Search through ADMAP for best sector */
+ vobu_start = SRI_END_OF_CELL;
+ /* FIXME: Implement a faster search algorithm */
+ while(address < admap_entries) {
+ next_vobu = admap->vobu_start_sectors[address];
+
+ /* fprintf(MSG_OUT, "libdvdnav: Found block %u\n", next_vobu); */
+
+ if(vobu_start <= seekto_block && next_vobu > seekto_block)
+ break;
+ vobu_start = next_vobu;
+ address++;
+ }
+ *vobu = vobu_start;
+ return DVDNAV_STATUS_OK;
+ }
+ fprintf(MSG_OUT, "libdvdnav: admap not located\n");
+ return DVDNAV_STATUS_ERR;
+}
+
+dvdnav_status_t dvdnav_time_search(dvdnav_t *this,
+ uint64_t time) {
+
+ uint32_t target;
+ uint64_t length = 0;
+ uint32_t first_cell_nr, last_cell_nr, cell_nr;
+ int32_t found = 0;
+ cell_playback_t *cell;
+ dvd_state_t *state;
+
+ if(this->position_current.still != 0) {
+ printerr("Cannot seek in a still frame.");
+ return DVDNAV_STATUS_ERR;
+ }
+
+ pthread_mutex_lock(&this->vm_lock);
+ state = &(this->vm->state);
+ if(!state->pgc) {
+ printerr("No current PGC.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+
+ if((state->pgc->prohibited_ops.title_or_time_play == 1) ||
+ (this->pci.pci_gi.vobu_uop_ctl.title_or_time_play == 1 )){
+ printerr("operation forbidden.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+
+ /* setup what cells we should be working within */
+ if (this->pgc_based) {
+ first_cell_nr = 1;
+ last_cell_nr = state->pgc->nr_of_cells;
+ } else {
+ /* Find start cell of program. */
+ first_cell_nr = state->pgc->program_map[state->pgN-1];
+ /* Find end cell of program */
+ if(state->pgN < state->pgc->nr_of_programs)
+ last_cell_nr = state->pgc->program_map[state->pgN] - 1;
+ else
+ last_cell_nr = state->pgc->nr_of_cells;
+ }
+
+ /* FIXME: using time map is not going to work unless we are pgc_based */
+ /* we'd need to recalculate the time to be relative to full pgc first*/
+ if(!this->pgc_based)
+ {
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: time_search - not pgc based\n");
+#endif
+ goto timemapdone;
+ }
+
+ if(!this->vm->vtsi->vts_tmapt){
+ /* no time map for this program chain */
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: time_search - no time map for this program chain\n");
+#endif
+ goto timemapdone;
+ }
+
+ if(this->vm->vtsi->vts_tmapt->nr_of_tmaps < state->pgcN){
+ /* to few time maps for this program chain */
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: time_search - to few time maps for this program chain\n");
+#endif
+ goto timemapdone;
+ }
+
+ /* get the tmpat corresponding to the pgc */
+ vts_tmap_t *tmap = &(this->vm->vtsi->vts_tmapt->tmap[state->pgcN-1]);
+
+ if(tmap->tmu == 0){
+ /* no time unit for this time map */
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: time_search - no time unit for this time map\n");
+#endif
+ goto timemapdone;
+ }
+
+ /* time is in pts (90khz clock), get the number of tmu's that represent */
+ /* first entry defines at time tmu not time zero */
+ int entry = time / tmap->tmu / 90000 - 1;
+ if(entry > tmap->nr_of_entries)
+ entry = tmap->nr_of_entries -1;
+
+ if(entry > 0)
+ {
+ /* get the table entry, disregarding marking of discontinuity */
+ target = tmap->map_ent[entry] & 0x7fffffff;
+ }
+ else
+ {
+ /* start from first vobunit */
+ target = state->pgc->cell_playback[first_cell_nr-1].first_sector;;
+ }
+
+ /* if we have an additional entry we can interpolate next position */
+ /* allowed only if next entry isn't discontinious */
+
+ if( entry < tmap->nr_of_entries - 1)
+ {
+ const uint32_t target2 = tmap->map_ent[entry+1];
+ const uint64_t timeunit = tmap->tmu*90000;
+ if( !( target2 & 0x80000000) )
+ {
+ length = target2 - target;
+ target += (uint32_t) (length * ( time - (entry+1)*timeunit ) / timeunit);
+ }
+ }
+ found = 1;
+
+timemapdone:
+
+
+ for(cell_nr = first_cell_nr; cell_nr <= last_cell_nr; cell_nr ++) {
+ cell = &(state->pgc->cell_playback[cell_nr-1]);
+
+ if(cell->block_type == BLOCK_TYPE_ANGLE_BLOCK && cell->block_mode != BLOCK_MODE_FIRST_CELL)
+ continue;
+
+ if(found) {
+
+ length = cell->last_sector - cell->first_sector + 1;
+ if (target >= length) {
+ target -= length;
+ } else {
+ /* convert the target sector from Cell-relative to absolute physical sector */
+ target += cell->first_sector;
+ break;
+ }
+
+ } else {
+
+ length = dvdnav_convert_time(&cell->playback_time);
+ if (time >= length) {
+ time -= length;
+ } else {
+ /* FIXME: there must be a better way than interpolation */
+ target = time * (cell->last_sector - cell->first_sector + 1) / length;
+ target += cell->first_sector;
+
+ #ifdef LOG_DEBUG
+ if( cell->first_sector > target || target > cell->last_sector )
+ fprintf(MSG_OUT, "libdvdnav: time_search - sector is not within cell min:%u, max:%u, cur:%u\n", cell->first_sector, cell->last_sector, target);
+ #endif
+
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ if(found) {
+ uint32_t vobu;
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: Seeking to cell %i from choice of %i to %i\n",
+ cell_nr, first_cell_nr, last_cell_nr);
+#endif
+ if (dvdnav_scan_admap(this, state->domain, target, &vobu) == DVDNAV_STATUS_OK) {
+ uint32_t start = state->pgc->cell_playback[cell_nr-1].first_sector;
+
+ if (vm_jump_cell_block(this->vm, cell_nr, vobu - start)) {
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: After cellN=%u blockN=%u target=%x vobu=%x start=%x\n" ,
+ state->cellN, state->blockN, target, vobu, start);
+#endif
+ this->vm->hop_channel += HOP_SEEK;
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+ }
+ }
+ }
+
+ fprintf(MSG_OUT, "libdvdnav: Error when seeking\n");
+ printerr("Error when seeking.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+}
+
+dvdnav_status_t dvdnav_sector_search(dvdnav_t *this,
+ uint64_t offset, int32_t origin) {
+ uint32_t target = 0;
+ uint32_t length = 0;
+ uint32_t first_cell_nr, last_cell_nr, cell_nr;
+ int32_t found;
+ cell_playback_t *cell;
+ dvd_state_t *state;
+ dvdnav_status_t result;
+
+ if(this->position_current.still != 0) {
+ printerr("Cannot seek in a still frame.");
+ return DVDNAV_STATUS_ERR;
+ }
+
+ result = dvdnav_get_position(this, &target, &length);
+ if(!result) {
+ printerr("Cannot get current position");
+ return DVDNAV_STATUS_ERR;
+ }
+
+ pthread_mutex_lock(&this->vm_lock);
+ state = &(this->vm->state);
+ if(!state->pgc) {
+ printerr("No current PGC.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: seeking to offset=%llu pos=%u length=%u\n", offset, target, length);
+ fprintf(MSG_OUT, "libdvdnav: Before cellN=%u blockN=%u\n", state->cellN, state->blockN);
+#endif
+
+ switch(origin) {
+ case SEEK_SET:
+ if(offset >= length) {
+ printerr("Request to seek behind end.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ target = offset;
+ break;
+ case SEEK_CUR:
+ if(target + offset >= length) {
+ printerr("Request to seek behind end.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ target += offset;
+ break;
+ case SEEK_END:
+ if(length < offset) {
+ printerr("Request to seek before start.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ target = length - offset;
+ break;
+ default:
+ /* Error occured */
+ printerr("Illegal seek mode.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+
+ this->cur_cell_time = 0;
+ if (this->pgc_based) {
+ first_cell_nr = 1;
+ last_cell_nr = state->pgc->nr_of_cells;
+ } else {
+ /* Find start cell of program. */
+ first_cell_nr = state->pgc->program_map[state->pgN-1];
+ /* Find end cell of program */
+ if(state->pgN < state->pgc->nr_of_programs)
+ last_cell_nr = state->pgc->program_map[state->pgN] - 1;
+ else
+ last_cell_nr = state->pgc->nr_of_cells;
+ }
+
+ found = 0;
+ for(cell_nr = first_cell_nr; (cell_nr <= last_cell_nr) && !found; cell_nr ++) {
+ cell = &(state->pgc->cell_playback[cell_nr-1]);
+ if(cell->block_type == BLOCK_TYPE_ANGLE_BLOCK && cell->block_mode != BLOCK_MODE_FIRST_CELL)
+ continue;
+ length = cell->last_sector - cell->first_sector + 1;
+ if (target >= length) {
+ target -= length;
+ } else {
+ /* convert the target sector from Cell-relative to absolute physical sector */
+ target += cell->first_sector;
+ found = 1;
+ break;
+ }
+ }
+
+ if(found) {
+ uint32_t vobu;
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: Seeking to cell %i from choice of %i to %i\n",
+ cell_nr, first_cell_nr, last_cell_nr);
+#endif
+ if (dvdnav_scan_admap(this, state->domain, target, &vobu) == DVDNAV_STATUS_OK) {
+ int32_t start = state->pgc->cell_playback[cell_nr-1].first_sector;
+
+ if (vm_jump_cell_block(this->vm, cell_nr, vobu - start)) {
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: After cellN=%u blockN=%u target=%x vobu=%x start=%x\n" ,
+ state->cellN, state->blockN, target, vobu, start);
+#endif
+ this->vm->hop_channel += HOP_SEEK;
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+ }
+ }
+ }
+
+ fprintf(MSG_OUT, "libdvdnav: Error when seeking\n");
+ fprintf(MSG_OUT, "libdvdnav: FIXME: Implement seeking to location %u\n", target);
+ printerr("Error when seeking.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+}
+
+dvdnav_status_t dvdnav_part_search(dvdnav_t *this, int32_t part) {
+ int32_t title, old_part;
+
+ if (dvdnav_current_title_info(this, &title, &old_part) == DVDNAV_STATUS_OK)
+ return dvdnav_part_play(this, title, part);
+ return DVDNAV_STATUS_ERR;
+}
+
+dvdnav_status_t dvdnav_prev_pg_search(dvdnav_t *this) {
+ pthread_mutex_lock(&this->vm_lock);
+ if(!this->vm->state.pgc) {
+ printerr("No current PGC.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: previous chapter\n");
+#endif
+ if (!vm_jump_prev_pg(this->vm)) {
+ fprintf(MSG_OUT, "libdvdnav: previous chapter failed.\n");
+ printerr("Skip to previous chapter failed.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ this->cur_cell_time = 0;
+ this->position_current.still = 0;
+ this->vm->hop_channel++;
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: previous chapter done\n");
+#endif
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_top_pg_search(dvdnav_t *this) {
+ pthread_mutex_lock(&this->vm_lock);
+ if(!this->vm->state.pgc) {
+ printerr("No current PGC.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: top chapter\n");
+#endif
+ if (!vm_jump_top_pg(this->vm)) {
+ fprintf(MSG_OUT, "libdvdnav: top chapter failed.\n");
+ printerr("Skip to top chapter failed.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ this->cur_cell_time = 0;
+ this->position_current.still = 0;
+ this->vm->hop_channel++;
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: top chapter done\n");
+#endif
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_next_pg_search(dvdnav_t *this) {
+ vm_t *try_vm;
+
+ pthread_mutex_lock(&this->vm_lock);
+ if(!this->vm->state.pgc) {
+ printerr("No current PGC.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: next chapter\n");
+#endif
+ /* make a copy of current VM and try to navigate the copy to the next PG */
+ try_vm = vm_new_copy(this->vm);
+ if (!vm_jump_next_pg(try_vm) || try_vm->stopped) {
+ vm_free_copy(try_vm);
+ /* next_pg failed, try to jump at least to the next cell */
+ try_vm = vm_new_copy(this->vm);
+ vm_get_next_cell(try_vm);
+ if (try_vm->stopped) {
+ vm_free_copy(try_vm);
+ fprintf(MSG_OUT, "libdvdnav: next chapter failed.\n");
+ printerr("Skip to next chapter failed.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ }
+ this->cur_cell_time = 0;
+ /* merge changes on success */
+ vm_merge(this->vm, try_vm);
+ vm_free_copy(try_vm);
+ this->position_current.still = 0;
+ this->vm->hop_channel++;
+#ifdef LOG_DEBUG
+ fprintf(MSG_OUT, "libdvdnav: next chapter done\n");
+#endif
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_menu_call(dvdnav_t *this, DVDMenuID_t menu) {
+ vm_t *try_vm;
+
+ pthread_mutex_lock(&this->vm_lock);
+ if(!this->vm->state.pgc) {
+ printerr("No current PGC.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+
+ this->cur_cell_time = 0;
+ /* make a copy of current VM and try to navigate the copy to the menu */
+ try_vm = vm_new_copy(this->vm);
+ if ( (menu == DVD_MENU_Escape) && (this->vm->state.domain != VTS_DOMAIN)) {
+ /* Try resume */
+ if (vm_jump_resume(try_vm) && !try_vm->stopped) {
+ /* merge changes on success */
+ vm_merge(this->vm, try_vm);
+ vm_free_copy(try_vm);
+ this->position_current.still = 0;
+ this->vm->hop_channel++;
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+ }
+ }
+ if (menu == DVD_MENU_Escape) menu = DVD_MENU_Root;
+
+ if (vm_jump_menu(try_vm, menu) && !try_vm->stopped) {
+ /* merge changes on success */
+ vm_merge(this->vm, try_vm);
+ vm_free_copy(try_vm);
+ this->position_current.still = 0;
+ this->vm->hop_channel++;
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+ } else {
+ vm_free_copy(try_vm);
+ printerr("No such menu or menu not reachable.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+}
+
+dvdnav_status_t dvdnav_get_position(dvdnav_t *this, uint32_t *pos,
+ uint32_t *len) {
+ uint32_t cur_sector;
+ int32_t cell_nr, first_cell_nr, last_cell_nr;
+ cell_playback_t *cell;
+ dvd_state_t *state;
+
+ if(!this->started) {
+ printerr("Virtual DVD machine not started.");
+ return DVDNAV_STATUS_ERR;
+ }
+
+ pthread_mutex_lock(&this->vm_lock);
+ state = &(this->vm->state);
+ if(!state->pgc || this->vm->stopped) {
+ printerr("No current PGC.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+ if (this->position_current.hop_channel != this->vm->hop_channel ||
+ this->position_current.domain != state->domain ||
+ this->position_current.vts != state->vtsN ||
+ this->position_current.cell_restart != state->cell_restart) {
+ printerr("New position not yet determined.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+
+ /* Get current sector */
+ cur_sector = this->vobu.vobu_start + this->vobu.blockN;
+
+ if (this->pgc_based) {
+ first_cell_nr = 1;
+ last_cell_nr = state->pgc->nr_of_cells;
+ } else {
+ /* Find start cell of program. */
+ first_cell_nr = state->pgc->program_map[state->pgN-1];
+ /* Find end cell of program */
+ if(state->pgN < state->pgc->nr_of_programs)
+ last_cell_nr = state->pgc->program_map[state->pgN] - 1;
+ else
+ last_cell_nr = state->pgc->nr_of_cells;
+ }
+
+ *pos = -1;
+ *len = 0;
+ for (cell_nr = first_cell_nr; cell_nr <= last_cell_nr; cell_nr++) {
+ cell = &(state->pgc->cell_playback[cell_nr-1]);
+ if (cell_nr == state->cellN) {
+ /* the current sector is in this cell,
+ * pos is length of PG up to here + sector's offset in this cell */
+ *pos = *len + cur_sector - cell->first_sector;
+ }
+ *len += cell->last_sector - cell->first_sector + 1;
+ }
+
+ assert((signed)*pos != -1);
+
+ pthread_mutex_unlock(&this->vm_lock);
+
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_get_position_in_title(dvdnav_t *this,
+ uint32_t *pos,
+ uint32_t *len) {
+ uint32_t cur_sector;
+ uint32_t first_cell_nr;
+ uint32_t last_cell_nr;
+ cell_playback_t *first_cell;
+ cell_playback_t *last_cell;
+ dvd_state_t *state;
+
+ state = &(this->vm->state);
+ if(!state->pgc) {
+ printerr("No current PGC.");
+ return DVDNAV_STATUS_ERR;
+ }
+
+ /* Get current sector */
+ cur_sector = this->vobu.vobu_start + this->vobu.blockN;
+
+ /* Now find first and last cells in title. */
+ first_cell_nr = state->pgc->program_map[0];
+ first_cell = &(state->pgc->cell_playback[first_cell_nr-1]);
+ last_cell_nr = state->pgc->nr_of_cells;
+ last_cell = &(state->pgc->cell_playback[last_cell_nr-1]);
+
+ *pos = cur_sector - first_cell->first_sector;
+ *len = last_cell->last_sector - first_cell->first_sector;
+
+ return DVDNAV_STATUS_OK;
+}
+
+uint32_t dvdnav_describe_title_chapters(dvdnav_t *this, int32_t title, uint64_t **times, uint64_t *duration) {
+ int32_t retval=0;
+ uint16_t parts, i;
+ title_info_t *ptitle = NULL;
+ ptt_info_t *ptt = NULL;
+ ifo_handle_t *ifo;
+ pgc_t *pgc;
+ cell_playback_t *cell;
+ uint64_t length, *tmp=NULL;
+
+ *times = NULL;
+ *duration = 0;
+ pthread_mutex_lock(&this->vm_lock);
+ if(!this->vm->vmgi) {
+ printerr("Bad VM state or missing VTSI.");
+ goto fail;
+ }
+ if(!this->started) {
+ /* don't report an error but be nice */
+ vm_start(this->vm);
+ this->started = 1;
+ }
+ ifo = vm_get_title_ifo(this->vm, title);
+ if(!ifo || !ifo->vts_pgcit) {
+ printerr("Couldn't open IFO for chosen title, exit.");
+ goto fail;
+ }
+
+ ptitle = &this->vm->vmgi->tt_srpt->title[title-1];
+ parts = ptitle->nr_of_ptts;
+ ptt = ifo->vts_ptt_srpt->title[ptitle->vts_ttn-1].ptt;
+
+ tmp = calloc(1, sizeof(uint64_t)*parts);
+ if(!tmp)
+ goto fail;
+
+ length = 0;
+ for(i=0; i<parts; i++) {
+ uint32_t cellnr, endcellnr;
+ pgc = ifo->vts_pgcit->pgci_srp[ptt[i].pgcn-1].pgc;
+ if(ptt[i].pgn > pgc->nr_of_programs) {
+ printerr("WRONG part number.");
+ goto fail;
+ }
+
+ cellnr = pgc->program_map[ptt[i].pgn-1];
+ if(ptt[i].pgn < pgc->nr_of_programs)
+ endcellnr = pgc->program_map[ptt[i].pgn];
+ else
+ endcellnr = 0;
+
+ do {
+ cell = &pgc->cell_playback[cellnr-1];
+ if(!(cell->block_type == BLOCK_TYPE_ANGLE_BLOCK &&
+ cell->block_mode != BLOCK_MODE_FIRST_CELL
+ ))
+ {
+ tmp[i] = length + dvdnav_convert_time(&cell->playback_time);
+ length = tmp[i];
+ }
+ cellnr++;
+ } while(cellnr < endcellnr);
+ }
+ *duration = length;
+ vm_ifo_close(ifo);
+ retval = parts;
+ *times = tmp;
+
+fail:
+ pthread_mutex_unlock(&this->vm_lock);
+ if(!retval && tmp)
+ free(tmp);
+ return retval;
+}
+
+dvdnav_status_t dvdnav_get_state(dvdnav_t *this, dvd_state_t *save_state)
+{
+ if(!this || !this->vm) return DVDNAV_STATUS_ERR;
+
+ pthread_mutex_lock(&this->vm_lock);
+
+ if( !vm_get_state(this->vm, save_state) )
+ {
+ printerr("Failed to get vm state.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_set_state(dvdnav_t *this, dvd_state_t *save_state)
+{
+ if(!this || !this->vm)
+ {
+ printerr("Passed a NULL pointer.");
+ return DVDNAV_STATUS_ERR;
+ }
+
+ if(!this->started) {
+ printerr("Virtual DVD machine not started.");
+ return DVDNAV_STATUS_ERR;
+ }
+
+ pthread_mutex_lock(&this->vm_lock);
+
+ /* reset the dvdnav state */
+ memset(&this->pci,0,sizeof(this->pci));
+ memset(&this->dsi,0,sizeof(this->dsi));
+ this->last_cmd_nav_lbn = SRI_END_OF_CELL;
+
+ /* Set initial values of flags */
+ this->position_current.still = 0;
+ this->skip_still = 0;
+ this->sync_wait = 0;
+ this->sync_wait_skip = 0;
+ this->spu_clut_changed = 0;
+
+
+ /* set the state. this will also start the vm on that state */
+ /* means the next read block should be comming from that new */
+ /* state */
+ if( !vm_set_state(this->vm, save_state) )
+ {
+ printerr("Failed to set vm state.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+}
diff --git a/lib/libdvd/libdvdnav/src/settings.c b/lib/libdvd/libdvdnav/src/settings.c
new file mode 100644
index 0000000000..7261f1d502
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/settings.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
+ *
+ * This file is part of libdvdnav, a DVD navigation library.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: settings.c 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <inttypes.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/time.h>
+#include "dvd_types.h"
+#include <dvdread/nav_types.h>
+#include <dvdread/ifo_types.h>
+#include "remap.h"
+#include "vm/decoder.h"
+#include "vm/vm.h"
+#include "dvdnav.h"
+#include "dvdnav_internal.h"
+
+/* Characteristics/setting API calls */
+
+dvdnav_status_t dvdnav_get_region_mask(dvdnav_t *this, int32_t *region) {
+ (*region) = this->vm->state.registers.SPRM[20];
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_set_region_mask(dvdnav_t *this, int32_t mask) {
+ pthread_mutex_lock(&this->vm_lock);
+ this->vm->state.registers.SPRM[20] = (mask & 0xff);
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_set_readahead_flag(dvdnav_t *this, int32_t use_readahead) {
+ this->use_read_ahead = use_readahead;
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_get_readahead_flag(dvdnav_t *this, int32_t *flag) {
+ (*flag) = this->use_read_ahead;
+ return DVDNAV_STATUS_OK;
+}
+
+static dvdnav_status_t set_language_register(dvdnav_t *this, char *code, int reg) {
+ if(!code[0] || !code[1]) {
+ printerr("Passed illegal language code.");
+ return DVDNAV_STATUS_ERR;
+ }
+
+ pthread_mutex_lock(&this->vm_lock);
+ this->vm->state.registers.SPRM[reg] = (code[0] << 8) | code[1];
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_menu_language_select(dvdnav_t *this, char *code) {
+ return set_language_register(this, code, 0);
+}
+
+dvdnav_status_t dvdnav_audio_language_select(dvdnav_t *this, char *code) {
+ return set_language_register(this, code, 16);
+}
+
+dvdnav_status_t dvdnav_spu_language_select(dvdnav_t *this, char *code) {
+ return set_language_register(this, code, 18);
+}
+
+dvdnav_status_t dvdnav_set_PGC_positioning_flag(dvdnav_t *this, int32_t pgc) {
+ this->pgc_based = pgc;
+ return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_get_PGC_positioning_flag(dvdnav_t *this, int32_t *flag) {
+ (*flag) = this->pgc_based;
+ return DVDNAV_STATUS_OK;
+}
diff --git a/lib/libdvd/libdvdnav/src/vm/Makefile.am b/lib/libdvd/libdvdnav/src/vm/Makefile.am
new file mode 100644
index 0000000000..67a4811aed
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/vm/Makefile.am
@@ -0,0 +1,16 @@
+include $(top_srcdir)/misc/Makefile.common
+
+includedir = ${prefix}/include/dvdnav
+
+AM_CPPFLAGS = -DDVDNAV_COMPILE $(THREAD_CFLAGS) $(DVDREAD_CFLAGS) \
+ -I$(top_srcdir)/src
+
+noinst_LTLIBRARIES = libdvdvm.la
+
+libdvdvm_la_SOURCES = decoder.c vm.c vmcmd.c
+
+libdvdvm_la_LDFLAGS = $(THREAD_LIBS)
+
+include_HEADERS =
+
+noinst_HEADERS = decoder.h vm.h vmcmd.h
diff --git a/lib/libdvd/libdvdnav/src/vm/decoder.c b/lib/libdvd/libdvdnav/src/vm/decoder.c
new file mode 100644
index 0000000000..8a26c1d558
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/vm/decoder.c
@@ -0,0 +1,788 @@
+/*
+ * Copyright (C) 2000, 2001 Martin Norbäck, Håkan Hjort
+ * 2002-2004 the dvdnav project
+ *
+ * This file is part of libdvdnav, a DVD navigation library. It is modified
+ * from a file originally part of the Ogle DVD player.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: decoder.c 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <string.h> /* For memset */
+#include <sys/time.h>
+#include <dvdread/nav_types.h>
+#include <dvdread/ifo_types.h> /* vm_cmd_t */
+
+#include "dvd_types.h"
+#include "remap.h"
+#include "decoder.h"
+#include "vm.h"
+#include "vmcmd.h"
+#include "dvdnav.h"
+#include "dvdnav_internal.h"
+
+uint32_t vm_getbits(command_t *command, int32_t start, int32_t count) {
+ uint64_t result = 0;
+ uint64_t bit_mask = 0;
+ uint64_t examining = 0;
+ int32_t bits;
+
+ if (count == 0) return 0;
+
+ if ( ((start - count) < -1) ||
+ (count > 32) ||
+ (start > 63) ||
+ (count < 0) ||
+ (start < 0) ) {
+ fprintf(MSG_OUT, "libdvdnav: Bad call to vm_getbits. Parameter out of range\n");
+ abort();
+ }
+ /* all ones, please */
+ bit_mask = ~bit_mask;
+ bit_mask >>= 63 - start;
+ bits = start + 1 - count;
+ examining = ((bit_mask >> bits) << bits );
+ command->examined |= examining;
+ result = (command->instruction & bit_mask) >> bits;
+ return (uint32_t) result;
+}
+
+static uint16_t get_GPRM(registers_t* registers, uint8_t reg) {
+ if (registers->GPRM_mode[reg] & 0x01) {
+ struct timeval current_time, time_offset;
+ uint16_t result;
+ /* Counter mode */
+ /* fprintf(MSG_OUT, "libdvdnav: Getting counter %d\n",reg);*/
+ gettimeofday(&current_time, NULL);
+ time_offset.tv_sec = current_time.tv_sec - registers->GPRM_time[reg].tv_sec;
+ time_offset.tv_usec = current_time.tv_usec - registers->GPRM_time[reg].tv_usec;
+ if (time_offset.tv_usec < 0) {
+ time_offset.tv_sec--;
+ time_offset.tv_usec += 1000000;
+ }
+ result = (uint16_t) (time_offset.tv_sec & 0xffff);
+ registers->GPRM[reg]=result;
+ return result;
+
+ } else {
+ /* Register mode */
+ return registers->GPRM[reg];
+ }
+
+}
+
+static void set_GPRM(registers_t* registers, uint8_t reg, uint16_t value) {
+ if (registers->GPRM_mode[reg] & 0x01) {
+ struct timeval current_time;
+ /* Counter mode */
+ /* fprintf(MSG_OUT, "libdvdnav: Setting counter %d\n",reg); */
+ gettimeofday(&current_time, NULL);
+ registers->GPRM_time[reg] = current_time;
+ registers->GPRM_time[reg].tv_sec -= value;
+ }
+ registers->GPRM[reg] = value;
+}
+
+/* Eval register code, can either be system or general register.
+ SXXX_XXXX, where S is 1 if it is system register. */
+static uint16_t eval_reg(command_t* command, uint8_t reg) {
+ if(reg & 0x80) {
+ if ((reg & 0x1f) == 20) {
+ fprintf(MSG_OUT, "libdvdnav: Suspected RCE Region Protection!!!\n");
+ }
+ return command->registers->SPRM[reg & 0x1f]; /* FIXME max 24 not 32 */
+ } else {
+ return get_GPRM(command->registers, reg & 0x0f) ;
+ }
+}
+
+/* Eval register or immediate data.
+ AAAA_AAAA BBBB_BBBB, if immediate use all 16 bits for data else use
+ lower eight bits for the system or general purpose register. */
+static uint16_t eval_reg_or_data(command_t* command, int32_t imm, int32_t start) {
+ if(imm) { /* immediate */
+ return vm_getbits(command, start, 16);
+ } else {
+ return eval_reg(command, vm_getbits(command, (start - 8), 8));
+ }
+}
+
+/* Eval register or immediate data.
+ xBBB_BBBB, if immediate use all 7 bits for data else use
+ lower four bits for the general purpose register number. */
+/* Evaluates gprm or data depending on bit, data is in byte n */
+static uint16_t eval_reg_or_data_2(command_t* command,
+ int32_t imm, int32_t start) {
+ if(imm) /* immediate */
+ return vm_getbits(command, (start - 1), 7);
+ else
+ return get_GPRM(command->registers, (vm_getbits(command, (start - 4), 4)) );
+}
+
+
+/* Compare data using operation, return result from comparison.
+ Helper function for the different if functions. */
+static int32_t eval_compare(uint8_t operation, uint16_t data1, uint16_t data2) {
+ switch(operation) {
+ case 1:
+ return data1 & data2;
+ case 2:
+ return data1 == data2;
+ case 3:
+ return data1 != data2;
+ case 4:
+ return data1 >= data2;
+ case 5:
+ return data1 > data2;
+ case 6:
+ return data1 <= data2;
+ case 7:
+ return data1 < data2;
+ }
+ fprintf(MSG_OUT, "libdvdnav: eval_compare: Invalid comparison code\n");
+ return 0;
+}
+
+
+/* Evaluate if version 1.
+ Has comparison data in byte 3 and 4-5 (immediate or register) */
+static int32_t eval_if_version_1(command_t* command) {
+ uint8_t op = vm_getbits(command, 54, 3);
+ if(op) {
+ return eval_compare(op, eval_reg(command, vm_getbits(command, 39, 8)),
+ eval_reg_or_data(command, vm_getbits(command, 55, 1), 31));
+ }
+ return 1;
+}
+
+/* Evaluate if version 2.
+ This version only compares register which are in byte 6 and 7 */
+static int32_t eval_if_version_2(command_t* command) {
+ uint8_t op = vm_getbits(command, 54, 3);
+ if(op) {
+ return eval_compare(op, eval_reg(command, vm_getbits(command, 15, 8)),
+ eval_reg(command, vm_getbits(command, 7, 8)));
+ }
+ return 1;
+}
+
+/* Evaluate if version 3.
+ Has comparison data in byte 2 and 6-7 (immediate or register) */
+static int32_t eval_if_version_3(command_t* command) {
+ uint8_t op = vm_getbits(command, 54, 3);
+ if(op) {
+ return eval_compare(op, eval_reg(command, vm_getbits(command, 47, 8)),
+ eval_reg_or_data(command, vm_getbits(command, 55, 1), 15));
+ }
+ return 1;
+}
+
+/* Evaluate if version 4.
+ Has comparison data in byte 1 and 4-5 (immediate or register)
+ The register in byte 1 is only the lowe nibble (4 bits) */
+static int32_t eval_if_version_4(command_t* command) {
+ uint8_t op = vm_getbits(command, 54, 3);
+ if(op) {
+ return eval_compare(op, eval_reg(command, vm_getbits(command, 51, 4)),
+ eval_reg_or_data(command, vm_getbits(command, 55, 1), 31));
+ }
+ return 1;
+}
+
+/* Evaluate special instruction.... returns the new row/line number,
+ 0 if no new row and 256 if Break. */
+static int32_t eval_special_instruction(command_t* command, int32_t cond) {
+ int32_t line, level;
+
+ switch(vm_getbits(command, 51, 4)) {
+ case 0: /* NOP */
+ line = 0;
+ return cond ? line : 0;
+ case 1: /* Goto line */
+ line = vm_getbits(command, 7, 8);
+ return cond ? line : 0;
+ case 2: /* Break */
+ /* max number of rows < 256, so we will end this set */
+ line = 256;
+ return cond ? 256 : 0;
+ case 3: /* Set temporary parental level and goto */
+ line = vm_getbits(command, 7, 8);
+ level = vm_getbits(command, 11, 4);
+ if(cond) {
+ /* This always succeeds now, if we want real parental protection */
+ /* we need to ask the user and have passwords and stuff. */
+ command->registers->SPRM[13] = level;
+ }
+ return cond ? line : 0;
+ }
+ return 0;
+}
+
+/* Evaluate link by subinstruction.
+ Return 1 if link, or 0 if no link
+ Actual link instruction is in return_values parameter */
+static int32_t eval_link_subins(command_t* command, int32_t cond, link_t *return_values) {
+ uint16_t button = vm_getbits(command, 15, 6);
+ uint8_t linkop = vm_getbits(command, 4, 5);
+
+ if(linkop > 0x10)
+ return 0; /* Unknown Link by Sub-Instruction command */
+
+ /* Assumes that the link_cmd_t enum has the same values as the LinkSIns codes */
+ return_values->command = linkop;
+ return_values->data1 = button;
+ return cond;
+}
+
+
+/* Evaluate link instruction.
+ Return 1 if link, or 0 if no link
+ Actual link instruction is in return_values parameter */
+static int32_t eval_link_instruction(command_t* command, int32_t cond, link_t *return_values) {
+ uint8_t op = vm_getbits(command, 51, 4);
+
+ switch(op) {
+ case 1:
+ return eval_link_subins(command, cond, return_values);
+ case 4:
+ return_values->command = LinkPGCN;
+ return_values->data1 = vm_getbits(command, 14, 15);
+ return cond;
+ case 5:
+ return_values->command = LinkPTTN;
+ return_values->data1 = vm_getbits(command, 9, 10);
+ return_values->data2 = vm_getbits(command, 15, 6);
+ return cond;
+ case 6:
+ return_values->command = LinkPGN;
+ return_values->data1 = vm_getbits(command, 6, 7);
+ return_values->data2 = vm_getbits(command, 15, 6);
+ return cond;
+ case 7:
+ return_values->command = LinkCN;
+ return_values->data1 = vm_getbits(command, 7, 8);
+ return_values->data2 = vm_getbits(command, 15, 6);
+ return cond;
+ }
+ return 0;
+}
+
+
+/* Evaluate a jump instruction.
+ returns 1 if jump or 0 if no jump
+ actual jump instruction is in return_values parameter */
+static int32_t eval_jump_instruction(command_t* command, int32_t cond, link_t *return_values) {
+
+ switch(vm_getbits(command, 51, 4)) {
+ case 1:
+ return_values->command = Exit;
+ return cond;
+ case 2:
+ return_values->command = JumpTT;
+ return_values->data1 = vm_getbits(command, 22, 7);
+ return cond;
+ case 3:
+ return_values->command = JumpVTS_TT;
+ return_values->data1 = vm_getbits(command, 22, 7);
+ return cond;
+ case 5:
+ return_values->command = JumpVTS_PTT;
+ return_values->data1 = vm_getbits(command, 22, 7);
+ return_values->data2 = vm_getbits(command, 41, 10);
+ return cond;
+ case 6:
+ switch(vm_getbits(command, 23, 2)) {
+ case 0:
+ return_values->command = JumpSS_FP;
+ return cond;
+ case 1:
+ return_values->command = JumpSS_VMGM_MENU;
+ return_values->data1 = vm_getbits(command, 19, 4);
+ return cond;
+ case 2:
+ return_values->command = JumpSS_VTSM;
+ return_values->data1 = vm_getbits(command, 31, 8);
+ return_values->data2 = vm_getbits(command, 39, 8);
+ return_values->data3 = vm_getbits(command, 19, 4);
+ return cond;
+ case 3:
+ return_values->command = JumpSS_VMGM_PGC;
+ return_values->data1 = vm_getbits(command, 46, 15);
+ return cond;
+ }
+ break;
+ case 8:
+ switch(vm_getbits(command, 23, 2)) {
+ case 0:
+ return_values->command = CallSS_FP;
+ return_values->data1 = vm_getbits(command, 31, 8);
+ return cond;
+ case 1:
+ return_values->command = CallSS_VMGM_MENU;
+ return_values->data1 = vm_getbits(command, 19, 4);
+ return_values->data2 = vm_getbits(command, 31, 8);
+ return cond;
+ case 2:
+ return_values->command = CallSS_VTSM;
+ return_values->data1 = vm_getbits(command, 19, 4);
+ return_values->data2 = vm_getbits(command, 31, 8);
+ return cond;
+ case 3:
+ return_values->command = CallSS_VMGM_PGC;
+ return_values->data1 = vm_getbits(command, 46, 15);
+ return_values->data2 = vm_getbits(command, 31, 8);
+ return cond;
+ }
+ break;
+ }
+ return 0;
+}
+
+/* Evaluate a set sytem register instruction
+ May contain a link so return the same as eval_link */
+static int32_t eval_system_set(command_t* command, int32_t cond, link_t *return_values) {
+ int32_t i;
+ uint16_t data, data2;
+
+ switch(vm_getbits(command, 59, 4)) {
+ case 1: /* Set system reg 1 &| 2 &| 3 (Audio, Subp. Angle) */
+ for(i = 1; i <= 3; i++) {
+ if(vm_getbits(command, 63 - ((2 + i)*8), 1)) {
+ data = eval_reg_or_data_2(command, vm_getbits(command, 60, 1), (47 - (i*8)));
+ if(cond) {
+ command->registers->SPRM[i] = data;
+ }
+ }
+ }
+ break;
+ case 2: /* Set system reg 9 & 10 (Navigation timer, Title PGC number) */
+ data = eval_reg_or_data(command, vm_getbits(command, 60, 1), 47);
+ data2 = vm_getbits(command, 23, 8); /* ?? size */
+ if(cond) {
+ command->registers->SPRM[9] = data; /* time */
+ command->registers->SPRM[10] = data2; /* pgcN */
+ }
+ break;
+ case 3: /* Mode: Counter / Register + Set */
+ data = eval_reg_or_data(command, vm_getbits(command, 60, 1), 47);
+ data2 = vm_getbits(command, 19, 4);
+ if(vm_getbits(command, 23, 1)) {
+ command->registers->GPRM_mode[data2] |= 1; /* Set bit 0 */
+ } else {
+ command->registers->GPRM_mode[data2] &= ~ 0x01; /* Reset bit 0 */
+ }
+ if(cond) {
+ set_GPRM(command->registers, data2, data);
+ }
+ break;
+ case 6: /* Set system reg 8 (Highlighted button) */
+ data = eval_reg_or_data(command, vm_getbits(command, 60, 1), 31); /* Not system reg!! */
+ if(cond) {
+ command->registers->SPRM[8] = data;
+ }
+ break;
+ }
+ if(vm_getbits(command, 51, 4)) {
+ return eval_link_instruction(command, cond, return_values);
+ }
+ return 0;
+}
+
+
+/* Evaluate set operation
+ Sets the register given to the value indicated by op and data.
+ For the swap case the contents of reg is stored in reg2.
+*/
+static void eval_set_op(command_t* command, int32_t op, int32_t reg, int32_t reg2, int32_t data) {
+ static const int32_t shortmax = 0xffff;
+ int32_t tmp;
+ switch(op) {
+ case 1:
+ set_GPRM(command->registers, reg, data);
+ break;
+ case 2: /* SPECIAL CASE - SWAP! */
+ set_GPRM(command->registers, reg2, get_GPRM(command->registers, reg));
+ set_GPRM(command->registers, reg, data);
+ break;
+ case 3:
+ tmp = get_GPRM(command->registers, reg) + data;
+ if(tmp > shortmax) tmp = shortmax;
+ set_GPRM(command->registers, reg, (uint16_t)tmp);
+ break;
+ case 4:
+ tmp = get_GPRM(command->registers, reg) - data;
+ if(tmp < 0) tmp = 0;
+ set_GPRM(command->registers, reg, (uint16_t)tmp);
+ break;
+ case 5:
+ tmp = get_GPRM(command->registers, reg) * data;
+ if(tmp > shortmax) tmp = shortmax;
+ set_GPRM(command->registers, reg, (uint16_t)tmp);
+ break;
+ case 6:
+ if (data != 0) {
+ set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) / data) );
+ } else {
+ set_GPRM(command->registers, reg, 0xffff); /* Avoid that divide by zero! */
+ }
+ break;
+ case 7:
+ if (data != 0) {
+ set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) % data) );
+ } else {
+ set_GPRM(command->registers, reg, 0xffff); /* Avoid that divide by zero! */
+ }
+ break;
+ case 8: /* SPECIAL CASE - RND! Return numbers between 1 and data. */
+ set_GPRM(command->registers, reg, 1 + ((uint16_t) ((float) data * rand()/(RAND_MAX+1.0))) );
+ break;
+ case 9:
+ set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) & data) );
+ break;
+ case 10:
+ set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) | data) );
+ break;
+ case 11:
+ set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) ^ data) );
+ break;
+ }
+}
+
+/* Evaluate set instruction, combined with either Link or Compare. */
+static void eval_set_version_1(command_t* command, int32_t cond) {
+ uint8_t op = vm_getbits(command, 59, 4);
+ uint8_t reg = vm_getbits(command, 35, 4); /* FIXME: This is different from vmcmd.c!!! */
+ uint8_t reg2 = vm_getbits(command, 19, 4);
+ uint16_t data = eval_reg_or_data(command, vm_getbits(command, 60, 1), 31);
+
+ if(cond) {
+ eval_set_op(command, op, reg, reg2, data);
+ }
+}
+
+
+/* Evaluate set instruction, combined with both Link and Compare. */
+static void eval_set_version_2(command_t* command, int32_t cond) {
+ uint8_t op = vm_getbits(command, 59, 4);
+ uint8_t reg = vm_getbits(command, 51, 4);
+ uint8_t reg2 = vm_getbits(command, 35, 4); /* FIXME: This is different from vmcmd.c!!! */
+ uint16_t data = eval_reg_or_data(command, vm_getbits(command, 60, 1), 47);
+
+ if(cond) {
+ eval_set_op(command, op, reg, reg2, data);
+ }
+}
+
+
+/* Evaluate a command
+ returns row number of goto, 0 if no goto, -1 if link.
+ Link command in return_values */
+static int32_t eval_command(uint8_t *bytes, registers_t* registers, link_t *return_values) {
+ int32_t cond, res = 0;
+ command_t command;
+ command.instruction =( (uint64_t) bytes[0] << 56 ) |
+ ( (uint64_t) bytes[1] << 48 ) |
+ ( (uint64_t) bytes[2] << 40 ) |
+ ( (uint64_t) bytes[3] << 32 ) |
+ ( (uint64_t) bytes[4] << 24 ) |
+ ( (uint64_t) bytes[5] << 16 ) |
+ ( (uint64_t) bytes[6] << 8 ) |
+ (uint64_t) bytes[7] ;
+ command.examined = 0;
+ command.registers = registers;
+ memset(return_values, 0, sizeof(link_t));
+
+ switch(vm_getbits(&command, 63, 3)) { /* three first old_bits */
+ case 0: /* Special instructions */
+ cond = eval_if_version_1(&command);
+ res = eval_special_instruction(&command, cond);
+ if(res == -1) {
+ fprintf(MSG_OUT, "libdvdnav: Unknown Instruction!\n");
+ abort();
+ }
+ break;
+ case 1: /* Link/jump instructions */
+ if(vm_getbits(&command, 60, 1)) {
+ cond = eval_if_version_2(&command);
+ res = eval_jump_instruction(&command, cond, return_values);
+ } else {
+ cond = eval_if_version_1(&command);
+ res = eval_link_instruction(&command, cond, return_values);
+ }
+ if(res)
+ res = -1;
+ break;
+ case 2: /* System set instructions */
+ cond = eval_if_version_2(&command);
+ res = eval_system_set(&command, cond, return_values);
+ if(res)
+ res = -1;
+ break;
+ case 3: /* Set instructions, either Compare or Link may be used */
+ cond = eval_if_version_3(&command);
+ eval_set_version_1(&command, cond);
+ if(vm_getbits(&command, 51, 4)) {
+ res = eval_link_instruction(&command, cond, return_values);
+ }
+ if(res)
+ res = -1;
+ break;
+ case 4: /* Set, Compare -> Link Sub-Instruction */
+ eval_set_version_2(&command, /*True*/ 1);
+ cond = eval_if_version_4(&command);
+ res = eval_link_subins(&command, cond, return_values);
+ if(res)
+ res = -1;
+ break;
+ case 5: /* Compare -> (Set and Link Sub-Instruction) */
+ /* FIXME: These are wrong. Need to be updated from vmcmd.c */
+ cond = eval_if_version_4(&command);
+ eval_set_version_2(&command, cond);
+ res = eval_link_subins(&command, cond, return_values);
+ if(res)
+ res = -1;
+ break;
+ case 6: /* Compare -> Set, allways Link Sub-Instruction */
+ /* FIXME: These are wrong. Need to be updated from vmcmd.c */
+ cond = eval_if_version_4(&command);
+ eval_set_version_2(&command, cond);
+ res = eval_link_subins(&command, /*True*/ 1, return_values);
+ if(res)
+ res = -1;
+ break;
+ default: /* Unknown command */
+ fprintf(MSG_OUT, "libdvdnav: WARNING: Unknown Command=%x\n", vm_getbits(&command, 63, 3));
+ abort();
+ }
+ /* Check if there are bits not yet examined */
+
+ if(command.instruction & ~ command.examined) {
+ fprintf(MSG_OUT, "libdvdnav: decoder.c: [WARNING, unknown bits:");
+ fprintf(MSG_OUT, " %08"PRIx64, (command.instruction & ~ command.examined) );
+ fprintf(MSG_OUT, "]\n");
+ }
+
+ return res;
+}
+
+/* Evaluate a set of commands in the given register set (which is modified) */
+int32_t vmEval_CMD(vm_cmd_t commands[], int32_t num_commands,
+ registers_t *registers, link_t *return_values) {
+ int32_t i = 0;
+ int32_t total = 0;
+
+#ifdef TRACE
+ /* DEBUG */
+ fprintf(MSG_OUT, "libdvdnav: Registers before transaction\n");
+ vm_print_registers( registers );
+ fprintf(MSG_OUT, "libdvdnav: Full list of commands to execute\n");
+ for(i = 0; i < num_commands; i++)
+ vm_print_cmd(i, &commands[i]);
+ fprintf(MSG_OUT, "libdvdnav: --------------------------------------------\n");
+ fprintf(MSG_OUT, "libdvdnav: Single stepping commands\n");
+#endif
+
+ i = 0;
+ while(i < num_commands && total < 100000) {
+ int32_t line;
+
+#ifdef TRACE
+ vm_print_cmd(i, &commands[i]);
+#endif
+
+ line = eval_command(&commands[i].bytes[0], registers, return_values);
+
+ if (line < 0) { /* Link command */
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: Registers after transaction\n");
+ vm_print_registers( registers );
+ fprintf(MSG_OUT, "libdvdnav: eval: Doing Link/Jump/Call\n");
+#endif
+ return 1;
+ }
+
+ if (line > 0) /* Goto command */
+ i = line - 1;
+ else /* Just continue on the next line */
+ i++;
+
+ total++;
+ }
+
+ memset(return_values, 0, sizeof(link_t));
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: Registers after transaction\n");
+ vm_print_registers( registers );
+#endif
+ return 0;
+}
+
+#ifdef TRACE
+
+static char *linkcmd2str(link_cmd_t cmd) {
+ switch(cmd) {
+ case LinkNoLink:
+ return "LinkNoLink";
+ case LinkTopC:
+ return "LinkTopC";
+ case LinkNextC:
+ return "LinkNextC";
+ case LinkPrevC:
+ return "LinkPrevC";
+ case LinkTopPG:
+ return "LinkTopPG";
+ case LinkNextPG:
+ return "LinkNextPG";
+ case LinkPrevPG:
+ return "LinkPrevPG";
+ case LinkTopPGC:
+ return "LinkTopPGC";
+ case LinkNextPGC:
+ return "LinkNextPGC";
+ case LinkPrevPGC:
+ return "LinkPrevPGC";
+ case LinkGoUpPGC:
+ return "LinkGoUpPGC";
+ case LinkTailPGC:
+ return "LinkTailPGC";
+ case LinkRSM:
+ return "LinkRSM";
+ case LinkPGCN:
+ return "LinkPGCN";
+ case LinkPTTN:
+ return "LinkPTTN";
+ case LinkPGN:
+ return "LinkPGN";
+ case LinkCN:
+ return "LinkCN";
+ case Exit:
+ return "Exit";
+ case JumpTT:
+ return "JumpTT";
+ case JumpVTS_TT:
+ return "JumpVTS_TT";
+ case JumpVTS_PTT:
+ return "JumpVTS_PTT";
+ case JumpSS_FP:
+ return "JumpSS_FP";
+ case JumpSS_VMGM_MENU:
+ return "JumpSS_VMGM_MENU";
+ case JumpSS_VTSM:
+ return "JumpSS_VTSM";
+ case JumpSS_VMGM_PGC:
+ return "JumpSS_VMGM_PGC";
+ case CallSS_FP:
+ return "CallSS_FP";
+ case CallSS_VMGM_MENU:
+ return "CallSS_VMGM_MENU";
+ case CallSS_VTSM:
+ return "CallSS_VTSM";
+ case CallSS_VMGM_PGC:
+ return "CallSS_VMGM_PGC";
+ case PlayThis:
+ return "PlayThis";
+ }
+ return "*** (bug)";
+}
+
+void vm_print_link(link_t value) {
+ char *cmd = linkcmd2str(value.command);
+
+ switch(value.command) {
+ case LinkNoLink:
+ case LinkTopC:
+ case LinkNextC:
+ case LinkPrevC:
+ case LinkTopPG:
+ case LinkNextPG:
+ case LinkPrevPG:
+ case LinkTopPGC:
+ case LinkNextPGC:
+ case LinkPrevPGC:
+ case LinkGoUpPGC:
+ case LinkTailPGC:
+ case LinkRSM:
+ fprintf(MSG_OUT, "libdvdnav: %s (button %d)\n", cmd, value.data1);
+ break;
+ case LinkPGCN:
+ case JumpTT:
+ case JumpVTS_TT:
+ case JumpSS_VMGM_MENU: /* == 2 -> Title Menu */
+ case JumpSS_VMGM_PGC:
+ fprintf(MSG_OUT, "libdvdnav: %s %d\n", cmd, value.data1);
+ break;
+ case LinkPTTN:
+ case LinkPGN:
+ case LinkCN:
+ fprintf(MSG_OUT, "libdvdnav: %s %d (button %d)\n", cmd, value.data1, value.data2);
+ break;
+ case Exit:
+ case JumpSS_FP:
+ case PlayThis: /* Humm.. should we have this at all.. */
+ fprintf(MSG_OUT, "libdvdnav: %s\n", cmd);
+ break;
+ case JumpVTS_PTT:
+ fprintf(MSG_OUT, "libdvdnav: %s %d:%d\n", cmd, value.data1, value.data2);
+ break;
+ case JumpSS_VTSM:
+ fprintf(MSG_OUT, "libdvdnav: %s vts %d title %d menu %d\n",
+ cmd, value.data1, value.data2, value.data3);
+ break;
+ case CallSS_FP:
+ fprintf(MSG_OUT, "libdvdnav: %s resume cell %d\n", cmd, value.data1);
+ break;
+ case CallSS_VMGM_MENU: /* == 2 -> Title Menu */
+ case CallSS_VTSM:
+ fprintf(MSG_OUT, "libdvdnav: %s %d resume cell %d\n", cmd, value.data1, value.data2);
+ break;
+ case CallSS_VMGM_PGC:
+ fprintf(MSG_OUT, "libdvdnav: %s %d resume cell %d\n", cmd, value.data1, value.data2);
+ break;
+ }
+ }
+
+void vm_print_registers( registers_t *registers ) {
+ int32_t i;
+ fprintf(MSG_OUT, "libdvdnav: # ");
+ for(i = 0; i < 24; i++)
+ fprintf(MSG_OUT, " %2d |", i);
+ fprintf(MSG_OUT, "\nlibdvdnav: SRPMS: ");
+ for(i = 0; i < 24; i++)
+ fprintf(MSG_OUT, "%04x|", registers->SPRM[i]);
+ fprintf(MSG_OUT, "\nlibdvdnav: GRPMS: ");
+ for(i = 0; i < 16; i++)
+ fprintf(MSG_OUT, "%04x|", get_GPRM(registers, i) );
+ fprintf(MSG_OUT, "\nlibdvdnav: Gmode: ");
+ for(i = 0; i < 16; i++)
+ fprintf(MSG_OUT, "%04x|", registers->GPRM_mode[i]);
+ fprintf(MSG_OUT, "\nlibdvdnav: Gtime: ");
+ for(i = 0; i < 16; i++)
+ fprintf(MSG_OUT, "%04lx|", registers->GPRM_time[i].tv_sec & 0xffff);
+ fprintf(MSG_OUT, "\n");
+}
+
+#endif
+
diff --git a/lib/libdvd/libdvdnav/src/vm/decoder.h b/lib/libdvd/libdvdnav/src/vm/decoder.h
new file mode 100644
index 0000000000..1e834a786d
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/vm/decoder.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2000, 2001 Martin Norbäck, Håkan Hjort
+ *
+ * This file is part of libdvdnav, a DVD navigation library. It is modified
+ * from a file originally part of the Ogle DVD player.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: decoder.h 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+#ifndef DECODER_H_INCLUDED
+#define DECODER_H_INCLUDED
+
+/* link command types */
+typedef enum {
+ LinkNoLink = 0,
+
+ LinkTopC = 1,
+ LinkNextC = 2,
+ LinkPrevC = 3,
+
+ LinkTopPG = 5,
+ LinkNextPG = 6,
+ LinkPrevPG = 7,
+
+ LinkTopPGC = 9,
+ LinkNextPGC = 10,
+ LinkPrevPGC = 11,
+ LinkGoUpPGC = 12,
+ LinkTailPGC = 13,
+
+ LinkRSM = 16,
+
+ LinkPGCN,
+ LinkPTTN,
+ LinkPGN,
+ LinkCN,
+
+ Exit,
+
+ JumpTT, /* 22 */
+ JumpVTS_TT,
+ JumpVTS_PTT,
+
+ JumpSS_FP,
+ JumpSS_VMGM_MENU,
+ JumpSS_VTSM,
+ JumpSS_VMGM_PGC,
+
+ CallSS_FP, /* 29 */
+ CallSS_VMGM_MENU,
+ CallSS_VTSM,
+ CallSS_VMGM_PGC,
+
+ PlayThis
+} link_cmd_t;
+
+/* a link's data set */
+typedef struct {
+ link_cmd_t command;
+ uint16_t data1;
+ uint16_t data2;
+ uint16_t data3;
+} link_t;
+
+/* the VM registers */
+typedef struct {
+ uint16_t SPRM[24];
+ uint16_t GPRM[16];
+ uint8_t GPRM_mode[16]; /* Need to have some thing to indicate normal/counter mode for every GPRM */
+ struct timeval GPRM_time[16]; /* For counter mode */
+} registers_t;
+
+/* a VM command data set */
+typedef struct {
+ uint64_t instruction;
+ uint64_t examined;
+ registers_t *registers;
+} command_t;
+
+/* the big VM function, executing the given commands and writing
+ * the link where to continue, the return value indicates if a jump
+ * has been performed */
+int32_t vmEval_CMD(vm_cmd_t commands[], int32_t num_commands,
+ registers_t *registers, link_t *return_values);
+
+/* extracts some bits from the command */
+uint32_t vm_getbits(command_t* command, int32_t start, int32_t count);
+
+#ifdef TRACE
+/* for debugging: prints a link in readable form */
+void vm_print_link(link_t value);
+
+/* for debugging: dumps VM registers */
+void vm_print_registers( registers_t *registers );
+#endif
+
+#endif /* DECODER_H_INCLUDED */
diff --git a/lib/libdvd/libdvdnav/src/vm/vm.c b/lib/libdvd/libdvdnav/src/vm/vm.c
new file mode 100644
index 0000000000..9c9a5c4d2a
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/vm/vm.c
@@ -0,0 +1,1947 @@
+/*
+ * Copyright (C) 2000, 2001 Håkan Hjort
+ * Copyright (C) 2001 Rich Wareham <richwareham@users.sourceforge.net>
+ * 2002-2004 the dvdnav project
+ *
+ * This file is part of libdvdnav, a DVD navigation library. It is modified
+ * from a file originally part of the Ogle DVD player.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: vm.c 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+
+#include <dvdread/nav_types.h>
+#include <dvdread/ifo_types.h>
+#include <dvdread/ifo_read.h>
+#include "dvd_types.h"
+
+#include "decoder.h"
+#include "remap.h"
+#include "vm.h"
+#include "dvdnav.h"
+#include "dvdnav_internal.h"
+
+#ifdef _MSC_VER
+#include <io.h> /* read() */
+#endif /* _MSC_VER */
+
+/*
+#define STRICT
+*/
+
+/* Local prototypes */
+
+/* get_XYZ returns a value.
+ * set_XYZ sets state using passed parameters.
+ * returns success/failure.
+ */
+
+/* Play */
+static link_t play_PGC(vm_t *vm);
+static link_t play_PGC_PG(vm_t *vm, int pgN);
+static link_t play_PGC_post(vm_t *vm);
+static link_t play_PG(vm_t *vm);
+static link_t play_Cell(vm_t *vm);
+static link_t play_Cell_post(vm_t *vm);
+
+/* Process link - returns 1 if a hop has been performed */
+static int process_command(vm_t *vm,link_t link_values);
+
+/* Set */
+static int set_TT(vm_t *vm, int tt);
+static int set_PTT(vm_t *vm, int tt, int ptt);
+static int set_VTS_TT(vm_t *vm, int vtsN, int vts_ttn);
+static int set_VTS_PTT(vm_t *vm, int vtsN, int vts_ttn, int part);
+static int set_FP_PGC(vm_t *vm);
+static int set_MENU(vm_t *vm, int menu);
+static int set_PGCN(vm_t *vm, int pgcN);
+static int set_PGN(vm_t *vm); /* Set PGN based on (vm->state).CellN */
+static void set_RSMinfo(vm_t *vm, int cellN, int blockN);
+
+/* Get */
+static int get_TT(vm_t *vm, int vtsN, int vts_ttn);
+static int get_ID(vm_t *vm, int id);
+static int get_PGCN(vm_t *vm);
+
+static pgcit_t* get_MENU_PGCIT(vm_t *vm, ifo_handle_t *h, uint16_t lang);
+static pgcit_t* get_PGCIT(vm_t *vm);
+
+
+/* Helper functions */
+
+#ifdef TRACE
+static void vm_print_current_domain_state(vm_t *vm) {
+ switch((vm->state).domain) {
+ case VTS_DOMAIN:
+ fprintf(MSG_OUT, "libdvdnav: Video Title Domain: -\n");
+ break;
+
+ case VTSM_DOMAIN:
+ fprintf(MSG_OUT, "libdvdnav: Video Title Menu Domain: -\n");
+ break;
+
+ case VMGM_DOMAIN:
+ fprintf(MSG_OUT, "libdvdnav: Video Manager Menu Domain: -\n");
+ break;
+
+ case FP_DOMAIN:
+ fprintf(MSG_OUT, "libdvdnav: First Play Domain: -\n");
+ break;
+
+ default:
+ fprintf(MSG_OUT, "libdvdnav: Unknown Domain: -\n");
+ break;
+ }
+ fprintf(MSG_OUT, "libdvdnav: VTS:%d PGC:%d PG:%u CELL:%u BLOCK:%u VTS_TTN:%u TTN:%u TT_PGCN:%u\n",
+ (vm->state).vtsN,
+ get_PGCN(vm),
+ (vm->state).pgN,
+ (vm->state).cellN,
+ (vm->state).blockN,
+ (vm->state).VTS_TTN_REG,
+ (vm->state).TTN_REG,
+ (vm->state).TT_PGCN_REG);
+}
+#endif
+
+static void dvd_read_name(char *name, const char *device) {
+ /* Because we are compiling with _FILE_OFFSET_BITS=64
+ * all off_t are 64bit.
+ */
+ off_t off;
+ int fd, i;
+ uint8_t data[DVD_VIDEO_LB_LEN];
+
+ /* Read DVD name */
+ fd = open(device, O_RDONLY);
+ if (fd > 0) {
+ off = lseek( fd, 32 * (off_t) DVD_VIDEO_LB_LEN, SEEK_SET );
+ if( off == ( 32 * (off_t) DVD_VIDEO_LB_LEN ) ) {
+ off = read( fd, data, DVD_VIDEO_LB_LEN );
+ close(fd);
+ if (off == ( (off_t) DVD_VIDEO_LB_LEN )) {
+ fprintf(MSG_OUT, "libdvdnav: DVD Title: ");
+ for(i=25; i < 73; i++ ) {
+ if((data[i] == 0)) break;
+ if((data[i] > 32) && (data[i] < 127)) {
+ fprintf(MSG_OUT, "%c", data[i]);
+ } else {
+ fprintf(MSG_OUT, " ");
+ }
+ }
+ strncpy(name, (char*) &data[25], 48);
+ name[48] = 0;
+ fprintf(MSG_OUT, "\nlibdvdnav: DVD Serial Number: ");
+ for(i=73; i < 89; i++ ) {
+ if((data[i] == 0)) break;
+ if((data[i] > 32) && (data[i] < 127)) {
+ fprintf(MSG_OUT, "%c", data[i]);
+ } else {
+ fprintf(MSG_OUT, " ");
+ }
+ }
+ fprintf(MSG_OUT, "\nlibdvdnav: DVD Title (Alternative): ");
+ for(i=89; i < 128; i++ ) {
+ if((data[i] == 0)) break;
+ if((data[i] > 32) && (data[i] < 127)) {
+ fprintf(MSG_OUT, "%c", data[i]);
+ } else {
+ fprintf(MSG_OUT, " ");
+ }
+ }
+ fprintf(MSG_OUT, "\n");
+ } else {
+ fprintf(MSG_OUT, "libdvdnav: Can't read name block. Probably not a DVD-ROM device.\n");
+ }
+ } else {
+ fprintf(MSG_OUT, "libdvdnav: Can't seek to block %u\n", 32 );
+ }
+ close(fd);
+ } else {
+ fprintf(MSG_OUT, "NAME OPEN FAILED\n");
+ }
+}
+
+static int ifoOpenNewVTSI(vm_t *vm, dvd_reader_t *dvd, int vtsN) {
+ if((vm->state).vtsN == vtsN) {
+ return 1; /* We alread have it */
+ }
+
+ if(vm->vtsi != NULL)
+ ifoClose(vm->vtsi);
+
+ vm->vtsi = ifoOpenVTSI(dvd, vtsN);
+ if(vm->vtsi == NULL) {
+ fprintf(MSG_OUT, "libdvdnav: ifoOpenVTSI failed\n");
+ return 0;
+ }
+ if(!ifoRead_VTS_PTT_SRPT(vm->vtsi)) {
+ fprintf(MSG_OUT, "libdvdnav: ifoRead_VTS_PTT_SRPT failed\n");
+ return 0;
+ }
+ if(!ifoRead_PGCIT(vm->vtsi)) {
+ fprintf(MSG_OUT, "libdvdnav: ifoRead_PGCIT failed\n");
+ return 0;
+ }
+ if(!ifoRead_PGCI_UT(vm->vtsi)) {
+ fprintf(MSG_OUT, "libdvdnav: ifoRead_PGCI_UT failed\n");
+ return 0;
+ }
+ if(!ifoRead_VOBU_ADMAP(vm->vtsi)) {
+ fprintf(MSG_OUT, "libdvdnav: ifoRead_VOBU_ADMAP vtsi failed\n");
+ return 0;
+ }
+ if(!ifoRead_TITLE_VOBU_ADMAP(vm->vtsi)) {
+ fprintf(MSG_OUT, "libdvdnav: ifoRead_TITLE_VOBU_ADMAP vtsi failed\n");
+ return 0;
+ }
+ if(!ifoRead_VTS_TMAPT(vm->vtsi)) {
+ fprintf(MSG_OUT, "libdvdnav: ifoRead_VTS_TMAPT vtsi failed\n");
+ return 0;
+ }
+ if(!ifoRead_TITLE_C_ADT(vm->vtsi)) {
+ fprintf(MSG_OUT, "libdvdnav: ifoRead_TITLE_C_ADT vtsi failed\n");
+ return 0;
+ }
+
+ (vm->state).vtsN = vtsN;
+
+ return 1;
+}
+
+
+/* Initialisation & Destruction */
+
+vm_t* vm_new_vm() {
+ return (vm_t*)calloc(sizeof(vm_t), sizeof(char));
+}
+
+void vm_free_vm(vm_t *vm) {
+ vm_stop(vm);
+ free(vm);
+}
+
+
+/* IFO Access */
+
+ifo_handle_t *vm_get_vmgi(vm_t *vm) {
+ return vm->vmgi;
+}
+
+ifo_handle_t *vm_get_vtsi(vm_t *vm) {
+ return vm->vtsi;
+}
+
+
+/* Reader Access */
+
+dvd_reader_t *vm_get_dvd_reader(vm_t *vm) {
+ return vm->dvd;
+}
+
+
+/* Basic Handling */
+
+int vm_start(vm_t *vm) {
+ /* Set pgc to FP (First Play) pgc */
+ set_FP_PGC(vm);
+ process_command(vm, play_PGC(vm));
+ return !vm->stopped;
+}
+
+void vm_stop(vm_t *vm) {
+ if(vm->vmgi) {
+ ifoClose(vm->vmgi);
+ vm->vmgi=NULL;
+ }
+ if(vm->vtsi) {
+ ifoClose(vm->vtsi);
+ vm->vtsi=NULL;
+ }
+ if(vm->dvd) {
+ DVDClose(vm->dvd);
+ vm->dvd=NULL;
+ }
+ vm->stopped = 1;
+}
+
+int vm_reset(vm_t *vm, const char *dvdroot) {
+ /* Setup State */
+ memset((vm->state).registers.SPRM, 0, sizeof((vm->state).registers.SPRM));
+ memset((vm->state).registers.GPRM, 0, sizeof((vm->state).registers.GPRM));
+ memset((vm->state).registers.GPRM_mode, 0, sizeof((vm->state).registers.GPRM_mode));
+ memset((vm->state).registers.GPRM_mode, 0, sizeof((vm->state).registers.GPRM_mode));
+ memset((vm->state).registers.GPRM_time, 0, sizeof((vm->state).registers.GPRM_time));
+ (vm->state).registers.SPRM[0] = ('e'<<8)|'n'; /* Player Menu Languange code */
+ (vm->state).AST_REG = 15; /* 15 why? */
+ (vm->state).SPST_REG = 62; /* 62 why? */
+ (vm->state).AGL_REG = 1;
+ (vm->state).TTN_REG = 1;
+ (vm->state).VTS_TTN_REG = 1;
+ /* (vm->state).TT_PGCN_REG = 0 */
+ (vm->state).PTTN_REG = 1;
+ (vm->state).HL_BTNN_REG = 1 << 10;
+ (vm->state).PTL_REG = 15; /* Parental Level */
+ (vm->state).registers.SPRM[12] = ('U'<<8)|'S'; /* Parental Management Country Code */
+ (vm->state).registers.SPRM[16] = ('e'<<8)|'n'; /* Initial Language Code for Audio */
+ (vm->state).registers.SPRM[18] = ('e'<<8)|'n'; /* Initial Language Code for Spu */
+ (vm->state).registers.SPRM[20] = 0x1; /* Player Regional Code Mask. Region free! */
+ (vm->state).registers.SPRM[14] = 0x100; /* Try Pan&Scan */
+
+ (vm->state).pgN = 0;
+ (vm->state).cellN = 0;
+ (vm->state).cell_restart = 0;
+
+ (vm->state).domain = FP_DOMAIN;
+ (vm->state).rsm_vtsN = 0;
+ (vm->state).rsm_cellN = 0;
+ (vm->state).rsm_blockN = 0;
+
+ (vm->state).vtsN = -1;
+
+ if (vm->dvd && dvdroot) {
+ /* a new dvd device has been requested */
+ vm_stop(vm);
+ }
+ if (!vm->dvd) {
+ vm->dvd = DVDOpen(dvdroot);
+ if(!vm->dvd) {
+ fprintf(MSG_OUT, "libdvdnav: vm: failed to open/read the DVD\n");
+ return 0;
+ }
+#ifdef _XBMC
+ if(DVDUDFVolumeInfo(vm->dvd, vm->dvd_name, sizeof(vm->dvd_name), NULL, 0))
+ if(DVDISOVolumeInfo(vm->dvd, vm->dvd_name, sizeof(vm->dvd_name), NULL, 0))
+ strcpy(vm->dvd_name, "");
+
+ fprintf(MSG_OUT, "libdvdnav: vm: DVD Title: %s\n", vm->dvd_name);
+#else
+ dvd_read_name(vm->dvd_name, dvdroot);
+#endif
+ vm->map = remap_loadmap(vm->dvd_name);
+ vm->vmgi = ifoOpenVMGI(vm->dvd);
+ if(!vm->vmgi) {
+ fprintf(MSG_OUT, "libdvdnav: vm: failed to read VIDEO_TS.IFO\n");
+ return 0;
+ }
+ if(!ifoRead_FP_PGC(vm->vmgi)) {
+ fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_FP_PGC failed\n");
+ return 0;
+ }
+ if(!ifoRead_TT_SRPT(vm->vmgi)) {
+ fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_TT_SRPT failed\n");
+ return 0;
+ }
+ if(!ifoRead_PGCI_UT(vm->vmgi)) {
+ fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_PGCI_UT failed\n");
+ return 0;
+ }
+ if(!ifoRead_PTL_MAIT(vm->vmgi)) {
+ fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_PTL_MAIT failed\n");
+ /* return 0; Not really used for now.. */
+ }
+ if(!ifoRead_VTS_ATRT(vm->vmgi)) {
+ fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_VTS_ATRT failed\n");
+ /* return 0; Not really used for now.. */
+ }
+ if(!ifoRead_VOBU_ADMAP(vm->vmgi)) {
+ fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_VOBU_ADMAP vgmi failed\n");
+ /* return 0; Not really used for now.. */
+ }
+ /* ifoRead_TXTDT_MGI(vmgi); Not implemented yet */
+ }
+ if (vm->vmgi) {
+ int i, mask;
+ fprintf(MSG_OUT, "libdvdnav: DVD disk reports itself with Region mask 0x%08x. Regions:",
+ vm->vmgi->vmgi_mat->vmg_category);
+ for (i = 1, mask = 1; i <= 8; i++, mask <<= 1)
+ if (((vm->vmgi->vmgi_mat->vmg_category >> 16) & mask) == 0)
+ fprintf(MSG_OUT, " %d", i);
+ fprintf(MSG_OUT, "\n");
+ }
+ return 1;
+}
+
+
+/* copying and merging */
+
+vm_t *vm_new_copy(vm_t *source) {
+ vm_t *target = vm_new_vm();
+ int vtsN;
+ int pgcN = get_PGCN(source);
+ int pgN = (source->state).pgN;
+
+ assert(pgcN);
+
+ memcpy(target, source, sizeof(vm_t));
+
+ /* open a new vtsi handle, because the copy might switch to another VTS */
+ target->vtsi = NULL;
+ vtsN = (target->state).vtsN;
+ if (vtsN > 0) {
+ (target->state).vtsN = 0;
+ if (!ifoOpenNewVTSI(target, target->dvd, vtsN))
+ assert(0);
+
+ /* restore pgc pointer into the new vtsi */
+ if (!set_PGCN(target, pgcN))
+ assert(0);
+ (target->state).pgN = pgN;
+ }
+
+ return target;
+}
+
+void vm_merge(vm_t *target, vm_t *source) {
+ if(target->vtsi)
+ ifoClose(target->vtsi);
+ memcpy(target, source, sizeof(vm_t));
+ memset(source, 0, sizeof(vm_t));
+}
+
+void vm_free_copy(vm_t *vm) {
+ if(vm->vtsi)
+ ifoClose(vm->vtsi);
+ free(vm);
+}
+
+
+/* regular playback */
+
+void vm_position_get(vm_t *vm, vm_position_t *position) {
+ position->button = (vm->state).HL_BTNN_REG >> 10;
+ position->vts = (vm->state).vtsN;
+ position->domain = (vm->state).domain;
+ position->spu_channel = (vm->state).SPST_REG;
+ position->audio_channel = (vm->state).AST_REG;
+ position->angle_channel = (vm->state).AGL_REG;
+ position->hop_channel = vm->hop_channel; /* Increases by one on each hop */
+ position->cell = (vm->state).cellN;
+ position->cell_restart = (vm->state).cell_restart;
+ position->cell_start = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].first_sector;
+ position->still = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].still_time;
+ position->block = (vm->state).blockN;
+
+ /* handle PGC stills at PGC end */
+ if ((vm->state).cellN == (vm->state).pgc->nr_of_cells)
+ position->still += (vm->state).pgc->still_time;
+ /* still already determined */
+ if (position->still)
+ return;
+ /* This is a rough fix for some strange still situations on some strange DVDs.
+ * There are discs (like the German "Back to the Future" RC2) where the only
+ * indication of a still is a cell playback time higher than the time the frames
+ * in this cell actually take to play (like 1 frame with 1 minute playback time).
+ * On the said BTTF disc, for these cells last_sector and last_vobu_start_sector
+ * are equal and the cells are very short, so we abuse these conditions to
+ * detect such discs. I consider these discs broken, so the fix is somewhat
+ * broken, too. */
+ if (((vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_sector ==
+ (vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_vobu_start_sector) &&
+ ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_sector -
+ (vm->state).pgc->cell_playback[(vm->state).cellN - 1].first_sector < 1024)) {
+ int time;
+ int size = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_sector -
+ (vm->state).pgc->cell_playback[(vm->state).cellN - 1].first_sector;
+ time = ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.hour >> 4 ) * 36000;
+ time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.hour & 0x0f) * 3600;
+ time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.minute >> 4 ) * 600;
+ time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.minute & 0x0f) * 60;
+ time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.second >> 4 ) * 10;
+ time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.second & 0x0f) * 1;
+ if (!time || size / time > 30)
+ /* datarate is too high, it might be a very short, but regular cell */
+ return;
+ if (time > 0xff) time = 0xff;
+ position->still = time;
+ }
+}
+
+void vm_get_next_cell(vm_t *vm) {
+ process_command(vm, play_Cell_post(vm));
+}
+
+
+/* Jumping */
+
+int vm_jump_pg(vm_t *vm, int pg) {
+ (vm->state).pgN = pg;
+ process_command(vm, play_PG(vm));
+ return 1;
+}
+
+int vm_jump_cell_block(vm_t *vm, int cell, int block) {
+ (vm->state).cellN = cell;
+ process_command(vm, play_Cell(vm));
+ /* play_Cell can jump to a different cell in case of angles */
+ if ((vm->state).cellN == cell)
+ (vm->state).blockN = block;
+ return 1;
+}
+
+int vm_jump_title_part(vm_t *vm, int title, int part) {
+ link_t link;
+
+ if(!set_PTT(vm, title, part))
+ return 0;
+ /* Some DVDs do not want us to jump directly into a title and have
+ * PGC pre commands taking us back to some menu. Since we do not like that,
+ * we do not execute PGC pre commands that would do a jump. */
+ /* process_command(vm, play_PGC_PG(vm, (vm->state).pgN)); */
+ link = play_PGC_PG(vm, (vm->state).pgN);
+ if (link.command != PlayThis)
+ /* jump occured -> ignore it and play the PG anyway */
+ process_command(vm, play_PG(vm));
+ else
+ process_command(vm, link);
+ return 1;
+}
+
+int vm_jump_top_pg(vm_t *vm) {
+ process_command(vm, play_PG(vm));
+ return 1;
+}
+
+int vm_jump_next_pg(vm_t *vm) {
+ if((vm->state).pgN >= (vm->state).pgc->nr_of_programs) {
+ /* last program -> move to TailPGC */
+ process_command(vm, play_PGC_post(vm));
+ return 1;
+ } else {
+ vm_jump_pg(vm, (vm->state).pgN + 1);
+ return 1;
+ }
+}
+
+int vm_jump_prev_pg(vm_t *vm) {
+ if ((vm->state).pgN <= 1) {
+ /* first program -> move to last program of previous PGC */
+ if ((vm->state).pgc->prev_pgc_nr && set_PGCN(vm, (vm->state).pgc->prev_pgc_nr)) {
+ process_command(vm, play_PGC(vm));
+ vm_jump_pg(vm, (vm->state).pgc->nr_of_programs);
+ return 1;
+ }
+ return 0;
+ } else {
+ vm_jump_pg(vm, (vm->state).pgN - 1);
+ return 1;
+ }
+}
+
+int vm_jump_up(vm_t *vm) {
+ if((vm->state).pgc->goup_pgc_nr && set_PGCN(vm, (vm->state).pgc->goup_pgc_nr)) {
+ process_command(vm, play_PGC(vm));
+ return 1;
+ }
+ return 0;
+}
+
+int vm_jump_menu(vm_t *vm, DVDMenuID_t menuid) {
+ domain_t old_domain = (vm->state).domain;
+
+ switch ((vm->state).domain) {
+ case VTS_DOMAIN:
+ set_RSMinfo(vm, 0, (vm->state).blockN);
+ /* FALL THROUGH */
+ case VTSM_DOMAIN:
+ case VMGM_DOMAIN:
+ switch(menuid) {
+ case DVD_MENU_Title:
+ case DVD_MENU_Escape:
+ (vm->state).domain = VMGM_DOMAIN;
+ break;
+ case DVD_MENU_Root:
+ case DVD_MENU_Subpicture:
+ case DVD_MENU_Audio:
+ case DVD_MENU_Angle:
+ case DVD_MENU_Part:
+ (vm->state).domain = VTSM_DOMAIN;
+ break;
+ }
+ if(get_PGCIT(vm) && set_MENU(vm, menuid)) {
+ process_command(vm, play_PGC(vm));
+ return 1; /* Jump */
+ } else {
+ (vm->state).domain = old_domain;
+ }
+ break;
+ case FP_DOMAIN: /* FIXME XXX $$$ What should we do here? */
+ break;
+ }
+
+ return 0;
+}
+
+int vm_jump_resume(vm_t *vm) {
+ link_t link_values = { LinkRSM, 0, 0, 0 };
+
+ if (!(vm->state).rsm_vtsN) /* Do we have resume info? */
+ return 0;
+ if (!process_command(vm, link_values))
+ return 0;
+ return 1;
+}
+
+int vm_exec_cmd(vm_t *vm, vm_cmd_t *cmd) {
+ link_t link_values;
+
+ if(vmEval_CMD(cmd, 1, &(vm->state).registers, &link_values))
+ return process_command(vm, link_values);
+ else
+ return 0; /* It updated some state thats all... */
+}
+
+
+/* getting information */
+
+int vm_get_current_menu(vm_t *vm, int *menuid) {
+ pgcit_t* pgcit;
+ int pgcn;
+ pgcn = (vm->state).pgcN;
+ pgcit = get_PGCIT(vm);
+ if(pgcit==NULL) return 0;
+ *menuid = pgcit->pgci_srp[pgcn - 1].entry_id & 0xf ;
+ return 1;
+}
+
+int vm_get_current_title_part(vm_t *vm, int *title_result, int *part_result) {
+ vts_ptt_srpt_t *vts_ptt_srpt;
+ int title, part = 0, vts_ttn;
+ int found;
+ int16_t pgcN, pgN;
+
+ vts_ptt_srpt = vm->vtsi->vts_ptt_srpt;
+ pgcN = get_PGCN(vm);
+ pgN = vm->state.pgN;
+
+ found = 0;
+ for (vts_ttn = 0; (vts_ttn < vts_ptt_srpt->nr_of_srpts) && !found; vts_ttn++) {
+ for (part = 0; (part < vts_ptt_srpt->title[vts_ttn].nr_of_ptts) && !found; part++) {
+ if (vts_ptt_srpt->title[vts_ttn].ptt[part].pgcn == pgcN) {
+ if (vts_ptt_srpt->title[vts_ttn].ptt[part].pgn == pgN) {
+ found = 1;
+ break;
+ }
+ if (part > 0 && vts_ptt_srpt->title[vts_ttn].ptt[part].pgn > pgN &&
+ vts_ptt_srpt->title[vts_ttn].ptt[part - 1].pgn < pgN) {
+ part--;
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (found) break;
+ }
+ vts_ttn++;
+ part++;
+
+ if (!found) {
+ fprintf(MSG_OUT, "libdvdnav: chapter NOT FOUND!\n");
+ return 0;
+ }
+
+ title = get_TT(vm, vm->state.vtsN, vts_ttn);
+
+#ifdef TRACE
+ if (title) {
+ fprintf(MSG_OUT, "libdvdnav: ************ this chapter FOUND!\n");
+ fprintf(MSG_OUT, "libdvdnav: VTS_PTT_SRPT - Title %3i part %3i: PGC: %3i PG: %3i\n",
+ title, part,
+ vts_ptt_srpt->title[vts_ttn-1].ptt[part-1].pgcn ,
+ vts_ptt_srpt->title[vts_ttn-1].ptt[part-1].pgn );
+ }
+#endif
+ *title_result = title;
+ *part_result = part;
+ return 1;
+}
+
+/* Return the substream id for 'logical' audio stream audioN.
+ * 0 <= audioN < 8
+ */
+int vm_get_audio_stream(vm_t *vm, int audioN) {
+ int streamN = -1;
+
+ if((vm->state).domain != VTS_DOMAIN)
+ audioN = 0;
+
+ if(audioN < 8) {
+ /* Is there any control info for this logical stream */
+ if((vm->state).pgc->audio_control[audioN] & (1<<15)) {
+ streamN = ((vm->state).pgc->audio_control[audioN] >> 8) & 0x07;
+ }
+ }
+
+ if((vm->state).domain != VTS_DOMAIN && streamN == -1)
+ streamN = 0;
+
+ /* FIXME: Should also check in vtsi/vmgi status what kind of stream
+ * it is (ac3/lpcm/dts/sdds...) to find the right (sub)stream id */
+ return streamN;
+}
+
+/* Return the substream id for 'logical' subpicture stream subpN and given mode.
+ * 0 <= subpN < 32
+ * mode == 0 - widescreen
+ * mode == 1 - letterbox
+ * mode == 2 - pan&scan
+ */
+int vm_get_subp_stream(vm_t *vm, int subpN, int mode) {
+ int streamN = -1;
+ int source_aspect = vm_get_video_aspect(vm);
+
+ if((vm->state).domain != VTS_DOMAIN)
+ subpN = 0;
+
+ if(subpN < 32) { /* a valid logical stream */
+ /* Is this logical stream present */
+ if((vm->state).pgc->subp_control[subpN] & (1<<31)) {
+ if(source_aspect == 0) /* 4:3 */
+ streamN = ((vm->state).pgc->subp_control[subpN] >> 24) & 0x1f;
+ if(source_aspect == 3) /* 16:9 */
+ switch (mode) {
+ case 0:
+ streamN = ((vm->state).pgc->subp_control[subpN] >> 16) & 0x1f;
+ break;
+ case 1:
+ streamN = ((vm->state).pgc->subp_control[subpN] >> 8) & 0x1f;
+ break;
+ case 2:
+ streamN = (vm->state).pgc->subp_control[subpN] & 0x1f;
+ }
+ }
+ }
+
+ if((vm->state).domain != VTS_DOMAIN && streamN == -1)
+ streamN = 0;
+
+ /* FIXME: Should also check in vtsi/vmgi status what kind of stream it is. */
+ return streamN;
+}
+
+int vm_get_audio_active_stream(vm_t *vm) {
+ int audioN;
+ int streamN;
+ audioN = (vm->state).AST_REG ;
+ streamN = vm_get_audio_stream(vm, audioN);
+
+ /* If no such stream, then select the first one that exists. */
+ if(streamN == -1) {
+ for(audioN = 0; audioN < 8; audioN++) {
+ if((vm->state).pgc->audio_control[audioN] & (1<<15)) {
+ if ((streamN = vm_get_audio_stream(vm, audioN)) >= 0)
+ break;
+ }
+ }
+ }
+
+ return streamN;
+}
+
+int vm_get_subp_active_stream(vm_t *vm, int mode) {
+ int subpN;
+ int streamN;
+ subpN = (vm->state).SPST_REG & ~0x40;
+ streamN = vm_get_subp_stream(vm, subpN, mode);
+
+ /* If no such stream, then select the first one that exists. */
+ if(streamN == -1) {
+ for(subpN = 0; subpN < 32; subpN++) {
+ if((vm->state).pgc->subp_control[subpN] & (1<<31)) {
+ if ((streamN = vm_get_subp_stream(vm, subpN, mode)) >= 0)
+ break;
+ }
+ }
+ }
+
+ if((vm->state).domain == VTS_DOMAIN && !((vm->state).SPST_REG & 0x40))
+ /* Bit 7 set means hide, and only let Forced display show */
+ return (streamN | 0x80);
+ else
+ return streamN;
+}
+
+void vm_get_angle_info(vm_t *vm, int *current, int *num_avail) {
+ *num_avail = 1;
+ *current = 1;
+
+ if((vm->state).domain == VTS_DOMAIN) {
+ title_info_t *title;
+ /* TTN_REG does not allways point to the correct title.. */
+ if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts)
+ return;
+ title = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1];
+ if(title->title_set_nr != (vm->state).vtsN ||
+ title->vts_ttn != (vm->state).VTS_TTN_REG)
+ return;
+ *num_avail = title->nr_of_angles;
+ *current = (vm->state).AGL_REG;
+ }
+}
+
+// XBMC #if 0
+/* currently unused */
+void vm_get_audio_info(vm_t *vm, int *current, int *num_avail) {
+ switch ((vm->state).domain) {
+ case VTS_DOMAIN:
+ *num_avail = vm->vtsi->vtsi_mat->nr_of_vts_audio_streams;
+ *current = (vm->state).AST_REG;
+ break;
+ case VTSM_DOMAIN:
+ *num_avail = vm->vtsi->vtsi_mat->nr_of_vtsm_audio_streams; /* 1 */
+ *current = 1;
+ break;
+ case VMGM_DOMAIN:
+ case FP_DOMAIN:
+ *num_avail = vm->vmgi->vmgi_mat->nr_of_vmgm_audio_streams; /* 1 */
+ *current = 1;
+ break;
+ }
+}
+
+/* currently unused */
+void vm_get_subp_info(vm_t *vm, int *current, int *num_avail) {
+ switch ((vm->state).domain) {
+ case VTS_DOMAIN:
+ *num_avail = vm->vtsi->vtsi_mat->nr_of_vts_subp_streams;
+ *current = (vm->state).SPST_REG;
+ break;
+ case VTSM_DOMAIN:
+ *num_avail = vm->vtsi->vtsi_mat->nr_of_vtsm_subp_streams; /* 1 */
+ *current = 0x41;
+ break;
+ case VMGM_DOMAIN:
+ case FP_DOMAIN:
+ *num_avail = vm->vmgi->vmgi_mat->nr_of_vmgm_subp_streams; /* 1 */
+ *current = 0x41;
+ break;
+ }
+}
+
+/* currently unused */
+void vm_get_video_res(vm_t *vm, int *width, int *height) {
+ video_attr_t attr = vm_get_video_attr(vm);
+
+ if(attr.video_format != 0)
+ *height = 576;
+ else
+ *height = 480;
+ switch(attr.picture_size) {
+ case 0:
+ *width = 720;
+ break;
+ case 1:
+ *width = 704;
+ break;
+ case 2:
+ *width = 352;
+ break;
+ case 3:
+ *width = 352;
+ *height /= 2;
+ break;
+ }
+}
+// XBMC #endif
+
+int vm_get_video_aspect(vm_t *vm) {
+ int aspect = vm_get_video_attr(vm).display_aspect_ratio;
+
+ assert(aspect == 0 || aspect == 3);
+ (vm->state).registers.SPRM[14] &= ~(0x3 << 10);
+ (vm->state).registers.SPRM[14] |= aspect << 10;
+
+ return aspect;
+}
+
+int vm_get_video_scale_permission(vm_t *vm) {
+ return vm_get_video_attr(vm).permitted_df;
+}
+
+video_attr_t vm_get_video_attr(vm_t *vm) {
+ switch ((vm->state).domain) {
+ case VTS_DOMAIN:
+ return vm->vtsi->vtsi_mat->vts_video_attr;
+ case VTSM_DOMAIN:
+ return vm->vtsi->vtsi_mat->vtsm_video_attr;
+ case VMGM_DOMAIN:
+ case FP_DOMAIN:
+ return vm->vmgi->vmgi_mat->vmgm_video_attr;
+ default:
+ abort();
+ }
+}
+
+audio_attr_t vm_get_audio_attr(vm_t *vm, int streamN) {
+ switch ((vm->state).domain) {
+ case VTS_DOMAIN:
+ return vm->vtsi->vtsi_mat->vts_audio_attr[streamN];
+ case VTSM_DOMAIN:
+ return vm->vtsi->vtsi_mat->vtsm_audio_attr;
+ case VMGM_DOMAIN:
+ case FP_DOMAIN:
+ return vm->vmgi->vmgi_mat->vmgm_audio_attr;
+ default:
+ abort();
+ }
+}
+
+subp_attr_t vm_get_subp_attr(vm_t *vm, int streamN) {
+ switch ((vm->state).domain) {
+ case VTS_DOMAIN:
+ return vm->vtsi->vtsi_mat->vts_subp_attr[streamN];
+ case VTSM_DOMAIN:
+ return vm->vtsi->vtsi_mat->vtsm_subp_attr;
+ case VMGM_DOMAIN:
+ case FP_DOMAIN:
+ return vm->vmgi->vmgi_mat->vmgm_subp_attr;
+ default:
+ abort();
+ }
+}
+
+
+/* Playback control */
+
+static link_t play_PGC(vm_t *vm) {
+ link_t link_values;
+
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: play_PGC:");
+ if((vm->state).domain != FP_DOMAIN) {
+ fprintf(MSG_OUT, " (vm->state).pgcN (%i)\n", get_PGCN(vm));
+ } else {
+ fprintf(MSG_OUT, " first_play_pgc\n");
+ }
+#endif
+
+ /* This must be set before the pre-commands are executed because they
+ * might contain a CallSS that will save resume state */
+
+ /* FIXME: This may be only a temporary fix for something... */
+ (vm->state).pgN = 1;
+ (vm->state).cellN = 0;
+ (vm->state).blockN = 0;
+
+ /* eval -> updates the state and returns either
+ - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN)
+ - just play video i.e first PG
+ (This is what happens if you fall of the end of the pre_cmds)
+ - or an error (are there more cases?) */
+ if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_pre) {
+ if(vmEval_CMD((vm->state).pgc->command_tbl->pre_cmds,
+ (vm->state).pgc->command_tbl->nr_of_pre,
+ &(vm->state).registers, &link_values)) {
+ /* link_values contains the 'jump' return value */
+ return link_values;
+ } else {
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: PGC pre commands didn't do a Jump, Link or Call\n");
+#endif
+ }
+ }
+ return play_PG(vm);
+}
+
+static link_t play_PGC_PG(vm_t *vm, int pgN) {
+ link_t link_values;
+
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: play_PGC_PG:");
+ if((vm->state).domain != FP_DOMAIN) {
+ fprintf(MSG_OUT, " (vm->state).pgcN (%i)\n", get_PGCN(vm));
+ } else {
+ fprintf(MSG_OUT, " first_play_pgc\n");
+ }
+#endif
+
+ /* This must be set before the pre-commands are executed because they
+ * might contain a CallSS that will save resume state */
+
+ /* FIXME: This may be only a temporary fix for something... */
+ (vm->state).pgN = pgN;
+ (vm->state).cellN = 0;
+ (vm->state).blockN = 0;
+
+ /* eval -> updates the state and returns either
+ - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN)
+ - just play video i.e first PG
+ (This is what happens if you fall of the end of the pre_cmds)
+ - or an error (are there more cases?) */
+ if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_pre) {
+ if(vmEval_CMD((vm->state).pgc->command_tbl->pre_cmds,
+ (vm->state).pgc->command_tbl->nr_of_pre,
+ &(vm->state).registers, &link_values)) {
+ /* link_values contains the 'jump' return value */
+ return link_values;
+ } else {
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: PGC pre commands didn't do a Jump, Link or Call\n");
+#endif
+ }
+ }
+ return play_PG(vm);
+}
+
+static link_t play_PGC_post(vm_t *vm) {
+ link_t link_values;
+
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: play_PGC_post:\n");
+#endif
+
+ /* eval -> updates the state and returns either
+ - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN)
+ - just go to next PGC
+ (This is what happens if you fall of the end of the post_cmds)
+ - or an error (are there more cases?) */
+ if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_post &&
+ vmEval_CMD((vm->state).pgc->command_tbl->post_cmds,
+ (vm->state).pgc->command_tbl->nr_of_post,
+ &(vm->state).registers, &link_values)) {
+ return link_values;
+ }
+
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: ** Fell of the end of the pgc, continuing in NextPGC\n");
+#endif
+ /* Should end up in the STOP_DOMAIN if next_pgc is 0. */
+ if(!set_PGCN(vm, (vm->state).pgc->next_pgc_nr)) {
+ link_values.command = Exit;
+ return link_values;
+ }
+ return play_PGC(vm);
+}
+
+static link_t play_PG(vm_t *vm) {
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: play_PG: (vm->state).pgN (%i)\n", (vm->state).pgN);
+#endif
+
+ assert((vm->state).pgN > 0);
+ if((vm->state).pgN > (vm->state).pgc->nr_of_programs) {
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: play_PG: (vm->state).pgN (%i) > pgc->nr_of_programs (%i)\n",
+ (vm->state).pgN, (vm->state).pgc->nr_of_programs );
+#endif
+ assert((vm->state).pgN == (vm->state).pgc->nr_of_programs + 1);
+ return play_PGC_post(vm);
+ }
+
+ (vm->state).cellN = (vm->state).pgc->program_map[(vm->state).pgN - 1];
+
+ return play_Cell(vm);
+}
+
+static link_t play_Cell(vm_t *vm) {
+ static const link_t play_this = {PlayThis, /* Block in Cell */ 0, 0, 0};
+
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: play_Cell: (vm->state).cellN (%i)\n", (vm->state).cellN);
+#endif
+
+ assert((vm->state).cellN > 0);
+ if((vm->state).cellN > (vm->state).pgc->nr_of_cells) {
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: (vm->state).cellN (%i) > pgc->nr_of_cells (%i)\n",
+ (vm->state).cellN, (vm->state).pgc->nr_of_cells );
+#endif
+ assert((vm->state).cellN == (vm->state).pgc->nr_of_cells + 1);
+ return play_PGC_post(vm);
+ }
+
+ /* Multi angle/Interleaved */
+ switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode) {
+ case 0: /* Normal */
+ assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 0);
+ break;
+ case 1: /* The first cell in the block */
+ switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type) {
+ case 0: /* Not part of a block */
+ assert(0);
+ break;
+ case 1: /* Angle block */
+ /* Loop and check each cell instead? So we don't get outside the block? */
+ (vm->state).cellN += (vm->state).AGL_REG - 1;
+#ifdef STRICT
+ assert((vm->state).cellN <= (vm->state).pgc->nr_of_cells);
+ assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode != 0);
+ assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 1);
+#else
+ if (!((vm->state).cellN <= (vm->state).pgc->nr_of_cells) ||
+ !((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode != 0) ||
+ !((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 1)) {
+ fprintf(MSG_OUT, "libdvdnav: Invalid angle block\n");
+ (vm->state).cellN -= (vm->state).AGL_REG - 1;
+ }
+#endif
+ break;
+ case 2: /* ?? */
+ case 3: /* ?? */
+ default:
+ fprintf(MSG_OUT, "libdvdnav: Invalid? Cell block_mode (%d), block_type (%d)\n",
+ (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode,
+ (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type);
+ assert(0);
+ }
+ break;
+ case 2: /* Cell in the block */
+ case 3: /* Last cell in the block */
+ /* These might perhaps happen for RSM or LinkC commands? */
+ default:
+ fprintf(MSG_OUT, "libdvdnav: Cell is in block but did not enter at first cell!\n");
+ }
+
+ /* Updates (vm->state).pgN and PTTN_REG */
+ if(!set_PGN(vm)) {
+ /* Should not happen */
+ assert(0);
+ return play_PGC_post(vm);
+ }
+ (vm->state).cell_restart++;
+ (vm->state).blockN = 0;
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: Cell should restart here\n");
+#endif
+ return play_this;
+}
+
+static link_t play_Cell_post(vm_t *vm) {
+ cell_playback_t *cell;
+
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: play_Cell_post: (vm->state).cellN (%i)\n", (vm->state).cellN);
+#endif
+
+ cell = &(vm->state).pgc->cell_playback[(vm->state).cellN - 1];
+
+ /* Still time is already taken care of before we get called. */
+
+ /* Deal with a Cell command, if any */
+ if(cell->cell_cmd_nr != 0) {
+ link_t link_values;
+
+/* These asserts are now not needed.
+ * Some DVDs have no cell commands listed in the PGC,
+ * but the Cell itself points to a cell command that does not exist.
+ * For this situation, just ignore the cell command and continue.
+ *
+ * assert((vm->state).pgc->command_tbl != NULL);
+ * assert((vm->state).pgc->command_tbl->nr_of_cell >= cell->cell_cmd_nr);
+ */
+
+ if ((vm->state).pgc->command_tbl != NULL &&
+ (vm->state).pgc->command_tbl->nr_of_cell >= cell->cell_cmd_nr) {
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: Cell command present, executing\n");
+#endif
+ if(vmEval_CMD(&(vm->state).pgc->command_tbl->cell_cmds[cell->cell_cmd_nr - 1], 1,
+ &(vm->state).registers, &link_values)) {
+ return link_values;
+ } else {
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: Cell command didn't do a Jump, Link or Call\n");
+#endif
+ }
+ } else {
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: Invalid Cell command\n");
+#endif
+ }
+ }
+
+ /* Where to continue after playing the cell... */
+ /* Multi angle/Interleaved */
+ switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode) {
+ case 0: /* Normal */
+ assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 0);
+ (vm->state).cellN++;
+ break;
+ case 1: /* The first cell in the block */
+ case 2: /* A cell in the block */
+ case 3: /* The last cell in the block */
+ default:
+ switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type) {
+ case 0: /* Not part of a block */
+ assert(0);
+ break;
+ case 1: /* Angle block */
+ /* Skip the 'other' angles */
+ (vm->state).cellN++;
+ while((vm->state).cellN <= (vm->state).pgc->nr_of_cells &&
+ (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode >= 2) {
+ (vm->state).cellN++;
+ }
+ break;
+ case 2: /* ?? */
+ case 3: /* ?? */
+ default:
+ fprintf(MSG_OUT, "libdvdnav: Invalid? Cell block_mode (%d), block_type (%d)\n",
+ (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode,
+ (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type);
+ assert(0);
+ }
+ break;
+ }
+
+ /* Figure out the correct pgN for the new cell */
+ if(!set_PGN(vm)) {
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: last cell in this PGC\n");
+#endif
+ return play_PGC_post(vm);
+ }
+ return play_Cell(vm);
+}
+
+
+/* link processing */
+
+static int process_command(vm_t *vm, link_t link_values) {
+
+ while(link_values.command != PlayThis) {
+
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: Before printout starts:\n");
+ vm_print_link(link_values);
+ fprintf(MSG_OUT, "libdvdnav: Link values %i %i %i %i\n", link_values.command,
+ link_values.data1, link_values.data2, link_values.data3);
+ vm_print_current_domain_state(vm);
+ fprintf(MSG_OUT, "libdvdnav: Before printout ends.\n");
+#endif
+
+ switch(link_values.command) {
+ case LinkNoLink:
+ /* BUTTON number:data1 */
+ if(link_values.data1 != 0)
+ (vm->state).HL_BTNN_REG = link_values.data1 << 10;
+ return 0; /* no actual jump */
+
+ case LinkTopC:
+ /* Restart playing from the beginning of the current Cell. */
+ /* BUTTON number:data1 */
+ if(link_values.data1 != 0)
+ (vm->state).HL_BTNN_REG = link_values.data1 << 10;
+ link_values = play_Cell(vm);
+ break;
+ case LinkNextC:
+ /* Link to Next Cell */
+ /* BUTTON number:data1 */
+ if(link_values.data1 != 0)
+ (vm->state).HL_BTNN_REG = link_values.data1 << 10;
+ (vm->state).cellN += 1;
+ link_values = play_Cell(vm);
+ break;
+ case LinkPrevC:
+ /* Link to Previous Cell */
+ /* BUTTON number:data1 */
+ if(link_values.data1 != 0)
+ (vm->state).HL_BTNN_REG = link_values.data1 << 10;
+ assert((vm->state).cellN > 1);
+ (vm->state).cellN -= 1;
+ link_values = play_Cell(vm);
+ break;
+
+ case LinkTopPG:
+ /* Link to Top of current Program */
+ /* BUTTON number:data1 */
+ if(link_values.data1 != 0)
+ (vm->state).HL_BTNN_REG = link_values.data1 << 10;
+ link_values = play_PG(vm);
+ break;
+ case LinkNextPG:
+ /* Link to Next Program */
+ /* BUTTON number:data1 */
+ if(link_values.data1 != 0)
+ (vm->state).HL_BTNN_REG = link_values.data1 << 10;
+ (vm->state).pgN += 1;
+ link_values = play_PG(vm);
+ break;
+ case LinkPrevPG:
+ /* Link to Previous Program */
+ /* BUTTON number:data1 */
+ if(link_values.data1 != 0)
+ (vm->state).HL_BTNN_REG = link_values.data1 << 10;
+ assert((vm->state).pgN > 1);
+ (vm->state).pgN -= 1;
+ link_values = play_PG(vm);
+ break;
+
+ case LinkTopPGC:
+ /* Restart playing from beginning of current Program Chain */
+ /* BUTTON number:data1 */
+ if(link_values.data1 != 0)
+ (vm->state).HL_BTNN_REG = link_values.data1 << 10;
+ link_values = play_PGC(vm);
+ break;
+ case LinkNextPGC:
+ /* Link to Next Program Chain */
+ /* BUTTON number:data1 */
+ if(link_values.data1 != 0)
+ (vm->state).HL_BTNN_REG = link_values.data1 << 10;
+ assert((vm->state).pgc->next_pgc_nr != 0);
+ if(set_PGCN(vm, (vm->state).pgc->next_pgc_nr))
+ link_values = play_PGC(vm);
+ else
+ link_values.command = Exit;
+ break;
+ case LinkPrevPGC:
+ /* Link to Previous Program Chain */
+ /* BUTTON number:data1 */
+ if(link_values.data1 != 0)
+ (vm->state).HL_BTNN_REG = link_values.data1 << 10;
+ assert((vm->state).pgc->prev_pgc_nr != 0);
+ if(set_PGCN(vm, (vm->state).pgc->prev_pgc_nr))
+ link_values = play_PGC(vm);
+ else
+ link_values.command = Exit;
+ break;
+ case LinkGoUpPGC:
+ /* Link to GoUp Program Chain */
+ /* BUTTON number:data1 */
+ if(link_values.data1 != 0)
+ (vm->state).HL_BTNN_REG = link_values.data1 << 10;
+ assert((vm->state).pgc->goup_pgc_nr != 0);
+ if(set_PGCN(vm, (vm->state).pgc->goup_pgc_nr))
+ link_values = play_PGC(vm);
+ else
+ link_values.command = Exit;
+ break;
+ case LinkTailPGC:
+ /* Link to Tail of Program Chain */
+ /* BUTTON number:data1 */
+ if(link_values.data1 != 0)
+ (vm->state).HL_BTNN_REG = link_values.data1 << 10;
+ link_values = play_PGC_post(vm);
+ break;
+
+ case LinkRSM:
+ {
+ /* Link to Resume point */
+ int i;
+
+ /* Check and see if there is any rsm info!! */
+ if (!(vm->state).rsm_vtsN) {
+ fprintf(MSG_OUT, "libdvdnav: trying to resume without any resume info set\n");
+ link_values.command = Exit;
+ break;
+ }
+
+ (vm->state).domain = VTS_DOMAIN;
+ if (!ifoOpenNewVTSI(vm, vm->dvd, (vm->state).rsm_vtsN))
+ assert(0);
+ set_PGCN(vm, (vm->state).rsm_pgcN);
+
+ /* These should never be set in SystemSpace and/or MenuSpace */
+ /* (vm->state).TTN_REG = rsm_tt; ?? */
+ /* (vm->state).TT_PGCN_REG = (vm->state).rsm_pgcN; ?? */
+ for(i = 0; i < 5; i++) {
+ (vm->state).registers.SPRM[4 + i] = (vm->state).rsm_regs[i];
+ }
+
+ if(link_values.data1 != 0)
+ (vm->state).HL_BTNN_REG = link_values.data1 << 10;
+
+ if((vm->state).rsm_cellN == 0) {
+ assert((vm->state).cellN); /* Checking if this ever happens */
+ (vm->state).pgN = 1;
+ link_values = play_PG(vm);
+ } else {
+ /* (vm->state).pgN = ?? this gets the right value in set_PGN() below */
+ (vm->state).cellN = (vm->state).rsm_cellN;
+ link_values.command = PlayThis;
+ link_values.data1 = (vm->state).rsm_blockN & 0xffff;
+ link_values.data2 = (vm->state).rsm_blockN >> 16;
+ if(!set_PGN(vm)) {
+ /* Were at the end of the PGC, should not happen for a RSM */
+ assert(0);
+ link_values.command = LinkTailPGC;
+ link_values.data1 = 0; /* No button */
+ }
+ }
+ }
+ break;
+ case LinkPGCN:
+ /* Link to Program Chain Number:data1 */
+ if(!set_PGCN(vm, link_values.data1))
+ assert(0);
+ link_values = play_PGC(vm);
+ break;
+ case LinkPTTN:
+ /* Link to Part of current Title Number:data1 */
+ /* BUTTON number:data2 */
+ /* PGC Pre-Commands are not executed */
+ assert((vm->state).domain == VTS_DOMAIN);
+ if(link_values.data2 != 0)
+ (vm->state).HL_BTNN_REG = link_values.data2 << 10;
+ if(!set_VTS_PTT(vm, (vm->state).vtsN, (vm->state).VTS_TTN_REG, link_values.data1))
+ assert(0);
+ link_values = play_PG(vm);
+ break;
+ case LinkPGN:
+ /* Link to Program Number:data1 */
+ /* BUTTON number:data2 */
+ if(link_values.data2 != 0)
+ (vm->state).HL_BTNN_REG = link_values.data2 << 10;
+ /* Update any other state, PTTN perhaps? */
+ (vm->state).pgN = link_values.data1;
+ link_values = play_PG(vm);
+ break;
+ case LinkCN:
+ /* Link to Cell Number:data1 */
+ /* BUTTON number:data2 */
+ if(link_values.data2 != 0)
+ (vm->state).HL_BTNN_REG = link_values.data2 << 10;
+ /* Update any other state, pgN, PTTN perhaps? */
+ (vm->state).cellN = link_values.data1;
+ link_values = play_Cell(vm);
+ break;
+
+ case Exit:
+ vm->stopped = 1;
+ return 0;
+
+ case JumpTT:
+ /* Jump to VTS Title Domain */
+ /* Only allowed from the First Play domain(PGC) */
+ /* or the Video Manager domain (VMG) */
+ /* Stop SPRM9 Timer */
+ /* Set SPRM1 and SPRM2 */
+ assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */
+ if(set_TT(vm, link_values.data1))
+ link_values = play_PGC(vm);
+ else
+ link_values.command = Exit;
+ break;
+ case JumpVTS_TT:
+ /* Jump to Title:data1 in same VTS Title Domain */
+ /* Only allowed from the VTS Menu Domain(VTSM) */
+ /* or the Video Title Set Domain(VTS) */
+ /* Stop SPRM9 Timer */
+ /* Set SPRM1 and SPRM2 */
+ assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VTS_DOMAIN); /* ?? */
+ if(!set_VTS_TT(vm, (vm->state).vtsN, link_values.data1))
+ assert(0);
+ link_values = play_PGC(vm);
+ break;
+ case JumpVTS_PTT:
+ /* Jump to Part:data2 of Title:data1 in same VTS Title Domain */
+ /* Only allowed from the VTS Menu Domain(VTSM) */
+ /* or the Video Title Set Domain(VTS) */
+ /* Stop SPRM9 Timer */
+ /* Set SPRM1 and SPRM2 */
+ assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VTS_DOMAIN); /* ?? */
+ if(!set_VTS_PTT(vm, (vm->state).vtsN, link_values.data1, link_values.data2))
+ assert(0);
+ link_values = play_PGC_PG(vm, (vm->state).pgN);
+ break;
+
+ case JumpSS_FP:
+ /* Jump to First Play Domain */
+ /* Only allowed from the VTS Menu Domain(VTSM) */
+ /* or the Video Manager domain (VMG) */
+ /* Stop SPRM9 Timer and any GPRM counters */
+ assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == VTSM_DOMAIN); /* ?? */
+ if (!set_FP_PGC(vm))
+ assert(0);
+ link_values = play_PGC(vm);
+ break;
+ case JumpSS_VMGM_MENU:
+ /* Jump to Video Manger domain - Title Menu:data1 or any PGC in VMG */
+ /* Allowed from anywhere except the VTS Title domain */
+ /* Stop SPRM9 Timer and any GPRM counters */
+ assert((vm->state).domain != VTS_DOMAIN); /* ?? */
+ (vm->state).domain = VMGM_DOMAIN;
+ if(!set_MENU(vm, link_values.data1))
+ assert(0);
+ link_values = play_PGC(vm);
+ break;
+ case JumpSS_VTSM:
+ /* Jump to a menu in Video Title domain, */
+ /* or to a Menu is the current VTS */
+ /* Stop SPRM9 Timer and any GPRM counters */
+ /* ifoOpenNewVTSI:data1 */
+ /* VTS_TTN_REG:data2 */
+ /* get_MENU:data3 */
+ if(link_values.data1 != 0) {
+ if (link_values.data1 != (vm->state).vtsN) {
+ /* the normal case */
+ assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */
+ (vm->state).domain = VTSM_DOMAIN;
+ if (!ifoOpenNewVTSI(vm, vm->dvd, link_values.data1)) /* Also sets (vm->state).vtsN */
+ assert(0);
+ } else {
+ /* This happens on some discs like "Captain Scarlet & the Mysterons" or
+ * the German RC2 of "Anatomie" in VTSM. */
+ assert((vm->state).domain == VTSM_DOMAIN ||
+ (vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */
+ (vm->state).domain = VTSM_DOMAIN;
+ }
+ } else {
+ /* This happens on 'The Fifth Element' region 2. */
+ assert((vm->state).domain == VTSM_DOMAIN);
+ }
+ /* I don't know what title is supposed to be used for. */
+ /* Alien or Aliens has this != 1, I think. */
+ /* assert(link_values.data2 == 1); */
+ (vm->state).VTS_TTN_REG = link_values.data2;
+ /* TTN_REG (SPRM4), VTS_TTN_REG (SPRM5), TT_PGCN_REG (SPRM6) are linked, */
+ /* so if one changes, the others must change to match it. */
+ (vm->state).TTN_REG = get_TT(vm, (vm->state).vtsN, (vm->state).VTS_TTN_REG);
+ if(!set_MENU(vm, link_values.data3))
+ assert(0);
+ link_values = play_PGC(vm);
+ break;
+ case JumpSS_VMGM_PGC:
+ /* set_PGCN:data1 */
+ /* Stop SPRM9 Timer and any GPRM counters */
+ assert((vm->state).domain != VTS_DOMAIN); /* ?? */
+ (vm->state).domain = VMGM_DOMAIN;
+ if(!set_PGCN(vm, link_values.data1))
+ assert(0);
+ link_values = play_PGC(vm);
+ break;
+
+ case CallSS_FP:
+ /* set_RSMinfo:data1 */
+ assert((vm->state).domain == VTS_DOMAIN); /* ?? */
+ /* Must be called before domain is changed */
+ set_RSMinfo(vm, link_values.data1, /* We dont have block info */ 0);
+ set_FP_PGC(vm);
+ link_values = play_PGC(vm);
+ break;
+ case CallSS_VMGM_MENU:
+ /* set_MENU:data1 */
+ /* set_RSMinfo:data2 */
+ assert((vm->state).domain == VTS_DOMAIN); /* ?? */
+ /* Must be called before domain is changed */
+ set_RSMinfo(vm, link_values.data2, /* We dont have block info */ 0);
+ (vm->state).domain = VMGM_DOMAIN;
+ if(!set_MENU(vm, link_values.data1))
+ assert(0);
+ link_values = play_PGC(vm);
+ break;
+ case CallSS_VTSM:
+ /* set_MENU:data1 */
+ /* set_RSMinfo:data2 */
+ assert((vm->state).domain == VTS_DOMAIN); /* ?? */
+ /* Must be called before domain is changed */
+ set_RSMinfo(vm, link_values.data2, /* We dont have block info */ 0);
+ (vm->state).domain = VTSM_DOMAIN;
+ if(!set_MENU(vm, link_values.data1))
+ assert(0);
+ link_values = play_PGC(vm);
+ break;
+ case CallSS_VMGM_PGC:
+ /* set_PGC:data1 */
+ /* set_RSMinfo:data2 */
+ assert((vm->state).domain == VTS_DOMAIN); /* ?? */
+ /* Must be called before domain is changed */
+ set_RSMinfo(vm, link_values.data2, /* We dont have block info */ 0);
+ (vm->state).domain = VMGM_DOMAIN;
+ if(!set_PGCN(vm, link_values.data1))
+ assert(0);
+ link_values = play_PGC(vm);
+ break;
+ case PlayThis:
+ /* Should never happen. */
+ assert(0);
+ break;
+ }
+
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: After printout starts:\n");
+ vm_print_current_domain_state(vm);
+ fprintf(MSG_OUT, "libdvdnav: After printout ends.\n");
+#endif
+
+ }
+ (vm->state).blockN = link_values.data1 | (link_values.data2 << 16);
+ return 1;
+}
+
+
+/* Set functions */
+
+static int set_TT(vm_t *vm, int tt) {
+ return set_PTT(vm, tt, 1);
+}
+
+static int set_PTT(vm_t *vm, int tt, int ptt) {
+ assert(tt <= vm->vmgi->tt_srpt->nr_of_srpts);
+ return set_VTS_PTT(vm, vm->vmgi->tt_srpt->title[tt - 1].title_set_nr,
+ vm->vmgi->tt_srpt->title[tt - 1].vts_ttn, ptt);
+}
+
+static int set_VTS_TT(vm_t *vm, int vtsN, int vts_ttn) {
+ return set_VTS_PTT(vm, vtsN, vts_ttn, 1);
+}
+
+static int set_VTS_PTT(vm_t *vm, int vtsN, int vts_ttn, int part) {
+ int pgcN, pgN, res;
+
+ (vm->state).domain = VTS_DOMAIN;
+
+ if (vtsN != (vm->state).vtsN)
+ if (!ifoOpenNewVTSI(vm, vm->dvd, vtsN)) /* Also sets (vm->state).vtsN */
+ return 0;
+
+ if ((vts_ttn < 1) || (vts_ttn > vm->vtsi->vts_ptt_srpt->nr_of_srpts) ||
+ (part < 1) || (part > vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].nr_of_ptts) ) {
+ return 0;
+ }
+
+ pgcN = vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgcn;
+ pgN = vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgn;
+
+ (vm->state).TT_PGCN_REG = pgcN;
+ (vm->state).PTTN_REG = part;
+ (vm->state).TTN_REG = get_TT(vm, vtsN, vts_ttn);
+ assert( (vm->state.TTN_REG) != 0 );
+ (vm->state).VTS_TTN_REG = vts_ttn;
+ (vm->state).vtsN = vtsN; /* Not sure about this one. We can get to it easily from TTN_REG */
+ /* Any other registers? */
+
+ res = set_PGCN(vm, pgcN); /* This clobber's state.pgN (sets it to 1), but we don't want clobbering here. */
+ (vm->state).pgN = pgN;
+ return res;
+}
+
+static int set_FP_PGC(vm_t *vm) {
+ (vm->state).domain = FP_DOMAIN;
+ if (!vm->vmgi->first_play_pgc) {
+ return set_PGCN(vm, 1);
+ }
+ (vm->state).pgc = vm->vmgi->first_play_pgc;
+ (vm->state).pgcN = vm->vmgi->vmgi_mat->first_play_pgc;
+ return 1;
+}
+
+
+static int set_MENU(vm_t *vm, int menu) {
+ assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == VTSM_DOMAIN);
+ return set_PGCN(vm, get_ID(vm, menu));
+}
+
+static int set_PGCN(vm_t *vm, int pgcN) {
+ pgcit_t *pgcit;
+
+ pgcit = get_PGCIT(vm);
+ assert(pgcit != NULL); /* ?? Make this return -1 instead */
+
+ if(pgcN < 1 || pgcN > pgcit->nr_of_pgci_srp) {
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: ** No such pgcN = %d\n", pgcN);
+#endif
+ return 0;
+ }
+
+ (vm->state).pgc = pgcit->pgci_srp[pgcN - 1].pgc;
+ (vm->state).pgcN = pgcN;
+ (vm->state).pgN = 1;
+
+ if((vm->state).domain == VTS_DOMAIN)
+ (vm->state).TT_PGCN_REG = pgcN;
+
+ return 1;
+}
+
+/* Figure out the correct pgN from the cell and update (vm->state). */
+static int set_PGN(vm_t *vm) {
+ int new_pgN = 0;
+
+ while(new_pgN < (vm->state).pgc->nr_of_programs
+ && (vm->state).cellN >= (vm->state).pgc->program_map[new_pgN])
+ new_pgN++;
+
+ if(new_pgN == (vm->state).pgc->nr_of_programs) /* We are at the last program */
+ if((vm->state).cellN > (vm->state).pgc->nr_of_cells)
+ return 0; /* We are past the last cell */
+
+ (vm->state).pgN = new_pgN;
+
+ if((vm->state).domain == VTS_DOMAIN) {
+ playback_type_t *pb_ty;
+ if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts)
+ return 0; /* ?? */
+ pb_ty = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1].pb_ty;
+ if(pb_ty->multi_or_random_pgc_title == /* One_Sequential_PGC_Title */ 0) {
+ int dummy, part;
+ vm_get_current_title_part(vm, &dummy, &part);
+ (vm->state).PTTN_REG = part;
+ } else {
+ /* FIXME: Handle RANDOM or SHUFFLE titles. */
+ fprintf(MSG_OUT, "libdvdnav: RANDOM or SHUFFLE titles are NOT handled yet.\n");
+ }
+ }
+ return 1;
+}
+
+/* Must be called before domain is changed (set_PGCN()) */
+static void set_RSMinfo(vm_t *vm, int cellN, int blockN) {
+ int i;
+
+ if(cellN) {
+ (vm->state).rsm_cellN = cellN;
+ (vm->state).rsm_blockN = blockN;
+ } else {
+ (vm->state).rsm_cellN = (vm->state).cellN;
+ (vm->state).rsm_blockN = blockN;
+ }
+ (vm->state).rsm_vtsN = (vm->state).vtsN;
+ (vm->state).rsm_pgcN = get_PGCN(vm);
+
+ /* assert((vm->state).rsm_pgcN == (vm->state).TT_PGCN_REG); for VTS_DOMAIN */
+
+ for(i = 0; i < 5; i++) {
+ (vm->state).rsm_regs[i] = (vm->state).registers.SPRM[4 + i];
+ }
+}
+
+
+/* Get functions */
+
+/* Searches the TT tables, to find the current TT.
+ * returns the current TT.
+ * returns 0 if not found.
+ */
+static int get_TT(vm_t *vm, int vtsN, int vts_ttn) {
+ int i;
+ int tt=0;
+
+ for(i = 1; i <= vm->vmgi->tt_srpt->nr_of_srpts; i++) {
+ if( vm->vmgi->tt_srpt->title[i - 1].title_set_nr == vtsN &&
+ vm->vmgi->tt_srpt->title[i - 1].vts_ttn == vts_ttn) {
+ tt=i;
+ break;
+ }
+ }
+ return tt;
+}
+
+/* Search for entry_id match of the PGC Category in the current VTS PGCIT table.
+ * Return pgcN based on entry_id match.
+ */
+static int get_ID(vm_t *vm, int id) {
+ int pgcN, i;
+ pgcit_t *pgcit;
+
+ /* Relies on state to get the correct pgcit. */
+ pgcit = get_PGCIT(vm);
+ assert(pgcit != NULL);
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: ** Searching for menu (0x%x) entry PGC\n", id);
+#endif
+
+ /* Force high bit set. */
+ id |=0x80;
+
+ /* Get menu/title */
+ for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
+ if( (pgcit->pgci_srp[i].entry_id) == id) {
+ pgcN = i + 1;
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: Found menu.\n");
+#endif
+ return pgcN;
+ }
+ }
+#ifdef TRACE
+ fprintf(MSG_OUT, "libdvdnav: ** No such id/menu (0x%02x) entry PGC\n", id & 0x7f);
+ for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
+ if ( (pgcit->pgci_srp[i].entry_id & 0x80) == 0x80) {
+ fprintf(MSG_OUT, "libdvdnav: Available menus: 0x%x\n",
+ pgcit->pgci_srp[i].entry_id & 0x7f);
+ }
+ }
+#endif
+ return 0; /* error */
+}
+
+/* FIXME: we have a pgcN member in the vm's state now, so this should be obsolete */
+static int get_PGCN(vm_t *vm) {
+ pgcit_t *pgcit;
+ int pgcN = 1;
+
+ pgcit = get_PGCIT(vm);
+
+ if (pgcit) {
+ while(pgcN <= pgcit->nr_of_pgci_srp) {
+ if(pgcit->pgci_srp[pgcN - 1].pgc == (vm->state).pgc) {
+ assert((vm->state).pgcN == pgcN);
+ return pgcN;
+ }
+ pgcN++;
+ }
+ }
+ fprintf(MSG_OUT, "libdvdnav: get_PGCN failed. Was trying to find pgcN in domain %d\n",
+ (vm->state).domain);
+ return 0; /* error */
+}
+
+static pgcit_t* get_MENU_PGCIT(vm_t *vm, ifo_handle_t *h, uint16_t lang) {
+ int i;
+
+ if(h == NULL || h->pgci_ut == NULL) {
+ fprintf(MSG_OUT, "libdvdnav: *** pgci_ut handle is NULL ***\n");
+ return NULL; /* error? */
+ }
+
+ i = 0;
+ while(i < h->pgci_ut->nr_of_lus
+ && h->pgci_ut->lu[i].lang_code != lang)
+ i++;
+ if(i == h->pgci_ut->nr_of_lus) {
+ fprintf(MSG_OUT, "libdvdnav: Language '%c%c' not found, using '%c%c' instead\n",
+ (char)(lang >> 8), (char)(lang & 0xff),
+ (char)(h->pgci_ut->lu[0].lang_code >> 8),
+ (char)(h->pgci_ut->lu[0].lang_code & 0xff));
+ fprintf(MSG_OUT, "libdvdnav: Menu Languages available: ");
+ for(i = 0; i < h->pgci_ut->nr_of_lus; i++) {
+ fprintf(MSG_OUT, "%c%c ",
+ (char)(h->pgci_ut->lu[i].lang_code >> 8),
+ (char)(h->pgci_ut->lu[i].lang_code & 0xff));
+ }
+ fprintf(MSG_OUT, "\n");
+ i = 0; /* error? */
+ }
+
+ return h->pgci_ut->lu[i].pgcit;
+}
+
+/* Uses state to decide what to return */
+static pgcit_t* get_PGCIT(vm_t *vm) {
+ pgcit_t *pgcit = NULL;
+
+ switch ((vm->state).domain) {
+ case VTS_DOMAIN:
+ if(!vm->vtsi) return NULL;
+ pgcit = vm->vtsi->vts_pgcit;
+ break;
+ case VTSM_DOMAIN:
+ if(!vm->vtsi) return NULL;
+ pgcit = get_MENU_PGCIT(vm, vm->vtsi, (vm->state).registers.SPRM[0]);
+ break;
+ case VMGM_DOMAIN:
+ case FP_DOMAIN:
+ pgcit = get_MENU_PGCIT(vm, vm->vmgi, (vm->state).registers.SPRM[0]);
+ break;
+ default:
+ abort();
+ }
+
+ return pgcit;
+}
+
+//return the ifo_handle_t describing required title, used to
+//identify chapters
+ifo_handle_t *vm_get_title_ifo(vm_t *vm, uint32_t title)
+{
+ ifo_handle_t *ifo = NULL;
+ uint8_t titleset_nr;
+ if((title < 1) || (title > vm->vmgi->tt_srpt->nr_of_srpts))
+ return NULL;
+ titleset_nr = vm->vmgi->tt_srpt->title[title-1].title_set_nr;
+ ifo = ifoOpen(vm->dvd, titleset_nr);
+ return ifo;
+}
+
+void vm_ifo_close(ifo_handle_t *ifo)
+{
+ ifoClose(ifo);
+}
+
+int vm_get_state(vm_t *vm, dvd_state_t *save_state) {
+ *save_state = vm->state;
+
+ /* remove the pgc pointer as it might not be valid later*/
+ save_state->pgc = NULL;
+
+ return 1;
+}
+
+int vm_set_state(vm_t *vm, dvd_state_t *save_state) {
+
+ /* restore state from save_state as taken from ogle */
+
+ /* open the needed vts */
+ if( !ifoOpenNewVTSI(vm, vm->dvd, save_state->vtsN) ) return 0;
+ // sets state.vtsN
+
+ vm->state = *save_state;
+ /* set state.domain before calling */
+ //calls get_pgcit()
+ // needs state.domain and sprm[0] set
+ // sets pgcit depending on state.domain
+ //writes: state.pgc
+ // state.pgN
+ // state.TT_PGCN_REG
+
+ if( !set_PGCN(vm, save_state->pgcN) ) return 0;
+ save_state->pgc = vm->state.pgc;
+
+ /* set the rest of state after the call */
+ vm->state = *save_state;
+
+ /* if we are not in standard playback, we must get all data */
+ /* otherwise we risk loosing stillframes, and overlays */
+ if(vm->state.domain != VTS_DOMAIN)
+ vm->state.blockN = 0;
+
+ /* force a flush of data here */
+ /* we don't need a hop seek here as it's a complete state*/
+ vm->hop_channel++;
+
+ return 1;
+}
+
+/* Debug functions */
+
+#ifdef TRACE
+void vm_position_print(vm_t *vm, vm_position_t *position) {
+ fprintf(MSG_OUT, "libdvdnav: But=%x Spu=%x Aud=%x Ang=%x Hop=%x vts=%x dom=%x cell=%x cell_restart=%x cell_start=%x still=%x block=%x\n",
+ position->button,
+ position->spu_channel,
+ position->audio_channel,
+ position->angle_channel,
+ position->hop_channel,
+ position->vts,
+ position->domain,
+ position->cell,
+ position->cell_restart,
+ position->cell_start,
+ position->still,
+ position->block);
+}
+#endif
+
diff --git a/lib/libdvd/libdvdnav/src/vm/vm.h b/lib/libdvd/libdvdnav/src/vm/vm.h
new file mode 100644
index 0000000000..fff9a7d9b1
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/vm/vm.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2000, 2001 Håkan Hjort
+ * Copyright (C) 2001 Rich Wareham <richwareham@users.sourceforge.net>
+ *
+ * This file is part of libdvdnav, a DVD navigation library. It is modified
+ * from a file originally part of the Ogle DVD player.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: vm.h 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+#ifndef VM_H_INCLUDED
+#define VM_H_INCLUDED
+
+/* DOMAIN enum */
+
+typedef enum {
+ FP_DOMAIN = 1,
+ VTS_DOMAIN = 2,
+ VMGM_DOMAIN = 4,
+ VTSM_DOMAIN = 8
+} domain_t;
+
+/**
+ * State: SPRM, GPRM, Domain, pgc, pgN, cellN, ?
+ */
+typedef struct {
+ registers_t registers;
+
+ domain_t domain;
+ int vtsN; /* 0 is vmgm? */
+ pgc_t *pgc; /* either this or 'int pgcN' is enough? */
+ int pgcN; /* but provide pgcN for quick lookup */
+ int pgN; /* is this needed? can allways fid pgN from cellN? */
+ int cellN;
+ int32_t cell_restart; /* get cell to restart */
+ int blockN;
+
+ /* Resume info */
+ int rsm_vtsN;
+ int rsm_blockN; /* of nav_packet */
+ uint16_t rsm_regs[5]; /* system registers 4-8 */
+ int rsm_pgcN;
+ int rsm_cellN;
+} dvd_state_t;
+
+typedef struct vm_position_s {
+ int16_t button; /* Button highlighted */
+ int32_t vts; /* vts number to use */
+ domain_t domain; /* domain to use */
+ int32_t spu_channel; /* spu channel to use */
+ int32_t angle_channel; /* angle channel to use */
+ int32_t audio_channel; /* audio channel to use */
+ int32_t hop_channel; /* channel hopping. E.g menu button pressed */
+#if 0
+ /* currently unused */
+ int32_t title; /* title number */
+ int32_t chapter; /* chapter number */
+#endif
+ int32_t cell; /* cell number */
+ int32_t cell_restart; /* get cell to restart */
+ int32_t cell_start; /* sector number of start of current cell in use */
+ int32_t still; /* is cell still */
+ int32_t block; /* block number within cell in use */
+} vm_position_t;
+
+typedef struct {
+ dvd_reader_t *dvd;
+ ifo_handle_t *vmgi;
+ ifo_handle_t *vtsi;
+ dvd_state_t state;
+ int32_t hop_channel;
+ char dvd_name[50];
+ remap_t *map;
+ int stopped;
+} vm_t;
+
+/* magic number for seeking hops */
+#define HOP_SEEK 0x1000
+
+
+/* Audio stream number */
+#define AST_REG registers.SPRM[1]
+/* Subpicture stream number */
+#define SPST_REG registers.SPRM[2]
+/* Angle number */
+#define AGL_REG registers.SPRM[3]
+/* Title Track Number */
+#define TTN_REG registers.SPRM[4]
+/* VTS Title Track Number */
+#define VTS_TTN_REG registers.SPRM[5]
+/* PGC Number for this Title Track */
+#define TT_PGCN_REG registers.SPRM[6]
+/* Current Part of Title (PTT) number for (One_Sequential_PGC_Title) */
+#define PTTN_REG registers.SPRM[7]
+/* Highlighted Button Number (btn nr 1 == value 1024) */
+#define HL_BTNN_REG registers.SPRM[8]
+/* Parental Level */
+#define PTL_REG registers.SPRM[13]
+
+/* Initialisation & destruction */
+vm_t *vm_new_vm(void);
+void vm_free_vm(vm_t *vm);
+
+/* IFO access */
+ifo_handle_t *vm_get_vmgi(vm_t *vm);
+ifo_handle_t *vm_get_vtsi(vm_t *vm);
+
+/* Reader Access */
+dvd_reader_t *vm_get_dvd_reader(vm_t *vm);
+
+/* Basic Handling */
+int vm_start(vm_t *vm);
+void vm_stop(vm_t *vm);
+int vm_reset(vm_t *vm, const char *dvdroot);
+
+/* copying and merging - useful for try-running an operation */
+vm_t *vm_new_copy(vm_t *vm);
+void vm_merge(vm_t *target, vm_t *source);
+void vm_free_copy(vm_t *vm);
+
+/* regular playback */
+void vm_position_get(vm_t *vm, vm_position_t *position);
+void vm_get_next_cell(vm_t *vm);
+
+/* Jumping - all these return 1, if a hop has been performed */
+int vm_jump_pg(vm_t *vm, int pg);
+int vm_jump_cell_block(vm_t *vm, int cell, int block);
+int vm_jump_title_part(vm_t *vm, int title, int part);
+int vm_jump_top_pg(vm_t *vm);
+int vm_jump_next_pg(vm_t *vm);
+int vm_jump_prev_pg(vm_t *vm);
+int vm_jump_up(vm_t *vm);
+int vm_jump_menu(vm_t *vm, DVDMenuID_t menuid);
+int vm_jump_resume(vm_t *vm);
+int vm_exec_cmd(vm_t *vm, vm_cmd_t *cmd);
+
+/* getting information */
+int vm_get_current_menu(vm_t *vm, int *menuid);
+int vm_get_current_title_part(vm_t *vm, int *title_result, int *part_result);
+int vm_get_audio_stream(vm_t *vm, int audioN);
+int vm_get_subp_stream(vm_t *vm, int subpN, int mode);
+int vm_get_audio_active_stream(vm_t *vm);
+int vm_get_subp_active_stream(vm_t *vm, int mode);
+void vm_get_angle_info(vm_t *vm, int *current, int *num_avail);
+// _XBMC #if 0
+/* currently unused */
+void vm_get_audio_info(vm_t *vm, int *current, int *num_avail);
+void vm_get_subp_info(vm_t *vm, int *current, int *num_avail);
+void vm_get_video_res(vm_t *vm, int *width, int *height);
+// _XBMC #endif
+int vm_get_video_aspect(vm_t *vm);
+int vm_get_video_scale_permission(vm_t *vm);
+video_attr_t vm_get_video_attr(vm_t *vm);
+audio_attr_t vm_get_audio_attr(vm_t *vm, int streamN);
+subp_attr_t vm_get_subp_attr(vm_t *vm, int streamN);
+ifo_handle_t *vm_get_title_ifo(vm_t *vm, uint32_t title);
+void vm_ifo_close(ifo_handle_t *ifo);
+
+int vm_get_state(vm_t *vm, dvd_state_t *save_state);
+int vm_set_state(vm_t *vm, dvd_state_t *save_state);
+
+/* Uncomment for VM command tracing */
+/* #define TRACE */
+#ifdef TRACE
+/* Debug */
+void vm_position_print(vm_t *vm, vm_position_t *position);
+#endif
+
+
+#endif /* VM_HV_INCLUDED */
diff --git a/lib/libdvd/libdvdnav/src/vm/vmcmd.c b/lib/libdvd/libdvdnav/src/vm/vmcmd.c
new file mode 100644
index 0000000000..9f68dbd399
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/vm/vmcmd.c
@@ -0,0 +1,549 @@
+/*
+ * Copyright (C) 2000, 2001 Martin Norbäck, Håkan Hjort
+ * 2002-2004 the dvdnav project
+ *
+ * This file is part of libdvdnav, a DVD navigation library. It is modified
+ * from a file originally part of the Ogle DVD player.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: vmcmd.c 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <sys/time.h>
+
+#include "dvd_types.h"
+#include <dvdread/nav_types.h>
+#include <dvdread/ifo_types.h>
+#include "decoder.h"
+#include "remap.h"
+#include "vm.h"
+#include "vmcmd.h"
+#include "dvdnav.h"
+#include "dvdnav_internal.h"
+
+/* freebsd compatibility */
+#ifndef PRIu8
+#define PRIu8 "d"
+#endif
+
+/* freebsd compatibility */
+#ifndef PRIu16
+#define PRIu16 "d"
+#endif
+
+static const char cmp_op_table[][4] = {
+ "", "&", "==", "!=", ">=", ">", "<=", "<"
+};
+static const char set_op_table[][4] = {
+ "", "=", "<->", "+=", "-=", "*=", "/=", "%=", "rnd", "&=", "|=", "^="
+};
+
+static const char link_table[][16] = {
+ "LinkNoLink", "LinkTopC", "LinkNextC", "LinkPrevC",
+ "", "LinkTopPG", "LinkNextPG", "LinkPrevPG",
+ "", "LinkTopPGC", "LinkNextPGC", "LinkPrevPGC",
+ "LinkGoUpPGC", "LinkTailPGC", "", "",
+ "RSM"
+};
+
+static const char *const system_reg_table[] = {
+ "Menu Description Language Code",
+ "Audio Stream Number",
+ "Sub-picture Stream Number",
+ "Angle Number",
+ "Title Track Number",
+ "VTS Title Track Number",
+ "VTS PGC Number",
+ "PTT Number for One_Sequential_PGC_Title",
+ "Highlighted Button Number",
+ "Navigation Timer",
+ "Title PGC Number for Navigation Timer",
+ "Audio Mixing Mode for Karaoke",
+ "Country Code for Parental Management",
+ "Parental Level",
+ "Player Configurations for Video",
+ "Player Configurations for Audio",
+ "Initial Language Code for Audio",
+ "Initial Language Code Extension for Audio",
+ "Initial Language Code for Sub-picture",
+ "Initial Language Code Extension for Sub-picture",
+ "Player Regional Code",
+ "Reserved 21",
+ "Reserved 22",
+ "Reserved 23"
+};
+
+static const char system_reg_abbr_table[][8] = {
+ "",
+ "ASTN",
+ "SPSTN",
+ "AGLN",
+ "TTN",
+ "VTS_TTN",
+ "TT_PGCN",
+ "PTTN",
+ "HL_BTNN",
+ "NVTMR",
+ "NV_PGCN",
+ "",
+ "CC_PLT",
+ "PLT",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+};
+
+static void print_system_reg(uint16_t reg) {
+ if(reg < sizeof(system_reg_abbr_table) / sizeof(system_reg_abbr_table[0]))
+ fprintf(MSG_OUT, "%s (SRPM:%d)", system_reg_table[reg], reg);
+ else
+ fprintf(MSG_OUT, " WARNING: Unknown system register ( reg=%d ) ", reg);
+}
+
+static void print_g_reg(uint8_t reg) {
+ if(reg < 16)
+ fprintf(MSG_OUT, "g[%" PRIu8 "]", reg);
+ else
+ fprintf(MSG_OUT, " WARNING: Unknown general register ");
+}
+
+static void print_reg(uint8_t reg) {
+ if(reg & 0x80)
+ print_system_reg(reg & 0x7f);
+ else
+ print_g_reg(reg & 0x7f);
+}
+
+static void print_cmp_op(uint8_t op) {
+ if(op < sizeof(cmp_op_table) / sizeof(cmp_op_table[0]))
+ fprintf(MSG_OUT, " %s ", cmp_op_table[op]);
+ else
+ fprintf(MSG_OUT, " WARNING: Unknown compare op ");
+}
+
+static void print_set_op(uint8_t op) {
+ if(op < sizeof(set_op_table) / sizeof(cmp_op_table[0]))
+ fprintf(MSG_OUT, " %s ", set_op_table[op]);
+ else
+ fprintf(MSG_OUT, " WARNING: Unknown set op ");
+}
+
+static void print_reg_or_data(command_t* command, int immediate, int start) {
+ if(immediate) {
+ uint32_t i = vm_getbits(command, start, 16);
+
+ fprintf(MSG_OUT, "0x%x", i);
+ if(isprint(i & 0xff) && isprint((i>>8) & 0xff))
+ fprintf(MSG_OUT, " (\"%c%c\")", (char)((i>>8) & 0xff), (char)(i & 0xff));
+ } else {
+ print_reg(vm_getbits(command, start - 8, 8));
+ }
+}
+
+static void print_reg_or_data_2(command_t* command, int immediate, int start) {
+ if(immediate)
+ fprintf(MSG_OUT, "0x%x", vm_getbits(command, start - 1, 7));
+ else
+ fprintf(MSG_OUT, "g[%" PRIu8 "]", vm_getbits(command, start - 4, 4));
+}
+
+static void print_reg_or_data_3(command_t* command, int immediate, int start) {
+ if(immediate) {
+ uint32_t i = vm_getbits(command, start, 16);
+
+ fprintf(MSG_OUT, "0x%x", i);
+ if(isprint(i & 0xff) && isprint((i>>8) & 0xff))
+ fprintf(MSG_OUT, " (\"%c%c\")", (char)((i>>8) & 0xff), (char)(i & 0xff));
+ } else {
+ print_reg(vm_getbits(command, start, 8));
+ }
+}
+
+
+static void print_if_version_1(command_t* command) {
+ uint8_t op = vm_getbits(command, 54, 3);
+
+ if(op) {
+ fprintf(MSG_OUT, "if (");
+ print_g_reg(vm_getbits(command,39,8));
+ print_cmp_op(op);
+ print_reg_or_data(command, vm_getbits(command, 55,1), 31);
+ fprintf(MSG_OUT, ") ");
+ }
+}
+
+static void print_if_version_2(command_t* command) {
+ uint8_t op = vm_getbits(command, 54, 3);
+
+ if(op) {
+ fprintf(MSG_OUT, "if (");
+ print_reg(vm_getbits(command, 15, 8));
+ print_cmp_op(op);
+ print_reg(vm_getbits(command, 7, 8));
+ fprintf(MSG_OUT, ") ");
+ }
+}
+
+static void print_if_version_3(command_t* command) {
+ uint8_t op = vm_getbits(command, 54, 3);
+
+ if(op) {
+ fprintf(MSG_OUT, "if (");
+ print_g_reg(vm_getbits(command, 43, 4));
+ print_cmp_op(op);
+ print_reg_or_data(command, vm_getbits(command, 55, 1), 15);
+ fprintf(MSG_OUT, ") ");
+ }
+}
+
+static void print_if_version_4(command_t* command) {
+ uint8_t op = vm_getbits(command, 54, 3);
+
+ if(op) {
+ fprintf(MSG_OUT, "if (");
+ print_g_reg(vm_getbits(command, 51, 4));
+ print_cmp_op(op);
+ print_reg_or_data(command, vm_getbits(command, 55, 1), 31);
+ fprintf(MSG_OUT, ") ");
+ }
+}
+
+static void print_if_version_5(command_t* command) {
+ uint8_t op = vm_getbits(command, 54, 3);
+ int set_immediate = vm_getbits(command, 60, 1);
+
+ if(op) {
+ if (set_immediate) {
+ fprintf(MSG_OUT, "if (");
+ print_g_reg(vm_getbits(command, 31, 8));
+ print_cmp_op(op);
+ print_reg(vm_getbits(command, 23, 8));
+ fprintf(MSG_OUT, ") ");
+ } else {
+ fprintf(MSG_OUT, "if (");
+ print_g_reg(vm_getbits(command, 39, 8));
+ print_cmp_op(op);
+ print_reg_or_data(command, vm_getbits(command, 55, 1), 31);
+ fprintf(MSG_OUT, ") ");
+ }
+ }
+}
+
+static void print_special_instruction(command_t* command) {
+ uint8_t op = vm_getbits(command, 51, 4);
+
+ switch(op) {
+ case 0: /* NOP */
+ fprintf(MSG_OUT, "Nop");
+ break;
+ case 1: /* Goto line */
+ fprintf(MSG_OUT, "Goto %" PRIu8, vm_getbits(command, 7, 8));
+ break;
+ case 2: /* Break */
+ fprintf(MSG_OUT, "Break");
+ break;
+ case 3: /* Parental level */
+ fprintf(MSG_OUT, "SetTmpPML %" PRIu8 ", Goto %" PRIu8,
+ vm_getbits(command, 11, 4), vm_getbits(command, 7, 8));
+ break;
+ default:
+ fprintf(MSG_OUT, "WARNING: Unknown special instruction (%i)",
+ vm_getbits(command, 51, 4));
+ }
+}
+
+static void print_linksub_instruction(command_t* command) {
+ uint32_t linkop = vm_getbits(command, 7, 8);
+ uint32_t button = vm_getbits(command, 15, 6);
+
+ if(linkop < sizeof(link_table)/sizeof(link_table[0]))
+ fprintf(MSG_OUT, "%s (button %" PRIu8 ")", link_table[linkop], button);
+ else
+ fprintf(MSG_OUT, "WARNING: Unknown linksub instruction (%i)", linkop);
+}
+
+static void print_link_instruction(command_t* command, int optional) {
+ uint8_t op = vm_getbits(command, 51, 4);
+
+ if(optional && op)
+ fprintf(MSG_OUT, ", ");
+
+ switch(op) {
+ case 0:
+ if(!optional)
+ fprintf(MSG_OUT, "WARNING: NOP (link)!");
+ break;
+ case 1:
+ print_linksub_instruction(command);
+ break;
+ case 4:
+ fprintf(MSG_OUT, "LinkPGCN %" PRIu16, vm_getbits(command, 14, 15));
+ break;
+ case 5:
+ fprintf(MSG_OUT, "LinkPTT %" PRIu16 " (button %" PRIu8 ")",
+ vm_getbits(command, 9, 10), vm_getbits(command, 15, 6));
+ break;
+ case 6:
+ fprintf(MSG_OUT, "LinkPGN %" PRIu8 " (button %" PRIu8 ")",
+ vm_getbits(command, 6, 7), vm_getbits(command, 15, 6));
+ break;
+ case 7:
+ fprintf(MSG_OUT, "LinkCN %" PRIu8 " (button %" PRIu8 ")",
+ vm_getbits(command, 7, 8), vm_getbits(command, 15, 6));
+ break;
+ default:
+ fprintf(MSG_OUT, "WARNING: Unknown link instruction");
+ }
+}
+
+static void print_jump_instruction(command_t* command) {
+ switch(vm_getbits(command, 51, 4)) {
+ case 1:
+ fprintf(MSG_OUT, "Exit");
+ break;
+ case 2:
+ fprintf(MSG_OUT, "JumpTT %" PRIu8, vm_getbits(command, 22, 7));
+ break;
+ case 3:
+ fprintf(MSG_OUT, "JumpVTS_TT %" PRIu8, vm_getbits(command, 22, 7));
+ break;
+ case 5:
+ fprintf(MSG_OUT, "JumpVTS_PTT %" PRIu8 ":%" PRIu16,
+ vm_getbits(command, 22, 7), vm_getbits(command, 41, 10));
+ break;
+ case 6:
+ switch(vm_getbits(command, 23, 2)) {
+ case 0:
+ fprintf(MSG_OUT, "JumpSS FP");
+ break;
+ case 1:
+ fprintf(MSG_OUT, "JumpSS VMGM (menu %" PRIu8 ")", vm_getbits(command, 19, 4));
+ break;
+ case 2:
+ fprintf(MSG_OUT, "JumpSS VTSM (vts %" PRIu8 ", title %" PRIu8
+ ", menu %" PRIu8 ")", vm_getbits(command, 30, 7), vm_getbits(command, 38, 7), vm_getbits(command, 19, 4));
+ break;
+ case 3:
+ fprintf(MSG_OUT, "JumpSS VMGM (pgc %" PRIu8 ")", vm_getbits(command, 46, 15));
+ break;
+ }
+ break;
+ case 8:
+ switch(vm_getbits(command, 23, 2)) {
+ case 0:
+ fprintf(MSG_OUT, "CallSS FP (rsm_cell %" PRIu8 ")",
+ vm_getbits(command, 31, 8));
+ break;
+ case 1:
+ fprintf(MSG_OUT, "CallSS VMGM (menu %" PRIu8
+ ", rsm_cell %" PRIu8 ")", vm_getbits(command, 19, 4), vm_getbits(command, 31, 8));
+ break;
+ case 2:
+ fprintf(MSG_OUT, "CallSS VTSM (menu %" PRIu8
+ ", rsm_cell %" PRIu8 ")", vm_getbits(command, 19, 4), vm_getbits(command, 31, 8));
+ break;
+ case 3:
+ fprintf(MSG_OUT, "CallSS VMGM (pgc %" PRIu8 ", rsm_cell %" PRIu8 ")",
+ vm_getbits(command, 46, 15), vm_getbits(command, 31, 8));
+ break;
+ }
+ break;
+ default:
+ fprintf(MSG_OUT, "WARNING: Unknown Jump/Call instruction");
+ }
+}
+
+static void print_system_set(command_t* command) {
+ int i;
+/* FIXME: What about SPRM11 ? Karaoke */
+/* Surely there must be some system set command for that ? */
+
+ switch(vm_getbits(command, 59, 4)) {
+ case 1: /* Set system reg 1 &| 2 &| 3 (Audio, Subp. Angle) */
+ for(i = 1; i <= 3; i++) {
+ if(vm_getbits(command, 47 - (i*8), 1)) {
+ print_system_reg(i);
+ fprintf(MSG_OUT, " = ");
+ print_reg_or_data_2(command, vm_getbits(command, 60, 1), 47 - (i*8) );
+ fprintf(MSG_OUT, " ");
+ }
+ }
+ break;
+ case 2: /* Set system reg 9 & 10 (Navigation timer, Title PGC number) */
+ print_system_reg(9);
+ fprintf(MSG_OUT, " = ");
+ print_reg_or_data(command, vm_getbits(command, 60, 1), 47);
+ fprintf(MSG_OUT, " ");
+ print_system_reg(10);
+ fprintf(MSG_OUT, " = %" PRIu16, vm_getbits(command, 30, 15)); /* ?? */
+ break;
+ case 3: /* Mode: Counter / Register + Set */
+ fprintf(MSG_OUT, "SetMode ");
+ if(vm_getbits(command, 23, 1))
+ fprintf(MSG_OUT, "Counter ");
+ else
+ fprintf(MSG_OUT, "Register ");
+ print_g_reg(vm_getbits(command, 19, 4));
+ print_set_op(0x1); /* '=' */
+ print_reg_or_data(command, vm_getbits(command, 60, 1), 47);
+ break;
+ case 6: /* Set system reg 8 (Highlighted button) */
+ print_system_reg(8);
+ if(vm_getbits(command, 60, 1)) /* immediate */
+ fprintf(MSG_OUT, " = 0x%x (button no %d)", vm_getbits(command, 31, 16), vm_getbits(command, 31, 6));
+ else
+ fprintf(MSG_OUT, " = g[%" PRIu8 "]", vm_getbits(command, 19, 4));
+ break;
+ default:
+ fprintf(MSG_OUT, "WARNING: Unknown system set instruction (%i)",
+ vm_getbits(command, 59, 4));
+ }
+}
+
+static void print_set_version_1(command_t* command) {
+ uint8_t set_op = vm_getbits(command, 59, 4);
+
+ if(set_op) {
+ print_g_reg(vm_getbits(command, 35, 4));
+ print_set_op(set_op);
+ print_reg_or_data(command, vm_getbits(command, 60, 1), 31);
+ } else {
+ fprintf(MSG_OUT, "NOP");
+ }
+}
+
+static void print_set_version_2(command_t* command) {
+ uint8_t set_op = vm_getbits(command, 59, 4);
+
+ if(set_op) {
+ print_g_reg(vm_getbits(command, 51, 4));
+ print_set_op(set_op);
+ print_reg_or_data(command, vm_getbits(command, 60, 1), 47);
+ } else {
+ fprintf(MSG_OUT, "NOP");
+ }
+}
+
+static void print_set_version_3(command_t* command) {
+ uint8_t set_op = vm_getbits(command, 59, 4);
+
+ if(set_op) {
+ print_g_reg(vm_getbits(command, 51, 4));
+ print_set_op(set_op);
+ print_reg_or_data_3(command, vm_getbits(command, 60, 1), 47);
+ } else {
+ fprintf(MSG_OUT, "NOP");
+ }
+}
+
+
+void vm_print_mnemonic(vm_cmd_t *vm_command) {
+ command_t command;
+ command.instruction =( (uint64_t) vm_command->bytes[0] << 56 ) |
+ ( (uint64_t) vm_command->bytes[1] << 48 ) |
+ ( (uint64_t) vm_command->bytes[2] << 40 ) |
+ ( (uint64_t) vm_command->bytes[3] << 32 ) |
+ ( (uint64_t) vm_command->bytes[4] << 24 ) |
+ ( (uint64_t) vm_command->bytes[5] << 16 ) |
+ ( (uint64_t) vm_command->bytes[6] << 8 ) |
+ (uint64_t) vm_command->bytes[7] ;
+ command.examined = 0;
+
+ switch(vm_getbits(&command,63,3)) { /* three first bits */
+ case 0: /* Special instructions */
+ print_if_version_1(&command);
+ print_special_instruction(&command);
+ break;
+ case 1: /* Jump/Call or Link instructions */
+ if(vm_getbits(&command,60,1)) {
+ print_if_version_2(&command);
+ print_jump_instruction(&command);
+ } else {
+ print_if_version_1(&command);
+ print_link_instruction(&command, 0); /* must be pressent */
+ }
+ break;
+ case 2: /* Set System Parameters instructions */
+ print_if_version_2(&command);
+ print_system_set(&command);
+ print_link_instruction(&command, 1); /* either 'if' or 'link' */
+ break;
+ case 3: /* Set General Parameters instructions */
+ print_if_version_3(&command);
+ print_set_version_1(&command);
+ print_link_instruction(&command, 1); /* either 'if' or 'link' */
+ break;
+ case 4: /* Set, Compare -> LinkSub instructions */
+ print_set_version_2(&command);
+ fprintf(MSG_OUT, ", ");
+ print_if_version_4(&command);
+ print_linksub_instruction(&command);
+ break;
+ case 5: /* Compare -> (Set and LinkSub) instructions */
+ print_if_version_5(&command);
+ fprintf(MSG_OUT, "{ ");
+ print_set_version_3(&command);
+ fprintf(MSG_OUT, ", ");
+ print_linksub_instruction(&command);
+ fprintf(MSG_OUT, " }");
+ break;
+ case 6: /* Compare -> Set, always LinkSub instructions */
+ print_if_version_5(&command);
+ fprintf(MSG_OUT, "{ ");
+ print_set_version_3(&command);
+ fprintf(MSG_OUT, " } ");
+ print_linksub_instruction(&command);
+ break;
+ default:
+ fprintf(MSG_OUT, "WARNING: Unknown instruction type (%i)", vm_getbits(&command, 63, 3));
+ }
+ /* Check if there still are bits set that were not examined */
+
+ if(command.instruction & ~ command.examined) {
+ fprintf(MSG_OUT, " libdvdnav: vmcmd.c: [WARNING, unknown bits:");
+ fprintf(MSG_OUT, " %08"PRIx64, (command.instruction & ~ command.examined) );
+ fprintf(MSG_OUT, "]");
+ }
+}
+
+void vm_print_cmd(int row, vm_cmd_t *vm_command) {
+ int i;
+
+ fprintf(MSG_OUT, "(%03d) ", row + 1);
+ for(i = 0; i < 8; i++)
+ fprintf(MSG_OUT, "%02x ", vm_command->bytes[i]);
+ fprintf(MSG_OUT, "| ");
+
+ vm_print_mnemonic(vm_command);
+ fprintf(MSG_OUT, "\n");
+}
+
diff --git a/lib/libdvd/libdvdnav/src/vm/vmcmd.h b/lib/libdvd/libdvdnav/src/vm/vmcmd.h
new file mode 100644
index 0000000000..4340b5df76
--- /dev/null
+++ b/lib/libdvd/libdvdnav/src/vm/vmcmd.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2000, 2001 Martin Norbäck, Håkan Hjort
+ *
+ * This file is part of libdvdnav, a DVD navigation library. It is modified
+ * from a file originally part of the Ogle DVD player.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: vmcmd.h 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+#ifndef VMCMD_H_INCLUDED
+#define VMCMD_H_INCLUDED
+
+void vm_print_mnemonic(vm_cmd_t *command);
+void vm_print_cmd(int row, vm_cmd_t *command);
+
+#endif /* VMCMD_H_INCLUDED */
diff --git a/lib/libdvd/libdvdnav/version.h b/lib/libdvd/libdvdnav/version.h
new file mode 100644
index 0000000000..fd4fb3ab13
--- /dev/null
+++ b/lib/libdvd/libdvdnav/version.h
@@ -0,0 +1 @@
+#define VERSION "4.1.3"
diff --git a/lib/libdvd/libdvdnav/version.sh b/lib/libdvd/libdvdnav/version.sh
new file mode 100755
index 0000000000..230da4a8af
--- /dev/null
+++ b/lib/libdvd/libdvdnav/version.sh
@@ -0,0 +1,18 @@
+##!/bin/sh
+#
+#svn_revision=`cd "$1" && LC_ALL=C svn info 2> /dev/null | grep Revision | cut -d' ' -f2`
+#test $svn_revision || svn_revision=`cd "$1" && grep revision .svn/entries 2>/dev/null | \
+# cut -d '"' -f2 2> /dev/null`
+#test $svn_revision || svn_revision=UNKNOWN
+#
+#if test "$svn_revision" = UNKNOWN && test -n "$2"; then
+# NEW_REVISION="#define VERSION \"$2\""
+#else
+# NEW_REVISION="#define VERSION \"SVN-r$svn_revision\""
+#fi
+#OLD_REVISION=`cat version.h 2> /dev/null`
+#
+## Update version.h only on revision changes to avoid spurious rebuilds
+#if test "$NEW_REVISION" != "$OLD_REVISION"; then
+# echo "$NEW_REVISION" > version.h
+#fi
diff --git a/lib/libdvd/libdvdread/.relignore b/lib/libdvd/libdvdread/.relignore
new file mode 100644
index 0000000000..2f2f41fa9c
--- /dev/null
+++ b/lib/libdvd/libdvdread/.relignore
@@ -0,0 +1,2 @@
+autom4te.cache
+config.status
diff --git a/lib/libdvd/libdvdread/AUTHORS b/lib/libdvd/libdvdread/AUTHORS
new file mode 100644
index 0000000000..cb528af0dd
--- /dev/null
+++ b/lib/libdvd/libdvdread/AUTHORS
@@ -0,0 +1,6 @@
+Daniel Caujolle-Bert <segfault@club-internet.fr>
+Thomas Vander Stichele <thomas@apestaart.org>
+Rich Wareham <richwareham@users.sourceforge.net>
+Kees Cook <kees@outflux.net>
+Michael Roitzsch <mroi@users.sourceforge.net>
+Frantisek Dvorak <valtri@users.sourceforge.net>
diff --git a/lib/libdvd/libdvdread/COPYING b/lib/libdvd/libdvdread/COPYING
new file mode 100644
index 0000000000..d60c31a97a
--- /dev/null
+++ b/lib/libdvd/libdvdread/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/lib/libdvd/libdvdread/ChangeLog b/lib/libdvd/libdvdread/ChangeLog
new file mode 100644
index 0000000000..3bd83761ae
--- /dev/null
+++ b/lib/libdvd/libdvdread/ChangeLog
@@ -0,0 +1,130 @@
+libdvdread (4.1.3)
+ * an embarassing amount of fixes regarding potential memory and resource leaks
+ (patches contributed by Erik Hovland)
+ * added dvdread-config (dvdnav-config's younger brother)
+ * added pkgconfig support
+ * split dvdread to a separate tree
+
+libdvdnav (4.1.2)
+ * multiple build system fixes
+ * added dvdnav_describe_title_chapters(title) to get title and chapters
+ duration
+
+libdvdnav (4.1.1)
+ * added dvdnav_audio_stream_channels() to return number of channels
+ * fixed dvdnav_time_search() in multi-angle dvds (but it still needs
+ improvements)
+ * added dvdnav_audio_stream_format() to identify the codec used
+ in audio streams
+ * starting DVD playback at specific title/part positions with
+ dvdnav_{title,part}_play() works again
+ * removed wrong SPU stream change event filter
+ (fixes unwanted subtitles in the trailer of "Girl, interrupted", RC2)
+ * fixed error "Expected NAV packet but none found." occuring sometimes
+ on resume from menu
+
+libdvdnav (0.1.10)
+ * filter the symbols that we export.
+ * fix LinkNextC assertion failure (fixes LotR-SEE bonus disc image gallery)
+ * detect zero stilltime still cells inside PGCs, not only at the end
+ (fixes "Red Dragon" RC2 scene selection)
+ * PGC stills seem to work, assertion removed
+ * fix rare race condition after Exit commands
+ * fix wrong JumpSS_VTSM execution in German RC2 "Anatomie"
+ (fix ported from Ogle)
+
+libdvdnav (0.1.9)
+ * libdvdnav does not depend on libdvdread any more. It has it's own version.
+ * fix some situations where an unlucky user could trigger assertions
+
+libdvdnav (0.1.8)
+ * more timing info in cell change event struct
+ * documentation review
+
+libdvdnav (0.1.7)
+ * fixed a bug in title jumping, where the title number would not be
+ converted from TTN to VTS_TTN properly
+ * some minor sanity checks added to prevent segfaults
+
+libdvdnav (0.1.6) unstable; urgency=low
+ * new event DVDNAV_WAIT to fix consistency problems in applications with fifos
+ where libdvdnav is always a bit ahead in the stream, the event forces
+ the application to wait for its fifos to get empty
+ * correct HIGHLIGHT reporting when a button is activated
+ * method to try-run VM operations, now used for safer chapter skipping and menu jumps
+ * fixed detection of current PTT to not assume a 1:1 mapping between PTTs and PGs
+ * releasing stills when jumping to menu fixes some state inconsistencies
+ * do not assume PGs to be physically layed out in sequence on the disc
+ * optional PGC based seeking
+ * new event on cell changes for timing info
+
+libdvdnav (0.1.5) unstable; urgency=low
+ * some bugfixes
+ * code cleanup
+ * build process polishing
+ * more sensible event order in get_next_block to ensure useful event delivery
+ * VOBU level resume
+ * fixed: seeking in a multiangle feature briefly showed the wrong angle
+
+libdvdnav (0.1.4) unstable; urgency=low
+ * more read cache improvements
+ * minor fixes for some problematic DVDs
+
+libdvdnav (0.1.3-1) unstable; urgency=low
+ * Zero-copy read cache.
+ * More support for alternative Menu languages.
+
+ -- Rich Wareham <richwareham@users.sourceforge.net> Fri, 2 Aug 2002 08:52:24 +0100
+
+libdvdnav (0.1.2-1) unstable; urgency=low
+ * Read Cache changes. Recommended setting for read_cache is OFF.
+ Unless one's DVD drive has too small a buffer.
+ * Should work with xine 0.9.10 or above.
+
+ -- James Courtier-Dutton <jcdutton@users.sourceforge.net> Sun, 3 Jul 2002 15:30:00 +0000
+
+libdvdnav (0.1.1-1) unstable; urgency=low
+
+ * New upstream version. (closes: #148495)
+ * Include TODO
+ * Fix config.h problem
+ * Threaded cache
+
+ -- Philipp Matthias Hahn <pmhahn@titan.lahn.de> Sat, 1 Jun 2002 17:47:59 +0200
+
+libdvdnav (0.1.0-2) unstable; urgency=low
+
+ * Add manual page dvdnav-config.1
+ * Add bug-presubj on Daniel's request
+ * Get dvdnav.c:1.17 from CVS to fix angle support
+ * Merge patch from Jamie Wilkinson (#146699)
+ * Rerun automake to fix dependencies
+ * Ack NMU from siggi
+ * Fix include in examples/menus.c
+
+ -- Philipp Hahn <pmhahn@titan.lahn.de> Thu, 23 May 2002 09:41:15 +0200
+
+libdvdnav (0.1.0-1.1) unstable; urgency=low
+
+ * Prepared for first 'real' release.
+ * Bug fixes
+ * Changes to allow apps to 'roll-their-own' dvdnav_get_next_block functions.
+ * NMU in order to get xine-dvdnav running again
+ - changed package name to libdvdnav0
+ (see patch from Jamie Wilkinson for a better solution)
+
+ -- Siggi Langauf <siggi@debian.org> Mon, 20 May 2002 15:57:40 +0200
+
+libdvdnav (0.0.1-1) unstable; urgency=low
+
+ * Repackaged using dh-make.
+
+ -- Philipp Matthias Hahn <pmhahn@titan.lahn.de> Sun, 7 Apr 2002 16:29:35 +0200
+
+libdvdnav (0.0.1) unstable; urgency=low
+
+ * Initial release.
+ * Split from xine-dvdnav
+
+ -- rjw57 <rjw57@hermes.cam.ac.uk> Tue, 12 Mar 2002 19:41:13 +0000
+
diff --git a/lib/libdvd/libdvdread/DEVELOPMENT-POLICY.txt b/lib/libdvd/libdvdread/DEVELOPMENT-POLICY.txt
new file mode 100644
index 0000000000..20c73e5005
--- /dev/null
+++ b/lib/libdvd/libdvdread/DEVELOPMENT-POLICY.txt
@@ -0,0 +1,25 @@
+This fork of dvdnav was created to overcome the lack of responsiveness
+of the official development channel, not to bastardize this library in
+something for specific usage by mplayer, so these are the rules to follow
+when developing code:
+- don't remove pre-existing code that mplayer doesn't need
+- don't add code to expose the internals of dvdnav
+- don't add code that binds applications to side-effects of the library
+- don't alter the API in an incompatible manner
+
+
+When committing code to the repository always follow these rules:
+- don't break the compilability of the library - always keep svn checkouts usable
+- never mix cosmetical and functional changes
+- don't commit unrelated changes as a single transaction
+- don't split strictly related changes over multiple commits
+- never alter the indentation / bracing / prototyping style of existing files
+- if you break something by accident fix it as soon as possible using the appropriate
+ svn tools to revert your commit(s). If in doubt ask explanations to the
+ mailing list
+- trivial patches such as spell fixes, prototype mismatch, missing includes,
+ more proper variable typization and similar should be committed without asking
+ prior authorization
+
+
+If in reiterated violation of these rules your account will be deleted.
diff --git a/lib/libdvd/libdvdread/Makefile b/lib/libdvd/libdvdread/Makefile
new file mode 100644
index 0000000000..dc2c906c4f
--- /dev/null
+++ b/lib/libdvd/libdvdread/Makefile
@@ -0,0 +1,166 @@
+include config.mak
+
+.SUFFIXES: .so
+
+AR=ar
+LD=ld
+RANLIB=ranlib
+
+VPATH+= $(SRC_PATH_BARE)/src
+
+CFLAGS += $(USEDEBUG) -Wall -funsigned-char
+CFLAGS += -I$(CURDIR) -I$(SRC_PATH)/src
+CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
+CFLAGS += -DHAVE_CONFIG_H -DHAVE_DLFCN_H
+
+L=libdvdread
+DVDREAD_L=libdvdread
+DVDREAD_LIB = $(DVDREAD_L).a
+DVDREAD_SHLIB = $(DVDREAD_L).so
+VPATH+= $(SRC_PATH_BARE)/src
+DVDREAD_HEADERS = src/dvd_reader.h \
+ src/ifo_print.h \
+ src/ifo_read.h \
+ src/ifo_types.h \
+ src/nav_print.h \
+ src/nav_read.h \
+ src/dvd_udf.h \
+ src/nav_types.h \
+ src/bitreader.h
+DVDREAD_SRCS = dvd_input.c dvd_reader.c dvd_udf.c ifo_print.c ifo_read.c \
+ md5.c nav_print.c nav_read.c bitreader.c
+CFLAGS += -I$(SRC_PATH)/src
+
+LIB = $(L).a
+SHLIB = $(L).so
+
+.OBJDIR= obj
+DEPFLAG = -M
+
+OBJS = $(patsubst %.c,%.o, $(SRCS))
+DVDREAD_OBJS = $(patsubst %.c,%.o, $(DVDREAD_SRCS))
+SHOBJS = $(patsubst %.c,%.so, $(SRCS))
+DVDREAD_SHOBJS = $(patsubst %.c,%.so, $(DVDREAD_SRCS))
+DEPS= ${OBJS:%.o=%.d}
+DVDREAD_DEPS= ${DVDREAD_OBJS:%.o=%.d}
+
+BUILDDEPS = Makefile config.mak
+
+ifeq ($(BUILD_SHARED),yes)
+all: $(SHLIB) $(DVDREAD_SHLIB) dvdread-config pkgconfig
+install: $(SHLIB) $(DVDREAD_SHLIB) install-shared install-dvdread-config install-pkgconfig
+endif
+
+ifeq ($(BUILD_STATIC),yes)
+all: $(LIB) $(DVDREAD_LIB) dvdread-config pkgconfig
+install: $(LIB) $(DVDREAD_LIB) install-static install-dvdread-config install-pkgconfig
+endif
+
+install: install-headers
+
+# Let version.sh create version.h
+
+SVN_ENTRIES = $(SRC_PATH_BARE)/.svn/entries
+ifeq ($(wildcard $(SVN_ENTRIES)),$(SVN_ENTRIES))
+version.h: $(SVN_ENTRIES)
+endif
+
+version.h:
+ sh $(SRC_PATH)/version.sh $(SRC_PATH) "$(SHLIB_VERSION)"
+
+$(SRCS) $(DVDREAD_SRCS): version.h
+
+
+# General targets
+
+${DVDREAD_LIB}: version.h $(DVDREAD_OBJS) $(BUILDDEPS)
+ cd $(.OBJDIR) && $(AR) rc $@ $(DVDREAD_OBJS)
+ cd $(.OBJDIR) && $(RANLIB) $@
+
+${DVDREAD_SHLIB}: version.h $(DVDREAD_SHOBJS) $(BUILDDEPS)
+ cd $(.OBJDIR) && $(CC) $(SHLDFLAGS) $(LDFLAGS) -ldl -Wl,-soname=$(DVDREAD_SHLIB).$(SHLIB_MAJOR) -o $@ $(DVDREAD_SHOBJS)
+
+.c.so: $(BUILDDEPS)
+ cd $(.OBJDIR) && $(CC) -fPIC -DPIC -MD $(CFLAGS) -c -o $@ $<
+
+.c.o: $(BUILDDEPS)
+ cd $(.OBJDIR) && $(CC) -MD $(CFLAGS) -c -o $@ $<
+
+
+# Install targets
+
+install-headers:
+ install -d $(DESTDIR)$(dvdread_incdir)
+ install -m 644 $(DVDREAD_HEADERS) $(DESTDIR)$(dvdread_incdir)
+
+install-shared: $(SHLIB)
+ install -d $(DESTDIR)$(shlibdir)
+
+ install $(INSTALLSTRIP) -m 755 $(.OBJDIR)/$(SHLIB) \
+ $(DESTDIR)$(shlibdir)/$(SHLIB).$(SHLIB_VERSION)
+
+ cd $(DESTDIR)$(shlibdir) && \
+ ln -sf $(SHLIB).$(SHLIB_VERSION) $(SHLIB).$(SHLIB_MAJOR)
+ cd $(DESTDIR)$(shlibdir) && \
+ ln -sf $(SHLIB).$(SHLIB_MAJOR) $(SHLIB)
+
+ install $(INSTALLSTRIP) -m 755 $(.OBJDIR)/$(DVDREAD_SHLIB) \
+ $(DESTDIR)$(shlibdir)/$(DVDREAD_SHLIB).$(SHLIB_VERSION)
+ cd $(DESTDIR)$(shlibdir) && \
+ ln -sf $(DVDREAD_SHLIB).$(SHLIB_VERSION) $(DVDREAD_SHLIB).$(SHLIB_MAJOR)
+ cd $(DESTDIR)$(shlibdir) && \
+ ln -sf $(DVDREAD_SHLIB).$(SHLIB_MAJOR) $(DVDREAD_SHLIB)
+
+install-static: $(LIB)
+ install -d $(DESTDIR)$(libdir)
+
+ install $(INSTALLSTRIP) -m 755 $(.OBJDIR)/$(LIB) $(DESTDIR)$(libdir)/$(LIB)
+ install $(INSTALLSTRIP) -m 755 $(.OBJDIR)/$(DVDREAD_LIB) $(DESTDIR)$(libdir)/$(DVDREAD_LIB)
+
+
+# Clean targets
+
+clean:
+ rm -rf *~ $(.OBJDIR)/*
+
+
+distclean: clean
+ find . -name "*~" | xargs rm -rf
+ rm -rf config.mak $(.OBJDIR)
+
+dvdread-config: $(.OBJDIR)/dvdread-config
+$(.OBJDIR)/dvdread-config: $(BUILDDEPS)
+ @echo '#!/bin/sh' > $(.OBJDIR)/dvdread-config
+ @echo 'prefix='$(PREFIX) >> $(.OBJDIR)/dvdread-config
+ @echo 'libdir='$(shlibdir) >> $(.OBJDIR)/dvdread-config
+ @echo 'version='$(SHLIB_VERSION) >> $(.OBJDIR)/dvdread-config
+ @echo >> $(.OBJDIR)/dvdread-config
+ cat $(SRC_PATH_BARE)/misc/dvdread-config.sh >> $(.OBJDIR)/dvdread-config
+ chmod 0755 $(.OBJDIR)/dvdread-config
+
+install-dvdread-config: dvdread-config
+ install -d $(DESTDIR)$(PREFIX)/bin
+ install -m 0755 $(.OBJDIR)/dvdread-config $(DESTDIR)$(PREFIX)/bin/dvdread-config
+
+pcedit = sed \
+ -e 's,@prefix@,$(PREFIX),' \
+ -e 's,@exec_prefix@,$(PREFIX),' \
+ -e 's,@libdir@,$(shlibdir),' \
+ -e 's,@includedir@,$(PREFIX)/include,' \
+ -e 's,@VERSION@,$(SHLIB_VERSION),'
+
+pkgconfig: $(.OBJDIR)/dvdread.pc
+$(.OBJDIR)/dvdread.pc: misc/dvdread.pc.in $(BUILDDEPS)
+ $(pcedit) $< > $@
+
+install-pkgconfig: $(.OBJDIR)/dvdread.pc
+ install -d $(DESTDIR)$(libdir)/pkgconfig
+ install -m 0644 $(.OBJDIR)/dvdread.pc $(DESTDIR)$(libdir)/pkgconfig
+
+vpath %.so ${.OBJDIR}
+vpath %.o ${.OBJDIR}
+vpath ${LIB} ${.OBJDIR}
+
+# include dependency files if they exist
+$(addprefix ${.OBJDIR}/, ${DEPS}): ;
+-include $(addprefix ${.OBJDIR}/, ${DEPS})
diff --git a/lib/libdvd/libdvdread/Makefile.am b/lib/libdvd/libdvdread/Makefile.am
new file mode 100644
index 0000000000..84adceed94
--- /dev/null
+++ b/lib/libdvd/libdvdread/Makefile.am
@@ -0,0 +1,42 @@
+include $(top_srcdir)/misc/Makefile.common
+
+
+SUBDIRS = src misc m4
+
+EXTRA_DIST = autogen.sh \
+ AUTHORS \
+ ChangeLog \
+ configure \
+ config.guess \
+ config.sub \
+ COPYING \
+ INSTALL \
+ install-sh \
+ libtool \
+ ltmain.sh \
+ missing \
+ mkinstalldirs \
+ README \
+ TODO
+
+MOSTLYCLEANFILES += $(PACKAGE)_$(VERSION).tar.gz \
+ $(distdir).tar.gz $(PACKAGE).tgz package_descriptions
+
+MAINTAINERCLEANFILES += configure $(ACLOCAL_M4) config.h.in \
+ ltmain.sh config.guess config.sub install-sh missing \
+ mkinstalldirs
+
+world:
+ @$(MAKE) clean all install 2> warnings.log
+ test -s warnings.log || rm warnings.log
+
+prune-cache:
+ -rm -f config.cache
+
+release-check:
+ @./config.status misc/relchk.sh
+ @./autogen.sh noconfig && $(SHELL) misc/relchk.sh
+
+dist-hook:
+ cp -r $(srcdir)/msvc $(distdir)/msvc
+ rm -rf `find $(distdir)/msvc -name CVS`
diff --git a/lib/libdvd/libdvdread/NEWS b/lib/libdvd/libdvdread/NEWS
new file mode 100644
index 0000000000..7aa22b1545
--- /dev/null
+++ b/lib/libdvd/libdvdread/NEWS
@@ -0,0 +1,2 @@
+This file is unused.
+The ChangeLog file lists changes for new versions.
diff --git a/lib/libdvd/libdvdread/README b/lib/libdvd/libdvdread/README
new file mode 100644
index 0000000000..d7f78d48a2
--- /dev/null
+++ b/lib/libdvd/libdvdread/README
@@ -0,0 +1,57 @@
+What is this all about?
+-----------------------
+
+libdvdnav is a library that allows easy use of sophisticated DVD navigation
+features such as DVD menus, multiangle playback and even interactive DVD games.
+All this functionality is provided through a simple API which provides the
+DVD playback as a single logical stream of blocks, intermitted by special
+dvdnav events to report certain conditions. The main usage of libdvdnav is a
+loop regularly calling a function to get the next block, surrounded by
+additional calls to tell the library of user interaction.
+The whole DVD virtual machine and internal playback states are completely
+encapsulated.
+
+Where does it come from?
+------------------------
+
+This library is based on a lot of code and expertise from the Ogle project.
+Ogle was the first DVD player who implemented free DVD navigation. The
+libdvdnav developers wish to express their gratitude to the Ogle people
+for all the valuable research work they have done.
+
+Initially, the dvdnav code was part of a plugin to the xine media player
+called xine-dvdnav. Later on, the DVD VM specific code was split
+from xine-dvdnav and went into the first version of libdvdnav.
+
+Where is it now?
+----------------
+
+libdvdnav is hosted on http://www.mplayerhq.hu/MPlayer/releases/dvdnav/ .
+Please report bugs to the developers mailinglist at
+mailto:dvdnav-discuss@mplayerhq.hu .
+
+We are still in beta stage, but libdvdnav is already quite usable. With
+regular DVD playback, there should not be any serious issues. The library
+also makes some limited effort to handle error situations gracefully, but
+there are still assertions in the code that may trigger on some DVDs. Please
+send a report to the developer mailinglist, if you encounter such problems.
+
+How can I use it?
+-----------------
+
+libdvdnav is completely licensed under GPL. You may use it at wish within the
+bounds of this license. See the file "COPYING" for a copy of the GPL.
+
+Sources for documentation on libdvdnav are:
+* the examples directory contains a simple program using libdvdnav
+ this one is well-commented and therefore a good starting point
+* the public header dvdnav.h documents the API
+* the public header dvdnav_events.h documents the dvdnav events
+* doc/library_layout contains some info on the internal working of libdvdnav
+
+Sources for documentation on DVD terminology, structure and surrounding concepts:
+* doc/dvd_structures briefly explains DVD terms and organization
+* a more detailed description of DVD structures is available at
+ http://www.mpucoder.com/dvd/
+* the ifo_types.h and nav_types.h headers are also interesting if you
+ are already used to the sometimes cryptical abbreviations
diff --git a/lib/libdvd/libdvdread/TODO b/lib/libdvd/libdvdread/TODO
new file mode 100644
index 0000000000..3fe2eed5af
--- /dev/null
+++ b/lib/libdvd/libdvdread/TODO
@@ -0,0 +1,12 @@
+* Support DVDs with errors on them. So we can recover from corrupt sectors in the .VOB. Also, handle corrupt .IFO files by using the backup .BUP files.
+* Support Random and Shuffle Titles. Only sequencial Titles are currently supported.
+* rework documentation
+* implement restriction levels:
+ 0 - execute everything as the app commands
+ 1 - do some sensible sanity checking
+ 2 - be more careful, when operations are prohibited (like not seeking/jumping in the presence of stills or cell commands)
+ 3 - fully respect user prohibitions
+* cleanup public API and fix libtool versioning
+* Update decoder.c with some of the more rare commands. Update already done to vmcmd.c
+* RELEASE! (maybe it's time for libdvdnav 0.5?)
+* Replace the auto* build system with a custom and clean one based on ffmpeg's (partly done)
diff --git a/lib/libdvd/libdvdread/autogen.sh b/lib/libdvd/libdvdread/autogen.sh
new file mode 100755
index 0000000000..72f2ac80ee
--- /dev/null
+++ b/lib/libdvd/libdvdread/autogen.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# $Id: autogen.sh 1128 2008-08-30 22:32:00Z rathann $
+#
+# run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname "$0"`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd "$srcdir"
+
+AUTORECONF=${AUTORECONF-autoreconf}
+
+if ! type $AUTORECONF >/dev/null 2>&1; then
+ echo "**Error**: Missing \`autoreconf' program." >&2
+ echo "You will need the autoconf and automake packages." >&2
+ echo "You can download them from ftp://ftp.gnu.org/pub/gnu/." >&2
+ exit 1
+fi
+
+$AUTORECONF -v --install || exit $?
+cd "$ORIGDIR" || exit $?
+
+test "$1" = noconfig && NOCONFIGURE=1
+
+if test -z "$NOCONFIGURE"; then
+ "$srcdir"/configure "$@"
+fi
diff --git a/lib/libdvd/libdvdread/configure.ac b/lib/libdvd/libdvdread/configure.ac
new file mode 100644
index 0000000000..1425c371ac
--- /dev/null
+++ b/lib/libdvd/libdvdread/configure.ac
@@ -0,0 +1,210 @@
+dnl --------------------------------------------------------------
+dnl Configure.ac for libdvdread
+dnl --------------------------------------------------------------
+
+dnl --------------------------------------------------------------
+dnl Require autoconf version 2.53
+dnl --------------------------------------------------------------
+AC_PREREQ([2.53])
+
+dnl --------------------------------------------------------------
+dnl Making releases: dvdread_sub += 1; change DVDREAD_LT_* accordingly
+dnl
+dnl These are defined in m4 so they can be passed to AC_INIT
+dnl --------------------------------------------------------------
+m4_define([dvdread_major], [4])
+m4_define([dvdread_minor], [1])
+m4_define([dvdread_sub], [3])
+m4_define([dvdread_pre], [])
+
+AC_INIT([libdvdread], [dvdread_major.dvdread_minor.dvdread_sub[]dvdread_pre])
+AC_CONFIG_SRCDIR([src/dvd_reader.h])
+AM_INIT_AUTOMAKE([1.6])
+
+dnl create a config.h file (Automake will add -DHAVE_CONFIG_H)
+AC_CONFIG_HEADERS([config.h])
+AC_CANONICAL_HOST
+
+DVDREAD_MAJOR="dvdread_major"
+DVDREAD_MINOR="dvdread_minor"
+DVDREAD_SUB="dvdread_sub"
+DVDREAD_PRE="dvdread_pre"
+
+AC_SUBST(DVDREAD_MAJOR)
+AC_SUBST(DVDREAD_MINOR)
+AC_SUBST(DVDREAD_SUB)
+
+dnl The libtool version numbers (DVDREAD_LT_*); Don't even think about faking this!
+dnl
+dnl immediately before every release do:
+dnl ===================================
+dnl if (the interface is totally unchanged from previous release)
+dnl DVDREAD_LT_REVISION ++;
+dnl else { /* interfaces have been added, removed or changed */
+dnl DVDREAD_LT_REVISION = 0;
+dnl DVDREAD_LT_CURRENT ++;
+dnl if (any interfaces have been _added_ since last release)
+dnl AGE ++;
+dnl if (any interfaces have been _removed_ or _incompatibly changed_)
+dnl AGE = 0;
+dnl }
+dnl
+dnl If you want to know more about what you are doing, here are some details:
+dnl * DVDREAD_LT_CURRENT is the current API version
+dnl * DVDREAD_LT_REVISION is an internal revision number which is increased when the API
+dnl itself did not change
+dnl * DVDREAD_LT_AGE is the number of previous API versions still supported by this library
+dnl * libtool has its own numbering scheme, because local library numbering schemes
+dnl are platform dependent
+dnl * in Linux, the library will be named
+dnl libname.so.(DVDREAD_LT_CURRENT - DVDREAD_LT_AGE).DVDREAD_LT_AGE.DVDREAD_LT_REVISION
+
+DVDREAD_LT_CURRENT=5
+DVDREAD_LT_AGE=1
+DVDREAD_LT_REVISION=2
+
+AC_SUBST(DVDREAD_LT_CURRENT)
+AC_SUBST(DVDREAD_LT_AGE)
+AC_SUBST(DVDREAD_LT_REVISION)
+
+dnl --------------------------------------------------------------
+dnl Make possible to build for another arch.
+dnl --------------------------------------------------------------
+if test x$DVDREAD_BUILD != "x"; then
+ AC_MSG_RESULT(*** build forced to $DVDREAD_BUILD ***)
+ build=$DVDREAD_BUILD
+ host=$DVDREAD_BUILD
+else
+ check_athlon=yes
+fi
+
+dnl --------------------------------------------------------------
+dnl Checks for programs.
+dnl --------------------------------------------------------------
+dnl Save CFLAGS, AC_ISC_POSIX set some unwanted default CFLAGS
+saved_CFLAGS="$CFLAGS"
+AC_ISC_POSIX
+CFLAGS="$saved_CFLAGS"
+AC_PROG_CC
+AC_PROG_MAKE_SET
+AC_PROG_INSTALL
+AC_PROG_LN_S
+
+dnl --------------------------------------------------------------
+dnl Libtool
+dnl --------------------------------------------------------------
+dnl LT_PREREQ only available in libtool-2.2+
+dnl LT_PREREQ([1.4.0])
+AC_LIBTOOL_DLOPEN
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
+AC_SUBST(LIBTOOL_DEPS)
+if ${CONFIG_SHELL} ./libtool --features | grep "enable static" >/dev/null; then
+ STATIC="-static"
+else
+ STATIC=
+fi
+AC_SUBST(STATIC)
+
+dnl --------------------------------------------------------------
+dnl Checks for header files.
+dnl --------------------------------------------------------------
+AC_HEADER_STDC
+AC_CHECK_HEADER(unistd.h)
+AC_CHECK_HEADER(string.h)
+
+dnl --------------------------------------------------------------
+dnl Checks for typedefs, structures, and compiler characteristics.
+dnl --------------------------------------------------------------
+AC_C_CONST
+AC_C_INLINE
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+dnl AC_CHECK_TYPES([ptrdiff_t])
+AC_C_BIGENDIAN
+
+dnl -------------------------------------------------------------
+dnl Check for basic *nix fonction that we may emulate on windows.
+dnl -------------------------------------------------------------
+case $host in
+ *mingw32* | *cygwin*)
+ AC_CHECK_FUNCS(gettimeofday)
+ ;;
+ *)
+ ;;
+esac
+
+dnl ---------------------------------------------
+dnl dynamic linker
+dnl ---------------------------------------------
+case $host in
+ *mingw32*)
+ CFLAGS="-idirafter \$(top_srcdir)/msvc/include $CFLAGS"
+ LDFLAGS="-no-undefined $LDFLAGS"
+ ;;
+ *cygwin*)
+ LDFLAGS="-no-undefined $LDFLAGS"
+ ;;
+ *)
+ AC_CHECK_LIB(c, dlopen,
+ DYNAMIC_LD_LIBS="",
+ AC_CHECK_LIB(dl, dlopen,
+ DYNAMIC_LD_LIBS="-ldl",
+ AC_MSG_ERROR(dynamic linker needed)))
+ AC_SUBST(DYNAMIC_LD_LIBS)
+ ;;
+esac
+
+dnl ---------------------------------------------
+dnl cflags
+dnl ---------------------------------------------
+dnl Common cflags for all platforms
+CFLAGS="-O3 -Wall -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE $CFLAGS"
+DEBUG_CFLAGS="-g -DDEBUG $CFLAGS"
+
+AC_SUBST(DEBUG_CFLAGS)
+
+dnl ---------------------------------------------
+dnl Get where .m4 should be installed.
+dnl ---------------------------------------------
+case "`id`" in
+ uid=0\(* )
+ AC_MSG_CHECKING(for aclocal directory)
+ if (aclocal --version) < /dev/null > /dev/null 2>&1; then
+ ACLOCAL_DIR="`eval $ACLOCAL --print-ac-dir`"
+ AC_MSG_RESULT($ACLOCAL_DIR)
+ else
+ ACLOCAL_DIR="/usr/local/share/aclocal"
+ AC_MSG_RESULT(none - will be installed in $ACLOCAL_DIR)
+ fi
+ escapedprefix="`echo $prefix | sed -e 's/\\//\\\\\//g'`"
+ ACLOCAL_DIR="`echo $ACLOCAL_DIR|sed -e 's/^'$escapedprefix/'\${prefix}'/`"
+ AC_SUBST(ACLOCAL_DIR)
+ ;;
+esac
+AM_CONDITIONAL(INSTALL_M4, test x"$ACLOCAL_DIR" != "x")
+
+dnl ---------------------------------------------
+dnl Check for doxygen (dynamic documentation generator)
+dnl ---------------------------------------------
+AC_CHECK_PROG(DOXYGEN, doxygen, doxygen, no)
+
+dnl ---------------------------------------------
+dnl Some include paths ( !!! DO NOT REMOVE !!! )
+dnl ---------------------------------------------
+INCLUDES='-I$(top_srcdir) $(DVDREAD_CFLAGS)'
+AC_SUBST(INCLUDES)
+
+dnl ---------------------------------------------
+dnl Output configuration files
+dnl ---------------------------------------------
+AC_OUTPUT([
+Makefile
+src/Makefile
+misc/Makefile
+misc/dvdread-config
+misc/dvdread.pc
+misc/libdvdread.spec
+misc/relchk.sh
+m4/Makefile
+])
diff --git a/lib/libdvd/libdvdread/configure2 b/lib/libdvd/libdvdread/configure2
new file mode 100755
index 0000000000..08c0c40e15
--- /dev/null
+++ b/lib/libdvd/libdvdread/configure2
@@ -0,0 +1,155 @@
+#!/bin/sh
+
+dvdread_sh_version=4.1.3
+dvdread_sh_major=`echo $dvdread_sh_version | awk -F. '{print $1}'`
+
+cc=gcc
+make=make
+
+# find source path
+source_path="`dirname \"$0\"`"
+source_path_used="yes"
+if test -z "$source_path" -o "$source_path" = "." ; then
+ source_path="`pwd`"
+ source_path_used="no"
+else
+ source_path="`cd \"$source_path\" && pwd`"
+ echo "$source_path" | grep -q '[[:blank:]]' &&
+ die "Out of tree builds are impossible with whitespace in source path."
+fi
+
+show_help(){
+ echo "Usage: configure [options]"
+ echo "Options: [defaults in brackets after descriptions]"
+ echo
+ echo "Standard options:"
+ echo " --help print this message"
+ echo " --prefix=PREFIX install in PREFIX [$PREFIX]"
+ echo " --libdir=DIR install libs in DIR [PREFIX/lib]"
+ echo " --shlibdir=DIR install shared libs in DIR [PREFIX/lib]"
+ echo " --incdir=DIR install includes in DIR [PREFIX/include/libdvdread]"
+ echo " --enable-static build static libraries [default=yes]"
+ echo " --disable-static do not build static libraries [default=no]"
+ echo " --enable-shared build shared libraries [default=no]"
+ echo " --disable-shared do not build shared libraries [default=yes]"
+ echo " --enable-debug compile with debug symbols [default=yes]"
+ echo " --disable-debug compile without debug symbols [default=no]"
+ echo "Advanced options (experts only):"
+ echo " --cc=CC use C compiler CC [$cc]"
+ echo " --make=MAKE use specified make [$make]"
+ echo " --extra-cflags=ECFLAGS add ECFLAGS to CFLAGS"
+ echo " --extra-ldflags=ELDFLAGS add ELDFLAGS to LDFLAGS"
+ echo "Developer options:"
+ echo " --disable-strip disable stripping of executables and shared libraries"
+ echo " --disable-opts disable compiler optimizations"
+ exit 1
+}
+
+SHARED=yes
+STATIC=yes
+PREFIX=/usr/local/
+INSTALLSTRIP=-s
+USEDEBUG=-g
+optimizations="-O3"
+
+for opt do
+ optval=`echo $opt | cut -d '=' -f 2-`
+ case "$opt" in
+ --enable-shared) SHARED=yes
+ ;;
+ --disable-shared) SHARED=no
+ ;;
+ --enable-static) STATIC=yes
+ ;;
+ --disable-static) STATIC=no
+ ;;
+ --prefix=*) PREFIX="$optval"
+ ;;
+ --libdir=*) libdir="$optval"
+ ;;
+ --shlibdir=*) shlibdir="$optval"
+ ;;
+ --incdir=*) incdir="$optval"
+ ;;
+ --cc=*) cc="$optval"
+ ;;
+ --make=*) make="$optval"
+ ;;
+ --extra-cflags=*) cflags="$cflags $optval"
+ ;;
+ --extra-ldflags=*) ldflags="$ldflags $optval"
+ ;;
+ --disable-strip) INSTALLSTRIP=
+ ;;
+ --disable-opts) optimizations=""
+ ;;
+ --disable-debug) USEDEBUG=""
+ ;;
+ --enable-debug) USEDEBUG="-g"
+ ;;
+ --help) show_help
+ ;;
+ esac
+done
+
+PREFIX=`cd $PREFIX && pwd`
+
+test -z "$libdir" && libdir=$PREFIX/lib
+test -z "$shlibdir" && shlibdir=$PREFIX/lib
+test -z "$incdir" && dvdread_incdir=$PREFIX/include/dvdread
+
+targetos=`uname -s`
+case $targetos in
+ Darwin)
+ SHLDFLAGS="-dynamiclib -Wl,-single_module -Wl,-read_only_relocs,suppress"
+ ;;
+ *)
+ SHLDFLAGS="-shared"
+ ;;
+esac
+
+cat > config.mak << EOF
+# Automatically generated by configure, do not edit
+PREFIX=$PREFIX
+libdir=$libdir
+shlibdir=$shlibdir
+incdir=$incdir
+dvdread_incdir=$dvdread_incdir
+BUILD_SHARED=$SHARED
+BUILD_STATIC=$STATIC
+SHLIB_VERSION=$dvdread_sh_version
+SHLIB_MAJOR=$dvdread_sh_major
+CC=$cc
+MAKE=$make
+CFLAGS=$optimizations $cflags
+LDFLAGS=$ldflags
+SHLDFLAGS=$SHLDFLAGS
+INSTALLSTRIP=$INSTALLSTRIP
+USEDEBUG=$USEDEBUG
+
+SRC_PATH="$source_path"
+SRC_PATH_BARE=$source_path
+
+EOF
+
+cat > config.h << EOF
+/* Automatically generated by configure, do not edit */
+#include "version.h"
+EOF
+
+# build tree in object directory if source path is different from current one
+if test "$source_path_used" != "no"; then
+ FILES="\
+ Makefile \
+ misc \
+ "
+ for f in $FILES ; do
+ ln -sf "$source_path/$f" $f
+ done
+fi
+
+[ -d obj ] || mkdir -p obj
+
+echo
+echo "Done, type 'make install' to build and install"
+
diff --git a/lib/libdvd/libdvdread/m4/Makefile.am b/lib/libdvd/libdvdread/m4/Makefile.am
new file mode 100644
index 0000000000..a29b467bb7
--- /dev/null
+++ b/lib/libdvd/libdvdread/m4/Makefile.am
@@ -0,0 +1,11 @@
+include $(top_srcdir)/misc/Makefile.common
+
+EXTRA_DIST = dvdread.m4
+
+if INSTALL_M4
+m4datadir = @ACLOCAL_DIR@
+else
+m4datadir = $(datadir)/aclocal
+endif
+
+m4data_DATA = dvdread.m4
diff --git a/lib/libdvd/libdvdread/m4/dvdread.m4 b/lib/libdvd/libdvdread/m4/dvdread.m4
new file mode 100644
index 0000000000..e11b35c046
--- /dev/null
+++ b/lib/libdvd/libdvdread/m4/dvdread.m4
@@ -0,0 +1,181 @@
+dnl Configure paths for DVDREAD
+dnl
+dnl Copyright (C) 2001 Daniel Caujolle-Bert <segfault@club-internet.fr>
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+dnl
+dnl
+dnl As a special exception to the GNU General Public License, if you
+dnl distribute this file as part of a program that contains a configuration
+dnl script generated by Autoconf, you may include it under the same
+dnl distribution terms that you use for the rest of that program.
+dnl
+
+dnl AM_PATH_DVDREAD([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
+dnl Test for DVDREAD, and define DVDREAD_CFLAGS and DVDREAD_LIBS
+dnl
+AC_DEFUN([AM_PATH_DVDREAD],
+[dnl
+dnl Get the cflags and libraries from the dvdread-config script
+dnl
+AC_ARG_WITH(dvdread-prefix,
+ AC_HELP_STRING([--with-dvdread-prefix=DIR], [prefix where DVDREAD is installed (optional)]),
+ dvdread_config_prefix="$withval", dvdread_config_prefix="")
+AC_ARG_WITH(dvdread-exec-prefix,
+ AC_HELP_STRING([--with-dvdread-exec-prefix=DIR], [exec prefix where DVDREAD is installed (optional)]),
+ dvdread_config_exec_prefix="$withval", dvdread_config_exec_prefix="")
+AC_ARG_ENABLE(dvdreadtest,
+ AC_HELP_STRING([--disable-dvdreadtest], [do not try to compile and run a test DVDREAD program]),
+ enable_dvdreadtest=$enableval, enable_dvdreadtest=yes)
+
+ if test x$dvdread_config_exec_prefix != x ; then
+ dvdread_config_args="$dvdread_config_args --exec-prefix=$dvdread_config_exec_prefix"
+ if test x${DVDREAD_CONFIG+set} != xset ; then
+ DVDREAD_CONFIG=$dvdread_config_exec_prefix/bin/dvdread-config
+ fi
+ fi
+ if test x$dvdread_config_prefix != x ; then
+ dvdread_config_args="$dvdread_config_args --prefix=$dvdread_config_prefix"
+ if test x${DVDREAD_CONFIG+set} != xset ; then
+ DVDREAD_CONFIG=$dvdread_config_prefix/bin/dvdread-config
+ fi
+ fi
+
+ min_dvdread_version=ifelse([$1], ,0.0.0,$1)
+ if test "x$enable_dvdreadtest" != "xyes" ; then
+ AC_MSG_CHECKING([for DVDREAD-LIB version >= $min_dvdread_version])
+ else
+ AC_PATH_PROG(DVDREAD_CONFIG, dvdread-config, no)
+ AC_MSG_CHECKING([for DVDREAD-LIB version >= $min_dvdread_version])
+ no_dvdread=""
+ if test "$DVDREAD_CONFIG" = "no" ; then
+ no_dvdread=yes
+ else
+ DVDREAD_CFLAGS=`$DVDREAD_CONFIG $dvdread_config_args --cflags`
+ DVDREAD_LIBS=`$DVDREAD_CONFIG $dvdread_config_args --libs`
+ dvdread_config_major_version=`$DVDREAD_CONFIG $dvdread_config_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+ dvdread_config_minor_version=`$DVDREAD_CONFIG $dvdread_config_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+ dvdread_config_sub_version=`$DVDREAD_CONFIG $dvdread_config_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+ dnl if test "x$enable_dvdreadtest" = "xyes" ; then
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $DVDREAD_CFLAGS"
+ LIBS="$DVDREAD_LIBS $LIBS"
+dnl
+dnl Now check if the installed DVDREAD is sufficiently new. (Also sanity
+dnl checks the results of dvdread-config to some extent
+dnl
+ AC_LANG_SAVE()
+ AC_LANG_C()
+ rm -f conf.dvdreadtest
+ AC_TRY_RUN([
+#include <dvdread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main ()
+{
+ int major, minor, sub;
+ char *tmp_version;
+
+ system ("touch conf.dvdreadtest");
+
+ /* HP/UX 9 (%@#!) writes to sscanf strings */
+ tmp_version = (char *) strdup("$min_dvdread_version");
+ if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &sub) != 3) {
+ printf("%s, bad version string\n", "$min_dvdread_version");
+ exit(1);
+ }
+
+ if (($dvdread_config_major_version > major) ||
+ (($dvdread_config_major_version == major) && ($dvdread_config_minor_version > minor)) ||
+ (($dvdread_config_major_version == major) && ($dvdread_config_minor_version == minor) && ($dvdread_config_sub_version >= sub))) {
+ return 0;
+ } else {
+ printf("\n*** An old version of libdvdread (%d.%d.%d) was found.\n",
+ $dvdread_config_major_version, $dvdread_config_minor_version, $dvdread_config_sub_version);
+ printf("*** You need a version of libdvdread newer than %d.%d.%d. The latest version of\n",
+ major, minor, sub);
+ printf("*** libdvdread is always available from:\n");
+ printf("*** http://dvd.sourceforge.net\n");
+ printf("***\n");
+ printf("*** If you have already installed a sufficiently new version, this error\n");
+ printf("*** probably means that the wrong copy of the dvdread-config shell script is\n");
+ printf("*** being found. The easiest way to fix this is to remove the old version\n");
+ printf("*** of libdvdread, but you can also set the DVDREAD_CONFIG environment to point to the\n");
+ printf("*** correct copy of dvdread-config. (In this case, you will have to\n");
+ printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
+ printf("*** so that the correct libraries are found at run-time))\n");
+ }
+ return 1;
+}
+],, no_dvdread=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ if test "x$no_dvdread" = x ; then
+ AC_MSG_RESULT(yes)
+ ifelse([$2], , :, [$2])
+ else
+ AC_MSG_RESULT(no)
+ if test "$DVDREAD_CONFIG" = "no" ; then
+ echo "*** The dvdread-config script installed by DVDREAD could not be found"
+ echo "*** If DVDREAD was installed in PREFIX, make sure PREFIX/bin is in"
+ echo "*** your path, or set the DVDREAD_CONFIG environment variable to the"
+ echo "*** full path to dvdread-config."
+ else
+ if test -f conf.dvdreadtest ; then
+ :
+ else
+ echo "*** Could not run DVDREAD test program, checking why..."
+ CFLAGS="$CFLAGS $DVDREAD_CFLAGS"
+ LIBS="$LIBS $DVDREAD_LIBS"
+ AC_TRY_LINK([
+#include <dvdread.h>
+#include <stdio.h>
+], [ return 0; ],
+ [ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding DVDREAD or finding the wrong"
+ echo "*** version of DVDREAD. If it is not finding DVDREAD, you'll need to set your"
+ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+ echo "*** to the installed location Also, make sure you have run ldconfig if that"
+ echo "*** is required on your system"
+ echo "***"
+ echo "*** If you have an old version installed, it is best to remove it, although"
+ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"
+ echo "***"],
+ [ echo "*** The test program failed to compile or link. See the file config.log for the"
+ echo "*** exact error that occured. This usually means DVDREAD was incorrectly installed"
+ echo "*** or that you have moved DVDREAD since it was installed. In the latter case, you"
+ echo "*** may want to edit the dvdread-config script: $DVDREAD_CONFIG" ])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ DVDREAD_CFLAGS=""
+ DVDREAD_LIBS=""
+ ifelse([$3], , :, [$3])
+ fi
+ AC_SUBST(DVDREAD_CFLAGS)
+ AC_SUBST(DVDREAD_LIBS)
+ AC_LANG_RESTORE()
+ rm -f conf.dvdreadtest
+])
diff --git a/lib/libdvd/libdvdread/misc/Makefile.am b/lib/libdvd/libdvdread/misc/Makefile.am
new file mode 100644
index 0000000000..efe65034c3
--- /dev/null
+++ b/lib/libdvd/libdvdread/misc/Makefile.am
@@ -0,0 +1,8 @@
+include $(top_srcdir)/misc/Makefile.common
+
+EXTRA_DIST = libdvdread.spec.in libdvdread.spec Makefile.common relchk.sh relchk.sh.in
+
+bin_SCRIPTS = dvdread-config
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = dvdread.pc
diff --git a/lib/libdvd/libdvdread/misc/Makefile.common b/lib/libdvd/libdvdread/misc/Makefile.common
new file mode 100644
index 0000000000..6faa23f2c7
--- /dev/null
+++ b/lib/libdvd/libdvdread/misc/Makefile.common
@@ -0,0 +1,10 @@
+MOSTLYCLEANFILES = *~ \\\#* .*~ .\\\#*
+MAINTAINERCLEANFILES = Makefile.in
+
+debug:
+ @$(MAKE) CFLAGS="$(DEBUG_CFLAGS)"
+
+debug-install: install-debug
+
+install-debug:
+ @$(MAKE) CFLAGS="$(DEBUG_CFLAGS)" install
diff --git a/lib/libdvd/libdvdread/misc/dvdread-config.in b/lib/libdvd/libdvdread/misc/dvdread-config.in
new file mode 100644
index 0000000000..cf38462e24
--- /dev/null
+++ b/lib/libdvd/libdvdread/misc/dvdread-config.in
@@ -0,0 +1,80 @@
+#!/bin/sh
+#
+#
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+exec_prefix_set=no
+
+usage()
+{
+ cat <<EOF
+Usage: dvdnav-config [OPTIONS] [LIBRARIES]
+Options:
+ [--prefix[=DIR]]
+ [--exec-prefix[=DIR]]
+ [--version]
+ [--libs]
+ [--cflags]
+EOF
+ exit $1
+}
+
+if test $# -eq 0; then
+ usage 1 1>&2
+fi
+
+while test $# -gt 0; do
+ case "$1" in
+ -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ case $1 in
+ --prefix=*)
+ prefix=$optarg
+ if test $exec_prefix_set = no ; then
+ exec_prefix=$optarg
+ fi
+ ;;
+ --prefix)
+ echo_prefix=yes
+ ;;
+ --exec-prefix=*)
+ exec_prefix=$optarg
+ exec_prefix_set=yes
+ ;;
+ --exec-prefix)
+ echo_exec_prefix=yes
+ ;;
+ --version)
+ echo @DVDREAD_MAJOR@.@DVDREAD_MINOR@.@DVDREAD_SUB@
+ ;;
+ --cflags)
+ echo_cflags=yes
+ ;;
+ --libs)
+ echo_libs=yes
+ ;;
+ *)
+ usage 1 1>&2
+ ;;
+ esac
+ shift
+done
+
+if test "$echo_prefix" = "yes"; then
+ echo $prefix
+fi
+
+if test "$echo_exec_prefix" = "yes"; then
+ echo $exec_prefix
+fi
+
+if test "$echo_cflags" = "yes"; then
+ echo -I@includedir@
+fi
+
+if test "$echo_libs" = "yes"; then
+ echo -L@libdir@ -ldvdread
+fi
diff --git a/lib/libdvd/libdvdread/misc/dvdread-config.sh b/lib/libdvd/libdvdread/misc/dvdread-config.sh
new file mode 100644
index 0000000000..e170c7ee1b
--- /dev/null
+++ b/lib/libdvd/libdvdread/misc/dvdread-config.sh
@@ -0,0 +1,56 @@
+dvdreadlib="-ldvdread"
+
+usage()
+{
+ cat <<EOF
+Usage: dvdread-config [OPTIONS] [LIBRARIES]
+Options:
+ [--prefix[=DIR]]
+ [--version]
+ [--libs]
+ [--cflags]
+EOF
+ exit $1
+}
+
+if test $# -eq 0; then
+ usage 1 1>&2
+fi
+
+while test $# -gt 0; do
+ case "$1" in
+ -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ case $1 in
+ --prefix)
+ echo_prefix=yes
+ ;;
+ --version)
+ echo $version
+ ;;
+ --cflags)
+ echo_cflags=yes
+ ;;
+ --libs)
+ echo_libs=yes
+ ;;
+ *)
+ usage 1 1>&2
+ ;;
+ esac
+ shift
+done
+
+if test "$echo_prefix" = "yes"; then
+ echo $prefix
+fi
+
+if test "$echo_cflags" = "yes"; then
+ echo -I$prefix/include $extracflags
+fi
+
+if test "$echo_libs" = "yes"; then
+ echo -L$libdir $dvdreadlib
+fi
diff --git a/lib/libdvd/libdvdread/misc/dvdread.pc.in b/lib/libdvd/libdvdread/misc/dvdread.pc.in
new file mode 100644
index 0000000000..917d0e665a
--- /dev/null
+++ b/lib/libdvd/libdvdread/misc/dvdread.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libdvdread
+Description: Low level DVD access library
+Version: @VERSION@
+
+Cflags: -I${includedir}
+Libs: -L${libdir} -ldvdread
diff --git a/lib/libdvd/libdvdread/misc/libdvdread.spec.in b/lib/libdvd/libdvdread/misc/libdvdread.spec.in
new file mode 100644
index 0000000000..44168576c1
--- /dev/null
+++ b/lib/libdvd/libdvdread/misc/libdvdread.spec.in
@@ -0,0 +1,50 @@
+%define prefix @prefix@
+%define name @PACKAGE_NAME@
+%define ver @PACKAGE_VERSION@
+%define rel 0
+
+Name: %{name}
+Summary: Low level DVD access library
+Version: %{ver}
+Release: %{rel}
+Group: Development/Libraries
+Copyright: GPL
+Url: http://dvd.sourceforge.net/
+Source: %{name}-%{version}.tar.gz
+Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root
+
+%description
+libdvdread provides support to applications wishing to make use of basic
+DVD reading features.
+
+%prep
+%setup
+
+%build
+CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{prefix}
+make
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install-strip DESTDIR=$RPM_BUILD_ROOT
+
+%clean
+rm -r $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+%doc AUTHORS ChangeLog COPYING INSTALL README
+%{prefix}/bin/dvdread-config
+%{prefix}/lib/libdvdread*.la
+%{prefix}/lib/libdvdread*.so.*
+%{prefix}/lib/libdvdread*.so
+%{prefix}/include/libdvdread/*
+@INSTALL_M4_TRUE@@ACLOCAL_DIR@/dvdread.m4
+
+%changelog
+* Sun Mar 18 2002 Daniel Caujolle-Bert <f1rmb@users.sourceforge.net>
+- Add missing files. Fix rpm generation.
+* Tue Mar 12 2002 Rich Wareham <richwareham@users.sourceforge.net>
+- Canabalisation to form libdvdnav spec file.
+* Sun Sep 09 2001 Thomas Vander Stichele <thomas@apestaart.org>
+- first spec file
diff --git a/lib/libdvd/libdvdread/misc/relchk.sh.in b/lib/libdvd/libdvdread/misc/relchk.sh.in
new file mode 100755
index 0000000000..8251874692
--- /dev/null
+++ b/lib/libdvd/libdvdread/misc/relchk.sh.in
@@ -0,0 +1,66 @@
+#!/bin/sh
+##
+## A simple compare directory content utility.
+##
+
+topdir="`pwd`"
+distdir="@PACKAGE_NAME@-@PACKAGE_VERSION@"
+log="$topdir/dist-log"
+logerror="$topdir/dist-errors"
+
+getdir() {
+ if test -r .relignore; then
+ filelist=`ls | grep -Fxvf .relignore`
+ else
+ filelist=`ls`
+ fi
+
+ for file in $filelist; do
+
+ if test -d $file -a $file != "CVS" -a $file != $distdir; then
+ (cd $file && getdir) || (cd ..)
+ else
+ if test ! -d $file -a \
+ $file != $log -a \
+ $file != $logerror -a \
+ $file != "$distdir.tar.gz"; then
+
+ orifile=`pwd`/$file
+
+ distfile=$topdir/$distdir${orifile##*$topdir}
+
+ echo -e "check:\t$orifile\nand\t$distfile" >> $log
+
+ if test ! -e $distfile; then
+ missingfile=${orifile##$topdir}
+ echo "${missingfile#/} is missing in tarball" >> $logerror
+ fi
+
+ fi
+ fi
+
+ done
+}
+
+main() {
+ rm -f $log $logerror
+
+ make config.status && make dist && mv $distdir.tar.gz $distdir.tmp.tar.gz && \
+ cp config.status config.tmp.status && make clean && make distclean && \
+ mv $distdir.tmp.tar.gz $distdir.tar.gz && mv config.tmp.status config.status && \
+ tar -xzf $distdir.tar.gz
+
+ echo "Check is running, be patient..."
+ getdir
+
+ rm -rf $distdir
+ rm -f $distdir.tar.gz
+ ./config.status --recheck
+ ./config.status
+
+ echo " * Log is ${log##*/}"
+ echo " * Error log is ${logerror##*/}"
+
+}
+
+main
diff --git a/lib/libdvd/libdvdread/msvc/config.h b/lib/libdvd/libdvdread/msvc/config.h
new file mode 100755
index 0000000000..c6c6f94dc3
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/config.h
@@ -0,0 +1,51 @@
+/* config.h. Generated by hand. */
+
+#define HAVE_DLFCN_H 1
+/* #undef HAVE_DVDCSS_DVDCSS_H*/
+/* #undef HAVE_INTTYPES_H */
+#define HAVE_MEMORY_H 1
+/* #undef HAVE_STDINT_H */
+#define HAVE_STDLIB_H 1
+#define HAVE_STRINGS_H 1
+#define HAVE_STRING_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TYPES_H 1
+/* #undef HAVE_UNISTD_H */
+#define PACKAGE "libdvdread"
+#define PACKAGE_BUGREPORT ""
+#define PACKAGE_NAME ""
+#define PACKAGE_STRING ""
+#define PACKAGE_TARNAME ""
+#define PACKAGE_VERSION ""
+#define STDC_HEADERS 1
+#define VERSION "1.2.6"
+/* #undef WORDS_BIGENDIAN */
+/* #undef __DARWIN__ */
+/* #undef const */
+#define inline __inline
+/* #undef size_t */
+
+#define ssize_t __int64
+
+#ifndef PATH_MAX
+#define PATH_MAX MAX_PATH
+#endif
+
+#define strcasecmp stricmp
+#define strncasecmp strnicmp
+
+#define S_ISDIR(m) ((m) & _S_IFDIR)
+#define S_ISREG(m) ((m) & _S_IFREG)
+#define S_ISBLK(m) 0
+#define S_ISCHR(m) 0
+
+/* Fallback types (very x86-centric, sorry) */
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+typedef unsigned int uint32_t;
+typedef signed int int32_t;
+typedef unsigned __int64 uint64_t;
+typedef signed __int64 int64_t;
+typedef unsigned int uintptr_t;
diff --git a/lib/libdvd/libdvdread/msvc/contrib/bcopy.c b/lib/libdvd/libdvdread/msvc/contrib/bcopy.c
new file mode 100755
index 0000000000..21be364aef
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/contrib/bcopy.c
@@ -0,0 +1,8 @@
+#include <string.h>
+
+void bcopy(const void *IN, void *OUT, size_t N);
+
+void bcopy(const void *IN, void *OUT, size_t N)
+{
+ memcpy(OUT, IN, N);
+}
diff --git a/lib/libdvd/libdvdread/msvc/contrib/dirent/dirent.c b/lib/libdvd/libdvdread/msvc/contrib/dirent/dirent.c
new file mode 100755
index 0000000000..00289ed57f
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/contrib/dirent/dirent.c
@@ -0,0 +1,135 @@
+/*
+
+ Implementation of POSIX directory browsing functions and types for Win32.
+
+ Kevlin Henney (mailto:kevlin@acm.org), March 1997.
+
+ Copyright Kevlin Henney, 1997. All rights reserved.
+
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose is hereby granted without fee, provided
+ that this copyright and permissions notice appear in all copies and
+ derivatives, and that no charge may be made for the software and its
+ documentation except to cover cost of distribution.
+
+ This software is supplied "as is" without express or implied warranty.
+
+ But that said, if there are any problems please get in touch.
+
+*/
+
+#include <dirent.h>
+#include <errno.h>
+#include <io.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef DIR
+
+struct DIR
+{
+ long handle; /* -1 for failed rewind */
+ struct _finddata_t info;
+ struct dirent result; /* d_name null iff first time */
+ char *name; /* NTBS */
+};
+
+#endif
+
+DIR *opendir(const char *name)
+{
+ DIR *dir = 0;
+
+ if(name && name[0])
+ {
+ size_t base_length = strlen(name);
+ const char *all = /* the root directory is a special case... */
+ strchr("/\\", name[base_length - 1]) ? "*" : "/*";
+
+ if((dir = (DIR *) malloc(sizeof *dir)) != 0 &&
+ (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0)
+ {
+ strcat(strcpy(dir->name, name), all);
+
+ if((dir->handle = _findfirst(dir->name, &dir->info)) != -1)
+ {
+ dir->result.d_name = 0;
+ }
+ else /* rollback */
+ {
+ free(dir->name);
+ free(dir);
+ dir = 0;
+ }
+ }
+ else /* rollback */
+ {
+ free(dir);
+ dir = 0;
+ errno = ENOMEM;
+ }
+ }
+ else
+ {
+ errno = EINVAL;
+ }
+
+ return dir;
+}
+
+int closedir(DIR *dir)
+{
+ int result = -1;
+
+ if(dir)
+ {
+ if(dir->handle != -1)
+ {
+ result = _findclose(dir->handle);
+ }
+
+ free(dir->name);
+ free(dir);
+ }
+
+ if(result == -1) /* map all errors to EBADF */
+ {
+ errno = EBADF;
+ }
+
+ return result;
+}
+
+struct dirent *readdir(DIR *dir)
+{
+ struct dirent *result = 0;
+
+ if(dir && dir->handle != -1)
+ {
+ if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
+ {
+ result = &dir->result;
+ result->d_name = dir->info.name;
+ }
+ }
+ else
+ {
+ errno = EBADF;
+ }
+
+ return result;
+}
+
+void rewinddir(DIR *dir)
+{
+ if(dir && dir->handle != -1)
+ {
+ _findclose(dir->handle);
+ dir->handle = _findfirst(dir->name, &dir->info);
+ dir->result.d_name = 0;
+ }
+ else
+ {
+ errno = EBADF;
+ }
+}
diff --git a/lib/libdvd/libdvdread/msvc/contrib/dirent/dirent.h b/lib/libdvd/libdvdread/msvc/contrib/dirent/dirent.h
new file mode 100755
index 0000000000..28a17731ab
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/contrib/dirent/dirent.h
@@ -0,0 +1,32 @@
+/*
+
+ Declaration of POSIX directory browsing functions and types for Win32.
+
+ Kevlin Henney (mailto:kevlin@acm.org), March 1997.
+
+ Copyright Kevlin Henney, 1997. All rights reserved.
+
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose is hereby granted without fee, provided
+ that this copyright and permissions notice appear in all copies and
+ derivatives, and that no charge may be made for the software and its
+ documentation except to cover cost of distribution.
+
+*/
+
+#ifndef DIRENT_INCLUDED
+#define DIRENT_INCLUDED
+
+typedef struct DIR DIR;
+
+struct dirent
+{
+ char *d_name;
+};
+
+DIR *opendir(const char *);
+int closedir(DIR *);
+struct dirent *readdir(DIR *);
+void rewinddir(DIR *);
+
+#endif
diff --git a/lib/libdvd/libdvdread/msvc/contrib/dlfcn.c b/lib/libdvd/libdvdread/msvc/contrib/dlfcn.c
new file mode 100755
index 0000000000..3eb996bd13
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/contrib/dlfcn.c
@@ -0,0 +1,97 @@
+/*
+ * $Id: dlfcn.c 1135 2008-09-06 21:55:51Z rathann $
+ * $Name$
+ *
+ * Adopted from Apache DSO code.
+ * Portions copyright Apache Software Foundation
+ *
+ * Structures and types used to implement dlopen, dlsym, etc.
+ * on Windows 95/NT.
+ */
+#include <windows.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "dlfcn.h"
+#include "os_types.h"
+
+void *dlopen(const char *module_name, int mode)
+{
+ UINT em;
+ HINSTANCE dsoh;
+ char path[MAX_PATH], *p;
+ /* Load the module...
+ * per PR2555, the LoadLibraryEx function is very picky about slashes.
+ * Debugging on NT 4 SP 6a reveals First Chance Exception within NTDLL.
+ * LoadLibrary in the MS PSDK also reveals that it -explicitly- states
+ * that backslashes must be used.
+ *
+ * Transpose '\' for '/' in the filename.
+ */
+ (void)strncpy(path, module_name, MAX_PATH);
+ p = path;
+ while (p = strchr(p, '/'))
+ *p = '\\';
+
+ /* First assume the dso/dll's required by -this- dso are sitting in the
+ * same path or can be found in the usual places. Failing that, let's
+ * let that dso look in the apache root.
+ */
+ em = SetErrorMode(SEM_FAILCRITICALERRORS);
+ dsoh = LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (!dsoh)
+ {
+ SetLastError(0); // clear the last error
+ dsoh = LoadLibraryEx(path, NULL, 0);
+ }
+ SetErrorMode(em);
+ SetLastError(0); // clear the last error
+ return (void *)dsoh;
+}
+
+char *dlerror(void)
+{
+ int len, nErrorCode;
+ static char errstr[120];
+ /* This is -not- threadsafe code, but it's about the best we can do.
+ * mostly a potential problem for isapi modules, since LoadModule
+ * errors are handled within a single config thread.
+ */
+
+ if((nErrorCode = GetLastError()) == 0)
+ return((char *)0);
+
+ SetLastError(0); // clear the last error
+ len = snprintf(errstr, sizeof(errstr), "(%d) ", nErrorCode);
+
+ len += FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ nErrorCode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
+ (LPTSTR) errstr + len,
+ sizeof(errstr) - len,
+ NULL
+ );
+ /* FormatMessage may have appended a newline (\r\n). So remove it
+ * and use ": " instead like the Unix errors. The error may also
+ * end with a . before the return - if so, trash it.
+ */
+ if (len > 1 && errstr[len-2] == '\r' && errstr[len-1] == '\n') {
+ if (len > 2 && errstr[len-3] == '.')
+ len--;
+ errstr[len-2] = ':';
+ errstr[len-1] = ' ';
+ }
+ return errstr;
+}
+
+int dlclose(void *handle)
+{
+ return FreeLibrary(handle);
+}
+
+void *dlsym(void *handle, const char *name)
+{
+ return GetProcAddress(handle, name);
+}
diff --git a/lib/libdvd/libdvdread/msvc/contrib/getopt.c b/lib/libdvd/libdvdread/msvc/contrib/getopt.c
new file mode 100755
index 0000000000..4b3ce3db40
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/contrib/getopt.c
@@ -0,0 +1,1009 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97
+ Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library. Its master source is NOT part of
+ the C library, however. The master source lives in /gd/gnu/lib.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+ Ditto for AIX 3.2 and <stdlib.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#include <unistd.h>
+#endif /* GNU C library. */
+
+#ifdef VMS
+#include <unixlib.h>
+#if HAVE_STRING_H - 0
+#include <string.h>
+#ifdef STRNCASECMP_IN_STRINGS_H
+# include <strings.h>
+#endif
+#endif
+#endif
+
+#if defined (WIN32) && !defined (__CYGWIN32__) || defined(UNDER_CE)
+/* It's not Unix, really. See? Capital letters. */
+#include <windows.h>
+#define getpid() GetCurrentProcessId()
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.
+ When compiling libc, the _ macro is predefined. */
+#ifdef HAVE_LIBINTL_H
+#include <libintl.h>
+#define _(msgid) gettext (msgid)
+#else
+#define _(msgid) (msgid)
+#endif
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* 1003.2 says this must be 1 before any call. */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+ causes problems with re-calling getopt as programs generally don't
+ know that. */
+
+int __getopt_initialized = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return -1 with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+}
+ordering;
+
+/* Value of POSIXLY_CORRECT environment variable. */
+static char *posixly_correct;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv();
+
+static char *
+ my_index(str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it. */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+ That was relevant to code that was here before. */
+#if !defined (__STDC__) || !__STDC__
+/* gcc with -traditional declares the built-in strlen to return int,
+ and has done so at least since version 2.4.5. -- rms. */
+extern int strlen(const char *);
+
+#endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+ indicating ARGV elements that should not be considered arguments. */
+
+static const char *nonoption_flags;
+static int nonoption_flags_len;
+
+static int original_argc;
+static char *const *original_argv;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+ is valid for the getopt call we must make sure that the ARGV passed
+ to getopt is that one passed to the process. */
+static void store_args(int argc, char *const *argv) __attribute__((unused));
+ static void
+ store_args(int argc, char *const *argv)
+{
+ /* XXX This is no good solution. We should rather copy the args so
+ that we can compare them later. But we must not use malloc(3). */
+ original_argc = argc;
+ original_argv = argv;
+}
+text_set_element(__libc_subinit, store_args);
+#endif
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+#if defined (__STDC__) && __STDC__
+static void exchange(char **);
+
+#endif
+
+static void
+ exchange(argv)
+ char **argv;
+{
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = optind;
+ char *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
+
+ while (top > middle && middle > bottom)
+ {
+ if (top - middle > middle - bottom)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
+
+ /* Swap it with the top part of the top segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[top - (middle - bottom) + i];
+ argv[top - (middle - bottom) + i] = tem;
+ }
+ /* Exclude the moved bottom segment from further swapping. */
+ top -= len;
+ }
+ else
+ {
+ /* Top segment is the short one. */
+ int len = top - middle;
+ register int i;
+
+ /* Swap it with the bottom part of the bottom segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[middle + i];
+ argv[middle + i] = tem;
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made. */
+
+#if defined (__STDC__) && __STDC__
+static const char *_getopt_initialize(int, char *const *, const char *);
+
+#endif
+static const char *
+ _getopt_initialize(argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ /* Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ posixly_correct = getenv("POSIXLY_CORRECT");
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (posixly_correct != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+
+#ifdef _LIBC
+ if (posixly_correct == NULL
+ && argc == original_argc && argv == original_argv)
+ {
+ /* Bash 2.0 puts a special variable in the environment for each
+ command it runs, specifying which ARGV elements are the results of
+ file name wildcard expansion and therefore should not be
+ considered as options. */
+ char var[100];
+
+ sprintf(var, "_%d_GNU_nonoption_argv_flags_", getpid());
+ nonoption_flags = getenv(var);
+ if (nonoption_flags == NULL)
+ nonoption_flags_len = 0;
+ else
+ nonoption_flags_len = strlen(nonoption_flags);
+ }
+ else
+ nonoption_flags_len = 0;
+#endif
+
+ return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns -1.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+ _getopt_internal(argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ optarg = NULL;
+
+ if (!__getopt_initialized || optind == 0)
+ {
+ optstring = _getopt_initialize(argc, argv, optstring);
+ optind = 1; /* Don't scan ARGV[0], the program name. */
+ __getopt_initialized = 1;
+ }
+
+ /* Test whether ARGV[optind] points to a non-option argument.
+ Either it does not have option syntax, or there is an environment flag
+ from the shell indicating it is not an option. The later information
+ is only used when the used in the GNU libc. */
+#ifdef _LIBC
+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \
+ || (optind < nonoption_flags_len \
+ && nonoption_flags[optind] == '1'))
+#else
+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ /* Advance to the next ARGV-element. */
+
+ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+ moved back by the user (who may also have changed the arguments). */
+ if (last_nonopt > optind)
+ last_nonopt = optind;
+ if (first_nonopt > optind)
+ first_nonopt = optind;
+
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc && NONOPTION_P)
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* The special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp(argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return -1;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if (NONOPTION_P)
+ {
+ if (ordering == REQUIRE_ORDER)
+ return -1;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Skip the initial punctuation. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ /* Decode the current option-ARGV-element. */
+
+ /* Check whether the ARGV-element is a long option.
+
+ If long_only and the ARGV-element has the form "-f", where f is
+ a valid short option, don't consider it an abbreviated form of
+ a long option that starts with f. Otherwise there would be no
+ way to give the -f short option.
+
+ On the other hand, if there's a long option "fubar" and
+ the ARGV-element is "-fu", do consider that an abbreviation of
+ the long option, just like "--fu", and not "-f" with arg "u".
+
+ This distinction seems to be the most useful approach. */
+
+ if (longopts != NULL
+ && (argv[optind][1] == '-'
+ || (long_only && (argv[optind][2] || !my_index(optstring, argv[optind][1])))))
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = -1;
+ int option_index;
+
+ for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp(p->name, nextchar, nameend - nextchar))
+ {
+ if ((unsigned int) (nameend - nextchar)
+ == (unsigned int) strlen(p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf(stderr, _("%s: option `%s' is ambiguous\n"),
+ argv[0], argv[optind]);
+ nextchar += strlen(nextchar);
+ optind++;
+ optopt = 0;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (opterr)
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf(stderr,
+ _("%s: option `--%s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf(stderr,
+ _("%s: option `%c%s' doesn't allow an argument\n"),
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+
+ nextchar += strlen(nextchar);
+
+ optopt = pfound->val;
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf(stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[optind - 1]);
+ nextchar += strlen(nextchar);
+ optopt = pfound->val;
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen(nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+ || my_index(optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf(stderr, _("%s: unrecognized option `--%s'\n"),
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf(stderr, _("%s: unrecognized option `%c%s'\n"),
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ optopt = 0;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next short option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index(optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+ if (posixly_correct)
+ /* 1003.2 specifies the format of this message. */
+ fprintf(stderr, _("%s: illegal option -- %c\n"),
+ argv[0], c);
+ else
+ fprintf(stderr, _("%s: invalid option -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ return '?';
+ }
+ /* Convenience. Treat POSIX -W foo same as long option --foo */
+ if (temp[0] == 'W' && temp[1] == ';')
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = 0;
+ int option_index;
+
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf(stderr, _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ return c;
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+
+ /* optarg is now the argument, see if it's in the
+ table of longopts. */
+
+ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp(p->name, nextchar, nameend - nextchar))
+ {
+ if ((unsigned int) (nameend - nextchar) == strlen(p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf(stderr, _("%s: option `-W %s' is ambiguous\n"),
+ argv[0], argv[optind]);
+ nextchar += strlen(nextchar);
+ optind++;
+ return '?';
+ }
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (opterr)
+ fprintf(stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+
+ nextchar += strlen(nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf(stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[optind - 1]);
+ nextchar += strlen(nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen(nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ nextchar = NULL;
+ return 'W'; /* Let the application handle it. */
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = NULL;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf(stderr,
+ _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+ getopt(argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal(argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* Not ELIDE_CODE. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+ main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt(argc, argv, "abc:d:0123456789");
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf("option %c\n", c);
+ break;
+
+ case 'a':
+ printf("option a\n");
+ break;
+
+ case 'b':
+ printf("option b\n");
+ break;
+
+ case 'c':
+ printf("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf("%s ", argv[optind++]);
+ printf("\n");
+ }
+
+ exit(0);
+}
+
+#endif /* TEST */
diff --git a/lib/libdvd/libdvdread/msvc/contrib/timer/timer.c b/lib/libdvd/libdvdread/msvc/contrib/timer/timer.c
new file mode 100755
index 0000000000..60efe86db9
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/contrib/timer/timer.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2000-2001 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine 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.
+ *
+ * xine 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
+ *
+ * WIN32 PORT,
+ * by Matthew Grooms <elon@altavista.com>
+ *
+ * timer.c - Missing unix timer functions
+ *
+ */
+
+#include "stdio.h"
+#include "timer.h"
+
+/*
+ this function returns somewhat
+ accurate unix time with the data
+ accurate to the first call to get
+ of day and the resolution accurate
+ to ~ miliseconds.
+*/
+
+static time_t startseconds = 0;
+
+int gettimeofday( struct timeval *tp, struct timezone *tzp )
+{
+ MMTIME mmtime;
+
+ // clock() returns time in miliseconds
+
+ if( !startseconds )
+ startseconds = time( 0 );
+
+ timeGetSystemTime( &mmtime, sizeof( mmtime ) );
+
+ tp->tv_sec = ( mmtime.u.ms / 1000 ) + startseconds;
+ tp->tv_usec = ( mmtime.u.ms % 1000 ) * 1000;
+
+ return 0;
+};
+
+/*
+ These functions are designed to mimick
+ a subset of itimer for use with the
+ alarm signal on win32. This is just
+ enough for xine to work.
+*/
+
+static HANDLE sigalarm = 0;
+
+int setitimer( int which, struct itimerval * value, struct itimerval *ovalue )
+{
+ long int miliseconds;
+
+ if( !sigalarm )
+ sigalarm = CreateEvent( 0, FALSE, TRUE, "SIGALARM" );
+
+ miliseconds = value->it_value.tv_usec / 1000;
+
+ timeSetEvent( miliseconds, 0, ( LPTIMECALLBACK ) sigalarm, 0, TIME_PERIODIC | TIME_CALLBACK_EVENT_PULSE );
+
+ return 0;
+}
+
+/*
+ Wait for sigalarm to wake the thread
+*/
+
+int pause( void )
+{
+ WaitForSingleObject( sigalarm, INFINITE );
+
+ return 0;
+}
+
+int nanosleep( const struct timespec * rqtp, struct timespec * rmtp )
+{
+ Sleep( rqtp->tv_nsec / 1000000 );
+
+ return 0;
+}
+
+unsigned int sleep( unsigned int seconds )
+{
+ Sleep( seconds * 1000 );
+ return 0;
+} \ No newline at end of file
diff --git a/lib/libdvd/libdvdread/msvc/contrib/timer/timer.h b/lib/libdvd/libdvdread/msvc/contrib/timer/timer.h
new file mode 100755
index 0000000000..efab6f4e18
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/contrib/timer/timer.h
@@ -0,0 +1,39 @@
+#include <time.h>
+#include <winsock.h>
+#include "pthread.h"
+
+#ifndef _ITIMER_
+#define _ITIMER_
+
+#define ITIMER_REAL 0
+#define ITIMER_VIRTUAL 1
+
+// time reference
+// ----------------------------------
+//
+// 1,000 milliseconds / sec
+// 1,000,000 microseconds / sec
+// 1,000,000,000 nanoseconds / sec
+//
+// timeval.time_sec = seconds
+// timeval.time_usec = microseconds
+
+struct itimerval
+{
+ struct timeval it_interval; /* timer interval */
+ struct timeval it_value; /* current value */
+};
+
+struct timezone {
+ int tz_minuteswest; /* minutes west of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+};
+
+int gettimeofday( struct timeval *tp, struct timezone *tzp );
+int setitimer( int which, struct itimerval * value, struct itimerval *ovalue );
+int pause( void );
+
+unsigned int sleep( unsigned int seconds );
+int nanosleep( const struct timespec *rqtp, struct timespec *rmtp );
+
+#endif \ No newline at end of file
diff --git a/lib/libdvd/libdvdread/msvc/ifo_dump.dsp b/lib/libdvd/libdvdread/msvc/ifo_dump.dsp
new file mode 100755
index 0000000000..fc39837296
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/ifo_dump.dsp
@@ -0,0 +1,110 @@
+# Microsoft Developer Studio Project File - Name="ifo_dump" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=ifo_dump - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "ifo_dump.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "ifo_dump.mak" CFG="ifo_dump - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "ifo_dump - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "ifo_dump - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "ifo_dump - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "." /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "ifo_dump - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "ifo_dump___Win32_Debug"
+# PROP BASE Intermediate_Dir "ifo_dump___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug\ifo_dump"
+# PROP Intermediate_Dir "Debug\ifo_dump"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "include" /I "." /I "include/pthreads" /I "install/include" /I ".." /I "../src" /I "contrib/timer" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "DVDNAV_COMPILE" /FR /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/bin/ifo_dump.exe" /pdbtype:sept
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "ifo_dump - Win32 Release"
+# Name "ifo_dump - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\src\ifo_dump.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\ifo_print.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\vmcmd.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/lib/libdvd/libdvdread/msvc/include/dlfcn.h b/lib/libdvd/libdvdread/msvc/include/dlfcn.h
new file mode 100755
index 0000000000..7a2416c843
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/include/dlfcn.h
@@ -0,0 +1,23 @@
+#ifndef __DLFCN_H__
+# define __DLFCN_H__
+/*
+ * $Id: dlfcn.h 1135 2008-09-06 21:55:51Z rathann $
+ * $Name$
+ *
+ *
+ */
+extern void *dlopen (const char *file, int mode);
+extern int dlclose (void *handle);
+extern void *dlsym (void * handle, const char * name);
+extern char *dlerror (void);
+
+/* These don't mean anything on windows */
+#define RTLD_NEXT ((void *) -1l)
+#define RTLD_DEFAULT ((void *) 0)
+#define RTLD_LAZY -1
+#define RTLD_NOW -1
+#define RTLD_BINDING_MASK -1
+#define RTLD_NOLOAD -1
+#define RTLD_GLOBAL -1
+
+#endif /* __DLFCN_H__ */
diff --git a/lib/libdvd/libdvdread/msvc/include/dvdnav_internal.h b/lib/libdvd/libdvdread/msvc/include/dvdnav_internal.h
new file mode 100644
index 0000000000..cee785472e
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/include/dvdnav_internal.h
@@ -0,0 +1,185 @@
+/* !! DO NO EDIT THIS FILE, it is automatically generated */
+/*
+ * Copyright (C) 2001 Rich Wareham <richwareham@users.sourceforge.net>
+ *
+ * This file is part of libdvdnav, a DVD navigation library.
+ *
+ * libdvdnav 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.
+ *
+ * libdvdnav 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
+ *
+ * $Id: dvdnav_internal.h 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+#ifndef DVDNAV_INTERNAL_H_INCLUDED
+#define DVDNAV_INTERNAL_H_INCLUDED
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+#include <pthread.h>
+
+#undef WORDS_BIGENDIAN
+
+#include "dvd_reader.h"
+#include "ifo_read.h"
+#include "ifo_types.h"
+
+/* Uncomment for VM command tracing */
+/* #define TRACE */
+
+#include "decoder.h"
+#include "dvdnav.h"
+#include "vm.h"
+#include "vmcmd.h"
+
+/* where should libdvdnav write its messages (stdout/stderr) */
+#define MSG_OUT stdout
+
+/* Maximum length of an error string */
+#define MAX_ERR_LEN 255
+
+/* Use the POSIX PATH_MAX if available */
+#ifdef PATH_MAX
+#define MAX_PATH_LEN PATH_MAX
+#else
+#define MAX_PATH_LEN 255 /* Arbitrary */
+#endif
+
+#ifndef DVD_VIDEO_LB_LEN
+#define DVD_VIDEO_LB_LEN 2048
+#endif
+
+typedef struct read_cache_s read_cache_t;
+
+/*
+ * These are defined here because they are
+ * not in ifo_types.h, they maybe one day
+ */
+
+#ifndef audio_status_t
+typedef struct {
+#ifdef WORDS_BIGENDIAN
+ unsigned int available : 1;
+ unsigned int zero1 : 4;
+ unsigned int stream_number : 3;
+ uint8_t zero2;
+#else
+ uint8_t zero2;
+ unsigned int stream_number : 3;
+ unsigned int zero1 : 4;
+ unsigned int available : 1;
+#endif
+} ATTRIBUTE_PACKED audio_status_t;
+#endif
+
+#ifndef spu_status_t
+typedef struct {
+#ifdef WORDS_BIGENDIAN
+ unsigned int available : 1;
+ unsigned int zero1 : 2;
+ unsigned int stream_number_4_3 : 5;
+ unsigned int zero2 : 3;
+ unsigned int stream_number_wide : 5;
+ unsigned int zero3 : 3;
+ unsigned int stream_number_letterbox : 5;
+ unsigned int zero4 : 3;
+ unsigned int stream_number_pan_scan : 5;
+#else
+ unsigned int stream_number_pan_scan : 5;
+ unsigned int zero4 : 3;
+ unsigned int stream_number_letterbox : 5;
+ unsigned int zero3 : 3;
+ unsigned int stream_number_wide : 5;
+ unsigned int zero2 : 3;
+ unsigned int stream_number_4_3 : 5;
+ unsigned int zero1 : 2;
+ unsigned int available : 1;
+#endif
+} ATTRIBUTE_PACKED spu_status_t;
+#endif
+
+typedef struct dvdnav_vobu_s {
+ int32_t vobu_start; /* Logical Absolute. MAX needed is 0x300000 */
+ int32_t vobu_length;
+ int32_t blockN; /* Relative offset */
+ int32_t vobu_next; /* Relative offset */
+} dvdnav_vobu_t;
+
+/** The main DVDNAV type **/
+
+struct dvdnav_s {
+ /* General data */
+ char path[MAX_PATH_LEN]; /* Path to DVD device/dir */
+ dvd_file_t *file; /* Currently opened file */
+ int open_vtsN; /* The domain and number of the... */
+ int open_domain; /* ..currently opened VOB */
+
+ /* Position data */
+ vm_position_t position_next;
+ vm_position_t position_current;
+ dvdnav_vobu_t vobu;
+
+ /* NAV data */
+ pci_t pci;
+ dsi_t dsi;
+ uint32_t last_cmd_nav_lbn; /* detects when a command is issued on an already left NAV */
+
+ /* Flags */
+ int skip_still; /* Set when skipping a still */
+ int sync_wait; /* applications should wait till they are in sync with us */
+ int sync_wait_skip; /* Set when skipping wait state */
+ int spu_clut_changed; /* The SPU CLUT changed */
+ int started; /* vm_start has been called? */
+ int use_read_ahead; /* 1 - use read-ahead cache, 0 - don't */
+ int pgc_based; /* positioning works PGC based instead of PG based */
+
+ /* VM */
+ vm_t *vm;
+ pthread_mutex_t vm_lock;
+
+ /* Read-ahead cache */
+ read_cache_t *cache;
+
+ /* Errors */
+ char err_str[MAX_ERR_LEN];
+};
+
+/** USEFUL MACROS **/
+
+#ifdef __GNUC__
+#define printerrf(format, args...) snprintf(this->err_str, MAX_ERR_LEN, format, ## args);
+#else
+#ifdef _MSC_VER
+#define printerrf(str) snprintf(this->err_str, MAX_ERR_LEN, str);
+#else
+#define printerrf(...) snprintf(this->err_str, MAX_ERR_LEN, __VA_ARGS__);
+#endif /* WIN32 */
+#endif
+#define printerr(str) strncpy(this->err_str, str, MAX_ERR_LEN);
+
+/* Save my typing */
+#define S_ERR DVDNAV_STATUS_ERR
+
+#ifndef _MSC_VER
+#define S_OK DVDNAV_STATUS_OK
+#endif /* MSC_VER */
+
+#endif /* DVDNAV_INTERNAL_H_INCLUDED */
diff --git a/lib/libdvd/libdvdread/msvc/include/getopt.h b/lib/libdvd/libdvdread/msvc/include/getopt.h
new file mode 100755
index 0000000000..2fa12f7baf
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/include/getopt.h
@@ -0,0 +1,134 @@
+/* Declarations for getopt.
+ Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library. Its master source is NOT part of
+ the C library, however. The master source lives in /gd/gnu/lib.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+ extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+ extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+ extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+ extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+ struct option
+ {
+#if defined (__STDC__) && __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+ };
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if defined (__STDC__) && __STDC__
+#ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+ extern int getopt(int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+ extern int getopt();
+#endif /* __GNU_LIBRARY__ */
+ extern int getopt_long(int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+ extern int getopt_long_only(int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+ extern int _getopt_internal(int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+ extern int getopt();
+ extern int getopt_long();
+ extern int getopt_long_only();
+
+ extern int _getopt_internal();
+#endif /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/lib/libdvd/libdvdread/msvc/include/inttypes.h b/lib/libdvd/libdvdread/msvc/include/inttypes.h
new file mode 100755
index 0000000000..55fd6a33e0
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/include/inttypes.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2000-2001 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine 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.
+ *
+ * xine 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
+ *
+ * WIN32 PORT,
+ * by Matthew Grooms <elon@altavista.com>
+ *
+ * inttypes.h - Standard integer definitions.
+ *
+ */
+
+#ifndef _SYS_INTTYPES_H_
+#define _SYS_INTTYPES_H_
+
+#include <config.h>
+
+#endif
diff --git a/lib/libdvd/libdvdread/msvc/include/os_types.h b/lib/libdvd/libdvdread/msvc/include/os_types.h
new file mode 100755
index 0000000000..69f05a8d93
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/include/os_types.h
@@ -0,0 +1,27 @@
+#ifndef __OS_TYPES_H__
+#define __OS_TYPES_H__
+/*
+ * $Id: os_types.h 1135 2008-09-06 21:55:51Z rathann $
+ * $Name$
+ *
+ * win32 types
+ * 04 Sept 2001 - Chris Wolf create.
+ */
+
+typedef unsigned char uint_8;
+typedef unsigned short uint_16;
+typedef unsigned int uint_32;
+typedef signed char sint_32;
+typedef signed short sint_16;
+typedef signed int sint_8;
+
+#define snprintf _snprintf
+#define M_PI 3.14159265358979323846 /* pi */
+#define DLLENTRY __declspec(dllexport)
+
+ // Temporarily hardcode this location
+#define AO_PLUGIN_PATH "c:\\Program Files\\Common Files\\Xiphophorus\\ao"
+
+#define SHARED_LIB_EXT ".dll"
+
+#endif /* __OS_TYPES_H__ */
diff --git a/lib/libdvd/libdvdread/msvc/include/pthreads/pthread.h b/lib/libdvd/libdvdread/msvc/include/pthreads/pthread.h
new file mode 100755
index 0000000000..7b89ca8401
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/include/pthreads/pthread.h
@@ -0,0 +1,1077 @@
+/* This is the POSIX thread API (POSIX 1003).
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#if !defined( PTHREAD_H )
+#define PTHREAD_H
+
+#ifdef _UWIN
+# define HAVE_STRUCT_TIMESPEC 1
+# define HAVE_SIGNAL_H 1
+# undef HAVE_CONFIG_H
+# pragma comment(lib, "pthread")
+#endif
+
+/*
+ * -------------------------------------------------------------
+ *
+ *
+ * Module: pthread.h
+ *
+ * Purpose:
+ * Provides an implementation of PThreads based upon the
+ * standard:
+ *
+ * POSIX 1003.1c-1995 (POSIX.1c)
+ *
+ * Parts of the implementation also comply with the
+ * Open Group Unix 98 specification in order to enhance
+ * code portability between Windows, various commercial
+ * Unix implementations, and Linux.
+ *
+ * Authors:
+ * There have been many contributors to this library.
+ * The initial implementation was contributed by
+ * John Bossom, and several others have provided major
+ * sections or revisions of parts of the implementation.
+ * Often significant effort has been contributed to
+ * find and fix important bugs and other problems to
+ * improve the reliability of the library, which sometimes
+ * is not reflected in the amount of code which changed as
+ * result.
+ * As much as possible, the contributors are acknowledged
+ * in the ChangeLog file in the source code distribution
+ * where their changes are noted in detail.
+ *
+ * Contributors are listed in the MAINTAINERS file.
+ *
+ * As usual, all bouquets go to the contributors, and all
+ * brickbats go to the project maintainer.
+ *
+ * Maintainer:
+ * The code base for this project is coordinated and
+ * eventually pre-tested, packaged, and made available by
+ *
+ * Ross Johnson <rpj@ise.canberra.edu.au>
+ *
+ * QA Testers:
+ * Ultimately, the library is tested in the real world by
+ * a host of competent and demanding scientists and
+ * engineers who report bugs and/or provide solutions
+ * which are then fixed or incorporated into subsequent
+ * versions of the library. Each time a bug is fixed, a
+ * test case is written to prove the fix and ensure
+ * that later changes to the code don't reintroduce the
+ * same error. The number of test cases is slowly growing
+ * and therefore so is the code reliability.
+ *
+ * Compliance:
+ * See the file ANNOUNCE for the list of implemented
+ * and not-implemented routines and defined options.
+ * Of course, these are all defined is this file as well.
+ *
+ * Web site:
+ * The source code and other information about this library
+ * are available from
+ *
+ * http://sources.redhat.com/pthreads-win32/
+ *
+ * -------------------------------------------------------------
+ */
+
+/*
+ * -----------------
+ * autoconf switches
+ * -----------------
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <windows.h>
+
+#ifndef NEED_FTIME
+#include <time.h>
+#else /* NEED_FTIME */
+/* use native WIN32 time API */
+#endif /* NEED_FTIME */
+
+#if HAVE_SIGNAL_H
+#include <signal.h>
+#endif /* HAVE_SIGNAL_H */
+
+#include <setjmp.h>
+
+#ifndef HAVE_STRUCT_TIMESPEC
+struct timespec {
+ long tv_sec;
+ long tv_nsec;
+};
+#endif /* HAVE_STRUCT_TIMESPEC */
+
+#ifndef SIG_BLOCK
+#define SIG_BLOCK 0
+#endif /* SIG_BLOCK */
+
+#ifndef SIG_UNBLOCK
+#define SIG_UNBLOCK 1
+#endif /* SIG_UNBLOCK */
+
+#ifndef SIG_SETMASK
+#define SIG_SETMASK 2
+#endif /* SIG_SETMASK */
+
+/*
+ * note: ETIMEDOUT is correctly defined in winsock.h
+ */
+#include <winsock.h>
+
+#ifdef NEED_ERRNO
+# include "need_errno.h"
+#else
+# include <errno.h>
+#endif
+
+#include <sched.h>
+
+/*
+ * In case ETIMEDOUT hasn't been defined above somehow.
+ */
+#ifndef ETIMEDOUT
+# define ETIMEDOUT 10060 /* This is the value in winsock.h. */
+#endif
+
+/*
+ * Several systems don't define ENOTSUP. If not, we use
+ * the same value as Solaris.
+ */
+#ifndef ENOTSUP
+# define ENOTSUP 48
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * -------------------------------------------------------------
+ *
+ * POSIX 1003.1c-1995 Options
+ * ===========================
+ *
+ * _POSIX_THREADS (set)
+ * If set, you can use threads
+ *
+ * _POSIX_THREAD_ATTR_STACKSIZE (set)
+ * If set, you can control the size of a thread's
+ * stack
+ * pthread_attr_getstacksize
+ * pthread_attr_setstacksize
+ *
+ * _POSIX_THREAD_ATTR_STACKADDR (not set)
+ * If set, you can allocate and control a thread's
+ * stack. If not supported, the following functions
+ * will return ENOSYS, indicating they are not
+ * supported:
+ * pthread_attr_getstackaddr
+ * pthread_attr_setstackaddr
+ *
+ * _POSIX_THREAD_PRIORITY_SCHEDULING (set)
+ * If set, you can use realtime scheduling.
+ * Indicates the availability of:
+ * pthread_attr_getinheritsched
+ * pthread_attr_getschedparam
+ * pthread_attr_getschedpolicy
+ * pthread_attr_getscope
+ * pthread_attr_setinheritsched
+ * pthread_attr_setschedparam
+ * pthread_attr_setschedpolicy
+ * pthread_attr_setscope
+ * pthread_getschedparam
+ * pthread_setschedparam
+ * sched_get_priority_max
+ * sched_get_priority_min
+ * sched_rr_set_interval
+ *
+ * _POSIX_THREAD_PRIO_INHERIT (not set)
+ * If set, you can create priority inheritance
+ * mutexes.
+ * pthread_mutexattr_getprotocol +
+ * pthread_mutexattr_setprotocol +
+ *
+ * _POSIX_THREAD_PRIO_PROTECT (not set)
+ * If set, you can create priority ceiling mutexes
+ * Indicates the availability of:
+ * pthread_mutex_getprioceiling
+ * pthread_mutex_setprioceiling
+ * pthread_mutexattr_getprioceiling
+ * pthread_mutexattr_getprotocol +
+ * pthread_mutexattr_setprioceiling
+ * pthread_mutexattr_setprotocol +
+ *
+ * _POSIX_THREAD_PROCESS_SHARED (not set)
+ * If set, you can create mutexes and condition
+ * variables that can be shared with another
+ * process.If set, indicates the availability
+ * of:
+ * pthread_mutexattr_getpshared
+ * pthread_mutexattr_setpshared
+ * pthread_condattr_getpshared
+ * pthread_condattr_setpshared
+ *
+ * _POSIX_THREAD_SAFE_FUNCTIONS (set)
+ * If set you can use the special *_r library
+ * functions that provide thread-safe behaviour
+ *
+ * + These functions provide both 'inherit' and/or
+ * 'protect' protocol, based upon these macro
+ * settings.
+ *
+ * POSIX 1003.1c-1995 Limits
+ * ===========================
+ *
+ * PTHREAD_DESTRUCTOR_ITERATIONS
+ * Maximum number of attempts to destroy
+ * a thread's thread-specific data on
+ * termination (must be at least 4)
+ *
+ * PTHREAD_KEYS_MAX
+ * Maximum number of thread-specific data keys
+ * available per process (must be at least 128)
+ *
+ * PTHREAD_STACK_MIN
+ * Minimum supported stack size for a thread
+ *
+ * PTHREAD_THREADS_MAX
+ * Maximum number of threads supported per
+ * process (must be at least 64).
+ *
+ *
+ * POSIX 1003.1j/D10-1999 Options
+ * ==============================
+ *
+ * _POSIX_READER_WRITER_LOCKS (set)
+ * If set, you can use read/write locks
+ *
+ * _POSIX_SPIN_LOCKS (set)
+ * If set, you can use spin locks
+ *
+ * _POSIX_BARRIERS (set)
+ * If set, you can use barriers
+ *
+ * -------------------------------------------------------------
+ */
+
+/*
+ * POSIX Options
+ */
+#ifndef _POSIX_THREADS
+#define _POSIX_THREADS
+#endif
+
+#ifndef _POSIX_READER_WRITER_LOCKS
+#define _POSIX_READER_WRITER_LOCKS
+#endif
+
+#ifndef _POSIX_SPIN_LOCKS
+#define _POSIX_SPIN_LOCKS
+#endif
+
+#ifndef _POSIX_BARRIERS
+#define _POSIX_BARRIERS
+#endif
+
+#define _POSIX_THREAD_SAFE_FUNCTIONS
+#define _POSIX_THREAD_ATTR_STACKSIZE
+#define _POSIX_THREAD_PRIORITY_SCHEDULING
+
+#if defined( KLUDGE )
+/*
+ * The following are not supported
+ */
+#define _POSIX_THREAD_ATTR_STACKADDR
+#define _POSIX_THREAD_PRIO_INHERIT
+#define _POSIX_THREAD_PRIO_PROTECT
+#define _POSIX_THREAD_PROCESS_SHARED
+
+#endif /* KLUDGE */
+
+/*
+ * POSIX Limits
+ *
+ * PTHREAD_DESTRUCTOR_ITERATIONS
+ * Standard states this must be at least
+ * 4.
+ *
+ * PTHREAD_KEYS_MAX
+ * WIN32 permits only 64 TLS keys per process.
+ * This limitation could be worked around by
+ * simply simulating keys.
+ *
+ * PTHREADS_STACK_MIN
+ * POSIX specifies 0 which is also the value WIN32
+ * interprets as allowing the system to
+ * set the size to that of the main thread. The
+ * maximum stack size in Win32 is 1Meg. WIN32
+ * allocates more stack as required up to the 1Meg
+ * limit.
+ *
+ * PTHREAD_THREADS_MAX
+ * Not documented by WIN32. Wrote a test program
+ * that kept creating threads until it failed
+ * revealed this approximate number.
+ *
+ */
+#define PTHREAD_DESTRUCTOR_ITERATIONS 4
+#define PTHREAD_KEYS_MAX 64
+#define PTHREAD_STACK_MIN 0
+#define PTHREAD_THREADS_MAX 2019
+
+
+#ifdef _UWIN
+# include <sys/types.h>
+#else
+typedef struct pthread_t_ *pthread_t;
+typedef struct pthread_attr_t_ *pthread_attr_t;
+typedef struct pthread_once_t_ pthread_once_t;
+typedef struct pthread_key_t_ *pthread_key_t;
+typedef struct pthread_mutex_t_ *pthread_mutex_t;
+typedef struct pthread_mutexattr_t_ *pthread_mutexattr_t;
+typedef struct pthread_cond_t_ *pthread_cond_t;
+typedef struct pthread_condattr_t_ *pthread_condattr_t;
+#endif
+typedef struct pthread_rwlock_t_ *pthread_rwlock_t;
+typedef struct pthread_rwlockattr_t_ *pthread_rwlockattr_t;
+typedef struct pthread_spinlock_t_ *pthread_spinlock_t;
+typedef struct pthread_barrier_t_ *pthread_barrier_t;
+typedef struct pthread_barrierattr_t_ *pthread_barrierattr_t;
+
+/*
+ * ====================
+ * ====================
+ * POSIX Threads
+ * ====================
+ * ====================
+ */
+
+enum {
+/*
+ * pthread_attr_{get,set}detachstate
+ */
+ PTHREAD_CREATE_JOINABLE = 0, /* Default */
+ PTHREAD_CREATE_DETACHED = 1,
+
+/*
+ * pthread_attr_{get,set}inheritsched
+ */
+ PTHREAD_INHERIT_SCHED = 0,
+ PTHREAD_EXPLICIT_SCHED = 1, /* Default */
+
+/*
+ * pthread_{get,set}scope
+ */
+ PTHREAD_SCOPE_PROCESS = 0,
+ PTHREAD_SCOPE_SYSTEM = 1, /* Default */
+
+/*
+ * pthread_setcancelstate paramters
+ */
+ PTHREAD_CANCEL_ENABLE = 0, /* Default */
+ PTHREAD_CANCEL_DISABLE = 1,
+
+/*
+ * pthread_setcanceltype parameters
+ */
+ PTHREAD_CANCEL_ASYNCHRONOUS = 0,
+ PTHREAD_CANCEL_DEFERRED = 1, /* Default */
+
+/*
+ * pthread_mutexattr_{get,set}pshared
+ * pthread_condattr_{get,set}pshared
+ */
+ PTHREAD_PROCESS_PRIVATE = 0,
+ PTHREAD_PROCESS_SHARED = 1,
+
+/*
+ * pthread_barrier_wait
+ */
+ PTHREAD_BARRIER_SERIAL_THREAD = -1
+};
+
+/*
+ * ====================
+ * ====================
+ * Cancelation
+ * ====================
+ * ====================
+ */
+#define PTHREAD_CANCELED ((void *) -1)
+
+
+/*
+ * ====================
+ * ====================
+ * Once Key
+ * ====================
+ * ====================
+ */
+#define PTHREAD_ONCE_INIT { FALSE, -1 }
+
+struct pthread_once_t_
+{
+ int done; /* indicates if user function executed */
+ long started; /* First thread to increment this value */
+ /* to zero executes the user function */
+};
+
+
+/*
+ * ====================
+ * ====================
+ * Object initialisers
+ * ====================
+ * ====================
+ */
+#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) -1)
+
+#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) -1)
+
+#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) -1)
+
+#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t) -1)
+
+enum
+{
+ PTHREAD_MUTEX_FAST_NP,
+ PTHREAD_MUTEX_RECURSIVE_NP,
+ PTHREAD_MUTEX_ERRORCHECK_NP,
+ PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP,
+ PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
+ PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
+ PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
+};
+
+
+/* There are three implementations of cancel cleanup.
+ * Note that pthread.h is included in both application
+ * compilation units and also internally for the library.
+ * The code here and within the library aims to work
+ * for all reasonable combinations of environments.
+ *
+ * The three implementations are:
+ *
+ * WIN32 SEH
+ * C
+ * C++
+ *
+ * Please note that exiting a push/pop block via
+ * "return", "exit", "break", or "continue" will
+ * lead to different behaviour amongst applications
+ * depending upon whether the library was built
+ * using SEH, C++, or C. For example, a library built
+ * with SEH will call the cleanup routine, while both
+ * C++ and C built versions will not.
+ */
+
+/*
+ * define defaults for cleanup code
+ */
+#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C )
+
+#if defined(_MSC_VER)
+#define __CLEANUP_SEH
+#elif defined(__cplusplus)
+#define __CLEANUP_CXX
+#else
+#define __CLEANUP_C
+#endif
+
+#endif
+
+#if defined( __CLEANUP_SEH ) && defined(__GNUC__)
+#error ERROR [__FILE__, line __LINE__]: GNUC does not support SEH.
+#endif
+
+typedef struct ptw32_cleanup_t ptw32_cleanup_t;
+typedef void (__cdecl *ptw32_cleanup_callback_t)(void *);
+
+struct ptw32_cleanup_t
+{
+ ptw32_cleanup_callback_t routine;
+ void *arg;
+ struct ptw32_cleanup_t *prev;
+};
+
+#ifdef __CLEANUP_SEH
+ /*
+ * WIN32 SEH version of cancel cleanup.
+ */
+
+#define pthread_cleanup_push( _rout, _arg ) \
+ { \
+ ptw32_cleanup_t _cleanup; \
+ \
+ _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \
+ _cleanup.arg = (_arg); \
+ __try \
+ { \
+
+#define pthread_cleanup_pop( _execute ) \
+ } \
+ __finally \
+ { \
+ if( _execute || AbnormalTermination()) \
+ { \
+ (*(_cleanup.routine))( _cleanup.arg ); \
+ } \
+ } \
+ }
+
+#else /* __CLEANUP_SEH */
+
+#ifdef __CLEANUP_C
+
+ /*
+ * C implementation of PThreads cancel cleanup
+ */
+
+#define pthread_cleanup_push( _rout, _arg ) \
+ { \
+ ptw32_cleanup_t _cleanup; \
+ \
+ ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \
+
+#define pthread_cleanup_pop( _execute ) \
+ (void) ptw32_pop_cleanup( _execute ); \
+ }
+
+#else /* __CLEANUP_C */
+
+#ifdef __CLEANUP_CXX
+
+ /*
+ * C++ version of cancel cleanup.
+ * - John E. Bossom.
+ */
+
+ class PThreadCleanup {
+ /*
+ * PThreadCleanup
+ *
+ * Purpose
+ * This class is a C++ helper class that is
+ * used to implement pthread_cleanup_push/
+ * pthread_cleanup_pop.
+ * The destructor of this class automatically
+ * pops the pushed cleanup routine regardless
+ * of how the code exits the scope
+ * (i.e. such as by an exception)
+ */
+ ptw32_cleanup_callback_t cleanUpRout;
+ void * obj;
+ int executeIt;
+
+ public:
+ PThreadCleanup() :
+ cleanUpRout( NULL ),
+ obj( NULL ),
+ executeIt( 0 )
+ /*
+ * No cleanup performed
+ */
+ {
+ }
+
+ PThreadCleanup(
+ ptw32_cleanup_callback_t routine,
+ void * arg ) :
+ cleanUpRout( routine ),
+ obj( arg ),
+ executeIt( 1 )
+ /*
+ * Registers a cleanup routine for 'arg'
+ */
+ {
+ }
+
+ ~PThreadCleanup()
+ {
+ if ( executeIt && ((void *) cleanUpRout != NULL) )
+ {
+ (void) (*cleanUpRout)( obj );
+ }
+ }
+
+ void execute( int exec )
+ {
+ executeIt = exec;
+ }
+ };
+
+ /*
+ * C++ implementation of PThreads cancel cleanup;
+ * This implementation takes advantage of a helper
+ * class who's destructor automatically calls the
+ * cleanup routine if we exit our scope weirdly
+ */
+#define pthread_cleanup_push( _rout, _arg ) \
+ { \
+ PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \
+ (void *) (_arg) );
+
+#define pthread_cleanup_pop( _execute ) \
+ cleanup.execute( _execute ); \
+ }
+
+#else
+
+#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined.
+
+#endif /* __CLEANUP_CXX */
+
+#endif /* __CLEANUP_C */
+
+#endif /* __CLEANUP_SEH */
+
+/*
+ * ===============
+ * ===============
+ * Methods
+ * ===============
+ * ===============
+ */
+
+/*
+ * PThread Attribute Functions
+ */
+int pthread_attr_init (pthread_attr_t * attr);
+
+int pthread_attr_destroy (pthread_attr_t * attr);
+
+int pthread_attr_getdetachstate (const pthread_attr_t * attr,
+ int *detachstate);
+
+int pthread_attr_getstackaddr (const pthread_attr_t * attr,
+ void **stackaddr);
+
+int pthread_attr_getstacksize (const pthread_attr_t * attr,
+ size_t * stacksize);
+
+int pthread_attr_setdetachstate (pthread_attr_t * attr,
+ int detachstate);
+
+int pthread_attr_setstackaddr (pthread_attr_t * attr,
+ void *stackaddr);
+
+int pthread_attr_setstacksize (pthread_attr_t * attr,
+ size_t stacksize);
+
+int pthread_attr_getschedparam (const pthread_attr_t *attr,
+ struct sched_param *param);
+
+int pthread_attr_setschedparam (pthread_attr_t *attr,
+ const struct sched_param *param);
+
+int pthread_attr_setschedpolicy (pthread_attr_t *,
+ int);
+
+int pthread_attr_getschedpolicy (pthread_attr_t *,
+ int *);
+
+int pthread_attr_setinheritsched(pthread_attr_t * attr,
+ int inheritsched);
+
+int pthread_attr_getinheritsched(pthread_attr_t * attr,
+ int * inheritsched);
+
+int pthread_attr_setscope (pthread_attr_t *,
+ int);
+
+int pthread_attr_getscope (const pthread_attr_t *,
+ int *);
+
+/*
+ * PThread Functions
+ */
+int pthread_create (pthread_t * tid,
+ const pthread_attr_t * attr,
+ void *(*start) (void *),
+ void *arg);
+
+int pthread_detach (pthread_t tid);
+
+int pthread_equal (pthread_t t1,
+ pthread_t t2);
+
+void pthread_exit (void *value_ptr);
+
+int pthread_join (pthread_t thread,
+ void **value_ptr);
+
+pthread_t pthread_self (void);
+
+int pthread_cancel (pthread_t thread);
+
+int pthread_setcancelstate (int state,
+ int *oldstate);
+
+int pthread_setcanceltype (int type,
+ int *oldtype);
+
+void pthread_testcancel (void);
+
+int pthread_once (pthread_once_t * once_control,
+ void (*init_routine) (void));
+
+ptw32_cleanup_t *ptw32_pop_cleanup (int execute);
+
+void ptw32_push_cleanup (ptw32_cleanup_t * cleanup,
+ void (*routine) (void *),
+ void *arg);
+
+/*
+ * Thread Specific Data Functions
+ */
+int pthread_key_create (pthread_key_t * key,
+ void (*destructor) (void *));
+
+int pthread_key_delete (pthread_key_t key);
+
+int pthread_setspecific (pthread_key_t key,
+ const void *value);
+
+void *pthread_getspecific (pthread_key_t key);
+
+
+/*
+ * Mutex Attribute Functions
+ */
+int pthread_mutexattr_init (pthread_mutexattr_t * attr);
+
+int pthread_mutexattr_destroy (pthread_mutexattr_t * attr);
+
+int pthread_mutexattr_getpshared (const pthread_mutexattr_t
+ * attr,
+ int *pshared);
+
+int pthread_mutexattr_setpshared (pthread_mutexattr_t * attr,
+ int pshared);
+
+int pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind);
+int pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind);
+
+/*
+ * Barrier Attribute Functions
+ */
+int pthread_barrierattr_init (pthread_barrierattr_t * attr);
+
+int pthread_barrierattr_destroy (pthread_barrierattr_t * attr);
+
+int pthread_barrierattr_getpshared (const pthread_barrierattr_t
+ * attr,
+ int *pshared);
+
+int pthread_barrierattr_setpshared (pthread_barrierattr_t * attr,
+ int pshared);
+
+/*
+ * Mutex Functions
+ */
+int pthread_mutex_init (pthread_mutex_t * mutex,
+ const pthread_mutexattr_t * attr);
+
+int pthread_mutex_destroy (pthread_mutex_t * mutex);
+
+int pthread_mutex_lock (pthread_mutex_t * mutex);
+
+int pthread_mutex_trylock (pthread_mutex_t * mutex);
+
+int pthread_mutex_unlock (pthread_mutex_t * mutex);
+
+/*
+ * Spinlock Functions
+ */
+int pthread_spin_init (pthread_spinlock_t * lock, int pshared);
+
+int pthread_spin_destroy (pthread_spinlock_t * lock);
+
+int pthread_spin_lock (pthread_spinlock_t * lock);
+
+int pthread_spin_trylock (pthread_spinlock_t * lock);
+
+int pthread_spin_unlock (pthread_spinlock_t * lock);
+
+/*
+ * Barrier Functions
+ */
+int pthread_barrier_init (pthread_barrier_t * barrier,
+ const pthread_barrierattr_t * attr,
+ unsigned int count);
+
+int pthread_barrier_destroy (pthread_barrier_t * barrier);
+
+int pthread_barrier_wait (pthread_barrier_t * barrier);
+
+/*
+ * Condition Variable Attribute Functions
+ */
+int pthread_condattr_init (pthread_condattr_t * attr);
+
+int pthread_condattr_destroy (pthread_condattr_t * attr);
+
+int pthread_condattr_getpshared (const pthread_condattr_t * attr,
+ int *pshared);
+
+int pthread_condattr_setpshared (pthread_condattr_t * attr,
+ int pshared);
+
+/*
+ * Condition Variable Functions
+ */
+int pthread_cond_init (pthread_cond_t * cond,
+ const pthread_condattr_t * attr);
+
+int pthread_cond_destroy (pthread_cond_t * cond);
+
+int pthread_cond_wait (pthread_cond_t * cond,
+ pthread_mutex_t * mutex);
+
+int pthread_cond_timedwait (pthread_cond_t * cond,
+ pthread_mutex_t * mutex,
+ const struct timespec *abstime);
+
+int pthread_cond_signal (pthread_cond_t * cond);
+
+int pthread_cond_broadcast (pthread_cond_t * cond);
+
+/*
+ * Scheduling
+ */
+int pthread_setschedparam (pthread_t thread,
+ int policy,
+ const struct sched_param *param);
+
+int pthread_getschedparam (pthread_t thread,
+ int *policy,
+ struct sched_param *param);
+
+int pthread_setconcurrency (int);
+
+int pthread_getconcurrency (void);
+
+/*
+ * Read-Write Lock Functions
+ */
+int pthread_rwlock_init(pthread_rwlock_t *lock,
+ const pthread_rwlockattr_t *attr);
+
+int pthread_rwlock_destroy(pthread_rwlock_t *lock);
+
+int pthread_rwlock_tryrdlock(pthread_rwlock_t *);
+
+int pthread_rwlock_trywrlock(pthread_rwlock_t *);
+
+int pthread_rwlock_rdlock(pthread_rwlock_t *lock);
+
+int pthread_rwlock_wrlock(pthread_rwlock_t *lock);
+
+int pthread_rwlock_unlock(pthread_rwlock_t *lock);
+
+
+/*
+ * Non-portable functions
+ */
+
+/*
+ * Compatibility with Linux.
+ */
+int pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, int kind);
+int pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, int *kind);
+
+/*
+ * Possibly supported by other POSIX threads implementations
+ */
+int pthread_delay_np (struct timespec * interval);
+
+/*
+ * Returns the Win32 HANDLE for the POSIX thread.
+ */
+HANDLE pthread_getw32threadhandle_np(pthread_t thread);
+
+/*
+ * Returns the number of CPUs available to the process.
+ */
+int pthread_getprocessors_np(int * count);
+
+/*
+ * Useful if an application wants to statically link
+ * the lib rather than load the DLL at run-time.
+ */
+int pthread_win32_process_attach_np(void);
+int pthread_win32_process_detach_np(void);
+int pthread_win32_thread_attach_np(void);
+int pthread_win32_thread_detach_np(void);
+
+
+/*
+ * Protected Methods
+ *
+ * This function blocks until the given WIN32 handle
+ * is signaled or pthread_cancel had been called.
+ * This function allows the caller to hook into the
+ * PThreads cancel mechanism. It is implemented using
+ *
+ * WaitForMultipleObjects
+ *
+ * on 'waitHandle' and a manually reset WIN32 Event
+ * used to implement pthread_cancel. The 'timeout'
+ * argument to TimedWait is simply passed to
+ * WaitForMultipleObjects.
+ */
+int pthreadCancelableWait (HANDLE waitHandle);
+int pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout);
+
+/*
+ * Thread-Safe C Runtime Library Mappings.
+ */
+#ifndef _UWIN
+#if 1
+#if (! defined(HAVE_ERRNO)) && (! defined(_REENTRANT)) && (! defined(_MT))
+int * _errno( void );
+#endif
+#else
+#if (! defined(NEED_ERRNO)) || (! defined( _REENTRANT ) && (! defined( _MT ) || ! defined( _MD )))
+#if defined(PTW32_BUILD)
+__declspec( dllexport ) int * _errno( void );
+#else
+int * _errno( void );
+#endif
+#endif
+#endif
+#endif
+
+/*
+ * WIN32 C runtime library had been made thread-safe
+ * without affecting the user interface. Provide
+ * mappings from the UNIX thread-safe versions to
+ * the standard C runtime library calls.
+ * Only provide function mappings for functions that
+ * actually exist on WIN32.
+ */
+
+#if !defined(__MINGW32__)
+#define strtok_r( _s, _sep, _lasts ) \
+ ( *(_lasts) = strtok( (_s), (_sep) ) )
+#endif /* !__MINGW32__ */
+
+#define asctime_r( _tm, _buf ) \
+ ( strcpy( (_buf), asctime( (_tm) ) ), \
+ (_buf) )
+
+#define ctime_r( _clock, _buf ) \
+ ( strcpy( (_buf), ctime( (_clock) ) ), \
+ (_buf) )
+
+#define gmtime_r( _clock, _result ) \
+ ( *(_result) = *gmtime( (_clock) ), \
+ (_result) )
+
+#define localtime_r( _clock, _result ) \
+ ( *(_result) = *localtime( (_clock) ), \
+ (_result) )
+
+#define rand_r( _seed ) \
+ ( _seed == _seed? rand() : rand() )
+
+
+#ifdef __cplusplus
+
+/*
+ * Internal exceptions
+ */
+class ptw32_exception {};
+class ptw32_exception_cancel : public ptw32_exception {};
+class ptw32_exception_exit : public ptw32_exception {};
+
+#endif
+
+/* FIXME: This is only required if the library was built using SEH */
+/*
+ * Get internal SEH tag
+ */
+DWORD ptw32_get_exception_services_code(void);
+
+#ifndef PTW32_BUILD
+
+#ifdef __CLEANUP_SEH
+
+/*
+ * Redefine the SEH __except keyword to ensure that applications
+ * propagate our internal exceptions up to the library's internal handlers.
+ */
+#define __except( E ) \
+ __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \
+ ? EXCEPTION_CONTINUE_SEARCH : ( E ) )
+
+#endif /* __CLEANUP_SEH */
+
+#ifdef __cplusplus
+
+/*
+ * Redefine the C++ catch keyword to ensure that applications
+ * propagate our internal exceptions up to the library's internal handlers.
+ */
+#ifdef _MSC_VER
+ /*
+ * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll'
+ * if you want Pthread-Win32 cancelation and pthread_exit to work.
+ */
+
+#ifndef PtW32NoCatchWarn
+
+#pragma message("When compiling applications with MSVC++ and C++ exception handling:")
+#pragma message(" Replace any 'catch( ... )' with 'PtW32CatchAll' in POSIX threads")
+#pragma message(" if you want POSIX thread cancelation and pthread_exit to work.")
+
+#endif
+
+#define PtW32CatchAll \
+ catch( ptw32_exception & ) { throw; } \
+ catch( ... )
+
+#else /* _MSC_VER */
+
+#define catch( E ) \
+ catch( ptw32_exception & ) { throw; } \
+ catch( E )
+
+#endif /* _MSC_VER */
+
+#endif /* __cplusplus */
+
+#endif /* ! PTW32_BUILD */
+
+#ifdef __cplusplus
+} /* End of extern "C" */
+#endif /* __cplusplus */
+
+#endif /* PTHREAD_H */
diff --git a/lib/libdvd/libdvdread/msvc/include/pthreads/sched.h b/lib/libdvd/libdvdread/msvc/include/pthreads/sched.h
new file mode 100755
index 0000000000..ab277920e0
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/include/pthreads/sched.h
@@ -0,0 +1,89 @@
+/*
+ * Module: sched.h
+ *
+ * Purpose:
+ * Provides an implementation of POSIX realtime extensions
+ * as defined in
+ *
+ * POSIX 1003.1b-1993 (POSIX.1b)
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+#ifndef _SCHED_H
+#define _SCHED_H
+
+#if defined(__MINGW32__) || defined(_UWIN)
+/* For pid_t */
+# include <sys/types.h>
+/* Required by Unix 98 */
+# include <time.h>
+#else
+typedef int pid_t;
+#endif
+
+/* Thread scheduling policies */
+
+enum {
+ SCHED_OTHER = 0,
+ SCHED_FIFO,
+ SCHED_RR,
+ SCHED_MIN = SCHED_OTHER,
+ SCHED_MAX = SCHED_RR
+};
+
+struct sched_param {
+ int sched_priority;
+};
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+int sched_yield (void);
+
+int sched_get_priority_min (int policy);
+
+int sched_get_priority_max (int policy);
+
+int sched_setscheduler (pid_t pid, int policy);
+
+int sched_getscheduler (pid_t pid);
+
+/*
+ * Note that this macro returns ENOTSUP rather than
+ * ENOSYS as might be expected. However, returning ENOSYS
+ * should mean that sched_get_priority_{min,max} are
+ * not implemented as well as sched_rr_get_interval.
+ * This is not the case, since we just don't support
+ * round-robin scheduling. Therefore I have chosen to
+ * return the same value as sched_setscheduler when
+ * SCHED_RR is passed to it.
+ */
+#define sched_rr_get_interval(_pid, _interval) \
+ ( errno = ENOTSUP, (int) -1 )
+
+
+#ifdef __cplusplus
+} /* End of extern "C" */
+#endif /* __cplusplus */
+
+
+#endif /* !_SCHED_H */
+
diff --git a/lib/libdvd/libdvdread/msvc/include/sys/time.h b/lib/libdvd/libdvdread/msvc/include/sys/time.h
new file mode 100755
index 0000000000..f874fa655f
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/include/sys/time.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2000-2001 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine 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.
+ *
+ * xine 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
+ *
+ * WIN32 PORT,
+ * by Matthew Grooms <elon@altavista.com>
+ *
+ * sys/time.h - There is no seperate sys/time.h for win32 so we simply
+ * include the standard time header as well as our xine
+ * timer functions.
+ */
+
+#include <time.h>
diff --git a/lib/libdvd/libdvdread/msvc/include/timer.h b/lib/libdvd/libdvdread/msvc/include/timer.h
new file mode 100755
index 0000000000..efab6f4e18
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/include/timer.h
@@ -0,0 +1,39 @@
+#include <time.h>
+#include <winsock.h>
+#include "pthread.h"
+
+#ifndef _ITIMER_
+#define _ITIMER_
+
+#define ITIMER_REAL 0
+#define ITIMER_VIRTUAL 1
+
+// time reference
+// ----------------------------------
+//
+// 1,000 milliseconds / sec
+// 1,000,000 microseconds / sec
+// 1,000,000,000 nanoseconds / sec
+//
+// timeval.time_sec = seconds
+// timeval.time_usec = microseconds
+
+struct itimerval
+{
+ struct timeval it_interval; /* timer interval */
+ struct timeval it_value; /* current value */
+};
+
+struct timezone {
+ int tz_minuteswest; /* minutes west of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+};
+
+int gettimeofday( struct timeval *tp, struct timezone *tzp );
+int setitimer( int which, struct itimerval * value, struct itimerval *ovalue );
+int pause( void );
+
+unsigned int sleep( unsigned int seconds );
+int nanosleep( const struct timespec *rqtp, struct timespec *rmtp );
+
+#endif \ No newline at end of file
diff --git a/lib/libdvd/libdvdread/msvc/include/unistd.h b/lib/libdvd/libdvdread/msvc/include/unistd.h
new file mode 100755
index 0000000000..7e4c63f3a5
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/include/unistd.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2000-2001 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine 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.
+ *
+ * xine 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
+ *
+ * WIN32 PORT,
+ * by Matthew Grooms <elon@altavista.com>
+ *
+ * unistd.h - This is mostly a catch all header that maps standard unix
+ * libc calls to the equivelent win32 functions.
+ *
+ */
+
+#include <windows.h>
+#include <malloc.h>
+#include <errno.h>
+#include <direct.h>
+
+#include <config.h>
+
+#ifndef _SYS_UNISTD_H_
+#define _SYS_UNISTD_H_
+
+#define inline __inline
+
+#define mkdir( A, B ) _mkdir( A )
+#define lstat stat
+
+#ifndef S_ISDIR
+#define S_ISDIR(A) ( S_IFDIR & A )
+#endif
+
+#define S_IXUSR S_IEXEC
+#define S_IXGRP S_IEXEC
+#define S_IXOTH S_IEXEC
+
+#define M_PI 3.14159265358979323846 /* pi */
+
+#define bzero( A, B ) memset( A, 0, B )
+
+#ifndef strcasecmp
+#define strcasecmp _stricmp
+#endif
+
+#ifndef strncasecmp
+#define strncasecmp _strnicmp
+#endif
+
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+
+// FIXME : I dont remember why this is here
+#define readlink
+
+#endif
diff --git a/lib/libdvd/libdvdread/msvc/install/README b/lib/libdvd/libdvdread/msvc/install/README
new file mode 100755
index 0000000000..5e6ba4ae9f
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/install/README
@@ -0,0 +1,7 @@
+MSVC Help
+---------
+
+In order to build using any application that requires libdvdnav using MSVC the
+following directories (lib and include) must be copied to the msvc directory of
+the particular application.
+
diff --git a/lib/libdvd/libdvdread/msvc/libdvdcss.def b/lib/libdvd/libdvdread/msvc/libdvdcss.def
new file mode 100755
index 0000000000..0a6e2fd997
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/libdvdcss.def
@@ -0,0 +1,12 @@
+;------------------------------------------------------------
+; LIBDVDCSS DLL DEFINITIONS FILE
+
+EXPORTS
+
+dvdcss_interface_2
+dvdcss_open
+dvdcss_error
+dvdcss_seek
+dvdcss_read
+dvdcss_close
+dvdcss_title \ No newline at end of file
diff --git a/lib/libdvd/libdvdread/msvc/libdvdcss.dsp b/lib/libdvd/libdvdread/msvc/libdvdcss.dsp
new file mode 100755
index 0000000000..bb91b6a3eb
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/libdvdcss.dsp
@@ -0,0 +1,139 @@
+# Microsoft Developer Studio Project File - Name="libdvdcss" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=libdvdcss - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libdvdcss.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libdvdcss.mak" CFG="libdvdcss - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libdvdcss - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "libdvdcss - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libdvdcss - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_USRDLL" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "." /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_USRDLL" /D PATH_MAX=2048 /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 /machine:IX86
+# ADD LINK32 /machine:IX86
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Desc=Create libdvdcss Install
+PostBuild_Cmds=scripts\libdvdcss_intstall.bat Release
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "libdvdcss - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_USRDLL" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "." /I "../libdvdcss/dvdcss" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_USRDLL" /D MAX_PATH=2048 /YX /FD /GZ ./ "../libdvdcss" /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 /machine:IX86
+# ADD LINK32 /dll /machine:IX86 /out:"Debug/bin/libdvdcss.dll"
+# SUBTRACT LINK32 /pdb:none
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Desc=Create libdvdcss Install
+PostBuild_Cmds=scripts\libdvdcss_intstall.bat Debug
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "libdvdcss - Win32 Release"
+# Name "libdvdcss - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\libdvdcss\css.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\libdvdcss\device.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\libdvdcss\error.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\libdvdcss\ioctl.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\libdvdcss\libdvdcss.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "DLL Defs"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\libdvdcss.def
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/lib/libdvd/libdvdread/msvc/libdvdnav.def b/lib/libdvd/libdvdread/msvc/libdvdnav.def
new file mode 100755
index 0000000000..7f633d18d2
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/libdvdnav.def
@@ -0,0 +1,82 @@
+;------------------------------------------------------------
+; LIBDVDNAV DLL DEFINITIONS FILE
+
+EXPORTS
+
+DVDOpen
+DVDClose
+DVDOpenFile
+DVDCloseFile
+DVDReadBlocks
+
+navRead_DSI
+navRead_PCI
+
+ifoClose
+ifoRead_VOBU_ADMAP
+ifoRead_VTS_ATRT
+ifoRead_PTL_MAIT
+ifoRead_PGCI_UT
+ifoRead_TT_SRPT
+ifoRead_FP_PGC
+ifoOpenVMGI
+ifoRead_TITLE_VOBU_ADMAP
+ifoRead_PGCIT
+ifoRead_VTS_PTT_SRPT
+ifoOpenVTSI
+ifoPrint
+
+dvdnav_set_readahead_flag
+dvdnav_set_region_mask
+dvdnav_spu_language_select
+dvdnav_audio_language_select
+dvdnav_menu_language_select
+dvdnav_get_angle_info
+dvdnav_current_title_info
+dvdnav_title_play
+dvdnav_part_play
+dvdnav_get_number_of_titles
+dvdnav_get_title_string
+dvdnav_open
+dvdnav_close
+dvdnav_wait_skip
+dvdnav_get_video_scale_permission
+dvdnav_get_video_aspect
+dvdnav_still_skip
+dvdnav_err_to_string
+dvdnav_get_next_cache_block
+dvdnav_free_cache_block
+dvdnav_get_position
+dvdnav_sector_search
+dvdnav_get_current_highlight
+dvdnav_button_select_and_activate
+dvdnav_right_button_select
+dvdnav_left_button_select
+dvdnav_lower_button_select
+dvdnav_upper_button_select
+dvdnav_mouse_select
+dvdnav_button_select
+dvdnav_mouse_activate
+dvdnav_button_activate
+dvdnav_angle_change
+dvdnav_prev_pg_search
+dvdnav_next_pg_search
+dvdnav_menu_call
+dvdnav_spu_stream_to_lang
+dvdnav_get_spu_logical_stream
+dvdnav_audio_stream_to_lang
+dvdnav_get_audio_logical_stream
+dvdnav_is_domain_vts
+
+dvdnav_set_PGC_positioning_flag
+dvdnav_get_number_of_parts
+dvdnav_reset
+
+;------------------------------------------------------------
+; timer exports
+
+gettimeofday
+setitimer
+pause
+sleep
+nanosleep
diff --git a/lib/libdvd/libdvdread/msvc/libdvdnav.dsp b/lib/libdvd/libdvdread/msvc/libdvdnav.dsp
new file mode 100755
index 0000000000..d301b234ee
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/libdvdnav.dsp
@@ -0,0 +1,188 @@
+# Microsoft Developer Studio Project File - Name="libdvdnav" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=libdvdnav - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libdvdnav.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libdvdnav.mak" CFG="libdvdnav - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libdvdnav - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "libdvdnav - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libdvdnav - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+LINK32=link.exe
+# ADD BASE LINK32 /machine:IX86
+# ADD LINK32 /machine:IX86
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "..\..\libdvdcss\src" /I "." /I "include" /I "contrib/dirent" /I "include/pthreads" /I "../../libdvdcss" /I ".." /I "../src" /I "../src/dvdread" /I "../src/vm" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "DVDNAV_COMPILE" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"Release\libdvdnav\libdvdnav.lib"
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Desc=Create libdvdnav Install Files
+PostBuild_Cmds=scripts\libdvdnav_install.bat Release
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "libdvdnav - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+LINK32=link.exe
+# ADD BASE LINK32 /machine:IX86
+# ADD LINK32 /debug /machine:IX86 /out:"Debug/libdvdnav.lib" /implib:"Debug/libdvdnav.lib"
+# SUBTRACT LINK32 /pdb:none /nodefaultlib
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "include" /I "contrib/dirent" /I "include/pthreads" /I "../../libdvdcss" /I "../src" /I "." /I ".." /I "../src/dvdread" /I "../src/vm" /D "WIN32" /D "_DEBUG" /D "_LIB" /D "DVDNAV_COMPILE" /D "HAVE_CONFIG_H" /FR"Debug/libdvdnav/" /Fp"Debug/libdvdnav/libdvdnav.pch" /YX /Fo"Debug/libdvdnav/" /Fd"Debug/libdvdnav/" /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 libwin32utils.lib /nologo /out:"Debug\libdvdnav\libdvdnav.lib"
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Desc=Create libdvdnav Install Files
+PostBuild_Cmds=scripts\libdvdnav_install.bat Debug
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "libdvdnav - Win32 Release"
+# Name "libdvdnav - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\src\vm\decoder.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\dvdread\dvd_input.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\dvdread\dvd_reader.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\dvdread\dvd_udf.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\dvdnav.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\highlight.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\dvdread\ifo_print.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\dvdread\ifo_read.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\dvdread\md5.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\dvdread\nav_print.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\dvdread\nav_read.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\navigation.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\read_cache.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\remap.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\searching.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\settings.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\vm\vm.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\vm\vmcmd.c
+# End Source File
+# End Group
+# Begin Group "DLL Defs"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\libdvdnav.def
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/lib/libdvd/libdvdread/msvc/libdvdnav.dsw b/lib/libdvd/libdvdread/msvc/libdvdnav.dsw
new file mode 100755
index 0000000000..8974efbee6
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/libdvdnav.dsw
@@ -0,0 +1,101 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "ifo_dump"=.\ifo_dump.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libdvdnav
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "libdvdcss"=.\libdvdcss.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libdvdnav"=.\libdvdnav.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libwin32utils
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "libwin32utils"=.\libwin32utils.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "play_title"=.\play_title.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libdvdnav
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "title_info"=.\title_info.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libdvdnav
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lib/libdvd/libdvdread/msvc/libwin32utils.def b/lib/libdvd/libdvdread/msvc/libwin32utils.def
new file mode 100755
index 0000000000..1277cc8b7b
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/libwin32utils.def
@@ -0,0 +1,229 @@
+;------------------------------------------------------------
+; LIBWIN32UTILS DLL DEFINITIONS FILE
+
+EXPORTS
+
+;------------------------------------------------------------
+; dirent exports
+
+opendir
+closedir
+readdir
+rewinddir
+
+;------------------------------------------------------------
+; pthread exports
+
+;pthread_atfork
+pthread_attr_destroy
+pthread_attr_getdetachstate
+pthread_attr_getinheritsched
+pthread_attr_getschedparam
+pthread_attr_getschedpolicy
+pthread_attr_getscope
+pthread_attr_getstackaddr
+pthread_attr_getstacksize
+pthread_attr_init
+pthread_attr_setdetachstate
+pthread_attr_setinheritsched
+pthread_attr_setschedparam
+pthread_attr_setschedpolicy
+pthread_attr_setscope
+pthread_attr_setstackaddr
+pthread_attr_setstacksize
+pthread_cancel
+;
+; These two are implemented as macros in pthread.h
+;
+;pthread_cleanup_pop
+;pthread_cleanup_push
+;
+pthread_condattr_destroy
+pthread_condattr_getpshared
+pthread_condattr_init
+pthread_condattr_setpshared
+pthread_cond_broadcast
+pthread_cond_destroy
+pthread_cond_init
+pthread_cond_signal
+pthread_cond_timedwait
+pthread_cond_wait
+pthread_create
+pthread_detach
+pthread_equal
+pthread_exit
+pthread_getconcurrency
+pthread_getschedparam
+pthread_getspecific
+pthread_join
+pthread_key_create
+pthread_key_delete
+;pthread_kill
+pthread_mutexattr_destroy
+;pthread_mutexattr_getprioceiling
+;pthread_mutexattr_getprotocol
+pthread_mutexattr_getpshared
+pthread_mutexattr_gettype
+pthread_mutexattr_init
+;pthread_mutexattr_setprioceiling
+;pthread_mutexattr_setprotocol
+pthread_mutexattr_setpshared
+pthread_mutexattr_settype
+pthread_mutexattr_destroy
+pthread_mutex_init
+pthread_mutex_destroy
+pthread_mutex_lock
+pthread_mutex_trylock
+pthread_mutex_unlock
+pthread_once
+pthread_self
+pthread_setcancelstate
+pthread_setcanceltype
+pthread_setconcurrency
+pthread_setschedparam
+pthread_setspecific
+;pthread_sigmask
+pthread_testcancel
+;
+; POSIX 1.b
+;
+sched_get_priority_min
+sched_get_priority_max
+sched_getscheduler
+sched_setscheduler
+sched_yield
+sem_init
+sem_destroy
+sem_trywait
+sem_wait
+sem_post
+sem_open
+sem_close
+sem_unlink
+sem_getvalue
+;
+; This next one is a macro
+;sched_rr_get_interval
+;
+;
+; Read/Write Locks
+;
+pthread_rwlock_init
+pthread_rwlock_destroy
+pthread_rwlock_tryrdlock
+pthread_rwlock_trywrlock
+pthread_rwlock_rdlock
+pthread_rwlock_wrlock
+pthread_rwlock_unlock
+;
+; Spin locks
+;
+pthread_spin_init
+pthread_spin_destroy
+pthread_spin_lock
+pthread_spin_unlock
+pthread_spin_trylock
+;
+; Barriers
+;
+pthread_barrier_init
+pthread_barrier_destroy
+pthread_barrier_wait
+pthread_barrierattr_init
+pthread_barrierattr_destroy
+pthread_barrierattr_getpshared
+pthread_barrierattr_setpshared
+;
+; Non-portable/compatibility with other implementations
+;
+pthread_delay_np
+pthread_mutexattr_getkind_np
+pthread_mutexattr_setkind_np
+;
+; Non-portable local implementation only
+;
+pthread_getw32threadhandle_np
+pthread_getprocessors_np
+pthreadCancelableWait
+pthreadCancelableTimedWait
+;
+; For use when linking statically
+;
+pthread_win32_process_attach_np
+pthread_win32_process_detach_np
+pthread_win32_thread_attach_np
+pthread_win32_thread_detach_np
+;
+; Needed if !defined(_MSC_VER) && !defined(__cplusplus)
+;
+ptw32_push_cleanup
+ptw32_pop_cleanup
+;
+; Not for use directly. Needed by macros in pthread.h
+; to return internal SEH code.
+;
+ptw32_get_exception_services_code
+
+;------------------------------------------------------------
+; timer exports
+
+adler32
+compress
+crc32
+deflate
+deflateCopy
+deflateEnd
+deflateInit2_
+deflateInit_
+deflateParams
+deflateReset
+deflateSetDictionary
+gzclose
+gzdopen
+gzerror
+gzflush
+gzopen
+gzread
+gzwrite
+inflate
+inflateEnd
+inflateInit2_
+inflateInit_
+inflateReset
+inflateSetDictionary
+inflateSync
+uncompress
+zlibVersion
+gzprintf
+gzputc
+gzgetc
+gzseek
+gzrewind
+gztell
+gzeof
+gzsetparams
+zError
+inflateSyncPoint
+get_crc_table
+compress2
+gzputs
+gzgets
+
+;------------------------------------------------------------
+; timer exports
+
+gettimeofday
+setitimer
+pause
+sleep
+nanosleep
+
+;------------------------------------------------------------
+; other exports
+bcopy
+dlclose
+dlsym
+dlopen
+dlerror
+
+optind \ No newline at end of file
diff --git a/lib/libdvd/libdvdread/msvc/libwin32utils.dsp b/lib/libdvd/libdvdread/msvc/libwin32utils.dsp
new file mode 100755
index 0000000000..f94af8f493
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/libwin32utils.dsp
@@ -0,0 +1,136 @@
+# Microsoft Developer Studio Project File - Name="libwin32utils" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=libwin32utils - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libwin32utils.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libwin32utils.mak" CFG="libwin32utils - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libwin32utils - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "libwin32utils - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libwin32utils - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release/libwin32utils"
+# PROP Intermediate_Dir "Release/libwin32utils"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /machine:I386
+# ADD LINK32 winmm.lib /nologo /machine:I386 /out:"Release/libwin32utils.lib"
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_LIB" /D "LIBWIN32UTILS_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "include" /I "contrib/dirent" /I "include/pthreads" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_LIB" /D "LIBWIN32UTILS_EXPORTS" /D "__CLEANUP_C" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD LIB32 /out:"libwin32utils.lib"
+
+!ELSEIF "$(CFG)" == "libwin32utils - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug/libwin32utils"
+# PROP Intermediate_Dir "Debug/libwin32utils"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 winmm.lib /nologo /debug /machine:I386 /out:"Debug/libwin32utils.lib" /pdbtype:sept
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_LIB" /D "LIBWIN32UTILS_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "include/pthreads" /I "include" /I "contrib/dirent" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_LIB" /D "LIBWIN32UTILS_EXPORTS" /D "__CLEANUP_C" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD LIB32 winmm.lib /out:"libwin32utils.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "libwin32utils - Win32 Release"
+# Name "libwin32utils - Win32 Debug"
+# Begin Group "Source Files ( dirent )"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\contrib\dirent\dirent.c
+# End Source File
+# End Group
+# Begin Group "Source Files ( timer )"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\contrib\timer\timer.c
+# End Source File
+# End Group
+# Begin Group "DLL Defs"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\libwin32utils.def
+# End Source File
+# End Group
+# Begin Group "Source Files ( other )"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\contrib\bcopy.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\contrib\dlfcn.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\contrib\getopt.c
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/lib/libdvd/libdvdread/msvc/play_title.dsp b/lib/libdvd/libdvdread/msvc/play_title.dsp
new file mode 100755
index 0000000000..8a3efdf587
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/play_title.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="play_title" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=play_title - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "play_title.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "play_title.mak" CFG="play_title - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "play_title - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "play_title - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "play_title - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "." /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "play_title - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "play_title___Win32_Debug"
+# PROP BASE Intermediate_Dir "play_title___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug\play_title"
+# PROP Intermediate_Dir "Debug\play_title"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "include" /I "contrib/dirent" /I "../../libdvdcss" /I "install/include" /I "." /I ".." /I "../src" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/bin/play_title.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "play_title - Win32 Release"
+# Name "play_title - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\src\play_title.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/lib/libdvd/libdvdread/msvc/scripts/libdvdcss_install.bat b/lib/libdvd/libdvdread/msvc/scripts/libdvdcss_install.bat
new file mode 100755
index 0000000000..84712b122b
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/scripts/libdvdcss_install.bat
@@ -0,0 +1,8 @@
+
+ECHO mkdir dll ...
+rmdir /s install\dll
+mkdir install\dll
+
+ECHO libvdvcss dll ...
+xcopy /Y %1\bin\libdvdcss.dll install\dll
+
diff --git a/lib/libdvd/libdvdread/msvc/scripts/libdvdnav_install.bat b/lib/libdvd/libdvdread/msvc/scripts/libdvdnav_install.bat
new file mode 100755
index 0000000000..f49f2f2294
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/scripts/libdvdnav_install.bat
@@ -0,0 +1,21 @@
+
+ECHO mkdir install ...
+rmdir /s install\include
+rmdir /s install\lib
+mkdir install\include\dvdnav
+mkdir install\lib
+
+ECHO includes ...
+xcopy /Y ..\src\dvdnav.h install\include\dvdnav
+xcopy /Y ..\src\dvdnav_events.h install\include\dvdnav
+xcopy /Y ..\src\dvd_types.h install\include\dvdnav
+xcopy /Y ..\src\dvdread\dvd_reader.h install\include\dvdnav
+xcopy /Y ..\src\dvdread\nav_read.h install\include\dvdnav
+xcopy /Y ..\src\dvdread\ifo_read.h install\include\dvdnav
+xcopy /Y ..\src\dvdread\nav_print.h install\include\dvdnav
+xcopy /Y ..\src\dvdread\ifo_print.h install\include\dvdnav
+xcopy /Y ..\src\dvdread\ifo_types.h install\include\dvdnav
+xcopy /Y ..\src\dvdread\nav_types.h install\include\dvdnav
+
+ECHO lib ...
+xcopy /Y %1\libdvdnav\libdvdnav.lib install\lib
diff --git a/lib/libdvd/libdvdread/msvc/title_info.dsp b/lib/libdvd/libdvdread/msvc/title_info.dsp
new file mode 100755
index 0000000000..39d3768d56
--- /dev/null
+++ b/lib/libdvd/libdvdread/msvc/title_info.dsp
@@ -0,0 +1,101 @@
+# Microsoft Developer Studio Project File - Name="title_info" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=title_info - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "title_info.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "title_info.mak" CFG="title_info - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "title_info - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "title_info - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "title_info - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "." /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "title_info - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "title_info___Win32_Debug"
+# PROP BASE Intermediate_Dir "title_info___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "title_info___Win32_Debug"
+# PROP Intermediate_Dir "title_info___Win32_Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "include" /I "contrib/dirent" /I "../../libdvdcss" /I "install/include" /I "." /I ".." /I "../src" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"Debug/title_info/title_info.pch" /YX /Fo"Debug/title_info/" /Fd"Debug/title_info/" /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/bin/title_info.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "title_info - Win32 Release"
+# Name "title_info - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\src\title_info.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/lib/libdvd/libdvdread/src/Makefile.am b/lib/libdvd/libdvdread/src/Makefile.am
new file mode 100644
index 0000000000..f79280cfbb
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/Makefile.am
@@ -0,0 +1,19 @@
+include $(top_srcdir)/misc/Makefile.common
+
+includedir = ${prefix}/include/dvdread
+
+AM_CPPFLAGS = -I$(top_srcdir)/src
+
+lib_LTLIBRARIES = libdvdread.la
+
+libdvdread_la_SOURCES = dvd_reader.c nav_read.c ifo_read.c \
+ dvd_input.c dvd_udf.c md5.c nav_print.c ifo_print.c bitreader.c \
+ bswap.h dvd_input.h dvdread_internal.h dvd_udf.h md5.h bitreader.h
+
+libdvdread_la_LIBADD = $(DYNAMIC_LD_LIBS)
+
+libdvdread_la_LDFLAGS = -version-info $(DVDREAD_LT_CURRENT):$(DVDREAD_LT_REVISION):$(DVDREAD_LT_AGE) \
+ -export-symbols-regex "(^dvd.*|^nav.*|^ifo.*|^DVD.*|^UDF.*)"
+
+include_HEADERS = dvd_reader.h nav_read.h ifo_read.h \
+ nav_print.h ifo_print.h ifo_types.h nav_types.h dvd_udf.h bitreader.h
diff --git a/lib/libdvd/libdvdread/src/bitreader.c b/lib/libdvd/libdvdread/src/bitreader.c
new file mode 100644
index 0000000000..441659f721
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/bitreader.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2000, 2001, 2002, 2003 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 "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "bitreader.h"
+
+int dvdread_getbits_init(getbits_state_t *state, uint8_t *start) {
+ if ((state == NULL) || (start == NULL)) return 0;
+ state->start = start;
+ state->bit_position = 0;
+ state->byte_position = 0;
+ state->byte = start[0];
+ return 1;
+}
+
+/* Non-optimized getbits. */
+/* This can easily be optimized for particular platforms. */
+uint32_t dvdread_getbits(getbits_state_t *state, uint32_t number_of_bits) {
+ uint32_t result=0;
+ uint8_t byte=0;
+ if (number_of_bits > 32) {
+ printf("Number of bits > 32 in getbits\n");
+ abort();
+ }
+
+ if ((state->bit_position) > 0) { /* Last getbits left us in the middle of a byte. */
+ if (number_of_bits > (8-state->bit_position)) { /* this getbits will span 2 or more bytes. */
+ byte = state->byte;
+ byte = byte >> (state->bit_position);
+ result = byte;
+ number_of_bits -= (8-state->bit_position);
+ state->bit_position = 0;
+ state->byte_position++;
+ state->byte = state->start[state->byte_position];
+ } else {
+ byte=state->byte;
+ state->byte = state->byte << number_of_bits;
+ byte = byte >> (8 - number_of_bits);
+ result = byte;
+ state->bit_position += number_of_bits; /* Here it is impossible for bit_position > 8 */
+ if (state->bit_position == 8) {
+ state->bit_position = 0;
+ state->byte_position++;
+ state->byte = state->start[state->byte_position];
+ }
+ number_of_bits = 0;
+ }
+ }
+ if ((state->bit_position) == 0) {
+ while (number_of_bits > 7) {
+ result = (result << 8) + state->byte;
+ state->byte_position++;
+ state->byte = state->start[state->byte_position];
+ number_of_bits -= 8;
+ }
+ if (number_of_bits > 0) { /* number_of_bits < 8 */
+ byte = state->byte;
+ state->byte = state->byte << number_of_bits;
+ state->bit_position += number_of_bits; /* Here it is impossible for bit_position > 7 */
+ byte = byte >> (8 - number_of_bits);
+ result = (result << number_of_bits) + byte;
+ number_of_bits = 0;
+ }
+ }
+
+ return result;
+}
+
+#if 0 /* TODO: optimized versions not yet used */
+
+/* WARNING: This function can only be used on a byte boundary.
+ No checks are made that we are in fact on a byte boundary.
+ */
+uint16_t dvdread_get16bits(getbits_state_t *state) {
+ uint16_t result;
+ state->byte_position++;
+ result = (state->byte << 8) + state->start[state->byte_position++];
+ state->byte = state->start[state->byte_position];
+ return result;
+}
+
+/* WARNING: This function can only be used on a byte boundary.
+ No checks are made that we are in fact on a byte boundary.
+ */
+uint32_t dvdread_get32bits(getbits_state_t *state) {
+ uint32_t result;
+ state->byte_position++;
+ result = (state->byte << 8) + state->start[state->byte_position++];
+ result = (result << 8) + state->start[state->byte_position++];
+ result = (result << 8) + state->start[state->byte_position++];
+ state->byte = state->start[state->byte_position];
+ return result;
+}
+
+#endif
diff --git a/lib/libdvd/libdvdread/src/bitreader.h b/lib/libdvd/libdvdread/src/bitreader.h
new file mode 100644
index 0000000000..54d421507d
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/bitreader.h
@@ -0,0 +1,40 @@
+#ifndef BITREADER_H_INCLUDED
+#define BITREADER_H_INCLUDED
+
+/*
+ * Copyright (C) 2000, 2001, 2002 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
+ */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ uint8_t *start;
+ uint32_t byte_position;
+ uint32_t bit_position;
+ uint8_t byte;
+} getbits_state_t;
+
+int dvdread_getbits_init(getbits_state_t *state, uint8_t *start);
+uint32_t dvdread_getbits(getbits_state_t *state, uint32_t number_of_bits);
+
+#ifdef __cplusplus
+};
+#endif
+#endif /* BITREADER_H_INCLUDED */
diff --git a/lib/libdvd/libdvdread/src/bswap.h b/lib/libdvd/libdvdread/src/bswap.h
new file mode 100644
index 0000000000..45286db0e5
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/bswap.h
@@ -0,0 +1,104 @@
+#ifndef BSWAP_H_INCLUDED
+#define BSWAP_H_INCLUDED
+
+/*
+ * 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
+ */
+
+#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
+
+/* For __FreeBSD_version */
+#if defined(HAVE_SYS_PARAM_H)
+#include <sys/param.h>
+#endif
+
+#if defined(__linux__) || defined(__GLIBC__)
+#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(__APPLE__)
+#include <libkern/OSByteOrder.h>
+#define B2N_16(x) x = OSSwapBigToHostInt16(x)
+#define B2N_32(x) x = OSSwapBigToHostInt32(x)
+#define B2N_64(x) x = OSSwapBigToHostInt64(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)
+
+#elif defined(__FreeBSD__) && __FreeBSD_version >= 470000
+#include <sys/endian.h>
+#define B2N_16(x) x = be16toh(x)
+#define B2N_32(x) x = be32toh(x)
+#define B2N_64(x) x = be64toh(x)
+
+/* This is a slow but portable implementation, it has multiple evaluation
+ * problems so beware.
+ * Old FreeBSD's and Solaris don't have <byteswap.h> or any other such
+ * functionality!
+ */
+
+#elif defined(__FreeBSD__) || defined(__sun) || defined(__bsdi__) || defined(WIN32) || defined(__CYGWIN__) || defined(__BEOS__)
+#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) & 0xff00000000000000ULL) >> 56) | \
+ (((x) & 0x00ff000000000000ULL) >> 40) | \
+ (((x) & 0x0000ff0000000000ULL) >> 24) | \
+ (((x) & 0x000000ff00000000ULL) >> 8) | \
+ (((x) & 0x00000000ff000000ULL) << 8) | \
+ (((x) & 0x0000000000ff0000ULL) << 24) | \
+ (((x) & 0x000000000000ff00ULL) << 40) | \
+ (((x) & 0x00000000000000ffULL) << 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 */
diff --git a/lib/libdvd/libdvdread/src/dvd_input.c b/lib/libdvd/libdvdread/src/dvd_input.c
new file mode 100644
index 0000000000..3fbc2ae2f7
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/dvd_input.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2002 Samuel Hocevar <sam@zoy.org>,
+ * 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, USA.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "dvd_reader.h"
+#include "dvd_input.h"
+
+
+/* The function pointers that is the exported interface of this file. */
+dvd_input_t (*dvdinput_open) (const char *);
+int (*dvdinput_close) (dvd_input_t);
+int (*dvdinput_seek) (dvd_input_t, int);
+int (*dvdinput_title) (dvd_input_t, int);
+int (*dvdinput_read) (dvd_input_t, void *, int, int);
+char * (*dvdinput_error) (dvd_input_t);
+
+#ifdef HAVE_DVDCSS_DVDCSS_H
+/* linking to libdvdcss */
+#include "dvdcss/dvdcss.h"
+#define DVDcss_open(a) dvdcss_open((char*)(a))
+#define DVDcss_close dvdcss_close
+#define DVDcss_seek dvdcss_seek
+#define DVDcss_title dvdcss_title
+#define DVDcss_read dvdcss_read
+#define DVDcss_error dvdcss_error
+#else
+
+/* dlopening libdvdcss */
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#else
+/* Only needed on MINGW at the moment */
+#include "../../msvc/contrib/dlfcn.c"
+#endif
+
+typedef struct dvdcss_s *dvdcss_handle;
+static dvdcss_handle (*DVDcss_open) (const char *);
+static int (*DVDcss_close) (dvdcss_handle);
+static int (*DVDcss_seek) (dvdcss_handle, int, int);
+static int (*DVDcss_title) (dvdcss_handle, int);
+static int (*DVDcss_read) (dvdcss_handle, void *, int, int);
+static char * (*DVDcss_error) (dvdcss_handle);
+#endif
+
+/* The DVDinput handle, add stuff here for new input methods. */
+struct dvd_input_s {
+ /* libdvdcss handle */
+ dvdcss_handle dvdcss;
+
+ /* dummy file input */
+ int fd;
+};
+
+
+/**
+ * initialize and open a DVD device or file.
+ */
+static dvd_input_t css_open(const char *target)
+{
+ dvd_input_t dev;
+
+ /* Allocate the handle structure */
+ dev = (dvd_input_t) malloc(sizeof(*dev));
+ if(dev == NULL) {
+ fprintf(stderr, "libdvdread: Could not allocate memory.\n");
+ return NULL;
+ }
+
+ /* Really open it with libdvdcss */
+ dev->dvdcss = DVDcss_open(target);
+ if(dev->dvdcss == 0) {
+ fprintf(stderr, "libdvdread: Could not open %s with libdvdcss.\n", target);
+ free(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+
+/**
+ * return the last error message
+ */
+static char *css_error(dvd_input_t dev)
+{
+ return DVDcss_error(dev->dvdcss);
+}
+
+/**
+ * seek into the device.
+ */
+static int css_seek(dvd_input_t dev, int blocks)
+{
+ /* DVDINPUT_NOFLAGS should match the DVDCSS_NOFLAGS value. */
+ return DVDcss_seek(dev->dvdcss, blocks, DVDINPUT_NOFLAGS);
+}
+
+/**
+ * set the block for the beginning of a new title (key).
+ */
+static int css_title(dvd_input_t dev, int block)
+{
+ return DVDcss_title(dev->dvdcss, block);
+}
+
+/**
+ * read data from the device.
+ */
+static int css_read(dvd_input_t dev, void *buffer, int blocks, int flags)
+{
+ return DVDcss_read(dev->dvdcss, buffer, blocks, flags);
+}
+
+/**
+ * close the DVD device and clean up the library.
+ */
+static int css_close(dvd_input_t dev)
+{
+ int ret;
+
+ ret = DVDcss_close(dev->dvdcss);
+
+ if(ret < 0)
+ return ret;
+
+ free(dev);
+
+ return 0;
+}
+
+/**
+ * initialize and open a DVD device or file.
+ */
+static dvd_input_t file_open(const char *target)
+{
+ dvd_input_t dev;
+
+ /* Allocate the library structure */
+ dev = (dvd_input_t) malloc(sizeof(*dev));
+ if(dev == NULL) {
+ fprintf(stderr, "libdvdread: Could not allocate memory.\n");
+ return NULL;
+ }
+
+ /* Open the device */
+#ifndef WIN32
+ dev->fd = open(target, O_RDONLY);
+#else
+ dev->fd = open(target, O_RDONLY | O_BINARY);
+#endif
+ if(dev->fd < 0) {
+ perror("libdvdread: Could not open input");
+ free(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+
+/**
+ * return the last error message
+ */
+static char *file_error(dvd_input_t dev)
+{
+ /* use strerror(errno)? */
+ return (char *)"unknown error";
+}
+
+/**
+ * seek into the device.
+ */
+static int file_seek(dvd_input_t dev, int blocks)
+{
+ off_t pos;
+
+ pos = lseek(dev->fd, (off_t)blocks * (off_t)DVD_VIDEO_LB_LEN, SEEK_SET);
+ if(pos < 0) {
+ return pos;
+ }
+ /* assert pos % DVD_VIDEO_LB_LEN == 0 */
+ return (int) (pos / DVD_VIDEO_LB_LEN);
+}
+
+/**
+ * set the block for the beginning of a new title (key).
+ */
+static int file_title(dvd_input_t dev, int block)
+{
+ return -1;
+}
+
+/**
+ * read data from the device.
+ */
+static int file_read(dvd_input_t dev, void *buffer, int blocks, int flags)
+{
+ size_t len;
+ ssize_t ret;
+
+ len = (size_t)blocks * DVD_VIDEO_LB_LEN;
+
+ while(len > 0) {
+
+ ret = read(dev->fd, buffer, len);
+
+ if(ret < 0) {
+ /* One of the reads failed, too bad. We won't even bother
+ * returning the reads that went OK, and as in the POSIX spec
+ * the file position is left unspecified after a failure. */
+ return ret;
+ }
+
+ if(ret == 0) {
+ /* Nothing more to read. Return all of the whole blocks, if any.
+ * Adjust the file position back to the previous block boundary. */
+ size_t bytes = (size_t)blocks * DVD_VIDEO_LB_LEN - len;
+ off_t over_read = -(bytes % DVD_VIDEO_LB_LEN);
+ /*off_t pos =*/ lseek(dev->fd, over_read, SEEK_CUR);
+ /* should have pos % 2048 == 0 */
+ return (int) (bytes / DVD_VIDEO_LB_LEN);
+ }
+
+ len -= ret;
+ }
+
+ return blocks;
+}
+
+/**
+ * close the DVD device and clean up.
+ */
+static int file_close(dvd_input_t dev)
+{
+ int ret;
+
+ ret = close(dev->fd);
+
+ if(ret < 0)
+ return ret;
+
+ free(dev);
+
+ return 0;
+}
+
+
+/**
+ * Setup read functions with either libdvdcss or minimal DVD access.
+ */
+int dvdinput_setup(void)
+{
+ void *dvdcss_library = NULL;
+ char **dvdcss_version = NULL;
+
+#ifdef HAVE_DVDCSS_DVDCSS_H
+ /* linking to libdvdcss */
+ dvdcss_library = &dvdcss_library; /* Give it some value != NULL */
+ /* the DVDcss_* functions have been #defined at the top */
+ dvdcss_version = &dvdcss_interface_2;
+
+#else
+ /* dlopening libdvdcss */
+
+#ifdef __APPLE__
+ #define CSS_LIB "libdvdcss.2.dylib"
+#elif defined(WIN32)
+ #define CSS_LIB "libdvdcss.dll"
+#else
+ #define CSS_LIB "libdvdcss.so.2"
+#endif
+ dvdcss_library = dlopen(CSS_LIB, RTLD_LAZY);
+
+ if(dvdcss_library != NULL) {
+#if defined(__OpenBSD__) && !defined(__ELF__)
+#define U_S "_"
+#else
+#define U_S
+#endif
+ DVDcss_open = (dvdcss_handle (*)(const char*))
+ 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, 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");
+
+ dvdcss_version = (char **)dlsym(dvdcss_library, U_S "dvdcss_interface_2");
+
+ 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 = NULL;
+ } else if(!DVDcss_open || !DVDcss_close || !DVDcss_title || !DVDcss_seek
+ || !DVDcss_read || !DVDcss_error || !dvdcss_version) {
+ fprintf(stderr, "libdvdread: Missing symbols in %s, "
+ "this shouldn't happen !\n", CSS_LIB);
+ dlclose(dvdcss_library);
+ }
+ }
+#endif /* HAVE_DVDCSS_DVDCSS_H */
+
+ if(dvdcss_library != NULL) {
+ /*
+ char *psz_method = getenv( "DVDCSS_METHOD" );
+ char *psz_verbose = getenv( "DVDCSS_VERBOSE" );
+ fprintf(stderr, "DVDCSS_METHOD %s\n", psz_method);
+ fprintf(stderr, "DVDCSS_VERBOSE %s\n", psz_verbose);
+ */
+ fprintf(stderr, "libdvdread: Using libdvdcss version %s for DVD access\n",
+ dvdcss_version ? *dvdcss_version : "");
+
+ /* libdvdcss wrapper functions */
+ dvdinput_open = css_open;
+ dvdinput_close = css_close;
+ dvdinput_seek = css_seek;
+ dvdinput_title = css_title;
+ dvdinput_read = css_read;
+ dvdinput_error = css_error;
+ return 1;
+
+ } else {
+ fprintf(stderr, "libdvdread: Encrypted DVD support unavailable.\n");
+
+ /* libdvdcss replacement functions */
+ dvdinput_open = file_open;
+ dvdinput_close = file_close;
+ dvdinput_seek = file_seek;
+ dvdinput_title = file_title;
+ dvdinput_read = file_read;
+ dvdinput_error = file_error;
+ return 0;
+ }
+}
diff --git a/lib/libdvd/libdvdread/src/dvd_input.h b/lib/libdvd/libdvdread/src/dvd_input.h
new file mode 100644
index 0000000000..ccd2e74fe1
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/dvd_input.h
@@ -0,0 +1,67 @@
+#ifndef DVD_INPUT_H_INCLUDED
+#define DVD_INPUT_H_INCLUDED
+
+/*
+ * Copyright (C) 2001, 2002 Samuel Hocevar <sam@zoy.org>,
+ * 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, USA.
+ */
+
+/**
+ * Defines and flags. Make sure they fit the libdvdcss API!
+ */
+#define DVDINPUT_NOFLAGS 0
+
+#define DVDINPUT_READ_DECRYPT (1 << 0)
+
+#if defined( __MINGW32__ )
+# undef lseek
+# define lseek _lseeki64
+# undef fseeko
+# define fseeko fseeko64
+# undef ftello
+# define ftello ftello64
+# define flockfile(...)
+# define funlockfile(...)
+# define getc_unlocked getc
+# undef off_t
+# define off_t off64_t
+# undef stat
+# define stat _stati64
+# define fstat _fstati64
+# define wstat _wstati64
+#endif
+
+
+typedef struct dvd_input_s *dvd_input_t;
+
+/**
+ * Function pointers that will be filled in by the input implementation.
+ * These functions provide the main API.
+ */
+extern dvd_input_t (*dvdinput_open) (const char *);
+extern int (*dvdinput_close) (dvd_input_t);
+extern int (*dvdinput_seek) (dvd_input_t, int);
+extern int (*dvdinput_title) (dvd_input_t, int);
+extern int (*dvdinput_read) (dvd_input_t, void *, int, int);
+extern char * (*dvdinput_error) (dvd_input_t);
+
+/**
+ * Setup function accessed by dvd_reader.c. Returns 1 if there is CSS support.
+ */
+int dvdinput_setup(void);
+
+#endif /* DVD_INPUT_H_INCLUDED */
diff --git a/lib/libdvd/libdvdread/src/dvd_reader.c b/lib/libdvd/libdvdread/src/dvd_reader.c
new file mode 100644
index 0000000000..e865b41ef5
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/dvd_reader.c
@@ -0,0 +1,1395 @@
+/*
+ * Copyright (C) 2001-2004 Billy Biggs <vektor@dumbterm.net>,
+ * HÂkan Hjort <d95hjort@dtek.chalmers.se>,
+ * Bjˆrn Englund <d4bjorn@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, USA.
+ */
+
+#include "config.h"
+
+#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 <dirent.h>
+
+#define WITH_CACHE
+
+/* misc win32 helpers */
+#ifdef WIN32
+#ifndef HAVE_GETTIMEOFDAY
+/* replacement gettimeofday implementation */
+#include <sys/timeb.h>
+static inline int _private_gettimeofday( struct timeval *tv, void *tz )
+{
+ struct timeb t;
+ ftime( &t );
+ tv->tv_sec = t.time;
+ tv->tv_usec = t.millitm * 1000;
+ return 0;
+}
+#define gettimeofday(TV, TZ) _private_gettimeofday((TV), (TZ))
+#endif
+#include <io.h> /* read() */
+#define lseek64 _lseeki64
+#endif
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__)|| defined(__DARWIN__)
+#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
+
+#include "dvd_udf.h"
+#include "dvd_input.h"
+#include "dvd_reader.h"
+#include "md5.h"
+
+#define DEFAULT_UDF_CACHE_LEVEL 1
+
+struct dvd_reader_s {
+ /* Basic information. */
+ int isImageFile;
+
+ /* Hack for keeping track of the css status.
+ * 0: no css, 1: perhaps (need init of keys), 2: have done init */
+ int css_state;
+ int css_title; /* Last title that we have called dvdinpute_title for. */
+
+ /* Information required for an image file. */
+ dvd_input_t dev;
+
+ /* Information required for a directory path drive. */
+ char *path_root;
+
+ /* Filesystem cache */
+ int udfcache_level; /* 0 - turned off, 1 - on */
+ void *udfcache;
+};
+
+#define TITLES_MAX 9
+
+struct dvd_file_s {
+ /* Basic information. */
+ dvd_reader_t *dvd;
+
+ /* Hack for selecting the right css title. */
+ int css_title;
+
+ /* Information required for an image file. */
+ uint32_t lb_start;
+ uint32_t seek_pos;
+
+#ifdef WITH_CACHE
+ char cache[DVD_VIDEO_LB_LEN];
+ uint32_t lb_cache;
+#endif
+ /* Information required for a directory path drive. */
+ size_t title_sizes[ TITLES_MAX ];
+ dvd_input_t title_devs[ TITLES_MAX ];
+
+ /* Calculated at open-time, size in blocks. */
+ ssize_t filesize;
+};
+
+int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number,
+ size_t block_count, unsigned char *data,
+ int encrypted );
+
+/**
+ * Set the level of caching on udf
+ * level = 0 (no caching)
+ * level = 1 (caching filesystem info)
+ */
+int DVDUDFCacheLevel(dvd_reader_t *device, int level)
+{
+ struct dvd_reader_s *dev = (struct dvd_reader_s *)device;
+
+ if(level > 0) {
+ level = 1;
+ } else if(level < 0) {
+ return dev->udfcache_level;
+ }
+
+ dev->udfcache_level = level;
+
+ return level;
+}
+
+void *GetUDFCacheHandle(dvd_reader_t *device)
+{
+ struct dvd_reader_s *dev = (struct dvd_reader_s *)device;
+
+ return dev->udfcache;
+}
+
+void SetUDFCacheHandle(dvd_reader_t *device, void *cache)
+{
+ struct dvd_reader_s *dev = (struct dvd_reader_s *)device;
+
+ dev->udfcache = cache;
+}
+
+
+
+/* Loop over all titles and call dvdcss_title to crack the keys. */
+static int initAllCSSKeys( dvd_reader_t *dvd )
+{
+ 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;
+
+ char *nokeys_str = getenv("DVDREAD_NOKEYS");
+ if(nokeys_str != NULL)
+ return 0;
+
+ 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( dvdinput_title( dvd->dev, (int)start ) < 0 ) {
+ fprintf( stderr, "libdvdread: Error cracking CSS key for %s (0x%08x)\n", filename, start);
+ }
+ 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( dvdinput_title( dvd->dev, (int)start ) < 0 ) {
+ fprintf( stderr, "libdvdread: Error cracking CSS key for %s (0x%08x)!!\n", filename, start);
+ }
+ 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, int have_css )
+{
+ dvd_reader_t *dvd;
+ dvd_input_t dev;
+
+ dev = dvdinput_open( location );
+ if( !dev ) {
+ fprintf( stderr, "libdvdread: Can't open %s for reading\n", location );
+ return NULL;
+ }
+
+ dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) );
+ if( !dvd ) {
+ dvdinput_close(dev);
+ return NULL;
+ }
+ dvd->isImageFile = 1;
+ dvd->dev = dev;
+ dvd->path_root = NULL;
+
+ dvd->udfcache_level = DEFAULT_UDF_CACHE_LEVEL;
+ dvd->udfcache = NULL;
+
+ if( have_css ) {
+ /* Only if DVDCSS_METHOD = title, a bit if it's disc or if
+ * DVDCSS_METHOD = key but region missmatch. Unfortunaly we
+ * don't have that information. */
+
+ dvd->css_state = 1; /* Need key init. */
+ }
+ dvd->css_title = 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 NULL;
+ dvd->isImageFile = 0;
+ dvd->dev = 0;
+ dvd->path_root = strdup( path_root );
+ if(!dvd->path_root) {
+ free(dvd);
+ return 0;
+ }
+
+ dvd->udfcache_level = DEFAULT_UDF_CACHE_LEVEL;
+ dvd->udfcache = NULL;
+
+ dvd->css_state = 0; /* Only used in the UDF path */
+ dvd->css_title = 0; /* Only matters in the UDF path */
+
+ 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)cd0c (a is for atapi), recomended to _not_ use r
+ OpenBSD /dev/rcd0c, it needs to be the raw device
+ NetBSD /dev/rcd0[d|c|..] d for x86, c (for non x86), perhaps others
+ Darwin /dev/rdisk0, it needs to be the raw device
+ BSD/OS /dev/sr0c (if not mounted) or /dev/rsr0c ('c' any letter will do) */
+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 *ppath )
+{
+ struct stat fileinfo;
+ int ret;
+ int have_css;
+ dvd_reader_t *ret_val = NULL;
+ char *dev_name = NULL;
+ char *path;
+
+#ifdef _MSC_VER
+ int len;
+#endif
+
+ if( ppath == NULL )
+ return 0;
+
+ path = strdup(ppath);
+ if( path == NULL )
+ return 0;
+
+ /* Try to open libdvdcss or fall back to standard functions */
+ have_css = dvdinput_setup();
+
+#ifdef _MSC_VER
+ /* Strip off the trailing \ if it is not a drive */
+ len = strlen(path);
+ if ((len > 1) &&
+ (path[len - 1] == '\\') &&
+ (path[len - 2] != ':'))
+ {
+ path[len-1] = '\0';
+ }
+#endif
+
+ ret = stat( path, &fileinfo );
+
+ if( ret < 0 ) {
+ /* maybe "host:port" url? try opening it with acCeSS library */
+ if( strchr(path,':') ) {
+ ret_val = DVDOpenImageFile( path, have_css );
+ free(path);
+ return ret_val;
+ }
+ /* If we can't stat the file, give up */
+ fprintf( stderr, "libdvdread: Can't stat %s\n", path );
+ perror("");
+ free(path);
+ return NULL;
+ }
+
+ /* 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)
+ ret_val = DVDOpenImageFile( sun_block2char( path ), have_css );
+#elif defined(SYS_BSD)
+ ret_val = DVDOpenImageFile( bsd_block2char( path ), have_css );
+#else
+ ret_val = DVDOpenImageFile( path, have_css );
+#endif
+
+ free(path);
+ return ret_val;
+
+ } 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 ) ) ) {
+ free(path);
+ return NULL;
+ }
+
+#ifndef WIN32 /* don't have fchdir, and getcwd( NULL, ... ) is strange */
+ /* Also WIN32 does not have symlinks, so we don't need this bit of code. */
+
+ /* 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 = malloc(PATH_MAX+1);
+ if(!new_path) {
+ free(path);
+ return NULL;
+ }
+ getcwd(new_path, PATH_MAX );
+ fchdir( cdir );
+ close( cdir );
+ free( path_copy );
+ path_copy = new_path;
+ }
+ }
+#endif
+ /**
+ * 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_copy[ strlen( path_copy ) - 1 ] == '/' )
+ path_copy[ strlen( path_copy ) - 1 ] = '\0';
+ }
+
+ if( strlen( path_copy ) > TITLES_MAX ) {
+ if( !strcasecmp( &(path_copy[ strlen( path_copy ) - TITLES_MAX ]),
+ "/video_ts" ) ) {
+ path_copy[ strlen( path_copy ) - TITLES_MAX ] = '\0';
+ }
+ }
+
+ if(path_copy[0] == '\0') {
+ path_copy[0] = '/';
+ path_copy[1] = '\0';
+ }
+
+#if defined(SYS_BSD)
+ if( ( fe = getfsfile( path_copy ) ) ) {
+ 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, have_css );
+ }
+#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 ) ) {
+ 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, have_css );
+ 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, have_css );
+ dev_name = strdup(me->mnt_fsname);
+ break;
+ }
+ }
+ fclose( mntfile );
+ }
+#elif defined(_MSC_VER)
+ auth_drive = DVDOpenImageFile( path, have_css );
+#endif
+
+#ifndef _MSC_VER
+ if( !dev_name ) {
+ fprintf( stderr, "libdvdread: Couldn't find device name.\n" );
+ } else if( !auth_drive ) {
+ fprintf( stderr, "libdvdread: Device %s inaccessible, "
+ "CSS authentication not available.\n", dev_name );
+ }
+#else
+ if( !auth_drive ) {
+ fprintf( stderr, "libdvdread: Device %s inaccessible, "
+ "CSS authentication not available.\n", dev_name );
+ }
+#endif
+
+ free( dev_name );
+ free( path_copy );
+
+ /**
+ * If we've opened a drive, just use that.
+ */
+ if( auth_drive ) {
+ free(path);
+ return auth_drive;
+ }
+
+ /**
+ * Otherwise, we now try to open the directory tree instead.
+ */
+ ret_val = DVDOpenPath( path );
+ free( path );
+ return ret_val;
+ }
+
+ /* If it's none of the above, screw it. */
+ fprintf( stderr, "libdvdread: Could not open %s\n", path );
+ free( path );
+ return NULL;
+}
+
+void DVDClose( dvd_reader_t *dvd )
+{
+ if( dvd ) {
+ if( dvd->dev ) dvdinput_close( dvd->dev );
+ if( dvd->path_root ) free( dvd->path_root );
+ if( dvd->udfcache ) FreeUDFCache( dvd->udfcache );
+ free( dvd );
+ }
+}
+
+/**
+ * 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 ) {
+ fprintf( stderr, "libdvdnav:DVDOpenFileUDF:UDFFindFile %s failed\n", filename );
+ return NULL;
+ }
+
+ dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
+ if( !dvd_file ) {
+ fprintf( stderr, "libdvdnav:DVDOpenFileUDF:malloc failed\n" );
+ return NULL;
+ }
+ 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_devs, 0, sizeof( dvd_file->title_devs ) );
+ dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
+
+#ifdef WITH_CACHE
+ dvd_file->lb_cache = -1;
+#endif
+
+ 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 )
+{
+#if defined(_XBMC)
+ struct stat fileinfo;
+
+ // no emulated opendir function in xbmc, so we'll
+ // check if the file exists by stat'ing it ...
+ sprintf(filename, "%s%s%s", path,
+ ( ( path[ strlen( path ) - 1 ] == '/' ) ? "" : "/" ),
+ file );
+
+ if (stat(filename, &fileinfo) == 0) return 0;
+
+#else
+ 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 );
+ closedir( dir );
+ return 0;
+ }
+ }
+
+ closedir( dir );
+#endif // _XBMC
+ 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;
+ dvd_input_t dev;
+
+ /* Get the full path of the file. */
+ if( !findDVDFile( dvd, filename, full_path ) ) {
+ fprintf( stderr, "libdvdnav:DVDOpenFilePath:findDVDFile %s failed\n", filename );
+ return NULL;
+ }
+
+ dev = dvdinput_open( full_path );
+ if( !dev ) {
+ fprintf( stderr, "libdvdnav:DVDOpenFilePath:dvdinput_open %s failed\n", full_path );
+ return NULL;
+ }
+
+ dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
+ if( !dvd_file ) {
+ fprintf( stderr, "libdvdnav:DVDOpenFilePath:dvd_file malloc failed\n" );
+ dvdinput_close(dev);
+ return NULL;
+ }
+ 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_devs, 0, sizeof( dvd_file->title_devs ) );
+ dvd_file->filesize = 0;
+
+ if( stat( full_path, &fileinfo ) < 0 ) {
+ fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
+ free( dvd_file );
+ return NULL;
+ }
+ dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
+ dvd_file->title_devs[ 0 ] = dev;
+ dvd_file->filesize = dvd_file->title_sizes[ 0 ];
+
+#ifdef WITH_CACHE
+ dvd_file->lb_cache = -1;
+#endif
+ 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 NULL;
+
+ dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
+ if( !dvd_file ) return NULL;
+ dvd_file->dvd = dvd;
+ /*Hack*/ dvd_file->css_title = title << 1 | menu;
+ 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_devs, 0, sizeof( dvd_file->title_devs ) );
+ dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
+
+#ifdef WITH_CACHE
+ dvd_file->lb_cache = -1;
+#endif
+ /* 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( dvd->css_state == 1 /* Need key init */ ) {
+ initAllCSSKeys( dvd );
+ dvd->css_state = 2;
+ }
+ /*
+ if( dvdinput_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 NULL;
+ dvd_file->dvd = dvd;
+ /*Hack*/ dvd_file->css_title = title << 1 | menu;
+ 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_devs, 0, sizeof( dvd_file->title_devs ) );
+ dvd_file->filesize = 0;
+
+#ifdef WITH_CACHE
+ dvd_file->lb_cache = -1;
+#endif
+
+ if( menu ) {
+ dvd_input_t dev;
+
+ 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 NULL;
+ }
+
+ dev = dvdinput_open( full_path );
+ if( dev == NULL ) {
+ free( dvd_file );
+ return NULL;
+ }
+
+ if( stat( full_path, &fileinfo ) < 0 ) {
+ fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
+ dvdinput_close(dev);
+ free( dvd_file );
+ return NULL;
+ }
+ dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
+ dvd_file->title_devs[ 0 ] = dev;
+ dvdinput_title( dvd_file->title_devs[0], 0);
+ dvd_file->filesize = dvd_file->title_sizes[ 0 ];
+
+ } else {
+ for( i = 0; i < TITLES_MAX; ++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_devs[ i ] = dvdinput_open( full_path );
+ dvdinput_title( dvd_file->title_devs[ i ], 0 );
+ dvd_file->filesize += dvd_file->title_sizes[ i ];
+ }
+ if( !dvd_file->title_devs[ 0 ] ) {
+ free( dvd_file );
+ return NULL;
+ }
+ }
+
+ 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 ];
+
+ /* Check arguments. */
+ if( dvd == NULL || titlenum < 0 )
+ return NULL;
+
+ 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 NULL;
+ }
+
+ 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 ) {
+ ;
+ } else {
+ for( i = 0; i < TITLES_MAX; ++i ) {
+ if( dvd_file->title_devs[ i ] ) {
+ dvdinput_close( dvd_file->title_devs[i] );
+ }
+ }
+ }
+
+ free( dvd_file );
+ dvd_file = 0;
+ }
+}
+
+/* Internal, but used from dvd_udf.c */
+int UDFReadBlocksRaw( 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 = dvdinput_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;
+ }
+
+ ret = dvdinput_read( device->dev, (char *) data,
+ (int) block_count, encrypted );
+ return ret;
+}
+
+/* This is using a single input and starting from 'dvd_file->lb_start' offset.
+ *
+ * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset'
+ * into the buffer located at 'data' and if 'encrypted' is set
+ * descramble the data if it's encrypted. Returning either an
+ * negative error or the number of blocks read. */
+static int DVDReadBlocksUDF( dvd_file_t *dvd_file, uint32_t offset,
+ size_t block_count, unsigned char *data,
+ int encrypted )
+{
+ return UDFReadBlocksRaw( dvd_file->dvd, dvd_file->lb_start + offset,
+ block_count, data, encrypted );
+}
+
+/* This is using possibly several inputs and starting from an offset of '0'.
+ *
+ * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset'
+ * into the buffer located at 'data' and if 'encrypted' is set
+ * descramble the data if it's encrypted. Returning either an
+ * negative error or the number of blocks read. */
+static int DVDReadBlocksPath( dvd_file_t *dvd_file, unsigned int offset,
+ size_t block_count, unsigned char *data,
+ int encrypted )
+{
+ int i;
+ int ret, ret2, off;
+
+ ret = 0;
+ ret2 = 0;
+ for( i = 0; i < TITLES_MAX; ++i ) {
+ if( !dvd_file->title_sizes[ i ] ) return 0; /* Past end of file */
+
+ if( offset < dvd_file->title_sizes[ i ] ) {
+ if( ( offset + block_count ) <= dvd_file->title_sizes[ i ] ) {
+ off = dvdinput_seek( dvd_file->title_devs[ i ], (int)offset );
+ if( off < 0 || off != (int)offset ) {
+ fprintf( stderr, "libdvdread: Can't seek to block %d\n",
+ offset );
+ return off < 0 ? off : 0;
+ }
+ ret = dvdinput_read( dvd_file->title_devs[ i ], data,
+ (int)block_count, encrypted );
+ break;
+ } else {
+ size_t part1_size = dvd_file->title_sizes[ i ] - offset;
+ /* 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 = dvdinput_seek( dvd_file->title_devs[ i ], (int)offset );
+ if( off < 0 || off != (int)offset ) {
+ fprintf( stderr, "libdvdread: Can't seek to block %d\n",
+ offset );
+ return off < 0 ? off : 0;
+ }
+ ret = dvdinput_read( dvd_file->title_devs[ i ], data,
+ (int)part1_size, encrypted );
+ 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. */
+
+ /* Does the next part exist? If not then return now. */
+ if( i + 1 >= TITLES_MAX || !dvd_file->title_devs[ i + 1 ] )
+ return ret;
+
+ /* Read part 2 */
+ off = dvdinput_seek( dvd_file->title_devs[ i + 1 ], 0 );
+ if( off < 0 || off != 0 ) {
+ fprintf( stderr, "libdvdread: Can't seek to block %d\n",
+ 0 );
+ return off < 0 ? off : 0;
+ }
+ ret2 = dvdinput_read( dvd_file->title_devs[ i + 1 ],
+ data + ( part1_size
+ * (int64_t)DVD_VIDEO_LB_LEN ),
+ (int)(block_count - part1_size),
+ encrypted );
+ if( ret2 < 0 ) return ret2;
+ break;
+ }
+ } else {
+ offset -= dvd_file->title_sizes[ i ];
+ }
+ }
+
+ return ret + ret2;
+}
+
+#ifdef WITH_CACHE
+
+/* returns true aslong as the sector isn't all zeros */
+inline int DVDCheckSector(unsigned char *data, int offset)
+{
+ int i = 0;
+ int32_t *p = (int32_t*)data + (DVD_VIDEO_LB_LEN>>2)*offset;
+ for(;i<(DVD_VIDEO_LB_LEN<<2);i++) {
+ if(*(p+i) != 0)
+ break;
+ }
+ return (i!=(DVD_VIDEO_LB_LEN>>2));
+}
+
+int DVDReadBlocksCached( dvd_file_t *dvd_file, int offset,
+ size_t block_count, unsigned char *data, int encrypted )
+{
+ int ret=0;
+ /* Check arguments. */
+ if( dvd_file == NULL || offset < 0 || data == NULL )
+ return -1;
+
+ if(encrypted & DVDINPUT_READ_DECRYPT) {
+ /* Hack, and it will still fail for multiple opens in a threaded app ! */
+ if( dvd_file->dvd->css_title != dvd_file->css_title ) {
+ dvd_file->dvd->css_title = dvd_file->css_title;
+ if( dvd_file->dvd->isImageFile ) {
+ dvdinput_title( dvd_file->dvd->dev, (int)dvd_file->lb_start );
+ }
+ /* Here each vobu has it's own dvdcss handle, so no need to update
+ else {
+ dvdinput_title( dvd_file->title_devs[ 0 ], (int)dvd_file->lb_start );
+ }*/
+ }
+ }
+
+ /* check if first sector is in cache */
+ int cachehit = 0;
+ if( offset == dvd_file->lb_cache ) {
+ memcpy( data, dvd_file->cache, DVD_VIDEO_LB_LEN );
+ block_count--;
+ offset++;
+ data+=DVD_VIDEO_LB_LEN;
+ cachehit = 1;
+ }
+
+
+ if( block_count > 0 )
+ {
+ if( dvd_file->dvd->isImageFile )
+ ret = DVDReadBlocksUDF( dvd_file, (uint32_t)offset,
+ block_count, data, encrypted );
+ else
+ ret = DVDReadBlocksPath( dvd_file, (unsigned int)offset,
+ block_count, data, encrypted );
+
+ if(ret<0)
+ return ret;
+
+ /* here is a hack for drive wich don't handle layerchange properly */
+ /* they start returning zero data while laser is shifting position */
+ /* normally just doing a reread will get the correct data */
+ if( dvd_file->dvd->isImageFile )
+ {
+ /* check sectors from the back */
+ int count = ret; /* previous call could have returned fewer than requested */
+ int i = count-1;
+ for(;i>=0;i--)
+ if(!DVDCheckSector(data, i)) break;
+
+ if(i>=0) {
+ fprintf( stderr, "libdvdread: potential layer change. %d zero sectors detected starting at %d!\n", i+1, offset);
+
+ /* reread the invalid sectors */
+ count = DVDReadBlocksUDF( dvd_file, (uint32_t)offset+i,
+ count-i, data+DVD_VIDEO_LB_LEN*i, encrypted );
+
+ if(count<0)
+ return count;
+ }
+ }
+
+ }
+
+ if(ret>0)
+ { /* store last sector read into cache */
+ dvd_file->lb_cache = offset+ret-1;
+ memcpy( dvd_file->cache, data+(DVD_VIDEO_LB_LEN*(ret-1)), DVD_VIDEO_LB_LEN );
+ }
+
+ return (ssize_t)(ret+cachehit);
+}
+#endif
+
+/* This is broken reading more than 2Gb at a time is ssize_t is 32-bit. */
+ssize_t DVDReadBlocks( dvd_file_t *dvd_file, int offset,
+ size_t block_count, unsigned char *data )
+{
+ int ret;
+ /* Check arguments. */
+ if( dvd_file == NULL || offset < 0 || data == NULL )
+ return -1;
+
+#ifdef WITH_CACHE
+ return (ssize_t)DVDReadBlocksCached( dvd_file, offset, block_count, data, DVDINPUT_READ_DECRYPT );
+#endif
+
+ /* Hack, and it will still fail for multiple opens in a threaded app ! */
+ if( dvd_file->dvd->css_title != dvd_file->css_title ) {
+ dvd_file->dvd->css_title = dvd_file->css_title;
+ if( dvd_file->dvd->isImageFile ) {
+ dvdinput_title( dvd_file->dvd->dev, (int)dvd_file->lb_start );
+ }
+ /* Here each vobu has it's own dvdcss handle, so no need to update
+ else {
+ dvdinput_title( dvd_file->title_devs[ 0 ], (int)dvd_file->lb_start );
+ }*/
+ }
+
+ if( dvd_file->dvd->isImageFile ) {
+ ret = DVDReadBlocksUDF( dvd_file, (uint32_t)offset,
+ block_count, data, DVDINPUT_READ_DECRYPT );
+ } else {
+ ret = DVDReadBlocksPath( dvd_file, (unsigned int)offset,
+ block_count, data, DVDINPUT_READ_DECRYPT );
+ }
+
+ return (ssize_t)ret;
+}
+
+int32_t DVDFileSeek( dvd_file_t *dvd_file, int32_t offset )
+{
+ /* Check arguments. */
+ if( dvd_file == NULL || offset < 0 )
+ return -1;
+
+ if( offset > dvd_file->filesize * DVD_VIDEO_LB_LEN ) {
+ return -1;
+ }
+ dvd_file->seek_pos = (uint32_t) offset;
+ return offset;
+}
+
+int DVDFileSeekForce(dvd_file_t *dvd_file, int offset, int force_size)
+{
+ /* Check arguments. */
+ if( dvd_file == NULL || offset <= 0 )
+ return -1;
+
+ if( dvd_file->dvd->isImageFile ) {
+ if( force_size < 0 )
+ force_size = (offset - 1) / DVD_VIDEO_LB_LEN + 1;
+ if( dvd_file->filesize < force_size ) {
+ dvd_file->filesize = force_size;
+ fprintf(stderr, "libdvdread: Ignored size of file indicated in UDF.\n");
+ }
+ }
+
+ if( offset > dvd_file->filesize * DVD_VIDEO_LB_LEN )
+ return -1;
+
+ dvd_file->seek_pos = (uint32_t) offset;
+ return offset;
+}
+
+ssize_t DVDReadBytes( dvd_file_t *dvd_file, void *data, size_t byte_size )
+{
+ unsigned char *secbuf_base, *secbuf;
+ unsigned int numsec, seek_sector, seek_byte;
+ int ret;
+
+ /* Check arguments. */
+ if( dvd_file == NULL || data == NULL )
+ return -1;
+
+ 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 ) +
+ ( ( ( seek_byte + byte_size ) % DVD_VIDEO_LB_LEN ) ? 1 : 0 );
+
+ secbuf_base = (unsigned char *) malloc( numsec * DVD_VIDEO_LB_LEN + 2048 );
+ secbuf = (unsigned char *)(((uintptr_t)secbuf_base & ~((uintptr_t)2047)) + 2048);
+ if( !secbuf_base ) {
+ fprintf( stderr, "libdvdread: Can't allocate memory "
+ "for file read!\n" );
+ return 0;
+ }
+
+#ifdef WITH_CACHE
+ ret = DVDReadBlocksCached( dvd_file, (uint32_t) seek_sector,
+ (size_t) numsec, secbuf, DVDINPUT_NOFLAGS );
+#else
+ if( dvd_file->dvd->isImageFile ) {
+ ret = DVDReadBlocksUDF( dvd_file, (uint32_t) seek_sector,
+ (size_t) numsec, secbuf, DVDINPUT_NOFLAGS );
+ } else {
+ ret = DVDReadBlocksPath( dvd_file, seek_sector,
+ (size_t) numsec, secbuf, DVDINPUT_NOFLAGS );
+ }
+#endif
+
+ if( ret != (int) numsec ) {
+ free( secbuf_base );
+ return ret < 0 ? ret : 0;
+ }
+
+ memcpy( data, &(secbuf[ seek_byte ]), byte_size );
+ free( secbuf_base );
+
+ DVDFileSeekForce(dvd_file, dvd_file->seek_pos + byte_size, -1);
+ return byte_size;
+}
+
+ssize_t DVDFileSize( dvd_file_t *dvd_file )
+{
+ /* Check arguments. */
+ if( dvd_file == NULL )
+ return -1;
+
+ return dvd_file->filesize;
+}
+
+int DVDDiscID( dvd_reader_t *dvd, unsigned char *discid )
+{
+ struct md5_ctx ctx;
+ int title;
+ int nr_of_files = 0;
+
+ /* Check arguments. */
+ if( dvd == NULL || discid == NULL )
+ return 0;
+
+ /* Go through the first 10 IFO:s, in order,
+ * and md5sum them, i.e VIDEO_TS.IFO and VTS_0?_0.IFO */
+ md5_init_ctx( &ctx );
+ for( title = 0; title < 10; title++ ) {
+ dvd_file_t *dvd_file = DVDOpenFile( dvd, title, DVD_READ_INFO_FILE );
+ if( dvd_file != NULL ) {
+ ssize_t bytes_read;
+ size_t file_size = dvd_file->filesize * DVD_VIDEO_LB_LEN;
+ char *buffer_base = malloc( file_size + 2048 );
+ char *buffer = (char *)(((uintptr_t)buffer_base & ~((uintptr_t)2047)) + 2048);
+
+ if( buffer_base == NULL ) {
+ DVDCloseFile( dvd_file );
+ fprintf( stderr, "libdvdread: DVDDiscId, failed to "
+ "allocate memory for file read!\n" );
+ return -1;
+ }
+ bytes_read = DVDReadBytes( dvd_file, buffer, file_size );
+ if( bytes_read != file_size ) {
+ fprintf( stderr, "libdvdread: DVDDiscId read returned %zd bytes"
+ ", wanted %zd\n", bytes_read, file_size );
+ DVDCloseFile( dvd_file );
+ free( buffer_base );
+ return -1;
+ }
+
+ md5_process_bytes( buffer, file_size, &ctx );
+
+ DVDCloseFile( dvd_file );
+ free( buffer_base );
+ nr_of_files++;
+ }
+ }
+ md5_finish_ctx( &ctx, discid );
+ if(!nr_of_files)
+ return -1;
+
+ return 0;
+}
+
+
+int DVDISOVolumeInfo( dvd_reader_t *dvd,
+ char *volid, unsigned int volid_size,
+ unsigned char *volsetid, unsigned int volsetid_size )
+{
+ unsigned char *buffer, *buffer_base;
+ int ret;
+
+ /* Check arguments. */
+ if( dvd == NULL )
+ return 0;
+
+ if( dvd->dev == NULL ) {
+ /* No block access, so no ISO... */
+ return -1;
+ }
+
+ buffer_base = malloc( DVD_VIDEO_LB_LEN + 2048 );
+ buffer = (unsigned char *)(((uintptr_t)buffer_base & ~((uintptr_t)2047)) + 2048);
+
+ if( buffer_base == NULL ) {
+ fprintf( stderr, "libdvdread: DVDISOVolumeInfo, failed to "
+ "allocate memory for file read!\n" );
+ return -1;
+ }
+
+ ret = UDFReadBlocksRaw( dvd, 16, 1, buffer, 0 );
+ if( ret != 1 ) {
+ fprintf( stderr, "libdvdread: DVDISOVolumeInfo, failed to "
+ "read ISO9660 Primary Volume Descriptor!\n" );
+ free( buffer_base );
+ return -1;
+ }
+
+ if( (volid != NULL) && (volid_size > 0) ) {
+ unsigned int n;
+ for(n = 0; n < 32; n++) {
+ if(buffer[40+n] == 0x20) {
+ break;
+ }
+ }
+
+ if(volid_size > n+1) {
+ volid_size = n+1;
+ }
+
+ memcpy(volid, &buffer[40], volid_size-1);
+ volid[volid_size-1] = '\0';
+ }
+
+ if( (volsetid != NULL) && (volsetid_size > 0) ) {
+ if(volsetid_size > 128) {
+ volsetid_size = 128;
+ }
+ memcpy(volsetid, &buffer[190], volsetid_size);
+ }
+ free( buffer_base );
+ return 0;
+}
+
+
+int DVDUDFVolumeInfo( dvd_reader_t *dvd,
+ char *volid, unsigned int volid_size,
+ unsigned char *volsetid, unsigned int volsetid_size )
+{
+ int ret;
+ /* Check arguments. */
+ if( dvd == NULL )
+ return -1;
+
+ if( dvd->dev == NULL ) {
+ /* No block access, so no UDF VolumeSet Identifier */
+ return -1;
+ }
+
+ if( (volid != NULL) && (volid_size > 0) ) {
+ ret = UDFGetVolumeIdentifier(dvd, volid, volid_size);
+ if(!ret) {
+ return -1;
+ }
+ }
+ if( (volsetid != NULL) && (volsetid_size > 0) ) {
+ ret = UDFGetVolumeSetIdentifier(dvd, volsetid, volsetid_size);
+ if(!ret) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/lib/libdvd/libdvdread/src/dvd_reader.h b/lib/libdvd/libdvdread/src/dvd_reader.h
new file mode 100644
index 0000000000..8c91242c98
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/dvd_reader.h
@@ -0,0 +1,275 @@
+#ifndef DVD_READER_H_INCLUDED
+#define DVD_READER_H_INCLUDED
+
+/*
+ * Copyright (C) 2001, 2002 Billy Biggs <vektor@dumbterm.net>,
+ * Håkan Hjort <d95hjort@dtek.chalmers.se>,
+ * Björn Englund <d4bjorn@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
+ */
+
+#ifdef _MSC_VER
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#endif
+
+#include <sys/types.h>
+#include <inttypes.h>
+
+/**
+ * The DVD access interface.
+ *
+ * This file contains the functions that form the interface to to
+ * reading files located on a DVD.
+ */
+
+/**
+ * The current version.
+ */
+#define DVDREAD_VERSION 904
+
+/**
+ * The length of one Logical Block of a DVD.
+ */
+#define DVD_VIDEO_LB_LEN 2048
+
+/**
+ * Maximum length of filenames allowed in UDF.
+ */
+#define MAX_UDF_FILE_NAME_LEN 2048
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Opaque type that is used as a handle for one instance of an opened DVD.
+ */
+typedef struct dvd_reader_s dvd_reader_t;
+
+/**
+ * Opaque type for a file read handle, much like a normal fd or FILE *.
+ */
+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.
+ *
+ * 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
+ *
+ * @param path Specifies the the device, file or directory to be used.
+ * @return If successful a a read handle is returned. Otherwise 0 is returned.
+ *
+ * dvd = DVDOpen(path);
+ */
+dvd_reader_t *DVDOpen( const char * );
+
+/**
+ * Closes and cleans up the DVD reader object.
+ *
+ * You must close all open files before calling this function.
+ *
+ * @param dvd A read handle that should be closed.
+ *
+ * DVDClose(dvd);
+ */
+void DVDClose( dvd_reader_t * );
+
+/**
+ *
+ */
+typedef enum {
+ DVD_READ_INFO_FILE, /**< VIDEO_TS.IFO or VTS_XX_0.IFO (title) */
+ DVD_READ_INFO_BACKUP_FILE, /**< VIDEO_TS.BUP or VTS_XX_0.BUP (title) */
+ DVD_READ_MENU_VOBS, /**< VIDEO_TS.VOB or VTS_XX_0.VOB (title) */
+ DVD_READ_TITLE_VOBS /**< VTS_XX_[1-9].VOB (title). All files in
+ the title set are opened and read as a
+ single file. */
+} 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.
+ *
+ * @param dvd A dvd read handle.
+ * @param titlenum Which Video Title Set should be used, VIDEO_TS is 0.
+ * @param domain Which domain.
+ * @return If successful a a file read handle is returned, otherwise 0.
+ *
+ * dvd_file = DVDOpenFile(dvd, titlenum, domain); */
+dvd_file_t *DVDOpenFile( dvd_reader_t *, int, dvd_read_domain_t );
+
+/**
+ * Closes a file and frees the associated structure.
+ *
+ * @param dvd_file The file read handle to be closed.
+ *
+ * DVDCloseFile(dvd_file);
+ */
+void DVDCloseFile( dvd_file_t * );
+
+/**
+ * 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.
+ *
+ * @param dvd_file A file read handle.
+ * @param offset Block offset from the start of the file to start reading at.
+ * @param block_count Number of block to read.
+ * @param data Pointer to a buffer to write the data into.
+ * @return Returns number of blocks read on success, -1 on error.
+ *
+ * blocks_read = DVDReadBlocks(dvd_file, offset, block_count, data);
+ */
+ssize_t DVDReadBlocks( dvd_file_t *, int, size_t, unsigned char * );
+
+/**
+ * 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.
+ *
+ * @param dvd_file A file read handle.
+ * @param seek_offset Byte offset from the start of the file to seek to.
+ * @return The resulting position in bytes from the beginning of the file.
+ *
+ * offset_set = DVDFileSeek(dvd_file, seek_offset);
+ */
+int32_t DVDFileSeek( dvd_file_t *, int32_t );
+
+/**
+ * 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.
+ *
+ * @param dvd_file A file read handle.
+ * @param data Pointer to a buffer to write the data into.
+ * @param bytes Number of bytes to read.
+ * @return Returns number of bytes read on success, -1 on error.
+ *
+ * bytes_read = DVDReadBytes(dvd_file, data, bytes);
+ */
+ssize_t DVDReadBytes( dvd_file_t *, void *, size_t );
+
+/**
+ * Returns the file size in blocks.
+ *
+ * @param dvd_file A file read handle.
+ * @return The size of the file in blocks, -1 on error.
+ *
+ * blocks = DVDFileSize(dvd_file);
+ */
+ssize_t DVDFileSize( dvd_file_t * );
+
+/**
+ * Get a unique 128 bit disc ID.
+ * This is the MD5 sum of VIDEO_TS.IFO and the VTS_0?_0.IFO files
+ * in title order (those that exist).
+ * If you need a 'text' representation of the id, print it as a
+ * hexadecimal number, using lowercase letters, discid[0] first.
+ * I.e. the same format as the command-line 'md5sum' program uses.
+ *
+ * @param dvd A read handle to get the disc ID from
+ * @param discid The buffer to put the disc ID into. The buffer must
+ * have room for 128 bits (16 chars).
+ * @return 0 on success, -1 on error.
+ */
+int DVDDiscID( dvd_reader_t *, unsigned char * );
+
+/**
+ * Get the UDF VolumeIdentifier and VolumeSetIdentifier
+ * from the PrimaryVolumeDescriptor.
+ *
+ * @param dvd A read handle to get the disc ID from
+ * @param volid The buffer to put the VolumeIdentifier into.
+ * The VolumeIdentifier is latin-1 encoded (8bit unicode)
+ * null terminated and max 32 bytes (including '\0')
+ * @param volid_size No more than volid_size bytes will be copied to volid.
+ * If the VolumeIdentifier is truncated because of this
+ * it will still be null terminated.
+ * @param volsetid The buffer to put the VolumeSetIdentifier into.
+ * The VolumeIdentifier is 128 bytes as
+ * stored in the UDF PrimaryVolumeDescriptor.
+ * Note that this is not a null terminated string.
+ * @param volsetid_size At most volsetid_size bytes will be copied to volsetid.
+ * @return 0 on success, -1 on error.
+ */
+int DVDUDFVolumeInfo( dvd_reader_t *, char *, unsigned int,
+ unsigned char *, unsigned int );
+
+int DVDFileSeekForce( dvd_file_t *, int offset, int force_size);
+
+/**
+ * Get the ISO9660 VolumeIdentifier and VolumeSetIdentifier
+ *
+ * * Only use this function as fallback if DVDUDFVolumeInfo returns 0 *
+ * * this will happen on a disc mastered only with a iso9660 filesystem *
+ * * All video DVD discs have UDF filesystem *
+ *
+ * @param dvd A read handle to get the disc ID from
+ * @param volid The buffer to put the VolumeIdentifier into.
+ * The VolumeIdentifier is coded with '0-9','A-Z','_'
+ * null terminated and max 33 bytes (including '\0')
+ * @param volid_size No more than volid_size bytes will be copied to volid.
+ * If the VolumeIdentifier is truncated because of this
+ * it will still be null terminated.
+ * @param volsetid The buffer to put the VolumeSetIdentifier into.
+ * The VolumeIdentifier is 128 bytes as
+ * stored in the ISO9660 PrimaryVolumeDescriptor.
+ * Note that this is not a null terminated string.
+ * @param volsetid_size At most volsetid_size bytes will be copied to volsetid.
+ * @return 0 on success, -1 on error.
+ */
+int DVDISOVolumeInfo( dvd_reader_t *, char *, unsigned int,
+ unsigned char *, unsigned int );
+
+/**
+ * Sets the level of caching that is done when reading from a device
+ *
+ * @param dvd A read handle to get the disc ID from
+ * @param level The level of caching wanted.
+ * -1 - returns the current setting.
+ * 0 - UDF Cache turned off.
+ * 1 - (default level) Pointers to IFO files and some data from
+ * PrimaryVolumeDescriptor are cached.
+ *
+ * @return The level of caching.
+ */
+int DVDUDFCacheLevel( dvd_reader_t *, int );
+
+#ifdef __cplusplus
+};
+#endif
+#endif /* DVD_READER_H_INCLUDED */
diff --git a/lib/libdvd/libdvdread/src/dvd_udf.c b/lib/libdvd/libdvdread/src/dvd_udf.c
new file mode 100644
index 0000000000..26a663a1c9
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/dvd_udf.c
@@ -0,0 +1,968 @@
+/*
+ * This code is based on dvdudf by:
+ * Christian Wolff <scarabaeus@convergence.de>.
+ *
+ * Modifications by:
+ * Billy Biggs <vektor@dumbterm.net>.
+ * Björn Englund <d4bjorn@dtek.chalmers.se>.
+ *
+ * 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 "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "dvd_reader.h"
+#include "dvd_udf.h"
+
+/* Private but located in/shared with dvd_reader.c */
+extern int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number,
+ size_t block_count, unsigned char *data,
+ int encrypted );
+
+/* It's required to either fail or deliver all the blocks asked for. */
+static int DVDReadLBUDF( dvd_reader_t *device, uint32_t lb_number,
+ size_t block_count, unsigned char *data,
+ int encrypted )
+{
+ int ret;
+ size_t count = block_count;
+
+ while(count > 0) {
+ ret = UDFReadBlocksRaw(device, lb_number, count, data, encrypted);
+
+ if(ret <= 0) {
+ /* One of the reads failed or nothing more to read, too bad.
+ * We won't even bother returning the reads that went ok. */
+ return ret;
+ }
+
+ count -= (size_t)ret;
+ lb_number += (uint32_t)ret;
+ }
+
+ return block_count;
+}
+
+
+#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;
+};
+
+struct extent_ad {
+ uint32_t location;
+ uint32_t length;
+};
+
+struct avdp_t {
+ struct extent_ad mvds;
+ struct extent_ad rvds;
+};
+
+struct pvd_t {
+ uint8_t VolumeIdentifier[32];
+ uint8_t VolumeSetIdentifier[128];
+};
+
+struct lbudf {
+ uint32_t lb;
+ uint8_t *data;
+ /* needed for proper freeing */
+ uint8_t *data_base;
+};
+
+struct icbmap {
+ uint32_t lbn;
+ struct AD file;
+ uint8_t filetype;
+};
+
+struct udf_cache {
+ int avdp_valid;
+ struct avdp_t avdp;
+ int pvd_valid;
+ struct pvd_t pvd;
+ int partition_valid;
+ struct Partition partition;
+ int rooticb_valid;
+ struct AD rooticb;
+ int lb_num;
+ struct lbudf *lbs;
+ int map_num;
+ struct icbmap *maps;
+};
+
+typedef enum {
+ PartitionCache, RootICBCache, LBUDFCache, MapCache, AVDPCache, PVDCache
+} UDFCacheType;
+
+void FreeUDFCache(void *cache)
+{
+ struct udf_cache *c = (struct udf_cache *)cache;
+ if(c == NULL)
+ return;
+
+ if(c->lbs) {
+ int n;
+ for(n = 0; n < c->lb_num; n++)
+ free(c->lbs[n].data_base);
+ free(c->lbs);
+ }
+ if(c->maps)
+ free(c->maps);
+ free(c);
+}
+
+
+static int GetUDFCache(dvd_reader_t *device, UDFCacheType type,
+ uint32_t nr, void *data)
+{
+ int n;
+ struct udf_cache *c;
+
+ if(DVDUDFCacheLevel(device, -1) <= 0)
+ return 0;
+
+ c = (struct udf_cache *)GetUDFCacheHandle(device);
+
+ if(c == NULL)
+ return 0;
+
+ switch(type) {
+ case AVDPCache:
+ if(c->avdp_valid) {
+ *(struct avdp_t *)data = c->avdp;
+ return 1;
+ }
+ break;
+ case PVDCache:
+ if(c->pvd_valid) {
+ *(struct pvd_t *)data = c->pvd;
+ return 1;
+ }
+ break;
+ case PartitionCache:
+ if(c->partition_valid) {
+ *(struct Partition *)data = c->partition;
+ return 1;
+ }
+ break;
+ case RootICBCache:
+ if(c->rooticb_valid) {
+ *(struct AD *)data = c->rooticb;
+ return 1;
+ }
+ break;
+ case LBUDFCache:
+ for(n = 0; n < c->lb_num; n++) {
+ if(c->lbs[n].lb == nr) {
+ *(uint8_t **)data = c->lbs[n].data;
+ return 1;
+ }
+ }
+ break;
+ case MapCache:
+ for(n = 0; n < c->map_num; n++) {
+ if(c->maps[n].lbn == nr) {
+ *(struct icbmap *)data = c->maps[n];
+ return 1;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int SetUDFCache(dvd_reader_t *device, UDFCacheType type,
+ uint32_t nr, void *data)
+{
+ int n;
+ struct udf_cache *c;
+ void *tmp;
+
+ if(DVDUDFCacheLevel(device, -1) <= 0)
+ return 0;
+
+ c = (struct udf_cache *)GetUDFCacheHandle(device);
+
+ if(c == NULL) {
+ c = calloc(1, sizeof(struct udf_cache));
+ /* fprintf(stderr, "calloc: %d\n", sizeof(struct udf_cache)); */
+ if(c == NULL)
+ return 0;
+ SetUDFCacheHandle(device, c);
+ }
+
+
+ switch(type) {
+ case AVDPCache:
+ c->avdp = *(struct avdp_t *)data;
+ c->avdp_valid = 1;
+ break;
+ case PVDCache:
+ c->pvd = *(struct pvd_t *)data;
+ c->pvd_valid = 1;
+ break;
+ case PartitionCache:
+ c->partition = *(struct Partition *)data;
+ c->partition_valid = 1;
+ break;
+ case RootICBCache:
+ c->rooticb = *(struct AD *)data;
+ c->rooticb_valid = 1;
+ break;
+ case LBUDFCache:
+ for(n = 0; n < c->lb_num; n++) {
+ if(c->lbs[n].lb == nr) {
+ /* replace with new data */
+ c->lbs[n].data_base = ((uint8_t **)data)[0];
+ c->lbs[n].data = ((uint8_t **)data)[1];
+ c->lbs[n].lb = nr;
+ return 1;
+ }
+ }
+ c->lb_num++;
+ tmp = realloc(c->lbs, c->lb_num * sizeof(struct lbudf));
+ /*
+ fprintf(stderr, "realloc lb: %d * %d = %d\n",
+ c->lb_num, sizeof(struct lbudf),
+ c->lb_num * sizeof(struct lbudf));
+ */
+ if(tmp == NULL) {
+ if(c->lbs) free(c->lbs);
+ c->lb_num = 0;
+ return 0;
+ }
+ c->lbs = tmp;
+ c->lbs[n].data_base = ((uint8_t **)data)[0];
+ c->lbs[n].data = ((uint8_t **)data)[1];
+ c->lbs[n].lb = nr;
+ break;
+ case MapCache:
+ for(n = 0; n < c->map_num; n++) {
+ if(c->maps[n].lbn == nr) {
+ /* replace with new data */
+ c->maps[n] = *(struct icbmap *)data;
+ c->maps[n].lbn = nr;
+ return 1;
+ }
+ }
+ c->map_num++;
+ tmp = realloc(c->maps, c->map_num * sizeof(struct icbmap));
+ /*
+ fprintf(stderr, "realloc maps: %d * %d = %d\n",
+ c->map_num, sizeof(struct icbmap),
+ c->map_num * sizeof(struct icbmap));
+ */
+ if(tmp == NULL) {
+ if(c->maps) free(c->maps);
+ c->map_num = 0;
+ return 0;
+ }
+ c->maps = tmp;
+ c->maps[n] = *(struct icbmap *)data;
+ c->maps[n].lbn = nr;
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* 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_base[DVD_VIDEO_LB_LEN + 2048];
+ uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & ~((uintptr_t)2047)) + 2048);
+ uint32_t lbnum;
+ uint16_t TagID;
+ struct icbmap tmpmap;
+
+ lbnum = partition->Start + ICB.Location;
+ tmpmap.lbn = lbnum;
+ if(GetUDFCache(device, MapCache, lbnum, &tmpmap)) {
+ *FileType = tmpmap.filetype;
+ memcpy(File, &tmpmap.file, sizeof(tmpmap.file));
+ return 1;
+ }
+
+ do {
+ if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 )
+ TagID = 0;
+ else
+ UDFDescriptor( LogBlock, &TagID );
+
+ if( TagID == 261 ) {
+ UDFFileEntry( LogBlock, FileType, partition, File );
+ memcpy(&tmpmap.file, File, sizeof(tmpmap.file));
+ tmpmap.filetype = *FileType;
+ SetUDFCache(device, MapCache, tmpmap.lbn, &tmpmap);
+ 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,
+ int cache_file_info)
+{
+ char filename[ MAX_UDF_FILE_NAME_LEN ];
+ uint8_t directory_base[ 2 * DVD_VIDEO_LB_LEN + 2048];
+ uint8_t *directory = (uint8_t *)(((uintptr_t)directory_base & ~((uintptr_t)2047)) + 2048);
+ uint32_t lbnum;
+ uint16_t TagID;
+ uint8_t filechar;
+ unsigned int p;
+ uint8_t *cached_dir_base = NULL, *cached_dir;
+ uint32_t dir_lba;
+ struct AD tmpICB;
+ int found = 0;
+ int in_cache = 0;
+
+ /* Scan dir for ICB of file */
+ lbnum = partition->Start + Dir.Location;
+
+ if(DVDUDFCacheLevel(device, -1) > 0) {
+ /* caching */
+
+ if(!GetUDFCache(device, LBUDFCache, lbnum, &cached_dir)) {
+ dir_lba = (Dir.Length + DVD_VIDEO_LB_LEN) / DVD_VIDEO_LB_LEN;
+ if((cached_dir_base = malloc(dir_lba * DVD_VIDEO_LB_LEN + 2048)) == NULL)
+ return 0;
+
+ cached_dir = (uint8_t *)(((uintptr_t)cached_dir_base & ~((uintptr_t)2047)) + 2048);
+ if( DVDReadLBUDF( device, lbnum, dir_lba, cached_dir, 0) <= 0 ) {
+ free(cached_dir_base);
+ cached_dir_base = NULL;
+ cached_dir = NULL;
+ }
+ /*
+ if(cached_dir) {
+ fprintf(stderr, "malloc dir: %d\n", dir_lba * DVD_VIDEO_LB_LEN);
+ }
+ */
+ {
+ uint8_t *data[2];
+ data[0] = cached_dir_base;
+ data[1] = cached_dir;
+ SetUDFCache(device, LBUDFCache, lbnum, data);
+ }
+ } else
+ in_cache = 1;
+
+ if(cached_dir == NULL)
+ return 0;
+
+ p = 0;
+
+ while( p < Dir.Length ) {
+ UDFDescriptor( &cached_dir[ p ], &TagID );
+ if( TagID == 257 ) {
+ p += UDFFileIdentifier( &cached_dir[ p ], &filechar, filename, &tmpICB );
+ if(cache_file_info && !in_cache) {
+ uint8_t tmpFiletype;
+ struct AD tmpFile;
+
+ if( !strcasecmp( FileName, filename ) ) {
+ memcpy(FileICB, &tmpICB, sizeof(tmpICB));
+ found = 1;
+ }
+ UDFMapICB(device, tmpICB, &tmpFiletype, partition, &tmpFile);
+ } else {
+ if( !strcasecmp( FileName, filename ) ) {
+ memcpy(FileICB, &tmpICB, sizeof(tmpICB));
+ return 1;
+ }
+ }
+ } else {
+ if(cache_file_info && (!in_cache) && found)
+ return 1;
+ return 0;
+ }
+ }
+ if(cache_file_info && (!in_cache) && found)
+ return 1;
+ return 0;
+ }
+
+ 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;
+}
+
+
+static int UDFGetAVDP( dvd_reader_t *device,
+ struct avdp_t *avdp)
+{
+ uint8_t Anchor_base[ DVD_VIDEO_LB_LEN + 2048 ];
+ uint8_t *Anchor = (uint8_t *)(((uintptr_t)Anchor_base & ~((uintptr_t)2047)) + 2048);
+ uint32_t lbnum, MVDS_location, MVDS_length;
+ uint16_t TagID;
+ uint32_t lastsector;
+ int terminate;
+ struct avdp_t;
+
+ if(GetUDFCache(device, AVDPCache, 0, avdp))
+ return 1;
+
+ /* 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 );
+ avdp->mvds.location = MVDS_location;
+ avdp->mvds.length = MVDS_length;
+
+ /* Backup volume descriptor */
+ UDFExtentAD( &Anchor[ 24 ], &MVDS_length, &MVDS_location );
+ avdp->rvds.location = MVDS_location;
+ avdp->rvds.length = MVDS_length;
+
+ SetUDFCache(device, AVDPCache, 0, avdp);
+
+ return 1;
+}
+
+/**
+ * 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_base[ DVD_VIDEO_LB_LEN + 2048 ];
+ uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & ~((uintptr_t)2047)) + 2048);
+ uint32_t lbnum, MVDS_location, MVDS_length;
+ uint16_t TagID;
+ int i, volvalid;
+ struct avdp_t avdp;
+
+ if(!UDFGetAVDP(device, &avdp))
+ return 0;
+
+ /* Main volume descriptor */
+ MVDS_location = avdp.mvds.location;
+ MVDS_length = avdp.mvds.length;
+
+ 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 */
+ MVDS_location = avdp.mvds.location;
+ MVDS_length = avdp.mvds.length;
+ }
+ } 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_base[ DVD_VIDEO_LB_LEN + 2048 ];
+ uint8_t *LogBlock = (uint8_t *)(((uintptr_t)LogBlock_base & ~((uintptr_t)2047)) + 2048);
+ 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';
+ strncat(tokenline, filename, MAX_UDF_FILE_NAME_LEN - 1);
+ memset(&ICB, 0, sizeof(ICB));
+
+ if(!(GetUDFCache(device, PartitionCache, 0, &partition) &&
+ GetUDFCache(device, RootICBCache, 0, &RootICB))) {
+ /* Find partition, 0 is the standard location for DVD Video.*/
+ if( !UDFFindPartition( device, 0, &partition ) ) return 0;
+ SetUDFCache(device, PartitionCache, 0, &partition);
+
+ /* 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;
+ SetUDFCache(device, RootICBCache, 0, &RootICB);
+ }
+
+ /* Find root dir */
+ if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) ) return 0;
+ if( filetype != 4 ) return 0; /* Root dir should be dir */
+
+ {
+ int cache_file_info = 0;
+ /* Tokenize filepath */
+ token = strtok(tokenline, "/");
+ while( token != NULL ) {
+ if( !UDFScanDir( device, File, token, &partition, &ICB,
+ cache_file_info))
+ return 0;
+ if( !UDFMapICB( device, ICB, &filetype, &partition, &File ) )
+ return 0;
+ if(!strcmp(token, "VIDEO_TS"))
+ cache_file_info = 1;
+ 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;
+}
+
+
+
+/**
+ * Gets a Descriptor .
+ * Returns 1 if descriptor found, 0 on error.
+ * id, tagid of descriptor
+ * bufsize, size of BlockBuf (must be >= DVD_VIDEO_LB_LEN).
+ */
+static int UDFGetDescriptor( dvd_reader_t *device, int id,
+ uint8_t *descriptor, int bufsize)
+{
+ uint32_t lbnum, MVDS_location, MVDS_length;
+ struct avdp_t avdp;
+ uint16_t TagID;
+ uint32_t lastsector;
+ int i, terminate;
+ int desc_found = 0;
+ /* Find Anchor */
+ lastsector = 0;
+ lbnum = 256; /* Try #1, prime anchor */
+ terminate = 0;
+ if(bufsize < DVD_VIDEO_LB_LEN)
+ return 0;
+
+ if(!UDFGetAVDP(device, &avdp))
+ return 0;
+
+ /* Main volume descriptor */
+ MVDS_location = avdp.mvds.location;
+ MVDS_length = avdp.mvds.length;
+ i = 1;
+ do {
+ /* Find Descriptor */
+ lbnum = MVDS_location;
+ do {
+ if( DVDReadLBUDF( device, lbnum++, 1, descriptor, 0 ) <= 0 )
+ TagID = 0;
+ else
+ UDFDescriptor( descriptor, &TagID );
+ if( (TagID == id) && ( !desc_found ) )
+ /* Descriptor */
+ desc_found = 1;
+ } while( ( lbnum <= MVDS_location + ( MVDS_length - 1 )
+ / DVD_VIDEO_LB_LEN ) && ( TagID != 8 )
+ && ( !desc_found) );
+
+ if( !desc_found ) {
+ /* Backup volume descriptor */
+ MVDS_location = avdp.rvds.location;
+ MVDS_length = avdp.rvds.length;
+ }
+ } while( i-- && ( !desc_found ) );
+
+ return desc_found;
+}
+
+
+static int UDFGetPVD(dvd_reader_t *device, struct pvd_t *pvd)
+{
+ uint8_t pvd_buf_base[DVD_VIDEO_LB_LEN + 2048];
+ uint8_t *pvd_buf = (uint8_t *)(((uintptr_t)pvd_buf_base & ~((uintptr_t)2047)) + 2048);
+ if(GetUDFCache(device, PVDCache, 0, pvd))
+ return 1;
+
+ if(!UDFGetDescriptor( device, 1, pvd_buf, sizeof(pvd_buf)))
+ return 0;
+
+ memcpy(pvd->VolumeIdentifier, &pvd_buf[24], 32);
+ memcpy(pvd->VolumeSetIdentifier, &pvd_buf[72], 128);
+ SetUDFCache(device, PVDCache, 0, pvd);
+ return 1;
+}
+
+/**
+ * Gets the Volume Identifier string, in 8bit unicode (latin-1)
+ * volid, place to put the string
+ * volid_size, size of the buffer volid points to
+ * returns the size of buffer needed for all data
+ */
+int UDFGetVolumeIdentifier(dvd_reader_t *device, char *volid,
+ unsigned int volid_size)
+{
+ struct pvd_t pvd;
+ unsigned int volid_len;
+
+ /* get primary volume descriptor */
+ if(!UDFGetPVD(device, &pvd))
+ return 0;
+
+ volid_len = pvd.VolumeIdentifier[31];
+ if(volid_len > 31)
+ /* this field is only 32 bytes something is wrong */
+ volid_len = 31;
+ if(volid_size > volid_len)
+ volid_size = volid_len;
+ Unicodedecode(pvd.VolumeIdentifier, volid_size, volid);
+ return volid_len;
+}
+
+/**
+ * Gets the Volume Set Identifier, as a 128-byte dstring (not decoded)
+ * WARNING This is not a null terminated string
+ * volsetid, place to put the data
+ * volsetid_size, size of the buffer volsetid points to
+ * the buffer should be >=128 bytes to store the whole volumesetidentifier
+ * returns the size of the available volsetid information (128)
+ * or 0 on error
+ */
+int UDFGetVolumeSetIdentifier(dvd_reader_t *device, uint8_t *volsetid,
+ unsigned int volsetid_size)
+{
+ struct pvd_t pvd;
+
+ /* get primary volume descriptor */
+ if(!UDFGetPVD(device, &pvd))
+ return 0;
+
+
+ if(volsetid_size > 128)
+ volsetid_size = 128;
+
+ memcpy(volsetid, pvd.VolumeSetIdentifier, volsetid_size);
+ return 128;
+}
diff --git a/lib/libdvd/libdvdread/src/dvd_udf.h b/lib/libdvd/libdvdread/src/dvd_udf.h
new file mode 100644
index 0000000000..3f38e8070c
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/dvd_udf.h
@@ -0,0 +1,62 @@
+#ifndef DVD_UDF_H_INCLUDED
+#define DVD_UDF_H_INCLUDED
+
+/*
+ * This code is based on dvdudf by:
+ * Christian Wolff <scarabaeus@convergence.de>.
+ *
+ * Modifications by:
+ * Billy Biggs <vektor@dumbterm.net>.
+ * Björn Englund <d4bjorn@dtek.chalmers.se>.
+ *
+ * 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 <inttypes.h>
+
+#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 );
+
+void FreeUDFCache(void *cache);
+int UDFGetVolumeIdentifier(dvd_reader_t *device,
+ char *volid, unsigned int volid_size);
+int UDFGetVolumeSetIdentifier(dvd_reader_t *device,
+ uint8_t *volsetid, unsigned int volsetid_size);
+void *GetUDFCacheHandle(dvd_reader_t *device);
+void SetUDFCacheHandle(dvd_reader_t *device, void *cache);
+
+#ifdef __cplusplus
+};
+#endif
+#endif /* DVD_UDF_H_INCLUDED */
diff --git a/lib/libdvd/libdvdread/src/dvdread_internal.h b/lib/libdvd/libdvdread/src/dvdread_internal.h
new file mode 100644
index 0000000000..ed9fd0f7a9
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/dvdread_internal.h
@@ -0,0 +1,15 @@
+#ifndef DVDREAD_INTERNAL_H
+#define DVDREAD_INTERNAL_H
+
+#ifdef _MSC_VER
+#include <unistd.h>
+#endif /* _MSC_VER */
+
+#define CHECK_VALUE(arg) \
+ if(!(arg)) { \
+ fprintf(stderr, "\n*** libdvdread: CHECK_VALUE failed in %s:%i ***" \
+ "\n*** for %s ***\n\n", \
+ __FILE__, __LINE__, # arg ); \
+ }
+
+#endif /* DVDREAD_INTERNAL_H */
diff --git a/lib/libdvd/libdvdread/src/ifo_print.c b/lib/libdvd/libdvdread/src/ifo_print.c
new file mode 100644
index 0000000000..fd1e7edb1d
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/ifo_print.c
@@ -0,0 +1,1251 @@
+/*
+ * 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
+ *
+ * $Id: ifo_print.c 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#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 ifo_print_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);
+}
+
+void dvdread_print_time(dvd_time_t *dtime) {
+ ifo_print_time(5, dtime);
+}
+
+/* Put this in some other file / package? It's used in nav_print too.
+ Possibly also by the vm / navigator. */
+static void ifo_print_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("| ");
+#if 0
+ //disabled call of dvdnav function
+ vm_print_mnemonic(command);
+#endif
+ printf("\n");
+}
+
+static void ifo_print_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:
+ printf("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("source letterboxed, ");
+ }
+
+ if(attr->film_mode) {
+ printf("film. ");
+ } else {
+ printf("video. "); //camera
+ }
+}
+
+static void ifo_print_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->unknown3 == 0) {
+ printf("-- Unspecified --");
+ return;
+ }
+
+ switch(attr->audio_format) {
+ case 0:
+ printf("ac3 ");
+ if(attr->quantization != 3)
+ printf("(please send a bug report) ac3 quant/drc not 3 (%d)", attr->quantization);
+ break;
+ case 1:
+ printf("(please send a bug report) ");
+ break;
+ case 2:
+ printf("mpeg1 ");
+ case 3:
+ printf("mpeg2ext ");
+ switch(attr->quantization) {
+ case 0:
+ printf("no drc ");
+ break;
+ case 1:
+ printf("drc ");
+ break;
+ default:
+ printf("(please send a bug report) mpeg reserved quant/drc (%d)", attr->quantization);
+ }
+ break;
+ case 4:
+ printf("lpcm ");
+ switch(attr->quantization) {
+ case 0:
+ printf("16bit ");
+ break;
+ case 1:
+ printf("20bit ");
+ break;
+ case 2:
+ printf("24bit ");
+ break;
+ case 3:
+ printf("(please send a bug report) lpcm reserved quant/drc (%d)", attr->quantization);
+ break;
+ }
+ break;
+ case 5:
+ printf("(please send a bug report) ");
+ break;
+ case 6:
+ printf("dts ");
+ if(attr->quantization != 3)
+ printf("(please send a bug report) dts quant/drc not 3 (%d)", attr->quantization);
+ 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 || attr->lang_code == 0xffff);
+ 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;
+ case 1:
+ printf("??kHz ");
+ break;
+ default:
+ printf("sample_frequency %i (please send a bug report) ",
+ attr->sample_frequency);
+ }
+
+ 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->unknown3);
+}
+
+static void ifo_print_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) ");
+ }
+
+}
+
+
+static void ifo_print_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 ifo_print_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 (Region Code=%02x)\n", vmgi_mat->vmg_category, ((vmgi_mat->vmg_category >> 16) & 0xff) ^0xff);
+ 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: ");
+ ifo_print_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);
+ ifo_print_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);
+ ifo_print_subp_attributes(5, &vmgi_mat->vmgm_subp_attr);
+ printf("\n");
+ }
+}
+
+
+void ifo_print_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: ");
+ ifo_print_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);
+ ifo_print_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);
+ ifo_print_subp_attributes(5, &vtsi_mat->vtsm_subp_attr);
+ printf("\n");
+ }
+
+ printf("Video attributes of VTS_VOBS: ");
+ ifo_print_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);
+ ifo_print_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);
+ ifo_print_subp_attributes(5, &vtsi_mat->vts_subp_attr[i]);
+ printf("\n");
+ }
+}
+
+
+static void ifo_print_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++) {
+ ifo_print_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++) {
+ ifo_print_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++) {
+ ifo_print_cmd(i, &cmd_tbl->cell_cmds[i]);
+ }
+}
+
+
+static void ifo_print_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 ifo_print_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);
+
+ dvdread_print_time(&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].playback_mode)
+ printf("only still VOBUs ");
+ if(cell_playback[i].restricted)
+ printf("restricted cell ");
+ if(cell_playback[i].unknown2)
+ printf("Unknown 0x%x ", cell_playback[i].unknown2);
+ 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 ifo_print_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 ifo_print_PGC(pgc_t *pgc) {
+ int i;
+
+ if (!pgc) {
+ printf("None\n");
+ return;
+ }
+ 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: ");
+ dvdread_print_time(&pgc->playback_time); printf("\n");
+
+ /* If no programs/no time then does this mean anything? */
+ printf("Prohibited user operations: ");
+ ifo_print_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: 4:3=%d, Wide=%d, Letterbox=%d, Pan-Scan=%d\n",
+ i, pgc->subp_control[i],
+ (pgc->subp_control[i] >>24) & 0x1f,
+ (pgc->subp_control[i] >>16) & 0x1f,
+ (pgc->subp_control[i] >>8) & 0x1f,
+ (pgc->subp_control[i] ) & 0x1f);
+ }
+ }
+
+ 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. */
+ ifo_print_PGC_COMMAND_TBL(pgc->command_tbl);
+ ifo_print_PGC_PROGRAM_MAP(pgc->program_map, pgc->nr_of_programs);
+ ifo_print_CELL_PLAYBACK(pgc->cell_playback, pgc->nr_of_cells);
+ ifo_print_CELL_POSITION(pgc->cell_position, pgc->nr_of_cells);
+}
+
+
+void ifo_print_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",
+ *(uint8_t *)&(tt_srpt->title[i].pb_ty));
+ printf("\t\t%s\n",
+ tt_srpt->title[i].pb_ty.multi_or_random_pgc_title ? "Random or Shuffle" : "Sequencial");
+ if (tt_srpt->title[i].pb_ty.jlc_exists_in_cell_cmd) printf("\t\tJump/Link/Call exists in cell cmd\n");
+ if (tt_srpt->title[i].pb_ty.jlc_exists_in_prepost_cmd) printf("\t\tJump/Link/Call exists in pre/post cmd\n");
+ if (tt_srpt->title[i].pb_ty.jlc_exists_in_button_cmd) printf("\t\tJump/Link/Call exists in button cmd\n");
+ if (tt_srpt->title[i].pb_ty.jlc_exists_in_tt_dom) printf("\t\tJump/Link/Call exists in tt_dom cmd\n");
+ printf("\t\tTitle or time play:%d\n", tt_srpt->title[i].pb_ty.title_or_time_play);
+ printf("\t\tChapter search or play:%d\n", tt_srpt->title[i].pb_ty.chapter_search_or_play);
+
+ 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 ifo_print_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 ifo_print_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 ifo_print_VTS_TMAPT(vts_tmapt_t *vts_tmapt) {
+ unsigned int timeunit;
+ int i, j;
+
+ printf("Number of VTS_TMAPS: %i\n", vts_tmapt->nr_of_tmaps);
+ printf("Last byte: %i\n", vts_tmapt->last_byte);
+
+ for(i = 0; i < vts_tmapt->nr_of_tmaps; i++) {
+ printf("TMAP %i (number matches title PGC number.)\n", i + 1);
+ printf(" offset %d relative to VTS_TMAPTI\n", vts_tmapt->tmap_offset[i]);
+ printf(" Time unit (seconds): %i\n", vts_tmapt->tmap[i].tmu);
+ printf(" Number of entries: %i\n", vts_tmapt->tmap[i].nr_of_entries);
+ timeunit = vts_tmapt->tmap[i].tmu;
+ for(j = 0; j < vts_tmapt->tmap[i].nr_of_entries; j++) {
+ unsigned int ac_time = timeunit * (j + 1);
+ printf("Time: %2i:%02i:%02i VOBU Sector: 0x%08x %s\n",
+ ac_time / (60 * 60), (ac_time / 60) % 60, ac_time % 60,
+ vts_tmapt->tmap[i].map_ent[j] & 0x7fffffff,
+ (vts_tmapt->tmap[i].map_ent[j] >> 31) ? "discontinuity" : "");
+ }
+ }
+}
+
+void ifo_print_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->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 ifo_print_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]);
+ }
+}
+
+const char *ifo_print_menu_name(int type) {
+ const char *menu_name;
+ menu_name="";
+ switch (type) {
+ case 2:
+ menu_name="Title";
+ break;
+ case 3:
+ menu_name = "Root";
+ break;
+ case 4:
+ menu_name = "Sub-Picture";
+ break;
+ case 5:
+ menu_name = "Audio";
+ break;
+ case 6:
+ menu_name = "Angle";
+ break;
+ case 7:
+ menu_name = "PTT (Chapter)";
+ break;
+ default:
+ menu_name = "Unknown";
+ break;
+ }
+ return &menu_name[0];
+}
+
+/* pgc_type=1 for menu, 0 for title. */
+void ifo_print_PGCIT(pgcit_t *pgcit, int pgc_type) {
+ int i;
+
+ printf("\nNumber of Program Chains: %3i\n", pgcit->nr_of_pgci_srp);
+ for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
+ printf("\nProgram (PGC): %3i\n", i + 1);
+ if (pgc_type) {
+ printf("PGC Category: Entry PGC %d, Menu Type=0x%02x:%s (Entry id 0x%02x), ",
+ pgcit->pgci_srp[i].entry_id >> 7,
+ pgcit->pgci_srp[i].entry_id & 0xf,
+ ifo_print_menu_name(pgcit->pgci_srp[i].entry_id & 0xf),
+ pgcit->pgci_srp[i].entry_id);
+ } else {
+ printf("PGC Category: %s VTS_TTN:0x%02x (Entry id 0x%02x), ",
+ pgcit->pgci_srp[i].entry_id >> 7 ? "At Start of" : "During",
+ pgcit->pgci_srp[i].entry_id & 0xf,
+ pgcit->pgci_srp[i].entry_id);
+ }
+ printf("Parental ID mask 0x%04x\n", pgcit->pgci_srp[i].ptl_id_mask);
+ ifo_print_PGC(pgcit->pgci_srp[i].pgc);
+ }
+}
+
+
+void ifo_print_PGCI_UT(pgci_ut_t *pgci_ut) {
+ int i, menu;
+
+ 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 Unit %d\n", i+1);
+ printf("\nMenu Language Code: %c%c\n",
+ pgci_ut->lu[i].lang_code >> 8,
+ pgci_ut->lu[i].lang_code & 0xff);
+
+ menu = pgci_ut->lu[i].exists;
+ printf("Menu Existence: %02x: ", menu);
+ if (menu == 0) {
+ printf("No menus ");
+ }
+ if (menu & 0x80) {
+ printf("Root ");
+ menu^=0x80;
+ }
+ if (menu & 0x40) {
+ printf("Sub-Picture ");
+ menu^=0x40;
+ }
+ if (menu & 0x20) {
+ printf("Audio ");
+ menu^=0x20;
+ }
+ if (menu & 0x10) {
+ printf("Angle ");
+ menu^=0x10;
+ }
+ if (menu & 0x08) {
+ printf("PTT ");
+ menu^=0x08;
+ }
+ if (menu > 0) {
+ printf("Unknown extra menus ");
+ menu^=0x08;
+ }
+ printf("\n");
+ ifo_print_PGCIT(pgci_ut->lu[i].pgcit, 1);
+ }
+}
+
+
+static void ifo_print_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: ");
+ ifo_print_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);
+ ifo_print_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);
+ ifo_print_subp_attributes(5, &vts_attributes->vtsm_subp_attr);
+ printf("\n");
+ }
+
+ printf("Video attributes of VTSTT_VOBS: ");
+ ifo_print_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);
+ ifo_print_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);
+ ifo_print_subp_attributes(5, &vts_attributes->vtstt_subp_attr[i]);
+ printf("\n");
+ }
+}
+
+
+void ifo_print_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);
+ ifo_print_VTS_ATTRIBUTES(&vts_atrt->vts[i]);
+ }
+}
+
+
+void ifo_print(dvd_reader_t *dvd, int title) {
+ ifo_handle_t *ifohandle;
+ printf("Local ifo_print\n");
+ 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");
+ ifo_print_VMGI_MAT(ifohandle->vmgi_mat);
+
+ printf("\nFirst Play PGC\n--------------\n");
+ if(ifohandle->first_play_pgc)
+ ifo_print_PGC(ifohandle->first_play_pgc);
+ else
+ printf("No First Play PGC present\n");
+
+ printf("\nTitle Track search pointer table\n");
+ printf( "------------------------------------------------\n");
+ ifo_print_TT_SRPT(ifohandle->tt_srpt);
+
+ printf("\nMenu PGCI Unit table\n");
+ printf( "--------------------\n");
+ if(ifohandle->pgci_ut) {
+ ifo_print_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) {
+ ifo_print_PTL_MAIT(ifohandle->ptl_mait);
+ } else {
+ printf("No Parental Management Information present\n");
+ }
+
+ printf("\nVideo Title Set Attribute Table\n");
+ printf( "-------------------------------\n");
+ ifo_print_VTS_ATRT(ifohandle->vts_atrt);
+
+ printf("\nText Data Manager Information\n");
+ printf( "-----------------------------\n");
+ if(ifohandle->txtdt_mgi) {
+ //ifo_print_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) {
+ ifo_print_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) {
+ ifo_print_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");
+ ifo_print_VTSI_MAT(ifohandle->vtsi_mat);
+
+ printf("\nPart of Title Track search pointer table\n");
+ printf( "----------------------------------------------\n");
+ ifo_print_VTS_PTT_SRPT(ifohandle->vts_ptt_srpt);
+
+ printf("\nPGCI Unit table\n");
+ printf( "--------------------\n");
+ ifo_print_PGCIT(ifohandle->vts_pgcit, 0);
+
+ printf("\nMenu PGCI Unit table\n");
+ printf( "--------------------\n");
+ if(ifohandle->pgci_ut) {
+ ifo_print_PGCI_UT(ifohandle->pgci_ut);
+ } else {
+ printf("No Menu PGCI Unit table present\n");
+ }
+
+ printf("\nVTS Time Map table\n");
+ printf( "-----------------\n");
+ if(ifohandle->vts_tmapt) {
+ ifo_print_VTS_TMAPT(ifohandle->vts_tmapt);
+ } else {
+ printf("No VTS Time Map table present\n");
+ }
+
+ printf("\nMenu Cell Adress table\n");
+ printf( "-----------------\n");
+ if(ifohandle->menu_c_adt) {
+ ifo_print_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) {
+ ifo_print_VOBU_ADMAP(ifohandle->menu_vobu_admap);
+ } else {
+ printf("No Menu VOBU address map present\n");
+ }
+
+ printf("\nCell Adress table\n");
+ printf( "-----------------\n");
+ ifo_print_C_ADT(ifohandle->vts_c_adt);
+
+ printf("\nVideo Title Set VOBU address map\n");
+ printf( "-----------------\n");
+ ifo_print_VOBU_ADMAP(ifohandle->vts_vobu_admap);
+ }
+
+ ifoClose(ifohandle);
+}
+
+/*
+ * $Log$
+ * Revision 1.3 2004/10/22 11:36:19 jcdutton
+ * Stop seg fault when using ifo_dump.
+ *
+ * Revision 1.2 2004/09/27 12:24:01 jcdutton
+ * Add extra info to printout when using ifo_dump.
+ *
+ * Revision 1.1 2004/01/11 21:43:13 mroi
+ * big build system changes
+ * * cleaned up all Makefiles and added a Makefile.common
+ * * added relchk script
+ * * moved libdvdread files to a dvdread subdir
+ * * moved DVD VM to a vm subdir
+ * * removed unused code in read_cache.c
+ *
+ * Revision 1.4 2004/01/01 15:13:13 jcdutton
+ * Put ifo_print.c and .h back in.
+ *
+ * Revision 1.7 2003/04/28 15:17:17 jcdutton
+ * Update ifodump to work with new libdvdnav cvs, instead of needing libdvdread.
+ *
+ * Revision 1.6 2003/04/05 22:49:04 jcdutton
+ * Update with more info from the latest libdvdread.
+ *
+ * Revision 1.5 2003/04/05 13:03:49 jcdutton
+ * Small updates.
+ *
+ * Revision 1.4 2003/04/01 08:01:03 jcdutton
+ * Add VTS Time map display. Requires libdvdread 0.9.4. The same version that comes with xine.
+ *
+ * Revision 1.3 2003/03/14 15:49:18 mroi
+ * adjust to new libdvdread version
+ *
+ * Revision 1.2 2002/08/30 05:12:33 jcdutton
+ * Minor update now that I know what PGC Entry IDs are for.
+ *
+ * Revision 1.1.1.1 2002/08/28 09:48:35 jcdutton
+ * Initial import into CVS.
+ *
+ *
+ *
+ */
+
diff --git a/lib/libdvd/libdvdread/src/ifo_print.h b/lib/libdvd/libdvdread/src/ifo_print.h
new file mode 100644
index 0000000000..4c958f1c12
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/ifo_print.h
@@ -0,0 +1,53 @@
+/*
+ * 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
+ *
+ * $Id: ifo_print.h 1135 2008-09-06 21:55:51Z rathann $
+ *
+ */
+
+#ifndef IFO_PRINT_H_INCLUDED
+#define IFO_PRINT_H_INCLUDED
+
+#include <inttypes.h>
+#include "ifo_types.h"
+
+void ifo_print(dvd_reader_t *dvd, int title);
+void dvdread_print_time(dvd_time_t *dtime);
+
+#endif /* IFO_PRINT_H_INCLUDED */
+
+/*
+ * $Log$
+ * Revision 1.1 2004/01/11 21:43:13 mroi
+ * big build system changes
+ * * cleaned up all Makefiles and added a Makefile.common
+ * * added relchk script
+ * * moved libdvdread files to a dvdread subdir
+ * * moved DVD VM to a vm subdir
+ * * removed unused code in read_cache.c
+ *
+ * Revision 1.4 2004/01/01 15:13:13 jcdutton
+ * Put ifo_print.c and .h back in.
+ *
+ * Revision 1.2 2003/04/28 15:17:17 jcdutton
+ * Update ifodump to work with new libdvdnav cvs, instead of needing libdvdread.
+ *
+ * Revision 1.1.1.1 2002/08/28 09:48:35 jcdutton
+ * Initial import into CVS.
+ *
+ *
+ *
+ */
+
diff --git a/lib/libdvd/libdvdread/src/ifo_read.c b/lib/libdvd/libdvdread/src/ifo_read.c
new file mode 100644
index 0000000000..a89d7f2273
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/ifo_read.c
@@ -0,0 +1,2212 @@
+/*
+ * Copyright (C) 2000, 2001, 2002, 2003
+ * 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 "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+
+#include "bswap.h"
+#include "ifo_types.h"
+#include "ifo_read.h"
+#include "dvd_reader.h"
+#include "dvdread_internal.h"
+#include "bitreader.h"
+
+#ifndef DVD_BLOCK_LEN
+#define DVD_BLOCK_LEN 2048
+#endif
+
+#ifndef NDEBUG
+#define CHECK_ZERO0(arg) \
+ if(arg != 0) { \
+ fprintf(stderr, "*** Zero check failed in %s:%i\n for %s = 0x%x\n", \
+ __FILE__, __LINE__, # arg, arg); \
+ }
+#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_ZERO0(arg) (void)(arg)
+#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 inline int DVDFileSeekForce_( dvd_file_t *dvd_file, uint32_t offset, int force_size ) {
+ return (DVDFileSeekForce(dvd_file, (int)offset, force_size) == (int)offset);
+}
+
+static inline int DVDFileSeek_( dvd_file_t *dvd_file, uint32_t offset ) {
+ return (DVDFileSeek(dvd_file, (int)offset) == (int)offset);
+}
+
+static void read_video_attr(video_attr_t *va) {
+ getbits_state_t state;
+ uint8_t buf[sizeof(video_attr_t)];
+
+ memcpy(buf, va, sizeof(video_attr_t));
+ if (!dvdread_getbits_init(&state, buf)) abort();
+ va->mpeg_version = dvdread_getbits(&state, 2);
+ va->video_format = dvdread_getbits(&state, 2);
+ va->display_aspect_ratio = dvdread_getbits(&state, 2);
+ va->permitted_df = dvdread_getbits(&state, 2);
+ va->line21_cc_1 = dvdread_getbits(&state, 1);
+ va->line21_cc_2 = dvdread_getbits(&state, 1);
+ va->unknown1 = dvdread_getbits(&state, 1);
+ va->bit_rate = dvdread_getbits(&state, 1);
+ va->picture_size = dvdread_getbits(&state, 2);
+ va->letterboxed = dvdread_getbits(&state, 1);
+ va->film_mode = dvdread_getbits(&state, 1);
+}
+
+static void read_audio_attr(audio_attr_t *aa) {
+ getbits_state_t state;
+ uint8_t buf[sizeof(audio_attr_t)];
+
+ memcpy(buf, aa, sizeof(audio_attr_t));
+ if (!dvdread_getbits_init(&state, buf)) abort();
+ aa->audio_format = dvdread_getbits(&state, 3);
+ aa->multichannel_extension = dvdread_getbits(&state, 1);
+ aa->lang_type = dvdread_getbits(&state, 2);
+ aa->application_mode = dvdread_getbits(&state, 2);
+ aa->quantization = dvdread_getbits(&state, 2);
+ aa->sample_frequency = dvdread_getbits(&state, 2);
+ aa->unknown1 = dvdread_getbits(&state, 1);
+ aa->channels = dvdread_getbits(&state, 3);
+ aa->lang_code = dvdread_getbits(&state, 16);
+ aa->lang_extension = dvdread_getbits(&state, 8);
+ aa->code_extension = dvdread_getbits(&state, 8);
+ aa->unknown3 = dvdread_getbits(&state, 8);
+ aa->app_info.karaoke.unknown4 = dvdread_getbits(&state, 1);
+ aa->app_info.karaoke.channel_assignment = dvdread_getbits(&state, 3);
+ aa->app_info.karaoke.version = dvdread_getbits(&state, 2);
+ aa->app_info.karaoke.mc_intro = dvdread_getbits(&state, 1);
+ aa->app_info.karaoke.mode = dvdread_getbits(&state, 1);
+}
+
+static void read_multichannel_ext(multichannel_ext_t *me) {
+ getbits_state_t state;
+ uint8_t buf[sizeof(multichannel_ext_t)];
+
+ memcpy(buf, me, sizeof(multichannel_ext_t));
+ if (!dvdread_getbits_init(&state, buf)) abort();
+ me->zero1 = dvdread_getbits(&state, 7);
+ me->ach0_gme = dvdread_getbits(&state, 1);
+ me->zero2 = dvdread_getbits(&state, 7);
+ me->ach1_gme = dvdread_getbits(&state, 1);
+ me->zero3 = dvdread_getbits(&state, 4);
+ me->ach2_gv1e = dvdread_getbits(&state, 1);
+ me->ach2_gv2e = dvdread_getbits(&state, 1);
+ me->ach2_gm1e = dvdread_getbits(&state, 1);
+ me->ach2_gm2e = dvdread_getbits(&state, 1);
+ me->zero4 = dvdread_getbits(&state, 4);
+ me->ach3_gv1e = dvdread_getbits(&state, 1);
+ me->ach3_gv2e = dvdread_getbits(&state, 1);
+ me->ach3_gmAe = dvdread_getbits(&state, 1);
+ me->ach3_se2e = dvdread_getbits(&state, 1);
+ me->zero5 = dvdread_getbits(&state, 4);
+ me->ach4_gv1e = dvdread_getbits(&state, 1);
+ me->ach4_gv2e = dvdread_getbits(&state, 1);
+ me->ach4_gmBe = dvdread_getbits(&state, 1);
+ me->ach4_seBe = dvdread_getbits(&state, 1);
+}
+
+static void read_subp_attr(subp_attr_t *sa) {
+ getbits_state_t state;
+ uint8_t buf[sizeof(subp_attr_t)];
+
+ memcpy(buf, sa, sizeof(subp_attr_t));
+ if (!dvdread_getbits_init(&state, buf)) abort();
+ sa->code_mode = dvdread_getbits(&state, 3);
+ sa->zero1 = dvdread_getbits(&state, 3);
+ sa->type = dvdread_getbits(&state, 2);
+ sa->zero2 = dvdread_getbits(&state, 8);
+ sa->lang_code = dvdread_getbits(&state, 16);
+ sa->lang_extension = dvdread_getbits(&state, 8);
+ sa->code_extension = dvdread_getbits(&state, 8);
+}
+
+static void read_user_ops(user_ops_t *uo) {
+ getbits_state_t state;
+ uint8_t buf[sizeof(user_ops_t)];
+
+ memcpy(buf, uo, sizeof(user_ops_t));
+ if (!dvdread_getbits_init(&state, buf)) abort();
+ uo->zero = dvdread_getbits(&state, 7);
+ uo->video_pres_mode_change = dvdread_getbits(&state, 1);
+ uo->karaoke_audio_pres_mode_change = dvdread_getbits(&state, 1);
+ uo->angle_change = dvdread_getbits(&state, 1);
+ uo->subpic_stream_change = dvdread_getbits(&state, 1);
+ uo->audio_stream_change = dvdread_getbits(&state, 1);
+ uo->pause_on = dvdread_getbits(&state, 1);
+ uo->still_off = dvdread_getbits(&state, 1);
+ uo->button_select_or_activate = dvdread_getbits(&state, 1);
+ uo->resume = dvdread_getbits(&state, 1);
+ uo->chapter_menu_call = dvdread_getbits(&state, 1);
+ uo->angle_menu_call = dvdread_getbits(&state, 1);
+ uo->audio_menu_call = dvdread_getbits(&state, 1);
+ uo->subpic_menu_call = dvdread_getbits(&state, 1);
+ uo->root_menu_call = dvdread_getbits(&state, 1);
+ uo->title_menu_call = dvdread_getbits(&state, 1);
+ uo->backward_scan = dvdread_getbits(&state, 1);
+ uo->forward_scan = dvdread_getbits(&state, 1);
+ uo->next_pg_search = dvdread_getbits(&state, 1);
+ uo->prev_or_top_pg_search = dvdread_getbits(&state, 1);
+ uo->time_or_chapter_search = dvdread_getbits(&state, 1);
+ uo->go_up = dvdread_getbits(&state, 1);
+ uo->stop = dvdread_getbits(&state, 1);
+ uo->title_play = dvdread_getbits(&state, 1);
+ uo->chapter_search_or_play = dvdread_getbits(&state, 1);
+ uo->title_or_time_play = dvdread_getbits(&state, 1);
+}
+
+static void read_pgci_srp(pgci_srp_t *ps) {
+ getbits_state_t state;
+ uint8_t buf[sizeof(pgci_srp_t)];
+
+ memcpy(buf, ps, sizeof(pgci_srp_t));
+ if (!dvdread_getbits_init(&state, buf)) abort();
+ ps->entry_id = dvdread_getbits(&state, 8);
+ ps->block_mode = dvdread_getbits(&state, 2);
+ ps->block_type = dvdread_getbits(&state, 2);
+ ps->unknown1 = dvdread_getbits(&state, 4);
+ ps->ptl_id_mask = dvdread_getbits(&state, 16);
+ ps->pgc_start_byte = dvdread_getbits(&state, 32);
+}
+
+static void read_cell_playback(cell_playback_t *cp) {
+ getbits_state_t state;
+ uint8_t buf[sizeof(cell_playback_t)];
+
+ memcpy(buf, cp, sizeof(cell_playback_t));
+ if (!dvdread_getbits_init(&state, buf)) abort();
+ cp->block_mode = dvdread_getbits(&state, 2);
+ cp->block_type = dvdread_getbits(&state, 2);
+ cp->seamless_play = dvdread_getbits(&state, 1);
+ cp->interleaved = dvdread_getbits(&state, 1);
+ cp->stc_discontinuity = dvdread_getbits(&state, 1);
+ cp->seamless_angle = dvdread_getbits(&state, 1);
+ cp->playback_mode = dvdread_getbits(&state, 1);
+ cp->restricted = dvdread_getbits(&state, 1);
+ cp->unknown2 = dvdread_getbits(&state, 6);
+ cp->still_time = dvdread_getbits(&state, 8);
+ cp->cell_cmd_nr = dvdread_getbits(&state, 8);
+
+ cp->playback_time.hour = dvdread_getbits(&state, 8);
+ cp->playback_time.minute = dvdread_getbits(&state, 8);
+ cp->playback_time.second = dvdread_getbits(&state, 8);
+ cp->playback_time.frame_u = dvdread_getbits(&state, 8);
+
+ cp->first_sector = dvdread_getbits(&state, 32);
+ cp->first_ilvu_end_sector = dvdread_getbits(&state, 32);
+ cp->last_vobu_start_sector = dvdread_getbits(&state, 32);
+ cp->last_sector = dvdread_getbits(&state, 32);
+}
+
+static void read_playback_type(playback_type_t *pt) {
+ getbits_state_t state;
+ uint8_t buf[sizeof(playback_type_t)];
+
+ memcpy(buf, pt, sizeof(playback_type_t));
+ if (!dvdread_getbits_init(&state, buf)) abort();
+ pt->zero_1 = dvdread_getbits(&state, 1);
+ pt->multi_or_random_pgc_title = dvdread_getbits(&state, 1);
+ pt->jlc_exists_in_cell_cmd = dvdread_getbits(&state, 1);
+ pt->jlc_exists_in_prepost_cmd = dvdread_getbits(&state, 1);
+ pt->jlc_exists_in_button_cmd = dvdread_getbits(&state, 1);
+ pt->jlc_exists_in_tt_dom = dvdread_getbits(&state, 1);
+ pt->chapter_search_or_play = dvdread_getbits(&state, 1);
+ pt->title_or_time_play = dvdread_getbits(&state, 1);
+}
+
+static void free_ptl_mait(ptl_mait_t* ptl_mait, int num_entries) {
+ int i;
+ for (i = 0; i < num_entries; i++)
+ free(ptl_mait->countries[i].pf_ptl_mai);
+
+ free(ptl_mait->countries);
+ free(ptl_mait);
+}
+
+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 NULL;
+
+ memset(ifofile, 0, sizeof(ifo_handle_t));
+
+ ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE);
+ if(!ifofile->file) /* Should really catch any error and try to fallback */
+ ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_BACKUP_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 NULL;
+ }
+
+ /* 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), ifoRead_FP_PGC() failed.\n");
+ ifoClose(ifofile);
+ return NULL;
+ }
+
+ 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), ifoRead_VTS_ATRT() failed.\n");
+ ifoClose(ifofile);
+ return NULL;
+ }
+
+ 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 NULL;
+ }
+
+
+ ifoRead_PGCI_UT(ifofile);
+ ifoRead_VTS_TMAPT(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 NULL;
+ }
+
+ return ifofile;
+ }
+
+ if(title) {
+ fprintf(stderr, "libdvdread: Invalid IFO for title %d (VTS_%02d_0.IFO).\n",
+ title, title);
+ } else {
+ fprintf(stderr, "libdvdread: Invalid IFO for VMGM (VIDEO_TS.IFO).\n");
+ }
+ ifoClose(ifofile);
+ return NULL;
+}
+
+
+ifo_handle_t *ifoOpenVMGI(dvd_reader_t *dvd) {
+ ifo_handle_t *ifofile;
+
+ ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t));
+ if(!ifofile)
+ return NULL;
+
+ memset(ifofile, 0, sizeof(ifo_handle_t));
+
+ ifofile->file = DVDOpenFile(dvd, 0, DVD_READ_INFO_FILE);
+ if(!ifofile->file) /* Should really catch any error and try to fallback */
+ ifofile->file = DVDOpenFile(dvd, 0, DVD_READ_INFO_BACKUP_FILE);
+ if(!ifofile->file) {
+ fprintf(stderr, "libdvdread: Can't open file VIDEO_TS.IFO.\n");
+ free(ifofile);
+ return NULL;
+ }
+
+ if(ifoRead_VMG(ifofile))
+ return ifofile;
+
+ fprintf(stderr, "libdvdread,ifoOpenVMGI(): Invalid main menu IFO (VIDEO_TS.IFO).\n");
+ ifoClose(ifofile);
+ return NULL;
+}
+
+
+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 NULL;
+
+ memset(ifofile, 0, sizeof(ifo_handle_t));
+
+ if(title <= 0 || title > 99) {
+ fprintf(stderr, "libdvdread: ifoOpenVTSI invalid title (%d).\n", title);
+ free(ifofile);
+ return NULL;
+ }
+
+ ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE);
+ if(!ifofile->file) /* Should really catch any error and try to fallback */
+ ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_BACKUP_FILE);
+ if(!ifofile->file) {
+ fprintf(stderr, "libdvdread: Can't open file VTS_%02d_0.IFO.\n", title);
+ free(ifofile);
+ return NULL;
+ }
+
+ 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 NULL;
+}
+
+
+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);
+ ifoFree_VTS_TMAPT(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);
+ read_video_attr(&vmgi_mat->vmgm_video_attr);
+ read_audio_attr(&vmgi_mat->vmgm_audio_attr);
+ read_subp_attr(&vmgi_mat->vmgm_subp_attr);
+
+
+ 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);
+ CHECK_VALUE(vmgi_mat->vmg_last_sector != 0);
+ CHECK_VALUE(vmgi_mat->vmgi_last_sector != 0);
+ CHECK_VALUE(vmgi_mat->vmgi_last_sector * 2 <= vmgi_mat->vmg_last_sector);
+ CHECK_VALUE(vmgi_mat->vmgi_last_sector * 2 <= vmgi_mat->vmg_last_sector);
+ CHECK_VALUE(vmgi_mat->vmg_nr_of_volumes != 0);
+ CHECK_VALUE(vmgi_mat->vmg_this_volume_nr != 0);
+ CHECK_VALUE(vmgi_mat->vmg_this_volume_nr <= vmgi_mat->vmg_nr_of_volumes);
+ CHECK_VALUE(vmgi_mat->disc_side == 1 || vmgi_mat->disc_side == 2);
+ CHECK_VALUE(vmgi_mat->vmg_nr_of_title_sets != 0);
+ CHECK_VALUE(vmgi_mat->vmgi_last_byte >= 341);
+ CHECK_VALUE(vmgi_mat->vmgi_last_byte / DVD_BLOCK_LEN <=
+ vmgi_mat->vmgi_last_sector);
+ /* It seems that first_play_pgc is optional. */
+ CHECK_VALUE(vmgi_mat->first_play_pgc < vmgi_mat->vmgi_last_byte);
+ CHECK_VALUE(vmgi_mat->vmgm_vobs == 0 ||
+ (vmgi_mat->vmgm_vobs > vmgi_mat->vmgi_last_sector &&
+ vmgi_mat->vmgm_vobs < vmgi_mat->vmg_last_sector));
+ CHECK_VALUE(vmgi_mat->tt_srpt <= vmgi_mat->vmgi_last_sector);
+ CHECK_VALUE(vmgi_mat->vmgm_pgci_ut <= vmgi_mat->vmgi_last_sector);
+ CHECK_VALUE(vmgi_mat->ptl_mait <= vmgi_mat->vmgi_last_sector);
+ CHECK_VALUE(vmgi_mat->vts_atrt <= vmgi_mat->vmgi_last_sector);
+ CHECK_VALUE(vmgi_mat->txtdt_mgi <= vmgi_mat->vmgi_last_sector);
+ CHECK_VALUE(vmgi_mat->vmgm_c_adt <= vmgi_mat->vmgi_last_sector);
+ CHECK_VALUE(vmgi_mat->vmgm_vobu_admap <= vmgi_mat->vmgi_last_sector);
+
+ CHECK_VALUE(vmgi_mat->nr_of_vmgm_audio_streams <= 1);
+ CHECK_VALUE(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;
+ }
+
+ read_video_attr(&vtsi_mat->vtsm_video_attr);
+ read_video_attr(&vtsi_mat->vts_video_attr);
+ read_audio_attr(&vtsi_mat->vtsm_audio_attr);
+ for(i=0; i<8; i++)
+ read_audio_attr(&vtsi_mat->vts_audio_attr[i]);
+ read_subp_attr(&vtsi_mat->vtsm_subp_attr);
+ for(i=0; i<32; i++)
+ read_subp_attr(&vtsi_mat->vts_subp_attr[i]);
+ 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);
+
+
+ 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);
+ CHECK_ZERO(vtsi_mat->zero_21);
+ CHECK_VALUE(vtsi_mat->vtsi_last_sector*2 <= vtsi_mat->vts_last_sector);
+ CHECK_VALUE(vtsi_mat->vtsi_last_byte/DVD_BLOCK_LEN <= vtsi_mat->vtsi_last_sector);
+ CHECK_VALUE(vtsi_mat->vtsm_vobs == 0 ||
+ (vtsi_mat->vtsm_vobs > vtsi_mat->vtsi_last_sector &&
+ vtsi_mat->vtsm_vobs < vtsi_mat->vts_last_sector));
+ CHECK_VALUE(vtsi_mat->vtstt_vobs == 0 ||
+ (vtsi_mat->vtstt_vobs > vtsi_mat->vtsi_last_sector &&
+ vtsi_mat->vtstt_vobs < vtsi_mat->vts_last_sector));
+ CHECK_VALUE(vtsi_mat->vts_ptt_srpt <= vtsi_mat->vtsi_last_sector);
+ CHECK_VALUE(vtsi_mat->vts_pgcit <= vtsi_mat->vtsi_last_sector);
+ CHECK_VALUE(vtsi_mat->vtsm_pgci_ut <= vtsi_mat->vtsi_last_sector);
+ CHECK_VALUE(vtsi_mat->vts_tmapt <= vtsi_mat->vtsi_last_sector);
+ CHECK_VALUE(vtsi_mat->vtsm_c_adt <= vtsi_mat->vtsi_last_sector);
+ CHECK_VALUE(vtsi_mat->vtsm_vobu_admap <= vtsi_mat->vtsi_last_sector);
+ CHECK_VALUE(vtsi_mat->vts_c_adt <= vtsi_mat->vtsi_last_sector);
+ CHECK_VALUE(vtsi_mat->vts_vobu_admap <= vtsi_mat->vtsi_last_sector);
+
+ CHECK_VALUE(vtsi_mat->nr_of_vtsm_audio_streams <= 1);
+ CHECK_VALUE(vtsi_mat->nr_of_vtsm_subp_streams <= 1);
+
+ CHECK_VALUE(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]);
+
+ CHECK_VALUE(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]);
+
+ for(i = 0; i < 8; i++) {
+ read_multichannel_ext(&vtsi_mat->vts_mu_audio_attr[i]);
+ CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero1);
+ CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero2);
+ CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero3);
+ CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero4);
+ CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero5);
+ CHECK_ZERO(vtsi_mat->vts_mu_audio_attr[i].zero6);
+ }
+
+ 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);
+
+ CHECK_VALUE(cmd_tbl->nr_of_pre + cmd_tbl->nr_of_post + cmd_tbl->nr_of_cell<= 255);
+
+ 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++) {
+ read_cell_playback(&cell_playback[i]);
+ /* Changed < to <= because this was false in the movie 'Pi'. */
+ CHECK_VALUE(cell_playback[i].last_vobu_start_sector <=
+ cell_playback[i].last_sector);
+ CHECK_VALUE(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;
+
+ read_user_ops(&pgc->prohibited_ops);
+ 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);
+ CHECK_VALUE(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); /* ?? */
+ CHECK_VALUE(pgc->program_map_offset == 0);
+ CHECK_VALUE(pgc->cell_playback_offset == 0);
+ CHECK_VALUE(pgc->cell_position_offset == 0);
+ } else {
+ CHECK_VALUE(pgc->program_map_offset != 0);
+ CHECK_VALUE(pgc->cell_playback_offset != 0);
+ CHECK_VALUE(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->nr_of_programs>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->nr_of_cells>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->nr_of_cells>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;
+
+ /* It seems that first_play_pgc is optional after all. */
+ ifofile->first_play_pgc = 0;
+ if(ifofile->vmgi_mat->first_play_pgc == 0)
+ return 1;
+
+ 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);
+ CHECK_VALUE(tt_srpt->nr_of_srpts != 0);
+ CHECK_VALUE(tt_srpt->nr_of_srpts < 100); /* ?? */
+ CHECK_VALUE((int)tt_srpt->nr_of_srpts * sizeof(title_info_t) <= info_length);
+
+ for(i = 0; i < tt_srpt->nr_of_srpts; i++) {
+ read_playback_type(&tt_srpt->title[i].pb_ty);
+ CHECK_VALUE(tt_srpt->title[i].pb_ty.zero_1 == 0);
+ CHECK_VALUE(tt_srpt->title[i].nr_of_angles != 0);
+ CHECK_VALUE(tt_srpt->title[i].nr_of_angles < 10);
+ /* CHECK_VALUE(tt_srpt->title[i].nr_of_ptts != 0); */
+ /* XXX: this assertion breaks Ghostbusters: */
+ CHECK_VALUE(tt_srpt->title[i].nr_of_ptts < 1000); /* ?? */
+ CHECK_VALUE(tt_srpt->title[i].title_set_nr != 0);
+ CHECK_VALUE(tt_srpt->title[i].title_set_nr < 100); /* ?? */
+ CHECK_VALUE(tt_srpt->title[i].vts_ttn != 0);
+ CHECK_VALUE(tt_srpt->title[i].vts_ttn < 100); /* ?? */
+ /* CHECK_VALUE(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);
+ CHECK_VALUE(vts_ptt_srpt->nr_of_srpts != 0);
+ CHECK_VALUE(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. */
+ CHECK_VALUE(data[i] + sizeof(ptt_info_t) <= vts_ptt_srpt->last_byte + 1 + 4);
+ }
+
+ vts_ptt_srpt->ttu_offset = data;
+
+ 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;
+ CHECK_VALUE(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 */
+ CHECK_VALUE(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);
+ }
+ }
+
+ 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++) {
+ CHECK_VALUE(vts_ptt_srpt->title[i].nr_of_ptts < 1000); /* ?? */
+ for(j = 0; j < vts_ptt_srpt->title[i].nr_of_ptts; j++) {
+ CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgcn != 0 );
+ CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgcn < 1000); /* ?? */
+ CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgn != 0);
+ CHECK_VALUE(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->ttu_offset);
+ 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, j;
+
+ 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);
+
+ CHECK_VALUE(ptl_mait->nr_of_countries != 0);
+ CHECK_VALUE(ptl_mait->nr_of_countries < 100); /* ?? */
+ CHECK_VALUE(ptl_mait->nr_of_vtss != 0);
+ CHECK_VALUE(ptl_mait->nr_of_vtss < 100); /* ?? */
+ CHECK_VALUE(ptl_mait->nr_of_countries * PTL_MAIT_COUNTRY_SIZE
+ <= ptl_mait->last_byte + 1 - PTL_MAIT_SIZE);
+
+ info_length = ptl_mait->nr_of_countries * sizeof(ptl_mait_country_t);
+ ptl_mait->countries = (ptl_mait_country_t *)malloc(info_length);
+ if(!ptl_mait->countries) {
+ free(ptl_mait);
+ ifofile->ptl_mait = 0;
+ return 0;
+ }
+
+ for(i = 0; i < ptl_mait->nr_of_countries; i++) {
+ if(!(DVDReadBytes(ifofile->file, &ptl_mait->countries[i], PTL_MAIT_COUNTRY_SIZE))) {
+ fprintf(stderr, "libdvdread: Unable to read PTL_MAIT.\n");
+ free(ptl_mait->countries);
+ free(ptl_mait);
+ ifofile->ptl_mait = 0;
+ 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);
+ CHECK_VALUE(ptl_mait->countries[i].pf_ptl_mai_start_byte
+ + 8*2 * (ptl_mait->nr_of_vtss + 1) <= ptl_mait->last_byte + 1);
+ }
+
+ for(i = 0; i < ptl_mait->nr_of_countries; i++) {
+ uint16_t *pf_temp;
+
+ if(!DVDFileSeek_(ifofile->file,
+ ifofile->vmgi_mat->ptl_mait * DVD_BLOCK_LEN
+ + ptl_mait->countries[i].pf_ptl_mai_start_byte)) {
+ fprintf(stderr, "libdvdread: Unable to seak PTL_MAIT table.\n");
+ free(ptl_mait->countries);
+ free(ptl_mait);
+ return 0;
+ }
+ info_length = (ptl_mait->nr_of_vtss + 1) * sizeof(pf_level_t);
+ pf_temp = (uint16_t *)malloc(info_length);
+ if(!pf_temp) {
+ free_ptl_mait(ptl_mait, i);
+ return 0;
+ }
+ if(!(DVDReadBytes(ifofile->file, pf_temp, info_length))) {
+ fprintf(stderr, "libdvdread: Unable to read PTL_MAIT table.\n");
+ free(pf_temp);
+ free_ptl_mait(ptl_mait, i);
+ return 0;
+ }
+ for (j = 0; j < ((ptl_mait->nr_of_vtss + 1) * 8); j++) {
+ B2N_16(pf_temp[j]);
+ }
+ ptl_mait->countries[i].pf_ptl_mai = (pf_level_t *)malloc(info_length);
+ if(!ptl_mait->countries[i].pf_ptl_mai) {
+ free(pf_temp);
+ free_ptl_mait(ptl_mait, i);
+ return 0;
+ }
+ { /* Transpose the array so we can use C indexing. */
+ int level, vts;
+ for(level = 0; level < 8; level++) {
+ for(vts = 0; vts <= ptl_mait->nr_of_vtss; vts++) {
+ ptl_mait->countries[i].pf_ptl_mai[vts][level] =
+ pf_temp[(7-level)*(ptl_mait->nr_of_vtss+1) + vts];
+ }
+ }
+ free(pf_temp);
+ }
+ }
+ return 1;
+}
+
+void ifoFree_PTL_MAIT(ifo_handle_t *ifofile) {
+ unsigned int i;
+
+ if(!ifofile)
+ return;
+
+ if(ifofile->ptl_mait) {
+ for(i = 0; i < ifofile->ptl_mait->nr_of_countries; i++) {
+ free(ifofile->ptl_mait->countries[i].pf_ptl_mai);
+ }
+ free(ifofile->ptl_mait->countries);
+ free(ifofile->ptl_mait);
+ ifofile->ptl_mait = 0;
+ }
+}
+
+int ifoRead_VTS_TMAPT(ifo_handle_t *ifofile) {
+ vts_tmapt_t *vts_tmapt;
+ uint32_t *vts_tmap_srp;
+ unsigned int offset;
+ int info_length;
+ unsigned int i, j;
+
+ if(!ifofile)
+ return 0;
+
+ if(!ifofile->vtsi_mat)
+ return 0;
+
+ if(ifofile->vtsi_mat->vts_tmapt == 0) { /* optional(?) */
+ ifofile->vts_tmapt = NULL;
+ fprintf(stderr,"Please send bug report - no VTS_TMAPT ?? \n");
+ return 1;
+ }
+
+ offset = ifofile->vtsi_mat->vts_tmapt * DVD_BLOCK_LEN;
+
+ if(!DVDFileSeek_(ifofile->file, offset))
+ return 0;
+
+ vts_tmapt = (vts_tmapt_t *)malloc(sizeof(vts_tmapt_t));
+ if(!vts_tmapt)
+ return 0;
+
+ ifofile->vts_tmapt = vts_tmapt;
+
+ if(!(DVDReadBytes(ifofile->file, vts_tmapt, VTS_TMAPT_SIZE))) {
+ fprintf(stderr, "libdvdread: Unable to read VTS_TMAPT.\n");
+ free(vts_tmapt);
+ ifofile->vts_tmapt = NULL;
+ return 0;
+ }
+
+ B2N_16(vts_tmapt->nr_of_tmaps);
+ B2N_32(vts_tmapt->last_byte);
+
+ CHECK_ZERO(vts_tmapt->zero_1);
+
+ info_length = vts_tmapt->nr_of_tmaps * 4;
+
+ vts_tmap_srp = (uint32_t *)malloc(info_length);
+ if(!vts_tmap_srp) {
+ free(vts_tmapt);
+ ifofile->vts_tmapt = NULL;
+ return 0;
+ }
+
+ vts_tmapt->tmap_offset = vts_tmap_srp;
+
+ if(!(DVDReadBytes(ifofile->file, vts_tmap_srp, info_length))) {
+ fprintf(stderr, "libdvdread: Unable to read VTS_TMAPT.\n");
+ free(vts_tmap_srp);
+ free(vts_tmapt);
+ ifofile->vts_tmapt = NULL;
+ return 0;
+ }
+
+ for (i = 0; i < vts_tmapt->nr_of_tmaps; i++) {
+ B2N_32(vts_tmap_srp[i]);
+ }
+
+
+ info_length = vts_tmapt->nr_of_tmaps * sizeof(vts_tmap_t);
+
+ vts_tmapt->tmap = (vts_tmap_t *)malloc(info_length);
+ if(!vts_tmapt->tmap) {
+ free(vts_tmap_srp);
+ free(vts_tmapt);
+ ifofile->vts_tmapt = NULL;
+ return 0;
+ }
+
+ memset(vts_tmapt->tmap, 0, info_length); /* So ifoFree_VTS_TMAPT works. */
+
+ for(i = 0; i < vts_tmapt->nr_of_tmaps; i++) {
+ if(!DVDFileSeek_(ifofile->file, offset + vts_tmap_srp[i])) {
+ ifoFree_VTS_TMAPT(ifofile);
+ return 0;
+ }
+
+ if(!(DVDReadBytes(ifofile->file, &vts_tmapt->tmap[i], VTS_TMAP_SIZE))) {
+ fprintf(stderr, "libdvdread: Unable to read VTS_TMAP.\n");
+ ifoFree_VTS_TMAPT(ifofile);
+ return 0;
+ }
+
+ B2N_16(vts_tmapt->tmap[i].nr_of_entries);
+ CHECK_ZERO(vts_tmapt->tmap[i].zero_1);
+
+ if(vts_tmapt->tmap[i].nr_of_entries == 0) { /* Early out if zero entries */
+ vts_tmapt->tmap[i].map_ent = NULL;
+ continue;
+ }
+
+ info_length = vts_tmapt->tmap[i].nr_of_entries * sizeof(map_ent_t);
+
+ vts_tmapt->tmap[i].map_ent = (map_ent_t *)malloc(info_length);
+ if(!vts_tmapt->tmap[i].map_ent) {
+ ifoFree_VTS_TMAPT(ifofile);
+ return 0;
+ }
+
+ if(!(DVDReadBytes(ifofile->file, vts_tmapt->tmap[i].map_ent, info_length))) {
+ fprintf(stderr, "libdvdread: Unable to read VTS_TMAP_ENT.\n");
+ ifoFree_VTS_TMAPT(ifofile);
+ return 0;
+ }
+
+ for(j = 0; j < vts_tmapt->tmap[i].nr_of_entries; j++)
+ B2N_32(vts_tmapt->tmap[i].map_ent[j]);
+ }
+
+ return 1;
+}
+
+void ifoFree_VTS_TMAPT(ifo_handle_t *ifofile) {
+ unsigned int i;
+
+ if(!ifofile)
+ return;
+
+ if(ifofile->vts_tmapt) {
+ for(i = 0; i < ifofile->vts_tmapt->nr_of_tmaps; i++)
+ if(ifofile->vts_tmapt->tmap[i].map_ent)
+ free(ifofile->vts_tmapt->tmap[i].map_ent);
+ free(ifofile->vts_tmapt->tmap);
+ free(ifofile->vts_tmapt->tmap_offset);
+ free(ifofile->vts_tmapt);
+ ifofile->vts_tmapt = NULL;
+ }
+}
+
+
+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. */
+ CHECK_VALUE(info_length % sizeof(cell_adr_t) == 0);
+
+ /* assert(info_length / sizeof(cell_adr_t) >= c_adt->nr_of_vobs);
+ Enemy of the State region 2 (de) has Titles where nr_of_vobs field
+ is to high, they high ones are never referenced though. */
+ if(info_length / sizeof(cell_adr_t) < c_adt->nr_of_vobs) {
+ fprintf(stderr, "libdvdread: *C_ADT nr_of_vobs > avaiable info entries\n");
+ c_adt->nr_of_vobs = info_length / sizeof(cell_adr_t);
+ }
+
+ 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);
+ CHECK_VALUE(c_adt->cell_adr_table[i].vob_id > 0);
+ CHECK_VALUE(c_adt->cell_adr_table[i].vob_id <= c_adt->nr_of_vobs);
+ CHECK_VALUE(c_adt->cell_adr_table[i].cell_id > 0);
+ CHECK_VALUE(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(!DVDFileSeekForce_(ifofile->file, sector * DVD_BLOCK_LEN, sector))
+ 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. */
+ CHECK_VALUE(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. */
+ CHECK_VALUE(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_SRP_SIZE);
+ ptr += PGCI_SRP_SIZE;
+ read_pgci_srp(&pgcit->pgci_srp[i]);
+ CHECK_VALUE(pgcit->pgci_srp[i].unknown1 == 0);
+ }
+ free(data);
+
+ for(i = 0; i < pgcit->nr_of_pgci_srp; i++)
+ CHECK_VALUE(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);
+ }
+ goto fail;
+ }
+ 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);
+ }
+ goto fail;
+ }
+ }
+
+ return 1;
+fail:
+ free(pgcit->pgci_srp);
+ pgcit->pgci_srp = NULL;
+ return 0;
+}
+
+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[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);
+ CHECK_VALUE(pgci_ut->nr_of_lus != 0);
+ CHECK_VALUE(pgci_ut->nr_of_lus < 100); /* ?? 3-4 ? */
+ CHECK_VALUE((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++) {
+ /* 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"
+ */
+ CHECK_VALUE((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;
+
+ read_video_attr(&vts_attributes->vtsm_vobs_attr);
+ read_video_attr(&vts_attributes->vtstt_vobs_video_attr);
+ read_audio_attr(&vts_attributes->vtsm_audio_attr);
+ for(i=0; i<8; i++)
+ read_audio_attr(&vts_attributes->vtstt_audio_attr[i]);
+ read_subp_attr(&vts_attributes->vtsm_subp_attr);
+ for(i=0; i<32; i++)
+ read_subp_attr(&vts_attributes->vtstt_subp_attr[i]);
+ B2N_32(vts_attributes->last_byte);
+ B2N_32(vts_attributes->vts_cat);
+
+ 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);
+ CHECK_VALUE(vts_attributes->nr_of_vtsm_audio_streams <= 1);
+ CHECK_VALUE(vts_attributes->nr_of_vtsm_subp_streams <= 1);
+ CHECK_VALUE(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]);
+ CHECK_VALUE(vts_attributes->nr_of_vtstt_subp_streams <= 32);
+ {
+ unsigned int nr_coded;
+ CHECK_VALUE(vts_attributes->last_byte + 1 >= VTS_ATTRIBUTES_MIN_SIZE);
+ 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;
+ }
+ CHECK_VALUE(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);
+ CHECK_VALUE(vts_atrt->nr_of_vtss != 0);
+ CHECK_VALUE(vts_atrt->nr_of_vtss < 100); /* ?? */
+ CHECK_VALUE((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;
+ }
+
+ vts_atrt->vts_atrt_offsets = data;
+
+ 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]);
+ CHECK_VALUE(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 */
+ CHECK_VALUE(offset + vts_atrt->vts[i].last_byte <= vts_atrt->last_byte + 1);
+ /* Is this check correct? */
+ }
+
+ 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->vts_atrt_offsets);
+ 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;
+ }
+}
+
diff --git a/lib/libdvd/libdvdread/src/ifo_read.h b/lib/libdvd/libdvdread/src/ifo_read.h
new file mode 100644
index 0000000000..3f4ea24ec2
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/ifo_read.h
@@ -0,0 +1,227 @@
+#ifndef IFO_READ_H_INCLUDED
+#define IFO_READ_H_INCLUDED
+
+/*
+ * Copyright (C) 2000, 2001, 2002 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 "ifo_types.h"
+#include "dvd_reader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * handle = ifoOpen(dvd, title);
+ *
+ * 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 *, int );
+
+/**
+ * handle = ifoOpenVMGI(dvd);
+ *
+ * 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 *);
+
+/**
+ * handle = ifoOpenVTSI(dvd, title);
+ *
+ * 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 *, int);
+
+/**
+ * ifoClose(ifofile);
+ * Cleans up the IFO information. This will free all data allocated for the
+ * substructures.
+ */
+void ifoClose(ifo_handle_t *);
+
+/**
+ * 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.
+ */
+
+/**
+ * okay = ifoRead_PLT_MAIT(ifofile);
+ *
+ * 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 *);
+
+/**
+ * okay = ifoRead_VTS_ATRT(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 *);
+
+/**
+ * okay = ifoRead_TT_SRPT(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 *);
+
+/**
+ * okay = ifoRead_VTS_PTT_SRPT(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 *);
+
+/**
+ * okay = ifoRead_FP_PGC(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 (VMGI). This structure is optional.
+ */
+int ifoRead_FP_PGC(ifo_handle_t *);
+
+/**
+ * okay = ifoRead_PGCIT(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 *);
+
+/**
+ * okay = ifoRead_PGCI_UT(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 *);
+
+/**
+ * okay = ifoRead_VTS_TMAPT(ifofile);
+ *
+ * Reads in the VTS Time Map Table, this data is only located in the video
+ * title set information file. This fills the ifofile->vts_tmapt structure
+ * and all its substructures. When pressent enables VOBU level time-based
+ * seeking for One_Sequential_PGC_Titles.
+ */
+int ifoRead_VTS_TMAPT(ifo_handle_t *);
+
+/**
+ * okay = ifoRead_C_ADT(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 *);
+
+/**
+ * okay = ifoRead_TITLE_C_ADT(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 *);
+
+/**
+ * okay = ifoRead_VOBU_ADMAP(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 *);
+
+/**
+ * okay = ifoRead_TITLE_VOBU_ADMAP(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 *);
+
+/**
+ * okay = ifoRead_TXTDT_MGI(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 *);
+
+/**
+ * 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 *);
+void ifoFree_VTS_ATRT(ifo_handle_t *);
+void ifoFree_TT_SRPT(ifo_handle_t *);
+void ifoFree_VTS_PTT_SRPT(ifo_handle_t *);
+void ifoFree_FP_PGC(ifo_handle_t *);
+void ifoFree_PGCIT(ifo_handle_t *);
+void ifoFree_PGCI_UT(ifo_handle_t *);
+void ifoFree_VTS_TMAPT(ifo_handle_t *);
+void ifoFree_C_ADT(ifo_handle_t *);
+void ifoFree_TITLE_C_ADT(ifo_handle_t *);
+void ifoFree_VOBU_ADMAP(ifo_handle_t *);
+void ifoFree_TITLE_VOBU_ADMAP(ifo_handle_t *);
+void ifoFree_TXTDT_MGI(ifo_handle_t *);
+
+#ifdef __cplusplus
+};
+#endif
+#endif /* IFO_READ_H_INCLUDED */
diff --git a/lib/libdvd/libdvdread/src/ifo_types.h b/lib/libdvd/libdvdread/src/ifo_types.h
new file mode 100644
index 0000000000..44e95da1f9
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/ifo_types.h
@@ -0,0 +1,747 @@
+#ifndef IFO_TYPES_H_INCLUDED
+#define IFO_TYPES_H_INCLUDED
+
+/*
+ * Copyright (C) 2000, 2001 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 <inttypes.h>
+#include "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 8U
+
+
+/**
+ * Video Attributes.
+ */
+typedef struct {
+ unsigned char mpeg_version : 2;
+ unsigned char video_format : 2;
+ unsigned char display_aspect_ratio : 2;
+ unsigned char permitted_df : 2;
+
+ unsigned char line21_cc_1 : 1;
+ unsigned char line21_cc_2 : 1;
+ unsigned char unknown1 : 1;
+ unsigned char bit_rate : 1;
+
+ unsigned char picture_size : 2;
+ unsigned char letterboxed : 1;
+ unsigned char film_mode : 1;
+} ATTRIBUTE_PACKED video_attr_t;
+
+/**
+ * Audio Attributes.
+ */
+typedef struct {
+ unsigned char audio_format : 3;
+ unsigned char multichannel_extension : 1;
+ unsigned char lang_type : 2;
+ unsigned char application_mode : 2;
+
+ unsigned char quantization : 2;
+ unsigned char sample_frequency : 2;
+ unsigned char unknown1 : 1;
+ unsigned char channels : 3;
+ uint16_t lang_code;
+ uint8_t lang_extension;
+ uint8_t code_extension;
+ uint8_t unknown3;
+ union {
+ struct ATTRIBUTE_PACKED {
+ unsigned char unknown4 : 1;
+ unsigned char channel_assignment : 3;
+ unsigned char version : 2;
+ unsigned char mc_intro : 1; /* probably 0: true, 1:false */
+ unsigned char mode : 1; /* Karaoke mode 0: solo 1: duet */
+ } karaoke;
+ struct ATTRIBUTE_PACKED {
+ unsigned char unknown5 : 4;
+ unsigned char dolby_encoded : 1; /* suitable for surround decoding */
+ unsigned char unknown6 : 3;
+ } surround;
+ } app_info;
+} ATTRIBUTE_PACKED audio_attr_t;
+
+
+/**
+ * MultiChannel Extension
+ */
+typedef struct {
+ unsigned int zero1 : 7;
+ unsigned int ach0_gme : 1;
+
+ unsigned int zero2 : 7;
+ unsigned int ach1_gme : 1;
+
+ unsigned int zero3 : 4;
+ unsigned int ach2_gv1e : 1;
+ unsigned int ach2_gv2e : 1;
+ unsigned int ach2_gm1e : 1;
+ unsigned int ach2_gm2e : 1;
+
+ unsigned int zero4 : 4;
+ unsigned int ach3_gv1e : 1;
+ unsigned int ach3_gv2e : 1;
+ unsigned int ach3_gmAe : 1;
+ unsigned int ach3_se2e : 1;
+
+ unsigned int zero5 : 4;
+ unsigned int ach4_gv1e : 1;
+ unsigned int ach4_gv2e : 1;
+ unsigned int ach4_gmBe : 1;
+ unsigned int ach4_seBe : 1;
+ uint8_t zero6[19];
+} ATTRIBUTE_PACKED multichannel_ext_t;
+
+
+/**
+ * Subpicture Attributes.
+ */
+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
+ */
+ unsigned char code_mode : 3;
+ unsigned char zero1 : 3;
+ unsigned char type : 2;
+ uint8_t zero2;
+ uint16_t lang_code;
+ uint8_t lang_extension;
+ uint8_t code_extension;
+} 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 8U
+
+/**
+ * PGC Program Map
+ */
+typedef uint8_t pgc_program_map_t;
+
+/**
+ * Cell Playback Information.
+ */
+typedef struct {
+ 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 playback_mode : 1; /**< When set, enter StillMode after each VOBU */
+ unsigned int restricted : 1; /**< ?? drop out of fastforward? */
+ unsigned int unknown2 : 6;
+ 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 {
+ 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;
+ unsigned int subpic_stream_change : 1;
+ unsigned int audio_stream_change : 1;
+ unsigned int pause_on : 1;
+ unsigned int still_off : 1;
+ unsigned int button_select_or_activate : 1;
+ unsigned int resume : 1; /* 16 */
+
+ unsigned int chapter_menu_call : 1; /* 15 */
+ unsigned int angle_menu_call : 1;
+ unsigned int audio_menu_call : 1;
+ unsigned int subpic_menu_call : 1;
+ unsigned int root_menu_call : 1;
+ unsigned int title_menu_call : 1;
+ unsigned int backward_scan : 1;
+ unsigned int forward_scan : 1; /* 8 */
+
+ unsigned int next_pg_search : 1; /* 7 */
+ unsigned int prev_or_top_pg_search : 1;
+ unsigned int time_or_chapter_search : 1;
+ unsigned int go_up : 1;
+ unsigned int stop : 1;
+ unsigned int title_play : 1;
+ unsigned int chapter_search_or_play : 1;
+ unsigned int title_or_time_play : 1; /* 0 */
+} 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 236U
+
+/**
+ * Program Chain Information Search Pointer.
+ */
+typedef struct {
+ uint8_t entry_id;
+ unsigned int block_mode : 2;
+ unsigned int block_type : 2;
+ unsigned int unknown1 : 4;
+ uint16_t ptl_id_mask;
+ uint32_t pgc_start_byte;
+ pgc_t *pgc;
+} ATTRIBUTE_PACKED pgci_srp_t;
+#define PGCI_SRP_SIZE 8U
+
+/**
+ * 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 8U
+
+/**
+ * Menu PGCI Language Unit.
+ */
+typedef struct {
+ uint16_t lang_code;
+ uint8_t lang_extension;
+ uint8_t exists;
+ uint32_t lang_start_byte;
+ pgcit_t *pgcit;
+} ATTRIBUTE_PACKED pgci_lu_t;
+#define PGCI_LU_SIZE 8U
+
+/**
+ * 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 8U
+
+/**
+ * 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; /* No explicit size given. */
+} ATTRIBUTE_PACKED c_adt_t;
+#define C_ADT_SIZE 8U
+
+/**
+ * VOBU Address Map.
+ */
+typedef struct {
+ uint32_t last_byte;
+ uint32_t *vobu_start_sectors;
+} ATTRIBUTE_PACKED vobu_admap_t;
+#define VOBU_ADMAP_SIZE 4U
+
+
+
+
+/**
+ * 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 {
+ 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 */
+} 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 8U
+
+
+/**
+ * Parental Management Information Unit Table.
+ * Level 1 (US: G), ..., 7 (US: NC-17), 8
+ */
+typedef uint16_t pf_level_t[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;
+ pf_level_t *pf_ptl_mai; /* table of (nr_of_vtss + 1), video_ts is first */
+} ATTRIBUTE_PACKED ptl_mait_country_t;
+#define PTL_MAIT_COUNTRY_SIZE 8U
+
+/**
+ * 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 8U
+
+/**
+ * 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 542U
+#define VTS_ATTRIBUTES_MIN_SIZE 356U
+
+/**
+ * Video Title Set Attribute Table.
+ */
+typedef struct {
+ uint16_t nr_of_vtss;
+ uint16_t zero_1;
+ uint32_t last_byte;
+ vts_attributes_t *vts;
+ uint32_t *vts_atrt_offsets; /* offsets table for each vts_attributes */
+} ATTRIBUTE_PACKED vts_atrt_t;
+#define VTS_ATRT_SIZE 8U
+
+/**
+ * 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 8U
+
+/**
+ * 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 20U
+
+
+/**
+ * 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 */
+ 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];
+ uint16_t zero_21;
+ multichannel_ext_t vts_mu_audio_attr[8];
+ /* 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;
+ uint32_t *ttu_offset; /* offset table for each ttu */
+} ATTRIBUTE_PACKED vts_ptt_srpt_t;
+#define VTS_PTT_SRPT_SIZE 8U
+
+
+/**
+ * Time Map Entry.
+ */
+/* Should this be bit field at all or just the uint32_t? */
+typedef uint32_t map_ent_t;
+
+/**
+ * Time Map.
+ */
+typedef struct {
+ uint8_t tmu; /* Time unit, in seconds */
+ uint8_t zero_1;
+ uint16_t nr_of_entries;
+ map_ent_t *map_ent;
+} ATTRIBUTE_PACKED vts_tmap_t;
+#define VTS_TMAP_SIZE 4U
+
+/**
+ * Time Map Table.
+ */
+typedef struct {
+ uint16_t nr_of_tmaps;
+ uint16_t zero_1;
+ uint32_t last_byte;
+ vts_tmap_t *tmap;
+ uint32_t *tmap_offset; /* offset table for each tmap */
+} ATTRIBUTE_PACKED vts_tmapt_t;
+#define VTS_TMAPT_SIZE 8U
+
+
+#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;
+ vts_tmapt_t *vts_tmapt;
+ c_adt_t *vts_c_adt;
+ vobu_admap_t *vts_vobu_admap;
+} ifo_handle_t;
+
+#endif /* IFO_TYPES_H_INCLUDED */
diff --git a/lib/libdvd/libdvdread/src/md5.c b/lib/libdvd/libdvdread/src/md5.c
new file mode 100644
index 0000000000..2bfdddee44
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/md5.c
@@ -0,0 +1,411 @@
+/* md5.c - Functions to compute MD5 message digest of files or memory blocks
+ according to the definition of MD5 in RFC 1321 from April 1992.
+ Copyright (C) 1995, 1996, 2001 Free Software Foundation, Inc.
+ NOTE: The canonical source of this file is maintained with the GNU C
+ Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, 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. */
+
+/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "md5.h"
+/* #include "unlocked-io.h" */
+
+#ifdef _LIBC
+# include <endian.h>
+# if __BYTE_ORDER == __BIG_ENDIAN
+# define WORDS_BIGENDIAN 1
+# endif
+#endif
+
+#ifdef WORDS_BIGENDIAN
+# define SWAP(n) \
+ (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
+#else
+# define SWAP(n) (n)
+#endif
+
+
+/* This array contains the bytes used to pad the buffer to the next
+ 64-byte boundary. (RFC 1321, 3.1: Step 1) */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
+
+
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+void
+md5_init_ctx (ctx)
+ struct md5_ctx *ctx;
+{
+ ctx->A = 0x67452301;
+ ctx->B = 0xefcdab89;
+ ctx->C = 0x98badcfe;
+ ctx->D = 0x10325476;
+
+ ctx->total[0] = ctx->total[1] = 0;
+ ctx->buflen = 0;
+}
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result
+ must be in little endian byte order.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+void *
+md5_read_ctx (ctx, resbuf)
+ const struct md5_ctx *ctx;
+ void *resbuf;
+{
+ ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
+ ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
+ ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
+ ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
+
+ return resbuf;
+}
+
+/* Process the remaining bytes in the internal buffer and the usual
+ prolog according to the standard and write the result to RESBUF.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+void *
+md5_finish_ctx (ctx, resbuf)
+ struct md5_ctx *ctx;
+ void *resbuf;
+{
+ /* Take yet unprocessed bytes into account. */
+ md5_uint32 bytes = ctx->buflen;
+ size_t pad;
+
+ /* Now count remaining bytes. */
+ ctx->total[0] += bytes;
+ if (ctx->total[0] < bytes)
+ ++ctx->total[1];
+
+ pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
+ memcpy (&ctx->buffer[bytes], fillbuf, pad);
+
+ /* Put the 64-bit file length in *bits* at the end of the buffer. */
+ *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3);
+ *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) |
+ (ctx->total[0] >> 29));
+
+ /* Process last bytes. */
+ md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
+
+ return md5_read_ctx (ctx, resbuf);
+}
+
+/* Compute MD5 message digest for bytes read from STREAM. The
+ resulting message digest number will be written into the 16 bytes
+ beginning at RESBLOCK. */
+int
+md5_stream (stream, resblock)
+ FILE *stream;
+ void *resblock;
+{
+ /* Important: BLOCKSIZE must be a multiple of 64. */
+#define BLOCKSIZE 4096
+ struct md5_ctx ctx;
+ char buffer[BLOCKSIZE + 72];
+ size_t sum;
+
+ /* Initialize the computation context. */
+ md5_init_ctx (&ctx);
+
+ /* Iterate over full file contents. */
+ while (1)
+ {
+ /* We read the file in blocks of BLOCKSIZE bytes. One call of the
+ computation function processes the whole buffer so that with the
+ next round of the loop another block can be read. */
+ size_t n;
+ sum = 0;
+
+ /* Read block. Take care for partial reads. */
+ do
+ {
+ n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
+
+ sum += n;
+ }
+ while (sum < BLOCKSIZE && n != 0);
+ if (n == 0 && ferror (stream))
+ return 1;
+
+ /* If end of file is reached, end the loop. */
+ if (n == 0)
+ break;
+
+ /* Process buffer with BLOCKSIZE bytes. Note that
+ BLOCKSIZE % 64 == 0
+ */
+ md5_process_block (buffer, BLOCKSIZE, &ctx);
+ }
+
+ /* Add the last bytes if necessary. */
+ if (sum > 0)
+ md5_process_bytes (buffer, sum, &ctx);
+
+ /* Construct result in desired memory. */
+ md5_finish_ctx (&ctx, resblock);
+ return 0;
+}
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+void *
+md5_buffer (buffer, len, resblock)
+ const char *buffer;
+ size_t len;
+ void *resblock;
+{
+ struct md5_ctx ctx;
+
+ /* Initialize the computation context. */
+ md5_init_ctx (&ctx);
+
+ /* Process whole buffer but last len % 64 bytes. */
+ md5_process_bytes (buffer, len, &ctx);
+
+ /* Put result in desired memory area. */
+ return md5_finish_ctx (&ctx, resblock);
+}
+
+
+void
+md5_process_bytes (buffer, len, ctx)
+ const void *buffer;
+ size_t len;
+ struct md5_ctx *ctx;
+{
+ /* When we already have some bits in our internal buffer concatenate
+ both inputs first. */
+ if (ctx->buflen != 0)
+ {
+ size_t left_over = ctx->buflen;
+ size_t add = 128 - left_over > len ? len : 128 - left_over;
+
+ memcpy (&ctx->buffer[left_over], buffer, add);
+ ctx->buflen += add;
+
+ if (left_over + add > 64)
+ {
+ md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx);
+ /* The regions in the following copy operation cannot overlap. */
+ memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
+ (left_over + add) & 63);
+ ctx->buflen = (left_over + add) & 63;
+ }
+
+ buffer = (const char *) buffer + add;
+ len -= add;
+ }
+
+ /* Process available complete blocks. */
+ if (len > 64)
+ {
+ md5_process_block (buffer, len & ~63, ctx);
+ buffer = (const char *) buffer + (len & ~63);
+ len &= 63;
+ }
+
+ /* Move remaining bytes in internal buffer. */
+ if (len > 0)
+ {
+ memcpy (ctx->buffer, buffer, len);
+ ctx->buflen = len;
+ }
+}
+
+
+/* These are the four functions used in the four steps of the MD5 algorithm
+ and defined in the RFC 1321. The first function is a little bit optimized
+ (as found in Colin Plumbs public domain implementation). */
+/* #define FF(b, c, d) ((b & c) | (~b & d)) */
+#define FF(b, c, d) (d ^ (b & (c ^ d)))
+#define FG(b, c, d) FF (d, b, c)
+#define FH(b, c, d) (b ^ c ^ d)
+#define FI(b, c, d) (c ^ (b | ~d))
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+ It is assumed that LEN % 64 == 0. */
+
+void
+md5_process_block (buffer, len, ctx)
+ const void *buffer;
+ size_t len;
+ struct md5_ctx *ctx;
+{
+ md5_uint32 correct_words[16];
+ const md5_uint32 *words = buffer;
+ size_t nwords = len / sizeof (md5_uint32);
+ const md5_uint32 *endp = words + nwords;
+ md5_uint32 A = ctx->A;
+ md5_uint32 B = ctx->B;
+ md5_uint32 C = ctx->C;
+ md5_uint32 D = ctx->D;
+
+ /* First increment the byte count. RFC 1321 specifies the possible
+ length of the file up to 2^64 bits. Here we only compute the
+ number of bytes. Do a double word increment. */
+ ctx->total[0] += len;
+ if (ctx->total[0] < len)
+ ++ctx->total[1];
+
+ /* Process all bytes in the buffer with 64 bytes in each round of
+ the loop. */
+ while (words < endp)
+ {
+ md5_uint32 *cwp = correct_words;
+ md5_uint32 A_save = A;
+ md5_uint32 B_save = B;
+ md5_uint32 C_save = C;
+ md5_uint32 D_save = D;
+
+ /* First round: using the given function, the context and a constant
+ the next context is computed. Because the algorithms processing
+ unit is a 32-bit word and it is determined to work on words in
+ little endian byte order we perhaps have to change the byte order
+ before the computation. To reduce the work for the next steps
+ we store the swapped words in the array CORRECT_WORDS. */
+
+#define OP(a, b, c, d, s, T) \
+ do \
+ { \
+ a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
+ ++words; \
+ a = rol (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* Before we start, one word to the strange constants.
+ They are defined in RFC 1321 as
+
+ T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64, or
+ perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}'
+ */
+
+ /* Round 1. */
+ OP (A, B, C, D, 7, 0xd76aa478);
+ OP (D, A, B, C, 12, 0xe8c7b756);
+ OP (C, D, A, B, 17, 0x242070db);
+ OP (B, C, D, A, 22, 0xc1bdceee);
+ OP (A, B, C, D, 7, 0xf57c0faf);
+ OP (D, A, B, C, 12, 0x4787c62a);
+ OP (C, D, A, B, 17, 0xa8304613);
+ OP (B, C, D, A, 22, 0xfd469501);
+ OP (A, B, C, D, 7, 0x698098d8);
+ OP (D, A, B, C, 12, 0x8b44f7af);
+ OP (C, D, A, B, 17, 0xffff5bb1);
+ OP (B, C, D, A, 22, 0x895cd7be);
+ OP (A, B, C, D, 7, 0x6b901122);
+ OP (D, A, B, C, 12, 0xfd987193);
+ OP (C, D, A, B, 17, 0xa679438e);
+ OP (B, C, D, A, 22, 0x49b40821);
+
+ /* For the second to fourth round we have the possibly swapped words
+ in CORRECT_WORDS. Redefine the macro to take an additional first
+ argument specifying the function to use. */
+#undef OP
+#define OP(f, a, b, c, d, k, s, T) \
+ do \
+ { \
+ a += f (b, c, d) + correct_words[k] + T; \
+ a = rol (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* Round 2. */
+ OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
+ OP (FG, D, A, B, C, 6, 9, 0xc040b340);
+ OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
+ OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
+ OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
+ OP (FG, D, A, B, C, 10, 9, 0x02441453);
+ OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
+ OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
+ OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
+ OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
+ OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
+ OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
+ OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
+ OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
+ OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
+ OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
+
+ /* Round 3. */
+ OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
+ OP (FH, D, A, B, C, 8, 11, 0x8771f681);
+ OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
+ OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
+ OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
+ OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
+ OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
+ OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
+ OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
+ OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
+ OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
+ OP (FH, B, C, D, A, 6, 23, 0x04881d05);
+ OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
+ OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
+ OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
+ OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
+
+ /* Round 4. */
+ OP (FI, A, B, C, D, 0, 6, 0xf4292244);
+ OP (FI, D, A, B, C, 7, 10, 0x432aff97);
+ OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
+ OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
+ OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
+ OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
+ OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
+ OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
+ OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
+ OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
+ OP (FI, C, D, A, B, 6, 15, 0xa3014314);
+ OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
+ OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
+ OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
+ OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
+ OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
+
+ /* Add the starting values of the context. */
+ A += A_save;
+ B += B_save;
+ C += C_save;
+ D += D_save;
+ }
+
+ /* Put checksum in context given as argument. */
+ ctx->A = A;
+ ctx->B = B;
+ ctx->C = C;
+ ctx->D = D;
+}
diff --git a/lib/libdvd/libdvdread/src/md5.h b/lib/libdvd/libdvdread/src/md5.h
new file mode 100644
index 0000000000..3b7dea1699
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/md5.h
@@ -0,0 +1,161 @@
+/* md5.h - Declaration of functions and data types used for MD5 sum
+ computing library functions.
+ Copyright (C) 1995, 1996, 1999 Free Software Foundation, Inc.
+ NOTE: The canonical source of this file is maintained with the GNU C
+ Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, 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 _MD5_H
+#define _MD5_H 1
+
+#include <stdio.h>
+
+#if defined HAVE_LIMITS_H || _LIBC
+# include <limits.h>
+#endif
+
+/* The following contortions are an attempt to use the C preprocessor
+ to determine an unsigned integral type that is 32 bits wide. An
+ alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
+ doing that would require that the configure script compile and *run*
+ the resulting executable. Locally running cross-compiled executables
+ is usually not possible. */
+
+#ifdef _LIBC
+# include <sys/types.h>
+typedef u_int32_t md5_uint32;
+#else
+# if defined __STDC__ && __STDC__
+# define UINT_MAX_32_BITS 4294967295U
+# else
+# define UINT_MAX_32_BITS 0xFFFFFFFF
+# endif
+
+/* If UINT_MAX isn't defined, assume it's a 32-bit type.
+ This should be valid for all systems GNU cares about because
+ that doesn't include 16-bit systems, and only modern systems
+ (that certainly have <limits.h>) have 64+-bit integral types. */
+
+# ifndef UINT_MAX
+# define UINT_MAX UINT_MAX_32_BITS
+# endif
+
+# if UINT_MAX == UINT_MAX_32_BITS
+ typedef unsigned int md5_uint32;
+# else
+# if USHRT_MAX == UINT_MAX_32_BITS
+ typedef unsigned short md5_uint32;
+# else
+# if ULONG_MAX == UINT_MAX_32_BITS
+ typedef unsigned long md5_uint32;
+# else
+ /* The following line is intended to evoke an error.
+ Using #error is not portable enough. */
+ "Cannot determine unsigned 32-bit data type."
+# endif
+# endif
+# endif
+#endif
+
+#undef __P
+#if defined (__STDC__) && __STDC__
+#define __P(x) x
+#else
+#define __P(x) ()
+#endif
+
+/* Structure to save state of computation between the single steps. */
+struct md5_ctx
+{
+ md5_uint32 A;
+ md5_uint32 B;
+ md5_uint32 C;
+ md5_uint32 D;
+
+ md5_uint32 total[2];
+ md5_uint32 buflen;
+ char buffer[128];
+};
+
+/*
+ * The following three functions are build up the low level used in
+ * the functions `md5_stream' and `md5_buffer'.
+ */
+
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+extern void md5_init_ctx __P ((struct md5_ctx *ctx));
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is necessary that LEN is a multiple of 64!!! */
+extern void md5_process_block __P ((const void *buffer, size_t len,
+ struct md5_ctx *ctx));
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is NOT required that LEN is a multiple of 64. */
+extern void md5_process_bytes __P ((const void *buffer, size_t len,
+ struct md5_ctx *ctx));
+
+/* Process the remaining bytes in the buffer and put result from CTX
+ in first 16 bytes following RESBUF. The result is always in little
+ endian byte order, so that a byte-wise output yields to the wanted
+ ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF be correctly
+ aligned for a 32 bits value. */
+extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));
+
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result is
+ always in little endian byte order, so that a byte-wise output yields
+ to the wanted ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf));
+
+
+/* Compute MD5 message digest for bytes read from STREAM. The
+ resulting message digest number will be written into the 16 bytes
+ beginning at RESBLOCK. */
+extern int md5_stream __P ((FILE *stream, void *resblock));
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+extern void *md5_buffer __P ((const char *buffer, size_t len, void *resblock));
+
+/* The following is from gnupg-1.0.2's cipher/bithelp.h. */
+/* Rotate a 32 bit integer by n bytes */
+#if defined __GNUC__ && defined __i386__
+static inline md5_uint32
+rol(md5_uint32 x, int n)
+{
+ __asm__("roll %%cl,%0"
+ :"=r" (x)
+ :"0" (x),"c" (n));
+ return x;
+}
+#else
+# define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) )
+#endif
+
+#endif
diff --git a/lib/libdvd/libdvdread/src/nav_print.c b/lib/libdvd/libdvdread/src/nav_print.c
new file mode 100644
index 0000000000..a4370c16e6
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/nav_print.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2000, 2001, 2002, 2003 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 "config.h"
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include "nav_types.h"
+#include "nav_print.h"
+#include "ifo_print.h"
+
+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 ");
+ dvdread_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 ");
+ dvdread_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);
+}
+
+
diff --git a/lib/libdvd/libdvdread/src/nav_print.h b/lib/libdvd/libdvdread/src/nav_print.h
new file mode 100644
index 0000000000..bc79ab641f
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/nav_print.h
@@ -0,0 +1,50 @@
+#ifndef NAV_PRINT_H_INCLUDED
+#define NAV_PRINT_H_INCLUDED
+
+/*
+ * Copyright (C) 2001, 2002 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
+ */
+
+#include "nav_types.h"
+
+/**
+ * Pretty printing of the NAV packets, PCI and DSI structs.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Prints information contained in the PCI to stdout.
+ *
+ * @param pci Pointer to the PCI data structure to be printed.
+ */
+void navPrint_PCI(pci_t *);
+
+/**
+ * Prints information contained in the DSI to stdout.
+ *
+ * @param dsi Pointer to the DSI data structure to be printed.
+ */
+void navPrint_DSI(dsi_t *);
+
+#ifdef __cplusplus
+};
+#endif
+#endif /* NAV_PRINT_H_INCLUDED */
diff --git a/lib/libdvd/libdvdread/src/nav_read.c b/lib/libdvd/libdvdread/src/nav_read.c
new file mode 100644
index 0000000000..8ee6033a25
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/nav_read.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2000, 2001, 2002, 2003 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 "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "bswap.h"
+#include "nav_types.h"
+#include "nav_read.h"
+#include "dvdread_internal.h"
+#include "bitreader.h"
+
+#define getbits_init dvdread_getbits_init
+#define getbits dvdread_getbits
+
+void navRead_PCI(pci_t *pci, unsigned char *buffer) {
+ int32_t i, j;
+ getbits_state_t state;
+ if (!getbits_init(&state, buffer)) abort(); /* Passed NULL pointers */
+
+ /* pci pci_gi */
+ pci->pci_gi.nv_pck_lbn = getbits(&state, 32 );
+ pci->pci_gi.vobu_cat = getbits(&state, 16 );
+ pci->pci_gi.zero1 = getbits(&state, 16 );
+ pci->pci_gi.vobu_uop_ctl.zero = getbits(&state, 7 );
+ pci->pci_gi.vobu_uop_ctl.video_pres_mode_change = getbits(&state, 1 );
+
+ pci->pci_gi.vobu_uop_ctl.karaoke_audio_pres_mode_change = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.angle_change = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.subpic_stream_change = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.audio_stream_change = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.pause_on = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.still_off = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.button_select_or_activate = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.resume = getbits(&state, 1 );
+
+ pci->pci_gi.vobu_uop_ctl.chapter_menu_call = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.angle_menu_call = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.audio_menu_call = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.subpic_menu_call = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.root_menu_call = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.title_menu_call = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.backward_scan = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.forward_scan = getbits(&state, 1 );
+
+ pci->pci_gi.vobu_uop_ctl.next_pg_search = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.prev_or_top_pg_search = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.time_or_chapter_search = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.go_up = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.stop = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.title_play = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.chapter_search_or_play = getbits(&state, 1 );
+ pci->pci_gi.vobu_uop_ctl.title_or_time_play = getbits(&state, 1 );
+ pci->pci_gi.vobu_s_ptm = getbits(&state, 32 );
+ pci->pci_gi.vobu_e_ptm = getbits(&state, 32 );
+ pci->pci_gi.vobu_se_e_ptm = getbits(&state, 32 );
+ pci->pci_gi.e_eltm.hour = getbits(&state, 8 );
+ pci->pci_gi.e_eltm.minute = getbits(&state, 8 );
+ pci->pci_gi.e_eltm.second = getbits(&state, 8 );
+ pci->pci_gi.e_eltm.frame_u = getbits(&state, 8 );
+ for(i = 0; i < 32; i++)
+ pci->pci_gi.vobu_isrc[i] = getbits(&state, 8 );
+
+ /* pci nsml_agli */
+ for(i = 0; i < 9; i++)
+ pci->nsml_agli.nsml_agl_dsta[i] = getbits(&state, 32 );
+
+ /* pci hli hli_gi */
+ pci->hli.hl_gi.hli_ss = getbits(&state, 16 );
+ pci->hli.hl_gi.hli_s_ptm = getbits(&state, 32 );
+ pci->hli.hl_gi.hli_e_ptm = getbits(&state, 32 );
+ pci->hli.hl_gi.btn_se_e_ptm = getbits(&state, 32 );
+ pci->hli.hl_gi.zero1 = getbits(&state, 2 );
+ pci->hli.hl_gi.btngr_ns = getbits(&state, 2 );
+ pci->hli.hl_gi.zero2 = getbits(&state, 1 );
+ pci->hli.hl_gi.btngr1_dsp_ty = getbits(&state, 3 );
+ pci->hli.hl_gi.zero3 = getbits(&state, 1 );
+ pci->hli.hl_gi.btngr2_dsp_ty = getbits(&state, 3 );
+ pci->hli.hl_gi.zero4 = getbits(&state, 1 );
+ pci->hli.hl_gi.btngr3_dsp_ty = getbits(&state, 3 );
+ pci->hli.hl_gi.btn_ofn = getbits(&state, 8 );
+ pci->hli.hl_gi.btn_ns = getbits(&state, 8 );
+ pci->hli.hl_gi.nsl_btn_ns = getbits(&state, 8 );
+ pci->hli.hl_gi.zero5 = getbits(&state, 8 );
+ pci->hli.hl_gi.fosl_btnn = getbits(&state, 8 );
+ pci->hli.hl_gi.foac_btnn = getbits(&state, 8 );
+
+ /* pci hli btn_colit */
+ for(i = 0; i < 3; i++)
+ for(j = 0; j < 2; j++)
+ pci->hli.btn_colit.btn_coli[i][j] = getbits(&state, 32 );
+
+ /* NOTE: I've had to change the structure from the disk layout to get
+ * the packing to work with Sun's Forte C compiler. */
+
+ /* pci hli btni */
+ for(i = 0; i < 36; i++) {
+ pci->hli.btnit[i].btn_coln = getbits(&state, 2 );
+ pci->hli.btnit[i].x_start = getbits(&state, 10 );
+ pci->hli.btnit[i].zero1 = getbits(&state, 2 );
+ pci->hli.btnit[i].x_end = getbits(&state, 10 );
+
+ pci->hli.btnit[i].auto_action_mode = getbits(&state, 2 );
+ pci->hli.btnit[i].y_start = getbits(&state, 10 );
+ pci->hli.btnit[i].zero2 = getbits(&state, 2 );
+ pci->hli.btnit[i].y_end = getbits(&state, 10 );
+
+ pci->hli.btnit[i].zero3 = getbits(&state, 2 );
+ pci->hli.btnit[i].up = getbits(&state, 6 );
+ pci->hli.btnit[i].zero4 = getbits(&state, 2 );
+ pci->hli.btnit[i].down = getbits(&state, 6 );
+ pci->hli.btnit[i].zero5 = getbits(&state, 2 );
+ pci->hli.btnit[i].left = getbits(&state, 6 );
+ pci->hli.btnit[i].zero6 = getbits(&state, 2 );
+ pci->hli.btnit[i].right = getbits(&state, 6 );
+ /* pci vm_cmd */
+ for(j = 0; j < 8; j++)
+ pci->hli.btnit[i].cmd.bytes[j] = getbits(&state, 8 );
+ }
+
+
+
+#ifndef NDEBUG
+ /* Asserts */
+
+ /* pci pci gi */
+ CHECK_VALUE(pci->pci_gi.zero1 == 0);
+
+ /* pci hli hli_gi */
+ CHECK_VALUE(pci->hli.hl_gi.zero1 == 0);
+ CHECK_VALUE(pci->hli.hl_gi.zero2 == 0);
+ CHECK_VALUE(pci->hli.hl_gi.zero3 == 0);
+ CHECK_VALUE(pci->hli.hl_gi.zero4 == 0);
+ CHECK_VALUE(pci->hli.hl_gi.zero5 == 0);
+
+ /* Are there buttons defined here? */
+ if((pci->hli.hl_gi.hli_ss & 0x03) != 0) {
+ CHECK_VALUE(pci->hli.hl_gi.btn_ns != 0);
+ CHECK_VALUE(pci->hli.hl_gi.btngr_ns != 0);
+ } else {
+ CHECK_VALUE((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 */
+ 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;
+ CHECK_VALUE(pci->hli.btnit[n].zero1 == 0);
+ CHECK_VALUE(pci->hli.btnit[n].zero2 == 0);
+ CHECK_VALUE(pci->hli.btnit[n].zero3 == 0);
+ CHECK_VALUE(pci->hli.btnit[n].zero4 == 0);
+ CHECK_VALUE(pci->hli.btnit[n].zero5 == 0);
+ CHECK_VALUE(pci->hli.btnit[n].zero6 == 0);
+
+ if (j < pci->hli.hl_gi.btn_ns) {
+ CHECK_VALUE(pci->hli.btnit[n].x_start <= pci->hli.btnit[n].x_end);
+ CHECK_VALUE(pci->hli.btnit[n].y_start <= pci->hli.btnit[n].y_end);
+ CHECK_VALUE(pci->hli.btnit[n].up <= pci->hli.hl_gi.btn_ns);
+ CHECK_VALUE(pci->hli.btnit[n].down <= pci->hli.hl_gi.btn_ns);
+ CHECK_VALUE(pci->hli.btnit[n].left <= pci->hli.hl_gi.btn_ns);
+ CHECK_VALUE(pci->hli.btnit[n].right <= pci->hli.hl_gi.btn_ns);
+ /* vmcmd_verify(pci->hli.btnit[n].cmd); */
+ } else {
+ int k;
+ CHECK_VALUE(pci->hli.btnit[n].btn_coln == 0);
+ CHECK_VALUE(pci->hli.btnit[n].auto_action_mode == 0);
+ CHECK_VALUE(pci->hli.btnit[n].x_start == 0);
+ CHECK_VALUE(pci->hli.btnit[n].y_start == 0);
+ CHECK_VALUE(pci->hli.btnit[n].x_end == 0);
+ CHECK_VALUE(pci->hli.btnit[n].y_end == 0);
+ CHECK_VALUE(pci->hli.btnit[n].up == 0);
+ CHECK_VALUE(pci->hli.btnit[n].down == 0);
+ CHECK_VALUE(pci->hli.btnit[n].left == 0);
+ CHECK_VALUE(pci->hli.btnit[n].right == 0);
+ for (k = 0; k < 8; k++)
+ CHECK_VALUE(pci->hli.btnit[n].cmd.bytes[k] == 0); /* CHECK_ZERO? */
+ }
+ }
+ }
+#endif /* !NDEBUG */
+}
+
+void navRead_DSI(dsi_t *dsi, unsigned char *buffer) {
+ int i;
+ getbits_state_t state;
+ if (!getbits_init(&state, buffer)) abort(); /* Passed NULL pointers */
+
+ /* dsi dsi gi */
+ dsi->dsi_gi.nv_pck_scr = getbits(&state, 32 );
+ dsi->dsi_gi.nv_pck_lbn = getbits(&state, 32 );
+ dsi->dsi_gi.vobu_ea = getbits(&state, 32 );
+ dsi->dsi_gi.vobu_1stref_ea = getbits(&state, 32 );
+ dsi->dsi_gi.vobu_2ndref_ea = getbits(&state, 32 );
+ dsi->dsi_gi.vobu_3rdref_ea = getbits(&state, 32 );
+ dsi->dsi_gi.vobu_vob_idn = getbits(&state, 16 );
+ dsi->dsi_gi.zero1 = getbits(&state, 8 );
+ dsi->dsi_gi.vobu_c_idn = getbits(&state, 8 );
+ dsi->dsi_gi.c_eltm.hour = getbits(&state, 8 );
+ dsi->dsi_gi.c_eltm.minute = getbits(&state, 8 );
+ dsi->dsi_gi.c_eltm.second = getbits(&state, 8 );
+ dsi->dsi_gi.c_eltm.frame_u = getbits(&state, 8 );
+
+ /* dsi sml pbi */
+ dsi->sml_pbi.category = getbits(&state, 16 );
+ dsi->sml_pbi.ilvu_ea = getbits(&state, 32 );
+ dsi->sml_pbi.ilvu_sa = getbits(&state, 32 );
+ dsi->sml_pbi.size = getbits(&state, 16 );
+ dsi->sml_pbi.vob_v_s_s_ptm = getbits(&state, 32 );
+ dsi->sml_pbi.vob_v_e_e_ptm = getbits(&state, 32 );
+ for(i = 0; i < 8; i++) {
+ dsi->sml_pbi.vob_a[i].stp_ptm1 = getbits(&state, 32 );
+ dsi->sml_pbi.vob_a[i].stp_ptm2 = getbits(&state, 32 );
+ dsi->sml_pbi.vob_a[i].gap_len1 = getbits(&state, 32 );
+ dsi->sml_pbi.vob_a[i].gap_len2 = getbits(&state, 32 );
+ }
+
+ /* dsi sml agli */
+ for(i = 0; i < 9; i++) {
+ dsi->sml_agli.data[ i ].address = getbits(&state, 32 );
+ dsi->sml_agli.data[ i ].size = getbits(&state, 16 );
+ }
+
+ /* dsi vobu sri */
+ dsi->vobu_sri.next_video = getbits(&state, 32 );
+ for(i = 0; i < 19; i++)
+ dsi->vobu_sri.fwda[i] = getbits(&state, 32 );
+ dsi->vobu_sri.next_vobu = getbits(&state, 32 );
+ dsi->vobu_sri.prev_vobu = getbits(&state, 32 );
+ for(i = 0; i < 19; i++)
+ dsi->vobu_sri.bwda[i] = getbits(&state, 32 );
+ dsi->vobu_sri.prev_video = getbits(&state, 32 );
+
+ /* dsi synci */
+ for(i = 0; i < 8; i++)
+ dsi->synci.a_synca[i] = getbits(&state, 16 );
+ for(i = 0; i < 32; i++)
+ dsi->synci.sp_synca[i] = getbits(&state, 32 );
+
+
+ /* Asserts */
+
+ /* dsi dsi gi */
+ CHECK_VALUE(dsi->dsi_gi.zero1 == 0);
+}
+
diff --git a/lib/libdvd/libdvdread/src/nav_read.h b/lib/libdvd/libdvdread/src/nav_read.h
new file mode 100644
index 0000000000..48fe2c8524
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/nav_read.h
@@ -0,0 +1,51 @@
+#ifndef NAV_READ_H_INCLUDED
+#define NAV_READ_H_INCLUDED
+
+/*
+ * Copyright (C) 2000, 2001, 2002 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 "nav_types.h"
+
+/**
+ * Parsing of NAV data, PCI and DSI parts.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Reads the PCI packet data pointed to into th pci struct.
+ *
+ * @param pci Pointer to the PCI data structure to be filled in.
+ * @param bufffer Pointer to the buffer of the on disc PCI data.
+ */
+void navRead_PCI(pci_t *, unsigned char *);
+
+/**
+ * Reads the DSI packet data pointed to into dsi struct.
+ *
+ * @param dsi Pointer to the DSI data structure to be filled in.
+ * @param bufffer Pointer to the buffer of the on disc DSI data.
+ */
+void navRead_DSI(dsi_t *, unsigned char *);
+
+#ifdef __cplusplus
+};
+#endif
+#endif /* NAV_READ_H_INCLUDED */
diff --git a/lib/libdvd/libdvdread/src/nav_types.h b/lib/libdvd/libdvdread/src/nav_types.h
new file mode 100644
index 0000000000..e0bbe2f57b
--- /dev/null
+++ b/lib/libdvd/libdvdread/src/nav_types.h
@@ -0,0 +1,249 @@
+#ifndef NAV_TYPES_H_INCLUDED
+#define NAV_TYPES_H_INCLUDED
+
+/*
+ * Copyright (C) 2000, 2001, 2002 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
+ */
+
+#include <inttypes.h>
+#include "ifo_types.h" /* only dvd_time_t, vm_cmd_t and user_ops_t */
+
+/* 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
+
+/**
+ * PCI General Information
+ */
+typedef struct {
+ uint32_t nv_pck_lbn; /**< sector address of this nav pack */
+ uint16_t vobu_cat; /**< 'category' of vobu */
+ uint16_t zero1; /**< reserved */
+ user_ops_t vobu_uop_ctl; /**< UOP of vobu */
+ uint32_t vobu_s_ptm; /**< start presentation time of vobu */
+ uint32_t vobu_e_ptm; /**< end presentation time of vobu */
+ uint32_t vobu_se_e_ptm; /**< end ptm of sequence end in vobu */
+ dvd_time_t e_eltm; /**< Cell elapsed time */
+ char vobu_isrc[32];
+} ATTRIBUTE_PACKED pci_gi_t;
+
+/**
+ * Non Seamless Angle Information
+ */
+typedef struct {
+ uint32_t nsml_agl_dsta[9]; /**< address of destination vobu in AGL_C#n */
+} ATTRIBUTE_PACKED nsml_agli_t;
+
+/**
+ * Highlight General Information
+ *
+ * For btngrX_dsp_ty the bits have the following meaning:
+ * 000b: normal 4/3 only buttons
+ * XX1b: wide (16/9) buttons
+ * X1Xb: letterbox buttons
+ * 1XXb: pan&scan buttons
+ */
+typedef struct {
+ uint16_t hli_ss; /**< status, only low 2 bits 0: no buttons, 1: different 2: equal 3: eual except for button cmds */
+ uint32_t hli_s_ptm; /**< start ptm of hli */
+ uint32_t hli_e_ptm; /**< end ptm of hli */
+ uint32_t btn_se_e_ptm; /**< end ptm of button select */
+ unsigned int zero1 : 2; /**< reserved */
+ unsigned int btngr_ns : 2; /**< number of button groups 1, 2 or 3 with 36/18/12 buttons */
+ unsigned int zero2 : 1; /**< reserved */
+ unsigned int btngr1_dsp_ty : 3; /**< display type of subpic stream for button group 1 */
+ unsigned int zero3 : 1; /**< reserved */
+ unsigned int btngr2_dsp_ty : 3; /**< display type of subpic stream for button group 2 */
+ unsigned int zero4 : 1; /**< reserved */
+ unsigned int btngr3_dsp_ty : 3; /**< display type of subpic stream for button group 3 */
+ uint8_t btn_ofn; /**< button offset number range 0-255 */
+ uint8_t btn_ns; /**< number of valid buttons <= 36/18/12 (low 6 bits) */
+ uint8_t nsl_btn_ns; /**< number of buttons selectable by U_BTNNi (low 6 bits) nsl_btn_ns <= btn_ns */
+ uint8_t zero5; /**< reserved */
+ uint8_t fosl_btnn; /**< forcedly selected button (low 6 bits) */
+ uint8_t foac_btnn; /**< forcedly activated button (low 6 bits) */
+} ATTRIBUTE_PACKED hl_gi_t;
+
+
+/**
+ * Button Color Information Table
+ * Each entry beeing a 32bit word that contains the color indexs and alpha
+ * values to use. They are all represented by 4 bit number and stored
+ * like this [Ci3, Ci2, Ci1, Ci0, A3, A2, A1, A0]. The actual palette
+ * that the indexes reference is in the PGC.
+ * @TODO split the uint32_t into a struct
+ */
+typedef struct {
+ uint32_t btn_coli[3][2]; /**< [button color number-1][select:0/action:1] */
+} ATTRIBUTE_PACKED btn_colit_t;
+
+/**
+ * Button Information
+ *
+ * NOTE: I've had to change the structure from the disk layout to get
+ * the packing to work with Sun's Forte C compiler.
+ * The 4 and 7 bytes are 'rotated' was: ABC DEF GHIJ is: ABCG DEFH IJ
+ */
+typedef struct {
+ unsigned int btn_coln : 2; /**< button color number */
+ unsigned int x_start : 10; /**< x start offset within the overlay */
+ unsigned int zero1 : 2; /**< reserved */
+ unsigned int x_end : 10; /**< x end offset within the overlay */
+
+ unsigned int auto_action_mode : 2; /**< 0: no, 1: activated if selected */
+ unsigned int y_start : 10; /**< y start offset within the overlay */
+ unsigned int zero2 : 2; /**< reserved */
+ unsigned int y_end : 10; /**< y end offset within the overlay */
+
+ unsigned int zero3 : 2; /**< reserved */
+ unsigned int up : 6; /**< button index when pressing up */
+ unsigned int zero4 : 2; /**< reserved */
+ unsigned int down : 6; /**< button index when pressing down */
+ unsigned int zero5 : 2; /**< reserved */
+ unsigned int left : 6; /**< button index when pressing left */
+ unsigned int zero6 : 2; /**< reserved */
+ unsigned int right : 6; /**< button index when pressing right */
+ 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; /**< sector address of this nav pack */
+ uint32_t vobu_ea; /**< end address of this VOBU */
+ uint32_t vobu_1stref_ea; /**< end address of the 1st reference image */
+ uint32_t vobu_2ndref_ea; /**< end address of the 2nd reference image */
+ uint32_t vobu_3rdref_ea; /**< end address of the 3rd reference image */
+ uint16_t vobu_vob_idn; /**< VOB Id number that this VOBU is part of */
+ uint8_t zero1; /**< reserved */
+ uint8_t vobu_c_idn; /**< Cell Id number that this VOBU is part of */
+ dvd_time_t c_eltm; /**< Cell elapsed time */
+} 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 */
+ uint32_t ilvu_sa; /**< start address of next interleaved unit */
+ uint16_t size; /**< size of next interleaved unit */
+ 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; /**< offset to next ILVU, high bit is before/after */
+ uint16_t size; /**< byte size of the ILVU pointed 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]; /**< offset to first audio packet for this VOBU */
+ uint32_t sp_synca[32]; /**< 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 */
diff --git a/lib/libdvd/libdvdread/version.h b/lib/libdvd/libdvdread/version.h
new file mode 100644
index 0000000000..fd4fb3ab13
--- /dev/null
+++ b/lib/libdvd/libdvdread/version.h
@@ -0,0 +1 @@
+#define VERSION "4.1.3"
diff --git a/lib/libdvd/libdvdread/version.sh b/lib/libdvd/libdvdread/version.sh
new file mode 100755
index 0000000000..230da4a8af
--- /dev/null
+++ b/lib/libdvd/libdvdread/version.sh
@@ -0,0 +1,18 @@
+##!/bin/sh
+#
+#svn_revision=`cd "$1" && LC_ALL=C svn info 2> /dev/null | grep Revision | cut -d' ' -f2`
+#test $svn_revision || svn_revision=`cd "$1" && grep revision .svn/entries 2>/dev/null | \
+# cut -d '"' -f2 2> /dev/null`
+#test $svn_revision || svn_revision=UNKNOWN
+#
+#if test "$svn_revision" = UNKNOWN && test -n "$2"; then
+# NEW_REVISION="#define VERSION \"$2\""
+#else
+# NEW_REVISION="#define VERSION \"SVN-r$svn_revision\""
+#fi
+#OLD_REVISION=`cat version.h 2> /dev/null`
+#
+## Update version.h only on revision changes to avoid spurious rebuilds
+#if test "$NEW_REVISION" != "$OLD_REVISION"; then
+# echo "$NEW_REVISION" > version.h
+#fi