MythTV  0.26-pre
ifo_read.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2000, 2001, 2002, 2003
00003  *               Björn Englund <d4bjorn@dtek.chalmers.se>,
00004  *               Håkan Hjort <d95hjort@dtek.chalmers.se>
00005  *
00006  * This file is part of libdvdread.
00007  *
00008  * libdvdread is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * libdvdread is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License along
00019  * with libdvdread; if not, write to the Free Software Foundation, Inc.,
00020  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00021  */
00022 
00023 #include "config.h"
00024 
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <inttypes.h>
00028 #include <string.h>
00029 
00030 #include "bswap.h"
00031 #include "dvdread/ifo_types.h"
00032 #include "dvdread/ifo_read.h"
00033 #include "dvdread/dvd_reader.h"
00034 #include "dvdread_internal.h"
00035 #include "dvdread/bitreader.h"
00036 
00037 #ifndef DVD_BLOCK_LEN
00038 #define DVD_BLOCK_LEN 2048
00039 #endif
00040 
00041 #ifndef NDEBUG
00042 #define CHECK_ZERO0(arg)                                                \
00043   if(arg != 0) {                                                        \
00044     fprintf(stderr, "*** Zero check failed in %s:%i\n    for %s = 0x%x\n", \
00045             __FILE__, __LINE__, # arg, arg);                            \
00046   }
00047 #define CHECK_ZERO(arg)                                                 \
00048   if(memcmp(my_friendly_zeros, &arg, sizeof(arg))) {                    \
00049     unsigned int i_CZ;                                                  \
00050     fprintf(stderr, "*** Zero check failed in %s:%i\n    for %s = 0x",  \
00051             __FILE__, __LINE__, # arg );                                \
00052     for(i_CZ = 0; i_CZ < sizeof(arg); i_CZ++)                           \
00053       fprintf(stderr, "%02x", *((uint8_t *)&arg + i_CZ));               \
00054     fprintf(stderr, "\n");                                              \
00055   }
00056 static const uint8_t my_friendly_zeros[2048];
00057 #else
00058 #define CHECK_ZERO0(arg) (void)(arg)
00059 #define CHECK_ZERO(arg) (void)(arg)
00060 #endif
00061 
00062 
00063 /* Prototypes for internal functions */
00064 static int ifoRead_VMG(ifo_handle_t *ifofile);
00065 static int ifoRead_VTS(ifo_handle_t *ifofile);
00066 static int ifoRead_PGC(ifo_handle_t *ifofile, pgc_t *pgc, unsigned int offset);
00067 static int ifoRead_PGC_COMMAND_TBL(ifo_handle_t *ifofile,
00068                                    pgc_command_tbl_t *cmd_tbl,
00069                                    unsigned int offset);
00070 static int ifoRead_PGC_PROGRAM_MAP(ifo_handle_t *ifofile,
00071                                    pgc_program_map_t *program_map,
00072                                    unsigned int nr, unsigned int offset);
00073 static int ifoRead_CELL_PLAYBACK_TBL(ifo_handle_t *ifofile,
00074                                      cell_playback_t *cell_playback,
00075                                      unsigned int nr, unsigned int offset);
00076 static int ifoRead_CELL_POSITION_TBL(ifo_handle_t *ifofile,
00077                                      cell_position_t *cell_position,
00078                                      unsigned int nr, unsigned int offset);
00079 static int ifoRead_VTS_ATTRIBUTES(ifo_handle_t *ifofile,
00080                                   vts_attributes_t *vts_attributes,
00081                                   unsigned int offset);
00082 static int ifoRead_C_ADT_internal(ifo_handle_t *ifofile, c_adt_t *c_adt,
00083                                   unsigned int sector);
00084 static int ifoRead_VOBU_ADMAP_internal(ifo_handle_t *ifofile,
00085                                        vobu_admap_t *vobu_admap,
00086                                        unsigned int sector);
00087 static int ifoRead_PGCIT_internal(ifo_handle_t *ifofile, pgcit_t *pgcit,
00088                                   unsigned int offset);
00089 
00090 static void ifoFree_PGC(pgc_t *pgc);
00091 static void ifoFree_PGC_COMMAND_TBL(pgc_command_tbl_t *cmd_tbl);
00092 static void ifoFree_PGCIT_internal(pgcit_t *pgcit);
00093 
00094 static inline int DVDFileSeekForce_( dvd_file_t *dvd_file, uint32_t offset, int force_size ) {
00095   return (DVDFileSeekForce(dvd_file, (int)offset, force_size) == (int)offset);
00096 }
00097 
00098 static inline int DVDFileSeek_( dvd_file_t *dvd_file, uint32_t offset ) {
00099   return (DVDFileSeek(dvd_file, (int)offset) == (int)offset);
00100 }
00101 
00102 static void read_video_attr(video_attr_t *va) {
00103   getbits_state_t state;
00104   uint8_t buf[sizeof(video_attr_t)];
00105 
00106   memcpy(buf, va, sizeof(video_attr_t));
00107   if (!dvdread_getbits_init(&state, buf)) abort();
00108   va->mpeg_version = dvdread_getbits(&state, 2);
00109   va->video_format = dvdread_getbits(&state, 2);
00110   va->display_aspect_ratio = dvdread_getbits(&state, 2);
00111   va->permitted_df = dvdread_getbits(&state, 2);
00112   va->line21_cc_1 = dvdread_getbits(&state, 1);
00113   va->line21_cc_2 = dvdread_getbits(&state, 1);
00114   va->unknown1 = dvdread_getbits(&state, 1);
00115   va->bit_rate = dvdread_getbits(&state, 1);
00116   va->picture_size = dvdread_getbits(&state, 2);
00117   va->letterboxed = dvdread_getbits(&state, 1);
00118   va->film_mode = dvdread_getbits(&state, 1);
00119 }
00120 
00121 static void read_audio_attr(audio_attr_t *aa) {
00122   getbits_state_t state;
00123   uint8_t buf[sizeof(audio_attr_t)];
00124 
00125   memcpy(buf, aa, sizeof(audio_attr_t));
00126   if (!dvdread_getbits_init(&state, buf)) abort();
00127   aa->audio_format = dvdread_getbits(&state, 3);
00128   aa->multichannel_extension = dvdread_getbits(&state, 1);
00129   aa->lang_type = dvdread_getbits(&state, 2);
00130   aa->application_mode = dvdread_getbits(&state, 2);
00131   aa->quantization = dvdread_getbits(&state, 2);
00132   aa->sample_frequency = dvdread_getbits(&state, 2);
00133   aa->unknown1 = dvdread_getbits(&state, 1);
00134   aa->channels = dvdread_getbits(&state, 3);
00135   aa->lang_code = dvdread_getbits(&state, 16);
00136   aa->lang_extension = dvdread_getbits(&state, 8);
00137   aa->code_extension = dvdread_getbits(&state, 8);
00138   aa->unknown3 = dvdread_getbits(&state, 8);
00139   aa->app_info.karaoke.unknown4 = dvdread_getbits(&state, 1);
00140   aa->app_info.karaoke.channel_assignment = dvdread_getbits(&state, 3);
00141   aa->app_info.karaoke.version = dvdread_getbits(&state, 2);
00142   aa->app_info.karaoke.mc_intro = dvdread_getbits(&state, 1);
00143   aa->app_info.karaoke.mode = dvdread_getbits(&state, 1);
00144 }
00145 
00146 static void read_multichannel_ext(multichannel_ext_t *me) {
00147   getbits_state_t state;
00148   uint8_t buf[sizeof(multichannel_ext_t)];
00149 
00150   memcpy(buf, me, sizeof(multichannel_ext_t));
00151   if (!dvdread_getbits_init(&state, buf)) abort();
00152   me->zero1 = dvdread_getbits(&state, 7);
00153   me->ach0_gme = dvdread_getbits(&state, 1);
00154   me->zero2 = dvdread_getbits(&state, 7);
00155   me->ach1_gme = dvdread_getbits(&state, 1);
00156   me->zero3 = dvdread_getbits(&state, 4);
00157   me->ach2_gv1e = dvdread_getbits(&state, 1);
00158   me->ach2_gv2e = dvdread_getbits(&state, 1);
00159   me->ach2_gm1e = dvdread_getbits(&state, 1);
00160   me->ach2_gm2e = dvdread_getbits(&state, 1);
00161   me->zero4 = dvdread_getbits(&state, 4);
00162   me->ach3_gv1e = dvdread_getbits(&state, 1);
00163   me->ach3_gv2e = dvdread_getbits(&state, 1);
00164   me->ach3_gmAe = dvdread_getbits(&state, 1);
00165   me->ach3_se2e = dvdread_getbits(&state, 1);
00166   me->zero5 = dvdread_getbits(&state, 4);
00167   me->ach4_gv1e = dvdread_getbits(&state, 1);
00168   me->ach4_gv2e = dvdread_getbits(&state, 1);
00169   me->ach4_gmBe = dvdread_getbits(&state, 1);
00170   me->ach4_seBe = dvdread_getbits(&state, 1);
00171 }
00172 
00173 static void read_subp_attr(subp_attr_t *sa) {
00174   getbits_state_t state;
00175   uint8_t buf[sizeof(subp_attr_t)];
00176 
00177   memcpy(buf, sa, sizeof(subp_attr_t));
00178   if (!dvdread_getbits_init(&state, buf)) abort();
00179   sa->code_mode = dvdread_getbits(&state, 3);
00180   sa->zero1 = dvdread_getbits(&state, 3);
00181   sa->type = dvdread_getbits(&state, 2);
00182   sa->zero2 = dvdread_getbits(&state, 8);
00183   sa->lang_code = dvdread_getbits(&state, 16);
00184   sa->lang_extension = dvdread_getbits(&state, 8);
00185   sa->code_extension = dvdread_getbits(&state, 8);
00186 }
00187 
00188 static void read_user_ops(user_ops_t *uo) {
00189   getbits_state_t state;
00190   uint8_t buf[sizeof(user_ops_t)];
00191 
00192   memcpy(buf, uo, sizeof(user_ops_t));
00193   if (!dvdread_getbits_init(&state, buf)) abort();
00194   uo->zero                           = dvdread_getbits(&state, 7);
00195   uo->video_pres_mode_change         = dvdread_getbits(&state, 1);
00196   uo->karaoke_audio_pres_mode_change = dvdread_getbits(&state, 1);
00197   uo->angle_change                   = dvdread_getbits(&state, 1);
00198   uo->subpic_stream_change           = dvdread_getbits(&state, 1);
00199   uo->audio_stream_change            = dvdread_getbits(&state, 1);
00200   uo->pause_on                       = dvdread_getbits(&state, 1);
00201   uo->still_off                      = dvdread_getbits(&state, 1);
00202   uo->button_select_or_activate      = dvdread_getbits(&state, 1);
00203   uo->resume                         = dvdread_getbits(&state, 1);
00204   uo->chapter_menu_call              = dvdread_getbits(&state, 1);
00205   uo->angle_menu_call                = dvdread_getbits(&state, 1);
00206   uo->audio_menu_call                = dvdread_getbits(&state, 1);
00207   uo->subpic_menu_call               = dvdread_getbits(&state, 1);
00208   uo->root_menu_call                 = dvdread_getbits(&state, 1);
00209   uo->title_menu_call                = dvdread_getbits(&state, 1);
00210   uo->backward_scan                  = dvdread_getbits(&state, 1);
00211   uo->forward_scan                   = dvdread_getbits(&state, 1);
00212   uo->next_pg_search                 = dvdread_getbits(&state, 1);
00213   uo->prev_or_top_pg_search          = dvdread_getbits(&state, 1);
00214   uo->time_or_chapter_search         = dvdread_getbits(&state, 1);
00215   uo->go_up                          = dvdread_getbits(&state, 1);
00216   uo->stop                           = dvdread_getbits(&state, 1);
00217   uo->title_play                     = dvdread_getbits(&state, 1);
00218   uo->chapter_search_or_play         = dvdread_getbits(&state, 1);
00219   uo->title_or_time_play             = dvdread_getbits(&state, 1);
00220 }
00221 
00222 static void read_pgci_srp(pgci_srp_t *ps) {
00223   getbits_state_t state;
00224   uint8_t buf[sizeof(pgci_srp_t)];
00225 
00226   memcpy(buf, ps, sizeof(pgci_srp_t));
00227   if (!dvdread_getbits_init(&state, buf)) abort();
00228   ps->entry_id                       = dvdread_getbits(&state, 8);
00229   ps->block_mode                     = dvdread_getbits(&state, 2);
00230   ps->block_type                     = dvdread_getbits(&state, 2);
00231   ps->unknown1                       = dvdread_getbits(&state, 4);
00232   ps->ptl_id_mask                    = dvdread_getbits(&state, 16);
00233   ps->pgc_start_byte                 = dvdread_getbits(&state, 32);
00234 }
00235 
00236 static void read_cell_playback(cell_playback_t *cp) {
00237   getbits_state_t state;
00238   uint8_t buf[sizeof(cell_playback_t)];
00239 
00240   memcpy(buf, cp, sizeof(cell_playback_t));
00241   if (!dvdread_getbits_init(&state, buf)) abort();
00242   cp->block_mode                      = dvdread_getbits(&state, 2);
00243   cp->block_type                      = dvdread_getbits(&state, 2);
00244   cp->seamless_play                   = dvdread_getbits(&state, 1);
00245   cp->interleaved                     = dvdread_getbits(&state, 1);
00246   cp->stc_discontinuity               = dvdread_getbits(&state, 1);
00247   cp->seamless_angle                  = dvdread_getbits(&state, 1);
00248   cp->playback_mode                   = dvdread_getbits(&state, 1);
00249   cp->restricted                      = dvdread_getbits(&state, 1);
00250   cp->unknown2                        = dvdread_getbits(&state, 6);
00251   cp->still_time                      = dvdread_getbits(&state, 8);
00252   cp->cell_cmd_nr                     = dvdread_getbits(&state, 8);
00253 
00254   cp->playback_time.hour              = dvdread_getbits(&state, 8);
00255   cp->playback_time.minute            = dvdread_getbits(&state, 8);
00256   cp->playback_time.second            = dvdread_getbits(&state, 8);
00257   cp->playback_time.frame_u           = dvdread_getbits(&state, 8);
00258 
00259   cp->first_sector                    = dvdread_getbits(&state, 32);
00260   cp->first_ilvu_end_sector           = dvdread_getbits(&state, 32);
00261   cp->last_vobu_start_sector          = dvdread_getbits(&state, 32);
00262   cp->last_sector                     = dvdread_getbits(&state, 32);
00263 }
00264 
00265 static void read_playback_type(playback_type_t *pt) {
00266   getbits_state_t state;
00267   uint8_t buf[sizeof(playback_type_t)];
00268 
00269   memcpy(buf, pt, sizeof(playback_type_t));
00270   if (!dvdread_getbits_init(&state, buf)) abort();
00271   pt->zero_1                          = dvdread_getbits(&state, 1);
00272   pt->multi_or_random_pgc_title       = dvdread_getbits(&state, 1);
00273   pt->jlc_exists_in_cell_cmd          = dvdread_getbits(&state, 1);
00274   pt->jlc_exists_in_prepost_cmd       = dvdread_getbits(&state, 1);
00275   pt->jlc_exists_in_button_cmd        = dvdread_getbits(&state, 1);
00276   pt->jlc_exists_in_tt_dom            = dvdread_getbits(&state, 1);
00277   pt->chapter_search_or_play          = dvdread_getbits(&state, 1);
00278   pt->title_or_time_play              = dvdread_getbits(&state, 1);
00279 }
00280 
00281 static void free_ptl_mait(ptl_mait_t* ptl_mait, int num_entries) {
00282   int i;
00283   for (i = 0; i < num_entries; i++)
00284     free(ptl_mait->countries[i].pf_ptl_mai);
00285 
00286   free(ptl_mait->countries);
00287   free(ptl_mait);
00288 }
00289 
00290 ifo_handle_t *ifoOpen(dvd_reader_t *dvd, int title) {
00291   ifo_handle_t *ifofile;
00292   int bup_file_opened = 0;
00293   char ifo_filename[13];
00294 
00295   ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t));
00296   if(!ifofile)
00297     return NULL;
00298 
00299   memset(ifofile, 0, sizeof(ifo_handle_t));
00300 
00301   ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE);
00302   if(!ifofile->file) { /* Failed to open IFO, try to open BUP */
00303     ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_BACKUP_FILE);
00304     bup_file_opened = 1;
00305   }
00306 
00307   if (title)
00308     snprintf(ifo_filename, 12, "VTS_%02d_0.%s", title, bup_file_opened ? "BUP" : "IFO");
00309   else
00310     snprintf(ifo_filename, 12, "VIDEO_TS.%s", bup_file_opened ? "BUP" : "IFO");
00311 
00312   ifo_filename[12] = '\0';
00313 
00314   if(!ifofile->file) {
00315     fprintf(stderr, "libdvdread: Can't open file %s.\n", ifo_filename);
00316     free(ifofile);
00317     return NULL;
00318   }
00319 
00320   /* First check if this is a VMGI file. */
00321   if(ifoRead_VMG(ifofile)) {
00322 
00323     /* These are both mandatory. */
00324     if(!ifoRead_FP_PGC(ifofile) || !ifoRead_TT_SRPT(ifofile))
00325       goto ifoOpen_try_bup;
00326 
00327     ifoRead_PGCI_UT(ifofile);
00328     ifoRead_PTL_MAIT(ifofile);
00329 
00330     /* This is also mandatory. */
00331     if(!ifoRead_VTS_ATRT(ifofile))
00332       goto ifoOpen_try_bup;
00333 
00334     ifoRead_TXTDT_MGI(ifofile);
00335     ifoRead_C_ADT(ifofile);
00336     ifoRead_VOBU_ADMAP(ifofile);
00337 
00338     return ifofile;
00339   }
00340 
00341   if(ifoRead_VTS(ifofile)) {
00342 
00343     if(!ifoRead_VTS_PTT_SRPT(ifofile) || !ifoRead_PGCIT(ifofile))
00344       goto ifoOpen_try_bup;
00345 
00346     ifoRead_PGCI_UT(ifofile);
00347     ifoRead_VTS_TMAPT(ifofile);
00348     ifoRead_C_ADT(ifofile);
00349     ifoRead_VOBU_ADMAP(ifofile);
00350 
00351     if(!ifoRead_TITLE_C_ADT(ifofile) || !ifoRead_TITLE_VOBU_ADMAP(ifofile))
00352       goto ifoOpen_try_bup;
00353 
00354     return ifofile;
00355   }
00356 
00357 ifoOpen_try_bup:
00358   if (bup_file_opened)
00359     goto ifoOpen_fail;
00360 
00361   /* Try BUP instead */
00362   ifoClose(ifofile);
00363 
00364   ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t));
00365   if(!ifofile)
00366     return NULL;
00367 
00368   memset(ifofile, 0, sizeof(ifo_handle_t));
00369   ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_BACKUP_FILE);
00370 
00371   if (title)
00372     snprintf(ifo_filename, 12, "VTS_%02d_0.BUP", title);
00373   else
00374     strncpy(ifo_filename, "VIDEO_TS.BUP", 12);
00375 
00376   if (!ifofile->file) {
00377     fprintf(stderr, "libdvdread: Can't open file %s.\n", ifo_filename);
00378     free(ifofile);
00379     return NULL;
00380   }
00381   bup_file_opened = 1;
00382 
00383   /* First check if this is a VMGI file. */
00384   if(ifoRead_VMG(ifofile)) {
00385 
00386     /* These are both mandatory. */
00387     if(!ifoRead_FP_PGC(ifofile) || !ifoRead_TT_SRPT(ifofile))
00388       goto ifoOpen_fail;
00389 
00390     ifoRead_PGCI_UT(ifofile);
00391     ifoRead_PTL_MAIT(ifofile);
00392 
00393     /* This is also mandatory. */
00394     if(!ifoRead_VTS_ATRT(ifofile))
00395       goto ifoOpen_fail;
00396 
00397     ifoRead_TXTDT_MGI(ifofile);
00398     ifoRead_C_ADT(ifofile);
00399     ifoRead_VOBU_ADMAP(ifofile);
00400 
00401     return ifofile;
00402   }
00403 
00404   if(ifoRead_VTS(ifofile)) {
00405 
00406     if(!ifoRead_VTS_PTT_SRPT(ifofile) || !ifoRead_PGCIT(ifofile))
00407       goto ifoOpen_fail;
00408 
00409     ifoRead_PGCI_UT(ifofile);
00410     ifoRead_VTS_TMAPT(ifofile);
00411     ifoRead_C_ADT(ifofile);
00412     ifoRead_VOBU_ADMAP(ifofile);
00413 
00414     if(!ifoRead_TITLE_C_ADT(ifofile) || !ifoRead_TITLE_VOBU_ADMAP(ifofile))
00415       goto ifoOpen_fail;
00416 
00417     return ifofile;
00418   }
00419 
00420 ifoOpen_fail:
00421   fprintf(stderr, "libdvdread: Invalid IFO for title %d (%s).\n", title, ifo_filename);
00422   ifoClose(ifofile);
00423   return NULL;
00424 }
00425 
00426 
00427 ifo_handle_t *ifoOpenVMGI(dvd_reader_t *dvd) {
00428   ifo_handle_t *ifofile;
00429 
00430   ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t));
00431   if(!ifofile)
00432     return NULL;
00433 
00434   memset(ifofile, 0, sizeof(ifo_handle_t));
00435 
00436   ifofile->file = DVDOpenFile(dvd, 0, DVD_READ_INFO_FILE);
00437   if(!ifofile->file) /* Should really catch any error and try to fallback */
00438     ifofile->file = DVDOpenFile(dvd, 0, DVD_READ_INFO_BACKUP_FILE);
00439   if(!ifofile->file) {
00440     fprintf(stderr, "libdvdread: Can't open file VIDEO_TS.IFO.\n");
00441     free(ifofile);
00442     return NULL;
00443   }
00444 
00445   if(ifoRead_VMG(ifofile))
00446     return ifofile;
00447 
00448   fprintf(stderr, "libdvdread,ifoOpenVMGI(): Invalid main menu IFO (VIDEO_TS.IFO).\n");
00449   ifoClose(ifofile);
00450   return NULL;
00451 }
00452 
00453 
00454 ifo_handle_t *ifoOpenVTSI(dvd_reader_t *dvd, int title) {
00455   ifo_handle_t *ifofile;
00456 
00457   ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t));
00458   if(!ifofile)
00459     return NULL;
00460 
00461   memset(ifofile, 0, sizeof(ifo_handle_t));
00462 
00463   if(title <= 0 || title > 99) {
00464     fprintf(stderr, "libdvdread: ifoOpenVTSI invalid title (%d).\n", title);
00465     free(ifofile);
00466     return NULL;
00467   }
00468 
00469   ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE);
00470   if(!ifofile->file) /* Should really catch any error and try to fallback */
00471     ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_BACKUP_FILE);
00472   if(!ifofile->file) {
00473     fprintf(stderr, "libdvdread: Can't open file VTS_%02d_0.IFO.\n", title);
00474     free(ifofile);
00475     return NULL;
00476   }
00477 
00478   ifoRead_VTS(ifofile);
00479   if(ifofile->vtsi_mat)
00480     return ifofile;
00481 
00482   fprintf(stderr, "libdvdread: Invalid IFO for title %d (VTS_%02d_0.IFO).\n",
00483           title, title);
00484   ifoClose(ifofile);
00485   return NULL;
00486 }
00487 
00488 
00489 void ifoClose(ifo_handle_t *ifofile) {
00490   if(!ifofile)
00491     return;
00492 
00493   ifoFree_VOBU_ADMAP(ifofile);
00494   ifoFree_TITLE_VOBU_ADMAP(ifofile);
00495   ifoFree_C_ADT(ifofile);
00496   ifoFree_TITLE_C_ADT(ifofile);
00497   ifoFree_TXTDT_MGI(ifofile);
00498   ifoFree_VTS_ATRT(ifofile);
00499   ifoFree_PTL_MAIT(ifofile);
00500   ifoFree_PGCI_UT(ifofile);
00501   ifoFree_TT_SRPT(ifofile);
00502   ifoFree_FP_PGC(ifofile);
00503   ifoFree_PGCIT(ifofile);
00504   ifoFree_VTS_PTT_SRPT(ifofile);
00505   ifoFree_VTS_TMAPT(ifofile);
00506 
00507   if(ifofile->vmgi_mat)
00508     free(ifofile->vmgi_mat);
00509 
00510   if(ifofile->vtsi_mat)
00511     free(ifofile->vtsi_mat);
00512 
00513   DVDCloseFile(ifofile->file);
00514   ifofile->file = 0;
00515   free(ifofile);
00516   ifofile = 0;
00517 }
00518 
00519 
00520 static int ifoRead_VMG(ifo_handle_t *ifofile) {
00521   vmgi_mat_t *vmgi_mat;
00522 
00523   vmgi_mat = (vmgi_mat_t *)malloc(sizeof(vmgi_mat_t));
00524   if(!vmgi_mat)
00525     return 0;
00526 
00527   ifofile->vmgi_mat = vmgi_mat;
00528 
00529   if(!DVDFileSeek_(ifofile->file, 0)) {
00530     free(ifofile->vmgi_mat);
00531     ifofile->vmgi_mat = 0;
00532     return 0;
00533   }
00534 
00535   if(!DVDReadBytes(ifofile->file, vmgi_mat, sizeof(vmgi_mat_t))) {
00536     free(ifofile->vmgi_mat);
00537     ifofile->vmgi_mat = 0;
00538     return 0;
00539   }
00540 
00541   if(strncmp("DVDVIDEO-VMG", vmgi_mat->vmg_identifier, 12) != 0) {
00542     free(ifofile->vmgi_mat);
00543     ifofile->vmgi_mat = 0;
00544     return 0;
00545   }
00546 
00547   B2N_32(vmgi_mat->vmg_last_sector);
00548   B2N_32(vmgi_mat->vmgi_last_sector);
00549   B2N_32(vmgi_mat->vmg_category);
00550   B2N_16(vmgi_mat->vmg_nr_of_volumes);
00551   B2N_16(vmgi_mat->vmg_this_volume_nr);
00552   B2N_16(vmgi_mat->vmg_nr_of_title_sets);
00553   B2N_64(vmgi_mat->vmg_pos_code);
00554   B2N_32(vmgi_mat->vmgi_last_byte);
00555   B2N_32(vmgi_mat->first_play_pgc);
00556   B2N_32(vmgi_mat->vmgm_vobs);
00557   B2N_32(vmgi_mat->tt_srpt);
00558   B2N_32(vmgi_mat->vmgm_pgci_ut);
00559   B2N_32(vmgi_mat->ptl_mait);
00560   B2N_32(vmgi_mat->vts_atrt);
00561   B2N_32(vmgi_mat->txtdt_mgi);
00562   B2N_32(vmgi_mat->vmgm_c_adt);
00563   B2N_32(vmgi_mat->vmgm_vobu_admap);
00564   read_video_attr(&vmgi_mat->vmgm_video_attr);
00565   read_audio_attr(&vmgi_mat->vmgm_audio_attr);
00566   read_subp_attr(&vmgi_mat->vmgm_subp_attr);
00567 
00568 
00569   CHECK_ZERO(vmgi_mat->zero_1);
00570   CHECK_ZERO(vmgi_mat->zero_2);
00571   CHECK_ZERO(vmgi_mat->zero_3);
00572   CHECK_ZERO(vmgi_mat->zero_4);
00573   CHECK_ZERO(vmgi_mat->zero_5);
00574   CHECK_ZERO(vmgi_mat->zero_6);
00575   CHECK_ZERO(vmgi_mat->zero_7);
00576   CHECK_ZERO(vmgi_mat->zero_8);
00577   CHECK_ZERO(vmgi_mat->zero_9);
00578   CHECK_ZERO(vmgi_mat->zero_10);
00579   CHECK_VALUE(vmgi_mat->vmg_last_sector != 0);
00580   CHECK_VALUE(vmgi_mat->vmgi_last_sector != 0);
00581   CHECK_VALUE(vmgi_mat->vmgi_last_sector * 2 <= vmgi_mat->vmg_last_sector);
00582   CHECK_VALUE(vmgi_mat->vmgi_last_sector * 2 <= vmgi_mat->vmg_last_sector);
00583   CHECK_VALUE(vmgi_mat->vmg_nr_of_volumes != 0);
00584   CHECK_VALUE(vmgi_mat->vmg_this_volume_nr != 0);
00585   CHECK_VALUE(vmgi_mat->vmg_this_volume_nr <= vmgi_mat->vmg_nr_of_volumes);
00586   CHECK_VALUE(vmgi_mat->disc_side == 1 || vmgi_mat->disc_side == 2);
00587   CHECK_VALUE(vmgi_mat->vmg_nr_of_title_sets != 0);
00588   CHECK_VALUE(vmgi_mat->vmgi_last_byte >= 341);
00589   CHECK_VALUE(vmgi_mat->vmgi_last_byte / DVD_BLOCK_LEN <=
00590               vmgi_mat->vmgi_last_sector);
00591   /* It seems that first_play_pgc is optional. */
00592   CHECK_VALUE(vmgi_mat->first_play_pgc < vmgi_mat->vmgi_last_byte);
00593   CHECK_VALUE(vmgi_mat->vmgm_vobs == 0 ||
00594               (vmgi_mat->vmgm_vobs > vmgi_mat->vmgi_last_sector &&
00595                vmgi_mat->vmgm_vobs < vmgi_mat->vmg_last_sector));
00596   CHECK_VALUE(vmgi_mat->tt_srpt <= vmgi_mat->vmgi_last_sector);
00597   CHECK_VALUE(vmgi_mat->vmgm_pgci_ut <= vmgi_mat->vmgi_last_sector);
00598   CHECK_VALUE(vmgi_mat->ptl_mait <= vmgi_mat->vmgi_last_sector);
00599   CHECK_VALUE(vmgi_mat->vts_atrt <= vmgi_mat->vmgi_last_sector);
00600   CHECK_VALUE(vmgi_mat->txtdt_mgi <= vmgi_mat->vmgi_last_sector);
00601   CHECK_VALUE(vmgi_mat->vmgm_c_adt <= vmgi_mat->vmgi_last_sector);
00602   CHECK_VALUE(vmgi_mat->vmgm_vobu_admap <= vmgi_mat->vmgi_last_sector);
00603 
00604   CHECK_VALUE(vmgi_mat->nr_of_vmgm_audio_streams <= 1);
00605   CHECK_VALUE(vmgi_mat->nr_of_vmgm_subp_streams <= 1);
00606 
00607   return 1;
00608 }
00609 
00610 
00611 static int ifoRead_VTS(ifo_handle_t *ifofile) {
00612   vtsi_mat_t *vtsi_mat;
00613   int i;
00614 
00615   vtsi_mat = (vtsi_mat_t *)malloc(sizeof(vtsi_mat_t));
00616   if(!vtsi_mat)
00617     return 0;
00618 
00619   ifofile->vtsi_mat = vtsi_mat;
00620 
00621   if(!DVDFileSeek_(ifofile->file, 0)) {
00622     free(ifofile->vtsi_mat);
00623     ifofile->vtsi_mat = 0;
00624     return 0;
00625   }
00626 
00627   if(!(DVDReadBytes(ifofile->file, vtsi_mat, sizeof(vtsi_mat_t)))) {
00628     free(ifofile->vtsi_mat);
00629     ifofile->vtsi_mat = 0;
00630     return 0;
00631   }
00632 
00633   if(strncmp("DVDVIDEO-VTS", vtsi_mat->vts_identifier, 12) != 0) {
00634     free(ifofile->vtsi_mat);
00635     ifofile->vtsi_mat = 0;
00636     return 0;
00637   }
00638 
00639   read_video_attr(&vtsi_mat->vtsm_video_attr);
00640   read_video_attr(&vtsi_mat->vts_video_attr);
00641   read_audio_attr(&vtsi_mat->vtsm_audio_attr);
00642   for(i=0; i<8; i++)
00643     read_audio_attr(&vtsi_mat->vts_audio_attr[i]);
00644   read_subp_attr(&vtsi_mat->vtsm_subp_attr);
00645   for(i=0; i<32; i++)
00646     read_subp_attr(&vtsi_mat->vts_subp_attr[i]);
00647   B2N_32(vtsi_mat->vts_last_sector);
00648   B2N_32(vtsi_mat->vtsi_last_sector);
00649   B2N_32(vtsi_mat->vts_category);
00650   B2N_32(vtsi_mat->vtsi_last_byte);
00651   B2N_32(vtsi_mat->vtsm_vobs);
00652   B2N_32(vtsi_mat->vtstt_vobs);
00653   B2N_32(vtsi_mat->vts_ptt_srpt);
00654   B2N_32(vtsi_mat->vts_pgcit);
00655   B2N_32(vtsi_mat->vtsm_pgci_ut);
00656   B2N_32(vtsi_mat->vts_tmapt);
00657   B2N_32(vtsi_mat->vtsm_c_adt);
00658   B2N_32(vtsi_mat->vtsm_vobu_admap);
00659   B2N_32(vtsi_mat->vts_c_adt);
00660   B2N_32(vtsi_mat->vts_vobu_admap);
00661 
00662 
00663   CHECK_ZERO(vtsi_mat->zero_1);
00664   CHECK_ZERO(vtsi_mat->zero_2);
00665   CHECK_ZERO(vtsi_mat->zero_3);
00666   CHECK_ZERO(vtsi_mat->zero_4);
00667   CHECK_ZERO(vtsi_mat->zero_5);
00668   CHECK_ZERO(vtsi_mat->zero_6);
00669   CHECK_ZERO(vtsi_mat->zero_7);
00670   CHECK_ZERO(vtsi_mat->zero_8);
00671   CHECK_ZERO(vtsi_mat->zero_9);
00672   CHECK_ZERO(vtsi_mat->zero_10);
00673   CHECK_ZERO(vtsi_mat->zero_11);
00674   CHECK_ZERO(vtsi_mat->zero_12);
00675   CHECK_ZERO(vtsi_mat->zero_13);
00676   CHECK_ZERO(vtsi_mat->zero_14);
00677   CHECK_ZERO(vtsi_mat->zero_15);
00678   CHECK_ZERO(vtsi_mat->zero_16);
00679   CHECK_ZERO(vtsi_mat->zero_17);
00680   CHECK_ZERO(vtsi_mat->zero_18);
00681   CHECK_ZERO(vtsi_mat->zero_19);
00682   CHECK_ZERO(vtsi_mat->zero_20);
00683   CHECK_ZERO(vtsi_mat->zero_21);
00684   CHECK_VALUE(vtsi_mat->vtsi_last_sector*2 <= vtsi_mat->vts_last_sector);
00685   CHECK_VALUE(vtsi_mat->vtsi_last_byte/DVD_BLOCK_LEN <= vtsi_mat->vtsi_last_sector);
00686   CHECK_VALUE(vtsi_mat->vtsm_vobs == 0 ||
00687               (vtsi_mat->vtsm_vobs > vtsi_mat->vtsi_last_sector &&
00688                vtsi_mat->vtsm_vobs < vtsi_mat->vts_last_sector));
00689   CHECK_VALUE(vtsi_mat->vtstt_vobs == 0 ||
00690               (vtsi_mat->vtstt_vobs > vtsi_mat->vtsi_last_sector &&
00691                vtsi_mat->vtstt_vobs < vtsi_mat->vts_last_sector));
00692   CHECK_VALUE(vtsi_mat->vts_ptt_srpt <= vtsi_mat->vtsi_last_sector);
00693   CHECK_VALUE(vtsi_mat->vts_pgcit <= vtsi_mat->vtsi_last_sector);
00694   CHECK_VALUE(vtsi_mat->vtsm_pgci_ut <= vtsi_mat->vtsi_last_sector);
00695   CHECK_VALUE(vtsi_mat->vts_tmapt <= vtsi_mat->vtsi_last_sector);
00696   CHECK_VALUE(vtsi_mat->vtsm_c_adt <= vtsi_mat->vtsi_last_sector);
00697   CHECK_VALUE(vtsi_mat->vtsm_vobu_admap <= vtsi_mat->vtsi_last_sector);
00698   CHECK_VALUE(vtsi_mat->vts_c_adt <= vtsi_mat->vtsi_last_sector);
00699   CHECK_VALUE(vtsi_mat->vts_vobu_admap <= vtsi_mat->vtsi_last_sector);
00700 
00701   CHECK_VALUE(vtsi_mat->nr_of_vtsm_audio_streams <= 1);
00702   CHECK_VALUE(vtsi_mat->nr_of_vtsm_subp_streams <= 1);
00703 
00704   CHECK_VALUE(vtsi_mat->nr_of_vts_audio_streams <= 8);
00705   for(i = vtsi_mat->nr_of_vts_audio_streams; i < 8; i++)
00706     CHECK_ZERO(vtsi_mat->vts_audio_attr[i]);
00707 
00708   CHECK_VALUE(vtsi_mat->nr_of_vts_subp_streams <= 32);
00709   for(i = vtsi_mat->nr_of_vts_subp_streams; i < 32; i++)
00710     CHECK_ZERO(vtsi_mat->vts_subp_attr[i]);
00711 
00712   for(i = 0; i < 8; i++) {
00713     read_multichannel_ext(&vtsi_mat->vts_mu_audio_attr[i]);
00714     CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero1);
00715     CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero2);
00716     CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero3);
00717     CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero4);
00718     CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero5);
00719     CHECK_ZERO(vtsi_mat->vts_mu_audio_attr[i].zero6);
00720   }
00721 
00722   return 1;
00723 }
00724 
00725 
00726 static int ifoRead_PGC_COMMAND_TBL(ifo_handle_t *ifofile,
00727                                    pgc_command_tbl_t *cmd_tbl,
00728                                    unsigned int offset) {
00729 
00730   memset(cmd_tbl, 0, sizeof(pgc_command_tbl_t));
00731 
00732   if(!DVDFileSeek_(ifofile->file, offset))
00733     return 0;
00734 
00735   if(!(DVDReadBytes(ifofile->file, cmd_tbl, PGC_COMMAND_TBL_SIZE)))
00736     return 0;
00737 
00738   B2N_16(cmd_tbl->nr_of_pre);
00739   B2N_16(cmd_tbl->nr_of_post);
00740   B2N_16(cmd_tbl->nr_of_cell);
00741 
00742   CHECK_VALUE(cmd_tbl->nr_of_pre + cmd_tbl->nr_of_post + cmd_tbl->nr_of_cell<= 255);
00743 
00744   if(cmd_tbl->nr_of_pre != 0) {
00745     unsigned int pre_cmds_size  = cmd_tbl->nr_of_pre * COMMAND_DATA_SIZE;
00746     cmd_tbl->pre_cmds = (vm_cmd_t *)malloc(pre_cmds_size);
00747     if(!cmd_tbl->pre_cmds)
00748       return 0;
00749 
00750     if(!(DVDReadBytes(ifofile->file, cmd_tbl->pre_cmds, pre_cmds_size))) {
00751       free(cmd_tbl->pre_cmds);
00752       return 0;
00753     }
00754   }
00755 
00756   if(cmd_tbl->nr_of_post != 0) {
00757     unsigned int post_cmds_size = cmd_tbl->nr_of_post * COMMAND_DATA_SIZE;
00758     cmd_tbl->post_cmds = (vm_cmd_t *)malloc(post_cmds_size);
00759     if(!cmd_tbl->post_cmds) {
00760       if(cmd_tbl->pre_cmds)
00761         free(cmd_tbl->pre_cmds);
00762       return 0;
00763     }
00764     if(!(DVDReadBytes(ifofile->file, cmd_tbl->post_cmds, post_cmds_size))) {
00765       if(cmd_tbl->pre_cmds)
00766         free(cmd_tbl->pre_cmds);
00767       free(cmd_tbl->post_cmds);
00768       return 0;
00769     }
00770   }
00771 
00772   if(cmd_tbl->nr_of_cell != 0) {
00773     unsigned int cell_cmds_size = cmd_tbl->nr_of_cell * COMMAND_DATA_SIZE;
00774     cmd_tbl->cell_cmds = (vm_cmd_t *)malloc(cell_cmds_size);
00775     if(!cmd_tbl->cell_cmds) {
00776       if(cmd_tbl->pre_cmds)
00777         free(cmd_tbl->pre_cmds);
00778       if(cmd_tbl->post_cmds)
00779         free(cmd_tbl->post_cmds);
00780       return 0;
00781     }
00782     if(!(DVDReadBytes(ifofile->file, cmd_tbl->cell_cmds, cell_cmds_size))) {
00783       if(cmd_tbl->pre_cmds)
00784         free(cmd_tbl->pre_cmds);
00785       if(cmd_tbl->post_cmds)
00786         free(cmd_tbl->post_cmds);
00787       free(cmd_tbl->cell_cmds);
00788       return 0;
00789     }
00790   }
00791 
00792   /*
00793    * Make a run over all the commands and see that we can interpret them all?
00794    */
00795   return 1;
00796 }
00797 
00798 
00799 static void ifoFree_PGC_COMMAND_TBL(pgc_command_tbl_t *cmd_tbl) {
00800   if(cmd_tbl) {
00801     if(cmd_tbl->nr_of_pre && cmd_tbl->pre_cmds)
00802       free(cmd_tbl->pre_cmds);
00803     if(cmd_tbl->nr_of_post && cmd_tbl->post_cmds)
00804       free(cmd_tbl->post_cmds);
00805     if(cmd_tbl->nr_of_cell && cmd_tbl->cell_cmds)
00806       free(cmd_tbl->cell_cmds);
00807     free(cmd_tbl);
00808   }
00809 }
00810 
00811 static int ifoRead_PGC_PROGRAM_MAP(ifo_handle_t *ifofile,
00812                                    pgc_program_map_t *program_map,
00813                                    unsigned int nr, unsigned int offset) {
00814   unsigned int size = nr * sizeof(pgc_program_map_t);
00815 
00816   if(!DVDFileSeek_(ifofile->file, offset))
00817     return 0;
00818 
00819   if(!(DVDReadBytes(ifofile->file, program_map, size)))
00820     return 0;
00821 
00822   return 1;
00823 }
00824 
00825 static int ifoRead_CELL_PLAYBACK_TBL(ifo_handle_t *ifofile,
00826                                      cell_playback_t *cell_playback,
00827                                      unsigned int nr, unsigned int offset) {
00828   unsigned int i;
00829   unsigned int size = nr * sizeof(cell_playback_t);
00830 
00831   if(!DVDFileSeek_(ifofile->file, offset))
00832     return 0;
00833 
00834   if(!(DVDReadBytes(ifofile->file, cell_playback, size)))
00835     return 0;
00836 
00837   for(i = 0; i < nr; i++) {
00838     read_cell_playback(&cell_playback[i]);
00839     /* Changed < to <= because this was false in the movie 'Pi'. */
00840     CHECK_VALUE(cell_playback[i].last_vobu_start_sector <=
00841                 cell_playback[i].last_sector);
00842     CHECK_VALUE(cell_playback[i].first_sector <=
00843                 cell_playback[i].last_vobu_start_sector);
00844   }
00845 
00846   return 1;
00847 }
00848 
00849 
00850 static int ifoRead_CELL_POSITION_TBL(ifo_handle_t *ifofile,
00851                                      cell_position_t *cell_position,
00852                                      unsigned int nr, unsigned int offset) {
00853   unsigned int i;
00854   unsigned int size = nr * sizeof(cell_position_t);
00855 
00856   if(!DVDFileSeek_(ifofile->file, offset))
00857     return 0;
00858 
00859   if(!(DVDReadBytes(ifofile->file, cell_position, size)))
00860     return 0;
00861 
00862   for(i = 0; i < nr; i++) {
00863     B2N_16(cell_position[i].vob_id_nr);
00864     CHECK_ZERO(cell_position[i].zero_1);
00865   }
00866 
00867   return 1;
00868 }
00869 
00870 static int ifoRead_PGC(ifo_handle_t *ifofile, pgc_t *pgc, unsigned int offset) {
00871   unsigned int i;
00872 
00873   if(!DVDFileSeek_(ifofile->file, offset))
00874     return 0;
00875 
00876   if(!(DVDReadBytes(ifofile->file, pgc, PGC_SIZE)))
00877     return 0;
00878 
00879   read_user_ops(&pgc->prohibited_ops);
00880   B2N_16(pgc->next_pgc_nr);
00881   B2N_16(pgc->prev_pgc_nr);
00882   B2N_16(pgc->goup_pgc_nr);
00883   B2N_16(pgc->command_tbl_offset);
00884   B2N_16(pgc->program_map_offset);
00885   B2N_16(pgc->cell_playback_offset);
00886   B2N_16(pgc->cell_position_offset);
00887 
00888   for(i = 0; i < 8; i++)
00889     B2N_16(pgc->audio_control[i]);
00890   for(i = 0; i < 32; i++)
00891     B2N_32(pgc->subp_control[i]);
00892   for(i = 0; i < 16; i++)
00893     B2N_32(pgc->palette[i]);
00894 
00895   CHECK_ZERO(pgc->zero_1);
00896   CHECK_VALUE(pgc->nr_of_programs <= pgc->nr_of_cells);
00897 
00898   /* verify time (look at print_time) */
00899   for(i = 0; i < 8; i++)
00900     if(!(pgc->audio_control[i] & 0x8000)) /* The 'is present' bit */
00901       CHECK_ZERO(pgc->audio_control[i]);
00902   for(i = 0; i < 32; i++)
00903     if(!(pgc->subp_control[i] & 0x80000000)) /* The 'is present' bit */
00904       CHECK_ZERO(pgc->subp_control[i]);
00905 
00906   /* Check that time is 0:0:0:0 also if nr_of_programs == 0 */
00907   if(pgc->nr_of_programs == 0) {
00908     CHECK_ZERO(pgc->still_time);
00909     CHECK_ZERO(pgc->pg_playback_mode); /* ?? */
00910     CHECK_VALUE(pgc->program_map_offset == 0);
00911     CHECK_VALUE(pgc->cell_playback_offset == 0);
00912     CHECK_VALUE(pgc->cell_position_offset == 0);
00913   } else {
00914     CHECK_VALUE(pgc->program_map_offset != 0);
00915     CHECK_VALUE(pgc->cell_playback_offset != 0);
00916     CHECK_VALUE(pgc->cell_position_offset != 0);
00917   }
00918 
00919   if(pgc->command_tbl_offset != 0) {
00920     pgc->command_tbl = malloc(sizeof(pgc_command_tbl_t));
00921     if(!pgc->command_tbl)
00922       return 0;
00923 
00924     if(!ifoRead_PGC_COMMAND_TBL(ifofile, pgc->command_tbl,
00925                                 offset + pgc->command_tbl_offset)) {
00926       free(pgc->command_tbl);
00927       return 0;
00928     }
00929   } else {
00930     pgc->command_tbl = NULL;
00931   }
00932 
00933   if(pgc->program_map_offset != 0 && pgc->nr_of_programs>0) {
00934     pgc->program_map = malloc(pgc->nr_of_programs * sizeof(pgc_program_map_t));
00935     if(!pgc->program_map) {
00936       ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
00937       return 0;
00938     }
00939     if(!ifoRead_PGC_PROGRAM_MAP(ifofile, pgc->program_map,pgc->nr_of_programs,
00940                                 offset + pgc->program_map_offset)) {
00941       ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
00942       free(pgc->program_map);
00943       return 0;
00944     }
00945   } else {
00946     pgc->program_map = NULL;
00947   }
00948 
00949   if(pgc->cell_playback_offset != 0 && pgc->nr_of_cells>0) {
00950     pgc->cell_playback = malloc(pgc->nr_of_cells * sizeof(cell_playback_t));
00951     if(!pgc->cell_playback) {
00952       ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
00953       if(pgc->program_map)
00954         free(pgc->program_map);
00955       return 0;
00956     }
00957     if(!ifoRead_CELL_PLAYBACK_TBL(ifofile, pgc->cell_playback,
00958                                   pgc->nr_of_cells,
00959                                   offset + pgc->cell_playback_offset)) {
00960       ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
00961       if(pgc->program_map)
00962         free(pgc->program_map);
00963       free(pgc->cell_playback);
00964       return 0;
00965     }
00966   } else {
00967     pgc->cell_playback = NULL;
00968   }
00969 
00970   if(pgc->cell_position_offset != 0 && pgc->nr_of_cells>0) {
00971     pgc->cell_position = malloc(pgc->nr_of_cells * sizeof(cell_position_t));
00972     if(!pgc->cell_position) {
00973       ifoFree_PGC(pgc);
00974       return 0;
00975     }
00976     if(!ifoRead_CELL_POSITION_TBL(ifofile, pgc->cell_position,
00977                                   pgc->nr_of_cells,
00978                                   offset + pgc->cell_position_offset)) {
00979       ifoFree_PGC(pgc);
00980       return 0;
00981     }
00982   } else {
00983     pgc->cell_position = NULL;
00984   }
00985 
00986   return 1;
00987 }
00988 
00989 int ifoRead_FP_PGC(ifo_handle_t *ifofile) {
00990 
00991   if(!ifofile)
00992     return 0;
00993 
00994   if(!ifofile->vmgi_mat)
00995     return 0;
00996 
00997   /* It seems that first_play_pgc is optional after all. */
00998   ifofile->first_play_pgc = 0;
00999   if(ifofile->vmgi_mat->first_play_pgc == 0)
01000     return 1;
01001 
01002   ifofile->first_play_pgc = (pgc_t *)malloc(sizeof(pgc_t));
01003   if(!ifofile->first_play_pgc)
01004     return 0;
01005 
01006   if(!ifoRead_PGC(ifofile, ifofile->first_play_pgc,
01007                   ifofile->vmgi_mat->first_play_pgc)) {
01008     free(ifofile->first_play_pgc);
01009     ifofile->first_play_pgc = 0;
01010     return 0;
01011   }
01012 
01013   return 1;
01014 }
01015 
01016 static void ifoFree_PGC(pgc_t *pgc) {
01017   if(pgc) {
01018     ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
01019     if(pgc->program_map)
01020       free(pgc->program_map);
01021     if(pgc->cell_playback)
01022       free(pgc->cell_playback);
01023     if(pgc->cell_position)
01024       free(pgc->cell_position);
01025   }
01026 }
01027 
01028 void ifoFree_FP_PGC(ifo_handle_t *ifofile) {
01029   if(!ifofile)
01030     return;
01031 
01032   if(ifofile->first_play_pgc) {
01033     ifoFree_PGC(ifofile->first_play_pgc);
01034     free(ifofile->first_play_pgc);
01035     ifofile->first_play_pgc = 0;
01036   }
01037 }
01038 
01039 
01040 int ifoRead_TT_SRPT(ifo_handle_t *ifofile) {
01041   tt_srpt_t *tt_srpt;
01042   int i, info_length;
01043 
01044   if(!ifofile)
01045     return 0;
01046 
01047   if(!ifofile->vmgi_mat)
01048     return 0;
01049 
01050   if(ifofile->vmgi_mat->tt_srpt == 0) /* mandatory */
01051     return 0;
01052 
01053   if(!DVDFileSeek_(ifofile->file, ifofile->vmgi_mat->tt_srpt * DVD_BLOCK_LEN))
01054     return 0;
01055 
01056   tt_srpt = (tt_srpt_t *)malloc(sizeof(tt_srpt_t));
01057   if(!tt_srpt)
01058     return 0;
01059 
01060   ifofile->tt_srpt = tt_srpt;
01061 
01062   if(!(DVDReadBytes(ifofile->file, tt_srpt, TT_SRPT_SIZE))) {
01063     fprintf(stderr, "libdvdread: Unable to read read TT_SRPT.\n");
01064     free(tt_srpt);
01065     return 0;
01066   }
01067 
01068   B2N_16(tt_srpt->nr_of_srpts);
01069   B2N_32(tt_srpt->last_byte);
01070 
01071   info_length = tt_srpt->last_byte + 1 - TT_SRPT_SIZE;
01072 
01073   tt_srpt->title = (title_info_t *)malloc(info_length);
01074   if(!tt_srpt->title) {
01075     free(tt_srpt);
01076     ifofile->tt_srpt = 0;
01077     return 0;
01078   }
01079   if(!(DVDReadBytes(ifofile->file, tt_srpt->title, info_length))) {
01080     fprintf(stderr, "libdvdread: Unable to read read TT_SRPT.\n");
01081     ifoFree_TT_SRPT(ifofile);
01082     return 0;
01083   }
01084 
01085   for(i =  0; i < tt_srpt->nr_of_srpts; i++) {
01086     B2N_16(tt_srpt->title[i].nr_of_ptts);
01087     B2N_16(tt_srpt->title[i].parental_id);
01088     B2N_32(tt_srpt->title[i].title_set_sector);
01089   }
01090 
01091 
01092   CHECK_ZERO(tt_srpt->zero_1);
01093   CHECK_VALUE(tt_srpt->nr_of_srpts != 0);
01094   CHECK_VALUE(tt_srpt->nr_of_srpts < 100); /* ?? */
01095   CHECK_VALUE((int)tt_srpt->nr_of_srpts * sizeof(title_info_t) <= info_length);
01096 
01097   for(i = 0; i < tt_srpt->nr_of_srpts; i++) {
01098     read_playback_type(&tt_srpt->title[i].pb_ty);
01099     CHECK_VALUE(tt_srpt->title[i].pb_ty.zero_1 == 0);
01100     CHECK_VALUE(tt_srpt->title[i].nr_of_angles != 0);
01101     CHECK_VALUE(tt_srpt->title[i].nr_of_angles < 10);
01102     /* CHECK_VALUE(tt_srpt->title[i].nr_of_ptts != 0); */
01103     /* XXX: this assertion breaks Ghostbusters: */
01104     CHECK_VALUE(tt_srpt->title[i].nr_of_ptts < 1000); /* ?? */
01105     CHECK_VALUE(tt_srpt->title[i].title_set_nr != 0);
01106     CHECK_VALUE(tt_srpt->title[i].title_set_nr < 100); /* ?? */
01107     CHECK_VALUE(tt_srpt->title[i].vts_ttn != 0);
01108     CHECK_VALUE(tt_srpt->title[i].vts_ttn < 100); /* ?? */
01109     /* CHECK_VALUE(tt_srpt->title[i].title_set_sector != 0); */
01110   }
01111 
01112   /* Make this a function */
01113 #if 0
01114   if(memcmp((uint8_t *)tt_srpt->title +
01115             tt_srpt->nr_of_srpts * sizeof(title_info_t),
01116             my_friendly_zeros,
01117             info_length - tt_srpt->nr_of_srpts * sizeof(title_info_t))) {
01118     fprintf(stderr, "VMG_PTT_SRPT slack is != 0, ");
01119     hexdump((uint8_t *)tt_srpt->title +
01120             tt_srpt->nr_of_srpts * sizeof(title_info_t),
01121             info_length - tt_srpt->nr_of_srpts * sizeof(title_info_t));
01122   }
01123 #endif
01124 
01125   return 1;
01126 }
01127 
01128 
01129 void ifoFree_TT_SRPT(ifo_handle_t *ifofile) {
01130   if(!ifofile)
01131     return;
01132 
01133   if(ifofile->tt_srpt) {
01134     free(ifofile->tt_srpt->title);
01135     free(ifofile->tt_srpt);
01136     ifofile->tt_srpt = 0;
01137   }
01138 }
01139 
01140 
01141 int ifoRead_VTS_PTT_SRPT(ifo_handle_t *ifofile) {
01142   vts_ptt_srpt_t *vts_ptt_srpt = NULL;
01143   int info_length, i, j;
01144   uint32_t *data = NULL;
01145 
01146   if(!ifofile)
01147     return 0;
01148 
01149   if(!ifofile->vtsi_mat)
01150     return 0;
01151 
01152   if(ifofile->vtsi_mat->vts_ptt_srpt == 0) /* mandatory */
01153     return 0;
01154 
01155   if(!DVDFileSeek_(ifofile->file,
01156                    ifofile->vtsi_mat->vts_ptt_srpt * DVD_BLOCK_LEN))
01157     return 0;
01158 
01159   vts_ptt_srpt = malloc(sizeof(vts_ptt_srpt_t));
01160   if(!vts_ptt_srpt)
01161     return 0;
01162 
01163   vts_ptt_srpt->title = NULL;
01164   ifofile->vts_ptt_srpt = vts_ptt_srpt;
01165 
01166   if(!(DVDReadBytes(ifofile->file, vts_ptt_srpt, VTS_PTT_SRPT_SIZE))) {
01167     fprintf(stderr, "libdvdread: Unable to read PTT search table.\n");
01168     goto fail;
01169   }
01170 
01171   B2N_16(vts_ptt_srpt->nr_of_srpts);
01172   B2N_32(vts_ptt_srpt->last_byte);
01173 
01174   CHECK_ZERO(vts_ptt_srpt->zero_1);
01175   CHECK_VALUE(vts_ptt_srpt->nr_of_srpts != 0);
01176   CHECK_VALUE(vts_ptt_srpt->nr_of_srpts < 100); /* ?? */
01177 
01178   info_length = vts_ptt_srpt->last_byte + 1 - VTS_PTT_SRPT_SIZE;
01179   data = malloc(info_length);
01180   if(!data)
01181     goto fail;
01182 
01183   if(!(DVDReadBytes(ifofile->file, data, info_length))) {
01184     fprintf(stderr, "libdvdread: Unable to read PTT search table.\n");
01185     goto fail;
01186   }
01187 
01188   if(vts_ptt_srpt->nr_of_srpts > info_length / sizeof(*data)) {
01189     fprintf(stderr, "libdvdread: PTT search table too small.\n");
01190     goto fail;
01191   }
01192   for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) {
01193     B2N_32(data[i]);
01194     /* assert(data[i] + sizeof(ptt_info_t) <= vts_ptt_srpt->last_byte + 1);
01195        Magic Knight Rayearth Daybreak is mastered very strange and has
01196        Titles with 0 PTTs. They all have a data[i] offsets beyond the end of
01197        of the vts_ptt_srpt structure. */
01198     CHECK_VALUE(data[i] + sizeof(ptt_info_t) <= vts_ptt_srpt->last_byte + 1 + 4);
01199   }
01200 
01201   vts_ptt_srpt->ttu_offset = data;
01202 
01203   vts_ptt_srpt->title = malloc(vts_ptt_srpt->nr_of_srpts * sizeof(ttu_t));
01204   if(!vts_ptt_srpt->title)
01205     goto fail;
01206 
01207   for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) {
01208     int n;
01209     if(i < vts_ptt_srpt->nr_of_srpts - 1)
01210       n = (data[i+1] - data[i]);
01211     else
01212       n = (vts_ptt_srpt->last_byte + 1 - data[i]);
01213 
01214     /* assert(n > 0 && (n % 4) == 0);
01215        Magic Knight Rayearth Daybreak is mastered very strange and has
01216        Titles with 0 PTTs. */
01217     if(n < 0) n = 0;
01218 
01219     CHECK_VALUE(n % 4 == 0);
01220 
01221     vts_ptt_srpt->title[i].nr_of_ptts = n / 4;
01222     vts_ptt_srpt->title[i].ptt = malloc(n * sizeof(ptt_info_t));
01223     if(!vts_ptt_srpt->title[i].ptt) {
01224       for(n = 0; n < i; n++)
01225         free(vts_ptt_srpt->title[n].ptt);
01226 
01227       goto fail;
01228     }
01229     for(j = 0; j < vts_ptt_srpt->title[i].nr_of_ptts; j++) {
01230       /* The assert placed here because of Magic Knight Rayearth Daybreak */
01231       CHECK_VALUE(data[i] + sizeof(ptt_info_t) <= vts_ptt_srpt->last_byte + 1);
01232       vts_ptt_srpt->title[i].ptt[j].pgcn
01233         = *(uint16_t*)(((char *)data) + data[i] + 4*j - VTS_PTT_SRPT_SIZE);
01234       vts_ptt_srpt->title[i].ptt[j].pgn
01235         = *(uint16_t*)(((char *)data) + data[i] + 4*j + 2 - VTS_PTT_SRPT_SIZE);
01236     }
01237   }
01238 
01239   for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) {
01240     for(j = 0; j < vts_ptt_srpt->title[i].nr_of_ptts; j++) {
01241       B2N_16(vts_ptt_srpt->title[i].ptt[j].pgcn);
01242       B2N_16(vts_ptt_srpt->title[i].ptt[j].pgn);
01243     }
01244   }
01245 
01246   for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) {
01247     CHECK_VALUE(vts_ptt_srpt->title[i].nr_of_ptts < 1000); /* ?? */
01248     for(j = 0; j < vts_ptt_srpt->title[i].nr_of_ptts; j++) {
01249       CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgcn != 0 );
01250       CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgcn < 1000); /* ?? */
01251       CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgn != 0);
01252       CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgn < 100); /* ?? */
01253     }
01254   }
01255 
01256   return 1;
01257 
01258 fail:
01259   free(data);
01260   ifofile->vts_ptt_srpt = 0;
01261   free(vts_ptt_srpt->title);
01262   free(vts_ptt_srpt);
01263   return 0;
01264 }
01265 
01266 
01267 void ifoFree_VTS_PTT_SRPT(ifo_handle_t *ifofile) {
01268   if(!ifofile)
01269     return;
01270 
01271   if(ifofile->vts_ptt_srpt) {
01272     int i;
01273     for(i = 0; i < ifofile->vts_ptt_srpt->nr_of_srpts; i++)
01274       free(ifofile->vts_ptt_srpt->title[i].ptt);
01275     free(ifofile->vts_ptt_srpt->ttu_offset);
01276     free(ifofile->vts_ptt_srpt->title);
01277     free(ifofile->vts_ptt_srpt);
01278     ifofile->vts_ptt_srpt = 0;
01279   }
01280 }
01281 
01282 
01283 int ifoRead_PTL_MAIT(ifo_handle_t *ifofile) {
01284   ptl_mait_t *ptl_mait;
01285   int info_length;
01286   unsigned int i, j;
01287 
01288   if(!ifofile)
01289     return 0;
01290 
01291   if(!ifofile->vmgi_mat)
01292     return 0;
01293 
01294   if(ifofile->vmgi_mat->ptl_mait == NULL)
01295     return 1;
01296 
01297   if(!DVDFileSeek_(ifofile->file, ifofile->vmgi_mat->ptl_mait * DVD_BLOCK_LEN))
01298     return 0;
01299 
01300   ptl_mait = (ptl_mait_t *)malloc(sizeof(ptl_mait_t));
01301   if(!ptl_mait)
01302     return 0;
01303 
01304   ifofile->ptl_mait = ptl_mait;
01305 
01306   if(!(DVDReadBytes(ifofile->file, ptl_mait, PTL_MAIT_SIZE))) {
01307     free(ptl_mait);
01308     ifofile->ptl_mait = NULL;
01309     return 0;
01310   }
01311 
01312   B2N_16(ptl_mait->nr_of_countries);
01313   B2N_16(ptl_mait->nr_of_vtss);
01314   B2N_32(ptl_mait->last_byte);
01315 
01316   CHECK_VALUE(ptl_mait->nr_of_countries != 0);
01317   CHECK_VALUE(ptl_mait->nr_of_countries < 100); /* ?? */
01318   CHECK_VALUE(ptl_mait->nr_of_vtss != 0);
01319   CHECK_VALUE(ptl_mait->nr_of_vtss < 100); /* ?? */
01320   CHECK_VALUE(ptl_mait->nr_of_countries * PTL_MAIT_COUNTRY_SIZE
01321               <= ptl_mait->last_byte + 1 - PTL_MAIT_SIZE);
01322 
01323   info_length = ptl_mait->nr_of_countries * sizeof(ptl_mait_country_t);
01324   ptl_mait->countries = (ptl_mait_country_t *)malloc(info_length);
01325   if(!ptl_mait->countries) {
01326     free(ptl_mait);
01327     ifofile->ptl_mait = NULL;
01328     return 0;
01329   }
01330   for(i = 0; i < ptl_mait->nr_of_countries; i++) {
01331     ptl_mait->countries[i].pf_ptl_mai = NULL;
01332   }
01333 
01334   for(i = 0; i < ptl_mait->nr_of_countries; i++) {
01335     if(!(DVDReadBytes(ifofile->file, &ptl_mait->countries[i], PTL_MAIT_COUNTRY_SIZE))) {
01336       fprintf(stderr, "libdvdread: Unable to read PTL_MAIT.\n");
01337       free(ptl_mait->countries);
01338       free(ptl_mait);
01339       ifofile->ptl_mait = NULL;
01340       return 0;
01341     }
01342   }
01343 
01344   for(i = 0; i < ptl_mait->nr_of_countries; i++) {
01345     B2N_16(ptl_mait->countries[i].country_code);
01346     B2N_16(ptl_mait->countries[i].pf_ptl_mai_start_byte);
01347   }
01348 
01349   for(i = 0; i < ptl_mait->nr_of_countries; i++) {
01350     CHECK_ZERO(ptl_mait->countries[i].zero_1);
01351     CHECK_ZERO(ptl_mait->countries[i].zero_2);
01352     CHECK_VALUE(ptl_mait->countries[i].pf_ptl_mai_start_byte
01353                 + sizeof(pf_level_t) * (ptl_mait->nr_of_vtss + 1) <= ptl_mait->last_byte + 1);
01354   }
01355 
01356   for(i = 0; i < ptl_mait->nr_of_countries; i++) {
01357     uint16_t *pf_temp;
01358 
01359     if(!DVDFileSeek_(ifofile->file,
01360                      ifofile->vmgi_mat->ptl_mait * DVD_BLOCK_LEN
01361                      + ptl_mait->countries[i].pf_ptl_mai_start_byte)) {
01362       fprintf(stderr, "libdvdread: Unable to seek PTL_MAIT table at index %d.\n",i);
01363       free(ptl_mait->countries);
01364       free(ptl_mait);
01365       ifofile->ptl_mait = NULL;
01366       return 0;
01367     }
01368     info_length = (ptl_mait->nr_of_vtss + 1) * sizeof(pf_level_t);
01369     pf_temp = (uint16_t *)malloc(info_length);
01370     if(!pf_temp) {
01371       free_ptl_mait(ptl_mait, i);
01372       ifofile->ptl_mait = NULL;
01373       return 0;
01374     }
01375     if(!(DVDReadBytes(ifofile->file, pf_temp, info_length))) {
01376       fprintf(stderr, "libdvdread: Unable to read PTL_MAIT table at index %d.\n",i);
01377       free(pf_temp);
01378       free_ptl_mait(ptl_mait, i);
01379       ifofile->ptl_mait = NULL;
01380       return 0;
01381     }
01382     for (j = 0; j < ((ptl_mait->nr_of_vtss + 1) * 8); j++) {
01383       B2N_16(pf_temp[j]);
01384     }
01385     ptl_mait->countries[i].pf_ptl_mai = (pf_level_t *)malloc(info_length);
01386     if(!ptl_mait->countries[i].pf_ptl_mai) {
01387       free(pf_temp);
01388       free_ptl_mait(ptl_mait, i);
01389       ifofile->ptl_mait = NULL;
01390       return 0;
01391     }
01392     { /* Transpose the array so we can use C indexing. */
01393       int level, vts;
01394       for(level = 0; level < PTL_MAIT_NUM_LEVEL; level++) {
01395         for(vts = 0; vts <= ptl_mait->nr_of_vtss; vts++) {
01396           ptl_mait->countries[i].pf_ptl_mai[vts][level] =
01397             pf_temp[(7-level)*(ptl_mait->nr_of_vtss+1) + vts];
01398         }
01399       }
01400       free(pf_temp);
01401     }
01402   }
01403   return 1;
01404 }
01405 
01406 void ifoFree_PTL_MAIT(ifo_handle_t *ifofile) {
01407   unsigned int i;
01408 
01409   if(!ifofile)
01410     return;
01411 
01412   if(ifofile->ptl_mait) {
01413     for(i = 0; i < ifofile->ptl_mait->nr_of_countries; i++) {
01414       free(ifofile->ptl_mait->countries[i].pf_ptl_mai);
01415     }
01416     free(ifofile->ptl_mait->countries);
01417     free(ifofile->ptl_mait);
01418     ifofile->ptl_mait = NULL;
01419   }
01420 }
01421 
01422 int ifoRead_VTS_TMAPT(ifo_handle_t *ifofile) {
01423   vts_tmapt_t *vts_tmapt;
01424   uint32_t *vts_tmap_srp;
01425   unsigned int offset;
01426   int info_length;
01427   unsigned int i, j;
01428 
01429   if(!ifofile)
01430     return 0;
01431 
01432   if(!ifofile->vtsi_mat)
01433     return 0;
01434 
01435   if(ifofile->vtsi_mat->vts_tmapt == 0) { /* optional(?) */
01436     ifofile->vts_tmapt = NULL;
01437     fprintf(stderr,"Please send bug report - no VTS_TMAPT ?? \n");
01438     return 1;
01439   }
01440 
01441   offset = ifofile->vtsi_mat->vts_tmapt * DVD_BLOCK_LEN;
01442 
01443   if(!DVDFileSeek_(ifofile->file, offset))
01444     return 0;
01445 
01446   vts_tmapt = (vts_tmapt_t *)malloc(sizeof(vts_tmapt_t));
01447   if(!vts_tmapt)
01448     return 0;
01449 
01450   ifofile->vts_tmapt = vts_tmapt;
01451 
01452   if(!(DVDReadBytes(ifofile->file, vts_tmapt, VTS_TMAPT_SIZE))) {
01453     fprintf(stderr, "libdvdread: Unable to read VTS_TMAPT.\n");
01454     free(vts_tmapt);
01455     ifofile->vts_tmapt = NULL;
01456     return 0;
01457   }
01458 
01459   B2N_16(vts_tmapt->nr_of_tmaps);
01460   B2N_32(vts_tmapt->last_byte);
01461 
01462   CHECK_ZERO(vts_tmapt->zero_1);
01463 
01464   info_length = vts_tmapt->nr_of_tmaps * 4;
01465 
01466   vts_tmap_srp = (uint32_t *)malloc(info_length);
01467   if(!vts_tmap_srp) {
01468     free(vts_tmapt);
01469     ifofile->vts_tmapt = NULL;
01470     return 0;
01471   }
01472 
01473   vts_tmapt->tmap_offset = vts_tmap_srp;
01474 
01475   if(!(DVDReadBytes(ifofile->file, vts_tmap_srp, info_length))) {
01476     fprintf(stderr, "libdvdread: Unable to read VTS_TMAPT.\n");
01477     free(vts_tmap_srp);
01478     free(vts_tmapt);
01479     ifofile->vts_tmapt = NULL;
01480     return 0;
01481   }
01482 
01483   for (i = 0; i < vts_tmapt->nr_of_tmaps; i++) {
01484     B2N_32(vts_tmap_srp[i]);
01485   }
01486 
01487 
01488   info_length = vts_tmapt->nr_of_tmaps * sizeof(vts_tmap_t);
01489 
01490   vts_tmapt->tmap = (vts_tmap_t *)malloc(info_length);
01491   if(!vts_tmapt->tmap) {
01492     free(vts_tmap_srp);
01493     free(vts_tmapt);
01494     ifofile->vts_tmapt = NULL;
01495     return 0;
01496   }
01497 
01498   memset(vts_tmapt->tmap, 0, info_length); /* So ifoFree_VTS_TMAPT works. */
01499 
01500   for(i = 0; i < vts_tmapt->nr_of_tmaps; i++) {
01501     if(!DVDFileSeek_(ifofile->file, offset + vts_tmap_srp[i])) {
01502       ifoFree_VTS_TMAPT(ifofile);
01503       return 0;
01504     }
01505 
01506     if(!(DVDReadBytes(ifofile->file, &vts_tmapt->tmap[i], VTS_TMAP_SIZE))) {
01507       fprintf(stderr, "libdvdread: Unable to read VTS_TMAP.\n");
01508       ifoFree_VTS_TMAPT(ifofile);
01509       return 0;
01510     }
01511 
01512     B2N_16(vts_tmapt->tmap[i].nr_of_entries);
01513     CHECK_ZERO(vts_tmapt->tmap[i].zero_1);
01514 
01515     if(vts_tmapt->tmap[i].nr_of_entries == 0) { /* Early out if zero entries */
01516       vts_tmapt->tmap[i].map_ent = NULL;
01517       continue;
01518     }
01519 
01520     info_length = vts_tmapt->tmap[i].nr_of_entries * sizeof(map_ent_t);
01521 
01522     vts_tmapt->tmap[i].map_ent = (map_ent_t *)malloc(info_length);
01523     if(!vts_tmapt->tmap[i].map_ent) {
01524       ifoFree_VTS_TMAPT(ifofile);
01525       return 0;
01526     }
01527 
01528     if(!(DVDReadBytes(ifofile->file, vts_tmapt->tmap[i].map_ent, info_length))) {
01529       fprintf(stderr, "libdvdread: Unable to read VTS_TMAP_ENT.\n");
01530       ifoFree_VTS_TMAPT(ifofile);
01531       return 0;
01532     }
01533 
01534     for(j = 0; j < vts_tmapt->tmap[i].nr_of_entries; j++)
01535       B2N_32(vts_tmapt->tmap[i].map_ent[j]);
01536   }
01537 
01538   return 1;
01539 }
01540 
01541 void ifoFree_VTS_TMAPT(ifo_handle_t *ifofile) {
01542   unsigned int i;
01543 
01544   if(!ifofile)
01545     return;
01546 
01547   if(ifofile->vts_tmapt) {
01548     for(i = 0; i < ifofile->vts_tmapt->nr_of_tmaps; i++)
01549       if(ifofile->vts_tmapt->tmap[i].map_ent)
01550         free(ifofile->vts_tmapt->tmap[i].map_ent);
01551     free(ifofile->vts_tmapt->tmap);
01552     free(ifofile->vts_tmapt->tmap_offset);
01553     free(ifofile->vts_tmapt);
01554     ifofile->vts_tmapt = NULL;
01555   }
01556 }
01557 
01558 
01559 int ifoRead_TITLE_C_ADT(ifo_handle_t *ifofile) {
01560 
01561   if(!ifofile)
01562     return 0;
01563 
01564   if(!ifofile->vtsi_mat)
01565     return 0;
01566 
01567   if(ifofile->vtsi_mat->vts_c_adt == 0) /* mandatory */
01568     return 0;
01569 
01570   ifofile->vts_c_adt = (c_adt_t *)malloc(sizeof(c_adt_t));
01571   if(!ifofile->vts_c_adt)
01572     return 0;
01573 
01574   if(!ifoRead_C_ADT_internal(ifofile, ifofile->vts_c_adt,
01575                              ifofile->vtsi_mat->vts_c_adt)) {
01576     free(ifofile->vts_c_adt);
01577     ifofile->vts_c_adt = 0;
01578     return 0;
01579   }
01580 
01581   return 1;
01582 }
01583 
01584 int ifoRead_C_ADT(ifo_handle_t *ifofile) {
01585   unsigned int sector;
01586 
01587   if(!ifofile)
01588     return 0;
01589 
01590   if(ifofile->vmgi_mat) {
01591     if(ifofile->vmgi_mat->vmgm_c_adt == 0)
01592       return 1;
01593     sector = ifofile->vmgi_mat->vmgm_c_adt;
01594   } else if(ifofile->vtsi_mat) {
01595     if(ifofile->vtsi_mat->vtsm_c_adt == 0)
01596       return 1;
01597     sector = ifofile->vtsi_mat->vtsm_c_adt;
01598   } else {
01599     return 0;
01600   }
01601 
01602   ifofile->menu_c_adt = (c_adt_t *)malloc(sizeof(c_adt_t));
01603   if(!ifofile->menu_c_adt)
01604     return 0;
01605 
01606   if(!ifoRead_C_ADT_internal(ifofile, ifofile->menu_c_adt, sector)) {
01607     free(ifofile->menu_c_adt);
01608     ifofile->menu_c_adt = 0;
01609     return 0;
01610   }
01611 
01612   return 1;
01613 }
01614 
01615 static int ifoRead_C_ADT_internal(ifo_handle_t *ifofile,
01616                                   c_adt_t *c_adt, unsigned int sector) {
01617   int i, info_length;
01618 
01619   if(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN))
01620     return 0;
01621 
01622   if(!(DVDReadBytes(ifofile->file, c_adt, C_ADT_SIZE)))
01623     return 0;
01624 
01625   B2N_16(c_adt->nr_of_vobs);
01626   B2N_32(c_adt->last_byte);
01627 
01628   info_length = c_adt->last_byte + 1 - C_ADT_SIZE;
01629 
01630   CHECK_ZERO(c_adt->zero_1);
01631   /* assert(c_adt->nr_of_vobs > 0);
01632      Magic Knight Rayearth Daybreak is mastered very strange and has
01633      Titles with a VOBS that has no cells. */
01634   CHECK_VALUE(info_length % sizeof(cell_adr_t) == 0);
01635 
01636   /* assert(info_length / sizeof(cell_adr_t) >= c_adt->nr_of_vobs);
01637      Enemy of the State region 2 (de) has Titles where nr_of_vobs field
01638      is to high, they high ones are never referenced though. */
01639   if(info_length / sizeof(cell_adr_t) < c_adt->nr_of_vobs) {
01640     fprintf(stderr, "libdvdread: *C_ADT nr_of_vobs > available info entries\n");
01641     c_adt->nr_of_vobs = info_length / sizeof(cell_adr_t);
01642   }
01643 
01644   c_adt->cell_adr_table = (cell_adr_t *)malloc(info_length);
01645   if(!c_adt->cell_adr_table)
01646     return 0;
01647 
01648   if(info_length &&
01649      !(DVDReadBytes(ifofile->file, c_adt->cell_adr_table, info_length))) {
01650     free(c_adt->cell_adr_table);
01651     return 0;
01652   }
01653 
01654   for(i = 0; i < info_length/sizeof(cell_adr_t); i++) {
01655     B2N_16(c_adt->cell_adr_table[i].vob_id);
01656     B2N_32(c_adt->cell_adr_table[i].start_sector);
01657     B2N_32(c_adt->cell_adr_table[i].last_sector);
01658 
01659     CHECK_ZERO(c_adt->cell_adr_table[i].zero_1);
01660     CHECK_VALUE(c_adt->cell_adr_table[i].vob_id > 0);
01661     CHECK_VALUE(c_adt->cell_adr_table[i].vob_id <= c_adt->nr_of_vobs);
01662     CHECK_VALUE(c_adt->cell_adr_table[i].cell_id > 0);
01663     CHECK_VALUE(c_adt->cell_adr_table[i].start_sector <
01664                 c_adt->cell_adr_table[i].last_sector);
01665   }
01666 
01667   return 1;
01668 }
01669 
01670 
01671 static void ifoFree_C_ADT_internal(c_adt_t *c_adt) {
01672   if(c_adt) {
01673     free(c_adt->cell_adr_table);
01674     free(c_adt);
01675   }
01676 }
01677 
01678 void ifoFree_C_ADT(ifo_handle_t *ifofile) {
01679   if(!ifofile)
01680     return;
01681 
01682   ifoFree_C_ADT_internal(ifofile->menu_c_adt);
01683   ifofile->menu_c_adt = 0;
01684 }
01685 
01686 void ifoFree_TITLE_C_ADT(ifo_handle_t *ifofile) {
01687   if(!ifofile)
01688     return;
01689 
01690   ifoFree_C_ADT_internal(ifofile->vts_c_adt);
01691   ifofile->vts_c_adt = 0;
01692 }
01693 
01694 int ifoRead_TITLE_VOBU_ADMAP(ifo_handle_t *ifofile) {
01695   if(!ifofile)
01696     return 0;
01697 
01698   if(!ifofile->vtsi_mat)
01699     return 0;
01700 
01701   if(ifofile->vtsi_mat->vts_vobu_admap == 0) /* mandatory */
01702     return 0;
01703 
01704   ifofile->vts_vobu_admap = (vobu_admap_t *)malloc(sizeof(vobu_admap_t));
01705   if(!ifofile->vts_vobu_admap)
01706     return 0;
01707 
01708   if(!ifoRead_VOBU_ADMAP_internal(ifofile, ifofile->vts_vobu_admap,
01709                                   ifofile->vtsi_mat->vts_vobu_admap)) {
01710     free(ifofile->vts_vobu_admap);
01711     ifofile->vts_vobu_admap = 0;
01712     return 0;
01713   }
01714 
01715   return 1;
01716 }
01717 
01718 int ifoRead_VOBU_ADMAP(ifo_handle_t *ifofile) {
01719   unsigned int sector;
01720 
01721   if(!ifofile)
01722     return 0;
01723 
01724   if(ifofile->vmgi_mat) {
01725     if(ifofile->vmgi_mat->vmgm_vobu_admap == 0)
01726       return 1;
01727     sector = ifofile->vmgi_mat->vmgm_vobu_admap;
01728   } else if(ifofile->vtsi_mat) {
01729     if(ifofile->vtsi_mat->vtsm_vobu_admap == 0)
01730       return 1;
01731     sector = ifofile->vtsi_mat->vtsm_vobu_admap;
01732   } else {
01733     return 0;
01734   }
01735 
01736   ifofile->menu_vobu_admap = (vobu_admap_t *)malloc(sizeof(vobu_admap_t));
01737   if(!ifofile->menu_vobu_admap)
01738     return 0;
01739 
01740   if(!ifoRead_VOBU_ADMAP_internal(ifofile, ifofile->menu_vobu_admap, sector)) {
01741     free(ifofile->menu_vobu_admap);
01742     ifofile->menu_vobu_admap = 0;
01743     return 0;
01744   }
01745 
01746   return 1;
01747 }
01748 
01749 static int ifoRead_VOBU_ADMAP_internal(ifo_handle_t *ifofile,
01750                                        vobu_admap_t *vobu_admap,
01751                                        unsigned int sector) {
01752   unsigned int i;
01753   int info_length;
01754 
01755   if(!DVDFileSeekForce_(ifofile->file, sector * DVD_BLOCK_LEN, sector))
01756     return 0;
01757 
01758   if(!(DVDReadBytes(ifofile->file, vobu_admap, VOBU_ADMAP_SIZE)))
01759     return 0;
01760 
01761   B2N_32(vobu_admap->last_byte);
01762 
01763   info_length = vobu_admap->last_byte + 1 - VOBU_ADMAP_SIZE;
01764   /* assert(info_length > 0);
01765      Magic Knight Rayearth Daybreak is mastered very strange and has
01766      Titles with a VOBS that has no VOBUs. */
01767   CHECK_VALUE(info_length % sizeof(uint32_t) == 0);
01768 
01769   vobu_admap->vobu_start_sectors = (uint32_t *)malloc(info_length);
01770   if(!vobu_admap->vobu_start_sectors) {
01771     return 0;
01772   }
01773   if(info_length &&
01774      !(DVDReadBytes(ifofile->file,
01775                     vobu_admap->vobu_start_sectors, info_length))) {
01776     free(vobu_admap->vobu_start_sectors);
01777     return 0;
01778   }
01779 
01780   for(i = 0; i < info_length/sizeof(uint32_t); i++)
01781     B2N_32(vobu_admap->vobu_start_sectors[i]);
01782 
01783   return 1;
01784 }
01785 
01786 
01787 static void ifoFree_VOBU_ADMAP_internal(vobu_admap_t *vobu_admap) {
01788   if(vobu_admap) {
01789     free(vobu_admap->vobu_start_sectors);
01790     free(vobu_admap);
01791   }
01792 }
01793 
01794 void ifoFree_VOBU_ADMAP(ifo_handle_t *ifofile) {
01795   if(!ifofile)
01796     return;
01797 
01798   ifoFree_VOBU_ADMAP_internal(ifofile->menu_vobu_admap);
01799   ifofile->menu_vobu_admap = 0;
01800 }
01801 
01802 void ifoFree_TITLE_VOBU_ADMAP(ifo_handle_t *ifofile) {
01803   if(!ifofile)
01804     return;
01805 
01806   ifoFree_VOBU_ADMAP_internal(ifofile->vts_vobu_admap);
01807   ifofile->vts_vobu_admap = 0;
01808 }
01809 
01810 int ifoRead_PGCIT(ifo_handle_t *ifofile) {
01811 
01812   if(!ifofile)
01813     return 0;
01814 
01815   if(!ifofile->vtsi_mat)
01816     return 0;
01817 
01818   if(ifofile->vtsi_mat->vts_pgcit == 0) /* mandatory */
01819     return 0;
01820 
01821   ifofile->vts_pgcit = (pgcit_t *)malloc(sizeof(pgcit_t));
01822   if(!ifofile->vts_pgcit)
01823     return 0;
01824 
01825   if(!ifoRead_PGCIT_internal(ifofile, ifofile->vts_pgcit,
01826                              ifofile->vtsi_mat->vts_pgcit * DVD_BLOCK_LEN)) {
01827     free(ifofile->vts_pgcit);
01828     ifofile->vts_pgcit = 0;
01829     return 0;
01830   }
01831 
01832   return 1;
01833 }
01834 
01835 static int ifoRead_PGCIT_internal(ifo_handle_t *ifofile, pgcit_t *pgcit,
01836                                   unsigned int offset) {
01837   int i, info_length;
01838   uint8_t *data, *ptr;
01839 
01840   if(!DVDFileSeek_(ifofile->file, offset))
01841     return 0;
01842 
01843   if(!(DVDReadBytes(ifofile->file, pgcit, PGCIT_SIZE)))
01844     return 0;
01845 
01846   B2N_16(pgcit->nr_of_pgci_srp);
01847   B2N_32(pgcit->last_byte);
01848 
01849   CHECK_ZERO(pgcit->zero_1);
01850   /* assert(pgcit->nr_of_pgci_srp != 0);
01851      Magic Knight Rayearth Daybreak is mastered very strange and has
01852      Titles with 0 PTTs. */
01853   CHECK_VALUE(pgcit->nr_of_pgci_srp < 10000); /* ?? seen max of 1338 */
01854 
01855   info_length = pgcit->nr_of_pgci_srp * PGCI_SRP_SIZE;
01856   data = malloc(info_length);
01857   if(!data)
01858     return 0;
01859 
01860   if(info_length && !(DVDReadBytes(ifofile->file, data, info_length))) {
01861     free(data);
01862     return 0;
01863   }
01864 
01865   pgcit->pgci_srp = malloc(pgcit->nr_of_pgci_srp * sizeof(pgci_srp_t));
01866   if(!pgcit->pgci_srp) {
01867     free(data);
01868     return 0;
01869   }
01870   ptr = data;
01871   for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
01872     memcpy(&pgcit->pgci_srp[i], ptr, PGCI_SRP_SIZE);
01873     ptr += PGCI_SRP_SIZE;
01874     read_pgci_srp(&pgcit->pgci_srp[i]);
01875     CHECK_VALUE(pgcit->pgci_srp[i].unknown1 == 0);
01876   }
01877   free(data);
01878 
01879   for(i = 0; i < pgcit->nr_of_pgci_srp; i++)
01880     CHECK_VALUE(pgcit->pgci_srp[i].pgc_start_byte + PGC_SIZE <= pgcit->last_byte+1);
01881 
01882   for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
01883     pgcit->pgci_srp[i].pgc = malloc(sizeof(pgc_t));
01884     if(!pgcit->pgci_srp[i].pgc) {
01885       int j;
01886       for(j = 0; j < i; j++) {
01887         ifoFree_PGC(pgcit->pgci_srp[j].pgc);
01888         free(pgcit->pgci_srp[j].pgc);
01889       }
01890       goto fail;
01891     }
01892     if(!ifoRead_PGC(ifofile, pgcit->pgci_srp[i].pgc,
01893                     offset + pgcit->pgci_srp[i].pgc_start_byte)) {
01894       int j;
01895       for(j = 0; j < i; j++) {
01896         ifoFree_PGC(pgcit->pgci_srp[j].pgc);
01897         free(pgcit->pgci_srp[j].pgc);
01898       }
01899       free(pgcit->pgci_srp[i].pgc);
01900       goto fail;
01901     }
01902   }
01903 
01904   return 1;
01905 fail:
01906   free(pgcit->pgci_srp);
01907   pgcit->pgci_srp = NULL;
01908   return 0;
01909 }
01910 
01911 static void ifoFree_PGCIT_internal(pgcit_t *pgcit) {
01912   if(pgcit) {
01913     int i;
01914     for(i = 0; i < pgcit->nr_of_pgci_srp; i++)
01915     {
01916       ifoFree_PGC(pgcit->pgci_srp[i].pgc);
01917       free(pgcit->pgci_srp[i].pgc);
01918     }
01919     free(pgcit->pgci_srp);
01920   }
01921 }
01922 
01923 void ifoFree_PGCIT(ifo_handle_t *ifofile) {
01924   if(!ifofile)
01925     return;
01926 
01927   if(ifofile->vts_pgcit) {
01928     ifoFree_PGCIT_internal(ifofile->vts_pgcit);
01929     free(ifofile->vts_pgcit);
01930     ifofile->vts_pgcit = 0;
01931   }
01932 }
01933 
01934 
01935 int ifoRead_PGCI_UT(ifo_handle_t *ifofile) {
01936   pgci_ut_t *pgci_ut;
01937   unsigned int sector;
01938   unsigned int i;
01939   int info_length;
01940   uint8_t *data, *ptr;
01941 
01942   if(!ifofile)
01943     return 0;
01944 
01945   if(ifofile->vmgi_mat) {
01946     if(ifofile->vmgi_mat->vmgm_pgci_ut == 0)
01947       return 1;
01948     sector = ifofile->vmgi_mat->vmgm_pgci_ut;
01949   } else if(ifofile->vtsi_mat) {
01950     if(ifofile->vtsi_mat->vtsm_pgci_ut == 0)
01951       return 1;
01952     sector = ifofile->vtsi_mat->vtsm_pgci_ut;
01953   } else {
01954     return 0;
01955   }
01956 
01957   ifofile->pgci_ut = (pgci_ut_t *)malloc(sizeof(pgci_ut_t));
01958   if(!ifofile->pgci_ut)
01959     return 0;
01960 
01961   if(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN)) {
01962     free(ifofile->pgci_ut);
01963     ifofile->pgci_ut = 0;
01964     return 0;
01965   }
01966 
01967   if(!(DVDReadBytes(ifofile->file, ifofile->pgci_ut, PGCI_UT_SIZE))) {
01968     free(ifofile->pgci_ut);
01969     ifofile->pgci_ut = 0;
01970     return 0;
01971   }
01972 
01973   pgci_ut = ifofile->pgci_ut;
01974 
01975   B2N_16(pgci_ut->nr_of_lus);
01976   B2N_32(pgci_ut->last_byte);
01977 
01978   CHECK_ZERO(pgci_ut->zero_1);
01979   CHECK_VALUE(pgci_ut->nr_of_lus != 0);
01980   CHECK_VALUE(pgci_ut->nr_of_lus < 100); /* ?? 3-4 ? */
01981   CHECK_VALUE((uint32_t)pgci_ut->nr_of_lus * PGCI_LU_SIZE < pgci_ut->last_byte);
01982 
01983   info_length = pgci_ut->nr_of_lus * PGCI_LU_SIZE;
01984   data = malloc(info_length);
01985   if(!data) {
01986     free(pgci_ut);
01987     ifofile->pgci_ut = 0;
01988     return 0;
01989   }
01990   if(!(DVDReadBytes(ifofile->file, data, info_length))) {
01991     free(data);
01992     free(pgci_ut);
01993     ifofile->pgci_ut = 0;
01994     return 0;
01995   }
01996 
01997   pgci_ut->lu = malloc(pgci_ut->nr_of_lus * sizeof(pgci_lu_t));
01998   if(!pgci_ut->lu) {
01999     free(data);
02000     free(pgci_ut);
02001     ifofile->pgci_ut = 0;
02002     return 0;
02003   }
02004   ptr = data;
02005   for(i = 0; i < pgci_ut->nr_of_lus; i++) {
02006     memcpy(&pgci_ut->lu[i], ptr, PGCI_LU_SIZE);
02007     ptr += PGCI_LU_SIZE;
02008     B2N_16(pgci_ut->lu[i].lang_code);
02009     B2N_32(pgci_ut->lu[i].lang_start_byte);
02010   }
02011   free(data);
02012 
02013   for(i = 0; i < pgci_ut->nr_of_lus; i++) {
02014     /* Maybe this is only defined for v1.1 and later titles? */
02015     /* If the bits in 'lu[i].exists' are enumerated abcd efgh then:
02016        VTS_x_yy.IFO        VIDEO_TS.IFO
02017        a == 0x83 "Root"         0x82 "Title"
02018        b == 0x84 "Subpicture"
02019        c == 0x85 "Audio"
02020        d == 0x86 "Angle"
02021        e == 0x87 "PTT"
02022     */
02023     CHECK_VALUE((pgci_ut->lu[i].exists & 0x07) == 0);
02024   }
02025 
02026   for(i = 0; i < pgci_ut->nr_of_lus; i++) {
02027     pgci_ut->lu[i].pgcit = malloc(sizeof(pgcit_t));
02028     if(!pgci_ut->lu[i].pgcit) {
02029       unsigned int j;
02030       for(j = 0; j < i; j++) {
02031         ifoFree_PGCIT_internal(pgci_ut->lu[j].pgcit);
02032         free(pgci_ut->lu[j].pgcit);
02033       }
02034       free(pgci_ut->lu);
02035       free(pgci_ut);
02036       ifofile->pgci_ut = 0;
02037       return 0;
02038     }
02039     if(!ifoRead_PGCIT_internal(ifofile, pgci_ut->lu[i].pgcit,
02040                                sector * DVD_BLOCK_LEN
02041                                + pgci_ut->lu[i].lang_start_byte)) {
02042       unsigned int j;
02043       for(j = 0; j < i; j++) {
02044         ifoFree_PGCIT_internal(pgci_ut->lu[j].pgcit);
02045         free(pgci_ut->lu[j].pgcit);
02046       }
02047       free(pgci_ut->lu[i].pgcit);
02048       free(pgci_ut->lu);
02049       free(pgci_ut);
02050       ifofile->pgci_ut = 0;
02051       return 0;
02052     }
02053     /* FIXME: Iterate and verify that all menus that should exists accordingly
02054      * to pgci_ut->lu[i].exists really do? */
02055   }
02056 
02057   return 1;
02058 }
02059 
02060 
02061 void ifoFree_PGCI_UT(ifo_handle_t *ifofile) {
02062   unsigned int i;
02063 
02064   if(!ifofile)
02065     return;
02066 
02067   if(ifofile->pgci_ut) {
02068     for(i = 0; i < ifofile->pgci_ut->nr_of_lus; i++) {
02069       ifoFree_PGCIT_internal(ifofile->pgci_ut->lu[i].pgcit);
02070       free(ifofile->pgci_ut->lu[i].pgcit);
02071     }
02072     free(ifofile->pgci_ut->lu);
02073     free(ifofile->pgci_ut);
02074     ifofile->pgci_ut = 0;
02075   }
02076 }
02077 
02078 static int ifoRead_VTS_ATTRIBUTES(ifo_handle_t *ifofile,
02079                                   vts_attributes_t *vts_attributes,
02080                                   unsigned int offset) {
02081   unsigned int i;
02082 
02083   if(!DVDFileSeek_(ifofile->file, offset))
02084     return 0;
02085 
02086   if(!(DVDReadBytes(ifofile->file, vts_attributes, sizeof(vts_attributes_t))))
02087     return 0;
02088 
02089   read_video_attr(&vts_attributes->vtsm_vobs_attr);
02090   read_video_attr(&vts_attributes->vtstt_vobs_video_attr);
02091   read_audio_attr(&vts_attributes->vtsm_audio_attr);
02092   for(i=0; i<8; i++)
02093     read_audio_attr(&vts_attributes->vtstt_audio_attr[i]);
02094   read_subp_attr(&vts_attributes->vtsm_subp_attr);
02095   for(i=0; i<32; i++)
02096     read_subp_attr(&vts_attributes->vtstt_subp_attr[i]);
02097   B2N_32(vts_attributes->last_byte);
02098   B2N_32(vts_attributes->vts_cat);
02099 
02100   CHECK_ZERO(vts_attributes->zero_1);
02101   CHECK_ZERO(vts_attributes->zero_2);
02102   CHECK_ZERO(vts_attributes->zero_3);
02103   CHECK_ZERO(vts_attributes->zero_4);
02104   CHECK_ZERO(vts_attributes->zero_5);
02105   CHECK_ZERO(vts_attributes->zero_6);
02106   CHECK_ZERO(vts_attributes->zero_7);
02107   CHECK_VALUE(vts_attributes->nr_of_vtsm_audio_streams <= 1);
02108   CHECK_VALUE(vts_attributes->nr_of_vtsm_subp_streams <= 1);
02109   CHECK_VALUE(vts_attributes->nr_of_vtstt_audio_streams <= 8);
02110   for(i = vts_attributes->nr_of_vtstt_audio_streams; i < 8; i++)
02111     CHECK_ZERO(vts_attributes->vtstt_audio_attr[i]);
02112   CHECK_VALUE(vts_attributes->nr_of_vtstt_subp_streams <= 32);
02113   {
02114     unsigned int nr_coded;
02115     CHECK_VALUE(vts_attributes->last_byte + 1 >= VTS_ATTRIBUTES_MIN_SIZE);
02116     nr_coded = (vts_attributes->last_byte + 1 - VTS_ATTRIBUTES_MIN_SIZE)/6;
02117     /* This is often nr_coded = 70, how do you know how many there really are? */
02118     if(nr_coded > 32) { /* We haven't read more from disk/file anyway */
02119       nr_coded = 32;
02120     }
02121     CHECK_VALUE(vts_attributes->nr_of_vtstt_subp_streams <= nr_coded);
02122     for(i = vts_attributes->nr_of_vtstt_subp_streams; i < nr_coded; i++)
02123       CHECK_ZERO(vts_attributes->vtstt_subp_attr[i]);
02124   }
02125 
02126   return 1;
02127 }
02128 
02129 
02130 
02131 int ifoRead_VTS_ATRT(ifo_handle_t *ifofile) {
02132   vts_atrt_t *vts_atrt;
02133   unsigned int i, info_length, sector;
02134   uint32_t *data;
02135 
02136   if(!ifofile)
02137     return 0;
02138 
02139   if(!ifofile->vmgi_mat)
02140     return 0;
02141 
02142   if(ifofile->vmgi_mat->vts_atrt == 0) /* mandatory */
02143     return 0;
02144 
02145   sector = ifofile->vmgi_mat->vts_atrt;
02146   if(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN))
02147     return 0;
02148 
02149   vts_atrt = (vts_atrt_t *)malloc(sizeof(vts_atrt_t));
02150   if(!vts_atrt)
02151     return 0;
02152 
02153   ifofile->vts_atrt = vts_atrt;
02154 
02155   if(!(DVDReadBytes(ifofile->file, vts_atrt, VTS_ATRT_SIZE))) {
02156     free(vts_atrt);
02157     ifofile->vts_atrt = 0;
02158     return 0;
02159   }
02160 
02161   B2N_16(vts_atrt->nr_of_vtss);
02162   B2N_32(vts_atrt->last_byte);
02163 
02164   CHECK_ZERO(vts_atrt->zero_1);
02165   CHECK_VALUE(vts_atrt->nr_of_vtss != 0);
02166   CHECK_VALUE(vts_atrt->nr_of_vtss < 100); /* ?? */
02167   CHECK_VALUE((uint32_t)vts_atrt->nr_of_vtss * (4 + VTS_ATTRIBUTES_MIN_SIZE) +
02168               VTS_ATRT_SIZE < vts_atrt->last_byte + 1);
02169 
02170   info_length = vts_atrt->nr_of_vtss * sizeof(uint32_t);
02171   data = (uint32_t *)malloc(info_length);
02172   if(!data) {
02173     free(vts_atrt);
02174     ifofile->vts_atrt = 0;
02175     return 0;
02176   }
02177 
02178   vts_atrt->vts_atrt_offsets = data;
02179 
02180   if(!(DVDReadBytes(ifofile->file, data, info_length))) {
02181     free(data);
02182     free(vts_atrt);
02183     ifofile->vts_atrt = 0;
02184     return 0;
02185   }
02186 
02187   for(i = 0; i < vts_atrt->nr_of_vtss; i++) {
02188     B2N_32(data[i]);
02189     CHECK_VALUE(data[i] + VTS_ATTRIBUTES_MIN_SIZE < vts_atrt->last_byte + 1);
02190   }
02191 
02192   info_length = vts_atrt->nr_of_vtss * sizeof(vts_attributes_t);
02193   vts_atrt->vts = (vts_attributes_t *)malloc(info_length);
02194   if(!vts_atrt->vts) {
02195     free(data);
02196     free(vts_atrt);
02197     ifofile->vts_atrt = 0;
02198     return 0;
02199   }
02200   for(i = 0; i < vts_atrt->nr_of_vtss; i++) {
02201     unsigned int offset = data[i];
02202     if(!ifoRead_VTS_ATTRIBUTES(ifofile, &(vts_atrt->vts[i]),
02203                                (sector * DVD_BLOCK_LEN) + offset)) {
02204       free(data);
02205       free(vts_atrt);
02206       ifofile->vts_atrt = 0;
02207       return 0;
02208     }
02209 
02210     /* This assert cant be in ifoRead_VTS_ATTRIBUTES */
02211     CHECK_VALUE(offset + vts_atrt->vts[i].last_byte <= vts_atrt->last_byte + 1);
02212     /* Is this check correct? */
02213   }
02214 
02215   return 1;
02216 }
02217 
02218 
02219 void ifoFree_VTS_ATRT(ifo_handle_t *ifofile) {
02220   if(!ifofile)
02221     return;
02222 
02223   if(ifofile->vts_atrt) {
02224     free(ifofile->vts_atrt->vts);
02225     free(ifofile->vts_atrt->vts_atrt_offsets);
02226     free(ifofile->vts_atrt);
02227     ifofile->vts_atrt = 0;
02228   }
02229 }
02230 
02231 
02232 int ifoRead_TXTDT_MGI(ifo_handle_t *ifofile) {
02233   txtdt_mgi_t *txtdt_mgi;
02234 
02235   if(!ifofile)
02236     return 0;
02237 
02238   if(!ifofile->vmgi_mat)
02239     return 0;
02240 
02241   /* Return successfully if there is nothing to read. */
02242   if(ifofile->vmgi_mat->txtdt_mgi == 0)
02243     return 1;
02244 
02245   if(!DVDFileSeek_(ifofile->file,
02246                    ifofile->vmgi_mat->txtdt_mgi * DVD_BLOCK_LEN))
02247     return 0;
02248 
02249   txtdt_mgi = (txtdt_mgi_t *)malloc(sizeof(txtdt_mgi_t));
02250   if(!txtdt_mgi) {
02251     return 0;
02252   }
02253   ifofile->txtdt_mgi = txtdt_mgi;
02254 
02255   if(!(DVDReadBytes(ifofile->file, txtdt_mgi, TXTDT_MGI_SIZE))) {
02256     fprintf(stderr, "libdvdread: Unable to read TXTDT_MGI.\n");
02257     free(txtdt_mgi);
02258     ifofile->txtdt_mgi = 0;
02259     return 0;
02260   }
02261 
02262   /* fprintf(stderr, "-- Not done yet --\n"); */
02263   return 1;
02264 }
02265 
02266 void ifoFree_TXTDT_MGI(ifo_handle_t *ifofile) {
02267   if(!ifofile)
02268     return;
02269 
02270   if(ifofile->txtdt_mgi) {
02271     free(ifofile->txtdt_mgi);
02272     ifofile->txtdt_mgi = 0;
02273   }
02274 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends