📄 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 <string.h>
#include "inttypes.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"); \
}
#define PRINT_DATA(nm, arg, sz) \
{ \
unsigned int i_CZ; \
fprintf(stderr, "PRINT %s %s:%i\n", nm, __FILE__, __LINE__ ); \
for(i_CZ = 0; i_CZ < sz; 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.openVTSI: 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))) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -