comparison ifo_read.c @ 3:fdbae45c30fc src

moved to src/ the sources files
author nicodvb
date Sun, 01 Jun 2008 15:16:10 +0000
parents
children 056f5573a7dc
comparison
equal deleted inserted replaced
2:a286eb135a1a 3:fdbae45c30fc
1 /*
2 * Copyright (C) 2000, 2001, 2002, 2003
3 * Björn Englund <d4bjorn@dtek.chalmers.se>,
4 * Håkan Hjort <d95hjort@dtek.chalmers.se>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <inttypes.h>
26 #include <string.h>
27
28 #include "bswap.h"
29 #include "ifo_types.h"
30 #include "ifo_read.h"
31 #include "dvd_reader.h"
32 #include "dvdread_internal.h"
33 #include "bitreader.h"
34
35 #ifndef DVD_BLOCK_LEN
36 #define DVD_BLOCK_LEN 2048
37 #endif
38
39 #ifndef NDEBUG
40 #define CHECK_ZERO0(arg) \
41 if(arg != 0) { \
42 fprintf(stderr, "*** Zero check failed in %s:%i\n for %s = 0x%x\n", \
43 __FILE__, __LINE__, # arg, arg); \
44 }
45 #define CHECK_ZERO(arg) \
46 if(memcmp(my_friendly_zeros, &arg, sizeof(arg))) { \
47 unsigned int i_CZ; \
48 fprintf(stderr, "*** Zero check failed in %s:%i\n for %s = 0x", \
49 __FILE__, __LINE__, # arg ); \
50 for(i_CZ = 0; i_CZ < sizeof(arg); i_CZ++) \
51 fprintf(stderr, "%02x", *((uint8_t *)&arg + i_CZ)); \
52 fprintf(stderr, "\n"); \
53 }
54 static const uint8_t my_friendly_zeros[2048];
55 #else
56 #define CHECK_ZERO0(arg) (void)(arg)
57 #define CHECK_ZERO(arg) (void)(arg)
58 #endif
59
60
61 /* Prototypes for internal functions */
62 static int ifoRead_VMG(ifo_handle_t *ifofile);
63 static int ifoRead_VTS(ifo_handle_t *ifofile);
64 static int ifoRead_PGC(ifo_handle_t *ifofile, pgc_t *pgc, unsigned int offset);
65 static int ifoRead_PGC_COMMAND_TBL(ifo_handle_t *ifofile,
66 pgc_command_tbl_t *cmd_tbl,
67 unsigned int offset);
68 static int ifoRead_PGC_PROGRAM_MAP(ifo_handle_t *ifofile,
69 pgc_program_map_t *program_map,
70 unsigned int nr, unsigned int offset);
71 static int ifoRead_CELL_PLAYBACK_TBL(ifo_handle_t *ifofile,
72 cell_playback_t *cell_playback,
73 unsigned int nr, unsigned int offset);
74 static int ifoRead_CELL_POSITION_TBL(ifo_handle_t *ifofile,
75 cell_position_t *cell_position,
76 unsigned int nr, unsigned int offset);
77 static int ifoRead_VTS_ATTRIBUTES(ifo_handle_t *ifofile,
78 vts_attributes_t *vts_attributes,
79 unsigned int offset);
80 static int ifoRead_C_ADT_internal(ifo_handle_t *ifofile, c_adt_t *c_adt,
81 unsigned int sector);
82 static int ifoRead_VOBU_ADMAP_internal(ifo_handle_t *ifofile,
83 vobu_admap_t *vobu_admap,
84 unsigned int sector);
85 static int ifoRead_PGCIT_internal(ifo_handle_t *ifofile, pgcit_t *pgcit,
86 unsigned int offset);
87
88 static void ifoFree_PGC(pgc_t *pgc);
89 static void ifoFree_PGC_COMMAND_TBL(pgc_command_tbl_t *cmd_tbl);
90 static void ifoFree_PGCIT_internal(pgcit_t *pgcit);
91
92 static inline int DVDFileSeekForce_( dvd_file_t *dvd_file, uint32_t offset, int force_size ) {
93 return (DVDFileSeekForce(dvd_file, (int)offset, force_size) == (int)offset);
94 }
95
96 static inline int DVDFileSeek_( dvd_file_t *dvd_file, uint32_t offset ) {
97 return (DVDFileSeek(dvd_file, (int)offset) == (int)offset);
98 }
99
100 static void read_video_attr(video_attr_t *va) {
101 getbits_state_t state;
102 uint8_t buf[sizeof(video_attr_t)];
103
104 memcpy(buf, va, sizeof(video_attr_t));
105 if (!dvdread_getbits_init(&state, buf)) abort();
106 va->mpeg_version = dvdread_getbits(&state, 2);
107 va->video_format = dvdread_getbits(&state, 2);
108 va->display_aspect_ratio = dvdread_getbits(&state, 2);
109 va->permitted_df = dvdread_getbits(&state, 2);
110 va->line21_cc_1 = dvdread_getbits(&state, 1);
111 va->line21_cc_2 = dvdread_getbits(&state, 1);
112 va->unknown1 = dvdread_getbits(&state, 1);
113 va->bit_rate = dvdread_getbits(&state, 1);
114 va->picture_size = dvdread_getbits(&state, 2);
115 va->letterboxed = dvdread_getbits(&state, 1);
116 va->film_mode = dvdread_getbits(&state, 1);
117 }
118
119 static void read_audio_attr(audio_attr_t *aa) {
120 getbits_state_t state;
121 uint8_t buf[sizeof(audio_attr_t)];
122
123 memcpy(buf, aa, sizeof(audio_attr_t));
124 if (!dvdread_getbits_init(&state, buf)) abort();
125 aa->audio_format = dvdread_getbits(&state, 3);
126 aa->multichannel_extension = dvdread_getbits(&state, 1);
127 aa->lang_type = dvdread_getbits(&state, 2);
128 aa->application_mode = dvdread_getbits(&state, 2);
129 aa->quantization = dvdread_getbits(&state, 2);
130 aa->sample_frequency = dvdread_getbits(&state, 2);
131 aa->unknown1 = dvdread_getbits(&state, 1);
132 aa->channels = dvdread_getbits(&state, 3);
133 aa->lang_code = dvdread_getbits(&state, 16);
134 aa->lang_extension = dvdread_getbits(&state, 8);
135 aa->code_extension = dvdread_getbits(&state, 8);
136 aa->unknown3 = dvdread_getbits(&state, 8);
137 aa->app_info.karaoke.unknown4 = dvdread_getbits(&state, 1);
138 aa->app_info.karaoke.channel_assignment = dvdread_getbits(&state, 3);
139 aa->app_info.karaoke.version = dvdread_getbits(&state, 2);
140 aa->app_info.karaoke.mc_intro = dvdread_getbits(&state, 1);
141 aa->app_info.karaoke.mode = dvdread_getbits(&state, 1);
142 }
143
144 static void read_multichannel_ext(multichannel_ext_t *me) {
145 getbits_state_t state;
146 uint8_t buf[sizeof(multichannel_ext_t)];
147
148 memcpy(buf, me, sizeof(multichannel_ext_t));
149 if (!dvdread_getbits_init(&state, buf)) abort();
150 me->zero1 = dvdread_getbits(&state, 7);
151 me->ach0_gme = dvdread_getbits(&state, 1);
152 me->zero2 = dvdread_getbits(&state, 7);
153 me->ach1_gme = dvdread_getbits(&state, 1);
154 me->zero3 = dvdread_getbits(&state, 4);
155 me->ach2_gv1e = dvdread_getbits(&state, 1);
156 me->ach2_gv2e = dvdread_getbits(&state, 1);
157 me->ach2_gm1e = dvdread_getbits(&state, 1);
158 me->ach2_gm2e = dvdread_getbits(&state, 1);
159 me->zero4 = dvdread_getbits(&state, 4);
160 me->ach3_gv1e = dvdread_getbits(&state, 1);
161 me->ach3_gv2e = dvdread_getbits(&state, 1);
162 me->ach3_gmAe = dvdread_getbits(&state, 1);
163 me->ach3_se2e = dvdread_getbits(&state, 1);
164 me->zero5 = dvdread_getbits(&state, 4);
165 me->ach4_gv1e = dvdread_getbits(&state, 1);
166 me->ach4_gv2e = dvdread_getbits(&state, 1);
167 me->ach4_gmBe = dvdread_getbits(&state, 1);
168 me->ach4_seBe = dvdread_getbits(&state, 1);
169 }
170
171 static void read_subp_attr(subp_attr_t *sa) {
172 getbits_state_t state;
173 uint8_t buf[sizeof(subp_attr_t)];
174
175 memcpy(buf, sa, sizeof(subp_attr_t));
176 if (!dvdread_getbits_init(&state, buf)) abort();
177 sa->code_mode = dvdread_getbits(&state, 3);
178 sa->zero1 = dvdread_getbits(&state, 3);
179 sa->type = dvdread_getbits(&state, 2);
180 sa->zero2 = dvdread_getbits(&state, 8);
181 sa->lang_code = dvdread_getbits(&state, 16);
182 sa->lang_extension = dvdread_getbits(&state, 8);
183 sa->code_extension = dvdread_getbits(&state, 8);
184 }
185
186 static void read_user_ops(user_ops_t *uo) {
187 getbits_state_t state;
188 uint8_t buf[sizeof(user_ops_t)];
189
190 memcpy(buf, uo, sizeof(user_ops_t));
191 if (!dvdread_getbits_init(&state, buf)) abort();
192 uo->zero = dvdread_getbits(&state, 7);
193 uo->video_pres_mode_change = dvdread_getbits(&state, 1);
194 uo->karaoke_audio_pres_mode_change = dvdread_getbits(&state, 1);
195 uo->angle_change = dvdread_getbits(&state, 1);
196 uo->subpic_stream_change = dvdread_getbits(&state, 1);
197 uo->audio_stream_change = dvdread_getbits(&state, 1);
198 uo->pause_on = dvdread_getbits(&state, 1);
199 uo->still_off = dvdread_getbits(&state, 1);
200 uo->button_select_or_activate = dvdread_getbits(&state, 1);
201 uo->resume = dvdread_getbits(&state, 1);
202 uo->chapter_menu_call = dvdread_getbits(&state, 1);
203 uo->angle_menu_call = dvdread_getbits(&state, 1);
204 uo->audio_menu_call = dvdread_getbits(&state, 1);
205 uo->subpic_menu_call = dvdread_getbits(&state, 1);
206 uo->root_menu_call = dvdread_getbits(&state, 1);
207 uo->title_menu_call = dvdread_getbits(&state, 1);
208 uo->backward_scan = dvdread_getbits(&state, 1);
209 uo->forward_scan = dvdread_getbits(&state, 1);
210 uo->next_pg_search = dvdread_getbits(&state, 1);
211 uo->prev_or_top_pg_search = dvdread_getbits(&state, 1);
212 uo->time_or_chapter_search = dvdread_getbits(&state, 1);
213 uo->go_up = dvdread_getbits(&state, 1);
214 uo->stop = dvdread_getbits(&state, 1);
215 uo->title_play = dvdread_getbits(&state, 1);
216 uo->chapter_search_or_play = dvdread_getbits(&state, 1);
217 uo->title_or_time_play = dvdread_getbits(&state, 1);
218 }
219
220 static void read_pgci_srp(pgci_srp_t *ps) {
221 getbits_state_t state;
222 uint8_t buf[sizeof(pgci_srp_t)];
223
224 memcpy(buf, ps, sizeof(pgci_srp_t));
225 if (!dvdread_getbits_init(&state, buf)) abort();
226 ps->entry_id = dvdread_getbits(&state, 8);
227 ps->block_mode = dvdread_getbits(&state, 2);
228 ps->block_type = dvdread_getbits(&state, 2);
229 ps->unknown1 = dvdread_getbits(&state, 4);
230 ps->ptl_id_mask = dvdread_getbits(&state, 16);
231 ps->pgc_start_byte = dvdread_getbits(&state, 32);
232 }
233
234 static void read_cell_playback(cell_playback_t *cp) {
235 getbits_state_t state;
236 uint8_t buf[sizeof(cell_playback_t)];
237
238 memcpy(buf, cp, sizeof(cell_playback_t));
239 if (!dvdread_getbits_init(&state, buf)) abort();
240 cp->block_mode = dvdread_getbits(&state, 2);
241 cp->block_type = dvdread_getbits(&state, 2);
242 cp->seamless_play = dvdread_getbits(&state, 1);
243 cp->interleaved = dvdread_getbits(&state, 1);
244 cp->stc_discontinuity = dvdread_getbits(&state, 1);
245 cp->seamless_angle = dvdread_getbits(&state, 1);
246 cp->playback_mode = dvdread_getbits(&state, 1);
247 cp->restricted = dvdread_getbits(&state, 1);
248 cp->unknown2 = dvdread_getbits(&state, 6);
249 cp->still_time = dvdread_getbits(&state, 8);
250 cp->cell_cmd_nr = dvdread_getbits(&state, 8);
251
252 cp->playback_time.hour = dvdread_getbits(&state, 8);
253 cp->playback_time.minute = dvdread_getbits(&state, 8);
254 cp->playback_time.second = dvdread_getbits(&state, 8);
255 cp->playback_time.frame_u = dvdread_getbits(&state, 8);
256
257 cp->first_sector = dvdread_getbits(&state, 32);
258 cp->first_ilvu_end_sector = dvdread_getbits(&state, 32);
259 cp->last_vobu_start_sector = dvdread_getbits(&state, 32);
260 cp->last_sector = dvdread_getbits(&state, 32);
261 }
262
263 static void read_playback_type(playback_type_t *pt) {
264 getbits_state_t state;
265 uint8_t buf[sizeof(playback_type_t)];
266
267 memcpy(buf, pt, sizeof(playback_type_t));
268 if (!dvdread_getbits_init(&state, buf)) abort();
269 pt->zero_1 = dvdread_getbits(&state, 1);
270 pt->multi_or_random_pgc_title = dvdread_getbits(&state, 1);
271 pt->jlc_exists_in_cell_cmd = dvdread_getbits(&state, 1);
272 pt->jlc_exists_in_prepost_cmd = dvdread_getbits(&state, 1);
273 pt->jlc_exists_in_button_cmd = dvdread_getbits(&state, 1);
274 pt->jlc_exists_in_tt_dom = dvdread_getbits(&state, 1);
275 pt->chapter_search_or_play = dvdread_getbits(&state, 1);
276 pt->title_or_time_play = dvdread_getbits(&state, 1);
277 }
278
279 ifo_handle_t *ifoOpen(dvd_reader_t *dvd, int title) {
280 ifo_handle_t *ifofile;
281
282 ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t));
283 if(!ifofile)
284 return NULL;
285
286 memset(ifofile, 0, sizeof(ifo_handle_t));
287
288 ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE);
289 if(!ifofile->file) /* Should really catch any error and try to fallback */
290 ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_BACKUP_FILE);
291 if(!ifofile->file) {
292 if(title) {
293 fprintf(stderr, "libdvdread: Can't open file VTS_%02d_0.IFO.\n", title);
294 } else {
295 fprintf(stderr, "libdvdread: Can't open file VIDEO_TS.IFO.\n");
296 }
297 free(ifofile);
298 return NULL;
299 }
300
301 /* First check if this is a VMGI file. */
302 if(ifoRead_VMG(ifofile)) {
303
304 /* These are both mandatory. */
305 if(!ifoRead_FP_PGC(ifofile) || !ifoRead_TT_SRPT(ifofile)) {
306 fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO), ifoRead_FP_PGC() failed.\n");
307 ifoClose(ifofile);
308 return NULL;
309 }
310
311 ifoRead_PGCI_UT(ifofile);
312 ifoRead_PTL_MAIT(ifofile);
313
314 /* This is also mandatory. */
315 if(!ifoRead_VTS_ATRT(ifofile)) {
316 fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO), ifoRead_VTS_ATRT() failed.\n");
317 ifoClose(ifofile);
318 return NULL;
319 }
320
321 ifoRead_TXTDT_MGI(ifofile);
322 ifoRead_C_ADT(ifofile);
323 ifoRead_VOBU_ADMAP(ifofile);
324
325 return ifofile;
326 }
327
328 if(ifoRead_VTS(ifofile)) {
329
330 if(!ifoRead_VTS_PTT_SRPT(ifofile) || !ifoRead_PGCIT(ifofile)) {
331 fprintf(stderr, "libdvdread: Invalid title IFO (VTS_%02d_0.IFO).\n",
332 title);
333 ifoClose(ifofile);
334 return NULL;
335 }
336
337
338 ifoRead_PGCI_UT(ifofile);
339 ifoRead_VTS_TMAPT(ifofile);
340 ifoRead_C_ADT(ifofile);
341 ifoRead_VOBU_ADMAP(ifofile);
342
343 if(!ifoRead_TITLE_C_ADT(ifofile) || !ifoRead_TITLE_VOBU_ADMAP(ifofile)) {
344 fprintf(stderr, "libdvdread: Invalid title IFO (VTS_%02d_0.IFO).\n",
345 title);
346 ifoClose(ifofile);
347 return NULL;
348 }
349
350 return ifofile;
351 }
352
353 if(title) {
354 fprintf(stderr, "libdvdread: Invalid IFO for title %d (VTS_%02d_0.IFO).\n",
355 title, title);
356 } else {
357 fprintf(stderr, "libdvdread: Invalid IFO for VMGM (VIDEO_TS.IFO).\n");
358 }
359 ifoClose(ifofile);
360 return NULL;
361 }
362
363
364 ifo_handle_t *ifoOpenVMGI(dvd_reader_t *dvd) {
365 ifo_handle_t *ifofile;
366
367 ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t));
368 if(!ifofile)
369 return NULL;
370
371 memset(ifofile, 0, sizeof(ifo_handle_t));
372
373 ifofile->file = DVDOpenFile(dvd, 0, DVD_READ_INFO_FILE);
374 if(!ifofile->file) /* Should really catch any error and try to fallback */
375 ifofile->file = DVDOpenFile(dvd, 0, DVD_READ_INFO_BACKUP_FILE);
376 if(!ifofile->file) {
377 fprintf(stderr, "libdvdread: Can't open file VIDEO_TS.IFO.\n");
378 free(ifofile);
379 return NULL;
380 }
381
382 if(ifoRead_VMG(ifofile))
383 return ifofile;
384
385 fprintf(stderr, "libdvdread,ifoOpenVMGI(): Invalid main menu IFO (VIDEO_TS.IFO).\n");
386 ifoClose(ifofile);
387 return NULL;
388 }
389
390
391 ifo_handle_t *ifoOpenVTSI(dvd_reader_t *dvd, int title) {
392 ifo_handle_t *ifofile;
393
394 ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t));
395 if(!ifofile)
396 return NULL;
397
398 memset(ifofile, 0, sizeof(ifo_handle_t));
399
400 if(title <= 0 || title > 99) {
401 fprintf(stderr, "libdvdread: ifoOpenVTSI invalid title (%d).\n", title);
402 free(ifofile);
403 return NULL;
404 }
405
406 ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE);
407 if(!ifofile->file) /* Should really catch any error and try to fallback */
408 ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_BACKUP_FILE);
409 if(!ifofile->file) {
410 fprintf(stderr, "libdvdread: Can't open file VTS_%02d_0.IFO.\n", title);
411 free(ifofile);
412 return NULL;
413 }
414
415 ifoRead_VTS(ifofile);
416 if(ifofile->vtsi_mat)
417 return ifofile;
418
419 fprintf(stderr, "libdvdread: Invalid IFO for title %d (VTS_%02d_0.IFO).\n",
420 title, title);
421 ifoClose(ifofile);
422 return NULL;
423 }
424
425
426 void ifoClose(ifo_handle_t *ifofile) {
427 if(!ifofile)
428 return;
429
430 ifoFree_VOBU_ADMAP(ifofile);
431 ifoFree_TITLE_VOBU_ADMAP(ifofile);
432 ifoFree_C_ADT(ifofile);
433 ifoFree_TITLE_C_ADT(ifofile);
434 ifoFree_TXTDT_MGI(ifofile);
435 ifoFree_VTS_ATRT(ifofile);
436 ifoFree_PTL_MAIT(ifofile);
437 ifoFree_PGCI_UT(ifofile);
438 ifoFree_TT_SRPT(ifofile);
439 ifoFree_FP_PGC(ifofile);
440 ifoFree_PGCIT(ifofile);
441 ifoFree_VTS_PTT_SRPT(ifofile);
442 ifoFree_VTS_TMAPT(ifofile);
443
444 if(ifofile->vmgi_mat)
445 free(ifofile->vmgi_mat);
446
447 if(ifofile->vtsi_mat)
448 free(ifofile->vtsi_mat);
449
450 DVDCloseFile(ifofile->file);
451 ifofile->file = 0;
452 free(ifofile);
453 ifofile = 0;
454 }
455
456
457 static int ifoRead_VMG(ifo_handle_t *ifofile) {
458 vmgi_mat_t *vmgi_mat;
459
460 vmgi_mat = (vmgi_mat_t *)malloc(sizeof(vmgi_mat_t));
461 if(!vmgi_mat)
462 return 0;
463
464 ifofile->vmgi_mat = vmgi_mat;
465
466 if(!DVDFileSeek_(ifofile->file, 0)) {
467 free(ifofile->vmgi_mat);
468 ifofile->vmgi_mat = 0;
469 return 0;
470 }
471
472 if(!DVDReadBytes(ifofile->file, vmgi_mat, sizeof(vmgi_mat_t))) {
473 free(ifofile->vmgi_mat);
474 ifofile->vmgi_mat = 0;
475 return 0;
476 }
477
478 if(strncmp("DVDVIDEO-VMG", vmgi_mat->vmg_identifier, 12) != 0) {
479 free(ifofile->vmgi_mat);
480 ifofile->vmgi_mat = 0;
481 return 0;
482 }
483
484 B2N_32(vmgi_mat->vmg_last_sector);
485 B2N_32(vmgi_mat->vmgi_last_sector);
486 B2N_32(vmgi_mat->vmg_category);
487 B2N_16(vmgi_mat->vmg_nr_of_volumes);
488 B2N_16(vmgi_mat->vmg_this_volume_nr);
489 B2N_16(vmgi_mat->vmg_nr_of_title_sets);
490 B2N_64(vmgi_mat->vmg_pos_code);
491 B2N_32(vmgi_mat->vmgi_last_byte);
492 B2N_32(vmgi_mat->first_play_pgc);
493 B2N_32(vmgi_mat->vmgm_vobs);
494 B2N_32(vmgi_mat->tt_srpt);
495 B2N_32(vmgi_mat->vmgm_pgci_ut);
496 B2N_32(vmgi_mat->ptl_mait);
497 B2N_32(vmgi_mat->vts_atrt);
498 B2N_32(vmgi_mat->txtdt_mgi);
499 B2N_32(vmgi_mat->vmgm_c_adt);
500 B2N_32(vmgi_mat->vmgm_vobu_admap);
501 read_video_attr(&vmgi_mat->vmgm_video_attr);
502 read_audio_attr(&vmgi_mat->vmgm_audio_attr);
503 read_subp_attr(&vmgi_mat->vmgm_subp_attr);
504
505
506 CHECK_ZERO(vmgi_mat->zero_1);
507 CHECK_ZERO(vmgi_mat->zero_2);
508 CHECK_ZERO(vmgi_mat->zero_3);
509 CHECK_ZERO(vmgi_mat->zero_4);
510 CHECK_ZERO(vmgi_mat->zero_5);
511 CHECK_ZERO(vmgi_mat->zero_6);
512 CHECK_ZERO(vmgi_mat->zero_7);
513 CHECK_ZERO(vmgi_mat->zero_8);
514 CHECK_ZERO(vmgi_mat->zero_9);
515 CHECK_ZERO(vmgi_mat->zero_10);
516 CHECK_VALUE(vmgi_mat->vmg_last_sector != 0);
517 CHECK_VALUE(vmgi_mat->vmgi_last_sector != 0);
518 CHECK_VALUE(vmgi_mat->vmgi_last_sector * 2 <= vmgi_mat->vmg_last_sector);
519 CHECK_VALUE(vmgi_mat->vmgi_last_sector * 2 <= vmgi_mat->vmg_last_sector);
520 CHECK_VALUE(vmgi_mat->vmg_nr_of_volumes != 0);
521 CHECK_VALUE(vmgi_mat->vmg_this_volume_nr != 0);
522 CHECK_VALUE(vmgi_mat->vmg_this_volume_nr <= vmgi_mat->vmg_nr_of_volumes);
523 CHECK_VALUE(vmgi_mat->disc_side == 1 || vmgi_mat->disc_side == 2);
524 CHECK_VALUE(vmgi_mat->vmg_nr_of_title_sets != 0);
525 CHECK_VALUE(vmgi_mat->vmgi_last_byte >= 341);
526 CHECK_VALUE(vmgi_mat->vmgi_last_byte / DVD_BLOCK_LEN <=
527 vmgi_mat->vmgi_last_sector);
528 /* It seems that first_play_pgc is optional. */
529 CHECK_VALUE(vmgi_mat->first_play_pgc < vmgi_mat->vmgi_last_byte);
530 CHECK_VALUE(vmgi_mat->vmgm_vobs == 0 ||
531 (vmgi_mat->vmgm_vobs > vmgi_mat->vmgi_last_sector &&
532 vmgi_mat->vmgm_vobs < vmgi_mat->vmg_last_sector));
533 CHECK_VALUE(vmgi_mat->tt_srpt <= vmgi_mat->vmgi_last_sector);
534 CHECK_VALUE(vmgi_mat->vmgm_pgci_ut <= vmgi_mat->vmgi_last_sector);
535 CHECK_VALUE(vmgi_mat->ptl_mait <= vmgi_mat->vmgi_last_sector);
536 CHECK_VALUE(vmgi_mat->vts_atrt <= vmgi_mat->vmgi_last_sector);
537 CHECK_VALUE(vmgi_mat->txtdt_mgi <= vmgi_mat->vmgi_last_sector);
538 CHECK_VALUE(vmgi_mat->vmgm_c_adt <= vmgi_mat->vmgi_last_sector);
539 CHECK_VALUE(vmgi_mat->vmgm_vobu_admap <= vmgi_mat->vmgi_last_sector);
540
541 CHECK_VALUE(vmgi_mat->nr_of_vmgm_audio_streams <= 1);
542 CHECK_VALUE(vmgi_mat->nr_of_vmgm_subp_streams <= 1);
543
544 return 1;
545 }
546
547
548 static int ifoRead_VTS(ifo_handle_t *ifofile) {
549 vtsi_mat_t *vtsi_mat;
550 int i;
551
552 vtsi_mat = (vtsi_mat_t *)malloc(sizeof(vtsi_mat_t));
553 if(!vtsi_mat)
554 return 0;
555
556 ifofile->vtsi_mat = vtsi_mat;
557
558 if(!DVDFileSeek_(ifofile->file, 0)) {
559 free(ifofile->vtsi_mat);
560 ifofile->vtsi_mat = 0;
561 return 0;
562 }
563
564 if(!(DVDReadBytes(ifofile->file, vtsi_mat, sizeof(vtsi_mat_t)))) {
565 free(ifofile->vtsi_mat);
566 ifofile->vtsi_mat = 0;
567 return 0;
568 }
569
570 if(strncmp("DVDVIDEO-VTS", vtsi_mat->vts_identifier, 12) != 0) {
571 free(ifofile->vtsi_mat);
572 ifofile->vtsi_mat = 0;
573 return 0;
574 }
575
576 read_video_attr(&vtsi_mat->vtsm_video_attr);
577 read_video_attr(&vtsi_mat->vts_video_attr);
578 read_audio_attr(&vtsi_mat->vtsm_audio_attr);
579 for(i=0; i<8; i++)
580 read_audio_attr(&vtsi_mat->vts_audio_attr[i]);
581 read_subp_attr(&vtsi_mat->vtsm_subp_attr);
582 for(i=0; i<32; i++)
583 read_subp_attr(&vtsi_mat->vts_subp_attr[i]);
584 B2N_32(vtsi_mat->vts_last_sector);
585 B2N_32(vtsi_mat->vtsi_last_sector);
586 B2N_32(vtsi_mat->vts_category);
587 B2N_32(vtsi_mat->vtsi_last_byte);
588 B2N_32(vtsi_mat->vtsm_vobs);
589 B2N_32(vtsi_mat->vtstt_vobs);
590 B2N_32(vtsi_mat->vts_ptt_srpt);
591 B2N_32(vtsi_mat->vts_pgcit);
592 B2N_32(vtsi_mat->vtsm_pgci_ut);
593 B2N_32(vtsi_mat->vts_tmapt);
594 B2N_32(vtsi_mat->vtsm_c_adt);
595 B2N_32(vtsi_mat->vtsm_vobu_admap);
596 B2N_32(vtsi_mat->vts_c_adt);
597 B2N_32(vtsi_mat->vts_vobu_admap);
598
599
600 CHECK_ZERO(vtsi_mat->zero_1);
601 CHECK_ZERO(vtsi_mat->zero_2);
602 CHECK_ZERO(vtsi_mat->zero_3);
603 CHECK_ZERO(vtsi_mat->zero_4);
604 CHECK_ZERO(vtsi_mat->zero_5);
605 CHECK_ZERO(vtsi_mat->zero_6);
606 CHECK_ZERO(vtsi_mat->zero_7);
607 CHECK_ZERO(vtsi_mat->zero_8);
608 CHECK_ZERO(vtsi_mat->zero_9);
609 CHECK_ZERO(vtsi_mat->zero_10);
610 CHECK_ZERO(vtsi_mat->zero_11);
611 CHECK_ZERO(vtsi_mat->zero_12);
612 CHECK_ZERO(vtsi_mat->zero_13);
613 CHECK_ZERO(vtsi_mat->zero_14);
614 CHECK_ZERO(vtsi_mat->zero_15);
615 CHECK_ZERO(vtsi_mat->zero_16);
616 CHECK_ZERO(vtsi_mat->zero_17);
617 CHECK_ZERO(vtsi_mat->zero_18);
618 CHECK_ZERO(vtsi_mat->zero_19);
619 CHECK_ZERO(vtsi_mat->zero_20);
620 CHECK_ZERO(vtsi_mat->zero_21);
621 CHECK_VALUE(vtsi_mat->vtsi_last_sector*2 <= vtsi_mat->vts_last_sector);
622 CHECK_VALUE(vtsi_mat->vtsi_last_byte/DVD_BLOCK_LEN <= vtsi_mat->vtsi_last_sector);
623 CHECK_VALUE(vtsi_mat->vtsm_vobs == 0 ||
624 (vtsi_mat->vtsm_vobs > vtsi_mat->vtsi_last_sector &&
625 vtsi_mat->vtsm_vobs < vtsi_mat->vts_last_sector));
626 CHECK_VALUE(vtsi_mat->vtstt_vobs == 0 ||
627 (vtsi_mat->vtstt_vobs > vtsi_mat->vtsi_last_sector &&
628 vtsi_mat->vtstt_vobs < vtsi_mat->vts_last_sector));
629 CHECK_VALUE(vtsi_mat->vts_ptt_srpt <= vtsi_mat->vtsi_last_sector);
630 CHECK_VALUE(vtsi_mat->vts_pgcit <= vtsi_mat->vtsi_last_sector);
631 CHECK_VALUE(vtsi_mat->vtsm_pgci_ut <= vtsi_mat->vtsi_last_sector);
632 CHECK_VALUE(vtsi_mat->vts_tmapt <= vtsi_mat->vtsi_last_sector);
633 CHECK_VALUE(vtsi_mat->vtsm_c_adt <= vtsi_mat->vtsi_last_sector);
634 CHECK_VALUE(vtsi_mat->vtsm_vobu_admap <= vtsi_mat->vtsi_last_sector);
635 CHECK_VALUE(vtsi_mat->vts_c_adt <= vtsi_mat->vtsi_last_sector);
636 CHECK_VALUE(vtsi_mat->vts_vobu_admap <= vtsi_mat->vtsi_last_sector);
637
638 CHECK_VALUE(vtsi_mat->nr_of_vtsm_audio_streams <= 1);
639 CHECK_VALUE(vtsi_mat->nr_of_vtsm_subp_streams <= 1);
640
641 CHECK_VALUE(vtsi_mat->nr_of_vts_audio_streams <= 8);
642 for(i = vtsi_mat->nr_of_vts_audio_streams; i < 8; i++)
643 CHECK_ZERO(vtsi_mat->vts_audio_attr[i]);
644
645 CHECK_VALUE(vtsi_mat->nr_of_vts_subp_streams <= 32);
646 for(i = vtsi_mat->nr_of_vts_subp_streams; i < 32; i++)
647 CHECK_ZERO(vtsi_mat->vts_subp_attr[i]);
648
649 for(i = 0; i < 8; i++) {
650 read_multichannel_ext(&vtsi_mat->vts_mu_audio_attr[i]);
651 CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero1);
652 CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero2);
653 CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero3);
654 CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero4);
655 CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero5);
656 CHECK_ZERO(vtsi_mat->vts_mu_audio_attr[i].zero6);
657 }
658
659 return 1;
660 }
661
662
663 static int ifoRead_PGC_COMMAND_TBL(ifo_handle_t *ifofile,
664 pgc_command_tbl_t *cmd_tbl,
665 unsigned int offset) {
666
667 memset(cmd_tbl, 0, sizeof(pgc_command_tbl_t));
668
669 if(!DVDFileSeek_(ifofile->file, offset))
670 return 0;
671
672 if(!(DVDReadBytes(ifofile->file, cmd_tbl, PGC_COMMAND_TBL_SIZE)))
673 return 0;
674
675 B2N_16(cmd_tbl->nr_of_pre);
676 B2N_16(cmd_tbl->nr_of_post);
677 B2N_16(cmd_tbl->nr_of_cell);
678
679 CHECK_VALUE(cmd_tbl->nr_of_pre + cmd_tbl->nr_of_post + cmd_tbl->nr_of_cell<= 255);
680
681 if(cmd_tbl->nr_of_pre != 0) {
682 unsigned int pre_cmds_size = cmd_tbl->nr_of_pre * COMMAND_DATA_SIZE;
683 cmd_tbl->pre_cmds = (vm_cmd_t *)malloc(pre_cmds_size);
684 if(!cmd_tbl->pre_cmds)
685 return 0;
686
687 if(!(DVDReadBytes(ifofile->file, cmd_tbl->pre_cmds, pre_cmds_size))) {
688 free(cmd_tbl->pre_cmds);
689 return 0;
690 }
691 }
692
693 if(cmd_tbl->nr_of_post != 0) {
694 unsigned int post_cmds_size = cmd_tbl->nr_of_post * COMMAND_DATA_SIZE;
695 cmd_tbl->post_cmds = (vm_cmd_t *)malloc(post_cmds_size);
696 if(!cmd_tbl->post_cmds) {
697 if(cmd_tbl->pre_cmds)
698 free(cmd_tbl->pre_cmds);
699 return 0;
700 }
701 if(!(DVDReadBytes(ifofile->file, cmd_tbl->post_cmds, post_cmds_size))) {
702 if(cmd_tbl->pre_cmds)
703 free(cmd_tbl->pre_cmds);
704 free(cmd_tbl->post_cmds);
705 return 0;
706 }
707 }
708
709 if(cmd_tbl->nr_of_cell != 0) {
710 unsigned int cell_cmds_size = cmd_tbl->nr_of_cell * COMMAND_DATA_SIZE;
711 cmd_tbl->cell_cmds = (vm_cmd_t *)malloc(cell_cmds_size);
712 if(!cmd_tbl->cell_cmds) {
713 if(cmd_tbl->pre_cmds)
714 free(cmd_tbl->pre_cmds);
715 if(cmd_tbl->post_cmds)
716 free(cmd_tbl->post_cmds);
717 return 0;
718 }
719 if(!(DVDReadBytes(ifofile->file, cmd_tbl->cell_cmds, cell_cmds_size))) {
720 if(cmd_tbl->pre_cmds)
721 free(cmd_tbl->pre_cmds);
722 if(cmd_tbl->post_cmds)
723 free(cmd_tbl->post_cmds);
724 free(cmd_tbl->cell_cmds);
725 return 0;
726 }
727 }
728
729 /*
730 * Make a run over all the commands and see that we can interpret them all?
731 */
732 return 1;
733 }
734
735
736 static void ifoFree_PGC_COMMAND_TBL(pgc_command_tbl_t *cmd_tbl) {
737 if(cmd_tbl) {
738 if(cmd_tbl->nr_of_pre && cmd_tbl->pre_cmds)
739 free(cmd_tbl->pre_cmds);
740 if(cmd_tbl->nr_of_post && cmd_tbl->post_cmds)
741 free(cmd_tbl->post_cmds);
742 if(cmd_tbl->nr_of_cell && cmd_tbl->cell_cmds)
743 free(cmd_tbl->cell_cmds);
744 free(cmd_tbl);
745 }
746 }
747
748 static int ifoRead_PGC_PROGRAM_MAP(ifo_handle_t *ifofile,
749 pgc_program_map_t *program_map,
750 unsigned int nr, unsigned int offset) {
751 unsigned int size = nr * sizeof(pgc_program_map_t);
752
753 if(!DVDFileSeek_(ifofile->file, offset))
754 return 0;
755
756 if(!(DVDReadBytes(ifofile->file, program_map, size)))
757 return 0;
758
759 return 1;
760 }
761
762 static int ifoRead_CELL_PLAYBACK_TBL(ifo_handle_t *ifofile,
763 cell_playback_t *cell_playback,
764 unsigned int nr, unsigned int offset) {
765 unsigned int i;
766 unsigned int size = nr * sizeof(cell_playback_t);
767
768 if(!DVDFileSeek_(ifofile->file, offset))
769 return 0;
770
771 if(!(DVDReadBytes(ifofile->file, cell_playback, size)))
772 return 0;
773
774 for(i = 0; i < nr; i++) {
775 read_cell_playback(&cell_playback[i]);
776 /* Changed < to <= because this was false in the movie 'Pi'. */
777 CHECK_VALUE(cell_playback[i].last_vobu_start_sector <=
778 cell_playback[i].last_sector);
779 CHECK_VALUE(cell_playback[i].first_sector <=
780 cell_playback[i].last_vobu_start_sector);
781 }
782
783 return 1;
784 }
785
786
787 static int ifoRead_CELL_POSITION_TBL(ifo_handle_t *ifofile,
788 cell_position_t *cell_position,
789 unsigned int nr, unsigned int offset) {
790 unsigned int i;
791 unsigned int size = nr * sizeof(cell_position_t);
792
793 if(!DVDFileSeek_(ifofile->file, offset))
794 return 0;
795
796 if(!(DVDReadBytes(ifofile->file, cell_position, size)))
797 return 0;
798
799 for(i = 0; i < nr; i++) {
800 B2N_16(cell_position[i].vob_id_nr);
801 CHECK_ZERO(cell_position[i].zero_1);
802 }
803
804 return 1;
805 }
806
807 static int ifoRead_PGC(ifo_handle_t *ifofile, pgc_t *pgc, unsigned int offset) {
808 unsigned int i;
809
810 if(!DVDFileSeek_(ifofile->file, offset))
811 return 0;
812
813 if(!(DVDReadBytes(ifofile->file, pgc, PGC_SIZE)))
814 return 0;
815
816 read_user_ops(&pgc->prohibited_ops);
817 B2N_16(pgc->next_pgc_nr);
818 B2N_16(pgc->prev_pgc_nr);
819 B2N_16(pgc->goup_pgc_nr);
820 B2N_16(pgc->command_tbl_offset);
821 B2N_16(pgc->program_map_offset);
822 B2N_16(pgc->cell_playback_offset);
823 B2N_16(pgc->cell_position_offset);
824
825 for(i = 0; i < 8; i++)
826 B2N_16(pgc->audio_control[i]);
827 for(i = 0; i < 32; i++)
828 B2N_32(pgc->subp_control[i]);
829 for(i = 0; i < 16; i++)
830 B2N_32(pgc->palette[i]);
831
832 CHECK_ZERO(pgc->zero_1);
833 CHECK_VALUE(pgc->nr_of_programs <= pgc->nr_of_cells);
834
835 /* verify time (look at print_time) */
836 for(i = 0; i < 8; i++)
837 if(!pgc->audio_control[i] & 0x8000) /* The 'is present' bit */
838 CHECK_ZERO(pgc->audio_control[i]);
839 for(i = 0; i < 32; i++)
840 if(!pgc->subp_control[i] & 0x80000000) /* The 'is present' bit */
841 CHECK_ZERO(pgc->subp_control[i]);
842
843 /* Check that time is 0:0:0:0 also if nr_of_programs == 0 */
844 if(pgc->nr_of_programs == 0) {
845 CHECK_ZERO(pgc->still_time);
846 CHECK_ZERO(pgc->pg_playback_mode); /* ?? */
847 CHECK_VALUE(pgc->program_map_offset == 0);
848 CHECK_VALUE(pgc->cell_playback_offset == 0);
849 CHECK_VALUE(pgc->cell_position_offset == 0);
850 } else {
851 CHECK_VALUE(pgc->program_map_offset != 0);
852 CHECK_VALUE(pgc->cell_playback_offset != 0);
853 CHECK_VALUE(pgc->cell_position_offset != 0);
854 }
855
856 if(pgc->command_tbl_offset != 0) {
857 pgc->command_tbl = malloc(sizeof(pgc_command_tbl_t));
858 if(!pgc->command_tbl)
859 return 0;
860
861 if(!ifoRead_PGC_COMMAND_TBL(ifofile, pgc->command_tbl,
862 offset + pgc->command_tbl_offset)) {
863 free(pgc->command_tbl);
864 return 0;
865 }
866 } else {
867 pgc->command_tbl = NULL;
868 }
869
870 if(pgc->program_map_offset != 0 && pgc->nr_of_programs>0) {
871 pgc->program_map = malloc(pgc->nr_of_programs * sizeof(pgc_program_map_t));
872 if(!pgc->program_map) {
873 ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
874 return 0;
875 }
876 if(!ifoRead_PGC_PROGRAM_MAP(ifofile, pgc->program_map,pgc->nr_of_programs,
877 offset + pgc->program_map_offset)) {
878 ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
879 free(pgc->program_map);
880 return 0;
881 }
882 } else {
883 pgc->program_map = NULL;
884 }
885
886 if(pgc->cell_playback_offset != 0 && pgc->nr_of_cells>0) {
887 pgc->cell_playback = malloc(pgc->nr_of_cells * sizeof(cell_playback_t));
888 if(!pgc->cell_playback) {
889 ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
890 if(pgc->program_map)
891 free(pgc->program_map);
892 return 0;
893 }
894 if(!ifoRead_CELL_PLAYBACK_TBL(ifofile, pgc->cell_playback,
895 pgc->nr_of_cells,
896 offset + pgc->cell_playback_offset)) {
897 ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
898 if(pgc->program_map)
899 free(pgc->program_map);
900 free(pgc->cell_playback);
901 return 0;
902 }
903 } else {
904 pgc->cell_playback = NULL;
905 }
906
907 if(pgc->cell_position_offset != 0 && pgc->nr_of_cells>0) {
908 pgc->cell_position = malloc(pgc->nr_of_cells * sizeof(cell_position_t));
909 if(!pgc->cell_position) {
910 ifoFree_PGC(pgc);
911 return 0;
912 }
913 if(!ifoRead_CELL_POSITION_TBL(ifofile, pgc->cell_position,
914 pgc->nr_of_cells,
915 offset + pgc->cell_position_offset)) {
916 ifoFree_PGC(pgc);
917 return 0;
918 }
919 } else {
920 pgc->cell_position = NULL;
921 }
922
923 return 1;
924 }
925
926 int ifoRead_FP_PGC(ifo_handle_t *ifofile) {
927
928 if(!ifofile)
929 return 0;
930
931 if(!ifofile->vmgi_mat)
932 return 0;
933
934 /* It seems that first_play_pgc is optional after all. */
935 ifofile->first_play_pgc = 0;
936 if(ifofile->vmgi_mat->first_play_pgc == 0)
937 return 1;
938
939 ifofile->first_play_pgc = (pgc_t *)malloc(sizeof(pgc_t));
940 if(!ifofile->first_play_pgc)
941 return 0;
942
943 if(!ifoRead_PGC(ifofile, ifofile->first_play_pgc,
944 ifofile->vmgi_mat->first_play_pgc)) {
945 free(ifofile->first_play_pgc);
946 ifofile->first_play_pgc = 0;
947 return 0;
948 }
949
950 return 1;
951 }
952
953 static void ifoFree_PGC(pgc_t *pgc) {
954 if(pgc) {
955 ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
956 if(pgc->program_map)
957 free(pgc->program_map);
958 if(pgc->cell_playback)
959 free(pgc->cell_playback);
960 if(pgc->cell_position)
961 free(pgc->cell_position);
962 }
963 }
964
965 void ifoFree_FP_PGC(ifo_handle_t *ifofile) {
966 if(!ifofile)
967 return;
968
969 if(ifofile->first_play_pgc) {
970 ifoFree_PGC(ifofile->first_play_pgc);
971 free(ifofile->first_play_pgc);
972 ifofile->first_play_pgc = 0;
973 }
974 }
975
976
977 int ifoRead_TT_SRPT(ifo_handle_t *ifofile) {
978 tt_srpt_t *tt_srpt;
979 int i, info_length;
980
981 if(!ifofile)
982 return 0;
983
984 if(!ifofile->vmgi_mat)
985 return 0;
986
987 if(ifofile->vmgi_mat->tt_srpt == 0) /* mandatory */
988 return 0;
989
990 if(!DVDFileSeek_(ifofile->file, ifofile->vmgi_mat->tt_srpt * DVD_BLOCK_LEN))
991 return 0;
992
993 tt_srpt = (tt_srpt_t *)malloc(sizeof(tt_srpt_t));
994 if(!tt_srpt)
995 return 0;
996
997 ifofile->tt_srpt = tt_srpt;
998
999 if(!(DVDReadBytes(ifofile->file, tt_srpt, TT_SRPT_SIZE))) {
1000 fprintf(stderr, "libdvdread: Unable to read read TT_SRPT.\n");
1001 free(tt_srpt);
1002 return 0;
1003 }
1004
1005 B2N_16(tt_srpt->nr_of_srpts);
1006 B2N_32(tt_srpt->last_byte);
1007
1008 info_length = tt_srpt->last_byte + 1 - TT_SRPT_SIZE;
1009
1010 tt_srpt->title = (title_info_t *)malloc(info_length);
1011 if(!tt_srpt->title) {
1012 free(tt_srpt);
1013 ifofile->tt_srpt = 0;
1014 return 0;
1015 }
1016 if(!(DVDReadBytes(ifofile->file, tt_srpt->title, info_length))) {
1017 fprintf(stderr, "libdvdread: Unable to read read TT_SRPT.\n");
1018 ifoFree_TT_SRPT(ifofile);
1019 return 0;
1020 }
1021
1022 for(i = 0; i < tt_srpt->nr_of_srpts; i++) {
1023 B2N_16(tt_srpt->title[i].nr_of_ptts);
1024 B2N_16(tt_srpt->title[i].parental_id);
1025 B2N_32(tt_srpt->title[i].title_set_sector);
1026 }
1027
1028
1029 CHECK_ZERO(tt_srpt->zero_1);
1030 CHECK_VALUE(tt_srpt->nr_of_srpts != 0);
1031 CHECK_VALUE(tt_srpt->nr_of_srpts < 100); /* ?? */
1032 CHECK_VALUE((int)tt_srpt->nr_of_srpts * sizeof(title_info_t) <= info_length);
1033
1034 for(i = 0; i < tt_srpt->nr_of_srpts; i++) {
1035 read_playback_type(&tt_srpt->title[i].pb_ty);
1036 CHECK_VALUE(tt_srpt->title[i].pb_ty.zero_1 == 0);
1037 CHECK_VALUE(tt_srpt->title[i].nr_of_angles != 0);
1038 CHECK_VALUE(tt_srpt->title[i].nr_of_angles < 10);
1039 /* CHECK_VALUE(tt_srpt->title[i].nr_of_ptts != 0); */
1040 /* XXX: this assertion breaks Ghostbusters: */
1041 CHECK_VALUE(tt_srpt->title[i].nr_of_ptts < 1000); /* ?? */
1042 CHECK_VALUE(tt_srpt->title[i].title_set_nr != 0);
1043 CHECK_VALUE(tt_srpt->title[i].title_set_nr < 100); /* ?? */
1044 CHECK_VALUE(tt_srpt->title[i].vts_ttn != 0);
1045 CHECK_VALUE(tt_srpt->title[i].vts_ttn < 100); /* ?? */
1046 /* CHECK_VALUE(tt_srpt->title[i].title_set_sector != 0); */
1047 }
1048
1049 /* Make this a function */
1050 #if 0
1051 if(memcmp((uint8_t *)tt_srpt->title +
1052 tt_srpt->nr_of_srpts * sizeof(title_info_t),
1053 my_friendly_zeros,
1054 info_length - tt_srpt->nr_of_srpts * sizeof(title_info_t))) {
1055 fprintf(stderr, "VMG_PTT_SRPT slack is != 0, ");
1056 hexdump((uint8_t *)tt_srpt->title +
1057 tt_srpt->nr_of_srpts * sizeof(title_info_t),
1058 info_length - tt_srpt->nr_of_srpts * sizeof(title_info_t));
1059 }
1060 #endif
1061
1062 return 1;
1063 }
1064
1065
1066 void ifoFree_TT_SRPT(ifo_handle_t *ifofile) {
1067 if(!ifofile)
1068 return;
1069
1070 if(ifofile->tt_srpt) {
1071 free(ifofile->tt_srpt->title);
1072 free(ifofile->tt_srpt);
1073 ifofile->tt_srpt = 0;
1074 }
1075 }
1076
1077
1078 int ifoRead_VTS_PTT_SRPT(ifo_handle_t *ifofile) {
1079 vts_ptt_srpt_t *vts_ptt_srpt;
1080 int info_length, i, j;
1081 uint32_t *data;
1082
1083 if(!ifofile)
1084 return 0;
1085
1086 if(!ifofile->vtsi_mat)
1087 return 0;
1088
1089 if(ifofile->vtsi_mat->vts_ptt_srpt == 0) /* mandatory */
1090 return 0;
1091
1092 if(!DVDFileSeek_(ifofile->file,
1093 ifofile->vtsi_mat->vts_ptt_srpt * DVD_BLOCK_LEN))
1094 return 0;
1095
1096 vts_ptt_srpt = (vts_ptt_srpt_t *)malloc(sizeof(vts_ptt_srpt_t));
1097 if(!vts_ptt_srpt)
1098 return 0;
1099
1100 ifofile->vts_ptt_srpt = vts_ptt_srpt;
1101
1102 if(!(DVDReadBytes(ifofile->file, vts_ptt_srpt, VTS_PTT_SRPT_SIZE))) {
1103 fprintf(stderr, "libdvdread: Unable to read PTT search table.\n");
1104 free(vts_ptt_srpt);
1105 return 0;
1106 }
1107
1108 B2N_16(vts_ptt_srpt->nr_of_srpts);
1109 B2N_32(vts_ptt_srpt->last_byte);
1110
1111 CHECK_ZERO(vts_ptt_srpt->zero_1);
1112 CHECK_VALUE(vts_ptt_srpt->nr_of_srpts != 0);
1113 CHECK_VALUE(vts_ptt_srpt->nr_of_srpts < 100); /* ?? */
1114
1115 info_length = vts_ptt_srpt->last_byte + 1 - VTS_PTT_SRPT_SIZE;
1116
1117 data = (uint32_t *)malloc(info_length);
1118 if(!data) {
1119 free(vts_ptt_srpt);
1120 ifofile->vts_ptt_srpt = 0;
1121 return 0;
1122 }
1123 if(!(DVDReadBytes(ifofile->file, data, info_length))) {
1124 fprintf(stderr, "libdvdread: Unable to read PTT search table.\n");
1125 free(vts_ptt_srpt);
1126 free(data);
1127 ifofile->vts_ptt_srpt = 0;
1128 return 0;
1129 }
1130
1131 for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) {
1132 B2N_32(data[i]);
1133 /* assert(data[i] + sizeof(ptt_info_t) <= vts_ptt_srpt->last_byte + 1);
1134 Magic Knight Rayearth Daybreak is mastered very strange and has
1135 Titles with 0 PTTs. They all have a data[i] offsets beyond the end of
1136 of the vts_ptt_srpt structure. */
1137 CHECK_VALUE(data[i] + sizeof(ptt_info_t) <= vts_ptt_srpt->last_byte + 1 + 4);
1138 }
1139
1140 vts_ptt_srpt->ttu_offset = data;
1141
1142 vts_ptt_srpt->title = malloc(vts_ptt_srpt->nr_of_srpts * sizeof(ttu_t));
1143 if(!vts_ptt_srpt->title) {
1144 free(vts_ptt_srpt);
1145 free(data);
1146 ifofile->vts_ptt_srpt = 0;
1147 return 0;
1148 }
1149 for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) {
1150 int n;
1151 if(i < vts_ptt_srpt->nr_of_srpts - 1)
1152 n = (data[i+1] - data[i]);
1153 else
1154 n = (vts_ptt_srpt->last_byte + 1 - data[i]);
1155 /* assert(n > 0 && (n % 4) == 0);
1156 Magic Knight Rayearth Daybreak is mastered very strange and has
1157 Titles with 0 PTTs. */
1158 if(n < 0) n = 0;
1159 CHECK_VALUE(n % 4 == 0);
1160
1161 vts_ptt_srpt->title[i].nr_of_ptts = n / 4;
1162 vts_ptt_srpt->title[i].ptt = malloc(n * sizeof(ptt_info_t));
1163 if(!vts_ptt_srpt->title[i].ptt) {
1164 for(n = 0; n < i; n++)
1165 free(vts_ptt_srpt->title[n].ptt);
1166 free(vts_ptt_srpt);
1167 free(data);
1168 ifofile->vts_ptt_srpt = 0;
1169 return 0;
1170 }
1171 for(j = 0; j < vts_ptt_srpt->title[i].nr_of_ptts; j++) {
1172 /* The assert placed here because of Magic Knight Rayearth Daybreak */
1173 CHECK_VALUE(data[i] + sizeof(ptt_info_t) <= vts_ptt_srpt->last_byte + 1);
1174 vts_ptt_srpt->title[i].ptt[j].pgcn
1175 = *(uint16_t*)(((char *)data) + data[i] + 4*j - VTS_PTT_SRPT_SIZE);
1176 vts_ptt_srpt->title[i].ptt[j].pgn
1177 = *(uint16_t*)(((char *)data) + data[i] + 4*j + 2 - VTS_PTT_SRPT_SIZE);
1178 }
1179 }
1180
1181 for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) {
1182 for(j = 0; j < vts_ptt_srpt->title[i].nr_of_ptts; j++) {
1183 B2N_16(vts_ptt_srpt->title[i].ptt[j].pgcn);
1184 B2N_16(vts_ptt_srpt->title[i].ptt[j].pgn);
1185 }
1186 }
1187
1188 for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) {
1189 CHECK_VALUE(vts_ptt_srpt->title[i].nr_of_ptts < 1000); /* ?? */
1190 for(j = 0; j < vts_ptt_srpt->title[i].nr_of_ptts; j++) {
1191 CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgcn != 0 );
1192 CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgcn < 1000); /* ?? */
1193 CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgn != 0);
1194 CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgn < 100); /* ?? */
1195 }
1196 }
1197
1198 return 1;
1199 }
1200
1201
1202 void ifoFree_VTS_PTT_SRPT(ifo_handle_t *ifofile) {
1203 if(!ifofile)
1204 return;
1205
1206 if(ifofile->vts_ptt_srpt) {
1207 int i;
1208 for(i = 0; i < ifofile->vts_ptt_srpt->nr_of_srpts; i++)
1209 free(ifofile->vts_ptt_srpt->title[i].ptt);
1210 free(ifofile->vts_ptt_srpt->ttu_offset);
1211 free(ifofile->vts_ptt_srpt->title);
1212 free(ifofile->vts_ptt_srpt);
1213 ifofile->vts_ptt_srpt = 0;
1214 }
1215 }
1216
1217
1218 int ifoRead_PTL_MAIT(ifo_handle_t *ifofile) {
1219 ptl_mait_t *ptl_mait;
1220 int info_length;
1221 unsigned int i, j;
1222
1223 if(!ifofile)
1224 return 0;
1225
1226 if(!ifofile->vmgi_mat)
1227 return 0;
1228
1229 if(ifofile->vmgi_mat->ptl_mait == 0)
1230 return 1;
1231
1232 if(!DVDFileSeek_(ifofile->file, ifofile->vmgi_mat->ptl_mait * DVD_BLOCK_LEN))
1233 return 0;
1234
1235 ptl_mait = (ptl_mait_t *)malloc(sizeof(ptl_mait_t));
1236 if(!ptl_mait)
1237 return 0;
1238
1239 ifofile->ptl_mait = ptl_mait;
1240
1241 if(!(DVDReadBytes(ifofile->file, ptl_mait, PTL_MAIT_SIZE))) {
1242 free(ptl_mait);
1243 ifofile->ptl_mait = 0;
1244 return 0;
1245 }
1246
1247 B2N_16(ptl_mait->nr_of_countries);
1248 B2N_16(ptl_mait->nr_of_vtss);
1249 B2N_32(ptl_mait->last_byte);
1250
1251 CHECK_VALUE(ptl_mait->nr_of_countries != 0);
1252 CHECK_VALUE(ptl_mait->nr_of_countries < 100); /* ?? */
1253 CHECK_VALUE(ptl_mait->nr_of_vtss != 0);
1254 CHECK_VALUE(ptl_mait->nr_of_vtss < 100); /* ?? */
1255 CHECK_VALUE(ptl_mait->nr_of_countries * PTL_MAIT_COUNTRY_SIZE
1256 <= ptl_mait->last_byte + 1 - PTL_MAIT_SIZE);
1257
1258 info_length = ptl_mait->nr_of_countries * sizeof(ptl_mait_country_t);
1259 ptl_mait->countries = (ptl_mait_country_t *)malloc(info_length);
1260 if(!ptl_mait->countries) {
1261 free(ptl_mait);
1262 ifofile->ptl_mait = 0;
1263 return 0;
1264 }
1265
1266 for(i = 0; i < ptl_mait->nr_of_countries; i++) {
1267 if(!(DVDReadBytes(ifofile->file, &ptl_mait->countries[i], PTL_MAIT_COUNTRY_SIZE))) {
1268 fprintf(stderr, "libdvdread: Unable to read PTL_MAIT.\n");
1269 free(ptl_mait->countries);
1270 free(ptl_mait);
1271 ifofile->ptl_mait = 0;
1272 return 0;
1273 }
1274 }
1275
1276 for(i = 0; i < ptl_mait->nr_of_countries; i++) {
1277 B2N_16(ptl_mait->countries[i].country_code);
1278 B2N_16(ptl_mait->countries[i].pf_ptl_mai_start_byte);
1279 }
1280
1281 for(i = 0; i < ptl_mait->nr_of_countries; i++) {
1282 CHECK_ZERO(ptl_mait->countries[i].zero_1);
1283 CHECK_ZERO(ptl_mait->countries[i].zero_2);
1284 CHECK_VALUE(ptl_mait->countries[i].pf_ptl_mai_start_byte
1285 + 8*2 * (ptl_mait->nr_of_vtss + 1) <= ptl_mait->last_byte + 1);
1286 }
1287
1288 for(i = 0; i < ptl_mait->nr_of_countries; i++) {
1289 uint16_t *pf_temp;
1290
1291 if(!DVDFileSeek_(ifofile->file,
1292 ifofile->vmgi_mat->ptl_mait * DVD_BLOCK_LEN
1293 + ptl_mait->countries[i].pf_ptl_mai_start_byte)) {
1294 fprintf(stderr, "libdvdread: Unable to seak PTL_MAIT table.\n");
1295 free(ptl_mait->countries);
1296 free(ptl_mait);
1297 return 0;
1298 }
1299 info_length = (ptl_mait->nr_of_vtss + 1) * sizeof(pf_level_t);
1300 pf_temp = (uint16_t *)malloc(info_length);
1301 if(!pf_temp) {
1302 for(j = 0; j < i ; j++) {
1303 free(ptl_mait->countries[j].pf_ptl_mai);
1304 }
1305 free(ptl_mait->countries);
1306 free(ptl_mait);
1307 return 0;
1308 }
1309 if(!(DVDReadBytes(ifofile->file, pf_temp, info_length))) {
1310 fprintf(stderr, "libdvdread: Unable to read PTL_MAIT table.\n");
1311 free(pf_temp);
1312 for(j = 0; j < i ; j++) {
1313 free(ptl_mait->countries[j].pf_ptl_mai);
1314 }
1315 free(ptl_mait->countries);
1316 free(ptl_mait);
1317 return 0;
1318 }
1319 for (j = 0; j < ((ptl_mait->nr_of_vtss + 1) * 8); j++) {
1320 B2N_16(pf_temp[j]);
1321 }
1322 ptl_mait->countries[i].pf_ptl_mai = (pf_level_t *)malloc(info_length);
1323 if(!ptl_mait->countries[i].pf_ptl_mai) {
1324 free(pf_temp);
1325 for(j = 0; j < i ; j++) {
1326 free(ptl_mait->countries[j].pf_ptl_mai);
1327 }
1328 free(ptl_mait->countries);
1329 free(ptl_mait);
1330 return 0;
1331 }
1332 { /* Transpose the array so we can use C indexing. */
1333 int level, vts;
1334 for(level = 0; level < 8; level++) {
1335 for(vts = 0; vts <= ptl_mait->nr_of_vtss; vts++) {
1336 ptl_mait->countries[i].pf_ptl_mai[vts][level] =
1337 pf_temp[(7-level)*(ptl_mait->nr_of_vtss+1) + vts];
1338 }
1339 }
1340 free(pf_temp);
1341 }
1342 }
1343 return 1;
1344 }
1345
1346 void ifoFree_PTL_MAIT(ifo_handle_t *ifofile) {
1347 unsigned int i;
1348
1349 if(!ifofile)
1350 return;
1351
1352 if(ifofile->ptl_mait) {
1353 for(i = 0; i < ifofile->ptl_mait->nr_of_countries; i++) {
1354 free(ifofile->ptl_mait->countries[i].pf_ptl_mai);
1355 }
1356 free(ifofile->ptl_mait->countries);
1357 free(ifofile->ptl_mait);
1358 ifofile->ptl_mait = 0;
1359 }
1360 }
1361
1362 int ifoRead_VTS_TMAPT(ifo_handle_t *ifofile) {
1363 vts_tmapt_t *vts_tmapt;
1364 uint32_t *vts_tmap_srp;
1365 unsigned int offset;
1366 int info_length;
1367 unsigned int i, j;
1368
1369 if(!ifofile)
1370 return 0;
1371
1372 if(!ifofile->vtsi_mat)
1373 return 0;
1374
1375 if(ifofile->vtsi_mat->vts_tmapt == 0) { /* optional(?) */
1376 ifofile->vts_tmapt = NULL;
1377 fprintf(stderr,"Please send bug report - no VTS_TMAPT ?? \n");
1378 return 1;
1379 }
1380
1381 offset = ifofile->vtsi_mat->vts_tmapt * DVD_BLOCK_LEN;
1382
1383 if(!DVDFileSeek_(ifofile->file, offset))
1384 return 0;
1385
1386 vts_tmapt = (vts_tmapt_t *)malloc(sizeof(vts_tmapt_t));
1387 if(!vts_tmapt)
1388 return 0;
1389
1390 ifofile->vts_tmapt = vts_tmapt;
1391
1392 if(!(DVDReadBytes(ifofile->file, vts_tmapt, VTS_TMAPT_SIZE))) {
1393 fprintf(stderr, "libdvdread: Unable to read VTS_TMAPT.\n");
1394 free(vts_tmapt);
1395 ifofile->vts_tmapt = NULL;
1396 return 0;
1397 }
1398
1399 B2N_16(vts_tmapt->nr_of_tmaps);
1400 B2N_32(vts_tmapt->last_byte);
1401
1402 CHECK_ZERO(vts_tmapt->zero_1);
1403
1404 info_length = vts_tmapt->nr_of_tmaps * 4;
1405
1406 vts_tmap_srp = (uint32_t *)malloc(info_length);
1407 if(!vts_tmap_srp) {
1408 free(vts_tmapt);
1409 ifofile->vts_tmapt = NULL;
1410 return 0;
1411 }
1412
1413 vts_tmapt->tmap_offset = vts_tmap_srp;
1414
1415 if(!(DVDReadBytes(ifofile->file, vts_tmap_srp, info_length))) {
1416 fprintf(stderr, "libdvdread: Unable to read VTS_TMAPT.\n");
1417 free(vts_tmap_srp);
1418 free(vts_tmapt);
1419 ifofile->vts_tmapt = NULL;
1420 return 0;
1421 }
1422
1423 for (i = 0; i < vts_tmapt->nr_of_tmaps; i++) {
1424 B2N_32(vts_tmap_srp[i]);
1425 }
1426
1427
1428 info_length = vts_tmapt->nr_of_tmaps * sizeof(vts_tmap_t);
1429
1430 vts_tmapt->tmap = (vts_tmap_t *)malloc(info_length);
1431 if(!vts_tmapt->tmap) {
1432 free(vts_tmap_srp);
1433 free(vts_tmapt);
1434 ifofile->vts_tmapt = NULL;
1435 return 0;
1436 }
1437
1438 memset(vts_tmapt->tmap, 0, info_length); /* So ifoFree_VTS_TMAPT works. */
1439
1440 for(i = 0; i < vts_tmapt->nr_of_tmaps; i++) {
1441 if(!DVDFileSeek_(ifofile->file, offset + vts_tmap_srp[i])) {
1442 ifoFree_VTS_TMAPT(ifofile);
1443 return 0;
1444 }
1445
1446 if(!(DVDReadBytes(ifofile->file, &vts_tmapt->tmap[i], VTS_TMAP_SIZE))) {
1447 fprintf(stderr, "libdvdread: Unable to read VTS_TMAP.\n");
1448 ifoFree_VTS_TMAPT(ifofile);
1449 return 0;
1450 }
1451
1452 B2N_16(vts_tmapt->tmap[i].nr_of_entries);
1453 CHECK_ZERO(vts_tmapt->tmap[i].zero_1);
1454
1455 if(vts_tmapt->tmap[i].nr_of_entries == 0) { /* Early out if zero entries */
1456 vts_tmapt->tmap[i].map_ent = NULL;
1457 continue;
1458 }
1459
1460 info_length = vts_tmapt->tmap[i].nr_of_entries * sizeof(map_ent_t);
1461
1462 vts_tmapt->tmap[i].map_ent = (map_ent_t *)malloc(info_length);
1463 if(!vts_tmapt->tmap[i].map_ent) {
1464 ifoFree_VTS_TMAPT(ifofile);
1465 return 0;
1466 }
1467
1468 if(!(DVDReadBytes(ifofile->file, vts_tmapt->tmap[i].map_ent, info_length))) {
1469 fprintf(stderr, "libdvdread: Unable to read VTS_TMAP_ENT.\n");
1470 ifoFree_VTS_TMAPT(ifofile);
1471 return 0;
1472 }
1473
1474 for(j = 0; j < vts_tmapt->tmap[i].nr_of_entries; j++)
1475 B2N_32(vts_tmapt->tmap[i].map_ent[j]);
1476 }
1477
1478 return 1;
1479 }
1480
1481 void ifoFree_VTS_TMAPT(ifo_handle_t *ifofile) {
1482 unsigned int i;
1483
1484 if(!ifofile)
1485 return;
1486
1487 if(ifofile->vts_tmapt) {
1488 for(i = 0; i < ifofile->vts_tmapt->nr_of_tmaps; i++)
1489 if(ifofile->vts_tmapt->tmap[i].map_ent)
1490 free(ifofile->vts_tmapt->tmap[i].map_ent);
1491 free(ifofile->vts_tmapt->tmap);
1492 free(ifofile->vts_tmapt->tmap_offset);
1493 free(ifofile->vts_tmapt);
1494 ifofile->vts_tmapt = NULL;
1495 }
1496 }
1497
1498
1499 int ifoRead_TITLE_C_ADT(ifo_handle_t *ifofile) {
1500
1501 if(!ifofile)
1502 return 0;
1503
1504 if(!ifofile->vtsi_mat)
1505 return 0;
1506
1507 if(ifofile->vtsi_mat->vts_c_adt == 0) /* mandatory */
1508 return 0;
1509
1510 ifofile->vts_c_adt = (c_adt_t *)malloc(sizeof(c_adt_t));
1511 if(!ifofile->vts_c_adt)
1512 return 0;
1513
1514 if(!ifoRead_C_ADT_internal(ifofile, ifofile->vts_c_adt,
1515 ifofile->vtsi_mat->vts_c_adt)) {
1516 free(ifofile->vts_c_adt);
1517 ifofile->vts_c_adt = 0;
1518 return 0;
1519 }
1520
1521 return 1;
1522 }
1523
1524 int ifoRead_C_ADT(ifo_handle_t *ifofile) {
1525 unsigned int sector;
1526
1527 if(!ifofile)
1528 return 0;
1529
1530 if(ifofile->vmgi_mat) {
1531 if(ifofile->vmgi_mat->vmgm_c_adt == 0)
1532 return 1;
1533 sector = ifofile->vmgi_mat->vmgm_c_adt;
1534 } else if(ifofile->vtsi_mat) {
1535 if(ifofile->vtsi_mat->vtsm_c_adt == 0)
1536 return 1;
1537 sector = ifofile->vtsi_mat->vtsm_c_adt;
1538 } else {
1539 return 0;
1540 }
1541
1542 ifofile->menu_c_adt = (c_adt_t *)malloc(sizeof(c_adt_t));
1543 if(!ifofile->menu_c_adt)
1544 return 0;
1545
1546 if(!ifoRead_C_ADT_internal(ifofile, ifofile->menu_c_adt, sector)) {
1547 free(ifofile->menu_c_adt);
1548 ifofile->menu_c_adt = 0;
1549 return 0;
1550 }
1551
1552 return 1;
1553 }
1554
1555 static int ifoRead_C_ADT_internal(ifo_handle_t *ifofile,
1556 c_adt_t *c_adt, unsigned int sector) {
1557 int i, info_length;
1558
1559 if(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN))
1560 return 0;
1561
1562 if(!(DVDReadBytes(ifofile->file, c_adt, C_ADT_SIZE)))
1563 return 0;
1564
1565 B2N_16(c_adt->nr_of_vobs);
1566 B2N_32(c_adt->last_byte);
1567
1568 info_length = c_adt->last_byte + 1 - C_ADT_SIZE;
1569
1570 CHECK_ZERO(c_adt->zero_1);
1571 /* assert(c_adt->nr_of_vobs > 0);
1572 Magic Knight Rayearth Daybreak is mastered very strange and has
1573 Titles with a VOBS that has no cells. */
1574 CHECK_VALUE(info_length % sizeof(cell_adr_t) == 0);
1575
1576 /* assert(info_length / sizeof(cell_adr_t) >= c_adt->nr_of_vobs);
1577 Enemy of the State region 2 (de) has Titles where nr_of_vobs field
1578 is to high, they high ones are never referenced though. */
1579 if(info_length / sizeof(cell_adr_t) < c_adt->nr_of_vobs) {
1580 fprintf(stderr, "libdvdread: *C_ADT nr_of_vobs > avaiable info entries\n");
1581 c_adt->nr_of_vobs = info_length / sizeof(cell_adr_t);
1582 }
1583
1584 c_adt->cell_adr_table = (cell_adr_t *)malloc(info_length);
1585 if(!c_adt->cell_adr_table)
1586 return 0;
1587
1588 if(info_length &&
1589 !(DVDReadBytes(ifofile->file, c_adt->cell_adr_table, info_length))) {
1590 free(c_adt->cell_adr_table);
1591 return 0;
1592 }
1593
1594 for(i = 0; i < info_length/sizeof(cell_adr_t); i++) {
1595 B2N_16(c_adt->cell_adr_table[i].vob_id);
1596 B2N_32(c_adt->cell_adr_table[i].start_sector);
1597 B2N_32(c_adt->cell_adr_table[i].last_sector);
1598
1599 CHECK_ZERO(c_adt->cell_adr_table[i].zero_1);
1600 CHECK_VALUE(c_adt->cell_adr_table[i].vob_id > 0);
1601 CHECK_VALUE(c_adt->cell_adr_table[i].vob_id <= c_adt->nr_of_vobs);
1602 CHECK_VALUE(c_adt->cell_adr_table[i].cell_id > 0);
1603 CHECK_VALUE(c_adt->cell_adr_table[i].start_sector <
1604 c_adt->cell_adr_table[i].last_sector);
1605 }
1606
1607 return 1;
1608 }
1609
1610
1611 static void ifoFree_C_ADT_internal(c_adt_t *c_adt) {
1612 if(c_adt) {
1613 free(c_adt->cell_adr_table);
1614 free(c_adt);
1615 }
1616 }
1617
1618 void ifoFree_C_ADT(ifo_handle_t *ifofile) {
1619 if(!ifofile)
1620 return;
1621
1622 ifoFree_C_ADT_internal(ifofile->menu_c_adt);
1623 ifofile->menu_c_adt = 0;
1624 }
1625
1626 void ifoFree_TITLE_C_ADT(ifo_handle_t *ifofile) {
1627 if(!ifofile)
1628 return;
1629
1630 ifoFree_C_ADT_internal(ifofile->vts_c_adt);
1631 ifofile->vts_c_adt = 0;
1632 }
1633
1634 int ifoRead_TITLE_VOBU_ADMAP(ifo_handle_t *ifofile) {
1635 if(!ifofile)
1636 return 0;
1637
1638 if(!ifofile->vtsi_mat)
1639 return 0;
1640
1641 if(ifofile->vtsi_mat->vts_vobu_admap == 0) /* mandatory */
1642 return 0;
1643
1644 ifofile->vts_vobu_admap = (vobu_admap_t *)malloc(sizeof(vobu_admap_t));
1645 if(!ifofile->vts_vobu_admap)
1646 return 0;
1647
1648 if(!ifoRead_VOBU_ADMAP_internal(ifofile, ifofile->vts_vobu_admap,
1649 ifofile->vtsi_mat->vts_vobu_admap)) {
1650 free(ifofile->vts_vobu_admap);
1651 ifofile->vts_vobu_admap = 0;
1652 return 0;
1653 }
1654
1655 return 1;
1656 }
1657
1658 int ifoRead_VOBU_ADMAP(ifo_handle_t *ifofile) {
1659 unsigned int sector;
1660
1661 if(!ifofile)
1662 return 0;
1663
1664 if(ifofile->vmgi_mat) {
1665 if(ifofile->vmgi_mat->vmgm_vobu_admap == 0)
1666 return 1;
1667 sector = ifofile->vmgi_mat->vmgm_vobu_admap;
1668 } else if(ifofile->vtsi_mat) {
1669 if(ifofile->vtsi_mat->vtsm_vobu_admap == 0)
1670 return 1;
1671 sector = ifofile->vtsi_mat->vtsm_vobu_admap;
1672 } else {
1673 return 0;
1674 }
1675
1676 ifofile->menu_vobu_admap = (vobu_admap_t *)malloc(sizeof(vobu_admap_t));
1677 if(!ifofile->menu_vobu_admap)
1678 return 0;
1679
1680 if(!ifoRead_VOBU_ADMAP_internal(ifofile, ifofile->menu_vobu_admap, sector)) {
1681 free(ifofile->menu_vobu_admap);
1682 ifofile->menu_vobu_admap = 0;
1683 return 0;
1684 }
1685
1686 return 1;
1687 }
1688
1689 static int ifoRead_VOBU_ADMAP_internal(ifo_handle_t *ifofile,
1690 vobu_admap_t *vobu_admap,
1691 unsigned int sector) {
1692 unsigned int i;
1693 int info_length;
1694
1695 if(!DVDFileSeekForce_(ifofile->file, sector * DVD_BLOCK_LEN, sector))
1696 return 0;
1697
1698 if(!(DVDReadBytes(ifofile->file, vobu_admap, VOBU_ADMAP_SIZE)))
1699 return 0;
1700
1701 B2N_32(vobu_admap->last_byte);
1702
1703 info_length = vobu_admap->last_byte + 1 - VOBU_ADMAP_SIZE;
1704 /* assert(info_length > 0);
1705 Magic Knight Rayearth Daybreak is mastered very strange and has
1706 Titles with a VOBS that has no VOBUs. */
1707 CHECK_VALUE(info_length % sizeof(uint32_t) == 0);
1708
1709 vobu_admap->vobu_start_sectors = (uint32_t *)malloc(info_length);
1710 if(!vobu_admap->vobu_start_sectors) {
1711 return 0;
1712 }
1713 if(info_length &&
1714 !(DVDReadBytes(ifofile->file,
1715 vobu_admap->vobu_start_sectors, info_length))) {
1716 free(vobu_admap->vobu_start_sectors);
1717 return 0;
1718 }
1719
1720 for(i = 0; i < info_length/sizeof(uint32_t); i++)
1721 B2N_32(vobu_admap->vobu_start_sectors[i]);
1722
1723 return 1;
1724 }
1725
1726
1727 static void ifoFree_VOBU_ADMAP_internal(vobu_admap_t *vobu_admap) {
1728 if(vobu_admap) {
1729 free(vobu_admap->vobu_start_sectors);
1730 free(vobu_admap);
1731 }
1732 }
1733
1734 void ifoFree_VOBU_ADMAP(ifo_handle_t *ifofile) {
1735 if(!ifofile)
1736 return;
1737
1738 ifoFree_VOBU_ADMAP_internal(ifofile->menu_vobu_admap);
1739 ifofile->menu_vobu_admap = 0;
1740 }
1741
1742 void ifoFree_TITLE_VOBU_ADMAP(ifo_handle_t *ifofile) {
1743 if(!ifofile)
1744 return;
1745
1746 ifoFree_VOBU_ADMAP_internal(ifofile->vts_vobu_admap);
1747 ifofile->vts_vobu_admap = 0;
1748 }
1749
1750 int ifoRead_PGCIT(ifo_handle_t *ifofile) {
1751
1752 if(!ifofile)
1753 return 0;
1754
1755 if(!ifofile->vtsi_mat)
1756 return 0;
1757
1758 if(ifofile->vtsi_mat->vts_pgcit == 0) /* mandatory */
1759 return 0;
1760
1761 ifofile->vts_pgcit = (pgcit_t *)malloc(sizeof(pgcit_t));
1762 if(!ifofile->vts_pgcit)
1763 return 0;
1764
1765 if(!ifoRead_PGCIT_internal(ifofile, ifofile->vts_pgcit,
1766 ifofile->vtsi_mat->vts_pgcit * DVD_BLOCK_LEN)) {
1767 free(ifofile->vts_pgcit);
1768 ifofile->vts_pgcit = 0;
1769 return 0;
1770 }
1771
1772 return 1;
1773 }
1774
1775 static int ifoRead_PGCIT_internal(ifo_handle_t *ifofile, pgcit_t *pgcit,
1776 unsigned int offset) {
1777 int i, info_length;
1778 uint8_t *data, *ptr;
1779
1780 if(!DVDFileSeek_(ifofile->file, offset))
1781 return 0;
1782
1783 if(!(DVDReadBytes(ifofile->file, pgcit, PGCIT_SIZE)))
1784 return 0;
1785
1786 B2N_16(pgcit->nr_of_pgci_srp);
1787 B2N_32(pgcit->last_byte);
1788
1789 CHECK_ZERO(pgcit->zero_1);
1790 /* assert(pgcit->nr_of_pgci_srp != 0);
1791 Magic Knight Rayearth Daybreak is mastered very strange and has
1792 Titles with 0 PTTs. */
1793 CHECK_VALUE(pgcit->nr_of_pgci_srp < 10000); /* ?? seen max of 1338 */
1794
1795 info_length = pgcit->nr_of_pgci_srp * PGCI_SRP_SIZE;
1796 data = malloc(info_length);
1797 if(!data)
1798 return 0;
1799
1800 if(info_length && !(DVDReadBytes(ifofile->file, data, info_length))) {
1801 free(data);
1802 return 0;
1803 }
1804
1805 pgcit->pgci_srp = malloc(pgcit->nr_of_pgci_srp * sizeof(pgci_srp_t));
1806 if(!pgcit->pgci_srp) {
1807 free(data);
1808 return 0;
1809 }
1810 ptr = data;
1811 for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
1812 memcpy(&pgcit->pgci_srp[i], ptr, PGCI_SRP_SIZE);
1813 ptr += PGCI_SRP_SIZE;
1814 read_pgci_srp(&pgcit->pgci_srp[i]);
1815 CHECK_VALUE(pgcit->pgci_srp[i].unknown1 == 0);
1816 }
1817 free(data);
1818
1819 for(i = 0; i < pgcit->nr_of_pgci_srp; i++)
1820 CHECK_VALUE(pgcit->pgci_srp[i].pgc_start_byte + PGC_SIZE <= pgcit->last_byte+1);
1821
1822 for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
1823 pgcit->pgci_srp[i].pgc = malloc(sizeof(pgc_t));
1824 if(!pgcit->pgci_srp[i].pgc) {
1825 int j;
1826 for(j = 0; j < i; j++) {
1827 ifoFree_PGC(pgcit->pgci_srp[j].pgc);
1828 free(pgcit->pgci_srp[j].pgc);
1829 }
1830 goto fail;
1831 }
1832 if(!ifoRead_PGC(ifofile, pgcit->pgci_srp[i].pgc,
1833 offset + pgcit->pgci_srp[i].pgc_start_byte)) {
1834 int j;
1835 for(j = 0; j < i; j++) {
1836 ifoFree_PGC(pgcit->pgci_srp[j].pgc);
1837 free(pgcit->pgci_srp[j].pgc);
1838 }
1839 goto fail;
1840 }
1841 }
1842
1843 return 1;
1844 fail:
1845 free(pgcit->pgci_srp);
1846 pgcit->pgci_srp = NULL;
1847 return 0;
1848 }
1849
1850 static void ifoFree_PGCIT_internal(pgcit_t *pgcit) {
1851 if(pgcit) {
1852 int i;
1853 for(i = 0; i < pgcit->nr_of_pgci_srp; i++)
1854 ifoFree_PGC(pgcit->pgci_srp[i].pgc);
1855 free(pgcit->pgci_srp);
1856 }
1857 }
1858
1859 void ifoFree_PGCIT(ifo_handle_t *ifofile) {
1860 if(!ifofile)
1861 return;
1862
1863 if(ifofile->vts_pgcit) {
1864 ifoFree_PGCIT_internal(ifofile->vts_pgcit);
1865 free(ifofile->vts_pgcit);
1866 ifofile->vts_pgcit = 0;
1867 }
1868 }
1869
1870
1871 int ifoRead_PGCI_UT(ifo_handle_t *ifofile) {
1872 pgci_ut_t *pgci_ut;
1873 unsigned int sector;
1874 unsigned int i;
1875 int info_length;
1876 uint8_t *data, *ptr;
1877
1878 if(!ifofile)
1879 return 0;
1880
1881 if(ifofile->vmgi_mat) {
1882 if(ifofile->vmgi_mat->vmgm_pgci_ut == 0)
1883 return 1;
1884 sector = ifofile->vmgi_mat->vmgm_pgci_ut;
1885 } else if(ifofile->vtsi_mat) {
1886 if(ifofile->vtsi_mat->vtsm_pgci_ut == 0)
1887 return 1;
1888 sector = ifofile->vtsi_mat->vtsm_pgci_ut;
1889 } else {
1890 return 0;
1891 }
1892
1893 ifofile->pgci_ut = (pgci_ut_t *)malloc(sizeof(pgci_ut_t));
1894 if(!ifofile->pgci_ut)
1895 return 0;
1896
1897 if(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN)) {
1898 free(ifofile->pgci_ut);
1899 ifofile->pgci_ut = 0;
1900 return 0;
1901 }
1902
1903 if(!(DVDReadBytes(ifofile->file, ifofile->pgci_ut, PGCI_UT_SIZE))) {
1904 free(ifofile->pgci_ut);
1905 ifofile->pgci_ut = 0;
1906 return 0;
1907 }
1908
1909 pgci_ut = ifofile->pgci_ut;
1910
1911 B2N_16(pgci_ut->nr_of_lus);
1912 B2N_32(pgci_ut->last_byte);
1913
1914 CHECK_ZERO(pgci_ut->zero_1);
1915 CHECK_VALUE(pgci_ut->nr_of_lus != 0);
1916 CHECK_VALUE(pgci_ut->nr_of_lus < 100); /* ?? 3-4 ? */
1917 CHECK_VALUE((uint32_t)pgci_ut->nr_of_lus * PGCI_LU_SIZE < pgci_ut->last_byte);
1918
1919 info_length = pgci_ut->nr_of_lus * PGCI_LU_SIZE;
1920 data = malloc(info_length);
1921 if(!data) {
1922 free(pgci_ut);
1923 ifofile->pgci_ut = 0;
1924 return 0;
1925 }
1926 if(!(DVDReadBytes(ifofile->file, data, info_length))) {
1927 free(data);
1928 free(pgci_ut);
1929 ifofile->pgci_ut = 0;
1930 return 0;
1931 }
1932
1933 pgci_ut->lu = malloc(pgci_ut->nr_of_lus * sizeof(pgci_lu_t));
1934 if(!pgci_ut->lu) {
1935 free(data);
1936 free(pgci_ut);
1937 ifofile->pgci_ut = 0;
1938 return 0;
1939 }
1940 ptr = data;
1941 for(i = 0; i < pgci_ut->nr_of_lus; i++) {
1942 memcpy(&pgci_ut->lu[i], ptr, PGCI_LU_SIZE);
1943 ptr += PGCI_LU_SIZE;
1944 B2N_16(pgci_ut->lu[i].lang_code);
1945 B2N_32(pgci_ut->lu[i].lang_start_byte);
1946 }
1947 free(data);
1948
1949 for(i = 0; i < pgci_ut->nr_of_lus; i++) {
1950 /* Maybe this is only defined for v1.1 and later titles? */
1951 /* If the bits in 'lu[i].exists' are enumerated abcd efgh then:
1952 VTS_x_yy.IFO VIDEO_TS.IFO
1953 a == 0x83 "Root" 0x82 "Title"
1954 b == 0x84 "Subpicture"
1955 c == 0x85 "Audio"
1956 d == 0x86 "Angle"
1957 e == 0x87 "PTT"
1958 */
1959 CHECK_VALUE((pgci_ut->lu[i].exists & 0x07) == 0);
1960 }
1961
1962 for(i = 0; i < pgci_ut->nr_of_lus; i++) {
1963 pgci_ut->lu[i].pgcit = malloc(sizeof(pgcit_t));
1964 if(!pgci_ut->lu[i].pgcit) {
1965 unsigned int j;
1966 for(j = 0; j < i; j++) {
1967 ifoFree_PGCIT_internal(pgci_ut->lu[j].pgcit);
1968 free(pgci_ut->lu[j].pgcit);
1969 }
1970 free(pgci_ut->lu);
1971 free(pgci_ut);
1972 ifofile->pgci_ut = 0;
1973 return 0;
1974 }
1975 if(!ifoRead_PGCIT_internal(ifofile, pgci_ut->lu[i].pgcit,
1976 sector * DVD_BLOCK_LEN
1977 + pgci_ut->lu[i].lang_start_byte)) {
1978 unsigned int j;
1979 for(j = 0; j < i; j++) {
1980 ifoFree_PGCIT_internal(pgci_ut->lu[j].pgcit);
1981 free(pgci_ut->lu[j].pgcit);
1982 }
1983 free(pgci_ut->lu[i].pgcit);
1984 free(pgci_ut->lu);
1985 free(pgci_ut);
1986 ifofile->pgci_ut = 0;
1987 return 0;
1988 }
1989 /*
1990 * FIXME: Iterate and verify that all menus that should exists accordingly
1991 * to pgci_ut->lu[i].exists really do?
1992 */
1993 }
1994
1995 return 1;
1996 }
1997
1998
1999 void ifoFree_PGCI_UT(ifo_handle_t *ifofile) {
2000 unsigned int i;
2001
2002 if(!ifofile)
2003 return;
2004
2005 if(ifofile->pgci_ut) {
2006 for(i = 0; i < ifofile->pgci_ut->nr_of_lus; i++) {
2007 ifoFree_PGCIT_internal(ifofile->pgci_ut->lu[i].pgcit);
2008 free(ifofile->pgci_ut->lu[i].pgcit);
2009 }
2010 free(ifofile->pgci_ut->lu);
2011 free(ifofile->pgci_ut);
2012 ifofile->pgci_ut = 0;
2013 }
2014 }
2015
2016 static int ifoRead_VTS_ATTRIBUTES(ifo_handle_t *ifofile,
2017 vts_attributes_t *vts_attributes,
2018 unsigned int offset) {
2019 unsigned int i;
2020
2021 if(!DVDFileSeek_(ifofile->file, offset))
2022 return 0;
2023
2024 if(!(DVDReadBytes(ifofile->file, vts_attributes, sizeof(vts_attributes_t))))
2025 return 0;
2026
2027 read_video_attr(&vts_attributes->vtsm_vobs_attr);
2028 read_video_attr(&vts_attributes->vtstt_vobs_video_attr);
2029 read_audio_attr(&vts_attributes->vtsm_audio_attr);
2030 for(i=0; i<8; i++)
2031 read_audio_attr(&vts_attributes->vtstt_audio_attr[i]);
2032 read_subp_attr(&vts_attributes->vtsm_subp_attr);
2033 for(i=0; i<32; i++)
2034 read_subp_attr(&vts_attributes->vtstt_subp_attr[i]);
2035 B2N_32(vts_attributes->last_byte);
2036 B2N_32(vts_attributes->vts_cat);
2037
2038 CHECK_ZERO(vts_attributes->zero_1);
2039 CHECK_ZERO(vts_attributes->zero_2);
2040 CHECK_ZERO(vts_attributes->zero_3);
2041 CHECK_ZERO(vts_attributes->zero_4);
2042 CHECK_ZERO(vts_attributes->zero_5);
2043 CHECK_ZERO(vts_attributes->zero_6);
2044 CHECK_ZERO(vts_attributes->zero_7);
2045 CHECK_VALUE(vts_attributes->nr_of_vtsm_audio_streams <= 1);
2046 CHECK_VALUE(vts_attributes->nr_of_vtsm_subp_streams <= 1);
2047 CHECK_VALUE(vts_attributes->nr_of_vtstt_audio_streams <= 8);
2048 for(i = vts_attributes->nr_of_vtstt_audio_streams; i < 8; i++)
2049 CHECK_ZERO(vts_attributes->vtstt_audio_attr[i]);
2050 CHECK_VALUE(vts_attributes->nr_of_vtstt_subp_streams <= 32);
2051 {
2052 unsigned int nr_coded;
2053 CHECK_VALUE(vts_attributes->last_byte + 1 >= VTS_ATTRIBUTES_MIN_SIZE);
2054 nr_coded = (vts_attributes->last_byte + 1 - VTS_ATTRIBUTES_MIN_SIZE)/6;
2055 /* This is often nr_coded = 70, how do you know how many there really are? */
2056 if(nr_coded > 32) { /* We haven't read more from disk/file anyway */
2057 nr_coded = 32;
2058 }
2059 CHECK_VALUE(vts_attributes->nr_of_vtstt_subp_streams <= nr_coded);
2060 for(i = vts_attributes->nr_of_vtstt_subp_streams; i < nr_coded; i++)
2061 CHECK_ZERO(vts_attributes->vtstt_subp_attr[i]);
2062 }
2063
2064 return 1;
2065 }
2066
2067
2068
2069 int ifoRead_VTS_ATRT(ifo_handle_t *ifofile) {
2070 vts_atrt_t *vts_atrt;
2071 unsigned int i, info_length, sector;
2072 uint32_t *data;
2073
2074 if(!ifofile)
2075 return 0;
2076
2077 if(!ifofile->vmgi_mat)
2078 return 0;
2079
2080 if(ifofile->vmgi_mat->vts_atrt == 0) /* mandatory */
2081 return 0;
2082
2083 sector = ifofile->vmgi_mat->vts_atrt;
2084 if(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN))
2085 return 0;
2086
2087 vts_atrt = (vts_atrt_t *)malloc(sizeof(vts_atrt_t));
2088 if(!vts_atrt)
2089 return 0;
2090
2091 ifofile->vts_atrt = vts_atrt;
2092
2093 if(!(DVDReadBytes(ifofile->file, vts_atrt, VTS_ATRT_SIZE))) {
2094 free(vts_atrt);
2095 ifofile->vts_atrt = 0;
2096 return 0;
2097 }
2098
2099 B2N_16(vts_atrt->nr_of_vtss);
2100 B2N_32(vts_atrt->last_byte);
2101
2102 CHECK_ZERO(vts_atrt->zero_1);
2103 CHECK_VALUE(vts_atrt->nr_of_vtss != 0);
2104 CHECK_VALUE(vts_atrt->nr_of_vtss < 100); /* ?? */
2105 CHECK_VALUE((uint32_t)vts_atrt->nr_of_vtss * (4 + VTS_ATTRIBUTES_MIN_SIZE) +
2106 VTS_ATRT_SIZE < vts_atrt->last_byte + 1);
2107
2108 info_length = vts_atrt->nr_of_vtss * sizeof(uint32_t);
2109 data = (uint32_t *)malloc(info_length);
2110 if(!data) {
2111 free(vts_atrt);
2112 ifofile->vts_atrt = 0;
2113 return 0;
2114 }
2115
2116 vts_atrt->vts_atrt_offsets = data;
2117
2118 if(!(DVDReadBytes(ifofile->file, data, info_length))) {
2119 free(data);
2120 free(vts_atrt);
2121 ifofile->vts_atrt = 0;
2122 return 0;
2123 }
2124
2125 for(i = 0; i < vts_atrt->nr_of_vtss; i++) {
2126 B2N_32(data[i]);
2127 CHECK_VALUE(data[i] + VTS_ATTRIBUTES_MIN_SIZE < vts_atrt->last_byte + 1);
2128 }
2129
2130 info_length = vts_atrt->nr_of_vtss * sizeof(vts_attributes_t);
2131 vts_atrt->vts = (vts_attributes_t *)malloc(info_length);
2132 if(!vts_atrt->vts) {
2133 free(data);
2134 free(vts_atrt);
2135 ifofile->vts_atrt = 0;
2136 return 0;
2137 }
2138 for(i = 0; i < vts_atrt->nr_of_vtss; i++) {
2139 unsigned int offset = data[i];
2140 if(!ifoRead_VTS_ATTRIBUTES(ifofile, &(vts_atrt->vts[i]),
2141 (sector * DVD_BLOCK_LEN) + offset)) {
2142 free(data);
2143 free(vts_atrt);
2144 ifofile->vts_atrt = 0;
2145 return 0;
2146 }
2147
2148 /* This assert cant be in ifoRead_VTS_ATTRIBUTES */
2149 CHECK_VALUE(offset + vts_atrt->vts[i].last_byte <= vts_atrt->last_byte + 1);
2150 /* Is this check correct? */
2151 }
2152
2153 return 1;
2154 }
2155
2156
2157 void ifoFree_VTS_ATRT(ifo_handle_t *ifofile) {
2158 if(!ifofile)
2159 return;
2160
2161 if(ifofile->vts_atrt) {
2162 free(ifofile->vts_atrt->vts);
2163 free(ifofile->vts_atrt->vts_atrt_offsets);
2164 free(ifofile->vts_atrt);
2165 ifofile->vts_atrt = 0;
2166 }
2167 }
2168
2169
2170 int ifoRead_TXTDT_MGI(ifo_handle_t *ifofile) {
2171 txtdt_mgi_t *txtdt_mgi;
2172
2173 if(!ifofile)
2174 return 0;
2175
2176 if(!ifofile->vmgi_mat)
2177 return 0;
2178
2179 /* Return successfully if there is nothing to read. */
2180 if(ifofile->vmgi_mat->txtdt_mgi == 0)
2181 return 1;
2182
2183 if(!DVDFileSeek_(ifofile->file,
2184 ifofile->vmgi_mat->txtdt_mgi * DVD_BLOCK_LEN))
2185 return 0;
2186
2187 txtdt_mgi = (txtdt_mgi_t *)malloc(sizeof(txtdt_mgi_t));
2188 if(!txtdt_mgi) {
2189 return 0;
2190 }
2191 ifofile->txtdt_mgi = txtdt_mgi;
2192
2193 if(!(DVDReadBytes(ifofile->file, txtdt_mgi, TXTDT_MGI_SIZE))) {
2194 fprintf(stderr, "libdvdread: Unable to read TXTDT_MGI.\n");
2195 free(txtdt_mgi);
2196 ifofile->txtdt_mgi = 0;
2197 return 0;
2198 }
2199
2200 /* fprintf(stderr, "-- Not done yet --\n"); */
2201 return 1;
2202 }
2203
2204 void ifoFree_TXTDT_MGI(ifo_handle_t *ifofile) {
2205 if(!ifofile)
2206 return;
2207
2208 if(ifofile->txtdt_mgi) {
2209 free(ifofile->txtdt_mgi);
2210 ifofile->txtdt_mgi = 0;
2211 }
2212 }
2213