📄 decoder.c
字号:
/* * Copyright (C) 2000, 2001 Martin Norbäck, Håkan Hjort * 2002-2004 the dvdnav project * * This file is part of libdvdnav, a DVD navigation library. It is modified * from a file originally part of the Ogle DVD player. * * libdvdnav is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * libdvdnav is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * $Id: decoder.c,v 1.14 2004/03/16 11:43:38 mroi Exp $ * */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <stdio.h>#include <stdlib.h>#include <inttypes.h>#include <string.h> /* For memset */#include "ifo_types.h" /* vm_cmd_t */#include "dvdnav_internal.h"uint32_t vm_getbits(command_t *command, int32_t start, int32_t count) { uint64_t result = 0; uint64_t bit_mask = 0; uint64_t examining = 0; int32_t bits; if (count == 0) return 0; if ( ((start - count) < -1) || (count > 32) || (start > 63) || (count < 0) || (start < 0) ) { fprintf(MSG_OUT, "libdvdnav: Bad call to vm_getbits. Parameter out of range\n"); abort(); } /* all ones, please */ bit_mask = ~bit_mask; bit_mask >>= 63 - start; bits = start + 1 - count; examining = ((bit_mask >> bits) << bits ); command->examined |= examining; result = (command->instruction & bit_mask) >> bits; return (uint32_t) result;}static uint16_t get_GPRM(registers_t* registers, uint8_t reg) { if (registers->GPRM_mode[reg] & 0x01) { struct timeval current_time, time_offset; uint16_t result; /* Counter mode */ /* fprintf(MSG_OUT, "libdvdnav: Getting counter %d\n",reg);*/ gettimeofday(¤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); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -