1 /*
2 Copyright (C) 2002-2005, 2017-2018 Rocky Bernstein <rocky@gnu.org>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Foundation
16 Software, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 /*
19 Things here refer to higher-level structures usually accessed via
20 vcdinfo_t. For lower-level access which generally use
21 structures other than vcdinfo_t, see inf.c
22 */
23
24
25 /* Private headers */
26 #include "info_private.h"
27 #include "vcd_assert.h"
28 #include "pbc.h"
29 #include "util.h"
30 #include "vcd_read.h"
31
32 #ifdef HAVE_STDLIB_H
33 #include <stdlib.h>
34 #endif
35 #ifdef HAVE_STRING_H
36 #include <string.h>
37 #endif
38 #ifdef HAVE_SYS_TYPES_H
39 #include <sys/types.h>
40 #endif
41 #ifdef HAVE_SYS_STAT_H
42 #include <sys/stat.h>
43 #endif
44 #ifdef HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif
47
48 #include <cdio/cdio.h>
49 #include <cdio/bytesex.h>
50 #include <cdio/cd_types.h>
51 #include <cdio/util.h>
52
53 /* Eventually move above libvcd includes but having vcdinfo including. */
54 #include <libvcd/info.h>
55
56 #include <stdio.h>
57 #include <stddef.h>
58 #include <errno.h>
59
60 #define BUF_COUNT 16
61 #define BUF_SIZE 80
62
63 /* Return a pointer to a internal free buffer */
64 static char *
_getbuf(void)65 _getbuf (void)
66 {
67 static char _buf[BUF_COUNT][BUF_SIZE];
68 static int _num = -1;
69
70 _num++;
71 _num %= BUF_COUNT;
72
73 memset (_buf[_num], 0, BUF_SIZE);
74
75 return _buf[_num];
76 }
77
78 /*
79 Initialize/allocate segment portion of vcdinfo_obj_t.
80
81 Getting exact segments sizes is done in a rather complicated way.
82 A simple approach would be to use the fixed size allocated on disk,
83 but players have trouble with the internal fragmentation padding.
84 More accurate results are obtained by consulting with ISO 9660
85 information for the corresponding file entry.
86
87 Another approach to get segment sizes is to read/scan the
88 MPEGs. That would be rather slow.
89 */
90 static void
_init_segments(vcdinfo_obj_t * p_obj)91 _init_segments (vcdinfo_obj_t *p_obj)
92 {
93 InfoVcd_t *info = vcdinfo_get_infoVcd(p_obj);
94 segnum_t num_segments = vcdinfo_get_num_segments(p_obj);
95 CdioListNode_t *entnode;
96 CdioList_t *entlist;
97 int i;
98 lsn_t last_lsn=0;
99
100 p_obj->first_segment_lsn = cdio_msf_to_lsn(&info->first_seg_addr);
101 p_obj->seg_sizes = calloc(1, num_segments * sizeof(uint32_t));
102
103 if (NULL == p_obj->seg_sizes || 0 == num_segments) return;
104
105 entlist = iso9660_fs_readdir(p_obj->img, "SEGMENT");
106
107 i=0;
108 _CDIO_LIST_FOREACH (entnode, entlist) {
109 iso9660_stat_t *statbuf = _cdio_list_node_data (entnode);
110
111 if (statbuf->type == _STAT_DIR) continue;
112
113 while(info->spi_contents[i].item_cont) {
114 p_obj->seg_sizes[i] = VCDINFO_SEGMENT_SECTOR_SIZE;
115 i++;
116 }
117
118 /* Should have an entry in the ISO 9660 filesystem. Get and save
119 in statbuf.secsize this size.
120 */
121 p_obj->seg_sizes[i] = statbuf->secsize;
122
123 if (last_lsn >= statbuf->lsn)
124 vcd_warn ("Segments if ISO 9660 directory out of order lsn %ul >= %ul",
125 (unsigned int) last_lsn, (unsigned int) statbuf->lsn);
126 last_lsn = statbuf->lsn;
127
128 i++;
129 }
130
131 while(i < num_segments && info->spi_contents[i].item_cont) {
132 p_obj->seg_sizes[i] = VCDINFO_SEGMENT_SECTOR_SIZE;
133 i++;
134 }
135
136 if (i != num_segments)
137 vcd_warn ("Number of segments found %d is not number of segments %d",
138 i, num_segments);
139
140 _cdio_list_free (entlist, true, NULL);
141
142
143 #if 0
144 /* Figure all of the segment sector sizes */
145 for (i=0; i < num_segments; i++) {
146
147 p_obj->seg_sizes[i] = VCDINFO_SEGMENT_SECTOR_SIZE;
148
149 if ( !info->spi_contents[i].item_cont ) {
150 /* Should have an entry in the ISO 9660 filesystem. Get and save
151 in statbuf.secsize this size.
152 */
153 lsn_t lsn = vcdinfo_get_seg_lsn(p_obj, i);
154 iso9660_stat_t *statbuf =iso9660_find_fs_lsn(p_obj->img, lsn);
155 if (NULL != statbuf) {
156 p_obj->seg_sizes[i] = statbuf->secsize;
157 free(statbuf);
158 } else {
159 vcd_warn ("Trouble finding ISO 9660 size for segment %d.", i);
160 }
161 }
162 }
163 #endif
164
165 }
166
167 /*!
168 Return the number of audio channels implied by "audio_type".
169 0 is returned on error.
170 */
171 unsigned int
vcdinfo_audio_type_num_channels(const vcdinfo_obj_t * p_obj,unsigned int audio_type)172 vcdinfo_audio_type_num_channels(const vcdinfo_obj_t *p_obj,
173 unsigned int audio_type)
174 {
175 const int audio_types[2][5] =
176 {
177 { /* VCD 2.0 */
178 0, /* no audio*/
179 1, /* single channel */
180 1, /* stereo */
181 2, /* dual channel */
182 0}, /* error */
183
184 { /* SVCD, HQVCD */
185 0, /* no stream */
186 1, /* 1 stream */
187 2, /* 2 streams */
188 1, /* 1 multi-channel stream (surround sound) */
189 0} /* error */
190 };
191
192 /* We should also check that the second index is in range too. */
193 if (audio_type > 4) {
194 return 0;
195 }
196
197 /* Get first index entry into above audio_type array from vcd_type */
198 switch (p_obj->vcd_type) {
199
200 case VCD_TYPE_VCD:
201 case VCD_TYPE_VCD11:
202 return 1;
203
204 case VCD_TYPE_VCD2:
205 return 3;
206 break;
207
208 case VCD_TYPE_HQVCD:
209 case VCD_TYPE_SVCD:
210 return audio_types[1][audio_type];
211 break;
212
213 case VCD_TYPE_INVALID:
214 default:
215 /* We have an invalid entry. Set to handle below. */
216 return 0;
217 }
218 }
219
220 /*!
221 Return a string describing an audio type.
222 */
223 const char *
vcdinfo_audio_type2str(const vcdinfo_obj_t * p_obj,unsigned int audio_type)224 vcdinfo_audio_type2str(const vcdinfo_obj_t *p_obj, unsigned int audio_type)
225 {
226 const char *audio_types[3][5] =
227 {
228 /* INVALID, VCD 1.0, or VCD 1.1 */
229 { "unknown", "invalid", "", "", "" },
230
231 /*VCD 2.0 */
232 { "no audio", "single channel", "stereo", "dual channel", "error" },
233
234 /* SVCD, HQVCD */
235 { "no stream", "1 stream", "2 streams",
236 "1 multi-channel stream (surround sound)", "error"},
237 };
238
239 unsigned int first_index = 0;
240
241 /* Get first index entry into above audio_type array from vcd_type */
242 switch (p_obj->vcd_type) {
243
244 case VCD_TYPE_VCD:
245 case VCD_TYPE_VCD11:
246 case VCD_TYPE_VCD2:
247 first_index=1;
248 break;
249
250 case VCD_TYPE_HQVCD:
251 case VCD_TYPE_SVCD:
252 first_index=2;
253 break;
254
255 case VCD_TYPE_INVALID:
256 default:
257 /* We have an invalid entry. Set to handle below. */
258 audio_type=4;
259 }
260
261 /* We should also check that the second index is in range too. */
262 if (audio_type > 3) {
263 first_index=0;
264 audio_type=1;
265 }
266
267 return audio_types[first_index][audio_type];
268 }
269
270 /*!
271 Note first i_seg is 0!
272 */
273 const char *
vcdinfo_ogt2str(const vcdinfo_obj_t * p_obj,segnum_t i_seg)274 vcdinfo_ogt2str(const vcdinfo_obj_t *p_obj, segnum_t i_seg)
275 {
276 const InfoVcd_t *info = &(p_obj->info);
277 const char *ogt_str[] =
278 {
279 "None",
280 "1 available",
281 "0 & 1 available",
282 "all 4 available"
283 };
284
285 return ogt_str[info->spi_contents[i_seg].ogt];
286 }
287
288
289 const char *
vcdinfo_video_type2str(const vcdinfo_obj_t * p_obj,segnum_t i_seg)290 vcdinfo_video_type2str(const vcdinfo_obj_t *p_obj, segnum_t i_seg)
291 {
292 const char *video_types[] =
293 {
294 "no stream",
295 "NTSC still",
296 "NTSC still (lo+hires)",
297 "NTSC motion",
298 "reserved (0x4)",
299 "PAL still",
300 "PAL still (lo+hires)",
301 "PAL motion"
302 "INVALID ENTRY"
303 };
304
305 return video_types[vcdinfo_get_video_type(p_obj, i_seg)];
306 }
307
308 /*!
309 \brief Classify i_itemid into the kind of item it is: track #, entry #,
310 segment #.
311 \param itemid is set to contain this classification an the converted
312 entry number.
313 */
314 void
vcdinfo_classify_itemid(uint16_t i_itemid,vcdinfo_itemid_t * itemid)315 vcdinfo_classify_itemid (uint16_t i_itemid,
316 /*out*/ vcdinfo_itemid_t *itemid)
317 {
318
319 itemid->num = i_itemid;
320 if (i_itemid < 2)
321 itemid->type = VCDINFO_ITEM_TYPE_NOTFOUND;
322 else if (i_itemid < MIN_ENCODED_TRACK_NUM) {
323 itemid->type = VCDINFO_ITEM_TYPE_TRACK;
324 itemid->num--;
325 } else if (i_itemid < 600) {
326 itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
327 itemid->num -= MIN_ENCODED_TRACK_NUM;
328 } else if (i_itemid < MIN_ENCODED_SEGMENT_NUM)
329 itemid->type = VCDINFO_ITEM_TYPE_LID;
330 else if (i_itemid <= MAX_ENCODED_SEGMENT_NUM) {
331 itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
332 itemid->num -= (MIN_ENCODED_SEGMENT_NUM);
333 } else
334 itemid->type = VCDINFO_ITEM_TYPE_SPAREID2;
335 }
336
337 const char *
vcdinfo_pin2str(uint16_t i_itemid)338 vcdinfo_pin2str (uint16_t i_itemid)
339 {
340 char *buf = _getbuf ();
341 vcdinfo_itemid_t itemid;
342
343 vcdinfo_classify_itemid(i_itemid, &itemid);
344 strcpy (buf, "??");
345
346 switch(itemid.type) {
347 case VCDINFO_ITEM_TYPE_NOTFOUND:
348 snprintf (buf, BUF_SIZE, "play nothing (0x%4.4x)", itemid.num);
349 break;
350 case VCDINFO_ITEM_TYPE_TRACK:
351 snprintf (buf, BUF_SIZE, "SEQUENCE[%d] (0x%4.4x)", itemid.num-1,
352 i_itemid);
353 break;
354 case VCDINFO_ITEM_TYPE_ENTRY:
355 snprintf (buf, BUF_SIZE, "ENTRY[%d] (0x%4.4x)", itemid.num, i_itemid);
356 break;
357 case VCDINFO_ITEM_TYPE_SEGMENT:
358 snprintf (buf, BUF_SIZE, "SEGMENT[%d] (0x%4.4x)", itemid.num, i_itemid);
359 break;
360 case VCDINFO_ITEM_TYPE_LID:
361 snprintf (buf, BUF_SIZE, "spare id (0x%4.4x)", itemid.num);
362 break;
363 case VCDINFO_ITEM_TYPE_SPAREID2:
364 snprintf (buf, BUF_SIZE, "spare id2 (0x%4.4x)", itemid.num);
365 break;
366 }
367
368 return buf;
369 }
370
371 /*!
372 Return a string containing the VCD album id, or NULL if there is
373 some problem in getting this.
374 */
375 const char *
vcdinfo_get_album_id(const vcdinfo_obj_t * p_obj)376 vcdinfo_get_album_id(const vcdinfo_obj_t *p_obj)
377 {
378 if ( !p_obj ) return NULL;
379 return vcdinf_get_album_id( &(p_obj->info) );
380 }
381
382 /*!
383 Return the VCD ID.
384 NULL is returned if there is some problem in getting this.
385 */
386 char *
vcdinfo_get_application_id(vcdinfo_obj_t * p_obj)387 vcdinfo_get_application_id(vcdinfo_obj_t *p_obj)
388 {
389 if ( !p_obj ) return NULL;
390 return iso9660_get_application_id( &(p_obj->pvd) );
391 }
392
393 /*!
394 Return a pointer to the cdio structure for the CD image opened or
395 NULL if error.
396 */
397 CdIo_t *
vcdinfo_get_cd_image(const vcdinfo_obj_t * p_vcd_obj)398 vcdinfo_get_cd_image (const vcdinfo_obj_t *p_vcd_obj)
399 {
400 if ( !p_vcd_obj ) return NULL;
401 return p_vcd_obj->img;
402 }
403
404
405 /*!
406 \fn vcdinfo_selection_get_lid(const vcdinfo_obj_t *p_obj, lid_t lid,
407 unsigned int selection);
408
409 \brief Get offset of a selection for a given lid.
410
411 Return the LID offset associated with a the selection number of the
412 passed-in LID parameter.
413
414 \return VCDINFO_INVALID_LID is returned if obj on error or obj
415 is NULL. Otherwise the LID offset is returned.
416 */
vcdinfo_selection_get_lid(const vcdinfo_obj_t * p_obj,lid_t lid,unsigned int selection)417 lid_t vcdinfo_selection_get_lid(const vcdinfo_obj_t *p_obj, lid_t lid,
418 unsigned int selection)
419 {
420 unsigned int offset;
421
422 if (!p_obj) return VCDINFO_INVALID_LID;
423
424 offset = vcdinfo_selection_get_offset(p_obj, lid, selection);
425 switch (offset) {
426 case VCDINFO_INVALID_OFFSET:
427 case PSD_OFS_MULTI_DEF:
428 case PSD_OFS_MULTI_DEF_NO_NUM:
429 return VCDINFO_INVALID_LID;
430 default:
431 {
432 vcdinfo_offset_t *ofs = vcdinfo_get_offset_t(p_obj, offset);
433 return ofs->lid;
434 }
435 }
436 }
437
438 /*!
439 \fn vcdinfo_selection_get_offset(const vcdinfo_obj_t *p_obj, lid_t lid,
440 unsigned int selection);
441
442 \brief Get offset of a selection for a given lid.
443
444 Return the LID offset associated with a the selection number of the
445 passed-in LID parameter.
446
447 \return VCDINFO_INVALID_OFFSET is returned if error, obj is NULL or
448 the lid is not some type of selection list. Otherwise the LID offset
449 is returned.
450 */
vcdinfo_selection_get_offset(const vcdinfo_obj_t * p_obj,lid_t lid,unsigned int selection)451 uint16_t vcdinfo_selection_get_offset(const vcdinfo_obj_t *p_obj, lid_t lid,
452 unsigned int selection)
453 {
454 unsigned int bsn;
455
456 PsdListDescriptor_t pxd;
457 vcdinfo_lid_get_pxd(p_obj, &pxd, lid);
458 if (pxd.descriptor_type != PSD_TYPE_SELECTION_LIST &&
459 pxd.descriptor_type != PSD_TYPE_EXT_SELECTION_LIST) {
460 vcd_warn( "Requesting selection of LID %i which not a selection list -"
461 " type is 0x%x",
462 lid, pxd.descriptor_type );
463 return VCDINFO_INVALID_OFFSET;
464 }
465
466 bsn=vcdinf_get_bsn(pxd.psd);
467
468 if ( (selection - bsn + 1) > 0) {
469 return vcdinfo_lid_get_offset(p_obj, lid, selection-bsn+1);
470 } else {
471 vcd_warn( "Selection number %u too small. bsn %u", selection, bsn );
472 return VCDINFO_INVALID_OFFSET;
473 }
474 }
475
476 /**
477 \fn vcdinfo_get_default_offset(const vcdinfo_obj_t *p_obj, unsinged int lid);
478 \brief Get return offset for a given PLD selector descriptor.
479 \return VCDINFO_INVALID_OFFSET is returned on error or if pld has no
480 "return" entry or pld is NULL. Otherwise the LID offset is returned.
481 */
482 uint16_t
vcdinfo_get_default_offset(const vcdinfo_obj_t * p_obj,lid_t lid)483 vcdinfo_get_default_offset(const vcdinfo_obj_t *p_obj, lid_t lid)
484 {
485 if (p_obj) {
486
487 PsdListDescriptor_t pxd;
488
489 vcdinfo_lid_get_pxd(p_obj, &pxd, lid);
490
491 switch (pxd.descriptor_type) {
492 case PSD_TYPE_EXT_SELECTION_LIST:
493 case PSD_TYPE_SELECTION_LIST:
494 return vcdinf_psd_get_default_offset(pxd.psd);
495 break;
496 case PSD_TYPE_PLAY_LIST:
497 case PSD_TYPE_END_LIST:
498 case PSD_TYPE_COMMAND_LIST:
499 break;
500 }
501 }
502 return VCDINFO_INVALID_OFFSET;
503 }
504
505 /*!
506 \brief Get default or multi-default LID.
507
508 Return the LID offset associated with a the "default" entry of the
509 passed-in LID parameter. Note "default" entries are associated
510 with PSDs that are (extended) selection lists. If the "default"
511 offset is a multi-default, we use entry_num to find the proper
512 "default" LID. Otherwise this routine is exactly like
513 vcdinfo_get_default_lid with the exception of requiring an
514 additional "entry_num" parameter.
515
516 \return VCDINFO_INVALID_LID is returned on error, or if the LID
517 is not a selection list or no "default" entry. Otherwise the LID
518 offset is returned.
519 */
520 lid_t
vcdinfo_get_multi_default_lid(const vcdinfo_obj_t * p_obj,lid_t lid,lsn_t lsn)521 vcdinfo_get_multi_default_lid(const vcdinfo_obj_t *p_obj, lid_t lid,
522 lsn_t lsn)
523 {
524 unsigned int offset;
525 unsigned int entry_num;
526
527 entry_num = vcdinfo_lsn_get_entry(p_obj, lsn);
528 offset = vcdinfo_get_multi_default_offset(p_obj, lid, entry_num);
529
530 switch (offset) {
531 case VCDINFO_INVALID_OFFSET:
532 case PSD_OFS_MULTI_DEF:
533 case PSD_OFS_MULTI_DEF_NO_NUM:
534 return VCDINFO_INVALID_LID;
535 default:
536 {
537 vcdinfo_offset_t *ofs = vcdinfo_get_offset_t(p_obj, offset);
538 return ofs->lid;
539 }
540 }
541 }
542
543 /*!
544 \brief Get default or multi-default LID offset.
545
546 Return the LID offset associated with a the "default" entry of the
547 passed-in LID parameter. Note "default" entries are associated
548 with PSDs that are (extended) selection lists. If the "default"
549 offset is a multi-default, we use entry_num to find the proper
550 "default" offset. Otherwise this routine is exactly like
551 vcdinfo_get_default_offset with the exception of requiring an
552 additional "entry_num" parameter.
553
554 \return VCDINFO_INVALID_OFFSET is returned on error, or if the LID
555 is not a selection list or no "default" entry. Otherwise the LID
556 offset is returned.
557 */
558 uint16_t
vcdinfo_get_multi_default_offset(const vcdinfo_obj_t * p_obj,lid_t lid,unsigned int entry_num)559 vcdinfo_get_multi_default_offset(const vcdinfo_obj_t *p_obj, lid_t lid,
560 unsigned int entry_num)
561 {
562 uint16_t offset=vcdinfo_get_default_offset(p_obj, lid);
563
564 switch (offset) {
565 case PSD_OFS_MULTI_DEF:
566 case PSD_OFS_MULTI_DEF_NO_NUM:
567 {
568 /* Have some work todo... Figure the selection number. */
569 PsdListDescriptor_t pxd;
570
571 vcdinfo_lid_get_pxd(p_obj, &pxd, lid);
572
573 switch (pxd.descriptor_type) {
574
575 case PSD_TYPE_SELECTION_LIST:
576 case PSD_TYPE_EXT_SELECTION_LIST: {
577 vcdinfo_itemid_t selection_itemid;
578 uint16_t selection_itemid_num;
579 unsigned int start_entry_num;
580
581 if (pxd.psd == NULL) return VCDINFO_INVALID_OFFSET;
582 selection_itemid_num = vcdinf_psd_get_itemid(pxd.psd);
583 vcdinfo_classify_itemid(selection_itemid_num, &selection_itemid);
584 if (selection_itemid.type != VCDINFO_ITEM_TYPE_TRACK) {
585 return VCDINFO_INVALID_OFFSET;
586 }
587
588 start_entry_num = vcdinfo_track_get_entry(p_obj,
589 selection_itemid.num);
590 return vcdinfo_selection_get_offset(p_obj, lid,
591 entry_num-start_entry_num);
592 }
593 default: ;
594 }
595 }
596 default:
597 return VCDINFO_INVALID_OFFSET;
598 }
599 }
600
601 /*!
602 Return a string containing the default VCD device if none is specified.
603 Return NULL we can't get this information.
604 */
605 char *
vcdinfo_get_default_device(const vcdinfo_obj_t * p_vcd_obj)606 vcdinfo_get_default_device (const vcdinfo_obj_t *p_vcd_obj)
607 {
608
609 /* If device not already open, then we'll open it temporarily and
610 let CdIo select a driver, get the default for that and then
611 close/destroy the temporary we created.
612 */
613 CdIo_t *p_cdio=NULL;
614 if (p_vcd_obj && p_vcd_obj->img)
615 p_cdio = p_vcd_obj->img;
616
617 return cdio_get_default_device(p_cdio);
618 }
619
620 /*!
621 Return number of sector units in of an entry. 0 is returned if entry_num
622 is out of range.
623 The first entry number is 0.
624 */
625 uint32_t
vcdinfo_get_entry_sect_count(const vcdinfo_obj_t * p_obj,unsigned int entry_num)626 vcdinfo_get_entry_sect_count (const vcdinfo_obj_t *p_obj,
627 unsigned int entry_num)
628 {
629 const EntriesVcd_t *entries = &(p_obj->entries);
630 const unsigned int entry_count = vcdinf_get_num_entries(entries);
631 if (entry_num > entry_count)
632 return 0;
633 else {
634 const lsn_t this_lsn = vcdinfo_get_entry_lsn(p_obj, entry_num);
635 lsn_t next_lsn;
636 if (entry_num < entry_count-1) {
637 track_t track=vcdinfo_get_track(p_obj, entry_num);
638 track_t next_track=vcdinfo_get_track(p_obj, entry_num+1);
639 next_lsn = vcdinfo_get_entry_lsn(p_obj, entry_num+1);
640 /* If we've changed tracks, don't include pregap sector between
641 tracks.
642 */
643 if (track != next_track) next_lsn -= CDIO_PREGAP_SECTORS;
644 } else {
645 /* entry_num == entry_count -1. Or the last entry.
646 This is really really ugly. There's probably a better
647 way to do it.
648 Below we get the track of the current entry and then the LBA of the
649 beginning of the following (leadout?) track.
650
651 Wait! It's uglier than that! Since VCD's can be created
652 *without* a pregap to the leadout track, we try not to use
653 that if we can get the entry from the ISO 9660 filesystem.
654 */
655 track_t track = vcdinfo_get_track(p_obj, entry_num);
656 if (track != VCDINFO_INVALID_TRACK) {
657 iso9660_stat_t *statbuf;
658 const lsn_t lsn = vcdinfo_get_track_lsn(p_obj, track);
659
660 /* Try to get the sector count from the ISO 9660 filesystem */
661 statbuf = iso9660_find_fs_lsn(p_obj->img, lsn);
662
663 if (NULL != statbuf) {
664 next_lsn = lsn + statbuf->secsize;
665 free(statbuf);
666 } else {
667 /* Failed on ISO 9660 filesystem. Use next track or
668 LEADOUT track. */
669 next_lsn = vcdinfo_get_track_lsn(p_obj, track+1);
670 }
671 if (next_lsn == VCDINFO_NULL_LSN)
672 return 0;
673 } else {
674 /* Something went wrong. Set up size to zero. */
675 return 0;
676 }
677 }
678 return (next_lsn - this_lsn);
679 }
680 }
681
682 /*! Return the starting MSF (minutes/secs/frames) for sequence
683 entry_num in obj. NULL is returned if there is no entry.
684 The first entry number is 0.
685 */
686 const msf_t *
vcdinfo_get_entry_msf(const vcdinfo_obj_t * p_obj,unsigned int entry_num)687 vcdinfo_get_entry_msf(const vcdinfo_obj_t *p_obj, unsigned int entry_num)
688 {
689 const EntriesVcd_t *entries = &(p_obj->entries);
690 return vcdinf_get_entry_msf(entries, entry_num);
691 }
692
693 /*! Return the starting LBA (logical block address) for sequence
694 entry_num in obj. VCDINFO_NULL_LBA is returned if there is no entry.
695 */
696 lba_t
vcdinfo_get_entry_lba(const vcdinfo_obj_t * p_obj,unsigned int entry_num)697 vcdinfo_get_entry_lba(const vcdinfo_obj_t *p_obj, unsigned int entry_num)
698 {
699 if ( !p_obj ) return VCDINFO_NULL_LBA;
700 else {
701 const msf_t *msf = vcdinfo_get_entry_msf(p_obj, entry_num);
702 return (msf != NULL) ? cdio_msf_to_lba(msf) : VCDINFO_NULL_LBA;
703 }
704 }
705
706 /*! Return the starting LBA (logical block address) for sequence
707 entry_num in obj. VCDINFO_NULL_LBA is returned if there is no entry.
708 */
709 lsn_t
vcdinfo_get_entry_lsn(const vcdinfo_obj_t * p_obj,unsigned int entry_num)710 vcdinfo_get_entry_lsn(const vcdinfo_obj_t *p_obj, unsigned int entry_num)
711 {
712 if ( !p_obj ) return VCDINFO_NULL_LBA;
713 else {
714 const msf_t *msf = vcdinfo_get_entry_msf(p_obj, entry_num);
715 return (msf != NULL) ? cdio_msf_to_lsn(msf) : VCDINFO_NULL_LSN;
716 }
717 }
718
719 EntriesVcd_t *
vcdinfo_get_entriesVcd(vcdinfo_obj_t * p_obj)720 vcdinfo_get_entriesVcd (vcdinfo_obj_t *p_obj)
721 {
722 if (!p_obj) return NULL;
723 return &(p_obj->entries);
724 }
725
726 /*!
727 Get the VCD format (VCD 1.0 VCD 1.1, SVCD, ... for this object.
728 The type is also set inside obj.
729 */
730 vcd_type_t
vcdinfo_get_format_version(const vcdinfo_obj_t * p_obj)731 vcdinfo_get_format_version (const vcdinfo_obj_t *p_obj)
732 {
733 return p_obj->vcd_type;
734 }
735
736 /*!
737 Return a string giving VCD format (VCD 1.0 VCD 1.1, SVCD, ...
738 for this object.
739 */
740 const char *
vcdinfo_get_format_version_str(const vcdinfo_obj_t * p_obj)741 vcdinfo_get_format_version_str (const vcdinfo_obj_t *p_obj)
742 {
743 if (!p_obj) return "*Uninitialized*";
744 return vcdinf_get_format_version_str(p_obj->vcd_type);
745 }
746
747 InfoVcd_t *
vcdinfo_get_infoVcd(vcdinfo_obj_t * p_obj)748 vcdinfo_get_infoVcd (vcdinfo_obj_t *p_obj)
749 {
750 if (!p_obj) return NULL;
751 return &(p_obj->info);
752 }
753
754 /*! Return the entry number closest and before the given LSN.
755 */
756 unsigned int
vcdinfo_lsn_get_entry(const vcdinfo_obj_t * p_obj,lsn_t lsn)757 vcdinfo_lsn_get_entry(const vcdinfo_obj_t *p_obj, lsn_t lsn)
758 {
759
760 /* Do a binary search to find the entry. */
761 unsigned int i = 0;
762 unsigned int j = vcdinfo_get_num_entries(p_obj);
763 unsigned int mid;
764 unsigned int mid_lsn;
765 do {
766 mid = (i+j)/2;
767 mid_lsn = vcdinfo_get_entry_lsn(p_obj, mid);
768 if ( lsn <= mid_lsn ) j = mid-1;
769 if ( lsn >= mid_lsn ) i = mid+1;
770 } while (i <= j);
771
772 /* We want the entry closest but before. */
773 return (lsn == mid_lsn) ? mid : mid-1;
774 }
775
776
777 /*!
778 \brief Get ISO 9660 Primary Volume Descriptor (PVD) for a VCDinfo
779 object.
780 */
781 iso9660_pvd_t *
vcdinfo_get_pvd(vcdinfo_obj_t * p_obj)782 vcdinfo_get_pvd (vcdinfo_obj_t *p_obj)
783 {
784 if (!p_obj) return NULL;
785 return &(p_obj->pvd);
786 }
787
788 void *
vcdinfo_get_scandata(vcdinfo_obj_t * p_obj)789 vcdinfo_get_scandata (vcdinfo_obj_t *p_obj)
790 {
791 if (!p_obj) return NULL;
792 return p_obj->scandata_buf;
793 }
794
795 void *
vcdinfo_get_searchDat(vcdinfo_obj_t * p_obj)796 vcdinfo_get_searchDat (vcdinfo_obj_t *p_obj)
797 {
798 if (!p_obj) return NULL;
799 return p_obj->search_buf;
800 }
801
802 void *
vcdinfo_get_tracksSVD(vcdinfo_obj_t * p_obj)803 vcdinfo_get_tracksSVD (vcdinfo_obj_t *p_obj)
804 {
805 if (!p_obj) return NULL;
806 return p_obj->tracks_buf;
807 }
808
809 /*!
810 Get the itemid for a given list ID.
811 VCDINFO_REJECTED_MASK is returned on error or if obj is NULL.
812 */
813 uint16_t
vcdinfo_lid_get_itemid(const vcdinfo_obj_t * p_obj,lid_t lid)814 vcdinfo_lid_get_itemid(const vcdinfo_obj_t *p_obj, lid_t lid)
815 {
816 PsdListDescriptor_t pxd;
817
818 if (!p_obj) return VCDINFO_REJECTED_MASK;
819 vcdinfo_lid_get_pxd(p_obj, &pxd, lid);
820 switch (pxd.descriptor_type) {
821 case PSD_TYPE_SELECTION_LIST:
822 case PSD_TYPE_EXT_SELECTION_LIST:
823 if (pxd.psd == NULL) return VCDINFO_REJECTED_MASK;
824 return vcdinf_psd_get_itemid(pxd.psd);
825 break;
826 case PSD_TYPE_PLAY_LIST:
827 /* FIXME: There is an array of items */
828 case PSD_TYPE_END_LIST:
829 case PSD_TYPE_COMMAND_LIST:
830 return VCDINFO_REJECTED_MASK;
831 }
832
833 return VCDINFO_REJECTED_MASK;
834
835 }
836
837 /*!
838 Get the LOT pointer.
839 */
840 LotVcd_t *
vcdinfo_get_lot(const vcdinfo_obj_t * p_obj)841 vcdinfo_get_lot(const vcdinfo_obj_t *p_obj)
842 {
843 if (!p_obj) return NULL;
844 return p_obj->lot;
845 }
846
847 /*!
848 Get the extended LOT pointer.
849 */
850 LotVcd_t *
vcdinfo_get_lot_x(const vcdinfo_obj_t * p_obj)851 vcdinfo_get_lot_x(const vcdinfo_obj_t *p_obj)
852 {
853 if (!p_obj) return NULL;
854 return p_obj->lot_x;
855 }
856
857 /*!
858 Return number of LIDs.
859 */
860 lid_t
vcdinfo_get_num_LIDs(const vcdinfo_obj_t * p_obj)861 vcdinfo_get_num_LIDs (const vcdinfo_obj_t *p_obj)
862 {
863 /* Should probably use _vcd_pbc_max_lid instead? */
864 if (!p_obj) return 0;
865 return vcdinf_get_num_LIDs( (&p_obj->info) );
866 }
867
868 /*!
869 Return the number of entries in the VCD.
870 */
871 unsigned int
vcdinfo_get_num_entries(const vcdinfo_obj_t * p_obj)872 vcdinfo_get_num_entries(const vcdinfo_obj_t *p_obj)
873 {
874 const EntriesVcd_t *entries = &(p_obj->entries);
875 return vcdinf_get_num_entries(entries);
876 }
877
878 /*!
879 Return the number of segments in the VCD. Return 0 if there is some
880 problem.
881 */
882 segnum_t
vcdinfo_get_num_segments(const vcdinfo_obj_t * p_obj)883 vcdinfo_get_num_segments(const vcdinfo_obj_t *p_obj)
884 {
885 if (!p_obj) return 0;
886 return vcdinf_get_num_segments( &(p_obj->info) );
887 }
888
889 /*!
890 \fn vcdinfo_get_offset_lid(const vcdinfo_obj_t *p_obj,
891 unsigned int entry_num);
892 \brief Get offset entry_num for a given LID.
893 \return VCDINFO_INVALID_OFFSET is returned if obj on error or obj
894 is NULL. Otherwise the LID offset is returned.
895 */
896 uint16_t
vcdinfo_lid_get_offset(const vcdinfo_obj_t * p_obj,lid_t lid,unsigned int entry_num)897 vcdinfo_lid_get_offset(const vcdinfo_obj_t *p_obj, lid_t lid,
898 unsigned int entry_num)
899 {
900 PsdListDescriptor_t pxd;
901
902 if (!p_obj) return VCDINFO_INVALID_OFFSET;
903 vcdinfo_lid_get_pxd(p_obj, &pxd, lid);
904
905 switch (pxd.descriptor_type) {
906 case PSD_TYPE_SELECTION_LIST:
907 case PSD_TYPE_EXT_SELECTION_LIST:
908 if (pxd.psd == NULL) return VCDINFO_INVALID_OFFSET;
909 return vcdinf_psd_get_offset(pxd.psd, entry_num-1);
910 break;
911 case PSD_TYPE_PLAY_LIST:
912 /* FIXME: There is an array of items */
913 case PSD_TYPE_END_LIST:
914 case PSD_TYPE_COMMAND_LIST:
915 return VCDINFO_INVALID_OFFSET;
916 }
917 return VCDINFO_INVALID_OFFSET;
918
919 }
920
921 /*!
922 NULL is returned on error.
923 */
924 static vcdinfo_offset_t *
_vcdinfo_get_offset_t(const vcdinfo_obj_t * p_obj,unsigned int offset,bool ext)925 _vcdinfo_get_offset_t (const vcdinfo_obj_t *p_obj, unsigned int offset,
926 bool ext)
927 {
928 CdioListNode_t *node;
929 CdioList_t *offset_list = ext ? p_obj->offset_x_list : p_obj->offset_list;
930
931 switch (offset) {
932 case PSD_OFS_DISABLED:
933 case PSD_OFS_MULTI_DEF:
934 case PSD_OFS_MULTI_DEF_NO_NUM:
935 return NULL;
936 default: ;
937 }
938
939 _CDIO_LIST_FOREACH (node, offset_list)
940 {
941 vcdinfo_offset_t *p_ofs = _cdio_list_node_data (node);
942 if (offset == p_ofs->offset)
943 return p_ofs;
944 }
945 return NULL;
946 }
947
948 /*!
949 Get the VCD info list.
950 */
951 CdioList_t *
vcdinfo_get_offset_list(const vcdinfo_obj_t * p_obj)952 vcdinfo_get_offset_list(const vcdinfo_obj_t *p_obj)
953 {
954 if (!p_obj) return NULL;
955 return p_obj->offset_list;
956 }
957
958
959 /*!
960 Get the VCD info extended offset list.
961 */
962 CdioList_t *
vcdinfo_get_offset_x_list(const vcdinfo_obj_t * p_obj)963 vcdinfo_get_offset_x_list(const vcdinfo_obj_t *p_obj)
964 {
965 if (!p_obj) return NULL;
966 return p_obj->offset_x_list;
967 }
968
969 /*!
970 Get the VCD info offset multiplier.
971 */
vcdinfo_get_offset_mult(const vcdinfo_obj_t * p_obj)972 unsigned int vcdinfo_get_offset_mult(const vcdinfo_obj_t *p_obj)
973 {
974 if (!p_obj) return 0xFFFF;
975 return p_obj->info.offset_mult;
976 }
977
978 /*!
979 Get entry in offset list for the item that has offset. This entry
980 has for example the LID. NULL is returned on error.
981 */
982 vcdinfo_offset_t *
vcdinfo_get_offset_t(const vcdinfo_obj_t * p_obj,unsigned int offset)983 vcdinfo_get_offset_t (const vcdinfo_obj_t *p_obj, unsigned int offset)
984 {
985 vcdinfo_offset_t *off_p= _vcdinfo_get_offset_t (p_obj, offset, true);
986 if (NULL != off_p)
987 return off_p;
988 return _vcdinfo_get_offset_t (p_obj, offset, false);
989 }
990
991 /*!
992 Return a string containing the VCD publisher id with trailing
993 blanks removed, or NULL if there is some problem in getting this.
994 */
995 char *
vcdinfo_get_preparer_id(const vcdinfo_obj_t * p_obj)996 vcdinfo_get_preparer_id(const vcdinfo_obj_t *p_obj)
997 {
998 if ( !p_obj ) return (NULL);
999 return iso9660_get_preparer_id(&(p_obj->pvd));
1000 }
1001
1002 /*!
1003 Get the PSD.
1004 */
1005 uint8_t *
vcdinfo_get_psd(const vcdinfo_obj_t * p_obj)1006 vcdinfo_get_psd(const vcdinfo_obj_t *p_obj)
1007 {
1008 if ( !p_obj ) return NULL;
1009 return p_obj->psd;
1010 }
1011
1012 /*!
1013 Get the extended PSD.
1014 */
1015 uint8_t *
vcdinfo_get_psd_x(const vcdinfo_obj_t * p_obj)1016 vcdinfo_get_psd_x(const vcdinfo_obj_t *p_obj)
1017 {
1018 if ( !p_obj ) return NULL;
1019 return p_obj->psd_x;
1020 }
1021
1022 /*!
1023 Return number of bytes in PSD. Return 0 if there's an error.
1024 */
1025 uint32_t
vcdinfo_get_psd_size(const vcdinfo_obj_t * p_obj)1026 vcdinfo_get_psd_size (const vcdinfo_obj_t *p_obj)
1027 {
1028 if ( !p_obj ) return 0;
1029 return vcdinf_get_psd_size(&(p_obj->info));
1030 }
1031
1032 /*!
1033 Return number of bytes in the extended PSD. Return 0 if there's an error.
1034 */
1035 uint32_t
vcdinfo_get_psd_x_size(const vcdinfo_obj_t * p_obj)1036 vcdinfo_get_psd_x_size (const vcdinfo_obj_t *p_obj)
1037 {
1038 if ( !p_obj ) return 0;
1039 return p_obj->psd_x_size;
1040 }
1041
1042 /*!
1043 Return a string containing the VCD publisher id with trailing
1044 blanks removed, or NULL if there is some problem in getting this.
1045 */
1046 char *
vcdinfo_get_publisher_id(const vcdinfo_obj_t * p_obj)1047 vcdinfo_get_publisher_id(const vcdinfo_obj_t *p_obj)
1048 {
1049 if ( !p_obj ) return (NULL);
1050 return iso9660_get_publisher_id(&(p_obj->pvd));
1051 }
1052
1053 /*!
1054 Get the PSD Selection List Descriptor for a given lid.
1055 NULL is returned if error or not found.
1056 */
1057 static bool
_vcdinfo_lid_get_pxd(const vcdinfo_obj_t * p_obj,PsdListDescriptor_t * pxd,uint16_t lid,bool ext)1058 _vcdinfo_lid_get_pxd(const vcdinfo_obj_t *p_obj, PsdListDescriptor_t *pxd,
1059 uint16_t lid, bool ext)
1060 {
1061 CdioListNode_t *node;
1062 unsigned mult = p_obj->info.offset_mult;
1063 const uint8_t *psd = ext ? p_obj->psd_x : p_obj->psd;
1064 CdioList_t *offset_list = ext ? p_obj->offset_x_list : p_obj->offset_list;
1065
1066 if (offset_list == NULL) return false;
1067
1068 _CDIO_LIST_FOREACH (node, offset_list)
1069 {
1070 vcdinfo_offset_t *ofs = _cdio_list_node_data (node);
1071 unsigned _rofs = ofs->offset * mult;
1072
1073 pxd->descriptor_type = psd[_rofs];
1074
1075 switch (pxd->descriptor_type)
1076 {
1077 case PSD_TYPE_PLAY_LIST:
1078 {
1079 pxd->pld = (PsdPlayListDescriptor_t *) (psd + _rofs);
1080 if (vcdinf_pld_get_lid(pxd->pld) == lid) {
1081 return true;
1082 }
1083 break;
1084 }
1085
1086 case PSD_TYPE_EXT_SELECTION_LIST:
1087 case PSD_TYPE_SELECTION_LIST:
1088 {
1089 pxd->psd = (PsdSelectionListDescriptor_t *) (psd + _rofs);
1090 if (vcdinf_psd_get_lid(pxd->psd) == lid) {
1091 return true;
1092 }
1093 break;
1094 }
1095 default: ;
1096 }
1097 }
1098 return false;
1099 }
1100
1101 /*!
1102 Get the PSD Selection List Descriptor for a given lid.
1103 False is returned if not found.
1104 */
1105 bool
vcdinfo_lid_get_pxd(const vcdinfo_obj_t * p_obj,PsdListDescriptor_t * pxd,uint16_t lid)1106 vcdinfo_lid_get_pxd(const vcdinfo_obj_t *p_obj, PsdListDescriptor_t *pxd,
1107 uint16_t lid)
1108 {
1109 if (_vcdinfo_lid_get_pxd(p_obj, pxd, lid, true))
1110 return true;
1111 return _vcdinfo_lid_get_pxd(p_obj, pxd, lid, false);
1112 }
1113
1114 /**
1115 \fn vcdinfo_get_return_offset(const vcdinfo_obj_t *p_obj);
1116 \brief Get return offset for a given LID.
1117 \return VCDINFO_INVALID_OFFSET is returned on error or if LID has no
1118 "return" entry. Otherwise the LID offset is returned.
1119 */
1120 uint16_t
vcdinfo_get_return_offset(const vcdinfo_obj_t * p_obj,lid_t lid)1121 vcdinfo_get_return_offset(const vcdinfo_obj_t *p_obj, lid_t lid)
1122 {
1123 if (NULL != p_obj) {
1124
1125 PsdListDescriptor_t pxd;
1126
1127 vcdinfo_lid_get_pxd(p_obj, &pxd, lid);
1128
1129 switch (pxd.descriptor_type) {
1130 case PSD_TYPE_PLAY_LIST:
1131 return vcdinf_pld_get_return_offset(pxd.pld);
1132 case PSD_TYPE_SELECTION_LIST:
1133 case PSD_TYPE_EXT_SELECTION_LIST:
1134 return vcdinf_psd_get_return_offset(pxd.psd);
1135 break;
1136 case PSD_TYPE_END_LIST:
1137 case PSD_TYPE_COMMAND_LIST:
1138 break;
1139 }
1140 }
1141
1142 return VCDINFO_INVALID_OFFSET;
1143 }
1144
1145 /*!
1146 Return the audio type for a given segment.
1147 VCDINFO_INVALID_AUDIO_TYPE is returned on error.
1148 */
1149 unsigned int
vcdinfo_get_seg_audio_type(const vcdinfo_obj_t * p_obj,segnum_t i_seg)1150 vcdinfo_get_seg_audio_type(const vcdinfo_obj_t *p_obj, segnum_t i_seg)
1151 {
1152 if ( !p_obj || NULL == &(p_obj->info)
1153 || i_seg >= vcdinfo_get_num_segments(p_obj) )
1154 return VCDINFO_INVALID_AUDIO_TYPE;
1155 return(p_obj->info.spi_contents[i_seg].audio_type);
1156 }
1157
1158 /*!
1159 Return true if this segment is supposed to continue to the next one,
1160 (is part of an "item" or listing in the ISO 9660 filesystem).
1161 */
1162 bool
vcdinfo_get_seg_continue(const vcdinfo_obj_t * p_obj,segnum_t i_seg)1163 vcdinfo_get_seg_continue(const vcdinfo_obj_t *p_obj, segnum_t i_seg)
1164 {
1165 if ( !p_obj || !&(p_obj->info)
1166 || i_seg >= vcdinfo_get_num_segments(p_obj) )
1167 return false;
1168 return(p_obj->info.spi_contents[i_seg].item_cont);
1169 }
1170
1171 /*! Return the starting LBA (logical block address) for segment
1172 entry_num in obj. VCDINFO_LBA_NULL is returned if there is no entry.
1173
1174 Note first i_seg is 0.
1175 */
1176 lba_t
vcdinfo_get_seg_lba(const vcdinfo_obj_t * p_obj,segnum_t i_seg)1177 vcdinfo_get_seg_lba(const vcdinfo_obj_t *p_obj, segnum_t i_seg)
1178 {
1179 if (!p_obj) return VCDINFO_NULL_LBA;
1180 return cdio_lsn_to_lba(vcdinfo_get_seg_lsn(p_obj, i_seg));
1181 }
1182
1183 /*! Return the starting LBA (logical block address) for segment
1184 entry_num in obj. VCDINFO_LSN_NULL is returned if there is no entry.
1185
1186 Note first i_seg is 0.
1187 */
1188 lsn_t
vcdinfo_get_seg_lsn(const vcdinfo_obj_t * p_obj,segnum_t i_seg)1189 vcdinfo_get_seg_lsn(const vcdinfo_obj_t *p_obj, segnum_t i_seg)
1190 {
1191 if (!p_obj || i_seg >= vcdinfo_get_num_segments(p_obj))
1192 return VCDINFO_NULL_LSN;
1193 return p_obj->first_segment_lsn + (VCDINFO_SEGMENT_SECTOR_SIZE * i_seg);
1194 }
1195
1196 /*! Return the starting MSF (minutes/secs/frames) for segment
1197 entry_num in obj. NULL is returned if there is no entry.
1198
1199 Note first i_seg is 0!
1200 */
1201 const msf_t *
vcdinfo_get_seg_msf(const vcdinfo_obj_t * p_obj,segnum_t i_seg)1202 vcdinfo_get_seg_msf(const vcdinfo_obj_t *p_obj, segnum_t i_seg)
1203 {
1204 if (!p_obj || i_seg >= vcdinfo_get_num_segments(p_obj))
1205 return NULL;
1206 else {
1207 lsn_t lsn = vcdinfo_get_seg_lsn(p_obj, i_seg);
1208 static msf_t msf;
1209 cdio_lsn_to_msf(lsn, &msf);
1210 return &msf;
1211 }
1212 }
1213
1214 /*! Return the x-y resolution for a given segment.
1215 Note first i_seg is 0.
1216 */
1217 void
vcdinfo_get_seg_resolution(const vcdinfo_obj_t * p_vcdinfo,segnum_t i_seg,uint16_t * max_x,uint16_t * max_y)1218 vcdinfo_get_seg_resolution(const vcdinfo_obj_t *p_vcdinfo, segnum_t i_seg,
1219 /*out*/ uint16_t *max_x, /*out*/ uint16_t *max_y)
1220 {
1221 vcdinfo_video_segment_type_t segtype
1222 = vcdinfo_get_video_type(p_vcdinfo, i_seg);
1223 segnum_t i_segs = vcdinfo_get_num_segments(p_vcdinfo);
1224
1225 if (i_seg >= i_segs) return;
1226
1227 switch (segtype) {
1228 case VCDINFO_FILES_VIDEO_NTSC_STILL:
1229 *max_x = 704;
1230 *max_y = 480;
1231 break;
1232 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
1233 *max_x = 352;
1234 *max_y = 240;
1235 break;
1236 case VCDINFO_FILES_VIDEO_PAL_STILL:
1237 *max_x = 704;
1238 *max_y = 576;
1239 break;
1240 case VCDINFO_FILES_VIDEO_PAL_STILL2:
1241 *max_x = 352;
1242 *max_y = 288;
1243 break;
1244 default:
1245 /* */
1246 switch (vcdinfo_get_format_version(p_vcdinfo)) {
1247 case VCD_TYPE_VCD:
1248 *max_x = 352;
1249 *max_y = 240;
1250 break;
1251 case VCD_TYPE_VCD11:
1252 case VCD_TYPE_VCD2:
1253 *max_x = 352;
1254 switch(segtype) {
1255 case VCDINFO_FILES_VIDEO_NTSC_MOTION:
1256 *max_y = 240;
1257 break;
1258 case VCDINFO_FILES_VIDEO_PAL_MOTION:
1259 *max_y = 288;
1260 default:
1261 *max_y = 289;
1262 }
1263 break;
1264 default: ;
1265 }
1266 }
1267 }
1268
1269
1270
1271 /*!
1272 Return the number of sectors for segment
1273 entry_num in obj. 0 is returned if there is no entry.
1274
1275 Use this routine to figure out the actual number of bytes a physical
1276 region of a disk or CD takes up for a segment.
1277
1278 If an item has been broken up into a number of "continued" segments,
1279 we will report the item size for the first segment and 0 for the
1280 remaining ones. We may revisit this decision later.
1281 */
1282 uint32_t
vcdinfo_get_seg_sector_count(const vcdinfo_obj_t * p_obj,segnum_t i_seg)1283 vcdinfo_get_seg_sector_count(const vcdinfo_obj_t *p_obj, segnum_t i_seg)
1284 {
1285 if (!p_obj || i_seg >= vcdinfo_get_num_segments(p_obj))
1286 return 0;
1287 return p_obj->seg_sizes[i_seg];
1288 }
1289
1290 /*!
1291 Return a string containing the VCD system id with trailing
1292 blanks removed, or NULL if there is some problem in getting this.
1293 */
1294 char *
vcdinfo_get_system_id(const vcdinfo_obj_t * p_obj)1295 vcdinfo_get_system_id(const vcdinfo_obj_t *p_obj)
1296 {
1297 if ( !p_obj || !&(p_obj->pvd) ) return NULL;
1298 return(iso9660_get_system_id(&p_obj->pvd));
1299 }
1300
1301 /*!
1302 Return the track number for entry n in obj.
1303
1304 In contrast to libcdio we start numbering at 0 which is the
1305 ISO9660 and metadata information for the Video CD. Thus track
1306 1 is the first track the first complete MPEG track generally.
1307 */
1308 track_t
vcdinfo_get_track(const vcdinfo_obj_t * p_obj,const unsigned int entry_num)1309 vcdinfo_get_track(const vcdinfo_obj_t *p_obj, const unsigned int entry_num)
1310 {
1311 const EntriesVcd_t *entries = &p_obj->entries;
1312 const unsigned int entry_count = vcdinf_get_num_entries(entries);
1313 /* Note entry_num is 0 origin. */
1314 return entry_num < entry_count ?
1315 vcdinf_get_track(entries, entry_num)-1: VCDINFO_INVALID_TRACK;
1316 }
1317
1318 /*!
1319 Return the audio type for a given track.
1320 VCDINFO_INVALID_AUDIO_TYPE is returned on error.
1321
1322 Note: track 1 is usually the first track.
1323 */
1324 unsigned int
vcdinfo_get_track_audio_type(const vcdinfo_obj_t * p_obj,track_t i_track)1325 vcdinfo_get_track_audio_type(const vcdinfo_obj_t *p_obj, track_t i_track)
1326 {
1327 TracksSVD_t *tracks;
1328 TracksSVD2_t *tracks2;
1329 if ( !p_obj || !&(p_obj->info) ) return VCDINFO_INVALID_AUDIO_TYPE;
1330 tracks = p_obj->tracks_buf;
1331
1332 if ( NULL == tracks ) return 0;
1333 tracks2 = (TracksSVD2_t *) &(tracks->playing_time[tracks->tracks]);
1334 return(tracks2->contents[i_track-1].audio);
1335 }
1336
1337 /*!
1338 Return the highest track number in the current medium.
1339
1340 Because we track start numbering at 0 (which is the ISO 9660 track
1341 containing Video CD naviagion and disk information), this is one
1342 less than the number of tracks.
1343
1344 If there are no tracks, we return -1.
1345 */
1346 unsigned int
vcdinfo_get_num_tracks(const vcdinfo_obj_t * p_obj)1347 vcdinfo_get_num_tracks(const vcdinfo_obj_t *p_obj)
1348 {
1349 if (!p_obj || !p_obj->img) return 0;
1350
1351 return cdio_get_num_tracks(p_obj->img)-1;
1352 }
1353
1354
1355 /*!
1356 Return the starting LBA (logical block address) for track number
1357 i_track in obj.
1358
1359 The IS0-9660 filesystem track has number 0. Tracks associated
1360 with playable entries numbers start at 1.
1361
1362 The "leadout" track is specified either by
1363 using i_track LEADOUT_TRACK or the total tracks+1.
1364 VCDINFO_NULL_LBA is returned on failure.
1365 */
1366 lba_t
vcdinfo_get_track_lba(const vcdinfo_obj_t * p_obj,track_t i_track)1367 vcdinfo_get_track_lba(const vcdinfo_obj_t *p_obj, track_t i_track)
1368 {
1369 if (!p_obj || !p_obj->img)
1370 return VCDINFO_NULL_LBA;
1371
1372
1373 /* CdIo tracks start at 1 rather than 0. */
1374 return cdio_get_track_lba(p_obj->img, i_track+1);
1375 }
1376
1377 /*!
1378 Return the starting LSN (logical sector number) for track number
1379 i_track in obj.
1380
1381 The IS0-9660 filesystem track has number 0. Tracks associated
1382 with playable entries numbers start at 1.
1383
1384 The "leadout" track is specified either by
1385 using i_track LEADOUT_TRACK or the total tracks+1.
1386 VCDINFO_NULL_LBA is returned on failure.
1387 */
1388 lsn_t
vcdinfo_get_track_lsn(const vcdinfo_obj_t * p_obj,track_t i_track)1389 vcdinfo_get_track_lsn(const vcdinfo_obj_t *p_obj, track_t i_track)
1390 {
1391 if (!p_obj || !p_obj->img)
1392 return VCDINFO_NULL_LSN;
1393
1394 /* CdIo tracks start at 1 rather than 0. */
1395 return cdio_get_track_lsn(p_obj->img, i_track+1);
1396 }
1397
1398 /*!
1399 Return the ending LSN for track number
1400 i_track in cdio. VCDINFO_NULL_LSN is returned on error.
1401 */
vcdinfo_get_track_last_lsn(const vcdinfo_obj_t * p_obj,track_t i_track)1402 lsn_t vcdinfo_get_track_last_lsn(const vcdinfo_obj_t *p_obj, track_t i_track)
1403 {
1404 if (!p_obj || !p_obj->img)
1405 return VCDINFO_NULL_LSN;
1406
1407 /* CdIo tracks start at 1 rather than 0. */
1408 return cdio_get_track_last_lsn(p_obj->img, i_track+1);
1409 }
1410
1411 /*!
1412 Return the starting MSF (minutes/secs/frames) for track number
1413 i_track in obj.
1414
1415 The IS0-9660 filesystem track has number 0. Tracks associated
1416 with playable entries numbers start at 1.
1417
1418 The "leadout" track is specified either by
1419 using i_track LEADOUT_TRACK or the total tracks+1.
1420 VCDINFO_NULL_LBA is returned on failure.
1421 */
1422 int
vcdinfo_get_track_msf(const vcdinfo_obj_t * p_obj,track_t i_track,uint8_t * min,uint8_t * sec,uint8_t * frame)1423 vcdinfo_get_track_msf(const vcdinfo_obj_t *p_obj, track_t i_track,
1424 uint8_t *min, uint8_t *sec, uint8_t *frame)
1425 {
1426 msf_t msf;
1427
1428 if (!p_obj || !p_obj->img)
1429 return 1;
1430
1431 /* CdIo tracks start at 1 rather than 0. */
1432 if (cdio_get_track_msf(p_obj->img, i_track+1, &msf)) {
1433 *min = cdio_from_bcd8(msf.m);
1434 *sec = cdio_from_bcd8(msf.s);
1435 *frame = cdio_from_bcd8(msf.f);
1436 return 0;
1437 }
1438
1439 return 1;
1440 }
1441
1442 /*!
1443 Return the size in sectors for track n.
1444
1445 The IS0-9660 filesystem track has number 0. Tracks associated
1446 with playable entries numbers start at 1.
1447
1448 FIXME: Whether we count the track pregap sectors is a bit haphazard.
1449 We should add a parameter to indicate whether this is wanted or not.
1450
1451 */
1452 unsigned int
vcdinfo_get_track_sect_count(const vcdinfo_obj_t * p_obj,const track_t i_track)1453 vcdinfo_get_track_sect_count(const vcdinfo_obj_t *p_obj,
1454 const track_t i_track)
1455 {
1456 if (!p_obj || VCDINFO_INVALID_TRACK == i_track)
1457 return 0;
1458
1459 {
1460 iso9660_stat_t *p_statbuf;
1461 const lsn_t lsn = vcdinfo_get_track_lsn(p_obj, i_track);
1462
1463 /* Try to get the sector count from the ISO 9660 filesystem */
1464 if (p_obj->has_xa && (p_statbuf = iso9660_find_fs_lsn(p_obj->img, lsn))) {
1465 unsigned int secsize = p_statbuf->secsize;
1466 free(p_statbuf);
1467 return secsize;
1468 } else {
1469 const lsn_t next_lsn=vcdinfo_get_track_lsn(p_obj, i_track+1);
1470 /* Failed on ISO 9660 filesystem. Use track information. */
1471 return next_lsn > lsn ? next_lsn - lsn : 0;
1472 }
1473 }
1474 return 0;
1475 }
1476
1477 /*!
1478 Return size in bytes for track number for entry n in obj.
1479
1480 The IS0-9660 filesystem track has number 1. Tracks associated
1481 with playable entries numbers start at 2.
1482
1483 FIXME: Whether we count the track pregap sectors is a bit haphazard.
1484 We should add a parameter to indicate whether this is wanted or not.
1485 */
1486 unsigned int
vcdinfo_get_track_size(const vcdinfo_obj_t * p_obj,track_t i_track)1487 vcdinfo_get_track_size(const vcdinfo_obj_t *p_obj, track_t i_track)
1488 {
1489 if (NULL == p_obj || VCDINFO_INVALID_TRACK == i_track)
1490 return 0;
1491
1492 {
1493 const lsn_t lsn = cdio_lba_to_lsn(vcdinfo_get_track_lba(p_obj,
1494 i_track));
1495
1496 /* Try to get the sector count from the ISO 9660 filesystem */
1497 if (p_obj->has_xa) {
1498 iso9660_stat_t *p_statbuf;
1499 p_statbuf = iso9660_find_fs_lsn(p_obj->img, lsn);
1500 return p_statbuf->size;
1501 }
1502 #if 0
1503 else {
1504 /* Failed on ISO 9660 filesystem. Use track information. */
1505 if (p_obj->img != NULL)
1506 return cdio_get_track_size(p_obj->img);
1507 }
1508 #endif
1509 }
1510 return 0;
1511 }
1512
1513 /*!
1514 \brief Get the kind of video stream segment of segment i_seg in p_obj.
1515 \return VCDINFO_FILES_VIDEO_INVALID is returned if on error or p_obj is
1516 null. Otherwise the enumeration type.
1517
1518 Note first i_seg is 0!
1519 */
1520 vcdinfo_video_segment_type_t
vcdinfo_get_video_type(const vcdinfo_obj_t * p_obj,segnum_t i_seg)1521 vcdinfo_get_video_type(const vcdinfo_obj_t *p_obj, segnum_t i_seg)
1522 {
1523 const InfoVcd_t *info;
1524 if (p_obj == NULL) return VCDINFO_FILES_VIDEO_INVALID;
1525 info = &p_obj->info;
1526 if (info == NULL) return VCDINFO_FILES_VIDEO_INVALID;
1527 return info->spi_contents[i_seg].video_type;
1528 }
1529
1530 /*!
1531 \brief Get the kind of VCD that p_obj refers to.
1532 */
1533 vcd_type_t
vcdinfo_get_VCD_type(const vcdinfo_obj_t * p_obj)1534 vcdinfo_get_VCD_type(const vcdinfo_obj_t *p_obj)
1535 {
1536 if (NULL == p_obj) return VCD_TYPE_INVALID;
1537 return p_obj->vcd_type;
1538 }
1539
1540
1541 /*!
1542 Return the VCD volume count - the number of CD's in the collection.
1543 O is returned if there is some problem in getting this.
1544 */
1545 unsigned int
vcdinfo_get_volume_count(const vcdinfo_obj_t * p_obj)1546 vcdinfo_get_volume_count(const vcdinfo_obj_t *p_obj)
1547 {
1548 if ( NULL == p_obj ) return 0;
1549 return vcdinf_get_volume_count(&p_obj->info);
1550 }
1551
1552 /*!
1553 Return the VCD ID.
1554 NULL is returned if there is some problem in getting this.
1555 */
1556 const char *
vcdinfo_get_volume_id(const vcdinfo_obj_t * p_obj)1557 vcdinfo_get_volume_id(const vcdinfo_obj_t *p_obj)
1558 {
1559 static char psz_vol_id[ISO_MAX_VOLUME_ID+1] = {'\0'};
1560 char *psz_vol_id2;
1561 if ( NULL == p_obj || NULL == &p_obj->pvd ) return (NULL);
1562 psz_vol_id2 = iso9660_get_volume_id(&p_obj->pvd);
1563 strncpy(psz_vol_id, psz_vol_id2, ISO_MAX_VOLUME_ID);
1564 free(psz_vol_id2);
1565 return psz_vol_id;
1566 }
1567
1568 /*!
1569 Return the VCD volumeset ID.
1570 NULL is returned if there is some problem in getting this.
1571 */
1572 const char *
vcdinfo_get_volumeset_id(const vcdinfo_obj_t * p_obj)1573 vcdinfo_get_volumeset_id(const vcdinfo_obj_t *p_obj)
1574 {
1575 static char volume_set_id[ISO_MAX_VOLUMESET_ID+1] = {'\0'};
1576 if ( NULL == p_obj || NULL == &p_obj->pvd ) return (NULL);
1577 strncpy(volume_set_id, p_obj->pvd.volume_set_id, ISO_MAX_VOLUMESET_ID);
1578 return vcdinfo_strip_trail(volume_set_id, ISO_MAX_VOLUMESET_ID);
1579 }
1580
1581 /*!
1582 Return the VCD volume num - the number of the CD in the collection.
1583 This is a number between 1 and the volume count.
1584 O is returned if there is some problem in getting this.
1585 */
1586 unsigned int
vcdinfo_get_volume_num(const vcdinfo_obj_t * p_obj)1587 vcdinfo_get_volume_num(const vcdinfo_obj_t *p_obj)
1588 {
1589 if ( NULL == p_obj ) return 0;
1590 return(uint16_from_be( p_obj->info.vol_id));
1591 }
1592
1593 int
vcdinfo_get_wait_time(uint16_t wtime)1594 vcdinfo_get_wait_time (uint16_t wtime)
1595 {
1596 /* Note: this doesn't agree exactly with _wtime */
1597 if (wtime < 61)
1598 return wtime;
1599 else if (wtime < 255)
1600 return (wtime - 60) * 10 + 60;
1601 else
1602 return -1;
1603 }
1604
1605 /*!
1606 Return true is there is playback control.
1607 */
1608 bool
vcdinfo_has_pbc(const vcdinfo_obj_t * p_obj)1609 vcdinfo_has_pbc (const vcdinfo_obj_t *p_obj)
1610 {
1611 return (p_obj && p_obj->info.psd_size!=0);
1612 }
1613
1614 /*!
1615 Return true if VCD has "extended attributes" (XA). Extended attributes
1616 add meta-data attributes to a entries of file describing the file.
1617 See also cdio_get_xa_attr_str() which returns a string similar to
1618 a string you might get on a Unix filesystem listing ("ls").
1619 */
1620 bool
vcdinfo_has_xa(const vcdinfo_obj_t * p_obj)1621 vcdinfo_has_xa(const vcdinfo_obj_t *p_obj)
1622 {
1623 return p_obj->has_xa;
1624 }
1625
1626 /*!
1627 Add one to the MSF.
1628 */
1629 void
vcdinfo_inc_msf(uint8_t * p_min,uint8_t * p_sec,int8_t * p_frame)1630 vcdinfo_inc_msf (uint8_t *p_min, uint8_t *p_sec, int8_t *p_frame)
1631 {
1632 (*p_frame)++;
1633 if (*p_frame>=CDIO_CD_FRAMES_PER_SEC) {
1634 *p_frame = 0;
1635 (*p_sec)++;
1636 if (*p_sec>=CDIO_CD_SECS_PER_MIN) {
1637 *p_sec = 0;
1638 (*p_min)++;
1639 }
1640 }
1641 }
1642
1643 const char *
vcdinfo_ofs2str(const vcdinfo_obj_t * p_obj,unsigned int offset,bool ext)1644 vcdinfo_ofs2str (const vcdinfo_obj_t *p_obj, unsigned int offset, bool ext)
1645 {
1646 vcdinfo_offset_t *ofs;
1647 char *buf;
1648
1649 switch (offset) {
1650 case PSD_OFS_DISABLED:
1651 return "disabled";
1652 case PSD_OFS_MULTI_DEF:
1653 return "multi-default";
1654 case PSD_OFS_MULTI_DEF_NO_NUM:
1655 return "multi_def_no_num";
1656 default: ;
1657 }
1658
1659 buf = _getbuf ();
1660 ofs = _vcdinfo_get_offset_t(p_obj, offset, ext);
1661 if (ofs != NULL) {
1662 if (ofs->lid)
1663 snprintf (buf, BUF_SIZE, "LID[%d] @0x%4.4x",
1664 ofs->lid, ofs->offset);
1665 else
1666 snprintf (buf, BUF_SIZE, "PSD[?] @0x%4.4x",
1667 ofs->offset);
1668 } else {
1669 snprintf (buf, BUF_SIZE, "? @0x%4.4x", offset);
1670 }
1671 return buf;
1672 }
1673
1674 bool
vcdinfo_read_psd(vcdinfo_obj_t * p_obj)1675 vcdinfo_read_psd (vcdinfo_obj_t *p_obj)
1676 {
1677 unsigned psd_size = vcdinfo_get_psd_size (p_obj);
1678
1679 if (psd_size)
1680 {
1681 if (psd_size > 256*1024)
1682 {
1683 vcd_error ("weird psd size (%u) -- aborting", psd_size);
1684 return false;
1685 }
1686
1687 free(p_obj->lot);
1688 p_obj->lot = calloc(1, ISO_BLOCKSIZE * LOT_VCD_SIZE);
1689 free(p_obj->psd);
1690 p_obj->psd = calloc(1, ISO_BLOCKSIZE * _vcd_len2blocks (psd_size,
1691 ISO_BLOCKSIZE));
1692
1693 if (cdio_read_mode2_sectors (p_obj->img, (void *) p_obj->lot, LOT_VCD_SECTOR,
1694 false, LOT_VCD_SIZE))
1695 return false;
1696
1697 if (cdio_read_mode2_sectors (p_obj->img, (void *) p_obj->psd, PSD_VCD_SECTOR,
1698 false, _vcd_len2blocks (psd_size,
1699 ISO_BLOCKSIZE)))
1700 return false;
1701
1702 } else {
1703 return false;
1704 }
1705 return true;
1706 }
1707
1708 /*! Return the entry number for the given track. */
1709 unsigned int
vcdinfo_track_get_entry(const vcdinfo_obj_t * p_obj,track_t i_track)1710 vcdinfo_track_get_entry(const vcdinfo_obj_t *p_obj, track_t i_track)
1711 {
1712 /* FIXME: Add structure to directly map track to first entry number.
1713 Until then...
1714 */
1715 lsn_t lsn= vcdinfo_get_track_lsn(p_obj, i_track);
1716 return vcdinfo_lsn_get_entry(p_obj, lsn);
1717 }
1718
1719 /*!
1720 Calls recursive routine to populate obj->offset_list or obj->offset_x_list
1721 by going through LOT.
1722
1723 Returns false if there was some error.
1724 */
1725 bool
vcdinfo_visit_lot(vcdinfo_obj_t * p_obj,bool extended)1726 vcdinfo_visit_lot (vcdinfo_obj_t *p_obj, bool extended)
1727 {
1728 struct _vcdinf_pbc_ctx pbc_ctx;
1729 bool ret;
1730
1731 pbc_ctx.psd_size = vcdinfo_get_psd_size (p_obj);
1732 pbc_ctx.psd_x_size = p_obj->psd_x_size;
1733 pbc_ctx.offset_mult = 8;
1734 pbc_ctx.maximum_lid = vcdinfo_get_num_LIDs(p_obj);
1735 pbc_ctx.offset_x_list = NULL;
1736 pbc_ctx.offset_list = NULL;
1737 pbc_ctx.psd = p_obj->psd;
1738 pbc_ctx.psd_x = p_obj->psd_x;
1739 pbc_ctx.lot = p_obj->lot;
1740 pbc_ctx.lot_x = p_obj->lot_x;
1741 pbc_ctx.extended = extended;
1742
1743 ret = vcdinf_visit_lot(&pbc_ctx);
1744 if (NULL != p_obj->offset_x_list)
1745 _cdio_list_free(p_obj->offset_x_list, true, NULL);
1746 p_obj->offset_x_list = pbc_ctx.offset_x_list;
1747 if (NULL != p_obj->offset_list)
1748 _cdio_list_free(p_obj->offset_list, true, NULL);
1749 p_obj->offset_list = pbc_ctx.offset_list;
1750 return ret;
1751 }
1752
1753 /*!
1754 Change trailing blanks in str to nulls. Str has a maximum size of
1755 n characters.
1756 */
1757 const char *
vcdinfo_strip_trail(const char str[],size_t n)1758 vcdinfo_strip_trail (const char str[], size_t n)
1759 {
1760 static char buf[1024];
1761 int j;
1762
1763 vcd_assert (n < 1024);
1764
1765 strncpy (buf, str, n);
1766 buf[n] = '\0';
1767
1768 for (j = strlen (buf) - 1; j >= 0; j--)
1769 {
1770 if (buf[j] != ' ')
1771 break;
1772
1773 buf[j] = '\0';
1774 }
1775
1776 return buf;
1777 }
1778
1779 /*!
1780 Return true if offset is "rejected". That is shouldn't be displayed
1781 in a list of entries.
1782 */
1783 bool
vcdinfo_is_rejected(uint16_t offset)1784 vcdinfo_is_rejected(uint16_t offset)
1785 {
1786 return (offset & VCDINFO_REJECTED_MASK) != 0;
1787 }
1788
1789 /*!
1790 Nulls/zeros vcdinfo_obj_t structures; The caller should have
1791 ensured that p_obj != NULL.
1792 routines using p_obj are called.
1793 */
1794 static void
_vcdinfo_zero(vcdinfo_obj_t * p_obj)1795 _vcdinfo_zero(vcdinfo_obj_t *p_obj)
1796 {
1797 memset(p_obj, 0, sizeof(vcdinfo_obj_t));
1798 p_obj->vcd_type = VCD_TYPE_INVALID;
1799 p_obj->img = NULL;
1800 p_obj->lot = NULL;
1801 p_obj->source_name = NULL;
1802 p_obj->seg_sizes = NULL;
1803 }
1804
1805 /*!
1806 Initialize the vcdinfo structure "obj". Should be done before other
1807 routines using p_obj are called.
1808 */
1809 bool
vcdinfo_init(vcdinfo_obj_t * p_obj)1810 vcdinfo_init(vcdinfo_obj_t *p_obj)
1811 {
1812 if (NULL == p_obj) return false;
1813 _vcdinfo_zero(p_obj);
1814 return cdio_init();
1815 }
1816
1817 /*!
1818 Set up vcdinfo structure "p_obj" for reading from a particular
1819 medium. This should be done before after initialization but before
1820 any routines that need to retrieve data.
1821
1822 source_name is the device or file to use for inspection, and
1823 source_type indicates what driver to use or class of drivers in the
1824 case of DRIVER_DEVICE.
1825 access_mode gives the CD access method for reading should the driver
1826 allow for more than one kind of access method (e.g. MMC versus ioctl
1827 on GNU/Linux)
1828
1829 If source_name is NULL we'll fill in the appropriate default device
1830 name for the given source_type. However if in addtion source_type is
1831 DRIVER_UNKNOWN, then we'll scan for a drive containing a VCD.
1832
1833 VCDINFO_OPEN_VCD is returned if everything went okay;
1834 VCDINFO_OPEN_ERROR if there was an error and VCDINFO_OPEN_OTHER if the
1835 medium is something other than a VCD.
1836
1837 Only if VCDINFO_OPEN_VCD is returned, the caller needs free the
1838 vcdinfo_obj_t.
1839 */
1840 vcdinfo_open_return_t
vcdinfo_open(vcdinfo_obj_t ** pp_obj,char * source_name[],driver_id_t source_type,const char access_mode[])1841 vcdinfo_open(vcdinfo_obj_t **pp_obj, char *source_name[],
1842 driver_id_t source_type, const char access_mode[])
1843 {
1844 CdIo_t *p_cdio;
1845 vcdinfo_obj_t *p_obj = calloc(1, sizeof(vcdinfo_obj_t));
1846 iso9660_stat_t *statbuf;
1847 bool free_source_name = false;
1848
1849 /* If we don't specify a driver_id or a source_name, scan the
1850 system for a CD that contains a VCD.
1851 */
1852 if (NULL == *source_name && source_type == DRIVER_UNKNOWN) {
1853 char **cd_drives=NULL;
1854 cd_drives = cdio_get_devices_with_cap_ret(NULL,
1855 (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD|CDIO_FS_ANAL_VIDEOCD
1856 |CDIO_FS_UNKNOWN),
1857 true, &source_type);
1858 if ( NULL == cd_drives || NULL == cd_drives[0] ) {
1859 goto err_return;
1860 }
1861 *source_name = strdup(cd_drives[0]);
1862 free_source_name = true;
1863 cdio_free_device_list(cd_drives);
1864 }
1865
1866 p_cdio = cdio_open(*source_name, source_type);
1867 if (NULL == p_cdio) {
1868 goto err_return;
1869 }
1870
1871 *pp_obj = p_obj;
1872
1873 if (access_mode != NULL)
1874 cdio_set_arg (p_cdio, "access-mode", access_mode);
1875
1876 if (NULL == *source_name) {
1877 *source_name = cdio_get_default_device(p_cdio);
1878 if (NULL == *source_name) {
1879 goto err_return;
1880 }
1881 free_source_name = true;
1882 }
1883
1884 memset (p_obj, 0, sizeof (vcdinfo_obj_t));
1885 p_obj->img = p_cdio; /* Note we do this after the above wipeout! */
1886
1887 if (!iso9660_fs_read_pvd(p_obj->img, &(p_obj->pvd))) {
1888 goto err_return;
1889 }
1890
1891 /* Determine if VCD has XA attributes. */
1892 {
1893
1894 iso9660_pvd_t const *pvd = &p_obj->pvd;
1895
1896 p_obj->has_xa = !strncmp ((char *) pvd + ISO_XA_MARKER_OFFSET,
1897 ISO_XA_MARKER_STRING,
1898 strlen (ISO_XA_MARKER_STRING));
1899 }
1900
1901 if (!read_info(p_obj->img, &(p_obj->info), &(p_obj->vcd_type)))
1902 goto other_return;
1903
1904 if (vcdinfo_get_format_version (p_obj) == VCD_TYPE_INVALID)
1905 goto other_return;
1906
1907 if (!read_entries(p_obj->img, &(p_obj->entries)))
1908 goto other_return;
1909
1910 {
1911 size_t len = strlen(*source_name)+1;
1912 p_obj->source_name = (char *) malloc(len * sizeof(char));
1913 strncpy(p_obj->source_name, *source_name, len);
1914 }
1915
1916 if (p_obj->vcd_type == VCD_TYPE_SVCD || p_obj->vcd_type == VCD_TYPE_HQVCD) {
1917 statbuf = iso9660_fs_stat (p_obj->img, "MPEGAV");
1918
1919 if (NULL != statbuf) {
1920 vcd_warn ("non compliant /MPEGAV folder detected!");
1921 free(statbuf);
1922 }
1923
1924
1925 statbuf = iso9660_fs_stat (p_obj->img, "SVCD/TRACKS.SVD;1");
1926 if (NULL != statbuf) {
1927 lsn_t lsn = statbuf->lsn;
1928 if (statbuf->size != ISO_BLOCKSIZE)
1929 vcd_warn ("TRACKS.SVD filesize != %d!", ISO_BLOCKSIZE);
1930
1931 p_obj->tracks_buf = calloc(1, ISO_BLOCKSIZE);
1932
1933 free(statbuf);
1934 if (cdio_read_mode2_sector (p_obj->img, p_obj->tracks_buf, lsn, false))
1935 goto err_return;
1936 }
1937 }
1938
1939 _init_segments (p_obj);
1940
1941 switch (p_obj->vcd_type) {
1942 case VCD_TYPE_VCD2: {
1943 /* FIXME: Can reduce CD reads by using
1944 iso9660_fs_readdir(img, "EXT", true) and then scanning for
1945 the files listed below.
1946 */
1947 statbuf = iso9660_fs_stat (p_cdio, "EXT/PSD_X.VCD;1");
1948 if (NULL != statbuf) {
1949 lsn_t lsn = statbuf->lsn;
1950 uint32_t secsize = statbuf->secsize;
1951
1952 p_obj->psd_x = calloc(1, ISO_BLOCKSIZE * secsize);
1953 p_obj->psd_x_size = statbuf->size;
1954
1955 vcd_debug ("found /EXT/PSD_X.VCD at sector %lu",
1956 (long unsigned int) lsn);
1957
1958 free(statbuf);
1959 if (cdio_read_mode2_sectors (p_cdio, p_obj->psd_x, lsn, false, secsize))
1960 goto err_return;
1961 }
1962
1963 statbuf = iso9660_fs_stat (p_cdio, "EXT/LOT_X.VCD;1");
1964 if (NULL != statbuf) {
1965 lsn_t lsn = statbuf->lsn;
1966 uint32_t secsize = statbuf->secsize;
1967 p_obj->lot_x = calloc(1, ISO_BLOCKSIZE * secsize);
1968
1969 vcd_debug ("found /EXT/LOT_X.VCD at sector %lu",
1970 (unsigned long int) lsn);
1971
1972 if (statbuf->size != LOT_VCD_SIZE * ISO_BLOCKSIZE)
1973 vcd_warn ("LOT_X.VCD size != 65535");
1974
1975 free(statbuf);
1976 if (cdio_read_mode2_sectors (p_cdio, p_obj->lot_x, lsn, false, secsize))
1977 goto err_return;
1978
1979 }
1980 break;
1981 }
1982 case VCD_TYPE_SVCD:
1983 case VCD_TYPE_HQVCD: {
1984 /* FIXME: Can reduce CD reads by using
1985 iso9660_fs_readdir(p_cdio, "SVCD", true) and then scanning for
1986 the files listed below.
1987 */
1988 statbuf = iso9660_fs_stat (p_cdio, "MPEGAV");
1989 if (NULL != statbuf) {
1990 vcd_warn ("non compliant /MPEGAV folder detected!");
1991 free(statbuf);
1992 }
1993
1994 statbuf = iso9660_fs_stat (p_cdio, "SVCD/TRACKS.SVD;1");
1995 if (NULL == statbuf)
1996 vcd_warn ("mandatory /SVCD/TRACKS.SVD not found!");
1997 else {
1998 vcd_debug ("found TRACKS.SVD signature at sector %lu",
1999 (unsigned long int) statbuf->lsn);
2000 free(statbuf);
2001 }
2002
2003 statbuf = iso9660_fs_stat (p_cdio, "SVCD/SEARCH.DAT;1");
2004 if (NULL == statbuf)
2005 vcd_warn ("mandatory /SVCD/SEARCH.DAT not found!");
2006 else {
2007 lsn_t lsn = statbuf->lsn;
2008 uint32_t secsize = statbuf->secsize;
2009 uint32_t stat_size = statbuf->size;
2010 uint32_t size;
2011
2012 vcd_debug ("found SEARCH.DAT at sector %lu", (unsigned long int) lsn);
2013
2014 p_obj->search_buf = calloc(1, ISO_BLOCKSIZE * secsize);
2015
2016 if (cdio_read_mode2_sectors (p_cdio, p_obj->search_buf, lsn, false, secsize))
2017 goto err_return;
2018
2019 size = (3 * uint16_from_be (((SearchDat_t *)p_obj->search_buf)->scan_points))
2020 + sizeof (SearchDat_t);
2021
2022 free(statbuf);
2023 if (size > stat_size) {
2024 vcd_warn ("number of scanpoints leads to bigger size than "
2025 "file size of SEARCH.DAT! -- rereading");
2026
2027 free (p_obj->search_buf);
2028 p_obj->search_buf = calloc(1, ISO_BLOCKSIZE
2029 * _vcd_len2blocks(size, ISO_BLOCKSIZE));
2030
2031 if (cdio_read_mode2_sectors (p_cdio, p_obj->search_buf, lsn, false,
2032 secsize))
2033 goto err_return;
2034 }
2035 }
2036 break;
2037 }
2038 default:
2039 ;
2040 }
2041
2042 statbuf = iso9660_fs_stat (p_cdio, "EXT/SCANDATA.DAT;1");
2043 if (statbuf != NULL) {
2044 lsn_t lsn = statbuf->lsn;
2045 uint32_t secsize = statbuf->secsize;
2046
2047 vcd_debug ("found /EXT/SCANDATA.DAT at sector %u", (unsigned int) lsn);
2048
2049 p_obj->scandata_buf = calloc(1, ISO_BLOCKSIZE * secsize);
2050
2051 free(statbuf);
2052 if (cdio_read_mode2_sectors (p_cdio, p_obj->scandata_buf, lsn, false,
2053 secsize))
2054 return VCDINFO_OPEN_ERROR;
2055 }
2056
2057 return VCDINFO_OPEN_VCD;
2058
2059 other_return:
2060 vcdinfo_close(p_obj);
2061 return VCDINFO_OPEN_OTHER;
2062
2063 err_return:
2064 if (free_source_name && *source_name) free(*source_name);
2065 vcdinfo_close(p_obj);
2066 return VCDINFO_OPEN_ERROR;
2067
2068
2069 }
2070
2071 /*!
2072 Dispose of any resources associated with vcdinfo structure "p_obj".
2073 Call this when "p_obj" it isn't needed anymore.
2074
2075 True is returned is everything went okay, and false if not.
2076 */
2077 bool
vcdinfo_close(vcdinfo_obj_t * p_obj)2078 vcdinfo_close(vcdinfo_obj_t *p_obj)
2079 {
2080 if (p_obj != NULL) {
2081 if (p_obj->offset_list != NULL)
2082 _cdio_list_free(p_obj->offset_list, true, NULL);
2083 if (p_obj->offset_x_list != NULL)
2084 _cdio_list_free(p_obj->offset_x_list, true, NULL);
2085 CDIO_FREE_IF_NOT_NULL(p_obj->seg_sizes);
2086 CDIO_FREE_IF_NOT_NULL(p_obj->lot);
2087 CDIO_FREE_IF_NOT_NULL(p_obj->lot_x);
2088 CDIO_FREE_IF_NOT_NULL(p_obj->psd_x);
2089 CDIO_FREE_IF_NOT_NULL(p_obj->psd);
2090 CDIO_FREE_IF_NOT_NULL(p_obj->scandata_buf);
2091 CDIO_FREE_IF_NOT_NULL(p_obj->tracks_buf);
2092 CDIO_FREE_IF_NOT_NULL(p_obj->search_buf);
2093 CDIO_FREE_IF_NOT_NULL(p_obj->source_name);
2094
2095 if (p_obj->img != NULL) cdio_destroy (p_obj->img);
2096 _vcdinfo_zero(p_obj);
2097 }
2098
2099 free(p_obj);
2100 return(true);
2101 }
2102
2103 /*! Return the selection number of the area that a point is enclosed in.
2104 In short we return < 0 on an error of some kind.
2105 If the VCD contains no extended selection list return -1.
2106 If we are not in an extended selection list LID, return -2.
2107 If there no area encloses the point return -3
2108
2109 max_x, max_y are the maximum values that x and y can take on.
2110 They would be the largest coordinate in the screen coordinate space.
2111 For example they might be 352, 240 (for VCD) or 704, 480 for SVCD NTSC,
2112 or 704, 576.
2113 */
2114 int
vcdinfo_get_area_selection(const vcdinfo_obj_t * p_vcdinfo,lid_t lid,int16_t x,int16_t y,uint16_t max_x,uint16_t max_y)2115 vcdinfo_get_area_selection(const vcdinfo_obj_t *p_vcdinfo,
2116 lid_t lid, int16_t x, int16_t y,
2117 uint16_t max_x, uint16_t max_y)
2118 {
2119 /* dbg_print(INPUT_DBG_CALL, "Called\n"); */
2120 PsdListDescriptor_t pxd;
2121 if (! vcdinfo_lid_get_pxd(p_vcdinfo, &pxd, lid) )
2122 return -1;
2123 if (pxd.descriptor_type != PSD_TYPE_EXT_SELECTION_LIST &&
2124 !pxd.psd->flags.SelectionAreaFlag)
2125 return -2;
2126 {
2127 const PsdSelectionListDescriptorExtended_t *d2 =
2128 (const void *) &(pxd.psd->ofs[pxd.psd->nos]);
2129 const int32_t scaled_x = x * 255 / max_x;
2130 const int32_t scaled_y = y * 255 / max_y;
2131 const int n = vcdinf_get_num_selections(pxd.psd);
2132 int i;
2133 vcd_debug("max x %d, max y %d, scaled x: %d, scaled y %d",
2134 max_x, max_y, (int) scaled_x, (int) scaled_y);
2135 for (i = 0; i < n; i++) {
2136 vcd_debug("x1: %d, y1 %d, x2: %d, y2 %d",
2137 d2->area[i].x1, d2->area[i].y1, d2->area[i].y2, d2->area[i].y2 );
2138 if (d2->area[i].x1 <= scaled_x &&
2139 d2->area[i].y1 <= scaled_y &&
2140 d2->area[i].x2 >= scaled_x &&
2141 d2->area[i].y2 >= scaled_y ) {
2142 return i + vcdinf_get_bsn(pxd.psd);
2143 }
2144 }
2145 }
2146 return -3;
2147
2148 }
2149
2150
2151 /*
2152 * Local variables:
2153 * c-file-style: "gnu"
2154 * tab-width: 8
2155 * indent-tabs-mode: nil
2156 * End:
2157 */
2158