--- libdvdread.orig/src/ifo_read.c 2009-10-29 09:11:32.066743831 -0700 +++ libdvdread/src/ifo_read.c 2009-11-13 10:27:49.293174360 -0800 @@ -87,9 +87,9 @@ 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); @@ -870,7 +870,6 @@ if(!ifoRead_PGC_COMMAND_TBL(ifofile, pgc->command_tbl, offset + pgc->command_tbl_offset)) { - free(pgc->command_tbl); return 0; } } else { @@ -880,13 +879,10 @@ 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 { @@ -896,18 +892,11 @@ 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 { @@ -917,13 +906,11 @@ 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 { @@ -946,29 +933,33 @@ 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; } } @@ -977,9 +968,7 @@ 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); } } @@ -1202,6 +1191,13 @@ 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; + } + } } @@ -1372,7 +1368,6 @@ if(ifofile->vtsi_mat->vts_tmapt == 0) { /* optional(?) */ ifofile->vts_tmapt = NULL; - fprintf(stderr,"Please send bug report - no VTS_TMAPT ?? \n"); return 1; } @@ -1756,10 +1751,11 @@ 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); @@ -1770,6 +1766,17 @@ 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; @@ -1818,21 +1825,26 @@ 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); } goto fail; } @@ -1845,12 +1857,16 @@ 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++) - ifoFree_PGC(pgcit->pgci_srp[i].pgc); - free(pgcit->pgci_srp); + for(i = 0; i < (*pgcit)->nr_of_pgci_srp; i++) + ifoFree_PGC(&(*pgcit)->pgci_srp[i].pgc); + free((*pgcit)->pgci_srp); + free(*pgcit); + } + if (pgcit) { + *pgcit = NULL; } } @@ -1859,12 +1875,20 @@ 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; @@ -1958,27 +1982,31 @@ } 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; @@ -2000,8 +2028,7 @@ 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); --- libdvdread.orig/src/dvdread/ifo_types.h 2009-10-29 09:11:32.161557143 -0700 +++ libdvdread/src/dvdread/ifo_types.h 2009-11-13 09:13:10.255237710 -0800 @@ -301,6 +301,7 @@ pgc_program_map_t *program_map; cell_playback_t *cell_playback; cell_position_t *cell_position; + int ref_count; } ATTRIBUTE_PACKED pgc_t; #define PGC_SIZE 236U @@ -326,6 +327,7 @@ uint16_t zero_1; uint32_t last_byte; pgci_srp_t *pgci_srp; + int ref_count; } ATTRIBUTE_PACKED pgcit_t; #define PGCIT_SIZE 8U