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