2 * Copyright (C) 2000, 2001, 2002, 2003
3 * Björn Englund <d4bjorn@dtek.chalmers.se>,
4 * Håkan Hjort <d95hjort@dtek.chalmers.se>
6 * Modified for use with MPlayer, changes contained in libdvdread_changes.diff.
7 * detailed changelog at http://svn.mplayerhq.hu/mplayer/trunk/
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #include "ifo_types.h"
35 #include "dvd_reader.h"
36 #include "dvdread_internal.h"
39 #define DVD_BLOCK_LEN 2048
43 #define CHECK_ZERO0(arg) \
45 fprintf(stderr, "*** Zero check failed in %s:%i\n for %s = 0x%x\n", \
46 __FILE__, __LINE__, # arg, arg); \
48 #define CHECK_ZERO(arg) \
49 if(memcmp(my_friendly_zeros, &arg, sizeof(arg))) { \
51 fprintf(stderr, "*** Zero check failed in %s:%i\n for %s = 0x", \
52 __FILE__, __LINE__, # arg ); \
53 for(i_CZ = 0; i_CZ < sizeof(arg); i_CZ++) \
54 fprintf(stderr, "%02x", *((uint8_t *)&arg + i_CZ)); \
55 fprintf(stderr, "\n"); \
57 static const uint8_t my_friendly_zeros
[2048];
59 #define CHECK_ZERO0(arg) (void)(arg)
60 #define CHECK_ZERO(arg) (void)(arg)
64 /* Prototypes for internal functions */
65 static int ifoRead_VMG(ifo_handle_t
*ifofile
);
66 static int ifoRead_VTS(ifo_handle_t
*ifofile
);
67 static int ifoRead_PGC(ifo_handle_t
*ifofile
, pgc_t
*pgc
, unsigned int offset
);
68 static int ifoRead_PGC_COMMAND_TBL(ifo_handle_t
*ifofile
,
69 pgc_command_tbl_t
*cmd_tbl
,
71 static int ifoRead_PGC_PROGRAM_MAP(ifo_handle_t
*ifofile
,
72 pgc_program_map_t
*program_map
,
73 unsigned int nr
, unsigned int offset
);
74 static int ifoRead_CELL_PLAYBACK_TBL(ifo_handle_t
*ifofile
,
75 cell_playback_t
*cell_playback
,
76 unsigned int nr
, unsigned int offset
);
77 static int ifoRead_CELL_POSITION_TBL(ifo_handle_t
*ifofile
,
78 cell_position_t
*cell_position
,
79 unsigned int nr
, unsigned int offset
);
80 static int ifoRead_VTS_ATTRIBUTES(ifo_handle_t
*ifofile
,
81 vts_attributes_t
*vts_attributes
,
83 static int ifoRead_C_ADT_internal(ifo_handle_t
*ifofile
, c_adt_t
*c_adt
,
85 static int ifoRead_VOBU_ADMAP_internal(ifo_handle_t
*ifofile
,
86 vobu_admap_t
*vobu_admap
,
88 static int ifoRead_PGCIT_internal(ifo_handle_t
*ifofile
, pgcit_t
*pgcit
,
91 static void ifoFree_PGC(pgc_t
*pgc
);
92 static void ifoFree_PGC_COMMAND_TBL(pgc_command_tbl_t
*cmd_tbl
);
93 static void ifoFree_PGCIT_internal(pgcit_t
*pgcit
);
96 static inline int DVDFileSeek_( dvd_file_t
*dvd_file
, uint32_t offset
) {
97 return (DVDFileSeek(dvd_file
, (int)offset
) == (int)offset
);
101 ifo_handle_t
*ifoOpen(dvd_reader_t
*dvd
, int title
) {
102 ifo_handle_t
*ifofile
;
104 ifofile
= malloc(sizeof(ifo_handle_t
));
108 memset(ifofile
, 0, sizeof(ifo_handle_t
));
110 ifofile
->file
= DVDOpenFile(dvd
, title
, DVD_READ_INFO_FILE
);
111 if(!ifofile
->file
) /* Should really catch any error and try to fallback */
112 ifofile
->file
= DVDOpenFile(dvd
, title
, DVD_READ_INFO_BACKUP_FILE
);
115 fprintf(stderr
, "libdvdread: Can't open file VTS_%02d_0.IFO.\n", title
);
117 fprintf(stderr
, "libdvdread: Can't open file VIDEO_TS.IFO.\n");
123 /* First check if this is a VMGI file. */
124 if(ifoRead_VMG(ifofile
)) {
126 /* These are both mandatory. */
127 if(!ifoRead_FP_PGC(ifofile
) || !ifoRead_TT_SRPT(ifofile
)) {
128 fprintf(stderr
, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO).\n");
133 ifoRead_PGCI_UT(ifofile
);
134 ifoRead_PTL_MAIT(ifofile
);
136 /* This is also mandatory. */
137 if(!ifoRead_VTS_ATRT(ifofile
)) {
138 fprintf(stderr
, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO).\n");
143 ifoRead_TXTDT_MGI(ifofile
);
144 ifoRead_C_ADT(ifofile
);
145 ifoRead_VOBU_ADMAP(ifofile
);
150 if(ifoRead_VTS(ifofile
)) {
152 if(!ifoRead_VTS_PTT_SRPT(ifofile
) || !ifoRead_PGCIT(ifofile
)) {
153 fprintf(stderr
, "libdvdread: Invalid title IFO (VTS_%02d_0.IFO).\n",
160 ifoRead_PGCI_UT(ifofile
);
161 ifoRead_VTS_TMAPT(ifofile
);
162 ifoRead_C_ADT(ifofile
);
163 ifoRead_VOBU_ADMAP(ifofile
);
165 if(!ifoRead_TITLE_C_ADT(ifofile
) || !ifoRead_TITLE_VOBU_ADMAP(ifofile
)) {
166 fprintf(stderr
, "libdvdread: Invalid title IFO (VTS_%02d_0.IFO).\n",
176 fprintf(stderr
, "libdvdread: Invalid IFO for title %d (VTS_%02d_0.IFO).\n",
179 fprintf(stderr
, "libdvdread: Invalid IFO for VMGM (VIDEO_TS.IFO).\n");
186 ifo_handle_t
*ifoOpenVMGI(dvd_reader_t
*dvd
) {
187 ifo_handle_t
*ifofile
;
189 ifofile
= malloc(sizeof(ifo_handle_t
));
193 memset(ifofile
, 0, sizeof(ifo_handle_t
));
195 ifofile
->file
= DVDOpenFile(dvd
, 0, DVD_READ_INFO_FILE
);
196 if(!ifofile
->file
) /* Should really catch any error and try to fallback */
197 ifofile
->file
= DVDOpenFile(dvd
, 0, DVD_READ_INFO_BACKUP_FILE
);
199 fprintf(stderr
, "libdvdread: Can't open file VIDEO_TS.IFO.\n");
204 if(ifoRead_VMG(ifofile
))
207 fprintf(stderr
, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO).\n");
213 ifo_handle_t
*ifoOpenVTSI(dvd_reader_t
*dvd
, int title
) {
214 ifo_handle_t
*ifofile
;
216 ifofile
= malloc(sizeof(ifo_handle_t
));
220 memset(ifofile
, 0, sizeof(ifo_handle_t
));
222 if(title
<= 0 || title
> 99) {
223 fprintf(stderr
, "libdvdread: ifoOpenVTSI invalid title (%d).\n", title
);
228 ifofile
->file
= DVDOpenFile(dvd
, title
, DVD_READ_INFO_FILE
);
229 if(!ifofile
->file
) /* Should really catch any error and try to fallback */
230 ifofile
->file
= DVDOpenFile(dvd
, title
, DVD_READ_INFO_BACKUP_FILE
);
232 fprintf(stderr
, "libdvdread: Can't open file VTS_%02d_0.IFO.\n", title
);
237 ifoRead_VTS(ifofile
);
238 if(ifofile
->vtsi_mat
)
241 fprintf(stderr
, "libdvdread: Invalid IFO for title %d (VTS_%02d_0.IFO).\n",
248 void ifoClose(ifo_handle_t
*ifofile
) {
252 ifoFree_VOBU_ADMAP(ifofile
);
253 ifoFree_TITLE_VOBU_ADMAP(ifofile
);
254 ifoFree_C_ADT(ifofile
);
255 ifoFree_TITLE_C_ADT(ifofile
);
256 ifoFree_TXTDT_MGI(ifofile
);
257 ifoFree_VTS_ATRT(ifofile
);
258 ifoFree_PTL_MAIT(ifofile
);
259 ifoFree_PGCI_UT(ifofile
);
260 ifoFree_TT_SRPT(ifofile
);
261 ifoFree_FP_PGC(ifofile
);
262 ifoFree_PGCIT(ifofile
);
263 ifoFree_VTS_PTT_SRPT(ifofile
);
265 if(ifofile
->vmgi_mat
)
266 free(ifofile
->vmgi_mat
);
268 if(ifofile
->vtsi_mat
)
269 free(ifofile
->vtsi_mat
);
271 DVDCloseFile(ifofile
->file
);
278 static int ifoRead_VMG(ifo_handle_t
*ifofile
) {
279 vmgi_mat_t
*vmgi_mat
;
281 vmgi_mat
= malloc(sizeof(vmgi_mat_t
));
285 ifofile
->vmgi_mat
= vmgi_mat
;
287 if(!DVDFileSeek_(ifofile
->file
, 0)) {
288 free(ifofile
->vmgi_mat
);
289 ifofile
->vmgi_mat
= 0;
293 if(!DVDReadBytes(ifofile
->file
, vmgi_mat
, sizeof(vmgi_mat_t
))) {
294 free(ifofile
->vmgi_mat
);
295 ifofile
->vmgi_mat
= 0;
299 if(strncmp("DVDVIDEO-VMG", vmgi_mat
->vmg_identifier
, 12) != 0) {
300 free(ifofile
->vmgi_mat
);
301 ifofile
->vmgi_mat
= 0;
305 B2N_32(vmgi_mat
->vmg_last_sector
);
306 B2N_32(vmgi_mat
->vmgi_last_sector
);
307 B2N_32(vmgi_mat
->vmg_category
);
308 B2N_16(vmgi_mat
->vmg_nr_of_volumes
);
309 B2N_16(vmgi_mat
->vmg_this_volume_nr
);
310 B2N_16(vmgi_mat
->vmg_nr_of_title_sets
);
311 B2N_64(vmgi_mat
->vmg_pos_code
);
312 B2N_32(vmgi_mat
->vmgi_last_byte
);
313 B2N_32(vmgi_mat
->first_play_pgc
);
314 B2N_32(vmgi_mat
->vmgm_vobs
);
315 B2N_32(vmgi_mat
->tt_srpt
);
316 B2N_32(vmgi_mat
->vmgm_pgci_ut
);
317 B2N_32(vmgi_mat
->ptl_mait
);
318 B2N_32(vmgi_mat
->vts_atrt
);
319 B2N_32(vmgi_mat
->txtdt_mgi
);
320 B2N_32(vmgi_mat
->vmgm_c_adt
);
321 B2N_32(vmgi_mat
->vmgm_vobu_admap
);
322 B2N_16(vmgi_mat
->vmgm_audio_attr
.lang_code
);
323 B2N_16(vmgi_mat
->vmgm_subp_attr
.lang_code
);
326 CHECK_ZERO(vmgi_mat
->zero_1
);
327 CHECK_ZERO(vmgi_mat
->zero_2
);
328 CHECK_ZERO(vmgi_mat
->zero_3
);
329 CHECK_ZERO(vmgi_mat
->zero_4
);
330 CHECK_ZERO(vmgi_mat
->zero_5
);
331 CHECK_ZERO(vmgi_mat
->zero_6
);
332 CHECK_ZERO(vmgi_mat
->zero_7
);
333 CHECK_ZERO(vmgi_mat
->zero_8
);
334 CHECK_ZERO(vmgi_mat
->zero_9
);
335 CHECK_ZERO(vmgi_mat
->zero_10
);
336 CHECK_VALUE(vmgi_mat
->vmg_last_sector
!= 0);
337 CHECK_VALUE(vmgi_mat
->vmgi_last_sector
!= 0);
338 CHECK_VALUE(vmgi_mat
->vmgi_last_sector
* 2 <= vmgi_mat
->vmg_last_sector
);
339 CHECK_VALUE(vmgi_mat
->vmgi_last_sector
* 2 <= vmgi_mat
->vmg_last_sector
);
340 CHECK_VALUE(vmgi_mat
->vmg_nr_of_volumes
!= 0);
341 CHECK_VALUE(vmgi_mat
->vmg_this_volume_nr
!= 0);
342 CHECK_VALUE(vmgi_mat
->vmg_this_volume_nr
<= vmgi_mat
->vmg_nr_of_volumes
);
343 CHECK_VALUE(vmgi_mat
->disc_side
== 1 || vmgi_mat
->disc_side
== 2);
344 CHECK_VALUE(vmgi_mat
->vmg_nr_of_title_sets
!= 0);
345 CHECK_VALUE(vmgi_mat
->vmgi_last_byte
>= 341);
346 CHECK_VALUE(vmgi_mat
->vmgi_last_byte
/ DVD_BLOCK_LEN
<=
347 vmgi_mat
->vmgi_last_sector
);
348 /* It seems that first_play_pgc is optional. */
349 CHECK_VALUE(vmgi_mat
->first_play_pgc
< vmgi_mat
->vmgi_last_byte
);
350 CHECK_VALUE(vmgi_mat
->vmgm_vobs
== 0 ||
351 (vmgi_mat
->vmgm_vobs
> vmgi_mat
->vmgi_last_sector
&&
352 vmgi_mat
->vmgm_vobs
< vmgi_mat
->vmg_last_sector
));
353 CHECK_VALUE(vmgi_mat
->tt_srpt
<= vmgi_mat
->vmgi_last_sector
);
354 CHECK_VALUE(vmgi_mat
->vmgm_pgci_ut
<= vmgi_mat
->vmgi_last_sector
);
355 CHECK_VALUE(vmgi_mat
->ptl_mait
<= vmgi_mat
->vmgi_last_sector
);
356 CHECK_VALUE(vmgi_mat
->vts_atrt
<= vmgi_mat
->vmgi_last_sector
);
357 CHECK_VALUE(vmgi_mat
->txtdt_mgi
<= vmgi_mat
->vmgi_last_sector
);
358 CHECK_VALUE(vmgi_mat
->vmgm_c_adt
<= vmgi_mat
->vmgi_last_sector
);
359 CHECK_VALUE(vmgi_mat
->vmgm_vobu_admap
<= vmgi_mat
->vmgi_last_sector
);
361 CHECK_VALUE(vmgi_mat
->nr_of_vmgm_audio_streams
<= 1);
362 CHECK_VALUE(vmgi_mat
->nr_of_vmgm_subp_streams
<= 1);
368 static int ifoRead_VTS(ifo_handle_t
*ifofile
) {
369 vtsi_mat_t
*vtsi_mat
;
372 vtsi_mat
= malloc(sizeof(vtsi_mat_t
));
376 ifofile
->vtsi_mat
= vtsi_mat
;
378 if(!DVDFileSeek_(ifofile
->file
, 0)) {
379 free(ifofile
->vtsi_mat
);
380 ifofile
->vtsi_mat
= 0;
384 if(!(DVDReadBytes(ifofile
->file
, vtsi_mat
, sizeof(vtsi_mat_t
)))) {
385 free(ifofile
->vtsi_mat
);
386 ifofile
->vtsi_mat
= 0;
390 if(strncmp("DVDVIDEO-VTS", vtsi_mat
->vts_identifier
, 12) != 0) {
391 free(ifofile
->vtsi_mat
);
392 ifofile
->vtsi_mat
= 0;
396 B2N_32(vtsi_mat
->vts_last_sector
);
397 B2N_32(vtsi_mat
->vtsi_last_sector
);
398 B2N_32(vtsi_mat
->vts_category
);
399 B2N_32(vtsi_mat
->vtsi_last_byte
);
400 B2N_32(vtsi_mat
->vtsm_vobs
);
401 B2N_32(vtsi_mat
->vtstt_vobs
);
402 B2N_32(vtsi_mat
->vts_ptt_srpt
);
403 B2N_32(vtsi_mat
->vts_pgcit
);
404 B2N_32(vtsi_mat
->vtsm_pgci_ut
);
405 B2N_32(vtsi_mat
->vts_tmapt
);
406 B2N_32(vtsi_mat
->vtsm_c_adt
);
407 B2N_32(vtsi_mat
->vtsm_vobu_admap
);
408 B2N_32(vtsi_mat
->vts_c_adt
);
409 B2N_32(vtsi_mat
->vts_vobu_admap
);
410 B2N_16(vtsi_mat
->vtsm_audio_attr
.lang_code
);
411 B2N_16(vtsi_mat
->vtsm_subp_attr
.lang_code
);
412 for(i
= 0; i
< 8; i
++)
413 B2N_16(vtsi_mat
->vts_audio_attr
[i
].lang_code
);
414 for(i
= 0; i
< 32; i
++)
415 B2N_16(vtsi_mat
->vts_subp_attr
[i
].lang_code
);
418 CHECK_ZERO(vtsi_mat
->zero_1
);
419 CHECK_ZERO(vtsi_mat
->zero_2
);
420 CHECK_ZERO(vtsi_mat
->zero_3
);
421 CHECK_ZERO(vtsi_mat
->zero_4
);
422 CHECK_ZERO(vtsi_mat
->zero_5
);
423 CHECK_ZERO(vtsi_mat
->zero_6
);
424 CHECK_ZERO(vtsi_mat
->zero_7
);
425 CHECK_ZERO(vtsi_mat
->zero_8
);
426 CHECK_ZERO(vtsi_mat
->zero_9
);
427 CHECK_ZERO(vtsi_mat
->zero_10
);
428 CHECK_ZERO(vtsi_mat
->zero_11
);
429 CHECK_ZERO(vtsi_mat
->zero_12
);
430 CHECK_ZERO(vtsi_mat
->zero_13
);
431 CHECK_ZERO(vtsi_mat
->zero_14
);
432 CHECK_ZERO(vtsi_mat
->zero_15
);
433 CHECK_ZERO(vtsi_mat
->zero_16
);
434 CHECK_ZERO(vtsi_mat
->zero_17
);
435 CHECK_ZERO(vtsi_mat
->zero_18
);
436 CHECK_ZERO(vtsi_mat
->zero_19
);
437 CHECK_ZERO(vtsi_mat
->zero_20
);
438 CHECK_ZERO(vtsi_mat
->zero_21
);
439 CHECK_VALUE(vtsi_mat
->vtsi_last_sector
*2 <= vtsi_mat
->vts_last_sector
);
440 CHECK_VALUE(vtsi_mat
->vtsi_last_byte
/DVD_BLOCK_LEN
<= vtsi_mat
->vtsi_last_sector
);
441 CHECK_VALUE(vtsi_mat
->vtsm_vobs
== 0 ||
442 (vtsi_mat
->vtsm_vobs
> vtsi_mat
->vtsi_last_sector
&&
443 vtsi_mat
->vtsm_vobs
< vtsi_mat
->vts_last_sector
));
444 CHECK_VALUE(vtsi_mat
->vtstt_vobs
== 0 ||
445 (vtsi_mat
->vtstt_vobs
> vtsi_mat
->vtsi_last_sector
&&
446 vtsi_mat
->vtstt_vobs
< vtsi_mat
->vts_last_sector
));
447 CHECK_VALUE(vtsi_mat
->vts_ptt_srpt
<= vtsi_mat
->vtsi_last_sector
);
448 CHECK_VALUE(vtsi_mat
->vts_pgcit
<= vtsi_mat
->vtsi_last_sector
);
449 CHECK_VALUE(vtsi_mat
->vtsm_pgci_ut
<= vtsi_mat
->vtsi_last_sector
);
450 CHECK_VALUE(vtsi_mat
->vts_tmapt
<= vtsi_mat
->vtsi_last_sector
);
451 CHECK_VALUE(vtsi_mat
->vtsm_c_adt
<= vtsi_mat
->vtsi_last_sector
);
452 CHECK_VALUE(vtsi_mat
->vtsm_vobu_admap
<= vtsi_mat
->vtsi_last_sector
);
453 CHECK_VALUE(vtsi_mat
->vts_c_adt
<= vtsi_mat
->vtsi_last_sector
);
454 CHECK_VALUE(vtsi_mat
->vts_vobu_admap
<= vtsi_mat
->vtsi_last_sector
);
456 CHECK_VALUE(vtsi_mat
->nr_of_vtsm_audio_streams
<= 1);
457 CHECK_VALUE(vtsi_mat
->nr_of_vtsm_subp_streams
<= 1);
459 CHECK_VALUE(vtsi_mat
->nr_of_vts_audio_streams
<= 8);
460 for(i
= vtsi_mat
->nr_of_vts_audio_streams
; i
< 8; i
++)
461 CHECK_ZERO(vtsi_mat
->vts_audio_attr
[i
]);
463 CHECK_VALUE(vtsi_mat
->nr_of_vts_subp_streams
<= 32);
464 for(i
= vtsi_mat
->nr_of_vts_subp_streams
; i
< 32; i
++)
465 CHECK_ZERO(vtsi_mat
->vts_subp_attr
[i
]);
467 for(i
= 0; i
< 8; i
++) {
468 CHECK_ZERO0(vtsi_mat
->vts_mu_audio_attr
[i
].zero1
);
469 CHECK_ZERO0(vtsi_mat
->vts_mu_audio_attr
[i
].zero2
);
470 CHECK_ZERO0(vtsi_mat
->vts_mu_audio_attr
[i
].zero3
);
471 CHECK_ZERO0(vtsi_mat
->vts_mu_audio_attr
[i
].zero4
);
472 CHECK_ZERO0(vtsi_mat
->vts_mu_audio_attr
[i
].zero5
);
473 CHECK_ZERO(vtsi_mat
->vts_mu_audio_attr
[i
].zero6
);
480 static int ifoRead_PGC_COMMAND_TBL(ifo_handle_t
*ifofile
,
481 pgc_command_tbl_t
*cmd_tbl
,
482 unsigned int offset
) {
484 memset(cmd_tbl
, 0, sizeof(pgc_command_tbl_t
));
486 if(!DVDFileSeek_(ifofile
->file
, offset
))
489 if(!(DVDReadBytes(ifofile
->file
, cmd_tbl
, PGC_COMMAND_TBL_SIZE
)))
492 B2N_16(cmd_tbl
->nr_of_pre
);
493 B2N_16(cmd_tbl
->nr_of_post
);
494 B2N_16(cmd_tbl
->nr_of_cell
);
496 CHECK_VALUE(cmd_tbl
->nr_of_pre
+ cmd_tbl
->nr_of_post
+ cmd_tbl
->nr_of_cell
<= 255);
498 if(cmd_tbl
->nr_of_pre
!= 0) {
499 unsigned int pre_cmds_size
= cmd_tbl
->nr_of_pre
* COMMAND_DATA_SIZE
;
500 cmd_tbl
->pre_cmds
= malloc(pre_cmds_size
);
501 if(!cmd_tbl
->pre_cmds
)
504 if(!(DVDReadBytes(ifofile
->file
, cmd_tbl
->pre_cmds
, pre_cmds_size
))) {
505 free(cmd_tbl
->pre_cmds
);
510 if(cmd_tbl
->nr_of_post
!= 0) {
511 unsigned int post_cmds_size
= cmd_tbl
->nr_of_post
* COMMAND_DATA_SIZE
;
512 cmd_tbl
->post_cmds
= malloc(post_cmds_size
);
513 if(!cmd_tbl
->post_cmds
) {
514 if(cmd_tbl
->pre_cmds
)
515 free(cmd_tbl
->pre_cmds
);
518 if(!(DVDReadBytes(ifofile
->file
, cmd_tbl
->post_cmds
, post_cmds_size
))) {
519 if(cmd_tbl
->pre_cmds
)
520 free(cmd_tbl
->pre_cmds
);
521 free(cmd_tbl
->post_cmds
);
526 if(cmd_tbl
->nr_of_cell
!= 0) {
527 unsigned int cell_cmds_size
= cmd_tbl
->nr_of_cell
* COMMAND_DATA_SIZE
;
528 cmd_tbl
->cell_cmds
= malloc(cell_cmds_size
);
529 if(!cmd_tbl
->cell_cmds
) {
530 if(cmd_tbl
->pre_cmds
)
531 free(cmd_tbl
->pre_cmds
);
532 if(cmd_tbl
->post_cmds
)
533 free(cmd_tbl
->post_cmds
);
536 if(!(DVDReadBytes(ifofile
->file
, cmd_tbl
->cell_cmds
, cell_cmds_size
))) {
537 if(cmd_tbl
->pre_cmds
)
538 free(cmd_tbl
->pre_cmds
);
539 if(cmd_tbl
->post_cmds
)
540 free(cmd_tbl
->post_cmds
);
541 free(cmd_tbl
->cell_cmds
);
547 * Make a run over all the commands and see that we can interpret them all?
553 static void ifoFree_PGC_COMMAND_TBL(pgc_command_tbl_t
*cmd_tbl
) {
555 if(cmd_tbl
->nr_of_pre
&& cmd_tbl
->pre_cmds
)
556 free(cmd_tbl
->pre_cmds
);
557 if(cmd_tbl
->nr_of_post
&& cmd_tbl
->post_cmds
)
558 free(cmd_tbl
->post_cmds
);
559 if(cmd_tbl
->nr_of_cell
&& cmd_tbl
->cell_cmds
)
560 free(cmd_tbl
->cell_cmds
);
565 static int ifoRead_PGC_PROGRAM_MAP(ifo_handle_t
*ifofile
,
566 pgc_program_map_t
*program_map
,
567 unsigned int nr
, unsigned int offset
) {
568 unsigned int size
= nr
* sizeof(pgc_program_map_t
);
570 if(!DVDFileSeek_(ifofile
->file
, offset
))
573 if(!(DVDReadBytes(ifofile
->file
, program_map
, size
)))
579 static int ifoRead_CELL_PLAYBACK_TBL(ifo_handle_t
*ifofile
,
580 cell_playback_t
*cell_playback
,
581 unsigned int nr
, unsigned int offset
) {
583 unsigned int size
= nr
* sizeof(cell_playback_t
);
585 if(!DVDFileSeek_(ifofile
->file
, offset
))
588 if(!(DVDReadBytes(ifofile
->file
, cell_playback
, size
)))
591 for(i
= 0; i
< nr
; i
++) {
592 B2N_32(cell_playback
[i
].first_sector
);
593 B2N_32(cell_playback
[i
].first_ilvu_end_sector
);
594 B2N_32(cell_playback
[i
].last_vobu_start_sector
);
595 B2N_32(cell_playback
[i
].last_sector
);
597 /* Changed < to <= because this was false in the movie 'Pi'. */
598 CHECK_VALUE(cell_playback
[i
].last_vobu_start_sector
<=
599 cell_playback
[i
].last_sector
);
600 CHECK_VALUE(cell_playback
[i
].first_sector
<=
601 cell_playback
[i
].last_vobu_start_sector
);
608 static int ifoRead_CELL_POSITION_TBL(ifo_handle_t
*ifofile
,
609 cell_position_t
*cell_position
,
610 unsigned int nr
, unsigned int offset
) {
612 unsigned int size
= nr
* sizeof(cell_position_t
);
614 if(!DVDFileSeek_(ifofile
->file
, offset
))
617 if(!(DVDReadBytes(ifofile
->file
, cell_position
, size
)))
620 for(i
= 0; i
< nr
; i
++) {
621 B2N_16(cell_position
[i
].vob_id_nr
);
622 CHECK_ZERO(cell_position
[i
].zero_1
);
628 static int ifoRead_PGC(ifo_handle_t
*ifofile
, pgc_t
*pgc
, unsigned int offset
) {
631 if(!DVDFileSeek_(ifofile
->file
, offset
))
634 if(!(DVDReadBytes(ifofile
->file
, pgc
, PGC_SIZE
)))
637 B2N_16(pgc
->next_pgc_nr
);
638 B2N_16(pgc
->prev_pgc_nr
);
639 B2N_16(pgc
->goup_pgc_nr
);
640 B2N_16(pgc
->command_tbl_offset
);
641 B2N_16(pgc
->program_map_offset
);
642 B2N_16(pgc
->cell_playback_offset
);
643 B2N_16(pgc
->cell_position_offset
);
645 for(i
= 0; i
< 16; i
++)
646 B2N_32(pgc
->palette
[i
]);
648 CHECK_ZERO(pgc
->zero_1
);
649 CHECK_VALUE(pgc
->nr_of_programs
<= pgc
->nr_of_cells
);
651 /* verify time (look at print_time) */
652 for(i
= 0; i
< 8; i
++)
653 if(!pgc
->audio_control
[i
].present
)
654 CHECK_ZERO(pgc
->audio_control
[i
]);
655 for(i
= 0; i
< 32; i
++)
656 if(!pgc
->subp_control
[i
].present
)
657 CHECK_ZERO(pgc
->subp_control
[i
]);
659 /* Check that time is 0:0:0:0 also if nr_of_programs == 0 */
660 if(pgc
->nr_of_programs
== 0) {
661 CHECK_ZERO(pgc
->still_time
);
662 CHECK_ZERO(pgc
->pg_playback_mode
); // ??
663 CHECK_VALUE(pgc
->program_map_offset
== 0);
664 CHECK_VALUE(pgc
->cell_playback_offset
== 0);
665 CHECK_VALUE(pgc
->cell_position_offset
== 0);
667 CHECK_VALUE(pgc
->program_map_offset
!= 0);
668 CHECK_VALUE(pgc
->cell_playback_offset
!= 0);
669 CHECK_VALUE(pgc
->cell_position_offset
!= 0);
672 if(pgc
->command_tbl_offset
!= 0) {
673 pgc
->command_tbl
= malloc(sizeof(pgc_command_tbl_t
));
674 if(!pgc
->command_tbl
)
677 if(!ifoRead_PGC_COMMAND_TBL(ifofile
, pgc
->command_tbl
,
678 offset
+ pgc
->command_tbl_offset
)) {
679 free(pgc
->command_tbl
);
683 pgc
->command_tbl
= NULL
;
686 if(pgc
->program_map_offset
!= 0) {
687 pgc
->program_map
= malloc(pgc
->nr_of_programs
* sizeof(pgc_program_map_t
));
688 if(!pgc
->program_map
) {
689 ifoFree_PGC_COMMAND_TBL(pgc
->command_tbl
);
692 if(!ifoRead_PGC_PROGRAM_MAP(ifofile
, pgc
->program_map
,pgc
->nr_of_programs
,
693 offset
+ pgc
->program_map_offset
)) {
694 ifoFree_PGC_COMMAND_TBL(pgc
->command_tbl
);
695 free(pgc
->program_map
);
699 pgc
->program_map
= NULL
;
702 if(pgc
->cell_playback_offset
!= 0) {
703 pgc
->cell_playback
= malloc(pgc
->nr_of_cells
* sizeof(cell_playback_t
));
704 if(!pgc
->cell_playback
) {
705 ifoFree_PGC_COMMAND_TBL(pgc
->command_tbl
);
707 free(pgc
->program_map
);
710 if(!ifoRead_CELL_PLAYBACK_TBL(ifofile
, pgc
->cell_playback
,
712 offset
+ pgc
->cell_playback_offset
)) {
713 ifoFree_PGC_COMMAND_TBL(pgc
->command_tbl
);
715 free(pgc
->program_map
);
716 free(pgc
->cell_playback
);
720 pgc
->cell_playback
= NULL
;
723 if(pgc
->cell_position_offset
!= 0) {
724 pgc
->cell_position
= malloc(pgc
->nr_of_cells
* sizeof(cell_position_t
));
725 if(!pgc
->cell_position
) {
729 if(!ifoRead_CELL_POSITION_TBL(ifofile
, pgc
->cell_position
,
731 offset
+ pgc
->cell_position_offset
)) {
736 pgc
->cell_position
= NULL
;
742 int ifoRead_FP_PGC(ifo_handle_t
*ifofile
) {
747 if(!ifofile
->vmgi_mat
)
750 /* It seems that first_play_pgc is optional after all. */
751 ifofile
->first_play_pgc
= 0;
752 if(ifofile
->vmgi_mat
->first_play_pgc
== 0)
755 ifofile
->first_play_pgc
= malloc(sizeof(pgc_t
));
756 if(!ifofile
->first_play_pgc
)
759 if(!ifoRead_PGC(ifofile
, ifofile
->first_play_pgc
,
760 ifofile
->vmgi_mat
->first_play_pgc
)) {
761 free(ifofile
->first_play_pgc
);
762 ifofile
->first_play_pgc
= 0;
769 static void ifoFree_PGC(pgc_t
*pgc
) {
771 ifoFree_PGC_COMMAND_TBL(pgc
->command_tbl
);
773 free(pgc
->program_map
);
774 if(pgc
->cell_playback
)
775 free(pgc
->cell_playback
);
776 if(pgc
->cell_position
)
777 free(pgc
->cell_position
);
781 void ifoFree_FP_PGC(ifo_handle_t
*ifofile
) {
785 if(ifofile
->first_play_pgc
) {
786 ifoFree_PGC(ifofile
->first_play_pgc
);
787 free(ifofile
->first_play_pgc
);
788 ifofile
->first_play_pgc
= 0;
793 int ifoRead_TT_SRPT(ifo_handle_t
*ifofile
) {
800 if(!ifofile
->vmgi_mat
)
803 if(ifofile
->vmgi_mat
->tt_srpt
== 0) /* mandatory */
806 if(!DVDFileSeek_(ifofile
->file
, ifofile
->vmgi_mat
->tt_srpt
* DVD_BLOCK_LEN
))
809 tt_srpt
= malloc(sizeof(tt_srpt_t
));
813 ifofile
->tt_srpt
= tt_srpt
;
815 if(!(DVDReadBytes(ifofile
->file
, tt_srpt
, TT_SRPT_SIZE
))) {
816 fprintf(stderr
, "libdvdread: Unable to read read TT_SRPT.\n");
821 B2N_16(tt_srpt
->nr_of_srpts
);
822 B2N_32(tt_srpt
->last_byte
);
824 info_length
= tt_srpt
->last_byte
+ 1 - TT_SRPT_SIZE
;
826 tt_srpt
->title
= malloc(info_length
);
827 if(!tt_srpt
->title
) {
829 ifofile
->tt_srpt
= 0;
832 if(!(DVDReadBytes(ifofile
->file
, tt_srpt
->title
, info_length
))) {
833 fprintf(stderr
, "libdvdread: Unable to read read TT_SRPT.\n");
834 ifoFree_TT_SRPT(ifofile
);
838 for(i
= 0; i
< tt_srpt
->nr_of_srpts
; i
++) {
839 B2N_16(tt_srpt
->title
[i
].nr_of_ptts
);
840 B2N_16(tt_srpt
->title
[i
].parental_id
);
841 B2N_32(tt_srpt
->title
[i
].title_set_sector
);
845 CHECK_ZERO(tt_srpt
->zero_1
);
846 CHECK_VALUE(tt_srpt
->nr_of_srpts
!= 0);
847 CHECK_VALUE(tt_srpt
->nr_of_srpts
< 100); // ??
848 CHECK_VALUE((int)tt_srpt
->nr_of_srpts
* sizeof(title_info_t
) <= info_length
);
850 for(i
= 0; i
< tt_srpt
->nr_of_srpts
; i
++) {
851 CHECK_VALUE(tt_srpt
->title
[i
].pb_ty
.zero_1
== 0);
852 CHECK_VALUE(tt_srpt
->title
[i
].nr_of_angles
!= 0);
853 CHECK_VALUE(tt_srpt
->title
[i
].nr_of_angles
< 10);
854 //CHECK_VALUE(tt_srpt->title[i].nr_of_ptts != 0);
855 // XXX: this assertion breaks Ghostbusters:
856 CHECK_VALUE(tt_srpt
->title
[i
].nr_of_ptts
< 1000); // ??
857 CHECK_VALUE(tt_srpt
->title
[i
].title_set_nr
!= 0);
858 CHECK_VALUE(tt_srpt
->title
[i
].title_set_nr
< 100); // ??
859 CHECK_VALUE(tt_srpt
->title
[i
].vts_ttn
!= 0);
860 CHECK_VALUE(tt_srpt
->title
[i
].vts_ttn
< 100); // ??
861 //CHECK_VALUE(tt_srpt->title[i].title_set_sector != 0);
864 // Make this a function
866 if(memcmp((uint8_t *)tt_srpt
->title
+
867 tt_srpt
->nr_of_srpts
* sizeof(title_info_t
),
869 info_length
- tt_srpt
->nr_of_srpts
* sizeof(title_info_t
))) {
870 fprintf(stderr
, "VMG_PTT_SRPT slack is != 0, ");
871 hexdump((uint8_t *)tt_srpt
->title
+
872 tt_srpt
->nr_of_srpts
* sizeof(title_info_t
),
873 info_length
- tt_srpt
->nr_of_srpts
* sizeof(title_info_t
));
881 void ifoFree_TT_SRPT(ifo_handle_t
*ifofile
) {
885 if(ifofile
->tt_srpt
) {
886 free(ifofile
->tt_srpt
->title
);
887 free(ifofile
->tt_srpt
);
888 ifofile
->tt_srpt
= 0;
893 int ifoRead_VTS_PTT_SRPT(ifo_handle_t
*ifofile
) {
894 vts_ptt_srpt_t
*vts_ptt_srpt
;
895 int info_length
, i
, j
;
901 if(!ifofile
->vtsi_mat
)
904 if(ifofile
->vtsi_mat
->vts_ptt_srpt
== 0) /* mandatory */
907 if(!DVDFileSeek_(ifofile
->file
,
908 ifofile
->vtsi_mat
->vts_ptt_srpt
* DVD_BLOCK_LEN
))
911 vts_ptt_srpt
= malloc(sizeof(vts_ptt_srpt_t
));
915 ifofile
->vts_ptt_srpt
= vts_ptt_srpt
;
917 if(!(DVDReadBytes(ifofile
->file
, vts_ptt_srpt
, VTS_PTT_SRPT_SIZE
))) {
918 fprintf(stderr
, "libdvdread: Unable to read PTT search table.\n");
923 B2N_16(vts_ptt_srpt
->nr_of_srpts
);
924 B2N_32(vts_ptt_srpt
->last_byte
);
926 CHECK_ZERO(vts_ptt_srpt
->zero_1
);
927 CHECK_VALUE(vts_ptt_srpt
->nr_of_srpts
!= 0);
928 CHECK_VALUE(vts_ptt_srpt
->nr_of_srpts
< 100); // ??
930 info_length
= vts_ptt_srpt
->last_byte
+ 1 - VTS_PTT_SRPT_SIZE
;
932 data
= malloc(info_length
);
935 ifofile
->vts_ptt_srpt
= 0;
938 if(!(DVDReadBytes(ifofile
->file
, data
, info_length
))) {
939 fprintf(stderr
, "libdvdread: Unable to read PTT search table.\n");
942 ifofile
->vts_ptt_srpt
= 0;
946 for(i
= 0; i
< vts_ptt_srpt
->nr_of_srpts
; i
++) {
948 /* assert(data[i] + sizeof(ptt_info_t) <= vts_ptt_srpt->last_byte + 1);
949 Magic Knight Rayearth Daybreak is mastered very strange and has
950 Titles with 0 PTTs. They all have a data[i] offsets beyond the end of
951 of the vts_ptt_srpt structure. */
952 CHECK_VALUE(data
[i
] + sizeof(ptt_info_t
) <= vts_ptt_srpt
->last_byte
+ 1 + 4);
955 vts_ptt_srpt
->ttu_offset
= data
;
957 vts_ptt_srpt
->title
= malloc(vts_ptt_srpt
->nr_of_srpts
* sizeof(ttu_t
));
958 if(!vts_ptt_srpt
->title
) {
961 ifofile
->vts_ptt_srpt
= 0;
964 for(i
= 0; i
< vts_ptt_srpt
->nr_of_srpts
; i
++) {
966 if(i
< vts_ptt_srpt
->nr_of_srpts
- 1)
967 n
= (data
[i
+1] - data
[i
]);
969 n
= (vts_ptt_srpt
->last_byte
+ 1 - data
[i
]);
970 /* assert(n > 0 && (n % 4) == 0);
971 Magic Knight Rayearth Daybreak is mastered very strange and has
972 Titles with 0 PTTs. */
974 CHECK_VALUE(n
% 4 == 0);
976 vts_ptt_srpt
->title
[i
].nr_of_ptts
= n
/ 4;
977 vts_ptt_srpt
->title
[i
].ptt
= malloc(n
* sizeof(ptt_info_t
));
978 if(!vts_ptt_srpt
->title
[i
].ptt
) {
979 for(n
= 0; n
< i
; n
++)
980 free(vts_ptt_srpt
->title
[n
].ptt
);
983 ifofile
->vts_ptt_srpt
= 0;
986 for(j
= 0; j
< vts_ptt_srpt
->title
[i
].nr_of_ptts
; j
++) {
987 /* The assert placed here because of Magic Knight Rayearth Daybreak */
988 CHECK_VALUE(data
[i
] + sizeof(ptt_info_t
) <= vts_ptt_srpt
->last_byte
+ 1);
989 vts_ptt_srpt
->title
[i
].ptt
[j
].pgcn
990 = *(uint16_t*)(((char *)data
) + data
[i
] + 4*j
- VTS_PTT_SRPT_SIZE
);
991 vts_ptt_srpt
->title
[i
].ptt
[j
].pgn
992 = *(uint16_t*)(((char *)data
) + data
[i
] + 4*j
+ 2 - VTS_PTT_SRPT_SIZE
);
996 for(i
= 0; i
< vts_ptt_srpt
->nr_of_srpts
; i
++) {
997 for(j
= 0; j
< vts_ptt_srpt
->title
[i
].nr_of_ptts
; j
++) {
998 B2N_16(vts_ptt_srpt
->title
[i
].ptt
[j
].pgcn
);
999 B2N_16(vts_ptt_srpt
->title
[i
].ptt
[j
].pgn
);
1003 for(i
= 0; i
< vts_ptt_srpt
->nr_of_srpts
; i
++) {
1004 CHECK_VALUE(vts_ptt_srpt
->title
[i
].nr_of_ptts
< 1000); // ??
1005 for(j
= 0; j
< vts_ptt_srpt
->title
[i
].nr_of_ptts
; j
++) {
1006 CHECK_VALUE(vts_ptt_srpt
->title
[i
].ptt
[j
].pgcn
!= 0 );
1007 CHECK_VALUE(vts_ptt_srpt
->title
[i
].ptt
[j
].pgcn
< 1000); // ??
1008 CHECK_VALUE(vts_ptt_srpt
->title
[i
].ptt
[j
].pgn
!= 0);
1009 CHECK_VALUE(vts_ptt_srpt
->title
[i
].ptt
[j
].pgn
< 100); // ??
1017 void ifoFree_VTS_PTT_SRPT(ifo_handle_t
*ifofile
) {
1021 if(ifofile
->vts_ptt_srpt
) {
1023 for(i
= 0; i
< ifofile
->vts_ptt_srpt
->nr_of_srpts
; i
++)
1024 free(ifofile
->vts_ptt_srpt
->title
[i
].ptt
);
1025 free(ifofile
->vts_ptt_srpt
->ttu_offset
);
1026 free(ifofile
->vts_ptt_srpt
->title
);
1027 free(ifofile
->vts_ptt_srpt
);
1028 ifofile
->vts_ptt_srpt
= 0;
1033 int ifoRead_PTL_MAIT(ifo_handle_t
*ifofile
) {
1034 ptl_mait_t
*ptl_mait
;
1041 if(!ifofile
->vmgi_mat
)
1044 if(ifofile
->vmgi_mat
->ptl_mait
== 0)
1047 if(!DVDFileSeek_(ifofile
->file
, ifofile
->vmgi_mat
->ptl_mait
* DVD_BLOCK_LEN
))
1050 ptl_mait
= malloc(sizeof(ptl_mait_t
));
1054 ifofile
->ptl_mait
= ptl_mait
;
1056 if(!(DVDReadBytes(ifofile
->file
, ptl_mait
, PTL_MAIT_SIZE
))) {
1058 ifofile
->ptl_mait
= 0;
1062 B2N_16(ptl_mait
->nr_of_countries
);
1063 B2N_16(ptl_mait
->nr_of_vtss
);
1064 B2N_32(ptl_mait
->last_byte
);
1066 CHECK_VALUE(ptl_mait
->nr_of_countries
!= 0);
1067 CHECK_VALUE(ptl_mait
->nr_of_countries
< 100); // ??
1068 CHECK_VALUE(ptl_mait
->nr_of_vtss
!= 0);
1069 CHECK_VALUE(ptl_mait
->nr_of_vtss
< 100); // ??
1070 CHECK_VALUE(ptl_mait
->nr_of_countries
* PTL_MAIT_COUNTRY_SIZE
1071 <= ptl_mait
->last_byte
+ 1 - PTL_MAIT_SIZE
);
1073 info_length
= ptl_mait
->nr_of_countries
* sizeof(ptl_mait_country_t
);
1074 ptl_mait
->countries
= malloc(info_length
);
1075 if(!ptl_mait
->countries
) {
1077 ifofile
->ptl_mait
= 0;
1081 for(i
= 0; i
< ptl_mait
->nr_of_countries
; i
++) {
1082 if(!(DVDReadBytes(ifofile
->file
, &ptl_mait
->countries
[i
], PTL_MAIT_COUNTRY_SIZE
))) {
1083 fprintf(stderr
, "libdvdread: Unable to read PTL_MAIT.\n");
1084 free(ptl_mait
->countries
);
1086 ifofile
->ptl_mait
= 0;
1091 for(i
= 0; i
< ptl_mait
->nr_of_countries
; i
++) {
1092 B2N_16(ptl_mait
->countries
[i
].country_code
);
1093 B2N_16(ptl_mait
->countries
[i
].pf_ptl_mai_start_byte
);
1096 for(i
= 0; i
< ptl_mait
->nr_of_countries
; i
++) {
1097 CHECK_ZERO(ptl_mait
->countries
[i
].zero_1
);
1098 CHECK_ZERO(ptl_mait
->countries
[i
].zero_2
);
1099 CHECK_VALUE(ptl_mait
->countries
[i
].pf_ptl_mai_start_byte
1100 + 8*2 * (ptl_mait
->nr_of_vtss
+ 1) <= ptl_mait
->last_byte
+ 1);
1103 for(i
= 0; i
< ptl_mait
->nr_of_countries
; i
++) {
1106 if(!DVDFileSeek_(ifofile
->file
,
1107 ifofile
->vmgi_mat
->ptl_mait
* DVD_BLOCK_LEN
1108 + ptl_mait
->countries
[i
].pf_ptl_mai_start_byte
)) {
1109 fprintf(stderr
, "libdvdread: Unable to seak PTL_MAIT table.\n");
1110 free(ptl_mait
->countries
);
1114 info_length
= (ptl_mait
->nr_of_vtss
+ 1) * sizeof(pf_level_t
);
1115 pf_temp
= malloc(info_length
);
1117 for(j
= 0; j
< i
; j
++) {
1118 free(ptl_mait
->countries
[j
].pf_ptl_mai
);
1120 free(ptl_mait
->countries
);
1124 if(!(DVDReadBytes(ifofile
->file
, pf_temp
, info_length
))) {
1125 fprintf(stderr
, "libdvdread: Unable to read PTL_MAIT table.\n");
1127 for(j
= 0; j
< i
; j
++) {
1128 free(ptl_mait
->countries
[j
].pf_ptl_mai
);
1130 free(ptl_mait
->countries
);
1134 for (j
= 0; j
< ((ptl_mait
->nr_of_vtss
+ 1) * 8); j
++) {
1137 ptl_mait
->countries
[i
].pf_ptl_mai
= malloc(info_length
);
1138 if(!ptl_mait
->countries
[i
].pf_ptl_mai
) {
1140 for(j
= 0; j
< i
; j
++) {
1141 free(ptl_mait
->countries
[j
].pf_ptl_mai
);
1143 free(ptl_mait
->countries
);
1147 { /* Transpose the array so we can use C indexing. */
1149 for(level
= 0; level
< 8; level
++) {
1150 for(vts
= 0; vts
<= ptl_mait
->nr_of_vtss
; vts
++) {
1151 ptl_mait
->countries
[i
].pf_ptl_mai
[vts
][level
] =
1152 pf_temp
[(7-level
)*(ptl_mait
->nr_of_vtss
+1) + vts
];
1161 void ifoFree_PTL_MAIT(ifo_handle_t
*ifofile
) {
1167 if(ifofile
->ptl_mait
) {
1168 for(i
= 0; i
< ifofile
->ptl_mait
->nr_of_countries
; i
++) {
1169 free(ifofile
->ptl_mait
->countries
[i
].pf_ptl_mai
);
1171 free(ifofile
->ptl_mait
->countries
);
1172 free(ifofile
->ptl_mait
);
1173 ifofile
->ptl_mait
= 0;
1177 int ifoRead_VTS_TMAPT(ifo_handle_t
*ifofile
) {
1178 vts_tmapt_t
*vts_tmapt
;
1179 uint32_t *vts_tmap_srp
;
1180 unsigned int offset
;
1187 if(!ifofile
->vtsi_mat
)
1190 if(ifofile
->vtsi_mat
->vts_tmapt
== 0) { /* optional(?) */
1191 ifofile
->vts_tmapt
= NULL
;
1192 fprintf(stderr
,"Please send bug report - no VTS_TMAPT ?? \n");
1196 offset
= ifofile
->vtsi_mat
->vts_tmapt
* DVD_BLOCK_LEN
;
1198 if(!DVDFileSeek_(ifofile
->file
, offset
))
1201 vts_tmapt
= malloc(sizeof(vts_tmapt_t
));
1205 ifofile
->vts_tmapt
= vts_tmapt
;
1207 if(!(DVDReadBytes(ifofile
->file
, vts_tmapt
, VTS_TMAPT_SIZE
))) {
1208 fprintf(stderr
, "libdvdread: Unable to read VTS_TMAPT.\n");
1210 ifofile
->vts_tmapt
= NULL
;
1214 B2N_16(vts_tmapt
->nr_of_tmaps
);
1215 B2N_32(vts_tmapt
->last_byte
);
1217 CHECK_ZERO(vts_tmapt
->zero_1
);
1219 info_length
= vts_tmapt
->nr_of_tmaps
* 4;
1221 vts_tmap_srp
= malloc(info_length
);
1224 ifofile
->vts_tmapt
= NULL
;
1228 vts_tmapt
->tmap_offset
= vts_tmap_srp
;
1230 if(!(DVDReadBytes(ifofile
->file
, vts_tmap_srp
, info_length
))) {
1231 fprintf(stderr
, "libdvdread: Unable to read VTS_TMAPT.\n");
1234 ifofile
->vts_tmapt
= NULL
;
1238 for (i
= 0; i
< vts_tmapt
->nr_of_tmaps
; i
++) {
1239 B2N_32(vts_tmap_srp
[i
]);
1243 info_length
= vts_tmapt
->nr_of_tmaps
* sizeof(vts_tmap_t
);
1245 vts_tmapt
->tmap
= malloc(info_length
);
1246 if(!vts_tmapt
->tmap
) {
1249 ifofile
->vts_tmapt
= NULL
;
1253 memset(vts_tmapt
->tmap
, 0, info_length
); /* So ifoFree_VTS_TMAPT works. */
1255 for(i
= 0; i
< vts_tmapt
->nr_of_tmaps
; i
++) {
1256 if(!DVDFileSeek_(ifofile
->file
, offset
+ vts_tmap_srp
[i
])) {
1257 ifoFree_VTS_TMAPT(ifofile
);
1261 if(!(DVDReadBytes(ifofile
->file
, &vts_tmapt
->tmap
[i
], VTS_TMAP_SIZE
))) {
1262 fprintf(stderr
, "libdvdread: Unable to read VTS_TMAP.\n");
1263 ifoFree_VTS_TMAPT(ifofile
);
1267 B2N_16(vts_tmapt
->tmap
[i
].nr_of_entries
);
1268 CHECK_ZERO(vts_tmapt
->tmap
[i
].zero_1
);
1270 if(vts_tmapt
->tmap
[i
].nr_of_entries
== 0) { /* Early out if zero entries */
1271 vts_tmapt
->tmap
[i
].map_ent
= NULL
;
1275 info_length
= vts_tmapt
->tmap
[i
].nr_of_entries
* sizeof(map_ent_t
);
1277 vts_tmapt
->tmap
[i
].map_ent
= malloc(info_length
);
1278 if(!vts_tmapt
->tmap
[i
].map_ent
) {
1279 ifoFree_VTS_TMAPT(ifofile
);
1283 if(!(DVDReadBytes(ifofile
->file
, vts_tmapt
->tmap
[i
].map_ent
, info_length
))) {
1284 fprintf(stderr
, "libdvdread: Unable to read VTS_TMAP_ENT.\n");
1285 ifoFree_VTS_TMAPT(ifofile
);
1289 for(j
= 0; j
< vts_tmapt
->tmap
[i
].nr_of_entries
; j
++)
1290 B2N_32(vts_tmapt
->tmap
[i
].map_ent
[j
]);
1296 void ifoFree_VTS_TMAPT(ifo_handle_t
*ifofile
) {
1302 if(ifofile
->vts_tmapt
) {
1303 for(i
= 0; i
< ifofile
->vts_tmapt
->nr_of_tmaps
; i
++)
1304 if(ifofile
->vts_tmapt
->tmap
[i
].map_ent
)
1305 free(ifofile
->vts_tmapt
->tmap
[i
].map_ent
);
1306 free(ifofile
->vts_tmapt
->tmap
);
1307 free(ifofile
->vts_tmapt
->tmap_offset
);
1308 free(ifofile
->vts_tmapt
);
1309 ifofile
->vts_tmapt
= NULL
;
1314 int ifoRead_TITLE_C_ADT(ifo_handle_t
*ifofile
) {
1319 if(!ifofile
->vtsi_mat
)
1322 if(ifofile
->vtsi_mat
->vts_c_adt
== 0) /* mandatory */
1325 ifofile
->vts_c_adt
= malloc(sizeof(c_adt_t
));
1326 if(!ifofile
->vts_c_adt
)
1329 if(!ifoRead_C_ADT_internal(ifofile
, ifofile
->vts_c_adt
,
1330 ifofile
->vtsi_mat
->vts_c_adt
)) {
1331 free(ifofile
->vts_c_adt
);
1332 ifofile
->vts_c_adt
= 0;
1339 int ifoRead_C_ADT(ifo_handle_t
*ifofile
) {
1340 unsigned int sector
;
1345 if(ifofile
->vmgi_mat
) {
1346 if(ifofile
->vmgi_mat
->vmgm_c_adt
== 0)
1348 sector
= ifofile
->vmgi_mat
->vmgm_c_adt
;
1349 } else if(ifofile
->vtsi_mat
) {
1350 if(ifofile
->vtsi_mat
->vtsm_c_adt
== 0)
1352 sector
= ifofile
->vtsi_mat
->vtsm_c_adt
;
1357 ifofile
->menu_c_adt
= malloc(sizeof(c_adt_t
));
1358 if(!ifofile
->menu_c_adt
)
1361 if(!ifoRead_C_ADT_internal(ifofile
, ifofile
->menu_c_adt
, sector
)) {
1362 free(ifofile
->menu_c_adt
);
1363 ifofile
->menu_c_adt
= 0;
1370 static int ifoRead_C_ADT_internal(ifo_handle_t
*ifofile
,
1371 c_adt_t
*c_adt
, unsigned int sector
) {
1374 if(!DVDFileSeek_(ifofile
->file
, sector
* DVD_BLOCK_LEN
))
1377 if(!(DVDReadBytes(ifofile
->file
, c_adt
, C_ADT_SIZE
)))
1380 B2N_16(c_adt
->nr_of_vobs
);
1381 B2N_32(c_adt
->last_byte
);
1383 info_length
= c_adt
->last_byte
+ 1 - C_ADT_SIZE
;
1385 CHECK_ZERO(c_adt
->zero_1
);
1386 /* assert(c_adt->nr_of_vobs > 0);
1387 Magic Knight Rayearth Daybreak is mastered very strange and has
1388 Titles with a VOBS that has no cells. */
1389 CHECK_VALUE(info_length
% sizeof(cell_adr_t
) == 0);
1391 /* assert(info_length / sizeof(cell_adr_t) >= c_adt->nr_of_vobs);
1392 Enemy of the State region 2 (de) has Titles where nr_of_vobs field
1393 is to high, they high ones are never referenced though. */
1394 if(info_length
/ sizeof(cell_adr_t
) < c_adt
->nr_of_vobs
) {
1395 fprintf(stderr
, "libdvdread: *C_ADT nr_of_vobs > avaiable info entries\n");
1396 c_adt
->nr_of_vobs
= info_length
/ sizeof(cell_adr_t
);
1399 c_adt
->cell_adr_table
= malloc(info_length
);
1400 if(!c_adt
->cell_adr_table
)
1404 !(DVDReadBytes(ifofile
->file
, c_adt
->cell_adr_table
, info_length
))) {
1405 free(c_adt
->cell_adr_table
);
1409 for(i
= 0; i
< info_length
/sizeof(cell_adr_t
); i
++) {
1410 B2N_16(c_adt
->cell_adr_table
[i
].vob_id
);
1411 B2N_32(c_adt
->cell_adr_table
[i
].start_sector
);
1412 B2N_32(c_adt
->cell_adr_table
[i
].last_sector
);
1414 CHECK_ZERO(c_adt
->cell_adr_table
[i
].zero_1
);
1415 CHECK_VALUE(c_adt
->cell_adr_table
[i
].vob_id
> 0);
1416 CHECK_VALUE(c_adt
->cell_adr_table
[i
].vob_id
<= c_adt
->nr_of_vobs
);
1417 CHECK_VALUE(c_adt
->cell_adr_table
[i
].cell_id
> 0);
1418 CHECK_VALUE(c_adt
->cell_adr_table
[i
].start_sector
<
1419 c_adt
->cell_adr_table
[i
].last_sector
);
1426 static void ifoFree_C_ADT_internal(c_adt_t
*c_adt
) {
1428 free(c_adt
->cell_adr_table
);
1433 void ifoFree_C_ADT(ifo_handle_t
*ifofile
) {
1437 ifoFree_C_ADT_internal(ifofile
->menu_c_adt
);
1438 ifofile
->menu_c_adt
= 0;
1441 void ifoFree_TITLE_C_ADT(ifo_handle_t
*ifofile
) {
1445 ifoFree_C_ADT_internal(ifofile
->vts_c_adt
);
1446 ifofile
->vts_c_adt
= 0;
1449 int ifoRead_TITLE_VOBU_ADMAP(ifo_handle_t
*ifofile
) {
1453 if(!ifofile
->vtsi_mat
)
1456 if(ifofile
->vtsi_mat
->vts_vobu_admap
== 0) /* mandatory */
1459 ifofile
->vts_vobu_admap
= malloc(sizeof(vobu_admap_t
));
1460 if(!ifofile
->vts_vobu_admap
)
1463 if(!ifoRead_VOBU_ADMAP_internal(ifofile
, ifofile
->vts_vobu_admap
,
1464 ifofile
->vtsi_mat
->vts_vobu_admap
)) {
1465 free(ifofile
->vts_vobu_admap
);
1466 ifofile
->vts_vobu_admap
= 0;
1473 int ifoRead_VOBU_ADMAP(ifo_handle_t
*ifofile
) {
1474 unsigned int sector
;
1479 if(ifofile
->vmgi_mat
) {
1480 if(ifofile
->vmgi_mat
->vmgm_vobu_admap
== 0)
1482 sector
= ifofile
->vmgi_mat
->vmgm_vobu_admap
;
1483 } else if(ifofile
->vtsi_mat
) {
1484 if(ifofile
->vtsi_mat
->vtsm_vobu_admap
== 0)
1486 sector
= ifofile
->vtsi_mat
->vtsm_vobu_admap
;
1491 ifofile
->menu_vobu_admap
= malloc(sizeof(vobu_admap_t
));
1492 if(!ifofile
->menu_vobu_admap
)
1495 if(!ifoRead_VOBU_ADMAP_internal(ifofile
, ifofile
->menu_vobu_admap
, sector
)) {
1496 free(ifofile
->menu_vobu_admap
);
1497 ifofile
->menu_vobu_admap
= 0;
1504 static int ifoRead_VOBU_ADMAP_internal(ifo_handle_t
*ifofile
,
1505 vobu_admap_t
*vobu_admap
,
1506 unsigned int sector
) {
1510 if(!DVDFileSeek_(ifofile
->file
, sector
* DVD_BLOCK_LEN
))
1513 if(!(DVDReadBytes(ifofile
->file
, vobu_admap
, VOBU_ADMAP_SIZE
)))
1516 B2N_32(vobu_admap
->last_byte
);
1518 info_length
= vobu_admap
->last_byte
+ 1 - VOBU_ADMAP_SIZE
;
1519 /* assert(info_length > 0);
1520 Magic Knight Rayearth Daybreak is mastered very strange and has
1521 Titles with a VOBS that has no VOBUs. */
1522 CHECK_VALUE(info_length
% sizeof(uint32_t) == 0);
1524 vobu_admap
->vobu_start_sectors
= malloc(info_length
);
1525 if(!vobu_admap
->vobu_start_sectors
) {
1529 !(DVDReadBytes(ifofile
->file
,
1530 vobu_admap
->vobu_start_sectors
, info_length
))) {
1531 free(vobu_admap
->vobu_start_sectors
);
1535 for(i
= 0; i
< info_length
/sizeof(uint32_t); i
++)
1536 B2N_32(vobu_admap
->vobu_start_sectors
[i
]);
1542 static void ifoFree_VOBU_ADMAP_internal(vobu_admap_t
*vobu_admap
) {
1544 free(vobu_admap
->vobu_start_sectors
);
1549 void ifoFree_VOBU_ADMAP(ifo_handle_t
*ifofile
) {
1553 ifoFree_VOBU_ADMAP_internal(ifofile
->menu_vobu_admap
);
1554 ifofile
->menu_vobu_admap
= 0;
1557 void ifoFree_TITLE_VOBU_ADMAP(ifo_handle_t
*ifofile
) {
1561 ifoFree_VOBU_ADMAP_internal(ifofile
->vts_vobu_admap
);
1562 ifofile
->vts_vobu_admap
= 0;
1565 int ifoRead_PGCIT(ifo_handle_t
*ifofile
) {
1570 if(!ifofile
->vtsi_mat
)
1573 if(ifofile
->vtsi_mat
->vts_pgcit
== 0) /* mandatory */
1576 ifofile
->vts_pgcit
= malloc(sizeof(pgcit_t
));
1577 if(!ifofile
->vts_pgcit
)
1580 if(!ifoRead_PGCIT_internal(ifofile
, ifofile
->vts_pgcit
,
1581 ifofile
->vtsi_mat
->vts_pgcit
* DVD_BLOCK_LEN
)) {
1582 free(ifofile
->vts_pgcit
);
1583 ifofile
->vts_pgcit
= 0;
1590 static int ifoRead_PGCIT_internal(ifo_handle_t
*ifofile
, pgcit_t
*pgcit
,
1591 unsigned int offset
) {
1593 uint8_t *data
, *ptr
;
1595 if(!DVDFileSeek_(ifofile
->file
, offset
))
1598 if(!(DVDReadBytes(ifofile
->file
, pgcit
, PGCIT_SIZE
)))
1601 B2N_16(pgcit
->nr_of_pgci_srp
);
1602 B2N_32(pgcit
->last_byte
);
1604 CHECK_ZERO(pgcit
->zero_1
);
1605 /* assert(pgcit->nr_of_pgci_srp != 0);
1606 Magic Knight Rayearth Daybreak is mastered very strange and has
1607 Titles with 0 PTTs. */
1608 CHECK_VALUE(pgcit
->nr_of_pgci_srp
< 10000); // ?? seen max of 1338
1610 info_length
= pgcit
->nr_of_pgci_srp
* PGCI_SRP_SIZE
;
1611 data
= malloc(info_length
);
1615 if(info_length
&& !(DVDReadBytes(ifofile
->file
, data
, info_length
))) {
1620 pgcit
->pgci_srp
= malloc(pgcit
->nr_of_pgci_srp
* sizeof(pgci_srp_t
));
1621 if(!pgcit
->pgci_srp
) {
1626 for(i
= 0; i
< pgcit
->nr_of_pgci_srp
; i
++) {
1627 memcpy(&pgcit
->pgci_srp
[i
], ptr
, PGCI_LU_SIZE
);
1628 ptr
+= PGCI_LU_SIZE
;
1629 B2N_16(pgcit
->pgci_srp
[i
].ptl_id_mask
);
1630 B2N_32(pgcit
->pgci_srp
[i
].pgc_start_byte
);
1631 CHECK_VALUE(pgcit
->pgci_srp
[i
].unknown1
== 0);
1635 for(i
= 0; i
< pgcit
->nr_of_pgci_srp
; i
++)
1636 CHECK_VALUE(pgcit
->pgci_srp
[i
].pgc_start_byte
+ PGC_SIZE
<= pgcit
->last_byte
+1);
1638 for(i
= 0; i
< pgcit
->nr_of_pgci_srp
; i
++) {
1639 pgcit
->pgci_srp
[i
].pgc
= malloc(sizeof(pgc_t
));
1640 if(!pgcit
->pgci_srp
[i
].pgc
) {
1642 for(j
= 0; j
< i
; j
++) {
1643 ifoFree_PGC(pgcit
->pgci_srp
[j
].pgc
);
1644 free(pgcit
->pgci_srp
[j
].pgc
);
1648 if(!ifoRead_PGC(ifofile
, pgcit
->pgci_srp
[i
].pgc
,
1649 offset
+ pgcit
->pgci_srp
[i
].pgc_start_byte
)) {
1651 for(j
= 0; j
< i
; j
++) {
1652 ifoFree_PGC(pgcit
->pgci_srp
[j
].pgc
);
1653 free(pgcit
->pgci_srp
[j
].pgc
);
1655 free(pgcit
->pgci_srp
);
1663 static void ifoFree_PGCIT_internal(pgcit_t
*pgcit
) {
1666 for(i
= 0; i
< pgcit
->nr_of_pgci_srp
; i
++)
1667 ifoFree_PGC(pgcit
->pgci_srp
[i
].pgc
);
1668 free(pgcit
->pgci_srp
);
1672 void ifoFree_PGCIT(ifo_handle_t
*ifofile
) {
1676 if(ifofile
->vts_pgcit
) {
1677 ifoFree_PGCIT_internal(ifofile
->vts_pgcit
);
1678 free(ifofile
->vts_pgcit
);
1679 ifofile
->vts_pgcit
= 0;
1684 int ifoRead_PGCI_UT(ifo_handle_t
*ifofile
) {
1686 unsigned int sector
;
1689 uint8_t *data
, *ptr
;
1694 if(ifofile
->vmgi_mat
) {
1695 if(ifofile
->vmgi_mat
->vmgm_pgci_ut
== 0)
1697 sector
= ifofile
->vmgi_mat
->vmgm_pgci_ut
;
1698 } else if(ifofile
->vtsi_mat
) {
1699 if(ifofile
->vtsi_mat
->vtsm_pgci_ut
== 0)
1701 sector
= ifofile
->vtsi_mat
->vtsm_pgci_ut
;
1706 ifofile
->pgci_ut
= malloc(sizeof(pgci_ut_t
));
1707 if(!ifofile
->pgci_ut
)
1710 if(!DVDFileSeek_(ifofile
->file
, sector
* DVD_BLOCK_LEN
)) {
1711 free(ifofile
->pgci_ut
);
1712 ifofile
->pgci_ut
= 0;
1716 if(!(DVDReadBytes(ifofile
->file
, ifofile
->pgci_ut
, PGCI_UT_SIZE
))) {
1717 free(ifofile
->pgci_ut
);
1718 ifofile
->pgci_ut
= 0;
1722 pgci_ut
= ifofile
->pgci_ut
;
1724 B2N_16(pgci_ut
->nr_of_lus
);
1725 B2N_32(pgci_ut
->last_byte
);
1727 CHECK_ZERO(pgci_ut
->zero_1
);
1728 CHECK_VALUE(pgci_ut
->nr_of_lus
!= 0);
1729 CHECK_VALUE(pgci_ut
->nr_of_lus
< 100); // ?? 3-4 ?
1730 CHECK_VALUE((uint32_t)pgci_ut
->nr_of_lus
* PGCI_LU_SIZE
< pgci_ut
->last_byte
);
1732 info_length
= pgci_ut
->nr_of_lus
* PGCI_LU_SIZE
;
1733 data
= malloc(info_length
);
1736 ifofile
->pgci_ut
= 0;
1739 if(!(DVDReadBytes(ifofile
->file
, data
, info_length
))) {
1742 ifofile
->pgci_ut
= 0;
1746 pgci_ut
->lu
= malloc(pgci_ut
->nr_of_lus
* sizeof(pgci_lu_t
));
1750 ifofile
->pgci_ut
= 0;
1754 for(i
= 0; i
< pgci_ut
->nr_of_lus
; i
++) {
1755 memcpy(&pgci_ut
->lu
[i
], ptr
, PGCI_LU_SIZE
);
1756 ptr
+= PGCI_LU_SIZE
;
1757 B2N_16(pgci_ut
->lu
[i
].lang_code
);
1758 B2N_32(pgci_ut
->lu
[i
].lang_start_byte
);
1762 for(i
= 0; i
< pgci_ut
->nr_of_lus
; i
++) {
1763 // Maybe this is only defined for v1.1 and later titles?
1764 /* If the bits in 'lu[i].exists' are enumerated abcd efgh then:
1765 VTS_x_yy.IFO VIDEO_TS.IFO
1766 a == 0x83 "Root" 0x82 "Title"
1767 b == 0x84 "Subpicture"
1772 CHECK_VALUE((pgci_ut
->lu
[i
].exists
& 0x07) == 0);
1775 for(i
= 0; i
< pgci_ut
->nr_of_lus
; i
++) {
1776 pgci_ut
->lu
[i
].pgcit
= malloc(sizeof(pgcit_t
));
1777 if(!pgci_ut
->lu
[i
].pgcit
) {
1779 for(j
= 0; j
< i
; j
++) {
1780 ifoFree_PGCIT_internal(pgci_ut
->lu
[j
].pgcit
);
1781 free(pgci_ut
->lu
[j
].pgcit
);
1785 ifofile
->pgci_ut
= 0;
1788 if(!ifoRead_PGCIT_internal(ifofile
, pgci_ut
->lu
[i
].pgcit
,
1789 sector
* DVD_BLOCK_LEN
1790 + pgci_ut
->lu
[i
].lang_start_byte
)) {
1792 for(j
= 0; j
< i
; j
++) {
1793 ifoFree_PGCIT_internal(pgci_ut
->lu
[j
].pgcit
);
1794 free(pgci_ut
->lu
[j
].pgcit
);
1796 free(pgci_ut
->lu
[i
].pgcit
);
1799 ifofile
->pgci_ut
= 0;
1802 // FIXME: Iterate and verify that all menus that should exists accordingly
1803 // to pgci_ut->lu[i].exists really do?
1810 void ifoFree_PGCI_UT(ifo_handle_t
*ifofile
) {
1816 if(ifofile
->pgci_ut
) {
1817 for(i
= 0; i
< ifofile
->pgci_ut
->nr_of_lus
; i
++) {
1818 ifoFree_PGCIT_internal(ifofile
->pgci_ut
->lu
[i
].pgcit
);
1819 free(ifofile
->pgci_ut
->lu
[i
].pgcit
);
1821 free(ifofile
->pgci_ut
->lu
);
1822 free(ifofile
->pgci_ut
);
1823 ifofile
->pgci_ut
= 0;
1827 static int ifoRead_VTS_ATTRIBUTES(ifo_handle_t
*ifofile
,
1828 vts_attributes_t
*vts_attributes
,
1829 unsigned int offset
) {
1832 if(!DVDFileSeek_(ifofile
->file
, offset
))
1835 if(!(DVDReadBytes(ifofile
->file
, vts_attributes
, sizeof(vts_attributes_t
))))
1838 B2N_32(vts_attributes
->last_byte
);
1839 B2N_32(vts_attributes
->vts_cat
);
1840 B2N_16(vts_attributes
->vtsm_audio_attr
.lang_code
);
1841 B2N_16(vts_attributes
->vtsm_subp_attr
.lang_code
);
1842 for(i
= 0; i
< 8; i
++)
1843 B2N_16(vts_attributes
->vtstt_audio_attr
[i
].lang_code
);
1844 for(i
= 0; i
< 32; i
++)
1845 B2N_16(vts_attributes
->vtstt_subp_attr
[i
].lang_code
);
1847 CHECK_ZERO(vts_attributes
->zero_1
);
1848 CHECK_ZERO(vts_attributes
->zero_2
);
1849 CHECK_ZERO(vts_attributes
->zero_3
);
1850 CHECK_ZERO(vts_attributes
->zero_4
);
1851 CHECK_ZERO(vts_attributes
->zero_5
);
1852 CHECK_ZERO(vts_attributes
->zero_6
);
1853 CHECK_ZERO(vts_attributes
->zero_7
);
1854 CHECK_VALUE(vts_attributes
->nr_of_vtsm_audio_streams
<= 1);
1855 CHECK_VALUE(vts_attributes
->nr_of_vtsm_subp_streams
<= 1);
1856 CHECK_VALUE(vts_attributes
->nr_of_vtstt_audio_streams
<= 8);
1857 for(i
= vts_attributes
->nr_of_vtstt_audio_streams
; i
< 8; i
++)
1858 CHECK_ZERO(vts_attributes
->vtstt_audio_attr
[i
]);
1859 CHECK_VALUE(vts_attributes
->nr_of_vtstt_subp_streams
<= 32);
1861 unsigned int nr_coded
;
1862 CHECK_VALUE(vts_attributes
->last_byte
+ 1 >= VTS_ATTRIBUTES_MIN_SIZE
);
1863 nr_coded
= (vts_attributes
->last_byte
+ 1 - VTS_ATTRIBUTES_MIN_SIZE
)/6;
1864 // This is often nr_coded = 70, how do you know how many there really are?
1865 if(nr_coded
> 32) { // We haven't read more from disk/file anyway
1868 CHECK_VALUE(vts_attributes
->nr_of_vtstt_subp_streams
<= nr_coded
);
1869 for(i
= vts_attributes
->nr_of_vtstt_subp_streams
; i
< nr_coded
; i
++)
1870 CHECK_ZERO(vts_attributes
->vtstt_subp_attr
[i
]);
1878 int ifoRead_VTS_ATRT(ifo_handle_t
*ifofile
) {
1879 vts_atrt_t
*vts_atrt
;
1880 unsigned int i
, info_length
, sector
;
1886 if(!ifofile
->vmgi_mat
)
1889 if(ifofile
->vmgi_mat
->vts_atrt
== 0) /* mandatory */
1892 sector
= ifofile
->vmgi_mat
->vts_atrt
;
1893 if(!DVDFileSeek_(ifofile
->file
, sector
* DVD_BLOCK_LEN
))
1896 vts_atrt
= malloc(sizeof(vts_atrt_t
));
1900 ifofile
->vts_atrt
= vts_atrt
;
1902 if(!(DVDReadBytes(ifofile
->file
, vts_atrt
, VTS_ATRT_SIZE
))) {
1904 ifofile
->vts_atrt
= 0;
1908 B2N_16(vts_atrt
->nr_of_vtss
);
1909 B2N_32(vts_atrt
->last_byte
);
1911 CHECK_ZERO(vts_atrt
->zero_1
);
1912 CHECK_VALUE(vts_atrt
->nr_of_vtss
!= 0);
1913 CHECK_VALUE(vts_atrt
->nr_of_vtss
< 100); //??
1914 CHECK_VALUE((uint32_t)vts_atrt
->nr_of_vtss
* (4 + VTS_ATTRIBUTES_MIN_SIZE
) +
1915 VTS_ATRT_SIZE
< vts_atrt
->last_byte
+ 1);
1917 info_length
= vts_atrt
->nr_of_vtss
* sizeof(uint32_t);
1918 data
= malloc(info_length
);
1921 ifofile
->vts_atrt
= 0;
1925 vts_atrt
->vts_atrt_offsets
= data
;
1927 if(!(DVDReadBytes(ifofile
->file
, data
, info_length
))) {
1930 ifofile
->vts_atrt
= 0;
1934 for(i
= 0; i
< vts_atrt
->nr_of_vtss
; i
++) {
1936 CHECK_VALUE(data
[i
] + VTS_ATTRIBUTES_MIN_SIZE
< vts_atrt
->last_byte
+ 1);
1939 info_length
= vts_atrt
->nr_of_vtss
* sizeof(vts_attributes_t
);
1940 vts_atrt
->vts
= malloc(info_length
);
1941 if(!vts_atrt
->vts
) {
1944 ifofile
->vts_atrt
= 0;
1947 for(i
= 0; i
< vts_atrt
->nr_of_vtss
; i
++) {
1948 unsigned int offset
= data
[i
];
1949 if(!ifoRead_VTS_ATTRIBUTES(ifofile
, &(vts_atrt
->vts
[i
]),
1950 (sector
* DVD_BLOCK_LEN
) + offset
)) {
1953 ifofile
->vts_atrt
= 0;
1957 // This assert cant be in ifoRead_VTS_ATTRIBUTES
1958 CHECK_VALUE(offset
+ vts_atrt
->vts
[i
].last_byte
<= vts_atrt
->last_byte
+ 1);
1959 // Is this check correct?
1966 void ifoFree_VTS_ATRT(ifo_handle_t
*ifofile
) {
1970 if(ifofile
->vts_atrt
) {
1971 free(ifofile
->vts_atrt
->vts
);
1972 free(ifofile
->vts_atrt
->vts_atrt_offsets
);
1973 free(ifofile
->vts_atrt
);
1974 ifofile
->vts_atrt
= 0;
1979 int ifoRead_TXTDT_MGI(ifo_handle_t
*ifofile
) {
1980 txtdt_mgi_t
*txtdt_mgi
;
1985 if(!ifofile
->vmgi_mat
)
1988 /* Return successfully if there is nothing to read. */
1989 if(ifofile
->vmgi_mat
->txtdt_mgi
== 0)
1992 if(!DVDFileSeek_(ifofile
->file
,
1993 ifofile
->vmgi_mat
->txtdt_mgi
* DVD_BLOCK_LEN
))
1996 txtdt_mgi
= malloc(sizeof(txtdt_mgi_t
));
2000 ifofile
->txtdt_mgi
= txtdt_mgi
;
2002 if(!(DVDReadBytes(ifofile
->file
, txtdt_mgi
, TXTDT_MGI_SIZE
))) {
2003 fprintf(stderr
, "libdvdread: Unable to read TXTDT_MGI.\n");
2005 ifofile
->txtdt_mgi
= 0;
2009 // fprintf(stderr, "-- Not done yet --\n");
2013 void ifoFree_TXTDT_MGI(ifo_handle_t
*ifofile
) {
2017 if(ifofile
->txtdt_mgi
) {
2018 free(ifofile
->txtdt_mgi
);
2019 ifofile
->txtdt_mgi
= 0;