aboutsummaryrefslogtreecommitdiff
path: root/lib/libdvd/libdvdread/src/ifo_read.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libdvd/libdvdread/src/ifo_read.c')
-rw-r--r--lib/libdvd/libdvdread/src/ifo_read.c164
1 files changed, 107 insertions, 57 deletions
diff --git a/lib/libdvd/libdvdread/src/ifo_read.c b/lib/libdvd/libdvdread/src/ifo_read.c
index 1bf1d6702d..76c9fafcb9 100644
--- a/lib/libdvd/libdvdread/src/ifo_read.c
+++ b/lib/libdvd/libdvdread/src/ifo_read.c
@@ -87,9 +87,9 @@ static int ifoRead_VOBU_ADMAP_internal(ifo_handle_t *ifofile,
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(pgc_t **pgc);
static void ifoFree_PGC_COMMAND_TBL(pgc_command_tbl_t *cmd_tbl);
-static void ifoFree_PGCIT_internal(pgcit_t *pgcit);
+static void ifoFree_PGCIT_internal(pgcit_t **pgcit);
static inline int DVDFileSeekForce_( dvd_file_t *dvd_file, uint32_t offset, int force_size ) {
return (DVDFileSeekForce(dvd_file, (int)offset, force_size) == (int)offset);
@@ -568,6 +568,8 @@ static int ifoRead_VMG(ifo_handle_t *ifofile) {
CHECK_ZERO(vmgi_mat->zero_1);
CHECK_ZERO(vmgi_mat->zero_2);
+ /* DVDs created by VDR-to-DVD device LG RC590M violate the following check with
+ * vmgi_mat->zero_3 = 0x00000000010000000000000000000000000000. */
CHECK_ZERO(vmgi_mat->zero_3);
CHECK_ZERO(vmgi_mat->zero_4);
CHECK_ZERO(vmgi_mat->zero_5);
@@ -923,7 +925,6 @@ static int ifoRead_PGC(ifo_handle_t *ifofile, pgc_t *pgc, unsigned int offset) {
if(!ifoRead_PGC_COMMAND_TBL(ifofile, pgc->command_tbl,
offset + pgc->command_tbl_offset)) {
- free(pgc->command_tbl);
return 0;
}
} else {
@@ -933,13 +934,10 @@ static int ifoRead_PGC(ifo_handle_t *ifofile, pgc_t *pgc, unsigned int offset) {
if(pgc->program_map_offset != 0 && pgc->nr_of_programs>0) {
pgc->program_map = malloc(pgc->nr_of_programs * sizeof(pgc_program_map_t));
if(!pgc->program_map) {
- ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
return 0;
}
if(!ifoRead_PGC_PROGRAM_MAP(ifofile, pgc->program_map,pgc->nr_of_programs,
offset + pgc->program_map_offset)) {
- ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
- free(pgc->program_map);
return 0;
}
} else {
@@ -949,18 +947,11 @@ static int ifoRead_PGC(ifo_handle_t *ifofile, pgc_t *pgc, unsigned int offset) {
if(pgc->cell_playback_offset != 0 && pgc->nr_of_cells>0) {
pgc->cell_playback = malloc(pgc->nr_of_cells * sizeof(cell_playback_t));
if(!pgc->cell_playback) {
- ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
- if(pgc->program_map)
- free(pgc->program_map);
return 0;
}
if(!ifoRead_CELL_PLAYBACK_TBL(ifofile, pgc->cell_playback,
pgc->nr_of_cells,
offset + pgc->cell_playback_offset)) {
- ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
- if(pgc->program_map)
- free(pgc->program_map);
- free(pgc->cell_playback);
return 0;
}
} else {
@@ -970,13 +961,11 @@ static int ifoRead_PGC(ifo_handle_t *ifofile, pgc_t *pgc, unsigned int offset) {
if(pgc->cell_position_offset != 0 && pgc->nr_of_cells>0) {
pgc->cell_position = malloc(pgc->nr_of_cells * sizeof(cell_position_t));
if(!pgc->cell_position) {
- ifoFree_PGC(pgc);
return 0;
}
if(!ifoRead_CELL_POSITION_TBL(ifofile, pgc->cell_position,
pgc->nr_of_cells,
offset + pgc->cell_position_offset)) {
- ifoFree_PGC(pgc);
return 0;
}
} else {
@@ -999,29 +988,33 @@ int ifoRead_FP_PGC(ifo_handle_t *ifofile) {
if(ifofile->vmgi_mat->first_play_pgc == 0)
return 1;
- ifofile->first_play_pgc = (pgc_t *)malloc(sizeof(pgc_t));
+ ifofile->first_play_pgc = (pgc_t *)calloc(1, sizeof(pgc_t));
if(!ifofile->first_play_pgc)
return 0;
+ ifofile->first_play_pgc->ref_count = 1;
if(!ifoRead_PGC(ifofile, ifofile->first_play_pgc,
ifofile->vmgi_mat->first_play_pgc)) {
- free(ifofile->first_play_pgc);
- ifofile->first_play_pgc = 0;
+ ifoFree_PGC(&ifofile->first_play_pgc);
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);
+static void ifoFree_PGC(pgc_t **pgc) {
+ if(pgc && *pgc && (--(*pgc)->ref_count) <= 0) {
+ 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);
+ free(*pgc);
+ }
+ if (pgc) {
+ *pgc = NULL;
}
}
@@ -1030,9 +1023,7 @@ void ifoFree_FP_PGC(ifo_handle_t *ifofile) {
return;
if(ifofile->first_play_pgc) {
- ifoFree_PGC(ifofile->first_play_pgc);
- free(ifofile->first_play_pgc);
- ifofile->first_play_pgc = 0;
+ ifoFree_PGC(&ifofile->first_play_pgc);
}
}
@@ -1082,6 +1073,12 @@ int ifoRead_TT_SRPT(ifo_handle_t *ifofile) {
return 0;
}
+ if(tt_srpt->nr_of_srpts>info_length/sizeof(title_info_t)){
+ fprintf(stderr,"libdvdread: data mismatch: info_length (%ld)!= nr_of_srpts (%d). Truncating.\n",
+ info_length/sizeof(title_info_t),tt_srpt->nr_of_srpts);
+ tt_srpt->nr_of_srpts=info_length/sizeof(title_info_t);
+ }
+
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);
@@ -1189,8 +1186,22 @@ int ifoRead_VTS_PTT_SRPT(ifo_handle_t *ifofile) {
fprintf(stderr, "libdvdread: PTT search table too small.\n");
goto fail;
}
+
+ if(vts_ptt_srpt->nr_of_srpts == 0) {
+ fprintf(stderr, "libdvdread: Zero entries in PTT search table.\n");
+ goto fail;
+ }
+
for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) {
- B2N_32(data[i]);
+ /* Transformers 3 has PTT start bytes that point outside the SRPT PTT */
+ uint32_t start = data[i];
+ B2N_32(start);
+ if(start + sizeof(ptt_info_t) > vts_ptt_srpt->last_byte + 1) {
+ /* don't mess with any bytes beyond the end of the allocation */
+ vts_ptt_srpt->nr_of_srpts = i;
+ break;
+ }
+ data[i] = start;
/* 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
@@ -1216,6 +1227,7 @@ int ifoRead_VTS_PTT_SRPT(ifo_handle_t *ifofile) {
Titles with 0 PTTs. */
if(n < 0) n = 0;
+ /* DVDs created by the VDR-to-DVD device LG RC590M violate the following requirement */
CHECK_VALUE(n % 4 == 0);
vts_ptt_srpt->title[i].nr_of_ptts = n / 4;
@@ -1250,6 +1262,13 @@ int ifoRead_VTS_PTT_SRPT(ifo_handle_t *ifofile) {
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); /* ?? */
+ if (vts_ptt_srpt->title[i].ptt[j].pgcn == 0 ||
+ vts_ptt_srpt->title[i].ptt[j].pgcn >= 1000 ||
+ vts_ptt_srpt->title[i].ptt[j].pgn == 0 ||
+ vts_ptt_srpt->title[i].ptt[j].pgn >= 100) {
+ return 0;
+ }
+
}
}
@@ -1291,7 +1310,7 @@ int ifoRead_PTL_MAIT(ifo_handle_t *ifofile) {
if(!ifofile->vmgi_mat)
return 0;
- if(ifofile->vmgi_mat->ptl_mait == NULL)
+ if(ifofile->vmgi_mat->ptl_mait == 0)
return 1;
if(!DVDFileSeek_(ifofile->file, ifofile->vmgi_mat->ptl_mait * DVD_BLOCK_LEN))
@@ -1372,6 +1391,7 @@ int ifoRead_PTL_MAIT(ifo_handle_t *ifofile) {
ifofile->ptl_mait = NULL;
return 0;
}
+ memset(pf_temp, 0, info_length);
if(!(DVDReadBytes(ifofile->file, pf_temp, info_length))) {
fprintf(stderr, "libdvdread: Unable to read PTL_MAIT table at index %d.\n",i);
free(pf_temp);
@@ -1434,7 +1454,7 @@ int ifoRead_VTS_TMAPT(ifo_handle_t *ifofile) {
if(ifofile->vtsi_mat->vts_tmapt == 0) { /* optional(?) */
ifofile->vts_tmapt = NULL;
- fprintf(stderr,"Please send bug report - no VTS_TMAPT ?? \n");
+ fprintf(stderr,"libdvdread: No VTS_TMAPT available - skipping.\n");
return 1;
}
@@ -1818,10 +1838,11 @@ int ifoRead_PGCIT(ifo_handle_t *ifofile) {
if(ifofile->vtsi_mat->vts_pgcit == 0) /* mandatory */
return 0;
- ifofile->vts_pgcit = (pgcit_t *)malloc(sizeof(pgcit_t));
+ ifofile->vts_pgcit = (pgcit_t *)calloc(1, sizeof(pgcit_t));
if(!ifofile->vts_pgcit)
return 0;
+ ifofile->vts_pgcit->ref_count = 1;
if(!ifoRead_PGCIT_internal(ifofile, ifofile->vts_pgcit,
ifofile->vtsi_mat->vts_pgcit * DVD_BLOCK_LEN)) {
free(ifofile->vts_pgcit);
@@ -1832,6 +1853,17 @@ int ifoRead_PGCIT(ifo_handle_t *ifofile) {
return 1;
}
+static int find_dup_pgc(pgci_srp_t *pgci_srp, uint32_t start_byte, int count) {
+ int i;
+
+ for(i = 0; i < count; i++) {
+ if(pgci_srp[i].pgc_start_byte == start_byte) {
+ return i;
+ }
+ }
+ return -1;
+}
+
static int ifoRead_PGCIT_internal(ifo_handle_t *ifofile, pgcit_t *pgcit,
unsigned int offset) {
int i, info_length;
@@ -1880,21 +1912,26 @@ static int ifoRead_PGCIT_internal(ifo_handle_t *ifofile, pgcit_t *pgcit,
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));
+ int dup;
+ if((dup = find_dup_pgc(pgcit->pgci_srp, pgcit->pgci_srp[i].pgc_start_byte, i)) >= 0) {
+ pgcit->pgci_srp[i].pgc = pgcit->pgci_srp[dup].pgc;
+ pgcit->pgci_srp[i].pgc->ref_count++;
+ continue;
+ }
+ pgcit->pgci_srp[i].pgc = calloc(1, 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);
+ ifoFree_PGC(&pgcit->pgci_srp[j].pgc);
}
goto fail;
}
+ pgcit->pgci_srp[i].pgc->ref_count = 1;
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);
+ for(j = 0; j <= i; j++) {
+ ifoFree_PGC(&pgcit->pgci_srp[j].pgc);
}
free(pgcit->pgci_srp[i].pgc);
goto fail;
@@ -1908,16 +1945,18 @@ fail:
return 0;
}
-static void ifoFree_PGCIT_internal(pgcit_t *pgcit) {
- if(pgcit) {
+static void ifoFree_PGCIT_internal(pgcit_t **pgcit) {
+ if(pgcit && *pgcit && (--(*pgcit)->ref_count <= 0)) {
int i;
- for(i = 0; i < pgcit->nr_of_pgci_srp; i++)
+ for(i = 0; i < (*pgcit)->nr_of_pgci_srp; i++)
{
- ifoFree_PGC(pgcit->pgci_srp[i].pgc);
- free(pgcit->pgci_srp[i].pgc);
+ ifoFree_PGC(&(*pgcit)->pgci_srp[i].pgc);
}
- free(pgcit->pgci_srp);
+ free((*pgcit)->pgci_srp);
+ free(*pgcit);
}
+ if (pgcit)
+ *pgcit = NULL;
}
void ifoFree_PGCIT(ifo_handle_t *ifofile) {
@@ -1925,12 +1964,20 @@ void ifoFree_PGCIT(ifo_handle_t *ifofile) {
return;
if(ifofile->vts_pgcit) {
- ifoFree_PGCIT_internal(ifofile->vts_pgcit);
- free(ifofile->vts_pgcit);
- ifofile->vts_pgcit = 0;
+ ifoFree_PGCIT_internal(&ifofile->vts_pgcit);
}
}
+static int find_dup_lut(pgci_lu_t *lu, uint32_t start_byte, int count) {
+ int i;
+
+ for(i = 0; i < count; i++) {
+ if(lu[i].lang_start_byte == start_byte) {
+ return i;
+ }
+ }
+ return -1;
+}
int ifoRead_PGCI_UT(ifo_handle_t *ifofile) {
pgci_ut_t *pgci_ut;
@@ -2024,27 +2071,31 @@ int ifoRead_PGCI_UT(ifo_handle_t *ifofile) {
}
for(i = 0; i < pgci_ut->nr_of_lus; i++) {
+ int dup;
+ if((dup = find_dup_lut(pgci_ut->lu, pgci_ut->lu[i].lang_start_byte, i)) >= 0) {
+ pgci_ut->lu[i].pgcit = pgci_ut->lu[dup].pgcit;
+ pgci_ut->lu[i].pgcit->ref_count++;
+ continue;
+ }
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);
+ ifoFree_PGCIT_internal(&pgci_ut->lu[j].pgcit);
}
free(pgci_ut->lu);
free(pgci_ut);
ifofile->pgci_ut = 0;
return 0;
}
+ pgci_ut->lu[i].pgcit->ref_count = 1;
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);
+ for(j = 0; j <= i; j++) {
+ ifoFree_PGCIT_internal(&pgci_ut->lu[j].pgcit);
}
- free(pgci_ut->lu[i].pgcit);
free(pgci_ut->lu);
free(pgci_ut);
ifofile->pgci_ut = 0;
@@ -2066,8 +2117,7 @@ void ifoFree_PGCI_UT(ifo_handle_t *ifofile) {
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);
+ ifoFree_PGCIT_internal(&ifofile->pgci_ut->lu[i].pgcit);
}
free(ifofile->pgci_ut->lu);
free(ifofile->pgci_ut);