168
|
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
|
|
34 #ifndef DVD_BLOCK_LEN
|
|
35 #define DVD_BLOCK_LEN 2048
|
|
36 #endif
|
|
37
|
|
38 #ifndef NDEBUG
|
|
39 #define CHECK_ZERO0(arg) \
|
|
40 if(arg != 0) { \
|
|
41 fprintf(stderr, "*** Zero check failed in %s:%i\n for %s = 0x%x\n", \
|
|
42 __FILE__, __LINE__, # arg, arg); \
|
|
43 }
|
|
44 #define CHECK_ZERO(arg) \
|
|
45 if(memcmp(my_friendly_zeros, &arg, sizeof(arg))) { \
|
|
46 unsigned int i_CZ; \
|
|
47 fprintf(stderr, "*** Zero check failed in %s:%i\n for %s = 0x", \
|
|
48 __FILE__, __LINE__, # arg ); \
|
|
49 for(i_CZ = 0; i_CZ < sizeof(arg); i_CZ++) \
|
|
50 fprintf(stderr, "%02x", *((uint8_t *)&arg + i_CZ)); \
|
|
51 fprintf(stderr, "\n"); \
|
|
52 }
|
|
53 static const uint8_t my_friendly_zeros[2048];
|
|
54 #else
|
|
55 #define CHECK_ZERO0(arg) (void)(arg)
|
|
56 #define CHECK_ZERO(arg) (void)(arg)
|
|
57 #endif
|
|
58
|
|
59
|
|
60 /* Prototypes for internal functions */
|
|
61 static int ifoRead_VMG(ifo_handle_t *ifofile);
|
|
62 static int ifoRead_VTS(ifo_handle_t *ifofile);
|
|
63 static int ifoRead_PGC(ifo_handle_t *ifofile, pgc_t *pgc, unsigned int offset);
|
|
64 static int ifoRead_PGC_COMMAND_TBL(ifo_handle_t *ifofile,
|
|
65 pgc_command_tbl_t *cmd_tbl,
|
|
66 unsigned int offset);
|
|
67 static int ifoRead_PGC_PROGRAM_MAP(ifo_handle_t *ifofile,
|
|
68 pgc_program_map_t *program_map,
|
|
69 unsigned int nr, unsigned int offset);
|
|
70 static int ifoRead_CELL_PLAYBACK_TBL(ifo_handle_t *ifofile,
|
|
71 cell_playback_t *cell_playback,
|
|
72 unsigned int nr, unsigned int offset);
|
|
73 static int ifoRead_CELL_POSITION_TBL(ifo_handle_t *ifofile,
|
|
74 cell_position_t *cell_position,
|
|
75 unsigned int nr, unsigned int offset);
|
|
76 static int ifoRead_VTS_ATTRIBUTES(ifo_handle_t *ifofile,
|
|
77 vts_attributes_t *vts_attributes,
|
|
78 unsigned int offset);
|
|
79 static int ifoRead_C_ADT_internal(ifo_handle_t *ifofile, c_adt_t *c_adt,
|
|
80 unsigned int sector);
|
|
81 static int ifoRead_VOBU_ADMAP_internal(ifo_handle_t *ifofile,
|
|
82 vobu_admap_t *vobu_admap,
|
|
83 unsigned int sector);
|
|
84 static int ifoRead_PGCIT_internal(ifo_handle_t *ifofile, pgcit_t *pgcit,
|
|
85 unsigned int offset);
|
|
86
|
|
87 static void ifoFree_PGC(pgc_t *pgc);
|
|
88 static void ifoFree_PGC_COMMAND_TBL(pgc_command_tbl_t *cmd_tbl);
|
|
89 static void ifoFree_PGCIT_internal(pgcit_t *pgcit);
|
|
90
|
|
91
|
|
92 static inline int DVDFileSeek_( dvd_file_t *dvd_file, uint32_t offset ) {
|
|
93 return (DVDFileSeek(dvd_file, (int)offset) == (int)offset);
|
|
94 }
|
|
95
|
|
96
|
|
97 ifo_handle_t *ifoOpen(dvd_reader_t *dvd, int title) {
|
|
98 ifo_handle_t *ifofile;
|
|
99
|
|
100 ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t));
|
|
101 if(!ifofile)
|
|
102 return 0;
|
|
103
|
|
104 memset(ifofile, 0, sizeof(ifo_handle_t));
|
|
105
|
|
106 ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE);
|
|
107 if(!ifofile->file) /* Should really catch any error and try to fallback */
|
|
108 ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_BACKUP_FILE);
|
|
109 if(!ifofile->file) {
|
|
110 if(title) {
|
|
111 fprintf(stderr, "libdvdread: Can't open file VTS_%02d_0.IFO.\n", title);
|
|
112 } else {
|
|
113 fprintf(stderr, "libdvdread: Can't open file VIDEO_TS.IFO.\n");
|
|
114 }
|
|
115 free(ifofile);
|
|
116 return 0;
|
|
117 }
|
|
118
|
|
119 /* First check if this is a VMGI file. */
|
|
120 if(ifoRead_VMG(ifofile)) {
|
|
121
|
|
122 /* These are both mandatory. */
|
|
123 if(!ifoRead_FP_PGC(ifofile) || !ifoRead_TT_SRPT(ifofile)) {
|
|
124 fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO).\n");
|
|
125 ifoClose(ifofile);
|
|
126 return 0;
|
|
127 }
|
|
128
|
|
129 ifoRead_PGCI_UT(ifofile);
|
|
130 ifoRead_PTL_MAIT(ifofile);
|
|
131
|
|
132 /* This is also mandatory. */
|
|
133 if(!ifoRead_VTS_ATRT(ifofile)) {
|
|
134 fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO).\n");
|
|
135 ifoClose(ifofile);
|
|
136 return 0;
|
|
137 }
|
|
138
|
|
139 ifoRead_TXTDT_MGI(ifofile);
|
|
140 ifoRead_C_ADT(ifofile);
|
|
141 ifoRead_VOBU_ADMAP(ifofile);
|
|
142
|
|
143 return ifofile;
|
|
144 }
|
|
145
|
|
146 if(ifoRead_VTS(ifofile)) {
|
|
147
|
|
148 if(!ifoRead_VTS_PTT_SRPT(ifofile) || !ifoRead_PGCIT(ifofile)) {
|
|
149 fprintf(stderr, "libdvdread: Invalid title IFO (VTS_%02d_0.IFO).\n",
|
|
150 title);
|
|
151 ifoClose(ifofile);
|
|
152 return 0;
|
|
153 }
|
|
154
|
|
155
|
|
156 ifoRead_PGCI_UT(ifofile);
|
|
157 ifoRead_VTS_TMAPT(ifofile);
|
|
158 ifoRead_C_ADT(ifofile);
|
|
159 ifoRead_VOBU_ADMAP(ifofile);
|
|
160
|
|
161 if(!ifoRead_TITLE_C_ADT(ifofile) || !ifoRead_TITLE_VOBU_ADMAP(ifofile)) {
|
|
162 fprintf(stderr, "libdvdread: Invalid title IFO (VTS_%02d_0.IFO).\n",
|
|
163 title);
|
|
164 ifoClose(ifofile);
|
|
165 return 0;
|
|
166 }
|
|
167
|
|
168 return ifofile;
|
|
169 }
|
|
170
|
|
171 if(title) {
|
|
172 fprintf(stderr, "libdvdread: Invalid IFO for title %d (VTS_%02d_0.IFO).\n",
|
|
173 title, title);
|
|
174 } else {
|
|
175 fprintf(stderr, "libdvdread: Invalid IFO for VMGM (VIDEO_TS.IFO).\n");
|
|
176 }
|
|
177 ifoClose(ifofile);
|
|
178 return 0;
|
|
179 }
|
|
180
|
|
181
|
|
182 ifo_handle_t *ifoOpenVMGI(dvd_reader_t *dvd) {
|
|
183 ifo_handle_t *ifofile;
|
|
184
|
|
185 ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t));
|
|
186 if(!ifofile)
|
|
187 return 0;
|
|
188
|
|
189 memset(ifofile, 0, sizeof(ifo_handle_t));
|
|
190
|
|
191 ifofile->file = DVDOpenFile(dvd, 0, DVD_READ_INFO_FILE);
|
|
192 if(!ifofile->file) /* Should really catch any error and try to fallback */
|
|
193 ifofile->file = DVDOpenFile(dvd, 0, DVD_READ_INFO_BACKUP_FILE);
|
|
194 if(!ifofile->file) {
|
|
195 fprintf(stderr, "libdvdread: Can't open file VIDEO_TS.IFO.\n");
|
|
196 free(ifofile);
|
|
197 return 0;
|
|
198 }
|
|
199
|
|
200 if(ifoRead_VMG(ifofile))
|
|
201 return ifofile;
|
|
202
|
|
203 fprintf(stderr, "libdvdread: Invalid main menu IFO (VIDEO_TS.IFO).\n");
|
|
204 ifoClose(ifofile);
|
|
205 return 0;
|
|
206 }
|
|
207
|
|
208
|
|
209 ifo_handle_t *ifoOpenVTSI(dvd_reader_t *dvd, int title) {
|
|
210 ifo_handle_t *ifofile;
|
|
211
|
|
212 ifofile = (ifo_handle_t *)malloc(sizeof(ifo_handle_t));
|
|
213 if(!ifofile)
|
|
214 return 0;
|
|
215
|
|
216 memset(ifofile, 0, sizeof(ifo_handle_t));
|
|
217
|
|
218 if(title <= 0 || title > 99) {
|
|
219 fprintf(stderr, "libdvdread: ifoOpenVTSI invalid title (%d).\n", title);
|
|
220 free(ifofile);
|
|
221 return 0;
|
|
222 }
|
|
223
|
|
224 ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE);
|
|
225 if(!ifofile->file) /* Should really catch any error and try to fallback */
|
|
226 ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_BACKUP_FILE);
|
|
227 if(!ifofile->file) {
|
|
228 fprintf(stderr, "libdvdread: Can't open file VTS_%02d_0.IFO.\n", title);
|
|
229 free(ifofile);
|
|
230 return 0;
|
|
231 }
|
|
232
|
|
233 ifoRead_VTS(ifofile);
|
|
234 if(ifofile->vtsi_mat)
|
|
235 return ifofile;
|
|
236
|
|
237 fprintf(stderr, "libdvdread: Invalid IFO for title %d (VTS_%02d_0.IFO).\n",
|
|
238 title, title);
|
|
239 ifoClose(ifofile);
|
|
240 return 0;
|
|
241 }
|
|
242
|
|
243
|
|
244 void ifoClose(ifo_handle_t *ifofile) {
|
|
245 if(!ifofile)
|
|
246 return;
|
|
247
|
|
248 ifoFree_VOBU_ADMAP(ifofile);
|
|
249 ifoFree_TITLE_VOBU_ADMAP(ifofile);
|
|
250 ifoFree_C_ADT(ifofile);
|
|
251 ifoFree_TITLE_C_ADT(ifofile);
|
|
252 ifoFree_TXTDT_MGI(ifofile);
|
|
253 ifoFree_VTS_ATRT(ifofile);
|
|
254 ifoFree_PTL_MAIT(ifofile);
|
|
255 ifoFree_PGCI_UT(ifofile);
|
|
256 ifoFree_TT_SRPT(ifofile);
|
|
257 ifoFree_FP_PGC(ifofile);
|
|
258 ifoFree_PGCIT(ifofile);
|
|
259 ifoFree_VTS_PTT_SRPT(ifofile);
|
|
260
|
|
261 if(ifofile->vmgi_mat)
|
|
262 free(ifofile->vmgi_mat);
|
|
263
|
|
264 if(ifofile->vtsi_mat)
|
|
265 free(ifofile->vtsi_mat);
|
|
266
|
|
267 DVDCloseFile(ifofile->file);
|
|
268 ifofile->file = 0;
|
|
269 free(ifofile);
|
|
270 ifofile = 0;
|
|
271 }
|
|
272
|
|
273
|
|
274 static int ifoRead_VMG(ifo_handle_t *ifofile) {
|
|
275 vmgi_mat_t *vmgi_mat;
|
|
276
|
|
277 vmgi_mat = (vmgi_mat_t *)malloc(sizeof(vmgi_mat_t));
|
|
278 if(!vmgi_mat)
|
|
279 return 0;
|
|
280
|
|
281 ifofile->vmgi_mat = vmgi_mat;
|
|
282
|
|
283 if(!DVDFileSeek_(ifofile->file, 0)) {
|
|
284 free(ifofile->vmgi_mat);
|
|
285 ifofile->vmgi_mat = 0;
|
|
286 return 0;
|
|
287 }
|
|
288
|
|
289 if(!DVDReadBytes(ifofile->file, vmgi_mat, sizeof(vmgi_mat_t))) {
|
|
290 free(ifofile->vmgi_mat);
|
|
291 ifofile->vmgi_mat = 0;
|
|
292 return 0;
|
|
293 }
|
|
294
|
|
295 if(strncmp("DVDVIDEO-VMG", vmgi_mat->vmg_identifier, 12) != 0) {
|
|
296 free(ifofile->vmgi_mat);
|
|
297 ifofile->vmgi_mat = 0;
|
|
298 return 0;
|
|
299 }
|
|
300
|
|
301 B2N_32(vmgi_mat->vmg_last_sector);
|
|
302 B2N_32(vmgi_mat->vmgi_last_sector);
|
|
303 B2N_32(vmgi_mat->vmg_category);
|
|
304 B2N_16(vmgi_mat->vmg_nr_of_volumes);
|
|
305 B2N_16(vmgi_mat->vmg_this_volume_nr);
|
|
306 B2N_16(vmgi_mat->vmg_nr_of_title_sets);
|
|
307 B2N_64(vmgi_mat->vmg_pos_code);
|
|
308 B2N_32(vmgi_mat->vmgi_last_byte);
|
|
309 B2N_32(vmgi_mat->first_play_pgc);
|
|
310 B2N_32(vmgi_mat->vmgm_vobs);
|
|
311 B2N_32(vmgi_mat->tt_srpt);
|
|
312 B2N_32(vmgi_mat->vmgm_pgci_ut);
|
|
313 B2N_32(vmgi_mat->ptl_mait);
|
|
314 B2N_32(vmgi_mat->vts_atrt);
|
|
315 B2N_32(vmgi_mat->txtdt_mgi);
|
|
316 B2N_32(vmgi_mat->vmgm_c_adt);
|
|
317 B2N_32(vmgi_mat->vmgm_vobu_admap);
|
|
318 B2N_16(vmgi_mat->vmgm_audio_attr.lang_code);
|
|
319 B2N_16(vmgi_mat->vmgm_subp_attr.lang_code);
|
|
320
|
|
321
|
|
322 CHECK_ZERO(vmgi_mat->zero_1);
|
|
323 CHECK_ZERO(vmgi_mat->zero_2);
|
|
324 CHECK_ZERO(vmgi_mat->zero_3);
|
|
325 CHECK_ZERO(vmgi_mat->zero_4);
|
|
326 CHECK_ZERO(vmgi_mat->zero_5);
|
|
327 CHECK_ZERO(vmgi_mat->zero_6);
|
|
328 CHECK_ZERO(vmgi_mat->zero_7);
|
|
329 CHECK_ZERO(vmgi_mat->zero_8);
|
|
330 CHECK_ZERO(vmgi_mat->zero_9);
|
|
331 CHECK_ZERO(vmgi_mat->zero_10);
|
|
332 CHECK_VALUE(vmgi_mat->vmg_last_sector != 0);
|
|
333 CHECK_VALUE(vmgi_mat->vmgi_last_sector != 0);
|
|
334 CHECK_VALUE(vmgi_mat->vmgi_last_sector * 2 <= vmgi_mat->vmg_last_sector);
|
|
335 CHECK_VALUE(vmgi_mat->vmgi_last_sector * 2 <= vmgi_mat->vmg_last_sector);
|
|
336 CHECK_VALUE(vmgi_mat->vmg_nr_of_volumes != 0);
|
|
337 CHECK_VALUE(vmgi_mat->vmg_this_volume_nr != 0);
|
|
338 CHECK_VALUE(vmgi_mat->vmg_this_volume_nr <= vmgi_mat->vmg_nr_of_volumes);
|
|
339 CHECK_VALUE(vmgi_mat->disc_side == 1 || vmgi_mat->disc_side == 2);
|
|
340 CHECK_VALUE(vmgi_mat->vmg_nr_of_title_sets != 0);
|
|
341 CHECK_VALUE(vmgi_mat->vmgi_last_byte >= 341);
|
|
342 CHECK_VALUE(vmgi_mat->vmgi_last_byte / DVD_BLOCK_LEN <=
|
|
343 vmgi_mat->vmgi_last_sector);
|
|
344 /* It seems that first_play_pgc is optional. */
|
|
345 CHECK_VALUE(vmgi_mat->first_play_pgc < vmgi_mat->vmgi_last_byte);
|
|
346 CHECK_VALUE(vmgi_mat->vmgm_vobs == 0 ||
|
|
347 (vmgi_mat->vmgm_vobs > vmgi_mat->vmgi_last_sector &&
|
|
348 vmgi_mat->vmgm_vobs < vmgi_mat->vmg_last_sector));
|
|
349 CHECK_VALUE(vmgi_mat->tt_srpt <= vmgi_mat->vmgi_last_sector);
|
|
350 CHECK_VALUE(vmgi_mat->vmgm_pgci_ut <= vmgi_mat->vmgi_last_sector);
|
|
351 CHECK_VALUE(vmgi_mat->ptl_mait <= vmgi_mat->vmgi_last_sector);
|
|
352 CHECK_VALUE(vmgi_mat->vts_atrt <= vmgi_mat->vmgi_last_sector);
|
|
353 CHECK_VALUE(vmgi_mat->txtdt_mgi <= vmgi_mat->vmgi_last_sector);
|
|
354 CHECK_VALUE(vmgi_mat->vmgm_c_adt <= vmgi_mat->vmgi_last_sector);
|
|
355 CHECK_VALUE(vmgi_mat->vmgm_vobu_admap <= vmgi_mat->vmgi_last_sector);
|
|
356
|
|
357 CHECK_VALUE(vmgi_mat->nr_of_vmgm_audio_streams <= 1);
|
|
358 CHECK_VALUE(vmgi_mat->nr_of_vmgm_subp_streams <= 1);
|
|
359
|
|
360 return 1;
|
|
361 }
|
|
362
|
|
363
|
|
364 static int ifoRead_VTS(ifo_handle_t *ifofile) {
|
|
365 vtsi_mat_t *vtsi_mat;
|
|
366 int i;
|
|
367
|
|
368 vtsi_mat = (vtsi_mat_t *)malloc(sizeof(vtsi_mat_t));
|
|
369 if(!vtsi_mat)
|
|
370 return 0;
|
|
371
|
|
372 ifofile->vtsi_mat = vtsi_mat;
|
|
373
|
|
374 if(!DVDFileSeek_(ifofile->file, 0)) {
|
|
375 free(ifofile->vtsi_mat);
|
|
376 ifofile->vtsi_mat = 0;
|
|
377 return 0;
|
|
378 }
|
|
379
|
|
380 if(!(DVDReadBytes(ifofile->file, vtsi_mat, sizeof(vtsi_mat_t)))) {
|
|
381 free(ifofile->vtsi_mat);
|
|
382 ifofile->vtsi_mat = 0;
|
|
383 return 0;
|
|
384 }
|
|
385
|
|
386 if(strncmp("DVDVIDEO-VTS", vtsi_mat->vts_identifier, 12) != 0) {
|
|
387 free(ifofile->vtsi_mat);
|
|
388 ifofile->vtsi_mat = 0;
|
|
389 return 0;
|
|
390 }
|
|
391
|
|
392 B2N_32(vtsi_mat->vts_last_sector);
|
|
393 B2N_32(vtsi_mat->vtsi_last_sector);
|
|
394 B2N_32(vtsi_mat->vts_category);
|
|
395 B2N_32(vtsi_mat->vtsi_last_byte);
|
|
396 B2N_32(vtsi_mat->vtsm_vobs);
|
|
397 B2N_32(vtsi_mat->vtstt_vobs);
|
|
398 B2N_32(vtsi_mat->vts_ptt_srpt);
|
|
399 B2N_32(vtsi_mat->vts_pgcit);
|
|
400 B2N_32(vtsi_mat->vtsm_pgci_ut);
|
|
401 B2N_32(vtsi_mat->vts_tmapt);
|
|
402 B2N_32(vtsi_mat->vtsm_c_adt);
|
|
403 B2N_32(vtsi_mat->vtsm_vobu_admap);
|
|
404 B2N_32(vtsi_mat->vts_c_adt);
|
|
405 B2N_32(vtsi_mat->vts_vobu_admap);
|
|
406 B2N_16(vtsi_mat->vtsm_audio_attr.lang_code);
|
|
407 B2N_16(vtsi_mat->vtsm_subp_attr.lang_code);
|
|
408 for(i = 0; i < 8; i++)
|
|
409 B2N_16(vtsi_mat->vts_audio_attr[i].lang_code);
|
|
410 for(i = 0; i < 32; i++)
|
|
411 B2N_16(vtsi_mat->vts_subp_attr[i].lang_code);
|
|
412
|
|
413
|
|
414 CHECK_ZERO(vtsi_mat->zero_1);
|
|
415 CHECK_ZERO(vtsi_mat->zero_2);
|
|
416 CHECK_ZERO(vtsi_mat->zero_3);
|
|
417 CHECK_ZERO(vtsi_mat->zero_4);
|
|
418 CHECK_ZERO(vtsi_mat->zero_5);
|
|
419 CHECK_ZERO(vtsi_mat->zero_6);
|
|
420 CHECK_ZERO(vtsi_mat->zero_7);
|
|
421 CHECK_ZERO(vtsi_mat->zero_8);
|
|
422 CHECK_ZERO(vtsi_mat->zero_9);
|
|
423 CHECK_ZERO(vtsi_mat->zero_10);
|
|
424 CHECK_ZERO(vtsi_mat->zero_11);
|
|
425 CHECK_ZERO(vtsi_mat->zero_12);
|
|
426 CHECK_ZERO(vtsi_mat->zero_13);
|
|
427 CHECK_ZERO(vtsi_mat->zero_14);
|
|
428 CHECK_ZERO(vtsi_mat->zero_15);
|
|
429 CHECK_ZERO(vtsi_mat->zero_16);
|
|
430 CHECK_ZERO(vtsi_mat->zero_17);
|
|
431 CHECK_ZERO(vtsi_mat->zero_18);
|
|
432 CHECK_ZERO(vtsi_mat->zero_19);
|
|
433 CHECK_ZERO(vtsi_mat->zero_20);
|
|
434 CHECK_ZERO(vtsi_mat->zero_21);
|
|
435 CHECK_VALUE(vtsi_mat->vtsi_last_sector*2 <= vtsi_mat->vts_last_sector);
|
|
436 CHECK_VALUE(vtsi_mat->vtsi_last_byte/DVD_BLOCK_LEN <= vtsi_mat->vtsi_last_sector);
|
|
437 CHECK_VALUE(vtsi_mat->vtsm_vobs == 0 ||
|
|
438 (vtsi_mat->vtsm_vobs > vtsi_mat->vtsi_last_sector &&
|
|
439 vtsi_mat->vtsm_vobs < vtsi_mat->vts_last_sector));
|
|
440 CHECK_VALUE(vtsi_mat->vtstt_vobs == 0 ||
|
|
441 (vtsi_mat->vtstt_vobs > vtsi_mat->vtsi_last_sector &&
|
|
442 vtsi_mat->vtstt_vobs < vtsi_mat->vts_last_sector));
|
|
443 CHECK_VALUE(vtsi_mat->vts_ptt_srpt <= vtsi_mat->vtsi_last_sector);
|
|
444 CHECK_VALUE(vtsi_mat->vts_pgcit <= vtsi_mat->vtsi_last_sector);
|
|
445 CHECK_VALUE(vtsi_mat->vtsm_pgci_ut <= vtsi_mat->vtsi_last_sector);
|
|
446 CHECK_VALUE(vtsi_mat->vts_tmapt <= vtsi_mat->vtsi_last_sector);
|
|
447 CHECK_VALUE(vtsi_mat->vtsm_c_adt <= vtsi_mat->vtsi_last_sector);
|
|
448 CHECK_VALUE(vtsi_mat->vtsm_vobu_admap <= vtsi_mat->vtsi_last_sector);
|
|
449 CHECK_VALUE(vtsi_mat->vts_c_adt <= vtsi_mat->vtsi_last_sector);
|
|
450 CHECK_VALUE(vtsi_mat->vts_vobu_admap <= vtsi_mat->vtsi_last_sector);
|
|
451
|
|
452 CHECK_VALUE(vtsi_mat->nr_of_vtsm_audio_streams <= 1);
|
|
453 CHECK_VALUE(vtsi_mat->nr_of_vtsm_subp_streams <= 1);
|
|
454
|
|
455 CHECK_VALUE(vtsi_mat->nr_of_vts_audio_streams <= 8);
|
|
456 for(i = vtsi_mat->nr_of_vts_audio_streams; i < 8; i++)
|
|
457 CHECK_ZERO(vtsi_mat->vts_audio_attr[i]);
|
|
458
|
|
459 CHECK_VALUE(vtsi_mat->nr_of_vts_subp_streams <= 32);
|
|
460 for(i = vtsi_mat->nr_of_vts_subp_streams; i < 32; i++)
|
|
461 CHECK_ZERO(vtsi_mat->vts_subp_attr[i]);
|
|
462
|
|
463 for(i = 0; i < 8; i++) {
|
|
464 CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero1);
|
|
465 CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero2);
|
|
466 CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero3);
|
|
467 CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero4);
|
|
468 CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero5);
|
|
469 CHECK_ZERO(vtsi_mat->vts_mu_audio_attr[i].zero6);
|
|
470 }
|
|
471
|
|
472 return 1;
|
|
473 }
|
|
474
|
|
475
|
|
476 static int ifoRead_PGC_COMMAND_TBL(ifo_handle_t *ifofile,
|
|
477 pgc_command_tbl_t *cmd_tbl,
|
|
478 unsigned int offset) {
|
|
479
|
|
480 memset(cmd_tbl, 0, sizeof(pgc_command_tbl_t));
|
|
481
|
|
482 if(!DVDFileSeek_(ifofile->file, offset))
|
|
483 return 0;
|
|
484
|
|
485 if(!(DVDReadBytes(ifofile->file, cmd_tbl, PGC_COMMAND_TBL_SIZE)))
|
|
486 return 0;
|
|
487
|
|
488 B2N_16(cmd_tbl->nr_of_pre);
|
|
489 B2N_16(cmd_tbl->nr_of_post);
|
|
490 B2N_16(cmd_tbl->nr_of_cell);
|
|
491
|
|
492 CHECK_VALUE(cmd_tbl->nr_of_pre + cmd_tbl->nr_of_post + cmd_tbl->nr_of_cell<= 255);
|
|
493
|
|
494 if(cmd_tbl->nr_of_pre != 0) {
|
|
495 unsigned int pre_cmds_size = cmd_tbl->nr_of_pre * COMMAND_DATA_SIZE;
|
|
496 cmd_tbl->pre_cmds = (vm_cmd_t *)malloc(pre_cmds_size);
|
|
497 if(!cmd_tbl->pre_cmds)
|
|
498 return 0;
|
|
499
|
|
500 if(!(DVDReadBytes(ifofile->file, cmd_tbl->pre_cmds, pre_cmds_size))) {
|
|
501 free(cmd_tbl->pre_cmds);
|
|
502 return 0;
|
|
503 }
|
|
504 }
|
|
505
|
|
506 if(cmd_tbl->nr_of_post != 0) {
|
|
507 unsigned int post_cmds_size = cmd_tbl->nr_of_post * COMMAND_DATA_SIZE;
|
|
508 cmd_tbl->post_cmds = (vm_cmd_t *)malloc(post_cmds_size);
|
|
509 if(!cmd_tbl->post_cmds) {
|
|
510 if(cmd_tbl->pre_cmds)
|
|
511 free(cmd_tbl->pre_cmds);
|
|
512 return 0;
|
|
513 }
|
|
514 if(!(DVDReadBytes(ifofile->file, cmd_tbl->post_cmds, post_cmds_size))) {
|
|
515 if(cmd_tbl->pre_cmds)
|
|
516 free(cmd_tbl->pre_cmds);
|
|
517 free(cmd_tbl->post_cmds);
|
|
518 return 0;
|
|
519 }
|
|
520 }
|
|
521
|
|
522 if(cmd_tbl->nr_of_cell != 0) {
|
|
523 unsigned int cell_cmds_size = cmd_tbl->nr_of_cell * COMMAND_DATA_SIZE;
|
|
524 cmd_tbl->cell_cmds = (vm_cmd_t *)malloc(cell_cmds_size);
|
|
525 if(!cmd_tbl->cell_cmds) {
|
|
526 if(cmd_tbl->pre_cmds)
|
|
527 free(cmd_tbl->pre_cmds);
|
|
528 if(cmd_tbl->post_cmds)
|
|
529 free(cmd_tbl->post_cmds);
|
|
530 return 0;
|
|
531 }
|
|
532 if(!(DVDReadBytes(ifofile->file, cmd_tbl->cell_cmds, cell_cmds_size))) {
|
|
533 if(cmd_tbl->pre_cmds)
|
|
534 free(cmd_tbl->pre_cmds);
|
|
535 if(cmd_tbl->post_cmds)
|
|
536 free(cmd_tbl->post_cmds);
|
|
537 free(cmd_tbl->cell_cmds);
|
|
538 return 0;
|
|
539 }
|
|
540 }
|
|
541
|
|
542 /*
|
|
543 * Make a run over all the commands and see that we can interpret them all?
|
|
544 */
|
|
545 return 1;
|
|
546 }
|
|
547
|
|
548
|
|
549 static void ifoFree_PGC_COMMAND_TBL(pgc_command_tbl_t *cmd_tbl) {
|
|
550 if(cmd_tbl) {
|
|
551 if(cmd_tbl->nr_of_pre && cmd_tbl->pre_cmds)
|
|
552 free(cmd_tbl->pre_cmds);
|
|
553 if(cmd_tbl->nr_of_post && cmd_tbl->post_cmds)
|
|
554 free(cmd_tbl->post_cmds);
|
|
555 if(cmd_tbl->nr_of_cell && cmd_tbl->cell_cmds)
|
|
556 free(cmd_tbl->cell_cmds);
|
|
557 free(cmd_tbl);
|
|
558 }
|
|
559 }
|
|
560
|
|
561 static int ifoRead_PGC_PROGRAM_MAP(ifo_handle_t *ifofile,
|
|
562 pgc_program_map_t *program_map,
|
|
563 unsigned int nr, unsigned int offset) {
|
|
564 unsigned int size = nr * sizeof(pgc_program_map_t);
|
|
565
|
|
566 if(!DVDFileSeek_(ifofile->file, offset))
|
|
567 return 0;
|
|
568
|
|
569 if(!(DVDReadBytes(ifofile->file, program_map, size)))
|
|
570 return 0;
|
|
571
|
|
572 return 1;
|
|
573 }
|
|
574
|
|
575 static int ifoRead_CELL_PLAYBACK_TBL(ifo_handle_t *ifofile,
|
|
576 cell_playback_t *cell_playback,
|
|
577 unsigned int nr, unsigned int offset) {
|
|
578 unsigned int i;
|
|
579 unsigned int size = nr * sizeof(cell_playback_t);
|
|
580
|
|
581 if(!DVDFileSeek_(ifofile->file, offset))
|
|
582 return 0;
|
|
583
|
|
584 if(!(DVDReadBytes(ifofile->file, cell_playback, size)))
|
|
585 return 0;
|
|
586
|
|
587 for(i = 0; i < nr; i++) {
|
|
588 B2N_32(cell_playback[i].first_sector);
|
|
589 B2N_32(cell_playback[i].first_ilvu_end_sector);
|
|
590 B2N_32(cell_playback[i].last_vobu_start_sector);
|
|
591 B2N_32(cell_playback[i].last_sector);
|
|
592
|
|
593 /* Changed < to <= because this was false in the movie 'Pi'. */
|
|
594 CHECK_VALUE(cell_playback[i].last_vobu_start_sector <=
|
|
595 cell_playback[i].last_sector);
|
|
596 CHECK_VALUE(cell_playback[i].first_sector <=
|
|
597 cell_playback[i].last_vobu_start_sector);
|
|
598 }
|
|
599
|
|
600 return 1;
|
|
601 }
|
|
602
|
|
603
|
|
604 static int ifoRead_CELL_POSITION_TBL(ifo_handle_t *ifofile,
|
|
605 cell_position_t *cell_position,
|
|
606 unsigned int nr, unsigned int offset) {
|
|
607 unsigned int i;
|
|
608 unsigned int size = nr * sizeof(cell_position_t);
|
|
609
|
|
610 if(!DVDFileSeek_(ifofile->file, offset))
|
|
611 return 0;
|
|
612
|
|
613 if(!(DVDReadBytes(ifofile->file, cell_position, size)))
|
|
614 return 0;
|
|
615
|
|
616 for(i = 0; i < nr; i++) {
|
|
617 B2N_16(cell_position[i].vob_id_nr);
|
|
618 CHECK_ZERO(cell_position[i].zero_1);
|
|
619 }
|
|
620
|
|
621 return 1;
|
|
622 }
|
|
623
|
|
624 static int ifoRead_PGC(ifo_handle_t *ifofile, pgc_t *pgc, unsigned int offset) {
|
|
625 unsigned int i;
|
|
626
|
|
627 if(!DVDFileSeek_(ifofile->file, offset))
|
|
628 return 0;
|
|
629
|
|
630 if(!(DVDReadBytes(ifofile->file, pgc, PGC_SIZE)))
|
|
631 return 0;
|
|
632
|
|
633 B2N_16(pgc->next_pgc_nr);
|
|
634 B2N_16(pgc->prev_pgc_nr);
|
|
635 B2N_16(pgc->goup_pgc_nr);
|
|
636 B2N_16(pgc->command_tbl_offset);
|
|
637 B2N_16(pgc->program_map_offset);
|
|
638 B2N_16(pgc->cell_playback_offset);
|
|
639 B2N_16(pgc->cell_position_offset);
|
|
640
|
|
641 for(i = 0; i < 8; i++)
|
|
642 B2N_16(pgc->audio_control[i]);
|
|
643 for(i = 0; i < 32; i++)
|
|
644 B2N_32(pgc->subp_control[i]);
|
|
645 for(i = 0; i < 16; i++)
|
|
646 B2N_32(pgc->palette[i]);
|
|
647
|
|
648 CHECK_ZERO(pgc->zero_1);
|
|
649 CHECK_VALUE(pgc->nr_of_programs <= pgc->nr_of_cells);
|
|
650
|
|
651 /* verify time (look at print_time) */
|
|
652 for(i = 0; i < 8; i++)
|
|
653 if(!pgc->audio_control[i] & 0x8000) /* The 'is present' bit */
|
|
654 CHECK_ZERO(pgc->audio_control[i]);
|
|
655 for(i = 0; i < 32; i++)
|
|
656 if(!pgc->subp_control[i] & 0x80000000) /* The 'is present' bit */
|
|
657 CHECK_ZERO(pgc->subp_control[i]);
|
|
658
|
|
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);
|
183
|
662 CHECK_ZERO(pgc->pg_playback_mode); /* ?? */
|
168
|
663 CHECK_VALUE(pgc->program_map_offset == 0);
|
|
664 CHECK_VALUE(pgc->cell_playback_offset == 0);
|
|
665 CHECK_VALUE(pgc->cell_position_offset == 0);
|
|
666 } else {
|
|
667 CHECK_VALUE(pgc->program_map_offset != 0);
|
|
668 CHECK_VALUE(pgc->cell_playback_offset != 0);
|
|
669 CHECK_VALUE(pgc->cell_position_offset != 0);
|
|
670 }
|
|
671
|
|
672 if(pgc->command_tbl_offset != 0) {
|
|
673 pgc->command_tbl = malloc(sizeof(pgc_command_tbl_t));
|
|
674 if(!pgc->command_tbl)
|
|
675 return 0;
|
|
676
|
|
677 if(!ifoRead_PGC_COMMAND_TBL(ifofile, pgc->command_tbl,
|
|
678 offset + pgc->command_tbl_offset)) {
|
|
679 free(pgc->command_tbl);
|
|
680 return 0;
|
|
681 }
|
|
682 } else {
|
|
683 pgc->command_tbl = NULL;
|
|
684 }
|
|
685
|
|
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);
|
|
690 return 0;
|
|
691 }
|
|
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);
|
|
696 return 0;
|
|
697 }
|
|
698 } else {
|
|
699 pgc->program_map = NULL;
|
|
700 }
|
|
701
|
|
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);
|
|
706 if(pgc->program_map)
|
|
707 free(pgc->program_map);
|
|
708 return 0;
|
|
709 }
|
|
710 if(!ifoRead_CELL_PLAYBACK_TBL(ifofile, pgc->cell_playback,
|
|
711 pgc->nr_of_cells,
|
|
712 offset + pgc->cell_playback_offset)) {
|
|
713 ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
|
|
714 if(pgc->program_map)
|
|
715 free(pgc->program_map);
|
|
716 free(pgc->cell_playback);
|
|
717 return 0;
|
|
718 }
|
|
719 } else {
|
|
720 pgc->cell_playback = NULL;
|
|
721 }
|
|
722
|
|
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) {
|
|
726 ifoFree_PGC(pgc);
|
|
727 return 0;
|
|
728 }
|
|
729 if(!ifoRead_CELL_POSITION_TBL(ifofile, pgc->cell_position,
|
|
730 pgc->nr_of_cells,
|
|
731 offset + pgc->cell_position_offset)) {
|
|
732 ifoFree_PGC(pgc);
|
|
733 return 0;
|
|
734 }
|
|
735 } else {
|
|
736 pgc->cell_position = NULL;
|
|
737 }
|
|
738
|
|
739 return 1;
|
|
740 }
|
|
741
|
|
742 int ifoRead_FP_PGC(ifo_handle_t *ifofile) {
|
|
743
|
|
744 if(!ifofile)
|
|
745 return 0;
|
|
746
|
|
747 if(!ifofile->vmgi_mat)
|
|
748 return 0;
|
|
749
|
|
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)
|
|
753 return 1;
|
|
754
|
|
755 ifofile->first_play_pgc = (pgc_t *)malloc(sizeof(pgc_t));
|
|
756 if(!ifofile->first_play_pgc)
|
|
757 return 0;
|
|
758
|
|
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;
|
|
763 return 0;
|
|
764 }
|
|
765
|
|
766 return 1;
|
|
767 }
|
|
768
|
|
769 static void ifoFree_PGC(pgc_t *pgc) {
|
|
770 if(pgc) {
|
|
771 ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
|
|
772 if(pgc->program_map)
|
|
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);
|
|
778 }
|
|
779 }
|
|
780
|
|
781 void ifoFree_FP_PGC(ifo_handle_t *ifofile) {
|
|
782 if(!ifofile)
|
|
783 return;
|
|
784
|
|
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;
|
|
789 }
|
|
790 }
|
|
791
|
|
792
|
|
793 int ifoRead_TT_SRPT(ifo_handle_t *ifofile) {
|
|
794 tt_srpt_t *tt_srpt;
|
|
795 int i, info_length;
|
|
796
|
|
797 if(!ifofile)
|
|
798 return 0;
|
|
799
|
|
800 if(!ifofile->vmgi_mat)
|
|
801 return 0;
|
|
802
|
|
803 if(ifofile->vmgi_mat->tt_srpt == 0) /* mandatory */
|
|
804 return 0;
|
|
805
|
|
806 if(!DVDFileSeek_(ifofile->file, ifofile->vmgi_mat->tt_srpt * DVD_BLOCK_LEN))
|
|
807 return 0;
|
|
808
|
|
809 tt_srpt = (tt_srpt_t *)malloc(sizeof(tt_srpt_t));
|
|
810 if(!tt_srpt)
|
|
811 return 0;
|
|
812
|
|
813 ifofile->tt_srpt = tt_srpt;
|
|
814
|
|
815 if(!(DVDReadBytes(ifofile->file, tt_srpt, TT_SRPT_SIZE))) {
|
|
816 fprintf(stderr, "libdvdread: Unable to read read TT_SRPT.\n");
|
|
817 free(tt_srpt);
|
|
818 return 0;
|
|
819 }
|
|
820
|
|
821 B2N_16(tt_srpt->nr_of_srpts);
|
|
822 B2N_32(tt_srpt->last_byte);
|
|
823
|
|
824 info_length = tt_srpt->last_byte + 1 - TT_SRPT_SIZE;
|
|
825
|
|
826 tt_srpt->title = (title_info_t *)malloc(info_length);
|
|
827 if(!tt_srpt->title) {
|
|
828 free(tt_srpt);
|
|
829 ifofile->tt_srpt = 0;
|
|
830 return 0;
|
|
831 }
|
|
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);
|
|
835 return 0;
|
|
836 }
|
|
837
|
|
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);
|
|
842 }
|
|
843
|
|
844
|
|
845 CHECK_ZERO(tt_srpt->zero_1);
|
|
846 CHECK_VALUE(tt_srpt->nr_of_srpts != 0);
|
183
|
847 CHECK_VALUE(tt_srpt->nr_of_srpts < 100); /* ?? */
|
168
|
848 CHECK_VALUE((int)tt_srpt->nr_of_srpts * sizeof(title_info_t) <= info_length);
|
|
849
|
|
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);
|
183
|
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); /* ?? */
|
168
|
857 CHECK_VALUE(tt_srpt->title[i].title_set_nr != 0);
|
183
|
858 CHECK_VALUE(tt_srpt->title[i].title_set_nr < 100); /* ?? */
|
168
|
859 CHECK_VALUE(tt_srpt->title[i].vts_ttn != 0);
|
183
|
860 CHECK_VALUE(tt_srpt->title[i].vts_ttn < 100); /* ?? */
|
|
861 /* CHECK_VALUE(tt_srpt->title[i].title_set_sector != 0); */
|
168
|
862 }
|
|
863
|
183
|
864 /* Make this a function */
|
168
|
865 #if 0
|
|
866 if(memcmp((uint8_t *)tt_srpt->title +
|
|
867 tt_srpt->nr_of_srpts * sizeof(title_info_t),
|
|
868 my_friendly_zeros,
|
|
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));
|
|
874 }
|
|
875 #endif
|
|
876
|
|
877 return 1;
|
|
878 }
|
|
879
|
|
880
|
|
881 void ifoFree_TT_SRPT(ifo_handle_t *ifofile) {
|
|
882 if(!ifofile)
|
|
883 return;
|
|
884
|
|
885 if(ifofile->tt_srpt) {
|
|
886 free(ifofile->tt_srpt->title);
|
|
887 free(ifofile->tt_srpt);
|
|
888 ifofile->tt_srpt = 0;
|
|
889 }
|
|
890 }
|
|
891
|
|
892
|
|
893 int ifoRead_VTS_PTT_SRPT(ifo_handle_t *ifofile) {
|
|
894 vts_ptt_srpt_t *vts_ptt_srpt;
|
|
895 int info_length, i, j;
|
|
896 uint32_t *data;
|
|
897
|
|
898 if(!ifofile)
|
|
899 return 0;
|
|
900
|
|
901 if(!ifofile->vtsi_mat)
|
|
902 return 0;
|
|
903
|
|
904 if(ifofile->vtsi_mat->vts_ptt_srpt == 0) /* mandatory */
|
|
905 return 0;
|
|
906
|
|
907 if(!DVDFileSeek_(ifofile->file,
|
|
908 ifofile->vtsi_mat->vts_ptt_srpt * DVD_BLOCK_LEN))
|
|
909 return 0;
|
|
910
|
|
911 vts_ptt_srpt = (vts_ptt_srpt_t *)malloc(sizeof(vts_ptt_srpt_t));
|
|
912 if(!vts_ptt_srpt)
|
|
913 return 0;
|
|
914
|
|
915 ifofile->vts_ptt_srpt = vts_ptt_srpt;
|
|
916
|
|
917 if(!(DVDReadBytes(ifofile->file, vts_ptt_srpt, VTS_PTT_SRPT_SIZE))) {
|
|
918 fprintf(stderr, "libdvdread: Unable to read PTT search table.\n");
|
|
919 free(vts_ptt_srpt);
|
|
920 return 0;
|
|
921 }
|
|
922
|
|
923 B2N_16(vts_ptt_srpt->nr_of_srpts);
|
|
924 B2N_32(vts_ptt_srpt->last_byte);
|
|
925
|
|
926 CHECK_ZERO(vts_ptt_srpt->zero_1);
|
|
927 CHECK_VALUE(vts_ptt_srpt->nr_of_srpts != 0);
|
183
|
928 CHECK_VALUE(vts_ptt_srpt->nr_of_srpts < 100); /* ?? */
|
168
|
929
|
|
930 info_length = vts_ptt_srpt->last_byte + 1 - VTS_PTT_SRPT_SIZE;
|
|
931
|
|
932 data = (uint32_t *)malloc(info_length);
|
|
933 if(!data) {
|
|
934 free(vts_ptt_srpt);
|
|
935 ifofile->vts_ptt_srpt = 0;
|
|
936 return 0;
|
|
937 }
|
|
938 if(!(DVDReadBytes(ifofile->file, data, info_length))) {
|
|
939 fprintf(stderr, "libdvdread: Unable to read PTT search table.\n");
|
|
940 free(vts_ptt_srpt);
|
|
941 free(data);
|
|
942 ifofile->vts_ptt_srpt = 0;
|
|
943 return 0;
|
|
944 }
|
|
945
|
|
946 for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) {
|
|
947 B2N_32(data[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);
|
|
953 }
|
|
954
|
|
955 vts_ptt_srpt->ttu_offset = data;
|
|
956
|
|
957 vts_ptt_srpt->title = malloc(vts_ptt_srpt->nr_of_srpts * sizeof(ttu_t));
|
|
958 if(!vts_ptt_srpt->title) {
|
|
959 free(vts_ptt_srpt);
|
|
960 free(data);
|
|
961 ifofile->vts_ptt_srpt = 0;
|
|
962 return 0;
|
|
963 }
|
|
964 for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) {
|
|
965 int n;
|
|
966 if(i < vts_ptt_srpt->nr_of_srpts - 1)
|
|
967 n = (data[i+1] - data[i]);
|
|
968 else
|
|
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. */
|
|
973 if(n < 0) n = 0;
|
|
974 CHECK_VALUE(n % 4 == 0);
|
|
975
|
|
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);
|
|
981 free(vts_ptt_srpt);
|
|
982 free(data);
|
|
983 ifofile->vts_ptt_srpt = 0;
|
|
984 return 0;
|
|
985 }
|
|
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);
|
|
993 }
|
|
994 }
|
|
995
|
|
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);
|
|
1000 }
|
|
1001 }
|
|
1002
|
|
1003 for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) {
|
183
|
1004 CHECK_VALUE(vts_ptt_srpt->title[i].nr_of_ptts < 1000); /* ?? */
|
168
|
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 );
|
183
|
1007 CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgcn < 1000); /* ?? */
|
168
|
1008 CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgn != 0);
|
183
|
1009 CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgn < 100); /* ?? */
|
168
|
1010 }
|
|
1011 }
|
|
1012
|
|
1013 return 1;
|
|
1014 }
|
|
1015
|
|
1016
|
|
1017 void ifoFree_VTS_PTT_SRPT(ifo_handle_t *ifofile) {
|
|
1018 if(!ifofile)
|
|
1019 return;
|
|
1020
|
|
1021 if(ifofile->vts_ptt_srpt) {
|
|
1022 int i;
|
|
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;
|
|
1029 }
|
|
1030 }
|
|
1031
|
|
1032
|
|
1033 int ifoRead_PTL_MAIT(ifo_handle_t *ifofile) {
|
|
1034 ptl_mait_t *ptl_mait;
|
|
1035 int info_length;
|
|
1036 unsigned int i, j;
|
|
1037
|
|
1038 if(!ifofile)
|
|
1039 return 0;
|
|
1040
|
|
1041 if(!ifofile->vmgi_mat)
|
|
1042 return 0;
|
|
1043
|
|
1044 if(ifofile->vmgi_mat->ptl_mait == 0)
|
|
1045 return 1;
|
|
1046
|
|
1047 if(!DVDFileSeek_(ifofile->file, ifofile->vmgi_mat->ptl_mait * DVD_BLOCK_LEN))
|
|
1048 return 0;
|
|
1049
|
|
1050 ptl_mait = (ptl_mait_t *)malloc(sizeof(ptl_mait_t));
|
|
1051 if(!ptl_mait)
|
|
1052 return 0;
|
|
1053
|
|
1054 ifofile->ptl_mait = ptl_mait;
|
|
1055
|
|
1056 if(!(DVDReadBytes(ifofile->file, ptl_mait, PTL_MAIT_SIZE))) {
|
|
1057 free(ptl_mait);
|
|
1058 ifofile->ptl_mait = 0;
|
|
1059 return 0;
|
|
1060 }
|
|
1061
|
|
1062 B2N_16(ptl_mait->nr_of_countries);
|
|
1063 B2N_16(ptl_mait->nr_of_vtss);
|
|
1064 B2N_32(ptl_mait->last_byte);
|
|
1065
|
|
1066 CHECK_VALUE(ptl_mait->nr_of_countries != 0);
|
183
|
1067 CHECK_VALUE(ptl_mait->nr_of_countries < 100); /* ?? */
|
168
|
1068 CHECK_VALUE(ptl_mait->nr_of_vtss != 0);
|
183
|
1069 CHECK_VALUE(ptl_mait->nr_of_vtss < 100); /* ?? */
|
168
|
1070 CHECK_VALUE(ptl_mait->nr_of_countries * PTL_MAIT_COUNTRY_SIZE
|
|
1071 <= ptl_mait->last_byte + 1 - PTL_MAIT_SIZE);
|
|
1072
|
|
1073 info_length = ptl_mait->nr_of_countries * sizeof(ptl_mait_country_t);
|
|
1074 ptl_mait->countries = (ptl_mait_country_t *)malloc(info_length);
|
|
1075 if(!ptl_mait->countries) {
|
|
1076 free(ptl_mait);
|
|
1077 ifofile->ptl_mait = 0;
|
|
1078 return 0;
|
|
1079 }
|
|
1080
|
|
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);
|
|
1085 free(ptl_mait);
|
|
1086 ifofile->ptl_mait = 0;
|
|
1087 return 0;
|
|
1088 }
|
|
1089 }
|
|
1090
|
|
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);
|
|
1094 }
|
|
1095
|
|
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);
|
|
1101 }
|
|
1102
|
|
1103 for(i = 0; i < ptl_mait->nr_of_countries; i++) {
|
|
1104 uint16_t *pf_temp;
|
|
1105
|
|
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);
|
|
1111 free(ptl_mait);
|
|
1112 return 0;
|
|
1113 }
|
|
1114 info_length = (ptl_mait->nr_of_vtss + 1) * sizeof(pf_level_t);
|
|
1115 pf_temp = (uint16_t *)malloc(info_length);
|
|
1116 if(!pf_temp) {
|
|
1117 for(j = 0; j < i ; j++) {
|
|
1118 free(ptl_mait->countries[j].pf_ptl_mai);
|
|
1119 }
|
|
1120 free(ptl_mait->countries);
|
|
1121 free(ptl_mait);
|
|
1122 return 0;
|
|
1123 }
|
|
1124 if(!(DVDReadBytes(ifofile->file, pf_temp, info_length))) {
|
|
1125 fprintf(stderr, "libdvdread: Unable to read PTL_MAIT table.\n");
|
|
1126 free(pf_temp);
|
|
1127 for(j = 0; j < i ; j++) {
|
|
1128 free(ptl_mait->countries[j].pf_ptl_mai);
|
|
1129 }
|
|
1130 free(ptl_mait->countries);
|
|
1131 free(ptl_mait);
|
|
1132 return 0;
|
|
1133 }
|
|
1134 for (j = 0; j < ((ptl_mait->nr_of_vtss + 1) * 8); j++) {
|
|
1135 B2N_16(pf_temp[j]);
|
|
1136 }
|
|
1137 ptl_mait->countries[i].pf_ptl_mai = (pf_level_t *)malloc(info_length);
|
|
1138 if(!ptl_mait->countries[i].pf_ptl_mai) {
|
|
1139 free(pf_temp);
|
|
1140 for(j = 0; j < i ; j++) {
|
|
1141 free(ptl_mait->countries[j].pf_ptl_mai);
|
|
1142 }
|
|
1143 free(ptl_mait->countries);
|
|
1144 free(ptl_mait);
|
|
1145 return 0;
|
|
1146 }
|
|
1147 { /* Transpose the array so we can use C indexing. */
|
|
1148 int level, vts;
|
|
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];
|
|
1153 }
|
|
1154 }
|
|
1155 free(pf_temp);
|
|
1156 }
|
|
1157 }
|
|
1158 return 1;
|
|
1159 }
|
|
1160
|
|
1161 void ifoFree_PTL_MAIT(ifo_handle_t *ifofile) {
|
|
1162 unsigned int i;
|
|
1163
|
|
1164 if(!ifofile)
|
|
1165 return;
|
|
1166
|
|
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);
|
|
1170 }
|
|
1171 free(ifofile->ptl_mait->countries);
|
|
1172 free(ifofile->ptl_mait);
|
|
1173 ifofile->ptl_mait = 0;
|
|
1174 }
|
|
1175 }
|
|
1176
|
|
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;
|
|
1181 int info_length;
|
|
1182 unsigned int i, j;
|
|
1183
|
|
1184 if(!ifofile)
|
|
1185 return 0;
|
|
1186
|
|
1187 if(!ifofile->vtsi_mat)
|
|
1188 return 0;
|
|
1189
|
|
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");
|
|
1193 return 1;
|
|
1194 }
|
|
1195
|
|
1196 offset = ifofile->vtsi_mat->vts_tmapt * DVD_BLOCK_LEN;
|
|
1197
|
|
1198 if(!DVDFileSeek_(ifofile->file, offset))
|
|
1199 return 0;
|
|
1200
|
|
1201 vts_tmapt = (vts_tmapt_t *)malloc(sizeof(vts_tmapt_t));
|
|
1202 if(!vts_tmapt)
|
|
1203 return 0;
|
|
1204
|
|
1205 ifofile->vts_tmapt = vts_tmapt;
|
|
1206
|
|
1207 if(!(DVDReadBytes(ifofile->file, vts_tmapt, VTS_TMAPT_SIZE))) {
|
|
1208 fprintf(stderr, "libdvdread: Unable to read VTS_TMAPT.\n");
|
|
1209 free(vts_tmapt);
|
|
1210 ifofile->vts_tmapt = NULL;
|
|
1211 return 0;
|
|
1212 }
|
|
1213
|
|
1214 B2N_16(vts_tmapt->nr_of_tmaps);
|
|
1215 B2N_32(vts_tmapt->last_byte);
|
|
1216
|
|
1217 CHECK_ZERO(vts_tmapt->zero_1);
|
|
1218
|
|
1219 info_length = vts_tmapt->nr_of_tmaps * 4;
|
|
1220
|
|
1221 vts_tmap_srp = (uint32_t *)malloc(info_length);
|
|
1222 if(!vts_tmap_srp) {
|
|
1223 free(vts_tmapt);
|
|
1224 ifofile->vts_tmapt = NULL;
|
|
1225 return 0;
|
|
1226 }
|
|
1227
|
|
1228 vts_tmapt->tmap_offset = vts_tmap_srp;
|
|
1229
|
|
1230 if(!(DVDReadBytes(ifofile->file, vts_tmap_srp, info_length))) {
|
|
1231 fprintf(stderr, "libdvdread: Unable to read VTS_TMAPT.\n");
|
|
1232 free(vts_tmap_srp);
|
|
1233 free(vts_tmapt);
|
|
1234 ifofile->vts_tmapt = NULL;
|
|
1235 return 0;
|
|
1236 }
|
|
1237
|
|
1238 for (i = 0; i < vts_tmapt->nr_of_tmaps; i++) {
|
|
1239 B2N_32(vts_tmap_srp[i]);
|
|
1240 }
|
|
1241
|
|
1242
|
|
1243 info_length = vts_tmapt->nr_of_tmaps * sizeof(vts_tmap_t);
|
|
1244
|
|
1245 vts_tmapt->tmap = (vts_tmap_t *)malloc(info_length);
|
|
1246 if(!vts_tmapt->tmap) {
|
|
1247 free(vts_tmap_srp);
|
|
1248 free(vts_tmapt);
|
|
1249 ifofile->vts_tmapt = NULL;
|
|
1250 return 0;
|
|
1251 }
|
|
1252
|
|
1253 memset(vts_tmapt->tmap, 0, info_length); /* So ifoFree_VTS_TMAPT works. */
|
|
1254
|
|
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);
|
|
1258 return 0;
|
|
1259 }
|
|
1260
|
|
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);
|
|
1264 return 0;
|
|
1265 }
|
|
1266
|
|
1267 B2N_16(vts_tmapt->tmap[i].nr_of_entries);
|
|
1268 CHECK_ZERO(vts_tmapt->tmap[i].zero_1);
|
|
1269
|
|
1270 if(vts_tmapt->tmap[i].nr_of_entries == 0) { /* Early out if zero entries */
|
|
1271 vts_tmapt->tmap[i].map_ent = NULL;
|
|
1272 continue;
|
|
1273 }
|
|
1274
|
|
1275 info_length = vts_tmapt->tmap[i].nr_of_entries * sizeof(map_ent_t);
|
|
1276
|
|
1277 vts_tmapt->tmap[i].map_ent = (map_ent_t *)malloc(info_length);
|
|
1278 if(!vts_tmapt->tmap[i].map_ent) {
|
|
1279 ifoFree_VTS_TMAPT(ifofile);
|
|
1280 return 0;
|
|
1281 }
|
|
1282
|
|
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);
|
|
1286 return 0;
|
|
1287 }
|
|
1288
|
|
1289 for(j = 0; j < vts_tmapt->tmap[i].nr_of_entries; j++)
|
|
1290 B2N_32(vts_tmapt->tmap[i].map_ent[j]);
|
|
1291 }
|
|
1292
|
|
1293 return 1;
|
|
1294 }
|
|
1295
|
|
1296 void ifoFree_VTS_TMAPT(ifo_handle_t *ifofile) {
|
|
1297 unsigned int i;
|
|
1298
|
|
1299 if(!ifofile)
|
|
1300 return;
|
|
1301
|
|
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;
|
|
1310 }
|
|
1311 }
|
|
1312
|
|
1313
|
|
1314 int ifoRead_TITLE_C_ADT(ifo_handle_t *ifofile) {
|
|
1315
|
|
1316 if(!ifofile)
|
|
1317 return 0;
|
|
1318
|
|
1319 if(!ifofile->vtsi_mat)
|
|
1320 return 0;
|
|
1321
|
|
1322 if(ifofile->vtsi_mat->vts_c_adt == 0) /* mandatory */
|
|
1323 return 0;
|
|
1324
|
|
1325 ifofile->vts_c_adt = (c_adt_t *)malloc(sizeof(c_adt_t));
|
|
1326 if(!ifofile->vts_c_adt)
|
|
1327 return 0;
|
|
1328
|
|
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;
|
|
1333 return 0;
|
|
1334 }
|
|
1335
|
|
1336 return 1;
|
|
1337 }
|
|
1338
|
|
1339 int ifoRead_C_ADT(ifo_handle_t *ifofile) {
|
|
1340 unsigned int sector;
|
|
1341
|
|
1342 if(!ifofile)
|
|
1343 return 0;
|
|
1344
|
|
1345 if(ifofile->vmgi_mat) {
|
|
1346 if(ifofile->vmgi_mat->vmgm_c_adt == 0)
|
|
1347 return 1;
|
|
1348 sector = ifofile->vmgi_mat->vmgm_c_adt;
|
|
1349 } else if(ifofile->vtsi_mat) {
|
|
1350 if(ifofile->vtsi_mat->vtsm_c_adt == 0)
|
|
1351 return 1;
|
|
1352 sector = ifofile->vtsi_mat->vtsm_c_adt;
|
|
1353 } else {
|
|
1354 return 0;
|
|
1355 }
|
|
1356
|
|
1357 ifofile->menu_c_adt = (c_adt_t *)malloc(sizeof(c_adt_t));
|
|
1358 if(!ifofile->menu_c_adt)
|
|
1359 return 0;
|
|
1360
|
|
1361 if(!ifoRead_C_ADT_internal(ifofile, ifofile->menu_c_adt, sector)) {
|
|
1362 free(ifofile->menu_c_adt);
|
|
1363 ifofile->menu_c_adt = 0;
|
|
1364 return 0;
|
|
1365 }
|
|
1366
|
|
1367 return 1;
|
|
1368 }
|
|
1369
|
|
1370 static int ifoRead_C_ADT_internal(ifo_handle_t *ifofile,
|
|
1371 c_adt_t *c_adt, unsigned int sector) {
|
|
1372 int i, info_length;
|
|
1373
|
|
1374 if(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN))
|
|
1375 return 0;
|
|
1376
|
|
1377 if(!(DVDReadBytes(ifofile->file, c_adt, C_ADT_SIZE)))
|
|
1378 return 0;
|
|
1379
|
|
1380 B2N_16(c_adt->nr_of_vobs);
|
|
1381 B2N_32(c_adt->last_byte);
|
|
1382
|
|
1383 info_length = c_adt->last_byte + 1 - C_ADT_SIZE;
|
|
1384
|
|
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);
|
|
1390
|
|
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);
|
|
1397 }
|
|
1398
|
|
1399 c_adt->cell_adr_table = (cell_adr_t *)malloc(info_length);
|
|
1400 if(!c_adt->cell_adr_table)
|
|
1401 return 0;
|
|
1402
|
|
1403 if(info_length &&
|
|
1404 !(DVDReadBytes(ifofile->file, c_adt->cell_adr_table, info_length))) {
|
|
1405 free(c_adt->cell_adr_table);
|
|
1406 return 0;
|
|
1407 }
|
|
1408
|
|
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);
|
|
1413
|
|
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);
|
|
1420 }
|
|
1421
|
|
1422 return 1;
|
|
1423 }
|
|
1424
|
|
1425
|
|
1426 static void ifoFree_C_ADT_internal(c_adt_t *c_adt) {
|
|
1427 if(c_adt) {
|
|
1428 free(c_adt->cell_adr_table);
|
|
1429 free(c_adt);
|
|
1430 }
|
|
1431 }
|
|
1432
|
|
1433 void ifoFree_C_ADT(ifo_handle_t *ifofile) {
|
|
1434 if(!ifofile)
|
|
1435 return;
|
|
1436
|
|
1437 ifoFree_C_ADT_internal(ifofile->menu_c_adt);
|
|
1438 ifofile->menu_c_adt = 0;
|
|
1439 }
|
|
1440
|
|
1441 void ifoFree_TITLE_C_ADT(ifo_handle_t *ifofile) {
|
|
1442 if(!ifofile)
|
|
1443 return;
|
|
1444
|
|
1445 ifoFree_C_ADT_internal(ifofile->vts_c_adt);
|
|
1446 ifofile->vts_c_adt = 0;
|
|
1447 }
|
|
1448
|
|
1449 int ifoRead_TITLE_VOBU_ADMAP(ifo_handle_t *ifofile) {
|
|
1450 if(!ifofile)
|
|
1451 return 0;
|
|
1452
|
|
1453 if(!ifofile->vtsi_mat)
|
|
1454 return 0;
|
|
1455
|
|
1456 if(ifofile->vtsi_mat->vts_vobu_admap == 0) /* mandatory */
|
|
1457 return 0;
|
|
1458
|
|
1459 ifofile->vts_vobu_admap = (vobu_admap_t *)malloc(sizeof(vobu_admap_t));
|
|
1460 if(!ifofile->vts_vobu_admap)
|
|
1461 return 0;
|
|
1462
|
|
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;
|
|
1467 return 0;
|
|
1468 }
|
|
1469
|
|
1470 return 1;
|
|
1471 }
|
|
1472
|
|
1473 int ifoRead_VOBU_ADMAP(ifo_handle_t *ifofile) {
|
|
1474 unsigned int sector;
|
|
1475
|
|
1476 if(!ifofile)
|
|
1477 return 0;
|
|
1478
|
|
1479 if(ifofile->vmgi_mat) {
|
|
1480 if(ifofile->vmgi_mat->vmgm_vobu_admap == 0)
|
|
1481 return 1;
|
|
1482 sector = ifofile->vmgi_mat->vmgm_vobu_admap;
|
|
1483 } else if(ifofile->vtsi_mat) {
|
|
1484 if(ifofile->vtsi_mat->vtsm_vobu_admap == 0)
|
|
1485 return 1;
|
|
1486 sector = ifofile->vtsi_mat->vtsm_vobu_admap;
|
|
1487 } else {
|
|
1488 return 0;
|
|
1489 }
|
|
1490
|
|
1491 ifofile->menu_vobu_admap = (vobu_admap_t *)malloc(sizeof(vobu_admap_t));
|
|
1492 if(!ifofile->menu_vobu_admap)
|
|
1493 return 0;
|
|
1494
|
|
1495 if(!ifoRead_VOBU_ADMAP_internal(ifofile, ifofile->menu_vobu_admap, sector)) {
|
|
1496 free(ifofile->menu_vobu_admap);
|
|
1497 ifofile->menu_vobu_admap = 0;
|
|
1498 return 0;
|
|
1499 }
|
|
1500
|
|
1501 return 1;
|
|
1502 }
|
|
1503
|
|
1504 static int ifoRead_VOBU_ADMAP_internal(ifo_handle_t *ifofile,
|
|
1505 vobu_admap_t *vobu_admap,
|
|
1506 unsigned int sector) {
|
|
1507 unsigned int i;
|
|
1508 int info_length;
|
|
1509
|
|
1510 if(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN))
|
|
1511 return 0;
|
|
1512
|
|
1513 if(!(DVDReadBytes(ifofile->file, vobu_admap, VOBU_ADMAP_SIZE)))
|
|
1514 return 0;
|
|
1515
|
|
1516 B2N_32(vobu_admap->last_byte);
|
|
1517
|
|
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);
|
|
1523
|
|
1524 vobu_admap->vobu_start_sectors = (uint32_t *)malloc(info_length);
|
|
1525 if(!vobu_admap->vobu_start_sectors) {
|
|
1526 return 0;
|
|
1527 }
|
|
1528 if(info_length &&
|
|
1529 !(DVDReadBytes(ifofile->file,
|
|
1530 vobu_admap->vobu_start_sectors, info_length))) {
|
|
1531 free(vobu_admap->vobu_start_sectors);
|
|
1532 return 0;
|
|
1533 }
|
|
1534
|
|
1535 for(i = 0; i < info_length/sizeof(uint32_t); i++)
|
|
1536 B2N_32(vobu_admap->vobu_start_sectors[i]);
|
|
1537
|
|
1538 return 1;
|
|
1539 }
|
|
1540
|
|
1541
|
|
1542 static void ifoFree_VOBU_ADMAP_internal(vobu_admap_t *vobu_admap) {
|
|
1543 if(vobu_admap) {
|
|
1544 free(vobu_admap->vobu_start_sectors);
|
|
1545 free(vobu_admap);
|
|
1546 }
|
|
1547 }
|
|
1548
|
|
1549 void ifoFree_VOBU_ADMAP(ifo_handle_t *ifofile) {
|
|
1550 if(!ifofile)
|
|
1551 return;
|
|
1552
|
|
1553 ifoFree_VOBU_ADMAP_internal(ifofile->menu_vobu_admap);
|
|
1554 ifofile->menu_vobu_admap = 0;
|
|
1555 }
|
|
1556
|
|
1557 void ifoFree_TITLE_VOBU_ADMAP(ifo_handle_t *ifofile) {
|
|
1558 if(!ifofile)
|
|
1559 return;
|
|
1560
|
|
1561 ifoFree_VOBU_ADMAP_internal(ifofile->vts_vobu_admap);
|
|
1562 ifofile->vts_vobu_admap = 0;
|
|
1563 }
|
|
1564
|
|
1565 int ifoRead_PGCIT(ifo_handle_t *ifofile) {
|
|
1566
|
|
1567 if(!ifofile)
|
|
1568 return 0;
|
|
1569
|
|
1570 if(!ifofile->vtsi_mat)
|
|
1571 return 0;
|
|
1572
|
|
1573 if(ifofile->vtsi_mat->vts_pgcit == 0) /* mandatory */
|
|
1574 return 0;
|
|
1575
|
|
1576 ifofile->vts_pgcit = (pgcit_t *)malloc(sizeof(pgcit_t));
|
|
1577 if(!ifofile->vts_pgcit)
|
|
1578 return 0;
|
|
1579
|
|
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;
|
|
1584 return 0;
|
|
1585 }
|
|
1586
|
|
1587 return 1;
|
|
1588 }
|
|
1589
|
|
1590 static int ifoRead_PGCIT_internal(ifo_handle_t *ifofile, pgcit_t *pgcit,
|
|
1591 unsigned int offset) {
|
|
1592 int i, info_length;
|
|
1593 uint8_t *data, *ptr;
|
|
1594
|
|
1595 if(!DVDFileSeek_(ifofile->file, offset))
|
|
1596 return 0;
|
|
1597
|
|
1598 if(!(DVDReadBytes(ifofile->file, pgcit, PGCIT_SIZE)))
|
|
1599 return 0;
|
|
1600
|
|
1601 B2N_16(pgcit->nr_of_pgci_srp);
|
|
1602 B2N_32(pgcit->last_byte);
|
|
1603
|
|
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. */
|
183
|
1608 CHECK_VALUE(pgcit->nr_of_pgci_srp < 10000); /* ?? seen max of 1338 */
|
168
|
1609
|
|
1610 info_length = pgcit->nr_of_pgci_srp * PGCI_SRP_SIZE;
|
|
1611 data = malloc(info_length);
|
|
1612 if(!data)
|
|
1613 return 0;
|
|
1614
|
|
1615 if(info_length && !(DVDReadBytes(ifofile->file, data, info_length))) {
|
|
1616 free(data);
|
|
1617 return 0;
|
|
1618 }
|
|
1619
|
|
1620 pgcit->pgci_srp = malloc(pgcit->nr_of_pgci_srp * sizeof(pgci_srp_t));
|
|
1621 if(!pgcit->pgci_srp) {
|
|
1622 free(data);
|
|
1623 return 0;
|
|
1624 }
|
|
1625 ptr = data;
|
|
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);
|
|
1632 }
|
|
1633 free(data);
|
|
1634
|
|
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);
|
|
1637
|
|
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) {
|
|
1641 int j;
|
|
1642 for(j = 0; j < i; j++) {
|
|
1643 ifoFree_PGC(pgcit->pgci_srp[j].pgc);
|
|
1644 free(pgcit->pgci_srp[j].pgc);
|
|
1645 }
|
|
1646 return 0;
|
|
1647 }
|
|
1648 if(!ifoRead_PGC(ifofile, pgcit->pgci_srp[i].pgc,
|
|
1649 offset + pgcit->pgci_srp[i].pgc_start_byte)) {
|
|
1650 int j;
|
|
1651 for(j = 0; j < i; j++) {
|
|
1652 ifoFree_PGC(pgcit->pgci_srp[j].pgc);
|
|
1653 free(pgcit->pgci_srp[j].pgc);
|
|
1654 }
|
|
1655 free(pgcit->pgci_srp);
|
|
1656 return 0;
|
|
1657 }
|
|
1658 }
|
|
1659
|
|
1660 return 1;
|
|
1661 }
|
|
1662
|
|
1663 static void ifoFree_PGCIT_internal(pgcit_t *pgcit) {
|
|
1664 if(pgcit) {
|
|
1665 int i;
|
|
1666 for(i = 0; i < pgcit->nr_of_pgci_srp; i++)
|
|
1667 ifoFree_PGC(pgcit->pgci_srp[i].pgc);
|
|
1668 free(pgcit->pgci_srp);
|
|
1669 }
|
|
1670 }
|
|
1671
|
|
1672 void ifoFree_PGCIT(ifo_handle_t *ifofile) {
|
|
1673 if(!ifofile)
|
|
1674 return;
|
|
1675
|
|
1676 if(ifofile->vts_pgcit) {
|
|
1677 ifoFree_PGCIT_internal(ifofile->vts_pgcit);
|
|
1678 free(ifofile->vts_pgcit);
|
|
1679 ifofile->vts_pgcit = 0;
|
|
1680 }
|
|
1681 }
|
|
1682
|
|
1683
|
|
1684 int ifoRead_PGCI_UT(ifo_handle_t *ifofile) {
|
|
1685 pgci_ut_t *pgci_ut;
|
|
1686 unsigned int sector;
|
|
1687 unsigned int i;
|
|
1688 int info_length;
|
|
1689 uint8_t *data, *ptr;
|
|
1690
|
|
1691 if(!ifofile)
|
|
1692 return 0;
|
|
1693
|
|
1694 if(ifofile->vmgi_mat) {
|
|
1695 if(ifofile->vmgi_mat->vmgm_pgci_ut == 0)
|
|
1696 return 1;
|
|
1697 sector = ifofile->vmgi_mat->vmgm_pgci_ut;
|
|
1698 } else if(ifofile->vtsi_mat) {
|
|
1699 if(ifofile->vtsi_mat->vtsm_pgci_ut == 0)
|
|
1700 return 1;
|
|
1701 sector = ifofile->vtsi_mat->vtsm_pgci_ut;
|
|
1702 } else {
|
|
1703 return 0;
|
|
1704 }
|
|
1705
|
|
1706 ifofile->pgci_ut = (pgci_ut_t *)malloc(sizeof(pgci_ut_t));
|
|
1707 if(!ifofile->pgci_ut)
|
|
1708 return 0;
|
|
1709
|
|
1710 if(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN)) {
|
|
1711 free(ifofile->pgci_ut);
|
|
1712 ifofile->pgci_ut = 0;
|
|
1713 return 0;
|
|
1714 }
|
|
1715
|
|
1716 if(!(DVDReadBytes(ifofile->file, ifofile->pgci_ut, PGCI_UT_SIZE))) {
|
|
1717 free(ifofile->pgci_ut);
|
|
1718 ifofile->pgci_ut = 0;
|
|
1719 return 0;
|
|
1720 }
|
|
1721
|
|
1722 pgci_ut = ifofile->pgci_ut;
|
|
1723
|
|
1724 B2N_16(pgci_ut->nr_of_lus);
|
|
1725 B2N_32(pgci_ut->last_byte);
|
|
1726
|
|
1727 CHECK_ZERO(pgci_ut->zero_1);
|
|
1728 CHECK_VALUE(pgci_ut->nr_of_lus != 0);
|
183
|
1729 CHECK_VALUE(pgci_ut->nr_of_lus < 100); /* ?? 3-4 ? */
|
168
|
1730 CHECK_VALUE((uint32_t)pgci_ut->nr_of_lus * PGCI_LU_SIZE < pgci_ut->last_byte);
|
|
1731
|
|
1732 info_length = pgci_ut->nr_of_lus * PGCI_LU_SIZE;
|
|
1733 data = malloc(info_length);
|
|
1734 if(!data) {
|
|
1735 free(pgci_ut);
|
|
1736 ifofile->pgci_ut = 0;
|
|
1737 return 0;
|
|
1738 }
|
|
1739 if(!(DVDReadBytes(ifofile->file, data, info_length))) {
|
|
1740 free(data);
|
|
1741 free(pgci_ut);
|
|
1742 ifofile->pgci_ut = 0;
|
|
1743 return 0;
|
|
1744 }
|
|
1745
|
|
1746 pgci_ut->lu = malloc(pgci_ut->nr_of_lus * sizeof(pgci_lu_t));
|
|
1747 if(!pgci_ut->lu) {
|
|
1748 free(data);
|
|
1749 free(pgci_ut);
|
|
1750 ifofile->pgci_ut = 0;
|
|
1751 return 0;
|
|
1752 }
|
|
1753 ptr = data;
|
|
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);
|
|
1759 }
|
|
1760 free(data);
|
|
1761
|
|
1762 for(i = 0; i < pgci_ut->nr_of_lus; i++) {
|
183
|
1763 /* Maybe this is only defined for v1.1 and later titles? */
|
168
|
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"
|
|
1768 c == 0x85 "Audio"
|
|
1769 d == 0x86 "Angle"
|
|
1770 e == 0x87 "PTT"
|
|
1771 */
|
|
1772 CHECK_VALUE((pgci_ut->lu[i].exists & 0x07) == 0);
|
|
1773 }
|
|
1774
|
|
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) {
|
|
1778 unsigned int j;
|
|
1779 for(j = 0; j < i; j++) {
|
|
1780 ifoFree_PGCIT_internal(pgci_ut->lu[j].pgcit);
|
|
1781 free(pgci_ut->lu[j].pgcit);
|
|
1782 }
|
|
1783 free(pgci_ut->lu);
|
|
1784 free(pgci_ut);
|
|
1785 ifofile->pgci_ut = 0;
|
|
1786 return 0;
|
|
1787 }
|
|
1788 if(!ifoRead_PGCIT_internal(ifofile, pgci_ut->lu[i].pgcit,
|
|
1789 sector * DVD_BLOCK_LEN
|
|
1790 + pgci_ut->lu[i].lang_start_byte)) {
|
|
1791 unsigned int j;
|
|
1792 for(j = 0; j < i; j++) {
|
|
1793 ifoFree_PGCIT_internal(pgci_ut->lu[j].pgcit);
|
|
1794 free(pgci_ut->lu[j].pgcit);
|
|
1795 }
|
|
1796 free(pgci_ut->lu[i].pgcit);
|
|
1797 free(pgci_ut->lu);
|
|
1798 free(pgci_ut);
|
|
1799 ifofile->pgci_ut = 0;
|
|
1800 return 0;
|
|
1801 }
|
183
|
1802 /*
|
|
1803 * FIXME: Iterate and verify that all menus that should exists accordingly
|
|
1804 * to pgci_ut->lu[i].exists really do?
|
|
1805 */
|
168
|
1806 }
|
|
1807
|
|
1808 return 1;
|
|
1809 }
|
|
1810
|
|
1811
|
|
1812 void ifoFree_PGCI_UT(ifo_handle_t *ifofile) {
|
|
1813 unsigned int i;
|
|
1814
|
|
1815 if(!ifofile)
|
|
1816 return;
|
|
1817
|
|
1818 if(ifofile->pgci_ut) {
|
|
1819 for(i = 0; i < ifofile->pgci_ut->nr_of_lus; i++) {
|
|
1820 ifoFree_PGCIT_internal(ifofile->pgci_ut->lu[i].pgcit);
|
|
1821 free(ifofile->pgci_ut->lu[i].pgcit);
|
|
1822 }
|
|
1823 free(ifofile->pgci_ut->lu);
|
|
1824 free(ifofile->pgci_ut);
|
|
1825 ifofile->pgci_ut = 0;
|
|
1826 }
|
|
1827 }
|
|
1828
|
|
1829 static int ifoRead_VTS_ATTRIBUTES(ifo_handle_t *ifofile,
|
|
1830 vts_attributes_t *vts_attributes,
|
|
1831 unsigned int offset) {
|
|
1832 unsigned int i;
|
|
1833
|
|
1834 if(!DVDFileSeek_(ifofile->file, offset))
|
|
1835 return 0;
|
|
1836
|
|
1837 if(!(DVDReadBytes(ifofile->file, vts_attributes, sizeof(vts_attributes_t))))
|
|
1838 return 0;
|
|
1839
|
|
1840 B2N_32(vts_attributes->last_byte);
|
|
1841 B2N_32(vts_attributes->vts_cat);
|
|
1842 B2N_16(vts_attributes->vtsm_audio_attr.lang_code);
|
|
1843 B2N_16(vts_attributes->vtsm_subp_attr.lang_code);
|
|
1844 for(i = 0; i < 8; i++)
|
|
1845 B2N_16(vts_attributes->vtstt_audio_attr[i].lang_code);
|
|
1846 for(i = 0; i < 32; i++)
|
|
1847 B2N_16(vts_attributes->vtstt_subp_attr[i].lang_code);
|
|
1848
|
|
1849 CHECK_ZERO(vts_attributes->zero_1);
|
|
1850 CHECK_ZERO(vts_attributes->zero_2);
|
|
1851 CHECK_ZERO(vts_attributes->zero_3);
|
|
1852 CHECK_ZERO(vts_attributes->zero_4);
|
|
1853 CHECK_ZERO(vts_attributes->zero_5);
|
|
1854 CHECK_ZERO(vts_attributes->zero_6);
|
|
1855 CHECK_ZERO(vts_attributes->zero_7);
|
|
1856 CHECK_VALUE(vts_attributes->nr_of_vtsm_audio_streams <= 1);
|
|
1857 CHECK_VALUE(vts_attributes->nr_of_vtsm_subp_streams <= 1);
|
|
1858 CHECK_VALUE(vts_attributes->nr_of_vtstt_audio_streams <= 8);
|
|
1859 for(i = vts_attributes->nr_of_vtstt_audio_streams; i < 8; i++)
|
|
1860 CHECK_ZERO(vts_attributes->vtstt_audio_attr[i]);
|
|
1861 CHECK_VALUE(vts_attributes->nr_of_vtstt_subp_streams <= 32);
|
|
1862 {
|
|
1863 unsigned int nr_coded;
|
|
1864 CHECK_VALUE(vts_attributes->last_byte + 1 >= VTS_ATTRIBUTES_MIN_SIZE);
|
|
1865 nr_coded = (vts_attributes->last_byte + 1 - VTS_ATTRIBUTES_MIN_SIZE)/6;
|
183
|
1866 /* This is often nr_coded = 70, how do you know how many there really are? */
|
|
1867 if(nr_coded > 32) { /* We haven't read more from disk/file anyway */
|
168
|
1868 nr_coded = 32;
|
|
1869 }
|
|
1870 CHECK_VALUE(vts_attributes->nr_of_vtstt_subp_streams <= nr_coded);
|
|
1871 for(i = vts_attributes->nr_of_vtstt_subp_streams; i < nr_coded; i++)
|
|
1872 CHECK_ZERO(vts_attributes->vtstt_subp_attr[i]);
|
|
1873 }
|
|
1874
|
|
1875 return 1;
|
|
1876 }
|
|
1877
|
|
1878
|
|
1879
|
|
1880 int ifoRead_VTS_ATRT(ifo_handle_t *ifofile) {
|
|
1881 vts_atrt_t *vts_atrt;
|
|
1882 unsigned int i, info_length, sector;
|
|
1883 uint32_t *data;
|
|
1884
|
|
1885 if(!ifofile)
|
|
1886 return 0;
|
|
1887
|
|
1888 if(!ifofile->vmgi_mat)
|
|
1889 return 0;
|
|
1890
|
|
1891 if(ifofile->vmgi_mat->vts_atrt == 0) /* mandatory */
|
|
1892 return 0;
|
|
1893
|
|
1894 sector = ifofile->vmgi_mat->vts_atrt;
|
|
1895 if(!DVDFileSeek_(ifofile->file, sector * DVD_BLOCK_LEN))
|
|
1896 return 0;
|
|
1897
|
|
1898 vts_atrt = (vts_atrt_t *)malloc(sizeof(vts_atrt_t));
|
|
1899 if(!vts_atrt)
|
|
1900 return 0;
|
|
1901
|
|
1902 ifofile->vts_atrt = vts_atrt;
|
|
1903
|
|
1904 if(!(DVDReadBytes(ifofile->file, vts_atrt, VTS_ATRT_SIZE))) {
|
|
1905 free(vts_atrt);
|
|
1906 ifofile->vts_atrt = 0;
|
|
1907 return 0;
|
|
1908 }
|
|
1909
|
|
1910 B2N_16(vts_atrt->nr_of_vtss);
|
|
1911 B2N_32(vts_atrt->last_byte);
|
|
1912
|
|
1913 CHECK_ZERO(vts_atrt->zero_1);
|
|
1914 CHECK_VALUE(vts_atrt->nr_of_vtss != 0);
|
183
|
1915 CHECK_VALUE(vts_atrt->nr_of_vtss < 100); /* ?? */
|
168
|
1916 CHECK_VALUE((uint32_t)vts_atrt->nr_of_vtss * (4 + VTS_ATTRIBUTES_MIN_SIZE) +
|
|
1917 VTS_ATRT_SIZE < vts_atrt->last_byte + 1);
|
|
1918
|
|
1919 info_length = vts_atrt->nr_of_vtss * sizeof(uint32_t);
|
|
1920 data = (uint32_t *)malloc(info_length);
|
|
1921 if(!data) {
|
|
1922 free(vts_atrt);
|
|
1923 ifofile->vts_atrt = 0;
|
|
1924 return 0;
|
|
1925 }
|
|
1926
|
|
1927 vts_atrt->vts_atrt_offsets = data;
|
|
1928
|
|
1929 if(!(DVDReadBytes(ifofile->file, data, info_length))) {
|
|
1930 free(data);
|
|
1931 free(vts_atrt);
|
|
1932 ifofile->vts_atrt = 0;
|
|
1933 return 0;
|
|
1934 }
|
|
1935
|
|
1936 for(i = 0; i < vts_atrt->nr_of_vtss; i++) {
|
|
1937 B2N_32(data[i]);
|
|
1938 CHECK_VALUE(data[i] + VTS_ATTRIBUTES_MIN_SIZE < vts_atrt->last_byte + 1);
|
|
1939 }
|
|
1940
|
|
1941 info_length = vts_atrt->nr_of_vtss * sizeof(vts_attributes_t);
|
|
1942 vts_atrt->vts = (vts_attributes_t *)malloc(info_length);
|
|
1943 if(!vts_atrt->vts) {
|
|
1944 free(data);
|
|
1945 free(vts_atrt);
|
|
1946 ifofile->vts_atrt = 0;
|
|
1947 return 0;
|
|
1948 }
|
|
1949 for(i = 0; i < vts_atrt->nr_of_vtss; i++) {
|
|
1950 unsigned int offset = data[i];
|
|
1951 if(!ifoRead_VTS_ATTRIBUTES(ifofile, &(vts_atrt->vts[i]),
|
|
1952 (sector * DVD_BLOCK_LEN) + offset)) {
|
|
1953 free(data);
|
|
1954 free(vts_atrt);
|
|
1955 ifofile->vts_atrt = 0;
|
|
1956 return 0;
|
|
1957 }
|
|
1958
|
183
|
1959 /* This assert cant be in ifoRead_VTS_ATTRIBUTES */
|
168
|
1960 CHECK_VALUE(offset + vts_atrt->vts[i].last_byte <= vts_atrt->last_byte + 1);
|
183
|
1961 /* Is this check correct? */
|
168
|
1962 }
|
|
1963
|
|
1964 return 1;
|
|
1965 }
|
|
1966
|
|
1967
|
|
1968 void ifoFree_VTS_ATRT(ifo_handle_t *ifofile) {
|
|
1969 if(!ifofile)
|
|
1970 return;
|
|
1971
|
|
1972 if(ifofile->vts_atrt) {
|
|
1973 free(ifofile->vts_atrt->vts);
|
|
1974 free(ifofile->vts_atrt->vts_atrt_offsets);
|
|
1975 free(ifofile->vts_atrt);
|
|
1976 ifofile->vts_atrt = 0;
|
|
1977 }
|
|
1978 }
|
|
1979
|
|
1980
|
|
1981 int ifoRead_TXTDT_MGI(ifo_handle_t *ifofile) {
|
|
1982 txtdt_mgi_t *txtdt_mgi;
|
|
1983
|
|
1984 if(!ifofile)
|
|
1985 return 0;
|
|
1986
|
|
1987 if(!ifofile->vmgi_mat)
|
|
1988 return 0;
|
|
1989
|
|
1990 /* Return successfully if there is nothing to read. */
|
|
1991 if(ifofile->vmgi_mat->txtdt_mgi == 0)
|
|
1992 return 1;
|
|
1993
|
|
1994 if(!DVDFileSeek_(ifofile->file,
|
|
1995 ifofile->vmgi_mat->txtdt_mgi * DVD_BLOCK_LEN))
|
|
1996 return 0;
|
|
1997
|
|
1998 txtdt_mgi = (txtdt_mgi_t *)malloc(sizeof(txtdt_mgi_t));
|
|
1999 if(!txtdt_mgi) {
|
|
2000 return 0;
|
|
2001 }
|
|
2002 ifofile->txtdt_mgi = txtdt_mgi;
|
|
2003
|
|
2004 if(!(DVDReadBytes(ifofile->file, txtdt_mgi, TXTDT_MGI_SIZE))) {
|
|
2005 fprintf(stderr, "libdvdread: Unable to read TXTDT_MGI.\n");
|
|
2006 free(txtdt_mgi);
|
|
2007 ifofile->txtdt_mgi = 0;
|
|
2008 return 0;
|
|
2009 }
|
|
2010
|
183
|
2011 /* fprintf(stderr, "-- Not done yet --\n"); */
|
168
|
2012 return 1;
|
|
2013 }
|
|
2014
|
|
2015 void ifoFree_TXTDT_MGI(ifo_handle_t *ifofile) {
|
|
2016 if(!ifofile)
|
|
2017 return;
|
|
2018
|
|
2019 if(ifofile->txtdt_mgi) {
|
|
2020 free(ifofile->txtdt_mgi);
|
|
2021 ifofile->txtdt_mgi = 0;
|
|
2022 }
|
|
2023 }
|
|
2024
|