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