# HG changeset patch # User mroi # Date 1073857393 0 # Node ID 9b1b740e3fc9374d93c54e7050658772b6db3c5b # Parent f19fce15577be1e18c40b85576a25be670144a0b 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 diff -r f19fce15577b -r 9b1b740e3fc9 Makefile.am --- a/Makefile.am Wed Jan 07 19:35:12 2004 +0000 +++ b/Makefile.am Sun Jan 11 21:43:13 2004 +0000 @@ -1,64 +1,29 @@ -lib_LTLIBRARIES = libdvdnav.la - -AM_CPPFLAGS = -DDVDNAV_COMPILE -AM_CFLAGS = @THREAD_CFLAGS@ +include $(top_srcdir)/misc/Makefile.common -libdvdnav_la_SOURCES = decoder.c dvdnav.c vm.c vmcmd.c \ - read_cache.c navigation.c highlight.c \ - searching.c settings.c remap.c \ - dvd_reader.c nav_read.c ifo_read.c \ - dvd_input.c dvd_udf.c md5.c - -libdvdnav_la_LIBADD = @DYNAMIC_LD_LIBS@ +SUBDIRS = dvdread vm -libdvdnav_la_LDFLAGS = $(THREAD_LIBS) \ - -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ -# libtool 1.4.3 seems to be broken so -export-symbols-regex does not work. :-( -# -export-symbols-regex "(^dvdnav.*|^nav.*|^ifo.*)" -# -release $(DVDNAV_MAJOR).$(DVDNAV_MINOR).$(DVDNAV_SUB) +includedir = ${prefix}/include/dvdnav -include_HEADERS = dvdnav.h dvdnav_events.h dvd_types.h \ - dvd_reader.h dvd_udf.h \ - nav_read.h ifo_read.h nav_print.h ifo_types.h nav_types.h - -noinst_HEADERS = bswap.h decoder.h dvdnav_internal.h \ - dvd_input.h dvdread_internal.h md5.h \ - read_cache.h remap.h vm.h vmcmd.h +AM_CPPFLAGS = -DDVDNAV_COMPILE $(THREAD_CFLAGS) \ + -I$(top_srcdir)/src/dvdread -I$(top_srcdir)/src/vm EXTRA_DIST = README.MAP FELLOWSHIP.map -### -# Install header files (default=$includedir/xine) -# -install-includeHEADERS: $(include_HEADERS) - @$(NORMAL_INSTALL) - $(mkinstalldirs) $(DESTDIR)$(includedir)/dvdnav - @list='$(include_HEADERS)'; for p in $$list; do \ - if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \ - echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/dvdnav/$$p"; \ - $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/dvdnav/$$p; \ - done +lib_LTLIBRARIES = libdvdnav.la +libdvdnav_la_SOURCES = dvdnav.c \ + read_cache.c navigation.c highlight.c \ + searching.c settings.c remap.c -### -# Remove them -# -uninstall-includeHEADERS: - @$(NORMAL_UNINSTALL) - list='$(include_HEADERS)'; for p in $$list; do \ - rm -f $(DESTDIR)$(includedir)/dvdnav/$$p; \ - done +libdvdnav_la_LIBADD = $(THREAD_LIBS) \ + $(top_builddir)/src/dvdread/libdvdread.la \ + $(top_builddir)/src/vm/libdvdvm.la -debug: - $(MAKE) CFLAGS="$(DEBUG_CFLAGS)" - -install-debug: debug - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +libdvdnav_la_LDFLAGS = \ + -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ + -export-symbols-regex "(^dvdnav.*|^nav.*|^ifo.*|^DVD.*)" +# -release $(DVDNAV_MAJOR).$(DVDNAV_MINOR).$(DVDNAV_SUB) -mostlyclean-generic: - -rm -f *~ \#* .*~ .\#* +include_HEADERS = dvdnav.h dvdnav_events.h dvd_types.h -maintainer-clean-generic: - -@echo "This command is intended for maintainers to use;" - -@echo "it deletes files that may require special tools to rebuild." - -rm -f Makefile.in +noinst_HEADERS = dvdnav_internal.h read_cache.h remap.h diff -r f19fce15577b -r 9b1b740e3fc9 bswap.h --- a/bswap.h Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -#ifndef BSWAP_H_INCLUDED -#define BSWAP_H_INCLUDED - -/* - * Copyright (C) 2000, 2001 Billy Biggs , - * Håkan Hjort - * - * 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 - -#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 -#endif - -#if defined(__linux__) -#include -#define B2N_16(x) x = bswap_16(x) -#define B2N_32(x) x = bswap_32(x) -#define B2N_64(x) x = bswap_64(x) - -#elif defined(__NetBSD__) -#include -#define B2N_16(x) BE16TOH(x) -#define B2N_32(x) BE32TOH(x) -#define B2N_64(x) BE64TOH(x) - -#elif defined(__OpenBSD__) -#include -#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 -#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 or any other such - * functionality! - */ - -#elif defined(__FreeBSD__) || defined(__sun) || defined(__bsdi__) || defined(WIN32) || defined(__CYGWIN__) -#define B2N_16(x) \ - x = ((((x) & 0xff00) >> 8) | \ - (((x) & 0x00ff) << 8)) -#define B2N_32(x) \ - x = ((((x) & 0xff000000) >> 24) | \ - (((x) & 0x00ff0000) >> 8) | \ - (((x) & 0x0000ff00) << 8) | \ - (((x) & 0x000000ff) << 24)) -#define B2N_64(x) \ - x = ((((x) & 0xff00000000000000) >> 56) | \ - (((x) & 0x00ff000000000000) >> 40) | \ - (((x) & 0x0000ff0000000000) >> 24) | \ - (((x) & 0x000000ff00000000) >> 8) | \ - (((x) & 0x00000000ff000000) << 8) | \ - (((x) & 0x0000000000ff0000) << 24) | \ - (((x) & 0x000000000000ff00) << 40) | \ - (((x) & 0x00000000000000ff) << 56)) - -#else - -/* If there isn't a header provided with your system with this functionality - * add the relevant || define( ) to the portable implementation above. - */ -#error "You need to add endian swap macros for you're system" - -#endif - -#endif /* WORDS_BIGENDIAN */ - -#endif /* BSWAP_H_INCLUDED */ diff -r f19fce15577b -r 9b1b740e3fc9 decoder.c --- a/decoder.c Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,779 +0,0 @@ -/* - * 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$ - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include /* For memset */ -#include "ifo_types.h" /* vm_cmd_t */ -#include - -#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"); - assert(0); - } - /* 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(¤t_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(¤t_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) { - 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"); - assert(0); - } - 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)); - assert(0); - } - /* 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, " %08llx", (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 -r f19fce15577b -r 9b1b740e3fc9 decoder.h --- a/decoder.h Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -/* - * 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$ - * - */ - -#ifndef DECODER_H_INCLUDED -#define DECODER_H_INCLUDED - -#include -#include - -#include "ifo_types.h" /* vm_cmd_t */ -#include "dvdnav_internal.h" - -/* 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 -r f19fce15577b -r 9b1b740e3fc9 dvd_input.c --- a/dvd_input.c Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,367 +0,0 @@ -/* - * Copyright (C) 2002 Samuel Hocevar , - * Håkan Hjort - * - * 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 -#include -#include -#include - -#include - -#include "dvd_reader.h" -#include "dvd_input.h" - - -#ifndef _MSC_VER -#define LIBDVDCSS_NAME = "libdvdcss.so.2" -#else -#define LIBDVDCSS_NAME = "libdvdcss.dll" -#endif - -/* 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 -#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 */ -#include - -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 begining 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 _MSC_VER - 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 begining 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 postition is left unspecified after a failure. */ - return ret; - } - - if(ret == 0) { - /* Nothing more to read. Return the whole blocks, if any, that we got. - and adjust the file possition 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 */ - -#ifndef _MSC_VER - dvdcss_library = dlopen("libdvdcss.so.2", RTLD_LAZY); -#else - dvdcss_library = dlopen("libdvdcss.dll", RTLD_LAZY); -#endif - - 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 libdvdcss.so.2, " - "this shouldn't happen !\n"); - 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); - - /* 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 -r f19fce15577b -r 9b1b740e3fc9 dvd_input.h --- a/dvd_input.h Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -#ifndef DVD_INPUT_H_INCLUDED -#define DVD_INPUT_H_INCLUDED - -/* - * Copyright (C) 2001, 2002 Samuel Hocevar , - * Håkan Hjort - * - * 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) - -typedef struct dvd_input_s *dvd_input_t; - -/** - * Pointers which will be filled either the input methods functions. - */ -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 -r f19fce15577b -r 9b1b740e3fc9 dvd_reader.c --- a/dvd_reader.c Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1192 +0,0 @@ -/* - * Copyright (C) 2001, 2002, 2003 Billy Biggs , - * Håkan Hjort , - * Björn Englund - * - * 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 -#include -#include /* For the timing of dvdcss_title crack. */ -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__)|| defined(__DARWIN__) -#define SYS_BSD 1 -#endif - -#if defined(__sun) -#include -#elif defined(SYS_BSD) -#include -#elif defined(__linux__) -#include -#endif - -#include "dvd_udf.h" -#include "dvd_input.h" -#include "dvd_reader.h" -#include "md5.h" - -#define DEFAULT_UDF_CACHE_LEVEL 1 - -#ifdef _MSC_VER -#define fchdir chdir -#endif - -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; -}; - -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; - - /* Information required for a directory path drive. */ - size_t title_sizes[ 9 ]; - dvd_input_t title_devs[ 9 ]; - - /* 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 0; - } - - dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) ); - if( !dvd ) return 0; - dvd->isImageFile = 1; - dvd->dev = dev; - dvd->path_root = 0; - - 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 0; - dvd->isImageFile = 0; - dvd->dev = 0; - dvd->path_root = strdup( path_root ); - - 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/ */ -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 = 0; - char *path; - -#ifdef _MSC_VER - int len; -#endif - - if( ppath == NULL ) - return 0; - - path = strdup(ppath); - - /* 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 0; - } - - /* First check if this is a block/char device or a file*/ - if( S_ISBLK( fileinfo.st_mode ) || - S_ISCHR( fileinfo.st_mode ) || - S_ISREG( fileinfo.st_mode ) ) { - - /** - * Block devices and regular files are assumed to be DVD-Video images. - */ -#if defined(__sun) - 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 0; - } - - /* Resolve any symlinks and get the absolut dir name. */ - { - char *new_path; - int cdir = open( ".", O_RDONLY ); - - if( cdir >= 0 ) { - chdir( path_copy ); - new_path = getcwd( NULL, PATH_MAX ); - fchdir( cdir ); - close( cdir ); - if( new_path ) { - free( path_copy ); - path_copy = new_path; - } - } - } - - /** - * If we're being asked to open a directory, check if that directory - * is the mountpoint for a DVD-ROM which we can use instead. - */ - - if( strlen( path_copy ) > 1 ) { - if( path_copy[ strlen( path_copy ) - 1 ] == '/' ) - path_copy[ strlen( path_copy ) - 1 ] = '\0'; - } - - if( strlen( path_copy ) > 9 ) { - if( !strcasecmp( &(path_copy[ strlen( path_copy ) - 9 ]), - "/video_ts" ) ) { - path_copy[ strlen( path_copy ) - 9 ] = '\0'; - } - } - -#if defined(SYS_BSD) - if( ( fe = getfsfile( path_copy ) ) ) { - 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 0; -} - -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 0; - } - - dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) ); - if( !dvd_file ) { - fprintf( stderr, "libdvdnav:DVDOpenFileUDF:malloc failed\n" ); - return 0; - } - dvd_file->dvd = dvd; - dvd_file->lb_start = start; - dvd_file->seek_pos = 0; - memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) ); - memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) ); - dvd_file->filesize = len / DVD_VIDEO_LB_LEN; - - return dvd_file; -} - -/** - * Searches for in directory , ignoring case. - * Returns 0 and full filename in . - * or -1 on file not found. - * or -2 on path not found. - */ -static int findDirFile( const char *path, const char *file, char *filename ) -{ - DIR *dir; - struct dirent *ent; - - dir = opendir( path ); - if( !dir ) return -2; - - while( ( ent = readdir( dir ) ) != NULL ) { - if( !strcasecmp( ent->d_name, file ) ) { - sprintf( filename, "%s%s%s", path, - ( ( path[ strlen( path ) - 1 ] == '/' ) ? "" : "/" ), - ent->d_name ); - return 0; - } - } - - return -1; -} - -static int findDVDFile( dvd_reader_t *dvd, const char *file, char *filename ) -{ - char video_path[ PATH_MAX + 1 ]; - const char *nodirfile; - int ret; - - /* Strip off the directory for our search */ - if( !strncasecmp( "/VIDEO_TS/", file, 10 ) ) { - nodirfile = &(file[ 10 ]); - } else { - nodirfile = file; - } - - ret = findDirFile( dvd->path_root, nodirfile, filename ); - if( ret < 0 ) { - /* Try also with adding the path, just in case. */ - sprintf( video_path, "%s/VIDEO_TS/", dvd->path_root ); - ret = findDirFile( video_path, nodirfile, filename ); - if( ret < 0 ) { - /* Try with the path, but in lower case. */ - sprintf( video_path, "%s/video_ts/", dvd->path_root ); - ret = findDirFile( video_path, nodirfile, filename ); - if( ret < 0 ) { - return 0; - } - } - } - - return 1; -} - -/** - * Open an unencrypted file from a DVD directory tree. - */ -static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, char *filename ) -{ - char full_path[ PATH_MAX + 1 ]; - dvd_file_t *dvd_file; - struct stat fileinfo; - 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 0; - } - - dev = dvdinput_open( full_path ); - if( !dev ) { - fprintf( stderr, "libdvdnav:DVDOpenFilePath:dvdinput_open %s failed\n", full_path ); - return 0; - } - - dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) ); - if( !dvd_file ) { - fprintf( stderr, "libdvdnav:DVDOpenFilePath:dvd_file malloc failed\n" ); - return 0; - } - dvd_file->dvd = dvd; - dvd_file->lb_start = 0; - dvd_file->seek_pos = 0; - memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) ); - memset( dvd_file->title_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 0; - } - 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 ]; - - return dvd_file; -} - -static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *dvd, int title, int menu ) -{ - char filename[ MAX_UDF_FILE_NAME_LEN ]; - uint32_t start, len; - dvd_file_t *dvd_file; - - if( title == 0 ) { - sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" ); - } else { - sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, menu ? 0 : 1 ); - } - start = UDFFindFile( dvd, filename, &len ); - if( start == 0 ) return 0; - - dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) ); - if( !dvd_file ) return 0; - dvd_file->dvd = dvd; - /*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; - - /* 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 0; - 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; - - 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 0; - } - - dev = dvdinput_open( full_path ); - if( dev == NULL ) { - free( dvd_file ); - return 0; - } - - if( stat( full_path, &fileinfo ) < 0 ) { - fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename ); - free( dvd_file ); - return 0; - } - dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN; - dvd_file->title_devs[ 0 ] = dev; - dvdinput_title( dvd_file->title_devs[0], 0); - dvd_file->filesize = dvd_file->title_sizes[ 0 ]; - - } else { - for( i = 0; i < 9; ++i ) { - - sprintf( filename, "VTS_%02i_%i.VOB", title, i + 1 ); - if( !findDVDFile( dvd, filename, full_path ) ) { - break; - } - - if( stat( full_path, &fileinfo ) < 0 ) { - fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename ); - break; - } - - dvd_file->title_sizes[ i ] = fileinfo.st_size / DVD_VIDEO_LB_LEN; - dvd_file->title_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 0; - } - } - - return dvd_file; -} - -dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum, - dvd_read_domain_t domain ) -{ - char filename[ MAX_UDF_FILE_NAME_LEN ]; - - /* 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 < 9; ++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 < 9; ++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( !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; -} - -/* 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; - - /* 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; -} - -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 & ~2047) + 2048); - if( !secbuf_base ) { - fprintf( stderr, "libdvdread: Can't allocate memory " - "for file read!\n" ); - return 0; - } - - 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 ); - } - - if( ret != (int) numsec ) { - free( secbuf_base ); - return ret < 0 ? ret : 0; - } - - memcpy( data, &(secbuf[ seek_byte ]), byte_size ); - free( secbuf_base ); - - dvd_file->seek_pos += byte_size; - 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; - - /* 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 = (unsigned char *)(((uintptr_t)buffer_base & ~2047) + 2048); - - if( buffer_base == NULL ) { - 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 %d bytes" - ", wanted %d\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 ); - } - } - md5_finish_ctx( &ctx, discid ); - - 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 & ~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 -r f19fce15577b -r 9b1b740e3fc9 dvd_reader.h --- a/dvd_reader.h Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,272 +0,0 @@ -#ifndef DVD_READER_H_INCLUDED -#define DVD_READER_H_INCLUDED - -/* - * Copyright (C) 2001, 2002 Billy Biggs , - * Håkan Hjort , - * Björn Englund - * - * 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 - -#include -#include -#endif - -#include - -/** - * 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 ); - -/** - * 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 -r f19fce15577b -r 9b1b740e3fc9 dvd_udf.c --- a/dvd_udf.c Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1004 +0,0 @@ -/* - * This code is based on dvdudf by: - * Christian Wolff . - * - * Modifications by: - * Billy Biggs . - * Björn Englund . - * - * 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 -#include -#include - -#ifndef _MSC_VER -#include -#endif /* _MSC_VER */ - -#include -#include -#include -#include - -#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; -}; - -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) { - 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; - - 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 = *(uint8_t **)data; - c->lbs[n].lb = nr; - return 1; - } - } - c->lb_num++; - c->lbs = 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(c->lbs == NULL) { - c->lb_num = 0; - return 0; - } - c->lbs[n].data = *(uint8_t **)data; - 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++; - c->maps = 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(c->maps == NULL) { - c->map_num = 0; - return 0; - } - 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 & ~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; - *File = 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 ); - tmpmap.file = *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 & ~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 & ~2047) + 2048); - if( DVDReadLBUDF( device, lbnum, dir_lba, cached_dir, 0) <= 0 ) { - free(cached_dir_base); - cached_dir = NULL; - } - /* - if(cached_dir) { - fprintf(stderr, "malloc dir: %d\n", - dir_lba * DVD_VIDEO_LB_LEN); - } - */ - SetUDFCache(device, LBUDFCache, lbnum, &cached_dir); - } 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 ) ) { - *FileICB = tmpICB; - found = 1; - - } - UDFMapICB(device, tmpICB, &tmpFiletype, - partition, &tmpFile); - } else { - if( !strcasecmp( FileName, filename ) ) { - *FileICB = 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 & ~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 & ~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 & ~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'; - strcat( tokenline, filename ); - - - 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 & ~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 -r f19fce15577b -r 9b1b740e3fc9 dvd_udf.h --- a/dvd_udf.h Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -#ifndef DVD_UDF_H_INCLUDED -#define DVD_UDF_H_INCLUDED - -/* - * This code is based on dvdudf by: - * Christian Wolff . - * - * Modifications by: - * Billy Biggs . - * Björn Englund . - * - * 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 - -#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 -r f19fce15577b -r 9b1b740e3fc9 dvdread/.cvsignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/.cvsignore Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,6 @@ +Makefile +Makefile.in +.libs +.deps +*.lo +*.la diff -r f19fce15577b -r 9b1b740e3fc9 dvdread/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/Makefile.am Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,17 @@ +include $(top_srcdir)/misc/Makefile.common + +includedir = ${prefix}/include/dvdnav + +AM_CPPFLAGS = -DDVDNAV_COMPILE -I$(top_srcdir)/src/vm + +noinst_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 + +libdvdread_la_LIBADD = $(DYNAMIC_LD_LIBS) + +include_HEADERS = dvd_reader.h nav_read.h ifo_read.h \ + nav_print.h ifo_print.h ifo_types.h nav_types.h + +noinst_HEADERS = bswap.h dvd_input.h dvdread_internal.h dvd_udf.h md5.h diff -r f19fce15577b -r 9b1b740e3fc9 dvdread/bswap.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/bswap.h Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,98 @@ +#ifndef BSWAP_H_INCLUDED +#define BSWAP_H_INCLUDED + +/* + * Copyright (C) 2000, 2001 Billy Biggs , + * Håkan Hjort + * + * 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 + +#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 +#endif + +#if defined(__linux__) +#include +#define B2N_16(x) x = bswap_16(x) +#define B2N_32(x) x = bswap_32(x) +#define B2N_64(x) x = bswap_64(x) + +#elif defined(__NetBSD__) +#include +#define B2N_16(x) BE16TOH(x) +#define B2N_32(x) BE32TOH(x) +#define B2N_64(x) BE64TOH(x) + +#elif defined(__OpenBSD__) +#include +#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 +#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 or any other such + * functionality! + */ + +#elif defined(__FreeBSD__) || defined(__sun) || defined(__bsdi__) || defined(WIN32) || defined(__CYGWIN__) +#define B2N_16(x) \ + x = ((((x) & 0xff00) >> 8) | \ + (((x) & 0x00ff) << 8)) +#define B2N_32(x) \ + x = ((((x) & 0xff000000) >> 24) | \ + (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | \ + (((x) & 0x000000ff) << 24)) +#define B2N_64(x) \ + x = ((((x) & 0xff00000000000000) >> 56) | \ + (((x) & 0x00ff000000000000) >> 40) | \ + (((x) & 0x0000ff0000000000) >> 24) | \ + (((x) & 0x000000ff00000000) >> 8) | \ + (((x) & 0x00000000ff000000) << 8) | \ + (((x) & 0x0000000000ff0000) << 24) | \ + (((x) & 0x000000000000ff00) << 40) | \ + (((x) & 0x00000000000000ff) << 56)) + +#else + +/* If there isn't a header provided with your system with this functionality + * add the relevant || define( ) to the portable implementation above. + */ +#error "You need to add endian swap macros for you're system" + +#endif + +#endif /* WORDS_BIGENDIAN */ + +#endif /* BSWAP_H_INCLUDED */ diff -r f19fce15577b -r 9b1b740e3fc9 dvdread/dvd_input.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/dvd_input.c Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,367 @@ +/* + * Copyright (C) 2002 Samuel Hocevar , + * Håkan Hjort + * + * 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 +#include +#include +#include + +#include + +#include "dvd_reader.h" +#include "dvd_input.h" + + +#ifndef _MSC_VER +#define LIBDVDCSS_NAME = "libdvdcss.so.2" +#else +#define LIBDVDCSS_NAME = "libdvdcss.dll" +#endif + +/* 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 +#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 */ +#include + +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 begining 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 _MSC_VER + 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 begining 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 postition is left unspecified after a failure. */ + return ret; + } + + if(ret == 0) { + /* Nothing more to read. Return the whole blocks, if any, that we got. + and adjust the file possition 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 */ + +#ifndef _MSC_VER + dvdcss_library = dlopen("libdvdcss.so.2", RTLD_LAZY); +#else + dvdcss_library = dlopen("libdvdcss.dll", RTLD_LAZY); +#endif + + 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 libdvdcss.so.2, " + "this shouldn't happen !\n"); + 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); + + /* 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 -r f19fce15577b -r 9b1b740e3fc9 dvdread/dvd_input.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/dvd_input.h Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,47 @@ +#ifndef DVD_INPUT_H_INCLUDED +#define DVD_INPUT_H_INCLUDED + +/* + * Copyright (C) 2001, 2002 Samuel Hocevar , + * Håkan Hjort + * + * 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) + +typedef struct dvd_input_s *dvd_input_t; + +/** + * Pointers which will be filled either the input methods functions. + */ +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 -r f19fce15577b -r 9b1b740e3fc9 dvdread/dvd_reader.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/dvd_reader.c Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,1192 @@ +/* + * Copyright (C) 2001, 2002, 2003 Billy Biggs , + * Håkan Hjort , + * Björn Englund + * + * 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 +#include +#include /* For the timing of dvdcss_title crack. */ +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__)|| defined(__DARWIN__) +#define SYS_BSD 1 +#endif + +#if defined(__sun) +#include +#elif defined(SYS_BSD) +#include +#elif defined(__linux__) +#include +#endif + +#include "dvd_udf.h" +#include "dvd_input.h" +#include "dvd_reader.h" +#include "md5.h" + +#define DEFAULT_UDF_CACHE_LEVEL 1 + +#ifdef _MSC_VER +#define fchdir chdir +#endif + +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; +}; + +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; + + /* Information required for a directory path drive. */ + size_t title_sizes[ 9 ]; + dvd_input_t title_devs[ 9 ]; + + /* 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 0; + } + + dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) ); + if( !dvd ) return 0; + dvd->isImageFile = 1; + dvd->dev = dev; + dvd->path_root = 0; + + 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 0; + dvd->isImageFile = 0; + dvd->dev = 0; + dvd->path_root = strdup( path_root ); + + 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/ */ +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 = 0; + char *path; + +#ifdef _MSC_VER + int len; +#endif + + if( ppath == NULL ) + return 0; + + path = strdup(ppath); + + /* 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 0; + } + + /* First check if this is a block/char device or a file*/ + if( S_ISBLK( fileinfo.st_mode ) || + S_ISCHR( fileinfo.st_mode ) || + S_ISREG( fileinfo.st_mode ) ) { + + /** + * Block devices and regular files are assumed to be DVD-Video images. + */ +#if defined(__sun) + 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 0; + } + + /* Resolve any symlinks and get the absolut dir name. */ + { + char *new_path; + int cdir = open( ".", O_RDONLY ); + + if( cdir >= 0 ) { + chdir( path_copy ); + new_path = getcwd( NULL, PATH_MAX ); + fchdir( cdir ); + close( cdir ); + if( new_path ) { + free( path_copy ); + path_copy = new_path; + } + } + } + + /** + * If we're being asked to open a directory, check if that directory + * is the mountpoint for a DVD-ROM which we can use instead. + */ + + if( strlen( path_copy ) > 1 ) { + if( path_copy[ strlen( path_copy ) - 1 ] == '/' ) + path_copy[ strlen( path_copy ) - 1 ] = '\0'; + } + + if( strlen( path_copy ) > 9 ) { + if( !strcasecmp( &(path_copy[ strlen( path_copy ) - 9 ]), + "/video_ts" ) ) { + path_copy[ strlen( path_copy ) - 9 ] = '\0'; + } + } + +#if defined(SYS_BSD) + if( ( fe = getfsfile( path_copy ) ) ) { + 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 0; +} + +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 0; + } + + dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) ); + if( !dvd_file ) { + fprintf( stderr, "libdvdnav:DVDOpenFileUDF:malloc failed\n" ); + return 0; + } + dvd_file->dvd = dvd; + dvd_file->lb_start = start; + dvd_file->seek_pos = 0; + memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) ); + memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) ); + dvd_file->filesize = len / DVD_VIDEO_LB_LEN; + + return dvd_file; +} + +/** + * Searches for in directory , ignoring case. + * Returns 0 and full filename in . + * or -1 on file not found. + * or -2 on path not found. + */ +static int findDirFile( const char *path, const char *file, char *filename ) +{ + DIR *dir; + struct dirent *ent; + + dir = opendir( path ); + if( !dir ) return -2; + + while( ( ent = readdir( dir ) ) != NULL ) { + if( !strcasecmp( ent->d_name, file ) ) { + sprintf( filename, "%s%s%s", path, + ( ( path[ strlen( path ) - 1 ] == '/' ) ? "" : "/" ), + ent->d_name ); + return 0; + } + } + + return -1; +} + +static int findDVDFile( dvd_reader_t *dvd, const char *file, char *filename ) +{ + char video_path[ PATH_MAX + 1 ]; + const char *nodirfile; + int ret; + + /* Strip off the directory for our search */ + if( !strncasecmp( "/VIDEO_TS/", file, 10 ) ) { + nodirfile = &(file[ 10 ]); + } else { + nodirfile = file; + } + + ret = findDirFile( dvd->path_root, nodirfile, filename ); + if( ret < 0 ) { + /* Try also with adding the path, just in case. */ + sprintf( video_path, "%s/VIDEO_TS/", dvd->path_root ); + ret = findDirFile( video_path, nodirfile, filename ); + if( ret < 0 ) { + /* Try with the path, but in lower case. */ + sprintf( video_path, "%s/video_ts/", dvd->path_root ); + ret = findDirFile( video_path, nodirfile, filename ); + if( ret < 0 ) { + return 0; + } + } + } + + return 1; +} + +/** + * Open an unencrypted file from a DVD directory tree. + */ +static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, char *filename ) +{ + char full_path[ PATH_MAX + 1 ]; + dvd_file_t *dvd_file; + struct stat fileinfo; + 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 0; + } + + dev = dvdinput_open( full_path ); + if( !dev ) { + fprintf( stderr, "libdvdnav:DVDOpenFilePath:dvdinput_open %s failed\n", full_path ); + return 0; + } + + dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) ); + if( !dvd_file ) { + fprintf( stderr, "libdvdnav:DVDOpenFilePath:dvd_file malloc failed\n" ); + return 0; + } + dvd_file->dvd = dvd; + dvd_file->lb_start = 0; + dvd_file->seek_pos = 0; + memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) ); + memset( dvd_file->title_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 0; + } + 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 ]; + + return dvd_file; +} + +static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *dvd, int title, int menu ) +{ + char filename[ MAX_UDF_FILE_NAME_LEN ]; + uint32_t start, len; + dvd_file_t *dvd_file; + + if( title == 0 ) { + sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" ); + } else { + sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, menu ? 0 : 1 ); + } + start = UDFFindFile( dvd, filename, &len ); + if( start == 0 ) return 0; + + dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) ); + if( !dvd_file ) return 0; + dvd_file->dvd = dvd; + /*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; + + /* 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 0; + 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; + + 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 0; + } + + dev = dvdinput_open( full_path ); + if( dev == NULL ) { + free( dvd_file ); + return 0; + } + + if( stat( full_path, &fileinfo ) < 0 ) { + fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename ); + free( dvd_file ); + return 0; + } + dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN; + dvd_file->title_devs[ 0 ] = dev; + dvdinput_title( dvd_file->title_devs[0], 0); + dvd_file->filesize = dvd_file->title_sizes[ 0 ]; + + } else { + for( i = 0; i < 9; ++i ) { + + sprintf( filename, "VTS_%02i_%i.VOB", title, i + 1 ); + if( !findDVDFile( dvd, filename, full_path ) ) { + break; + } + + if( stat( full_path, &fileinfo ) < 0 ) { + fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename ); + break; + } + + dvd_file->title_sizes[ i ] = fileinfo.st_size / DVD_VIDEO_LB_LEN; + dvd_file->title_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 0; + } + } + + return dvd_file; +} + +dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum, + dvd_read_domain_t domain ) +{ + char filename[ MAX_UDF_FILE_NAME_LEN ]; + + /* 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 < 9; ++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 < 9; ++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( !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; +} + +/* 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; + + /* 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; +} + +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 & ~2047) + 2048); + if( !secbuf_base ) { + fprintf( stderr, "libdvdread: Can't allocate memory " + "for file read!\n" ); + return 0; + } + + 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 ); + } + + if( ret != (int) numsec ) { + free( secbuf_base ); + return ret < 0 ? ret : 0; + } + + memcpy( data, &(secbuf[ seek_byte ]), byte_size ); + free( secbuf_base ); + + dvd_file->seek_pos += byte_size; + 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; + + /* 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 = (unsigned char *)(((uintptr_t)buffer_base & ~2047) + 2048); + + if( buffer_base == NULL ) { + 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 %d bytes" + ", wanted %d\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 ); + } + } + md5_finish_ctx( &ctx, discid ); + + 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 & ~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 -r f19fce15577b -r 9b1b740e3fc9 dvdread/dvd_reader.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/dvd_reader.h Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,272 @@ +#ifndef DVD_READER_H_INCLUDED +#define DVD_READER_H_INCLUDED + +/* + * Copyright (C) 2001, 2002 Billy Biggs , + * Håkan Hjort , + * Björn Englund + * + * 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 + +#include +#include +#endif + +#include + +/** + * 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 ); + +/** + * 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 -r f19fce15577b -r 9b1b740e3fc9 dvdread/dvd_udf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/dvd_udf.c Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,1004 @@ +/* + * This code is based on dvdudf by: + * Christian Wolff . + * + * Modifications by: + * Billy Biggs . + * Björn Englund . + * + * 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 +#include +#include + +#ifndef _MSC_VER +#include +#endif /* _MSC_VER */ + +#include +#include +#include +#include + +#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; +}; + +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) { + 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; + + 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 = *(uint8_t **)data; + c->lbs[n].lb = nr; + return 1; + } + } + c->lb_num++; + c->lbs = 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(c->lbs == NULL) { + c->lb_num = 0; + return 0; + } + c->lbs[n].data = *(uint8_t **)data; + 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++; + c->maps = 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(c->maps == NULL) { + c->map_num = 0; + return 0; + } + 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 & ~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; + *File = 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 ); + tmpmap.file = *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 & ~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 & ~2047) + 2048); + if( DVDReadLBUDF( device, lbnum, dir_lba, cached_dir, 0) <= 0 ) { + free(cached_dir_base); + cached_dir = NULL; + } + /* + if(cached_dir) { + fprintf(stderr, "malloc dir: %d\n", + dir_lba * DVD_VIDEO_LB_LEN); + } + */ + SetUDFCache(device, LBUDFCache, lbnum, &cached_dir); + } 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 ) ) { + *FileICB = tmpICB; + found = 1; + + } + UDFMapICB(device, tmpICB, &tmpFiletype, + partition, &tmpFile); + } else { + if( !strcasecmp( FileName, filename ) ) { + *FileICB = 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 & ~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 & ~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 & ~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'; + strcat( tokenline, filename ); + + + 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 & ~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 -r f19fce15577b -r 9b1b740e3fc9 dvdread/dvd_udf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/dvd_udf.h Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,62 @@ +#ifndef DVD_UDF_H_INCLUDED +#define DVD_UDF_H_INCLUDED + +/* + * This code is based on dvdudf by: + * Christian Wolff . + * + * Modifications by: + * Billy Biggs . + * Björn Englund . + * + * 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 + +#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 -r f19fce15577b -r 9b1b740e3fc9 dvdread/dvdread_internal.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/dvdread_internal.h Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,15 @@ +#ifndef DVDREAD_INTERNAL_H +#define DVDREAD_INTERNAL_H + +#ifdef _MSC_VER +#include +#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 -r f19fce15577b -r 9b1b740e3fc9 dvdread/ifo_print.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/ifo_print.c Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,1202 @@ +/* + * 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$ + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" // Needed for WORDS_BIGENDIAN +#include "ifo_types.h" +#include "ifo_read.h" +#include "ifo_print.h" +#include "vmcmd.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); +} + +/* 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("| "); + vm_print_mnemonic(command); + 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 "); + break; + case 1: + printf("(please send a bug report) "); + break; + case 2: + printf("mpeg1 "); + break; + case 3: + printf("mpeg2ext "); + break; + case 4: + printf("lpcm "); + break; + case 5: + printf("(please send a bug report) "); + break; + case 6: + printf("dts "); + break; + default: + printf("(please send a bug report) "); + } + + if(attr->multichannel_extension) + printf("multichannel_extension "); + + switch(attr->lang_type) { + case 0: + // not specified + assert(attr->lang_code == 0 || 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;inr_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: "); + ifo_print_time(5, &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\n", + i, pgc->subp_control[i]); + } + } + + printf("Next PGC number: %i\n", pgc->next_pgc_nr); + printf("Prev PGC number: %i\n", pgc->prev_pgc_nr); + printf("GoUp PGC number: %i\n", pgc->goup_pgc_nr); + if(pgc->nr_of_programs != 0) { + printf("Still time: %i seconds (255=inf)\n", pgc->still_time); + printf("PG Playback mode %02x\n", pgc->pg_playback_mode); + } + + if(pgc->nr_of_programs != 0) { + for(i = 0; i < 16; i++) { + printf("Color %2i: %08x\n", i, pgc->palette[i]); + } + } + + /* Memmory offsets to div. tables. */ + 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;inr_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;inr_of_srpts;i++) { + for(j=0;jtitle[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"); + ifo_print_PGC(ifohandle->first_play_pgc); + + 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.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 -r f19fce15577b -r 9b1b740e3fc9 dvdread/ifo_print.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/ifo_print.h Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,56 @@ +/* + * 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$ + * + */ + +#ifndef IFO_PRINT_H_INCLUDED +#define IFO_PRINT_H_INCLUDED + +#include +#ifdef DVDNAV_COMPILE +# include "ifo_types.h" +#else +# include /* Only for vm_cmd_t */ +#endif + +void ifo_print(dvd_reader_t *dvd, int title); + +#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 -r f19fce15577b -r 9b1b740e3fc9 dvdread/ifo_read.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/ifo_read.c Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,2024 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003 + * Björn Englund , + * Håkan Hjort + * + * 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 +#include +#include +#include + +#include "bswap.h" +#include "ifo_types.h" +#include "ifo_read.h" +#include "dvd_reader.h" +#include "dvdread_internal.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 DVDFileSeek_( dvd_file_t *dvd_file, uint32_t offset ) { + return (DVDFileSeek(dvd_file, (int)offset) == (int)offset); +} + + +ifo_handle_t *ifoOpen(dvd_reader_t *dvd, int title) { + ifo_handle_t *ifofile; + + ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t)); + if(!ifofile) + return 0; + + memset(ifofile, 0, sizeof(ifo_handle_t)); + + ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE); + if(!ifofile->file) /* 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 0; + } + + /* First check if this is a VMGI file. */ + if(ifoRead_VMG(ifofile)) { + + /* These are both mandatory. */ + if(!ifoRead_FP_PGC(ifofile) || !ifoRead_TT_SRPT(ifofile)) { + fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO).\n"); + ifoClose(ifofile); + return 0; + } + + ifoRead_PGCI_UT(ifofile); + ifoRead_PTL_MAIT(ifofile); + + /* This is also mandatory. */ + if(!ifoRead_VTS_ATRT(ifofile)) { + fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO).\n"); + ifoClose(ifofile); + return 0; + } + + ifoRead_TXTDT_MGI(ifofile); + ifoRead_C_ADT(ifofile); + ifoRead_VOBU_ADMAP(ifofile); + + return ifofile; + } + + if(ifoRead_VTS(ifofile)) { + + if(!ifoRead_VTS_PTT_SRPT(ifofile) || !ifoRead_PGCIT(ifofile)) { + fprintf(stderr, "libdvdread: Invalid title IFO (VTS_%02d_0.IFO).\n", + title); + ifoClose(ifofile); + return 0; + } + + + ifoRead_PGCI_UT(ifofile); + ifoRead_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 0; + } + + 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 0; +} + + +ifo_handle_t *ifoOpenVMGI(dvd_reader_t *dvd) { + ifo_handle_t *ifofile; + + ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t)); + if(!ifofile) + return 0; + + memset(ifofile, 0, sizeof(ifo_handle_t)); + + ifofile->file = DVDOpenFile(dvd, 0, DVD_READ_INFO_FILE); + if(!ifofile->file) /* 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 0; + } + + if(ifoRead_VMG(ifofile)) + return ifofile; + + fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO).\n"); + ifoClose(ifofile); + return 0; +} + + +ifo_handle_t *ifoOpenVTSI(dvd_reader_t *dvd, int title) { + ifo_handle_t *ifofile; + + ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t)); + if(!ifofile) + return 0; + + memset(ifofile, 0, sizeof(ifo_handle_t)); + + if(title <= 0 || title > 99) { + fprintf(stderr, "libdvdread: ifoOpenVTSI invalid title (%d).\n", title); + free(ifofile); + return 0; + } + + 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 0; + } + + ifoRead_VTS(ifofile); + if(ifofile->vtsi_mat) + return ifofile; + + fprintf(stderr, "libdvdread: Invalid IFO for title %d (VTS_%02d_0.IFO).\n", + title, title); + ifoClose(ifofile); + return 0; +} + + +void ifoClose(ifo_handle_t *ifofile) { + if(!ifofile) + return; + + ifoFree_VOBU_ADMAP(ifofile); + ifoFree_TITLE_VOBU_ADMAP(ifofile); + ifoFree_C_ADT(ifofile); + ifoFree_TITLE_C_ADT(ifofile); + ifoFree_TXTDT_MGI(ifofile); + ifoFree_VTS_ATRT(ifofile); + ifoFree_PTL_MAIT(ifofile); + ifoFree_PGCI_UT(ifofile); + ifoFree_TT_SRPT(ifofile); + ifoFree_FP_PGC(ifofile); + ifoFree_PGCIT(ifofile); + ifoFree_VTS_PTT_SRPT(ifofile); + + if(ifofile->vmgi_mat) + free(ifofile->vmgi_mat); + + if(ifofile->vtsi_mat) + free(ifofile->vtsi_mat); + + DVDCloseFile(ifofile->file); + ifofile->file = 0; + free(ifofile); + ifofile = 0; +} + + +static int ifoRead_VMG(ifo_handle_t *ifofile) { + vmgi_mat_t *vmgi_mat; + + vmgi_mat = (vmgi_mat_t *)malloc(sizeof(vmgi_mat_t)); + if(!vmgi_mat) + return 0; + + ifofile->vmgi_mat = vmgi_mat; + + if(!DVDFileSeek_(ifofile->file, 0)) { + free(ifofile->vmgi_mat); + ifofile->vmgi_mat = 0; + return 0; + } + + if(!DVDReadBytes(ifofile->file, vmgi_mat, sizeof(vmgi_mat_t))) { + free(ifofile->vmgi_mat); + ifofile->vmgi_mat = 0; + return 0; + } + + if(strncmp("DVDVIDEO-VMG", vmgi_mat->vmg_identifier, 12) != 0) { + free(ifofile->vmgi_mat); + ifofile->vmgi_mat = 0; + return 0; + } + + B2N_32(vmgi_mat->vmg_last_sector); + B2N_32(vmgi_mat->vmgi_last_sector); + B2N_32(vmgi_mat->vmg_category); + B2N_16(vmgi_mat->vmg_nr_of_volumes); + B2N_16(vmgi_mat->vmg_this_volume_nr); + B2N_16(vmgi_mat->vmg_nr_of_title_sets); + B2N_64(vmgi_mat->vmg_pos_code); + B2N_32(vmgi_mat->vmgi_last_byte); + B2N_32(vmgi_mat->first_play_pgc); + B2N_32(vmgi_mat->vmgm_vobs); + B2N_32(vmgi_mat->tt_srpt); + B2N_32(vmgi_mat->vmgm_pgci_ut); + B2N_32(vmgi_mat->ptl_mait); + B2N_32(vmgi_mat->vts_atrt); + B2N_32(vmgi_mat->txtdt_mgi); + B2N_32(vmgi_mat->vmgm_c_adt); + B2N_32(vmgi_mat->vmgm_vobu_admap); + B2N_16(vmgi_mat->vmgm_audio_attr.lang_code); + B2N_16(vmgi_mat->vmgm_subp_attr.lang_code); + + + CHECK_ZERO(vmgi_mat->zero_1); + CHECK_ZERO(vmgi_mat->zero_2); + CHECK_ZERO(vmgi_mat->zero_3); + CHECK_ZERO(vmgi_mat->zero_4); + CHECK_ZERO(vmgi_mat->zero_5); + CHECK_ZERO(vmgi_mat->zero_6); + CHECK_ZERO(vmgi_mat->zero_7); + CHECK_ZERO(vmgi_mat->zero_8); + CHECK_ZERO(vmgi_mat->zero_9); + CHECK_ZERO(vmgi_mat->zero_10); + 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; + } + + B2N_32(vtsi_mat->vts_last_sector); + B2N_32(vtsi_mat->vtsi_last_sector); + B2N_32(vtsi_mat->vts_category); + B2N_32(vtsi_mat->vtsi_last_byte); + B2N_32(vtsi_mat->vtsm_vobs); + B2N_32(vtsi_mat->vtstt_vobs); + B2N_32(vtsi_mat->vts_ptt_srpt); + B2N_32(vtsi_mat->vts_pgcit); + B2N_32(vtsi_mat->vtsm_pgci_ut); + B2N_32(vtsi_mat->vts_tmapt); + B2N_32(vtsi_mat->vtsm_c_adt); + B2N_32(vtsi_mat->vtsm_vobu_admap); + B2N_32(vtsi_mat->vts_c_adt); + B2N_32(vtsi_mat->vts_vobu_admap); + B2N_16(vtsi_mat->vtsm_audio_attr.lang_code); + B2N_16(vtsi_mat->vtsm_subp_attr.lang_code); + for(i = 0; i < 8; i++) + B2N_16(vtsi_mat->vts_audio_attr[i].lang_code); + for(i = 0; i < 32; i++) + B2N_16(vtsi_mat->vts_subp_attr[i].lang_code); + + + CHECK_ZERO(vtsi_mat->zero_1); + CHECK_ZERO(vtsi_mat->zero_2); + CHECK_ZERO(vtsi_mat->zero_3); + CHECK_ZERO(vtsi_mat->zero_4); + CHECK_ZERO(vtsi_mat->zero_5); + CHECK_ZERO(vtsi_mat->zero_6); + CHECK_ZERO(vtsi_mat->zero_7); + CHECK_ZERO(vtsi_mat->zero_8); + CHECK_ZERO(vtsi_mat->zero_9); + CHECK_ZERO(vtsi_mat->zero_10); + CHECK_ZERO(vtsi_mat->zero_11); + CHECK_ZERO(vtsi_mat->zero_12); + CHECK_ZERO(vtsi_mat->zero_13); + CHECK_ZERO(vtsi_mat->zero_14); + CHECK_ZERO(vtsi_mat->zero_15); + CHECK_ZERO(vtsi_mat->zero_16); + CHECK_ZERO(vtsi_mat->zero_17); + CHECK_ZERO(vtsi_mat->zero_18); + CHECK_ZERO(vtsi_mat->zero_19); + CHECK_ZERO(vtsi_mat->zero_20); + 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++) { + 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++) { + B2N_32(cell_playback[i].first_sector); + B2N_32(cell_playback[i].first_ilvu_end_sector); + B2N_32(cell_playback[i].last_vobu_start_sector); + B2N_32(cell_playback[i].last_sector); + + /* Changed < to <= because this was false in the movie 'Pi'. */ + 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; + + 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->program_map = malloc(pgc->nr_of_programs * sizeof(pgc_program_map_t)); + if(!pgc->program_map) { + ifoFree_PGC_COMMAND_TBL(pgc->command_tbl); + return 0; + } + if(!ifoRead_PGC_PROGRAM_MAP(ifofile, pgc->program_map,pgc->nr_of_programs, + offset + pgc->program_map_offset)) { + ifoFree_PGC_COMMAND_TBL(pgc->command_tbl); + free(pgc->program_map); + return 0; + } + } else { + pgc->program_map = NULL; + } + + if(pgc->cell_playback_offset != 0) { + pgc->cell_playback = malloc(pgc->nr_of_cells * sizeof(cell_playback_t)); + if(!pgc->cell_playback) { + ifoFree_PGC_COMMAND_TBL(pgc->command_tbl); + if(pgc->program_map) + free(pgc->program_map); + return 0; + } + if(!ifoRead_CELL_PLAYBACK_TBL(ifofile, pgc->cell_playback, + pgc->nr_of_cells, + offset + pgc->cell_playback_offset)) { + ifoFree_PGC_COMMAND_TBL(pgc->command_tbl); + if(pgc->program_map) + free(pgc->program_map); + free(pgc->cell_playback); + return 0; + } + } else { + pgc->cell_playback = NULL; + } + + if(pgc->cell_position_offset != 0) { + pgc->cell_position = malloc(pgc->nr_of_cells * sizeof(cell_position_t)); + if(!pgc->cell_position) { + ifoFree_PGC(pgc); + return 0; + } + if(!ifoRead_CELL_POSITION_TBL(ifofile, pgc->cell_position, + pgc->nr_of_cells, + offset + pgc->cell_position_offset)) { + ifoFree_PGC(pgc); + return 0; + } + } else { + pgc->cell_position = NULL; + } + + return 1; +} + +int ifoRead_FP_PGC(ifo_handle_t *ifofile) { + + if(!ifofile) + return 0; + + if(!ifofile->vmgi_mat) + return 0; + + /* 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++) { + 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) { + for(j = 0; j < i ; j++) { + free(ptl_mait->countries[j].pf_ptl_mai); + } + free(ptl_mait->countries); + free(ptl_mait); + return 0; + } + if(!(DVDReadBytes(ifofile->file, pf_temp, info_length))) { + fprintf(stderr, "libdvdread: Unable to read PTL_MAIT table.\n"); + free(pf_temp); + for(j = 0; j < i ; j++) { + free(ptl_mait->countries[j].pf_ptl_mai); + } + free(ptl_mait->countries); + free(ptl_mait); + 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); + for(j = 0; j < i ; j++) { + free(ptl_mait->countries[j].pf_ptl_mai); + } + free(ptl_mait->countries); + free(ptl_mait); + 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(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN)) + return 0; + + if(!(DVDReadBytes(ifofile->file, vobu_admap, VOBU_ADMAP_SIZE))) + return 0; + + B2N_32(vobu_admap->last_byte); + + info_length = vobu_admap->last_byte + 1 - VOBU_ADMAP_SIZE; + /* assert(info_length > 0); + Magic Knight Rayearth Daybreak is mastered very strange and has + Titles with a VOBS that has no VOBUs. */ + 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_LU_SIZE); + ptr += PGCI_LU_SIZE; + B2N_16(pgcit->pgci_srp[i].ptl_id_mask); + B2N_32(pgcit->pgci_srp[i].pgc_start_byte); + 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); + } + return 0; + } + if(!ifoRead_PGC(ifofile, pgcit->pgci_srp[i].pgc, + offset + pgcit->pgci_srp[i].pgc_start_byte)) { + int j; + for(j = 0; j < i; j++) { + ifoFree_PGC(pgcit->pgci_srp[j].pgc); + free(pgcit->pgci_srp[j].pgc); + } + free(pgcit->pgci_srp); + return 0; + } + } + + return 1; +} + +static void ifoFree_PGCIT_internal(pgcit_t *pgcit) { + if(pgcit) { + int i; + for(i = 0; i < pgcit->nr_of_pgci_srp; i++) + ifoFree_PGC(pgcit->pgci_srp[i].pgc); + free(pgcit->pgci_srp); + } +} + +void ifoFree_PGCIT(ifo_handle_t *ifofile) { + if(!ifofile) + return; + + if(ifofile->vts_pgcit) { + ifoFree_PGCIT_internal(ifofile->vts_pgcit); + free(ifofile->vts_pgcit); + ifofile->vts_pgcit = 0; + } +} + + +int ifoRead_PGCI_UT(ifo_handle_t *ifofile) { + pgci_ut_t *pgci_ut; + unsigned int sector; + unsigned int i; + int info_length; + uint8_t *data, *ptr; + + if(!ifofile) + return 0; + + if(ifofile->vmgi_mat) { + if(ifofile->vmgi_mat->vmgm_pgci_ut == 0) + return 1; + sector = ifofile->vmgi_mat->vmgm_pgci_ut; + } else if(ifofile->vtsi_mat) { + if(ifofile->vtsi_mat->vtsm_pgci_ut == 0) + return 1; + sector = ifofile->vtsi_mat->vtsm_pgci_ut; + } else { + return 0; + } + + ifofile->pgci_ut = (pgci_ut_t *)malloc(sizeof(pgci_ut_t)); + if(!ifofile->pgci_ut) + return 0; + + if(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN)) { + free(ifofile->pgci_ut); + ifofile->pgci_ut = 0; + return 0; + } + + if(!(DVDReadBytes(ifofile->file, ifofile->pgci_ut, PGCI_UT_SIZE))) { + free(ifofile->pgci_ut); + ifofile->pgci_ut = 0; + return 0; + } + + pgci_ut = ifofile->pgci_ut; + + B2N_16(pgci_ut->nr_of_lus); + B2N_32(pgci_ut->last_byte); + + CHECK_ZERO(pgci_ut->zero_1); + 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; + + B2N_32(vts_attributes->last_byte); + B2N_32(vts_attributes->vts_cat); + B2N_16(vts_attributes->vtsm_audio_attr.lang_code); + B2N_16(vts_attributes->vtsm_subp_attr.lang_code); + for(i = 0; i < 8; i++) + B2N_16(vts_attributes->vtstt_audio_attr[i].lang_code); + for(i = 0; i < 32; i++) + B2N_16(vts_attributes->vtstt_subp_attr[i].lang_code); + + CHECK_ZERO(vts_attributes->zero_1); + CHECK_ZERO(vts_attributes->zero_2); + CHECK_ZERO(vts_attributes->zero_3); + CHECK_ZERO(vts_attributes->zero_4); + CHECK_ZERO(vts_attributes->zero_5); + CHECK_ZERO(vts_attributes->zero_6); + CHECK_ZERO(vts_attributes->zero_7); + 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 -r f19fce15577b -r 9b1b740e3fc9 dvdread/ifo_read.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/ifo_read.h Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,227 @@ +#ifndef IFO_READ_H_INCLUDED +#define IFO_READ_H_INCLUDED + +/* + * Copyright (C) 2000, 2001, 2002 Björn Englund , + * Håkan Hjort + * + * 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 -r f19fce15577b -r 9b1b740e3fc9 dvdread/ifo_types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/ifo_types.h Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,884 @@ +#ifndef IFO_TYPES_H_INCLUDED +#define IFO_TYPES_H_INCLUDED + +/* + * Copyright (C) 2000, 2001 Björn Englund , + * Håkan Hjort + * + * 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 +#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 8 + + +/** + * Video Attributes. + */ +typedef struct { +#ifdef WORDS_BIGENDIAN + 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; +#else + unsigned char permitted_df : 2; + unsigned char display_aspect_ratio : 2; + unsigned char video_format : 2; + unsigned char mpeg_version : 2; + + unsigned char film_mode : 1; + unsigned char letterboxed : 1; + unsigned char picture_size : 2; + + unsigned char bit_rate : 1; + unsigned char unknown1 : 1; + unsigned char line21_cc_2 : 1; + unsigned char line21_cc_1 : 1; +#endif +} ATTRIBUTE_PACKED video_attr_t; + +/** + * Audio Attributes. + */ +typedef struct { +#ifdef WORDS_BIGENDIAN + 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; +#else + unsigned char application_mode : 2; + unsigned char lang_type : 2; + unsigned char multichannel_extension : 1; + unsigned char audio_format : 3; + + unsigned char channels : 3; + unsigned char unknown1 : 1; + unsigned char sample_frequency : 2; + unsigned char quantization : 2; +#endif + uint16_t lang_code; + uint8_t lang_extension; + uint8_t code_extension; + uint8_t unknown3; + union { + struct ATTRIBUTE_PACKED { +#ifdef WORDS_BIGENDIAN + 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 */ +#else + unsigned char mode : 1; + unsigned char mc_intro : 1; + unsigned char version : 2; + unsigned char channel_assignment : 3; + unsigned char unknown4 : 1; +#endif + } karaoke; + struct ATTRIBUTE_PACKED { +#ifdef WORDS_BIGENDIAN + unsigned char unknown5 : 4; + unsigned char dolby_encoded : 1; /* suitable for surround decoding */ + unsigned char unknown6 : 3; +#else + unsigned char unknown6 : 3; + unsigned char dolby_encoded : 1; + unsigned char unknown5 : 4; +#endif + } surround; + } app_info; +} ATTRIBUTE_PACKED audio_attr_t; + + +/** + * MultiChannel Extension + */ +typedef struct { +#ifdef WORDS_BIGENDIAN + 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; +#else + unsigned char ach0_gme : 1; + unsigned char zero1 : 7; + + unsigned char ach1_gme : 1; + unsigned char zero2 : 7; + + unsigned char ach2_gm2e : 1; + unsigned char ach2_gm1e : 1; + unsigned char ach2_gv2e : 1; + unsigned char ach2_gv1e : 1; + unsigned char zero3 : 4; + + unsigned char ach3_se2e : 1; + unsigned char ach3_gmAe : 1; + unsigned char ach3_gv2e : 1; + unsigned char ach3_gv1e : 1; + unsigned char zero4 : 4; + + unsigned char ach4_seBe : 1; + unsigned char ach4_gmBe : 1; + unsigned char ach4_gv2e : 1; + unsigned char ach4_gv1e : 1; + unsigned char zero5 : 4; +#endif + 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 + */ +#ifdef WORDS_BIGENDIAN + unsigned char code_mode : 3; + unsigned char zero1 : 3; + unsigned char type : 2; +#else + unsigned char type : 2; + unsigned char zero1 : 3; + unsigned char code_mode : 3; +#endif + 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 8 + +/** + * PGC Program Map + */ +typedef uint8_t pgc_program_map_t; + +/** + * Cell Playback Information. + */ +typedef struct { +#ifdef WORDS_BIGENDIAN + unsigned int block_mode : 2; + unsigned int block_type : 2; + unsigned int seamless_play : 1; + unsigned int interleaved : 1; + unsigned int stc_discontinuity: 1; + unsigned int seamless_angle : 1; + + unsigned int playback_mode : 1; /**< When set, enter StillMode after each VOBU */ + unsigned int restricted : 1; /**< ?? drop out of fastforward? */ + unsigned int unknown2 : 6; +#else + unsigned char seamless_angle : 1; + unsigned char stc_discontinuity: 1; + unsigned char interleaved : 1; + unsigned char seamless_play : 1; + unsigned char block_type : 2; + unsigned char block_mode : 2; + + unsigned char unknown2 : 6; + unsigned char restricted : 1; + unsigned char playback_mode : 1; +#endif + uint8_t still_time; + uint8_t cell_cmd_nr; + dvd_time_t playback_time; + uint32_t first_sector; + uint32_t first_ilvu_end_sector; + uint32_t last_vobu_start_sector; + uint32_t last_sector; +} ATTRIBUTE_PACKED cell_playback_t; + +#define BLOCK_TYPE_NONE 0x0 +#define BLOCK_TYPE_ANGLE_BLOCK 0x1 + +#define BLOCK_MODE_NOT_IN_BLOCK 0x0 +#define BLOCK_MODE_FIRST_CELL 0x1 +#define BLOCK_MODE_IN_BLOCK 0x2 +#define BLOCK_MODE_LAST_CELL 0x3 + +/** + * Cell Position Information. + */ +typedef struct { + uint16_t vob_id_nr; + uint8_t zero_1; + uint8_t cell_nr; +} ATTRIBUTE_PACKED cell_position_t; + +/** + * User Operations. + */ +typedef struct { +#ifdef WORDS_BIGENDIAN + unsigned int zero : 7; /* 25-31 */ + unsigned int video_pres_mode_change : 1; /* 24 */ + + unsigned int karaoke_audio_pres_mode_change : 1; /* 23 */ + unsigned int angle_change : 1; + 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 */ +#else + unsigned int video_pres_mode_change : 1; /* 24 */ + unsigned int zero : 7; /* 25-31 */ + + unsigned int resume : 1; /* 16 */ + unsigned int button_select_or_activate : 1; + unsigned int still_off : 1; + unsigned int pause_on : 1; + unsigned int audio_stream_change : 1; + unsigned int subpic_stream_change : 1; + unsigned int angle_change : 1; + unsigned int karaoke_audio_pres_mode_change : 1; /* 23 */ + + unsigned int forward_scan : 1; /* 8 */ + unsigned int backward_scan : 1; + unsigned int title_menu_call : 1; + unsigned int root_menu_call : 1; + unsigned int subpic_menu_call : 1; + unsigned int audio_menu_call : 1; + unsigned int angle_menu_call : 1; + unsigned int chapter_menu_call : 1; /* 15 */ + + unsigned int title_or_time_play : 1; /* 0 */ + unsigned int chapter_search_or_play : 1; + unsigned int title_play : 1; + unsigned int stop : 1; + unsigned int go_up : 1; + unsigned int time_or_chapter_search : 1; + unsigned int prev_or_top_pg_search : 1; + unsigned int next_pg_search : 1; /* 7 */ +#endif +} ATTRIBUTE_PACKED user_ops_t; + +/** + * Program Chain Information. + */ +typedef struct { + uint16_t zero_1; + uint8_t nr_of_programs; + uint8_t nr_of_cells; + dvd_time_t playback_time; + user_ops_t prohibited_ops; + uint16_t audio_control[8]; /* New type? */ + uint32_t subp_control[32]; /* New type? */ + uint16_t next_pgc_nr; + uint16_t prev_pgc_nr; + uint16_t goup_pgc_nr; + uint8_t still_time; + uint8_t pg_playback_mode; + uint32_t palette[16]; /* New type struct {zero_1, Y, Cr, Cb} ? */ + uint16_t command_tbl_offset; + uint16_t program_map_offset; + uint16_t cell_playback_offset; + uint16_t cell_position_offset; + pgc_command_tbl_t *command_tbl; + pgc_program_map_t *program_map; + cell_playback_t *cell_playback; + cell_position_t *cell_position; +} ATTRIBUTE_PACKED pgc_t; +#define PGC_SIZE 236 + +/** + * Program Chain Information Search Pointer. + */ +typedef struct { + uint8_t entry_id; +#ifdef WORDS_BIGENDIAN + unsigned int block_mode : 2; + unsigned int block_type : 2; + unsigned int unknown1 : 4; +#else + unsigned char unknown1 : 4; + unsigned char block_type : 2; + unsigned char block_mode : 2; +#endif + uint16_t ptl_id_mask; + uint32_t pgc_start_byte; + pgc_t *pgc; +} ATTRIBUTE_PACKED pgci_srp_t; +#define PGCI_SRP_SIZE 8 + +/** + * Program Chain Information Table. + */ +typedef struct { + uint16_t nr_of_pgci_srp; + uint16_t zero_1; + uint32_t last_byte; + pgci_srp_t *pgci_srp; +} ATTRIBUTE_PACKED pgcit_t; +#define PGCIT_SIZE 8 + +/** + * Menu PGCI Language Unit. + */ +typedef struct { + uint16_t lang_code; + uint8_t lang_extension; + uint8_t exists; + uint32_t lang_start_byte; + pgcit_t *pgcit; +} ATTRIBUTE_PACKED pgci_lu_t; +#define PGCI_LU_SIZE 8 + +/** + * Menu PGCI Unit Table. + */ +typedef struct { + uint16_t nr_of_lus; + uint16_t zero_1; + uint32_t last_byte; + pgci_lu_t *lu; +} ATTRIBUTE_PACKED pgci_ut_t; +#define PGCI_UT_SIZE 8 + +/** + * Cell Address Information. + */ +typedef struct { + uint16_t vob_id; + uint8_t cell_id; + uint8_t zero_1; + uint32_t start_sector; + uint32_t last_sector; +} ATTRIBUTE_PACKED cell_adr_t; + +/** + * Cell Address Table. + */ +typedef struct { + uint16_t nr_of_vobs; /* VOBs */ + uint16_t zero_1; + uint32_t last_byte; + cell_adr_t *cell_adr_table; /* No explicit size given. */ +} ATTRIBUTE_PACKED c_adt_t; +#define C_ADT_SIZE 8 + +/** + * VOBU Address Map. + */ +typedef struct { + uint32_t last_byte; + uint32_t *vobu_start_sectors; +} ATTRIBUTE_PACKED vobu_admap_t; +#define VOBU_ADMAP_SIZE 4 + + + + +/** + * VMGI + * + * The following structures relate to the Video Manager. + */ + +/** + * Video Manager Information Management Table. + */ +typedef struct { + char vmg_identifier[12]; + uint32_t vmg_last_sector; + uint8_t zero_1[12]; + uint32_t vmgi_last_sector; + uint8_t zero_2; + uint8_t specification_version; + uint32_t vmg_category; + uint16_t vmg_nr_of_volumes; + uint16_t vmg_this_volume_nr; + uint8_t disc_side; + uint8_t zero_3[19]; + uint16_t vmg_nr_of_title_sets; /* Number of VTSs. */ + char provider_identifier[32]; + uint64_t vmg_pos_code; + uint8_t zero_4[24]; + uint32_t vmgi_last_byte; + uint32_t first_play_pgc; + uint8_t zero_5[56]; + uint32_t vmgm_vobs; /* sector */ + uint32_t tt_srpt; /* sector */ + uint32_t vmgm_pgci_ut; /* sector */ + uint32_t ptl_mait; /* sector */ + uint32_t vts_atrt; /* sector */ + uint32_t txtdt_mgi; /* sector */ + uint32_t vmgm_c_adt; /* sector */ + uint32_t vmgm_vobu_admap; /* sector */ + uint8_t zero_6[32]; + + video_attr_t vmgm_video_attr; + uint8_t zero_7; + uint8_t nr_of_vmgm_audio_streams; /* should be 0 or 1 */ + audio_attr_t vmgm_audio_attr; + audio_attr_t zero_8[7]; + uint8_t zero_9[17]; + uint8_t nr_of_vmgm_subp_streams; /* should be 0 or 1 */ + subp_attr_t vmgm_subp_attr; + subp_attr_t zero_10[27]; /* XXX: how much 'padding' here? */ +} ATTRIBUTE_PACKED vmgi_mat_t; + +typedef struct { +#ifdef WORDS_BIGENDIAN + unsigned int zero_1 : 1; + unsigned int multi_or_random_pgc_title : 1; /* 0: one sequential pgc title */ + unsigned int jlc_exists_in_cell_cmd : 1; + unsigned int jlc_exists_in_prepost_cmd : 1; + unsigned int jlc_exists_in_button_cmd : 1; + unsigned int jlc_exists_in_tt_dom : 1; + unsigned int chapter_search_or_play : 1; /* UOP 1 */ + unsigned int title_or_time_play : 1; /* UOP 0 */ +#else + unsigned char title_or_time_play : 1; + unsigned char chapter_search_or_play : 1; + unsigned char jlc_exists_in_tt_dom : 1; + unsigned char jlc_exists_in_button_cmd : 1; + unsigned char jlc_exists_in_prepost_cmd : 1; + unsigned char jlc_exists_in_cell_cmd : 1; + unsigned char multi_or_random_pgc_title : 1; + unsigned char zero_1 : 1; +#endif +} ATTRIBUTE_PACKED playback_type_t; + +/** + * Title Information. + */ +typedef struct { + playback_type_t pb_ty; + uint8_t nr_of_angles; + uint16_t nr_of_ptts; + uint16_t parental_id; + uint8_t title_set_nr; + uint8_t vts_ttn; + uint32_t title_set_sector; +} ATTRIBUTE_PACKED title_info_t; + +/** + * PartOfTitle Search Pointer Table. + */ +typedef struct { + uint16_t nr_of_srpts; + uint16_t zero_1; + uint32_t last_byte; + title_info_t *title; +} ATTRIBUTE_PACKED tt_srpt_t; +#define TT_SRPT_SIZE 8 + + +/** + * Parental Management Information Unit Table. + * 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 8 + +/** + * Parental Management Information Table. + */ +typedef struct { + uint16_t nr_of_countries; + uint16_t nr_of_vtss; + uint32_t last_byte; + ptl_mait_country_t *countries; +} ATTRIBUTE_PACKED ptl_mait_t; +#define PTL_MAIT_SIZE 8 + +/** + * Video Title Set Attributes. + */ +typedef struct { + uint32_t last_byte; + uint32_t vts_cat; + + video_attr_t vtsm_vobs_attr; + uint8_t zero_1; + uint8_t nr_of_vtsm_audio_streams; /* should be 0 or 1 */ + audio_attr_t vtsm_audio_attr; + audio_attr_t zero_2[7]; + uint8_t zero_3[16]; + uint8_t zero_4; + uint8_t nr_of_vtsm_subp_streams; /* should be 0 or 1 */ + subp_attr_t vtsm_subp_attr; + subp_attr_t zero_5[27]; + + uint8_t zero_6[2]; + + video_attr_t vtstt_vobs_video_attr; + uint8_t zero_7; + uint8_t nr_of_vtstt_audio_streams; + audio_attr_t vtstt_audio_attr[8]; + uint8_t zero_8[16]; + uint8_t zero_9; + uint8_t nr_of_vtstt_subp_streams; + subp_attr_t vtstt_subp_attr[32]; +} ATTRIBUTE_PACKED vts_attributes_t; +#define VTS_ATTRIBUTES_SIZE 542 +#define VTS_ATTRIBUTES_MIN_SIZE 356 + +/** + * Video Title Set Attribute Table. + */ +typedef struct { + uint16_t nr_of_vtss; + uint16_t zero_1; + uint32_t last_byte; + vts_attributes_t *vts; + uint32_t *vts_atrt_offsets; /* offsets table for each vts_attributes */ +} ATTRIBUTE_PACKED vts_atrt_t; +#define VTS_ATRT_SIZE 8 + +/** + * Text Data. (Incomplete) + */ +typedef struct { + uint32_t last_byte; /* offsets are relative here */ + uint16_t offsets[100]; /* == nr_of_srpts + 1 (first is disc title) */ +#if 0 + uint16_t unknown; /* 0x48 ?? 0x48 words (16bit) info following */ + uint16_t zero_1; + + uint8_t type_of_info; /* ?? 01 == disc, 02 == Title, 04 == Title part */ + uint8_t unknown1; + uint8_t unknown2; + uint8_t unknown3; + uint8_t unknown4; /* ?? allways 0x30 language?, text format? */ + uint8_t unknown5; + uint16_t offset; /* from first */ + + char text[12]; /* ended by 0x09 */ +#endif +} ATTRIBUTE_PACKED txtdt_t; + +/** + * Text Data Language Unit. (Incomplete) + */ +typedef struct { + uint16_t lang_code; + uint16_t unknown; /* 0x0001, title 1? disc 1? side 1? */ + uint32_t txtdt_start_byte; /* prt, rel start of vmg_txtdt_mgi */ + txtdt_t *txtdt; +} ATTRIBUTE_PACKED txtdt_lu_t; +#define TXTDT_LU_SIZE 8 + +/** + * Text Data Manager Information. (Incomplete) + */ +typedef struct { + char disc_name[14]; /* how many bytes?? */ + uint16_t nr_of_language_units; /* 32bit?? */ + uint32_t last_byte; + txtdt_lu_t *lu; +} ATTRIBUTE_PACKED txtdt_mgi_t; +#define TXTDT_MGI_SIZE 20 + + +/** + * VTS + * + * Structures relating to the Video Title Set (VTS). + */ + +/** + * Video Title Set Information Management Table. + */ +typedef struct { + char vts_identifier[12]; + uint32_t vts_last_sector; + uint8_t zero_1[12]; + uint32_t vtsi_last_sector; + uint8_t zero_2; + uint8_t specification_version; + uint32_t vts_category; + uint16_t zero_3; + uint16_t zero_4; + uint8_t zero_5; + uint8_t zero_6[19]; + uint16_t zero_7; + uint8_t zero_8[32]; + uint64_t zero_9; + uint8_t zero_10[24]; + uint32_t vtsi_last_byte; + uint32_t zero_11; + uint8_t zero_12[56]; + uint32_t vtsm_vobs; /* sector */ + uint32_t vtstt_vobs; /* sector */ + uint32_t vts_ptt_srpt; /* sector */ + uint32_t vts_pgcit; /* sector */ + uint32_t vtsm_pgci_ut; /* sector */ + uint32_t vts_tmapt; /* sector */ + 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 8 + + +/** + * 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 4 + +/** + * 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 8 + + +#if PRAGMA_PACK +#pragma pack() +#endif + + +/** + * The following structure defines an IFO file. The structure is divided into + * two parts, the VMGI, or Video Manager Information, which is read from the + * VIDEO_TS.[IFO,BUP] file, and the VTSI, or Video Title Set Information, which + * is read in from the VTS_XX_0.[IFO,BUP] files. + */ +typedef struct { + dvd_file_t *file; + + /* VMGI */ + vmgi_mat_t *vmgi_mat; + tt_srpt_t *tt_srpt; + pgc_t *first_play_pgc; + ptl_mait_t *ptl_mait; + vts_atrt_t *vts_atrt; + txtdt_mgi_t *txtdt_mgi; + + /* Common */ + pgci_ut_t *pgci_ut; + c_adt_t *menu_c_adt; + vobu_admap_t *menu_vobu_admap; + + /* VTSI */ + vtsi_mat_t *vtsi_mat; + vts_ptt_srpt_t *vts_ptt_srpt; + pgcit_t *vts_pgcit; + 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 -r f19fce15577b -r 9b1b740e3fc9 dvdread/md5.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/md5.c Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,417 @@ +/* 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 , 1995. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#if STDC_HEADERS || defined _LIBC +# include +# include +#else +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# endif +#endif + +#include "md5.h" +/* #include "unlocked-io.h" */ + +#ifdef _LIBC +# include +# 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 -r f19fce15577b -r 9b1b740e3fc9 dvdread/md5.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/md5.h Sun Jan 11 21:43:13 2004 +0000 @@ -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 + +#if defined HAVE_LIMITS_H || _LIBC +# include +#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 +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 ) 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 -r f19fce15577b -r 9b1b740e3fc9 dvdread/nav_print.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/nav_print.c Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003 Håkan Hjort + * + * Much of the contents in this file is based on VOBDUMP. + * + * VOBDUMP: a program for examining DVD .VOB filse + * + * Copyright 1998, 1999 Eric Smith + * + * 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 +#include + +#include "nav_types.h" +#include "nav_print.h" +#include "dvdread_internal.h" + +static void print_time(dvd_time_t *dtime) { + const char *rate; + CHECK_VALUE((dtime->hour>>4) < 0xa && (dtime->hour&0xf) < 0xa); + CHECK_VALUE((dtime->minute>>4) < 0x7 && (dtime->minute&0xf) < 0xa); + CHECK_VALUE((dtime->second>>4) < 0x7 && (dtime->second&0xf) < 0xa); + CHECK_VALUE((dtime->frame_u&0xf) < 0xa); + + printf("%02x:%02x:%02x.%02x", + dtime->hour, + dtime->minute, + dtime->second, + dtime->frame_u & 0x3f); + switch((dtime->frame_u & 0xc0) >> 6) { + case 1: + rate = "25.00"; + break; + case 3: + rate = "29.97"; + break; + default: + rate = "(please send a bug report)"; + break; + } + printf(" @ %s fps", rate); +} + + +static void navPrint_PCI_GI(pci_gi_t *pci_gi) { + int i; + + printf("pci_gi:\n"); + printf("nv_pck_lbn 0x%08x\n", pci_gi->nv_pck_lbn); + printf("vobu_cat 0x%04x\n", pci_gi->vobu_cat); + printf("vobu_uop_ctl 0x%08x\n", *(uint32_t*)&pci_gi->vobu_uop_ctl); + printf("vobu_s_ptm 0x%08x\n", pci_gi->vobu_s_ptm); + printf("vobu_e_ptm 0x%08x\n", pci_gi->vobu_e_ptm); + printf("vobu_se_e_ptm 0x%08x\n", pci_gi->vobu_se_e_ptm); + printf("e_eltm "); + print_time(&pci_gi->e_eltm); + printf("\n"); + + printf("vobu_isrc \""); + for(i = 0; i < 32; i++) { + char c = pci_gi->vobu_isrc[i]; + if((c >= ' ') && (c <= '~')) + printf("%c", c); + else + printf("."); + } + printf("\"\n"); +} + +static void navPrint_NSML_AGLI(nsml_agli_t *nsml_agli) { + int i, j = 0; + + for(i = 0; i < 9; i++) + j |= nsml_agli->nsml_agl_dsta[i]; + if(j == 0) + return; + + printf("nsml_agli:\n"); + for(i = 0; i < 9; i++) + if(nsml_agli->nsml_agl_dsta[i]) + printf("nsml_agl_c%d_dsta 0x%08x\n", i + 1, + nsml_agli->nsml_agl_dsta[i]); +} + +static void navPrint_HL_GI(hl_gi_t *hl_gi, int *btngr_ns, int *btn_ns) { + + if((hl_gi->hli_ss & 0x03) == 0) + return; + + printf("hl_gi:\n"); + printf("hli_ss 0x%01x\n", hl_gi->hli_ss & 0x03); + printf("hli_s_ptm 0x%08x\n", hl_gi->hli_s_ptm); + printf("hli_e_ptm 0x%08x\n", hl_gi->hli_e_ptm); + printf("btn_se_e_ptm 0x%08x\n", hl_gi->btn_se_e_ptm); + + *btngr_ns = hl_gi->btngr_ns; + printf("btngr_ns %d\n", hl_gi->btngr_ns); + printf("btngr%d_dsp_ty 0x%02x\n", 1, hl_gi->btngr1_dsp_ty); + printf("btngr%d_dsp_ty 0x%02x\n", 2, hl_gi->btngr2_dsp_ty); + printf("btngr%d_dsp_ty 0x%02x\n", 3, hl_gi->btngr3_dsp_ty); + + printf("btn_ofn %d\n", hl_gi->btn_ofn); + *btn_ns = hl_gi->btn_ns; + printf("btn_ns %d\n", hl_gi->btn_ns); + printf("nsl_btn_ns %d\n", hl_gi->nsl_btn_ns); + printf("fosl_btnn %d\n", hl_gi->fosl_btnn); + printf("foac_btnn %d\n", hl_gi->foac_btnn); +} + +static void navPrint_BTN_COLIT(btn_colit_t *btn_colit) { + int i, j; + + j = 0; + for(i = 0; i < 6; i++) + j |= btn_colit->btn_coli[i/2][i&1]; + if(j == 0) + return; + + printf("btn_colit:\n"); + for(i = 0; i < 3; i++) + for(j = 0; j < 2; j++) + printf("btn_cqoli %d %s_coli: %08x\n", + i, (j == 0) ? "sl" : "ac", + btn_colit->btn_coli[i][j]); +} + +static void navPrint_BTNIT(btni_t *btni_table, int btngr_ns, int btn_ns) { + int i, j; + + printf("btnit:\n"); + printf("btngr_ns: %i\n", btngr_ns); + printf("btn_ns: %i\n", btn_ns); + + if(btngr_ns == 0) + return; + + for(i = 0; i < btngr_ns; i++) { + for(j = 0; j < (36 / btngr_ns); j++) { + if(j < btn_ns) { + btni_t *btni = &btni_table[(36 / btngr_ns) * i + j]; + + printf("group %d btni %d: ", i+1, j+1); + printf("btn_coln %d, auto_action_mode %d\n", + btni->btn_coln, btni->auto_action_mode); + printf("coords (%d, %d) .. (%d, %d)\n", + btni->x_start, btni->y_start, btni->x_end, btni->y_end); + + printf("up %d, ", btni->up); + printf("down %d, ", btni->down); + printf("left %d, ", btni->left); + printf("right %d\n", btni->right); + + /* ifoPrint_COMMAND(&btni->cmd); */ + printf("\n"); + } + } + } +} + +static void navPrint_HLI(hli_t *hli) { + int btngr_ns = 0, btn_ns = 0; + + printf("hli:\n"); + navPrint_HL_GI(&hli->hl_gi, & btngr_ns, & btn_ns); + navPrint_BTN_COLIT(&hli->btn_colit); + navPrint_BTNIT(hli->btnit, btngr_ns, btn_ns); +} + +void navPrint_PCI(pci_t *pci) { + printf("pci packet:\n"); + navPrint_PCI_GI(&pci->pci_gi); + navPrint_NSML_AGLI(&pci->nsml_agli); + navPrint_HLI(&pci->hli); +} + +static void navPrint_DSI_GI(dsi_gi_t *dsi_gi) { + printf("dsi_gi:\n"); + printf("nv_pck_scr 0x%08x\n", dsi_gi->nv_pck_scr); + printf("nv_pck_lbn 0x%08x\n", dsi_gi->nv_pck_lbn ); + printf("vobu_ea 0x%08x\n", dsi_gi->vobu_ea); + printf("vobu_1stref_ea 0x%08x\n", dsi_gi->vobu_1stref_ea); + printf("vobu_2ndref_ea 0x%08x\n", dsi_gi->vobu_2ndref_ea); + printf("vobu_3rdref_ea 0x%08x\n", dsi_gi->vobu_3rdref_ea); + printf("vobu_vob_idn 0x%04x\n", dsi_gi->vobu_vob_idn); + printf("vobu_c_idn 0x%02x\n", dsi_gi->vobu_c_idn); + printf("c_eltm "); + print_time(&dsi_gi->c_eltm); + printf("\n"); +} + +static void navPrint_SML_PBI(sml_pbi_t *sml_pbi) { + printf("sml_pbi:\n"); + printf("category 0x%04x\n", sml_pbi->category); + if(sml_pbi->category & 0x8000) + printf("VOBU is in preunit\n"); + if(sml_pbi->category & 0x4000) + printf("VOBU is in ILVU\n"); + if(sml_pbi->category & 0x2000) + printf("VOBU at the beginning of ILVU\n"); + if(sml_pbi->category & 0x1000) + printf("VOBU at end of PREU of ILVU\n"); + + printf("ilvu_ea 0x%08x\n", sml_pbi->ilvu_ea); + printf("nxt_ilvu_sa 0x%08x\n", sml_pbi->ilvu_sa); + printf("nxt_ilvu_size 0x%04x\n", sml_pbi->size); + + printf("vob_v_s_s_ptm 0x%08x\n", sml_pbi->vob_v_s_s_ptm); + printf("vob_v_e_e_ptm 0x%08x\n", sml_pbi->vob_v_e_e_ptm); + + /* $$$ more code needed here */ +} + +static void navPrint_SML_AGLI(sml_agli_t *sml_agli) { + int i; + printf("sml_agli:\n"); + for(i = 0; i < 9; i++) { + printf("agl_c%d address: 0x%08x size 0x%04x\n", i, + sml_agli->data[i].address, sml_agli->data[i].size); + } +} + +static void navPrint_VOBU_SRI(vobu_sri_t *vobu_sri) { + int i; + int stime[19] = { 240, 120, 60, 20, 15, 14, 13, 12, 11, + 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; + printf("vobu_sri:\n"); + printf("Next VOBU with Video %08x\n", vobu_sri->next_video); + for(i = 0; i < 19; i++) { + printf("%3.1f %08x ", stime[i]/2.0, vobu_sri->fwda[i]); + } + printf("\n"); + printf("Next VOBU %08x\n", vobu_sri->next_vobu); + printf("--\n"); + printf("Prev VOBU %08x\n", vobu_sri->prev_vobu); + for(i = 0; i < 19; i++) { + printf("%3.1f %08x ", stime[18 - i]/2.0, vobu_sri->bwda[i]); + } + printf("\n"); + printf("Prev VOBU with Video %08x\n", vobu_sri->prev_video); +} + +static void navPrint_SYNCI(synci_t *synci) { + int i; + + printf("synci:\n"); + /* $$$ more code needed here */ + for(i = 0; i < 8; i++) + printf("%04x ", synci->a_synca[i]); + for(i = 0; i < 32; i++) + printf("%08x ", synci->sp_synca[i]); +} + +void navPrint_DSI(dsi_t *dsi) { + printf("dsi packet:\n"); + navPrint_DSI_GI(&dsi->dsi_gi); + navPrint_SML_PBI(&dsi->sml_pbi); + navPrint_SML_AGLI(&dsi->sml_agli); + navPrint_VOBU_SRI(&dsi->vobu_sri); + navPrint_SYNCI(&dsi->synci); +} + + diff -r f19fce15577b -r 9b1b740e3fc9 dvdread/nav_print.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/nav_print.h Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,50 @@ +#ifndef NAV_PRINT_H_INCLUDED +#define NAV_PRINT_H_INCLUDED + +/* + * Copyright (C) 2001, 2002 Billy Biggs , + * Håkan Hjort + * + * 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 -r f19fce15577b -r 9b1b740e3fc9 dvdread/nav_read.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/nav_read.c Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,357 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003 Håkan Hjort + * + * 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 +#include +#include +#include + +#include "bswap.h" +#include "nav_types.h" +#include "nav_read.h" +#include "dvdread_internal.h" + +typedef struct { + uint8_t *start; + uint32_t byte_position; + uint32_t bit_position; + uint8_t byte; +} getbits_state_t; + +static int32_t getbits_init(getbits_state_t *state, uint8_t *start) { + if ((state == NULL) || (start == NULL)) return -1; + state->start = start; + state->bit_position = 0; + state->byte_position = 0; + state->byte = start[0]; + return 0; +} + +/* Non-optimized getbits. */ +/* This can easily be optimized for particular platforms. */ +static uint32_t 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"); + assert(0); + } + + 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. + */ +static uint16_t 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. + */ +static uint32_t 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 + +void navRead_PCI(pci_t *pci, unsigned char *buffer) { + int32_t i, j; + getbits_state_t state; + if (getbits_init(&state, buffer)) assert(0); /* 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)) assert(0); /* 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 -r f19fce15577b -r 9b1b740e3fc9 dvdread/nav_read.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/nav_read.h Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,51 @@ +#ifndef NAV_READ_H_INCLUDED +#define NAV_READ_H_INCLUDED + +/* + * Copyright (C) 2000, 2001, 2002 Håkan Hjort . + * + * 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 -r f19fce15577b -r 9b1b740e3fc9 dvdread/nav_types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvdread/nav_types.h Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,273 @@ +#ifndef NAV_TYPES_H_INCLUDED +#define NAV_TYPES_H_INCLUDED + +/* + * Copyright (C) 2000, 2001, 2002 Håkan Hjort + * + * 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 + * + * 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 +#include "ifo_types.h" /* only dvd_time_t, vm_cmd_t and user_ops_t */ + + +#undef ATTRIBUTE_PACKED +#undef PRAGMA_PACK_BEGIN +#undef PRAGMA_PACK_END + +#if defined(__GNUC__) +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) +#define ATTRIBUTE_PACKED __attribute__ ((packed)) +#define PRAGMA_PACK 0 +#endif +#endif + +#if !defined(ATTRIBUTE_PACKED) +#define ATTRIBUTE_PACKED +#define PRAGMA_PACK 1 +#endif + + +/* The length including the substream id byte. */ +#define PCI_BYTES 0x3d4 +#define DSI_BYTES 0x3fa + +#define PS2_PCI_SUBSTREAM_ID 0x00 +#define PS2_DSI_SUBSTREAM_ID 0x01 + +/* Remove this */ +#define DSI_START_BYTE 1031 + + +#if PRAGMA_PACK +#pragma pack(1) +#endif + + +/** + * PCI General Information + */ +typedef struct { + uint32_t nv_pck_lbn; /**< 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 -r f19fce15577b -r 9b1b740e3fc9 dvdread_internal.h --- a/dvdread_internal.h Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -#ifndef DVDREAD_INTERNAL_H -#define DVDREAD_INTERNAL_H - -#ifdef _MSC_VER -#include -#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 -r f19fce15577b -r 9b1b740e3fc9 ifo_print.c --- a/ifo_print.c Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1194 +0,0 @@ -/* - * 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$ - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" // Needed for WORDS_BIGENDIAN -#include -#include -#include "ifo_print.h" -#include "vmcmd.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); -} - -/* 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("| "); - vm_print_mnemonic(command); - 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 "); - break; - case 1: - printf("(please send a bug report) "); - break; - case 2: - printf("mpeg1 "); - break; - case 3: - printf("mpeg2ext "); - break; - case 4: - printf("lpcm "); - break; - case 5: - printf("(please send a bug report) "); - break; - case 6: - printf("dts "); - break; - default: - printf("(please send a bug report) "); - } - - if(attr->multichannel_extension) - printf("multichannel_extension "); - - switch(attr->lang_type) { - case 0: - // not specified - assert(attr->lang_code == 0 || 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;inr_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: "); - ifo_print_time(5, &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\n", - i, pgc->subp_control[i]); - } - } - - printf("Next PGC number: %i\n", pgc->next_pgc_nr); - printf("Prev PGC number: %i\n", pgc->prev_pgc_nr); - printf("GoUp PGC number: %i\n", pgc->goup_pgc_nr); - if(pgc->nr_of_programs != 0) { - printf("Still time: %i seconds (255=inf)\n", pgc->still_time); - printf("PG Playback mode %02x\n", pgc->pg_playback_mode); - } - - if(pgc->nr_of_programs != 0) { - for(i = 0; i < 16; i++) { - printf("Color %2i: %08x\n", i, pgc->palette[i]); - } - } - - /* Memmory offsets to div. tables. */ - 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;inr_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;inr_of_srpts;i++) { - for(j=0;jtitle[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"); - ifo_print_PGC(ifohandle->first_play_pgc); - - 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.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 -r f19fce15577b -r 9b1b740e3fc9 ifo_print.h --- a/ifo_print.h Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * 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$ - * - */ - -#ifndef IFO_PRINT_H_INCLUDED -#define IFO_PRINT_H_INCLUDED - -#include -#include /* Only for vm_cmd_t */ - -void ifo_print(dvd_reader_t *dvd, int title); - -#endif /* IFO_PRINT_H_INCLUDED */ - -/* - * $Log$ - * 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 -r f19fce15577b -r 9b1b740e3fc9 ifo_read.c --- a/ifo_read.c Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2024 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002, 2003 - * Björn Englund , - * Håkan Hjort - * - * 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 -#include -#include -#include - -#include "bswap.h" -#include "ifo_types.h" -#include "ifo_read.h" -#include "dvd_reader.h" -#include "dvdread_internal.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 DVDFileSeek_( dvd_file_t *dvd_file, uint32_t offset ) { - return (DVDFileSeek(dvd_file, (int)offset) == (int)offset); -} - - -ifo_handle_t *ifoOpen(dvd_reader_t *dvd, int title) { - ifo_handle_t *ifofile; - - ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t)); - if(!ifofile) - return 0; - - memset(ifofile, 0, sizeof(ifo_handle_t)); - - ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE); - if(!ifofile->file) /* 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 0; - } - - /* First check if this is a VMGI file. */ - if(ifoRead_VMG(ifofile)) { - - /* These are both mandatory. */ - if(!ifoRead_FP_PGC(ifofile) || !ifoRead_TT_SRPT(ifofile)) { - fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO).\n"); - ifoClose(ifofile); - return 0; - } - - ifoRead_PGCI_UT(ifofile); - ifoRead_PTL_MAIT(ifofile); - - /* This is also mandatory. */ - if(!ifoRead_VTS_ATRT(ifofile)) { - fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO).\n"); - ifoClose(ifofile); - return 0; - } - - ifoRead_TXTDT_MGI(ifofile); - ifoRead_C_ADT(ifofile); - ifoRead_VOBU_ADMAP(ifofile); - - return ifofile; - } - - if(ifoRead_VTS(ifofile)) { - - if(!ifoRead_VTS_PTT_SRPT(ifofile) || !ifoRead_PGCIT(ifofile)) { - fprintf(stderr, "libdvdread: Invalid title IFO (VTS_%02d_0.IFO).\n", - title); - ifoClose(ifofile); - return 0; - } - - - ifoRead_PGCI_UT(ifofile); - ifoRead_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 0; - } - - 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 0; -} - - -ifo_handle_t *ifoOpenVMGI(dvd_reader_t *dvd) { - ifo_handle_t *ifofile; - - ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t)); - if(!ifofile) - return 0; - - memset(ifofile, 0, sizeof(ifo_handle_t)); - - ifofile->file = DVDOpenFile(dvd, 0, DVD_READ_INFO_FILE); - if(!ifofile->file) /* 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 0; - } - - if(ifoRead_VMG(ifofile)) - return ifofile; - - fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO).\n"); - ifoClose(ifofile); - return 0; -} - - -ifo_handle_t *ifoOpenVTSI(dvd_reader_t *dvd, int title) { - ifo_handle_t *ifofile; - - ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t)); - if(!ifofile) - return 0; - - memset(ifofile, 0, sizeof(ifo_handle_t)); - - if(title <= 0 || title > 99) { - fprintf(stderr, "libdvdread: ifoOpenVTSI invalid title (%d).\n", title); - free(ifofile); - return 0; - } - - 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 0; - } - - ifoRead_VTS(ifofile); - if(ifofile->vtsi_mat) - return ifofile; - - fprintf(stderr, "libdvdread: Invalid IFO for title %d (VTS_%02d_0.IFO).\n", - title, title); - ifoClose(ifofile); - return 0; -} - - -void ifoClose(ifo_handle_t *ifofile) { - if(!ifofile) - return; - - ifoFree_VOBU_ADMAP(ifofile); - ifoFree_TITLE_VOBU_ADMAP(ifofile); - ifoFree_C_ADT(ifofile); - ifoFree_TITLE_C_ADT(ifofile); - ifoFree_TXTDT_MGI(ifofile); - ifoFree_VTS_ATRT(ifofile); - ifoFree_PTL_MAIT(ifofile); - ifoFree_PGCI_UT(ifofile); - ifoFree_TT_SRPT(ifofile); - ifoFree_FP_PGC(ifofile); - ifoFree_PGCIT(ifofile); - ifoFree_VTS_PTT_SRPT(ifofile); - - if(ifofile->vmgi_mat) - free(ifofile->vmgi_mat); - - if(ifofile->vtsi_mat) - free(ifofile->vtsi_mat); - - DVDCloseFile(ifofile->file); - ifofile->file = 0; - free(ifofile); - ifofile = 0; -} - - -static int ifoRead_VMG(ifo_handle_t *ifofile) { - vmgi_mat_t *vmgi_mat; - - vmgi_mat = (vmgi_mat_t *)malloc(sizeof(vmgi_mat_t)); - if(!vmgi_mat) - return 0; - - ifofile->vmgi_mat = vmgi_mat; - - if(!DVDFileSeek_(ifofile->file, 0)) { - free(ifofile->vmgi_mat); - ifofile->vmgi_mat = 0; - return 0; - } - - if(!DVDReadBytes(ifofile->file, vmgi_mat, sizeof(vmgi_mat_t))) { - free(ifofile->vmgi_mat); - ifofile->vmgi_mat = 0; - return 0; - } - - if(strncmp("DVDVIDEO-VMG", vmgi_mat->vmg_identifier, 12) != 0) { - free(ifofile->vmgi_mat); - ifofile->vmgi_mat = 0; - return 0; - } - - B2N_32(vmgi_mat->vmg_last_sector); - B2N_32(vmgi_mat->vmgi_last_sector); - B2N_32(vmgi_mat->vmg_category); - B2N_16(vmgi_mat->vmg_nr_of_volumes); - B2N_16(vmgi_mat->vmg_this_volume_nr); - B2N_16(vmgi_mat->vmg_nr_of_title_sets); - B2N_64(vmgi_mat->vmg_pos_code); - B2N_32(vmgi_mat->vmgi_last_byte); - B2N_32(vmgi_mat->first_play_pgc); - B2N_32(vmgi_mat->vmgm_vobs); - B2N_32(vmgi_mat->tt_srpt); - B2N_32(vmgi_mat->vmgm_pgci_ut); - B2N_32(vmgi_mat->ptl_mait); - B2N_32(vmgi_mat->vts_atrt); - B2N_32(vmgi_mat->txtdt_mgi); - B2N_32(vmgi_mat->vmgm_c_adt); - B2N_32(vmgi_mat->vmgm_vobu_admap); - B2N_16(vmgi_mat->vmgm_audio_attr.lang_code); - B2N_16(vmgi_mat->vmgm_subp_attr.lang_code); - - - CHECK_ZERO(vmgi_mat->zero_1); - CHECK_ZERO(vmgi_mat->zero_2); - CHECK_ZERO(vmgi_mat->zero_3); - CHECK_ZERO(vmgi_mat->zero_4); - CHECK_ZERO(vmgi_mat->zero_5); - CHECK_ZERO(vmgi_mat->zero_6); - CHECK_ZERO(vmgi_mat->zero_7); - CHECK_ZERO(vmgi_mat->zero_8); - CHECK_ZERO(vmgi_mat->zero_9); - CHECK_ZERO(vmgi_mat->zero_10); - 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; - } - - B2N_32(vtsi_mat->vts_last_sector); - B2N_32(vtsi_mat->vtsi_last_sector); - B2N_32(vtsi_mat->vts_category); - B2N_32(vtsi_mat->vtsi_last_byte); - B2N_32(vtsi_mat->vtsm_vobs); - B2N_32(vtsi_mat->vtstt_vobs); - B2N_32(vtsi_mat->vts_ptt_srpt); - B2N_32(vtsi_mat->vts_pgcit); - B2N_32(vtsi_mat->vtsm_pgci_ut); - B2N_32(vtsi_mat->vts_tmapt); - B2N_32(vtsi_mat->vtsm_c_adt); - B2N_32(vtsi_mat->vtsm_vobu_admap); - B2N_32(vtsi_mat->vts_c_adt); - B2N_32(vtsi_mat->vts_vobu_admap); - B2N_16(vtsi_mat->vtsm_audio_attr.lang_code); - B2N_16(vtsi_mat->vtsm_subp_attr.lang_code); - for(i = 0; i < 8; i++) - B2N_16(vtsi_mat->vts_audio_attr[i].lang_code); - for(i = 0; i < 32; i++) - B2N_16(vtsi_mat->vts_subp_attr[i].lang_code); - - - CHECK_ZERO(vtsi_mat->zero_1); - CHECK_ZERO(vtsi_mat->zero_2); - CHECK_ZERO(vtsi_mat->zero_3); - CHECK_ZERO(vtsi_mat->zero_4); - CHECK_ZERO(vtsi_mat->zero_5); - CHECK_ZERO(vtsi_mat->zero_6); - CHECK_ZERO(vtsi_mat->zero_7); - CHECK_ZERO(vtsi_mat->zero_8); - CHECK_ZERO(vtsi_mat->zero_9); - CHECK_ZERO(vtsi_mat->zero_10); - CHECK_ZERO(vtsi_mat->zero_11); - CHECK_ZERO(vtsi_mat->zero_12); - CHECK_ZERO(vtsi_mat->zero_13); - CHECK_ZERO(vtsi_mat->zero_14); - CHECK_ZERO(vtsi_mat->zero_15); - CHECK_ZERO(vtsi_mat->zero_16); - CHECK_ZERO(vtsi_mat->zero_17); - CHECK_ZERO(vtsi_mat->zero_18); - CHECK_ZERO(vtsi_mat->zero_19); - CHECK_ZERO(vtsi_mat->zero_20); - 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++) { - 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++) { - B2N_32(cell_playback[i].first_sector); - B2N_32(cell_playback[i].first_ilvu_end_sector); - B2N_32(cell_playback[i].last_vobu_start_sector); - B2N_32(cell_playback[i].last_sector); - - /* Changed < to <= because this was false in the movie 'Pi'. */ - 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; - - 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->program_map = malloc(pgc->nr_of_programs * sizeof(pgc_program_map_t)); - if(!pgc->program_map) { - ifoFree_PGC_COMMAND_TBL(pgc->command_tbl); - return 0; - } - if(!ifoRead_PGC_PROGRAM_MAP(ifofile, pgc->program_map,pgc->nr_of_programs, - offset + pgc->program_map_offset)) { - ifoFree_PGC_COMMAND_TBL(pgc->command_tbl); - free(pgc->program_map); - return 0; - } - } else { - pgc->program_map = NULL; - } - - if(pgc->cell_playback_offset != 0) { - pgc->cell_playback = malloc(pgc->nr_of_cells * sizeof(cell_playback_t)); - if(!pgc->cell_playback) { - ifoFree_PGC_COMMAND_TBL(pgc->command_tbl); - if(pgc->program_map) - free(pgc->program_map); - return 0; - } - if(!ifoRead_CELL_PLAYBACK_TBL(ifofile, pgc->cell_playback, - pgc->nr_of_cells, - offset + pgc->cell_playback_offset)) { - ifoFree_PGC_COMMAND_TBL(pgc->command_tbl); - if(pgc->program_map) - free(pgc->program_map); - free(pgc->cell_playback); - return 0; - } - } else { - pgc->cell_playback = NULL; - } - - if(pgc->cell_position_offset != 0) { - pgc->cell_position = malloc(pgc->nr_of_cells * sizeof(cell_position_t)); - if(!pgc->cell_position) { - ifoFree_PGC(pgc); - return 0; - } - if(!ifoRead_CELL_POSITION_TBL(ifofile, pgc->cell_position, - pgc->nr_of_cells, - offset + pgc->cell_position_offset)) { - ifoFree_PGC(pgc); - return 0; - } - } else { - pgc->cell_position = NULL; - } - - return 1; -} - -int ifoRead_FP_PGC(ifo_handle_t *ifofile) { - - if(!ifofile) - return 0; - - if(!ifofile->vmgi_mat) - return 0; - - /* 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++) { - 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) { - for(j = 0; j < i ; j++) { - free(ptl_mait->countries[j].pf_ptl_mai); - } - free(ptl_mait->countries); - free(ptl_mait); - return 0; - } - if(!(DVDReadBytes(ifofile->file, pf_temp, info_length))) { - fprintf(stderr, "libdvdread: Unable to read PTL_MAIT table.\n"); - free(pf_temp); - for(j = 0; j < i ; j++) { - free(ptl_mait->countries[j].pf_ptl_mai); - } - free(ptl_mait->countries); - free(ptl_mait); - 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); - for(j = 0; j < i ; j++) { - free(ptl_mait->countries[j].pf_ptl_mai); - } - free(ptl_mait->countries); - free(ptl_mait); - 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(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN)) - return 0; - - if(!(DVDReadBytes(ifofile->file, vobu_admap, VOBU_ADMAP_SIZE))) - return 0; - - B2N_32(vobu_admap->last_byte); - - info_length = vobu_admap->last_byte + 1 - VOBU_ADMAP_SIZE; - /* assert(info_length > 0); - Magic Knight Rayearth Daybreak is mastered very strange and has - Titles with a VOBS that has no VOBUs. */ - 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_LU_SIZE); - ptr += PGCI_LU_SIZE; - B2N_16(pgcit->pgci_srp[i].ptl_id_mask); - B2N_32(pgcit->pgci_srp[i].pgc_start_byte); - 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); - } - return 0; - } - if(!ifoRead_PGC(ifofile, pgcit->pgci_srp[i].pgc, - offset + pgcit->pgci_srp[i].pgc_start_byte)) { - int j; - for(j = 0; j < i; j++) { - ifoFree_PGC(pgcit->pgci_srp[j].pgc); - free(pgcit->pgci_srp[j].pgc); - } - free(pgcit->pgci_srp); - return 0; - } - } - - return 1; -} - -static void ifoFree_PGCIT_internal(pgcit_t *pgcit) { - if(pgcit) { - int i; - for(i = 0; i < pgcit->nr_of_pgci_srp; i++) - ifoFree_PGC(pgcit->pgci_srp[i].pgc); - free(pgcit->pgci_srp); - } -} - -void ifoFree_PGCIT(ifo_handle_t *ifofile) { - if(!ifofile) - return; - - if(ifofile->vts_pgcit) { - ifoFree_PGCIT_internal(ifofile->vts_pgcit); - free(ifofile->vts_pgcit); - ifofile->vts_pgcit = 0; - } -} - - -int ifoRead_PGCI_UT(ifo_handle_t *ifofile) { - pgci_ut_t *pgci_ut; - unsigned int sector; - unsigned int i; - int info_length; - uint8_t *data, *ptr; - - if(!ifofile) - return 0; - - if(ifofile->vmgi_mat) { - if(ifofile->vmgi_mat->vmgm_pgci_ut == 0) - return 1; - sector = ifofile->vmgi_mat->vmgm_pgci_ut; - } else if(ifofile->vtsi_mat) { - if(ifofile->vtsi_mat->vtsm_pgci_ut == 0) - return 1; - sector = ifofile->vtsi_mat->vtsm_pgci_ut; - } else { - return 0; - } - - ifofile->pgci_ut = (pgci_ut_t *)malloc(sizeof(pgci_ut_t)); - if(!ifofile->pgci_ut) - return 0; - - if(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN)) { - free(ifofile->pgci_ut); - ifofile->pgci_ut = 0; - return 0; - } - - if(!(DVDReadBytes(ifofile->file, ifofile->pgci_ut, PGCI_UT_SIZE))) { - free(ifofile->pgci_ut); - ifofile->pgci_ut = 0; - return 0; - } - - pgci_ut = ifofile->pgci_ut; - - B2N_16(pgci_ut->nr_of_lus); - B2N_32(pgci_ut->last_byte); - - CHECK_ZERO(pgci_ut->zero_1); - 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; - - B2N_32(vts_attributes->last_byte); - B2N_32(vts_attributes->vts_cat); - B2N_16(vts_attributes->vtsm_audio_attr.lang_code); - B2N_16(vts_attributes->vtsm_subp_attr.lang_code); - for(i = 0; i < 8; i++) - B2N_16(vts_attributes->vtstt_audio_attr[i].lang_code); - for(i = 0; i < 32; i++) - B2N_16(vts_attributes->vtstt_subp_attr[i].lang_code); - - CHECK_ZERO(vts_attributes->zero_1); - CHECK_ZERO(vts_attributes->zero_2); - CHECK_ZERO(vts_attributes->zero_3); - CHECK_ZERO(vts_attributes->zero_4); - CHECK_ZERO(vts_attributes->zero_5); - CHECK_ZERO(vts_attributes->zero_6); - CHECK_ZERO(vts_attributes->zero_7); - 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 -r f19fce15577b -r 9b1b740e3fc9 ifo_read.h --- a/ifo_read.h Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,227 +0,0 @@ -#ifndef IFO_READ_H_INCLUDED -#define IFO_READ_H_INCLUDED - -/* - * Copyright (C) 2000, 2001, 2002 Björn Englund , - * Håkan Hjort - * - * 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 -r f19fce15577b -r 9b1b740e3fc9 ifo_types.h --- a/ifo_types.h Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,884 +0,0 @@ -#ifndef IFO_TYPES_H_INCLUDED -#define IFO_TYPES_H_INCLUDED - -/* - * Copyright (C) 2000, 2001 Björn Englund , - * Håkan Hjort - * - * 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 -#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 8 - - -/** - * Video Attributes. - */ -typedef struct { -#ifdef WORDS_BIGENDIAN - 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; -#else - unsigned char permitted_df : 2; - unsigned char display_aspect_ratio : 2; - unsigned char video_format : 2; - unsigned char mpeg_version : 2; - - unsigned char film_mode : 1; - unsigned char letterboxed : 1; - unsigned char picture_size : 2; - - unsigned char bit_rate : 1; - unsigned char unknown1 : 1; - unsigned char line21_cc_2 : 1; - unsigned char line21_cc_1 : 1; -#endif -} ATTRIBUTE_PACKED video_attr_t; - -/** - * Audio Attributes. - */ -typedef struct { -#ifdef WORDS_BIGENDIAN - 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; -#else - unsigned char application_mode : 2; - unsigned char lang_type : 2; - unsigned char multichannel_extension : 1; - unsigned char audio_format : 3; - - unsigned char channels : 3; - unsigned char unknown1 : 1; - unsigned char sample_frequency : 2; - unsigned char quantization : 2; -#endif - uint16_t lang_code; - uint8_t lang_extension; - uint8_t code_extension; - uint8_t unknown3; - union { - struct ATTRIBUTE_PACKED { -#ifdef WORDS_BIGENDIAN - 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 */ -#else - unsigned char mode : 1; - unsigned char mc_intro : 1; - unsigned char version : 2; - unsigned char channel_assignment : 3; - unsigned char unknown4 : 1; -#endif - } karaoke; - struct ATTRIBUTE_PACKED { -#ifdef WORDS_BIGENDIAN - unsigned char unknown5 : 4; - unsigned char dolby_encoded : 1; /* suitable for surround decoding */ - unsigned char unknown6 : 3; -#else - unsigned char unknown6 : 3; - unsigned char dolby_encoded : 1; - unsigned char unknown5 : 4; -#endif - } surround; - } app_info; -} ATTRIBUTE_PACKED audio_attr_t; - - -/** - * MultiChannel Extension - */ -typedef struct { -#ifdef WORDS_BIGENDIAN - 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; -#else - unsigned char ach0_gme : 1; - unsigned char zero1 : 7; - - unsigned char ach1_gme : 1; - unsigned char zero2 : 7; - - unsigned char ach2_gm2e : 1; - unsigned char ach2_gm1e : 1; - unsigned char ach2_gv2e : 1; - unsigned char ach2_gv1e : 1; - unsigned char zero3 : 4; - - unsigned char ach3_se2e : 1; - unsigned char ach3_gmAe : 1; - unsigned char ach3_gv2e : 1; - unsigned char ach3_gv1e : 1; - unsigned char zero4 : 4; - - unsigned char ach4_seBe : 1; - unsigned char ach4_gmBe : 1; - unsigned char ach4_gv2e : 1; - unsigned char ach4_gv1e : 1; - unsigned char zero5 : 4; -#endif - 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 - */ -#ifdef WORDS_BIGENDIAN - unsigned char code_mode : 3; - unsigned char zero1 : 3; - unsigned char type : 2; -#else - unsigned char type : 2; - unsigned char zero1 : 3; - unsigned char code_mode : 3; -#endif - 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 8 - -/** - * PGC Program Map - */ -typedef uint8_t pgc_program_map_t; - -/** - * Cell Playback Information. - */ -typedef struct { -#ifdef WORDS_BIGENDIAN - unsigned int block_mode : 2; - unsigned int block_type : 2; - unsigned int seamless_play : 1; - unsigned int interleaved : 1; - unsigned int stc_discontinuity: 1; - unsigned int seamless_angle : 1; - - unsigned int playback_mode : 1; /**< When set, enter StillMode after each VOBU */ - unsigned int restricted : 1; /**< ?? drop out of fastforward? */ - unsigned int unknown2 : 6; -#else - unsigned char seamless_angle : 1; - unsigned char stc_discontinuity: 1; - unsigned char interleaved : 1; - unsigned char seamless_play : 1; - unsigned char block_type : 2; - unsigned char block_mode : 2; - - unsigned char unknown2 : 6; - unsigned char restricted : 1; - unsigned char playback_mode : 1; -#endif - uint8_t still_time; - uint8_t cell_cmd_nr; - dvd_time_t playback_time; - uint32_t first_sector; - uint32_t first_ilvu_end_sector; - uint32_t last_vobu_start_sector; - uint32_t last_sector; -} ATTRIBUTE_PACKED cell_playback_t; - -#define BLOCK_TYPE_NONE 0x0 -#define BLOCK_TYPE_ANGLE_BLOCK 0x1 - -#define BLOCK_MODE_NOT_IN_BLOCK 0x0 -#define BLOCK_MODE_FIRST_CELL 0x1 -#define BLOCK_MODE_IN_BLOCK 0x2 -#define BLOCK_MODE_LAST_CELL 0x3 - -/** - * Cell Position Information. - */ -typedef struct { - uint16_t vob_id_nr; - uint8_t zero_1; - uint8_t cell_nr; -} ATTRIBUTE_PACKED cell_position_t; - -/** - * User Operations. - */ -typedef struct { -#ifdef WORDS_BIGENDIAN - unsigned int zero : 7; /* 25-31 */ - unsigned int video_pres_mode_change : 1; /* 24 */ - - unsigned int karaoke_audio_pres_mode_change : 1; /* 23 */ - unsigned int angle_change : 1; - 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 */ -#else - unsigned int video_pres_mode_change : 1; /* 24 */ - unsigned int zero : 7; /* 25-31 */ - - unsigned int resume : 1; /* 16 */ - unsigned int button_select_or_activate : 1; - unsigned int still_off : 1; - unsigned int pause_on : 1; - unsigned int audio_stream_change : 1; - unsigned int subpic_stream_change : 1; - unsigned int angle_change : 1; - unsigned int karaoke_audio_pres_mode_change : 1; /* 23 */ - - unsigned int forward_scan : 1; /* 8 */ - unsigned int backward_scan : 1; - unsigned int title_menu_call : 1; - unsigned int root_menu_call : 1; - unsigned int subpic_menu_call : 1; - unsigned int audio_menu_call : 1; - unsigned int angle_menu_call : 1; - unsigned int chapter_menu_call : 1; /* 15 */ - - unsigned int title_or_time_play : 1; /* 0 */ - unsigned int chapter_search_or_play : 1; - unsigned int title_play : 1; - unsigned int stop : 1; - unsigned int go_up : 1; - unsigned int time_or_chapter_search : 1; - unsigned int prev_or_top_pg_search : 1; - unsigned int next_pg_search : 1; /* 7 */ -#endif -} ATTRIBUTE_PACKED user_ops_t; - -/** - * Program Chain Information. - */ -typedef struct { - uint16_t zero_1; - uint8_t nr_of_programs; - uint8_t nr_of_cells; - dvd_time_t playback_time; - user_ops_t prohibited_ops; - uint16_t audio_control[8]; /* New type? */ - uint32_t subp_control[32]; /* New type? */ - uint16_t next_pgc_nr; - uint16_t prev_pgc_nr; - uint16_t goup_pgc_nr; - uint8_t still_time; - uint8_t pg_playback_mode; - uint32_t palette[16]; /* New type struct {zero_1, Y, Cr, Cb} ? */ - uint16_t command_tbl_offset; - uint16_t program_map_offset; - uint16_t cell_playback_offset; - uint16_t cell_position_offset; - pgc_command_tbl_t *command_tbl; - pgc_program_map_t *program_map; - cell_playback_t *cell_playback; - cell_position_t *cell_position; -} ATTRIBUTE_PACKED pgc_t; -#define PGC_SIZE 236 - -/** - * Program Chain Information Search Pointer. - */ -typedef struct { - uint8_t entry_id; -#ifdef WORDS_BIGENDIAN - unsigned int block_mode : 2; - unsigned int block_type : 2; - unsigned int unknown1 : 4; -#else - unsigned char unknown1 : 4; - unsigned char block_type : 2; - unsigned char block_mode : 2; -#endif - uint16_t ptl_id_mask; - uint32_t pgc_start_byte; - pgc_t *pgc; -} ATTRIBUTE_PACKED pgci_srp_t; -#define PGCI_SRP_SIZE 8 - -/** - * Program Chain Information Table. - */ -typedef struct { - uint16_t nr_of_pgci_srp; - uint16_t zero_1; - uint32_t last_byte; - pgci_srp_t *pgci_srp; -} ATTRIBUTE_PACKED pgcit_t; -#define PGCIT_SIZE 8 - -/** - * Menu PGCI Language Unit. - */ -typedef struct { - uint16_t lang_code; - uint8_t lang_extension; - uint8_t exists; - uint32_t lang_start_byte; - pgcit_t *pgcit; -} ATTRIBUTE_PACKED pgci_lu_t; -#define PGCI_LU_SIZE 8 - -/** - * Menu PGCI Unit Table. - */ -typedef struct { - uint16_t nr_of_lus; - uint16_t zero_1; - uint32_t last_byte; - pgci_lu_t *lu; -} ATTRIBUTE_PACKED pgci_ut_t; -#define PGCI_UT_SIZE 8 - -/** - * Cell Address Information. - */ -typedef struct { - uint16_t vob_id; - uint8_t cell_id; - uint8_t zero_1; - uint32_t start_sector; - uint32_t last_sector; -} ATTRIBUTE_PACKED cell_adr_t; - -/** - * Cell Address Table. - */ -typedef struct { - uint16_t nr_of_vobs; /* VOBs */ - uint16_t zero_1; - uint32_t last_byte; - cell_adr_t *cell_adr_table; /* No explicit size given. */ -} ATTRIBUTE_PACKED c_adt_t; -#define C_ADT_SIZE 8 - -/** - * VOBU Address Map. - */ -typedef struct { - uint32_t last_byte; - uint32_t *vobu_start_sectors; -} ATTRIBUTE_PACKED vobu_admap_t; -#define VOBU_ADMAP_SIZE 4 - - - - -/** - * VMGI - * - * The following structures relate to the Video Manager. - */ - -/** - * Video Manager Information Management Table. - */ -typedef struct { - char vmg_identifier[12]; - uint32_t vmg_last_sector; - uint8_t zero_1[12]; - uint32_t vmgi_last_sector; - uint8_t zero_2; - uint8_t specification_version; - uint32_t vmg_category; - uint16_t vmg_nr_of_volumes; - uint16_t vmg_this_volume_nr; - uint8_t disc_side; - uint8_t zero_3[19]; - uint16_t vmg_nr_of_title_sets; /* Number of VTSs. */ - char provider_identifier[32]; - uint64_t vmg_pos_code; - uint8_t zero_4[24]; - uint32_t vmgi_last_byte; - uint32_t first_play_pgc; - uint8_t zero_5[56]; - uint32_t vmgm_vobs; /* sector */ - uint32_t tt_srpt; /* sector */ - uint32_t vmgm_pgci_ut; /* sector */ - uint32_t ptl_mait; /* sector */ - uint32_t vts_atrt; /* sector */ - uint32_t txtdt_mgi; /* sector */ - uint32_t vmgm_c_adt; /* sector */ - uint32_t vmgm_vobu_admap; /* sector */ - uint8_t zero_6[32]; - - video_attr_t vmgm_video_attr; - uint8_t zero_7; - uint8_t nr_of_vmgm_audio_streams; /* should be 0 or 1 */ - audio_attr_t vmgm_audio_attr; - audio_attr_t zero_8[7]; - uint8_t zero_9[17]; - uint8_t nr_of_vmgm_subp_streams; /* should be 0 or 1 */ - subp_attr_t vmgm_subp_attr; - subp_attr_t zero_10[27]; /* XXX: how much 'padding' here? */ -} ATTRIBUTE_PACKED vmgi_mat_t; - -typedef struct { -#ifdef WORDS_BIGENDIAN - unsigned int zero_1 : 1; - unsigned int multi_or_random_pgc_title : 1; /* 0: one sequential pgc title */ - unsigned int jlc_exists_in_cell_cmd : 1; - unsigned int jlc_exists_in_prepost_cmd : 1; - unsigned int jlc_exists_in_button_cmd : 1; - unsigned int jlc_exists_in_tt_dom : 1; - unsigned int chapter_search_or_play : 1; /* UOP 1 */ - unsigned int title_or_time_play : 1; /* UOP 0 */ -#else - unsigned char title_or_time_play : 1; - unsigned char chapter_search_or_play : 1; - unsigned char jlc_exists_in_tt_dom : 1; - unsigned char jlc_exists_in_button_cmd : 1; - unsigned char jlc_exists_in_prepost_cmd : 1; - unsigned char jlc_exists_in_cell_cmd : 1; - unsigned char multi_or_random_pgc_title : 1; - unsigned char zero_1 : 1; -#endif -} ATTRIBUTE_PACKED playback_type_t; - -/** - * Title Information. - */ -typedef struct { - playback_type_t pb_ty; - uint8_t nr_of_angles; - uint16_t nr_of_ptts; - uint16_t parental_id; - uint8_t title_set_nr; - uint8_t vts_ttn; - uint32_t title_set_sector; -} ATTRIBUTE_PACKED title_info_t; - -/** - * PartOfTitle Search Pointer Table. - */ -typedef struct { - uint16_t nr_of_srpts; - uint16_t zero_1; - uint32_t last_byte; - title_info_t *title; -} ATTRIBUTE_PACKED tt_srpt_t; -#define TT_SRPT_SIZE 8 - - -/** - * Parental Management Information Unit Table. - * 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 8 - -/** - * Parental Management Information Table. - */ -typedef struct { - uint16_t nr_of_countries; - uint16_t nr_of_vtss; - uint32_t last_byte; - ptl_mait_country_t *countries; -} ATTRIBUTE_PACKED ptl_mait_t; -#define PTL_MAIT_SIZE 8 - -/** - * Video Title Set Attributes. - */ -typedef struct { - uint32_t last_byte; - uint32_t vts_cat; - - video_attr_t vtsm_vobs_attr; - uint8_t zero_1; - uint8_t nr_of_vtsm_audio_streams; /* should be 0 or 1 */ - audio_attr_t vtsm_audio_attr; - audio_attr_t zero_2[7]; - uint8_t zero_3[16]; - uint8_t zero_4; - uint8_t nr_of_vtsm_subp_streams; /* should be 0 or 1 */ - subp_attr_t vtsm_subp_attr; - subp_attr_t zero_5[27]; - - uint8_t zero_6[2]; - - video_attr_t vtstt_vobs_video_attr; - uint8_t zero_7; - uint8_t nr_of_vtstt_audio_streams; - audio_attr_t vtstt_audio_attr[8]; - uint8_t zero_8[16]; - uint8_t zero_9; - uint8_t nr_of_vtstt_subp_streams; - subp_attr_t vtstt_subp_attr[32]; -} ATTRIBUTE_PACKED vts_attributes_t; -#define VTS_ATTRIBUTES_SIZE 542 -#define VTS_ATTRIBUTES_MIN_SIZE 356 - -/** - * Video Title Set Attribute Table. - */ -typedef struct { - uint16_t nr_of_vtss; - uint16_t zero_1; - uint32_t last_byte; - vts_attributes_t *vts; - uint32_t *vts_atrt_offsets; /* offsets table for each vts_attributes */ -} ATTRIBUTE_PACKED vts_atrt_t; -#define VTS_ATRT_SIZE 8 - -/** - * Text Data. (Incomplete) - */ -typedef struct { - uint32_t last_byte; /* offsets are relative here */ - uint16_t offsets[100]; /* == nr_of_srpts + 1 (first is disc title) */ -#if 0 - uint16_t unknown; /* 0x48 ?? 0x48 words (16bit) info following */ - uint16_t zero_1; - - uint8_t type_of_info; /* ?? 01 == disc, 02 == Title, 04 == Title part */ - uint8_t unknown1; - uint8_t unknown2; - uint8_t unknown3; - uint8_t unknown4; /* ?? allways 0x30 language?, text format? */ - uint8_t unknown5; - uint16_t offset; /* from first */ - - char text[12]; /* ended by 0x09 */ -#endif -} ATTRIBUTE_PACKED txtdt_t; - -/** - * Text Data Language Unit. (Incomplete) - */ -typedef struct { - uint16_t lang_code; - uint16_t unknown; /* 0x0001, title 1? disc 1? side 1? */ - uint32_t txtdt_start_byte; /* prt, rel start of vmg_txtdt_mgi */ - txtdt_t *txtdt; -} ATTRIBUTE_PACKED txtdt_lu_t; -#define TXTDT_LU_SIZE 8 - -/** - * Text Data Manager Information. (Incomplete) - */ -typedef struct { - char disc_name[14]; /* how many bytes?? */ - uint16_t nr_of_language_units; /* 32bit?? */ - uint32_t last_byte; - txtdt_lu_t *lu; -} ATTRIBUTE_PACKED txtdt_mgi_t; -#define TXTDT_MGI_SIZE 20 - - -/** - * VTS - * - * Structures relating to the Video Title Set (VTS). - */ - -/** - * Video Title Set Information Management Table. - */ -typedef struct { - char vts_identifier[12]; - uint32_t vts_last_sector; - uint8_t zero_1[12]; - uint32_t vtsi_last_sector; - uint8_t zero_2; - uint8_t specification_version; - uint32_t vts_category; - uint16_t zero_3; - uint16_t zero_4; - uint8_t zero_5; - uint8_t zero_6[19]; - uint16_t zero_7; - uint8_t zero_8[32]; - uint64_t zero_9; - uint8_t zero_10[24]; - uint32_t vtsi_last_byte; - uint32_t zero_11; - uint8_t zero_12[56]; - uint32_t vtsm_vobs; /* sector */ - uint32_t vtstt_vobs; /* sector */ - uint32_t vts_ptt_srpt; /* sector */ - uint32_t vts_pgcit; /* sector */ - uint32_t vtsm_pgci_ut; /* sector */ - uint32_t vts_tmapt; /* sector */ - 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 8 - - -/** - * 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 4 - -/** - * 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 8 - - -#if PRAGMA_PACK -#pragma pack() -#endif - - -/** - * The following structure defines an IFO file. The structure is divided into - * two parts, the VMGI, or Video Manager Information, which is read from the - * VIDEO_TS.[IFO,BUP] file, and the VTSI, or Video Title Set Information, which - * is read in from the VTS_XX_0.[IFO,BUP] files. - */ -typedef struct { - dvd_file_t *file; - - /* VMGI */ - vmgi_mat_t *vmgi_mat; - tt_srpt_t *tt_srpt; - pgc_t *first_play_pgc; - ptl_mait_t *ptl_mait; - vts_atrt_t *vts_atrt; - txtdt_mgi_t *txtdt_mgi; - - /* Common */ - pgci_ut_t *pgci_ut; - c_adt_t *menu_c_adt; - vobu_admap_t *menu_vobu_admap; - - /* VTSI */ - vtsi_mat_t *vtsi_mat; - vts_ptt_srpt_t *vts_ptt_srpt; - pgcit_t *vts_pgcit; - 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 -r f19fce15577b -r 9b1b740e3fc9 md5.c --- a/md5.c Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,417 +0,0 @@ -/* 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 , 1995. */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#if STDC_HEADERS || defined _LIBC -# include -# include -#else -# ifndef HAVE_MEMCPY -# define memcpy(d, s, n) bcopy ((s), (d), (n)) -# endif -#endif - -#include "md5.h" -/* #include "unlocked-io.h" */ - -#ifdef _LIBC -# include -# 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 -r f19fce15577b -r 9b1b740e3fc9 md5.h --- a/md5.h Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,161 +0,0 @@ -/* 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 - -#if defined HAVE_LIMITS_H || _LIBC -# include -#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 -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 ) 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 -r f19fce15577b -r 9b1b740e3fc9 nav_print.c --- a/nav_print.c Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,279 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002, 2003 Håkan Hjort - * - * Much of the contents in this file is based on VOBDUMP. - * - * VOBDUMP: a program for examining DVD .VOB filse - * - * Copyright 1998, 1999 Eric Smith - * - * 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 -#include - -#include "nav_types.h" -#include "nav_print.h" -#include "dvdread_internal.h" - -static void print_time(dvd_time_t *dtime) { - const char *rate; - CHECK_VALUE((dtime->hour>>4) < 0xa && (dtime->hour&0xf) < 0xa); - CHECK_VALUE((dtime->minute>>4) < 0x7 && (dtime->minute&0xf) < 0xa); - CHECK_VALUE((dtime->second>>4) < 0x7 && (dtime->second&0xf) < 0xa); - CHECK_VALUE((dtime->frame_u&0xf) < 0xa); - - printf("%02x:%02x:%02x.%02x", - dtime->hour, - dtime->minute, - dtime->second, - dtime->frame_u & 0x3f); - switch((dtime->frame_u & 0xc0) >> 6) { - case 1: - rate = "25.00"; - break; - case 3: - rate = "29.97"; - break; - default: - rate = "(please send a bug report)"; - break; - } - printf(" @ %s fps", rate); -} - - -static void navPrint_PCI_GI(pci_gi_t *pci_gi) { - int i; - - printf("pci_gi:\n"); - printf("nv_pck_lbn 0x%08x\n", pci_gi->nv_pck_lbn); - printf("vobu_cat 0x%04x\n", pci_gi->vobu_cat); - printf("vobu_uop_ctl 0x%08x\n", *(uint32_t*)&pci_gi->vobu_uop_ctl); - printf("vobu_s_ptm 0x%08x\n", pci_gi->vobu_s_ptm); - printf("vobu_e_ptm 0x%08x\n", pci_gi->vobu_e_ptm); - printf("vobu_se_e_ptm 0x%08x\n", pci_gi->vobu_se_e_ptm); - printf("e_eltm "); - print_time(&pci_gi->e_eltm); - printf("\n"); - - printf("vobu_isrc \""); - for(i = 0; i < 32; i++) { - char c = pci_gi->vobu_isrc[i]; - if((c >= ' ') && (c <= '~')) - printf("%c", c); - else - printf("."); - } - printf("\"\n"); -} - -static void navPrint_NSML_AGLI(nsml_agli_t *nsml_agli) { - int i, j = 0; - - for(i = 0; i < 9; i++) - j |= nsml_agli->nsml_agl_dsta[i]; - if(j == 0) - return; - - printf("nsml_agli:\n"); - for(i = 0; i < 9; i++) - if(nsml_agli->nsml_agl_dsta[i]) - printf("nsml_agl_c%d_dsta 0x%08x\n", i + 1, - nsml_agli->nsml_agl_dsta[i]); -} - -static void navPrint_HL_GI(hl_gi_t *hl_gi, int *btngr_ns, int *btn_ns) { - - if((hl_gi->hli_ss & 0x03) == 0) - return; - - printf("hl_gi:\n"); - printf("hli_ss 0x%01x\n", hl_gi->hli_ss & 0x03); - printf("hli_s_ptm 0x%08x\n", hl_gi->hli_s_ptm); - printf("hli_e_ptm 0x%08x\n", hl_gi->hli_e_ptm); - printf("btn_se_e_ptm 0x%08x\n", hl_gi->btn_se_e_ptm); - - *btngr_ns = hl_gi->btngr_ns; - printf("btngr_ns %d\n", hl_gi->btngr_ns); - printf("btngr%d_dsp_ty 0x%02x\n", 1, hl_gi->btngr1_dsp_ty); - printf("btngr%d_dsp_ty 0x%02x\n", 2, hl_gi->btngr2_dsp_ty); - printf("btngr%d_dsp_ty 0x%02x\n", 3, hl_gi->btngr3_dsp_ty); - - printf("btn_ofn %d\n", hl_gi->btn_ofn); - *btn_ns = hl_gi->btn_ns; - printf("btn_ns %d\n", hl_gi->btn_ns); - printf("nsl_btn_ns %d\n", hl_gi->nsl_btn_ns); - printf("fosl_btnn %d\n", hl_gi->fosl_btnn); - printf("foac_btnn %d\n", hl_gi->foac_btnn); -} - -static void navPrint_BTN_COLIT(btn_colit_t *btn_colit) { - int i, j; - - j = 0; - for(i = 0; i < 6; i++) - j |= btn_colit->btn_coli[i/2][i&1]; - if(j == 0) - return; - - printf("btn_colit:\n"); - for(i = 0; i < 3; i++) - for(j = 0; j < 2; j++) - printf("btn_cqoli %d %s_coli: %08x\n", - i, (j == 0) ? "sl" : "ac", - btn_colit->btn_coli[i][j]); -} - -static void navPrint_BTNIT(btni_t *btni_table, int btngr_ns, int btn_ns) { - int i, j; - - printf("btnit:\n"); - printf("btngr_ns: %i\n", btngr_ns); - printf("btn_ns: %i\n", btn_ns); - - if(btngr_ns == 0) - return; - - for(i = 0; i < btngr_ns; i++) { - for(j = 0; j < (36 / btngr_ns); j++) { - if(j < btn_ns) { - btni_t *btni = &btni_table[(36 / btngr_ns) * i + j]; - - printf("group %d btni %d: ", i+1, j+1); - printf("btn_coln %d, auto_action_mode %d\n", - btni->btn_coln, btni->auto_action_mode); - printf("coords (%d, %d) .. (%d, %d)\n", - btni->x_start, btni->y_start, btni->x_end, btni->y_end); - - printf("up %d, ", btni->up); - printf("down %d, ", btni->down); - printf("left %d, ", btni->left); - printf("right %d\n", btni->right); - - /* ifoPrint_COMMAND(&btni->cmd); */ - printf("\n"); - } - } - } -} - -static void navPrint_HLI(hli_t *hli) { - int btngr_ns = 0, btn_ns = 0; - - printf("hli:\n"); - navPrint_HL_GI(&hli->hl_gi, & btngr_ns, & btn_ns); - navPrint_BTN_COLIT(&hli->btn_colit); - navPrint_BTNIT(hli->btnit, btngr_ns, btn_ns); -} - -void navPrint_PCI(pci_t *pci) { - printf("pci packet:\n"); - navPrint_PCI_GI(&pci->pci_gi); - navPrint_NSML_AGLI(&pci->nsml_agli); - navPrint_HLI(&pci->hli); -} - -static void navPrint_DSI_GI(dsi_gi_t *dsi_gi) { - printf("dsi_gi:\n"); - printf("nv_pck_scr 0x%08x\n", dsi_gi->nv_pck_scr); - printf("nv_pck_lbn 0x%08x\n", dsi_gi->nv_pck_lbn ); - printf("vobu_ea 0x%08x\n", dsi_gi->vobu_ea); - printf("vobu_1stref_ea 0x%08x\n", dsi_gi->vobu_1stref_ea); - printf("vobu_2ndref_ea 0x%08x\n", dsi_gi->vobu_2ndref_ea); - printf("vobu_3rdref_ea 0x%08x\n", dsi_gi->vobu_3rdref_ea); - printf("vobu_vob_idn 0x%04x\n", dsi_gi->vobu_vob_idn); - printf("vobu_c_idn 0x%02x\n", dsi_gi->vobu_c_idn); - printf("c_eltm "); - print_time(&dsi_gi->c_eltm); - printf("\n"); -} - -static void navPrint_SML_PBI(sml_pbi_t *sml_pbi) { - printf("sml_pbi:\n"); - printf("category 0x%04x\n", sml_pbi->category); - if(sml_pbi->category & 0x8000) - printf("VOBU is in preunit\n"); - if(sml_pbi->category & 0x4000) - printf("VOBU is in ILVU\n"); - if(sml_pbi->category & 0x2000) - printf("VOBU at the beginning of ILVU\n"); - if(sml_pbi->category & 0x1000) - printf("VOBU at end of PREU of ILVU\n"); - - printf("ilvu_ea 0x%08x\n", sml_pbi->ilvu_ea); - printf("nxt_ilvu_sa 0x%08x\n", sml_pbi->ilvu_sa); - printf("nxt_ilvu_size 0x%04x\n", sml_pbi->size); - - printf("vob_v_s_s_ptm 0x%08x\n", sml_pbi->vob_v_s_s_ptm); - printf("vob_v_e_e_ptm 0x%08x\n", sml_pbi->vob_v_e_e_ptm); - - /* $$$ more code needed here */ -} - -static void navPrint_SML_AGLI(sml_agli_t *sml_agli) { - int i; - printf("sml_agli:\n"); - for(i = 0; i < 9; i++) { - printf("agl_c%d address: 0x%08x size 0x%04x\n", i, - sml_agli->data[i].address, sml_agli->data[i].size); - } -} - -static void navPrint_VOBU_SRI(vobu_sri_t *vobu_sri) { - int i; - int stime[19] = { 240, 120, 60, 20, 15, 14, 13, 12, 11, - 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; - printf("vobu_sri:\n"); - printf("Next VOBU with Video %08x\n", vobu_sri->next_video); - for(i = 0; i < 19; i++) { - printf("%3.1f %08x ", stime[i]/2.0, vobu_sri->fwda[i]); - } - printf("\n"); - printf("Next VOBU %08x\n", vobu_sri->next_vobu); - printf("--\n"); - printf("Prev VOBU %08x\n", vobu_sri->prev_vobu); - for(i = 0; i < 19; i++) { - printf("%3.1f %08x ", stime[18 - i]/2.0, vobu_sri->bwda[i]); - } - printf("\n"); - printf("Prev VOBU with Video %08x\n", vobu_sri->prev_video); -} - -static void navPrint_SYNCI(synci_t *synci) { - int i; - - printf("synci:\n"); - /* $$$ more code needed here */ - for(i = 0; i < 8; i++) - printf("%04x ", synci->a_synca[i]); - for(i = 0; i < 32; i++) - printf("%08x ", synci->sp_synca[i]); -} - -void navPrint_DSI(dsi_t *dsi) { - printf("dsi packet:\n"); - navPrint_DSI_GI(&dsi->dsi_gi); - navPrint_SML_PBI(&dsi->sml_pbi); - navPrint_SML_AGLI(&dsi->sml_agli); - navPrint_VOBU_SRI(&dsi->vobu_sri); - navPrint_SYNCI(&dsi->synci); -} - - diff -r f19fce15577b -r 9b1b740e3fc9 nav_print.h --- a/nav_print.h Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -#ifndef NAV_PRINT_H_INCLUDED -#define NAV_PRINT_H_INCLUDED - -/* - * Copyright (C) 2001, 2002 Billy Biggs , - * Håkan Hjort - * - * 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 -r f19fce15577b -r 9b1b740e3fc9 nav_read.c --- a/nav_read.c Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,357 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002, 2003 Håkan Hjort - * - * 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 -#include -#include -#include - -#include "bswap.h" -#include "nav_types.h" -#include "nav_read.h" -#include "dvdread_internal.h" - -typedef struct { - uint8_t *start; - uint32_t byte_position; - uint32_t bit_position; - uint8_t byte; -} getbits_state_t; - -static int32_t getbits_init(getbits_state_t *state, uint8_t *start) { - if ((state == NULL) || (start == NULL)) return -1; - state->start = start; - state->bit_position = 0; - state->byte_position = 0; - state->byte = start[0]; - return 0; -} - -/* Non-optimized getbits. */ -/* This can easily be optimized for particular platforms. */ -static uint32_t 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"); - assert(0); - } - - 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. - */ -static uint16_t 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. - */ -static uint32_t 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 - -void navRead_PCI(pci_t *pci, unsigned char *buffer) { - int32_t i, j; - getbits_state_t state; - if (getbits_init(&state, buffer)) assert(0); /* 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)) assert(0); /* 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 -r f19fce15577b -r 9b1b740e3fc9 nav_read.h --- a/nav_read.h Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -#ifndef NAV_READ_H_INCLUDED -#define NAV_READ_H_INCLUDED - -/* - * Copyright (C) 2000, 2001, 2002 Håkan Hjort . - * - * 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 -r f19fce15577b -r 9b1b740e3fc9 nav_types.h --- a/nav_types.h Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,273 +0,0 @@ -#ifndef NAV_TYPES_H_INCLUDED -#define NAV_TYPES_H_INCLUDED - -/* - * Copyright (C) 2000, 2001, 2002 Håkan Hjort - * - * 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 - * - * 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 -#include "ifo_types.h" /* only dvd_time_t, vm_cmd_t and user_ops_t */ - - -#undef ATTRIBUTE_PACKED -#undef PRAGMA_PACK_BEGIN -#undef PRAGMA_PACK_END - -#if defined(__GNUC__) -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) -#define ATTRIBUTE_PACKED __attribute__ ((packed)) -#define PRAGMA_PACK 0 -#endif -#endif - -#if !defined(ATTRIBUTE_PACKED) -#define ATTRIBUTE_PACKED -#define PRAGMA_PACK 1 -#endif - - -/* The length including the substream id byte. */ -#define PCI_BYTES 0x3d4 -#define DSI_BYTES 0x3fa - -#define PS2_PCI_SUBSTREAM_ID 0x00 -#define PS2_DSI_SUBSTREAM_ID 0x01 - -/* Remove this */ -#define DSI_START_BYTE 1031 - - -#if PRAGMA_PACK -#pragma pack(1) -#endif - - -/** - * PCI General Information - */ -typedef struct { - uint32_t nv_pck_lbn; /**< 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 -r f19fce15577b -r 9b1b740e3fc9 read_cache.c --- a/read_cache.c Wed Jan 07 19:35:12 2004 +0000 +++ b/read_cache.c Sun Jan 11 21:43:13 2004 +0000 @@ -20,6 +20,11 @@ * $Id$ * */ +/* + * 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" @@ -31,42 +36,6 @@ #include #include - -#define DVDNAV_PROFILE - - -/* Read-ahead cache structure. */ -#if _MULTITHREAD_ - -/* For the multithreaded cache, the cache is a ring buffer + writing - * thread that continuously reads data into the buffer until it is - * full or the 'upper-bound' has been reached. - */ - -#define CACHE_BUFFER_SIZE 2048 /* Cache this number of blocks at a time */ - -struct read_cache_s { - pthread_mutex_t cache_lock; - pthread_t read_thread; - - /* Buffer */ - uint8_t *buffer; - - /* Size of buffer */ - int32_t size; - /* block offset from sector start of buffer 'head' */ - uint32_t pos; - /* block offset from sector start of read point */ - uint32_t read_point; - /* block offset from buffer start to ring-boundary */ - uint32_t start; - - /* Bit of strange cross-linking going on here :) -- Gotta love C :) */ - dvdnav_t *dvd_self; -}; - -#else - #define READ_CACHE_CHUNKS 10 /* all cache chunks must be memory aligned to allow use of raw devices */ @@ -98,7 +67,6 @@ /* Bit of strange cross-linking going on here :) -- Gotta love C :) */ dvdnav_t *dvd_self; }; -#endif /* #define READ_CACHE_TRACE 0 @@ -122,241 +90,6 @@ # endif #endif -#if _MULTITHREAD_ - -void * read_cache_read_thread (void * this_gen) { - int cont = 1; - int32_t diff, start; - uint32_t pos, size, startp, endp; - uint32_t s,c; - uint8_t *at; - read_cache_t *self = (read_cache_t*)this_gen; - - while(cont) { - - pthread_mutex_lock(&self->cache_lock); - - if(self->size >= 0) { - diff = self->read_point - self->pos; - if(diff >= self->size/2) { - dprintf("(II) Read thread -- "); - - startp = (self->start) % CACHE_BUFFER_SIZE; - endp = abs((self->start + diff - 1) % CACHE_BUFFER_SIZE); - dprintf("startp = %i, endp = %i -- ",startp, endp); - - pos = self->pos + diff; - size = self->size - diff; - start = (self->start + diff) % CACHE_BUFFER_SIZE; - - /* Fill remainder of buffer */ - - if(startp > endp) { - s = pos + size; c = CACHE_BUFFER_SIZE - startp; - at = self->buffer + (startp * DVD_VIDEO_LB_LEN); - if(c > 0) { - dprintf("(1) Reading from %i to %i to %i ", s, s+c-1, startp); - pthread_mutex_unlock(&self->cache_lock); - DVDReadBlocks(self->dvd_self->file, s,c, at); - pthread_mutex_lock(&self->cache_lock); - } - - s = pos + size + c; c = CACHE_BUFFER_SIZE - size - c; - at = self->buffer; - if(c > 0) { - dprintf("(2) Reading from %i to %i to %i ", s, s+c-1, 0); - pthread_mutex_unlock(&self->cache_lock); - DVDReadBlocks(self->dvd_self->file, s,c, at); - pthread_mutex_lock(&self->cache_lock); - } - } else { - s = pos + size; c = CACHE_BUFFER_SIZE - size; - at = self->buffer + (startp * DVD_VIDEO_LB_LEN); - if(c > 0) { - dprintf("(3) Reading from %i to %i to %i ", s, s+c-1, startp); - pthread_mutex_unlock(&self->cache_lock); - DVDReadBlocks(self->dvd_self->file, s,c, at); - pthread_mutex_lock(&self->cache_lock); - } - } - - dprintf("\n"); - - self->pos = pos; - self->start = start; self->size = CACHE_BUFFER_SIZE; - } - } - - pthread_mutex_unlock(&self->cache_lock); - cont = (self->buffer != NULL); - usleep(100); - } - - return NULL; -} - -read_cache_t *dvdnav_read_cache_new(dvdnav_t* dvd_self) { - read_cache_t *me; - - me = (read_cache_t*)malloc(sizeof(struct read_cache_s)); - - if(me) { - int err; - - me->dvd_self = dvd_self; - me->buffer = (uint8_t*)malloc(CACHE_BUFFER_SIZE * DVD_VIDEO_LB_LEN); - me->start = 0; - me->pos = 0; - me->read_point = 0; - me->size = -1; - - /* Initialise the mutex */ - pthread_mutex_init(&me->cache_lock, NULL); - - if ((err = pthread_create (&me->read_thread, - NULL, read_cache_read_thread, me)) != 0) { - dprintf("read_cache: can't create new thread (%s)\n",strerror(err)); - } - } - - return me; -} - -void dvdnav_read_cache_free(read_cache_t* self) { - dvdnav_t *tmp; - - pthread_mutex_lock(&self->cache_lock); - - if(self->buffer) { - free(self->buffer); - self->buffer = NULL; - self->size = -2; - } - - pthread_mutex_unlock(&self->cache_lock); - - pthread_join(self->read_thread, NULL); - - pthread_mutex_destroy(&self->cache_lock); - - tmp = self->dvd_self; - free(self); - - /* We free the main structure, too, because we have no buffers out there. */ - free(tmp); -} - -/* This function MUST be called whenever self->file changes. */ -void dvdnav_read_cache_clear(read_cache_t *self) { - if(!self) - return; - - pthread_mutex_lock(&self->cache_lock); - self->size = -1; - self->start = 0; - self->pos = 0; - self->read_point = 0; - pthread_mutex_unlock(&self->cache_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) { - if(!self) - return; - - if(!self->dvd_self->use_read_ahead) { - return; - } - - pthread_mutex_lock(&self->cache_lock); - dprintf("Requested pre-cache (%i -> +%i) : current state pos=%i, size=%i.\n", - sector, block_count, self->pos, self->size); - - /* Are the contents of the buffer in any way relevant? */ - if((self->size > 0) && (sector >= self->pos) && (sector <= self->pos+self->size)) { - dprintf("Contents relevant ... adjusting\n"); - self->read_point = sector; - } else { - /* Flush the cache as its not much use */ - dprintf("Contents irrelevent... flushing\n"); - self->size = 0; - self->start = 0; - self->pos = sector; - self->read_point = sector; - } - - pthread_mutex_unlock(&self->cache_lock); -} - -/* This function will do the cache read */ -int dvdnav_read_cache_block( read_cache_t *self, int sector, size_t block_count, uint8_t **buf) { - int result, diff; - - if(!self) - return 0; - - pthread_mutex_lock(&self->cache_lock); - dprintf("Read from %i -> +%i (buffer pos=%i, read_point=%i, size=%i)... ", sector, block_count, - self->pos, self->read_point, self->size); - if((self->size > 0) && (sector >= self->read_point) && - (sector + block_count <= self->pos + self->size)) { - /* Hit */ - - /* Drop any skipped blocks */ - diff = sector - self->read_point; - if(diff > 0) - self->read_point += diff; - - diff = self->read_point - self->pos; - - if(((self->start + diff) % CACHE_BUFFER_SIZE) + block_count <= CACHE_BUFFER_SIZE) { - dprintf("************** Single read\n"); - memcpy(*buf, self->buffer + (((self->start + diff) % CACHE_BUFFER_SIZE) * DVD_VIDEO_LB_LEN), - block_count * DVD_VIDEO_LB_LEN); - self->read_point += block_count; - pthread_mutex_unlock(&self->cache_lock); - - return (int)block_count; - } else { - int32_t boundary = CACHE_BUFFER_SIZE - self->start; - - dprintf("************** Multiple read\n"); - memcpy(*buf, self->buffer + (((self->start + diff) % CACHE_BUFFER_SIZE) * DVD_VIDEO_LB_LEN), - boundary * DVD_VIDEO_LB_LEN); - memcpy(*buf + (boundary * DVD_VIDEO_LB_LEN), self->buffer, - (block_count-boundary) * DVD_VIDEO_LB_LEN); - self->read_point += block_count; - pthread_mutex_unlock(&self->cache_lock); - - return (int)block_count; - } - } else { - /* Miss */ - - fprintf(MSG_OUT, "libdvdnav: DVD read cache miss! (not bad but a performance hit) sector=%d\n", sector); - result = DVDReadBlocks( self->dvd_self->file, sector, block_count, *buf); - self->read_point = sector+block_count; - if(self->read_point > self->pos + self->size) { - /* Flush the cache as its not much use */ - dprintf("Contents irrelevent... flushing\n"); - self->size = 0; - self->start = 0; - self->pos = sector+block_count; - } - pthread_mutex_unlock(&self->cache_lock); - usleep(300); - return result; - } - - /* Should never get here */ - return 0; -} - -dvdnav_status_t dvdnav_free_cache_block(dvdnav_t *self, unsigned char *buf) { - return DVDNAV_STATUS_OK; -} - -#else read_cache_t *dvdnav_read_cache_new(dvdnav_t* dvd_self) { read_cache_t *self; @@ -520,7 +253,8 @@ /* Increment read-ahead size if sector follows the last sector */ if (sector == (self->last_sector + 1)) { - self->read_ahead_incr++; + 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; @@ -539,34 +273,33 @@ chunk->usage_count++; pthread_mutex_unlock(&self->lock); - /* Read blocks if needed */ - if (sector >= (chunk->cache_start_sector + chunk->cache_read_count)) { + dprintf("libdvdnav: sector=%d, start_sector=%d, last_sector=%d\n", sector, chunk->cache_start_sector, chunk->cache_start_sector + chunk->cache_block_count); - 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; + } - /* 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 = self->read_ahead_size + incr; - } - self->read_ahead_incr = 0; + /* 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); - /* 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; - } - 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; @@ -611,5 +344,3 @@ return DVDNAV_STATUS_OK; } - -#endif diff -r f19fce15577b -r 9b1b740e3fc9 vm.c --- a/vm.c Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1844 +0,0 @@ -/* - * Copyright (C) 2000, 2001 Håkan Hjort - * Copyright (C) 2001 Rich Wareham - * - * 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$ - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ifo_types.h" -#include "ifo_read.h" - -#include "dvdnav_internal.h" - -#ifdef _MSC_VER -#include /* read() */ -#define lseek64 lseek -#endif /* _MSC_VER */ - -#ifdef __CYGWIN__ -# define off64_t off_t -# define lseek64 lseek -#endif - -/* -#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) { - int fd, i; -#if !defined(__FreeBSD__) && !defined(WIN32) - off64_t off; -#else - off_t off; -#endif - uint8_t data[DVD_VIDEO_LB_LEN]; - - /* Read DVD name */ - fd=open(device, O_RDONLY); - if (fd > 0) { - off = lseek64( fd, 32 * (int64_t) DVD_VIDEO_LB_LEN, SEEK_SET ); - if( off == ( 32 * (int64_t) DVD_VIDEO_LB_LEN ) ) { - off = read( fd, data, DVD_VIDEO_LB_LEN ); - close(fd); - if (off == ( (int64_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, &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 void ifoOpenNewVTSI(vm_t *vm, dvd_reader_t *dvd, int vtsN) { - if((vm->state).vtsN == vtsN) { - return; /* 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 - CRASHING!!!\n"); - assert(0); - } - if(!ifoRead_VTS_PTT_SRPT(vm->vtsi)) { - fprintf(MSG_OUT, "libdvdnav: ifoRead_VTS_PTT_SRPT failed - CRASHING!!!\n"); - assert(0); - } - if(!ifoRead_PGCIT(vm->vtsi)) { - fprintf(MSG_OUT, "libdvdnav: ifoRead_PGCIT failed - CRASHING!!!\n"); - assert(0); - } - if(!ifoRead_PGCI_UT(vm->vtsi)) { - fprintf(MSG_OUT, "libdvdnav: ifoRead_PGCI_UT failed - CRASHING!!!\n"); - assert(0); - } - if(!ifoRead_VOBU_ADMAP(vm->vtsi)) { - fprintf(MSG_OUT, "libdvdnav: ifoRead_VOBU_ADMAP vtsi failed - CRASHING\n"); - assert(0); - } - if(!ifoRead_TITLE_VOBU_ADMAP(vm->vtsi)) { - fprintf(MSG_OUT, "libdvdnav: ifoRead_TITLE_VOBU_ADMAP vtsi failed - CRASHING\n"); - assert(0); - } - (vm->state).vtsN = vtsN; -} - - -/* 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 */ - -void vm_start(vm_t *vm) { - /* Set pgc to FP (First Play) pgc */ - set_FP_PGC(vm); - process_command(vm, play_PGC(vm)); -} - -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: faild to open/read the DVD\n"); - return 0; - } - dvd_read_name(vm->dvd_name, dvdroot); - vm->map = remap_loadmap(vm->dvd_name); - vm->vmgi = ifoOpenVMGI(vm->dvd); - if(!vm->vmgi) { - fprintf(MSG_OUT, "libdvdnav: vm: faild 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; - ifoOpenNewVTSI(target, target->dvd, vtsN); - - /* 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 (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) { - 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 but directly play the PG. */ - /* process_command(vm, play_PGC_PG(vm, (vm->state).pgN)); */ - process_command(vm, play_PG(vm)); - 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); - *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; - } -} - -#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; - } -} -#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; - } - assert(0); -} - -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; - } - assert(0); -} - -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; - } - assert(0); -} - - -/* 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); - 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); - 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)) - assert(0); - link_values = play_PGC(vm); - 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)) - assert(0); - link_values = play_PGC(vm); - 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)) - assert(0); - link_values = play_PGC(vm); - 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; - ifoOpenNewVTSI(vm, vm->dvd, (vm->state).rsm_vtsN); - 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 righ value in set_PGN() below */ - (vm->state).cellN = (vm->state).rsm_cellN; - link_values.command = PlayThis; - link_values.data1 = (vm->state).rsm_blockN; - 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)) - assert(0); - link_values = play_PGC(vm); - 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 */ - /* FIXME: This goes badly wrong for some DVDs. */ - /* FIXME: Keep in touch with ogle people regarding what to do here */ - /* ifoOpenNewVTSI:data1 */ - /* VTS_TTN_REG:data2 */ - /* get_MENU:data3 */ -#ifdef TRACE - fprintf(MSG_OUT, "libdvdnav: BUG TRACKING *******************************************************************\n"); - fprintf(MSG_OUT, "libdvdnav: data1=%u data2=%u data3=%u\n", - link_values.data1, - link_values.data2, - link_values.data3); - fprintf(MSG_OUT, "libdvdnav: *******************************************************************\n"); -#endif - - if(link_values.data1 != 0) { - assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */ - (vm->state).domain = VTSM_DOMAIN; - ifoOpenNewVTSI(vm, vm->dvd, link_values.data1); /* Also sets (vm->state).vtsN */ - } 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; - 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) - ifoOpenNewVTSI(vm, vm->dvd, vtsN); /* Also sets (vm->state).vtsN */ - - 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; - (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; - - switch ((vm->state).domain) { - case VTS_DOMAIN: - pgcit = vm->vtsi->vts_pgcit; - break; - case VTSM_DOMAIN: - 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: - pgcit = NULL; /* Should never hapen */ - fprintf(MSG_OUT, "libdvdnav: get_PGCIT: Unknown domain:%d\n", - (vm->state).domain); - assert(0); - break; - } - - return pgcit; -} - - -/* 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 -r f19fce15577b -r 9b1b740e3fc9 vm.h --- a/vm.h Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2000, 2001 Håkan Hjort - * Copyright (C) 2001 Rich Wareham - * - * 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$ - * - */ - -#ifndef VM_H_INCLUDED -#define VM_H_INCLUDED - -#include "remap.h" -#include "dvdnav_internal.h" - -/* 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 */ -void 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); -#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); -#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); - -#ifdef TRACE -/* Debug */ -void vm_position_print(vm_t *vm, vm_position_t *position); -#endif - - -#endif /* VM_HV_INCLUDED */ diff -r f19fce15577b -r 9b1b740e3fc9 vm/.cvsignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/.cvsignore Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,6 @@ +Makefile +Makefile.in +.libs +.deps +*.lo +*.la diff -r f19fce15577b -r 9b1b740e3fc9 vm/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/Makefile.am Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,16 @@ +include $(top_srcdir)/misc/Makefile.common + +includedir = ${prefix}/include/dvdnav + +AM_CPPFLAGS = -DDVDNAV_COMPILE $(THREAD_CFLAGS) \ + -I$(top_srcdir)/src -I$(top_srcdir)/src/dvdread + +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 -r f19fce15577b -r 9b1b740e3fc9 vm/decoder.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/decoder.c Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,779 @@ +/* + * 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$ + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include /* For memset */ +#include "ifo_types.h" /* vm_cmd_t */ +#include + +#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"); + assert(0); + } + /* 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(¤t_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(¤t_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) { + 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"); + assert(0); + } + 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)); + assert(0); + } + /* 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, " %08llx", (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 -r f19fce15577b -r 9b1b740e3fc9 vm/decoder.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/decoder.h Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,118 @@ +/* + * 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$ + * + */ + +#ifndef DECODER_H_INCLUDED +#define DECODER_H_INCLUDED + +#include +#include + +#include "ifo_types.h" /* vm_cmd_t */ +#include "dvdnav_internal.h" + +/* 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 -r f19fce15577b -r 9b1b740e3fc9 vm/vm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/vm.c Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,1848 @@ +/* + * Copyright (C) 2000, 2001 Håkan Hjort + * Copyright (C) 2001 Rich Wareham + * + * 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$ + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ifo_types.h" +#include "ifo_read.h" + +#include "dvdnav_internal.h" + +#ifdef _MSC_VER +#include /* read() */ +#define lseek64 lseek +#endif /* _MSC_VER */ + +#ifdef __CYGWIN__ +# define off64_t off_t +# define lseek64 lseek +#endif + +/* +#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) { + int fd, i; +#if !defined(__FreeBSD__) && !defined(WIN32) + off64_t off; +#else + off_t off; +#endif + uint8_t data[DVD_VIDEO_LB_LEN]; + + /* Read DVD name */ + fd=open(device, O_RDONLY); + if (fd > 0) { + off = lseek64( fd, 32 * (int64_t) DVD_VIDEO_LB_LEN, SEEK_SET ); + if( off == ( 32 * (int64_t) DVD_VIDEO_LB_LEN ) ) { + off = read( fd, data, DVD_VIDEO_LB_LEN ); + close(fd); + if (off == ( (int64_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, &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 void ifoOpenNewVTSI(vm_t *vm, dvd_reader_t *dvd, int vtsN) { + if((vm->state).vtsN == vtsN) { + return; /* 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 - CRASHING!!!\n"); + assert(0); + } + if(!ifoRead_VTS_PTT_SRPT(vm->vtsi)) { + fprintf(MSG_OUT, "libdvdnav: ifoRead_VTS_PTT_SRPT failed - CRASHING!!!\n"); + assert(0); + } + if(!ifoRead_PGCIT(vm->vtsi)) { + fprintf(MSG_OUT, "libdvdnav: ifoRead_PGCIT failed - CRASHING!!!\n"); + assert(0); + } + if(!ifoRead_PGCI_UT(vm->vtsi)) { + fprintf(MSG_OUT, "libdvdnav: ifoRead_PGCI_UT failed - CRASHING!!!\n"); + assert(0); + } + if(!ifoRead_VOBU_ADMAP(vm->vtsi)) { + fprintf(MSG_OUT, "libdvdnav: ifoRead_VOBU_ADMAP vtsi failed - CRASHING\n"); + assert(0); + } + if(!ifoRead_TITLE_VOBU_ADMAP(vm->vtsi)) { + fprintf(MSG_OUT, "libdvdnav: ifoRead_TITLE_VOBU_ADMAP vtsi failed - CRASHING\n"); + assert(0); + } + (vm->state).vtsN = vtsN; +} + + +/* 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 */ + +void vm_start(vm_t *vm) { + /* Set pgc to FP (First Play) pgc */ + set_FP_PGC(vm); + process_command(vm, play_PGC(vm)); +} + +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: faild to open/read the DVD\n"); + return 0; + } + dvd_read_name(vm->dvd_name, dvdroot); + vm->map = remap_loadmap(vm->dvd_name); + vm->vmgi = ifoOpenVMGI(vm->dvd); + if(!vm->vmgi) { + fprintf(MSG_OUT, "libdvdnav: vm: faild 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; + ifoOpenNewVTSI(target, target->dvd, vtsN); + + /* 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 (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); + *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; + } +} + +#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; + } +} +#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; + } + assert(0); +} + +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; + } + assert(0); +} + +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; + } + assert(0); +} + + +/* 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); + 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); + 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)) + assert(0); + link_values = play_PGC(vm); + 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)) + assert(0); + link_values = play_PGC(vm); + 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)) + assert(0); + link_values = play_PGC(vm); + 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; + ifoOpenNewVTSI(vm, vm->dvd, (vm->state).rsm_vtsN); + 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 righ value in set_PGN() below */ + (vm->state).cellN = (vm->state).rsm_cellN; + link_values.command = PlayThis; + link_values.data1 = (vm->state).rsm_blockN; + 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)) + assert(0); + link_values = play_PGC(vm); + 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; + ifoOpenNewVTSI(vm, vm->dvd, link_values.data1); /* Also sets (vm->state).vtsN */ + } 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; + 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) + ifoOpenNewVTSI(vm, vm->dvd, vtsN); /* Also sets (vm->state).vtsN */ + + 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; + (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; + + switch ((vm->state).domain) { + case VTS_DOMAIN: + pgcit = vm->vtsi->vts_pgcit; + break; + case VTSM_DOMAIN: + 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: + pgcit = NULL; /* Should never hapen */ + fprintf(MSG_OUT, "libdvdnav: get_PGCIT: Unknown domain:%d\n", + (vm->state).domain); + assert(0); + break; + } + + return pgcit; +} + + +/* 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 -r f19fce15577b -r 9b1b740e3fc9 vm/vm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/vm.h Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2000, 2001 Håkan Hjort + * Copyright (C) 2001 Rich Wareham + * + * 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$ + * + */ + +#ifndef VM_H_INCLUDED +#define VM_H_INCLUDED + +#include "remap.h" +#include "dvdnav_internal.h" + +/* 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 */ +void 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); +#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); +#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); + +#ifdef TRACE +/* Debug */ +void vm_position_print(vm_t *vm, vm_position_t *position); +#endif + + +#endif /* VM_HV_INCLUDED */ diff -r f19fce15577b -r 9b1b740e3fc9 vm/vmcmd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/vmcmd.c Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,539 @@ +/* + * 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$ + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#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[] = { + NULL, "&", "==", "!=", ">=", ">", "<=", "<" +}; +static const char *set_op_table[] = { + NULL, "=", "<->", "+=", "-=", "*=", "/=", "%=", "rnd", "&=", "|=", "^=" +}; + +static const char *link_table[] = { + "LinkNoLink", "LinkTopC", "LinkNextC", "LinkPrevC", + NULL, "LinkTopPG", "LinkNextPG", "LinkPrevPG", + NULL, "LinkTopPGC", "LinkNextPGC", "LinkPrevPGC", + "LinkGoUpPGC", "LinkTailPGC", NULL, NULL, + "RSM" +}; + +static const char *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[] = { + NULL, + "ASTN", + "SPSTN", + "AGLN", + "TTN", + "VTS_TTN", + "TT_PGCN", + "PTTN", + "HL_BTNN", + "NVTMR", + "NV_PGCN", + NULL, + "CC_PLT", + "PLT", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +static void print_system_reg(uint16_t reg) { + if(reg < sizeof(system_reg_abbr_table) / sizeof(char *)) + 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(char *) && cmp_op_table[op] != NULL) + 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(char *) && set_op_table[op] != NULL) + 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(char *) && link_table[linkop] != NULL) + 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, " %08llx", (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 -r f19fce15577b -r 9b1b740e3fc9 vm/vmcmd.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/vmcmd.h Sun Jan 11 21:43:13 2004 +0000 @@ -0,0 +1,33 @@ +/* + * 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$ + * + */ + +#ifndef VMCMD_H_INCLUDED +#define VMCMD_H_INCLUDED + +#include + +void vm_print_mnemonic(vm_cmd_t *command); +void vm_print_cmd(int row, vm_cmd_t *command); + +#endif /* VMCMD_H_INCLUDED */ diff -r f19fce15577b -r 9b1b740e3fc9 vmcmd.c --- a/vmcmd.c Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,539 +0,0 @@ -/* - * 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$ - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include - -#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[] = { - NULL, "&", "==", "!=", ">=", ">", "<=", "<" -}; -static const char *set_op_table[] = { - NULL, "=", "<->", "+=", "-=", "*=", "/=", "%=", "rnd", "&=", "|=", "^=" -}; - -static const char *link_table[] = { - "LinkNoLink", "LinkTopC", "LinkNextC", "LinkPrevC", - NULL, "LinkTopPG", "LinkNextPG", "LinkPrevPG", - NULL, "LinkTopPGC", "LinkNextPGC", "LinkPrevPGC", - "LinkGoUpPGC", "LinkTailPGC", NULL, NULL, - "RSM" -}; - -static const char *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[] = { - NULL, - "ASTN", - "SPSTN", - "AGLN", - "TTN", - "VTS_TTN", - "TT_PGCN", - "PTTN", - "HL_BTNN", - "NVTMR", - "NV_PGCN", - NULL, - "CC_PLT", - "PLT", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, -}; - -static void print_system_reg(uint16_t reg) { - if(reg < sizeof(system_reg_abbr_table) / sizeof(char *)) - 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(char *) && cmp_op_table[op] != NULL) - 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(char *) && set_op_table[op] != NULL) - 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(char *) && link_table[linkop] != NULL) - 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, " %08llx", (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 -r f19fce15577b -r 9b1b740e3fc9 vmcmd.h --- a/vmcmd.h Wed Jan 07 19:35:12 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* - * 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$ - * - */ - -#ifndef VMCMD_H_INCLUDED -#define VMCMD_H_INCLUDED - -#include - -void vm_print_mnemonic(vm_cmd_t *command); -void vm_print_cmd(int row, vm_cmd_t *command); - -#endif /* VMCMD_H_INCLUDED */