📄 ifo_read.c
字号:
/* * Copyright (C) 2000, 2001, 2002, 2003 * Bj鰎n Englund <d4bjorn@dtek.chalmers.se>, * H錵an Hjort <d95hjort@dtek.chalmers.se> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "config.h"#include <stdio.h>#include <stdlib.h>#include <inttypes.h>#include <string.h>#include "bswap.h"#include "ifo_types.h"#include "ifo_read.h"#include "dvd_reader.h"#include "dvdread_internal.h"#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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -