1 /*
2 Copyright (C) 2002, 2003, 2004, 2005, 2006, 2018
3 Rocky Bernstein <rocky@gnu.org>
4 Copyright (C) 2001, 2002 Herbert Valerio Riedel <hvr@gnu.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Foundation
18 Software, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #include <stdio.h>
26 #ifdef HAVE_STDLIB_H
27 #include <stdlib.h>
28 #endif
29 #ifdef HAVE_STRING_H
30 #include <string.h>
31 #endif
32 #include <stddef.h>
33
34 #include <popt.h>
35 /* Accomodate to older popt that doesn't support the "optional" flag */
36 #ifndef POPT_ARGFLAG_OPTIONAL
37 #define POPT_ARGFLAG_OPTIONAL 0
38 #endif
39
40 /* We don't want to pull in cdio's config */
41 #define __CDIO_CONFIG_H__
42 #include <cdio/cdio.h>
43 #include <cdio/bytesex.h>
44 #include <cdio/iso9660.h>
45
46 /* Eventually move above libvcd includes but having vcdinfo including. */
47 #include <libvcd/info.h>
48 #include <libvcd/files.h>
49
50 /* FIXME */
51 #include <libvcd/files_private.h>
52
53 /* Private headers */
54 #include "bitvec.h"
55 #include "pbc.h"
56
57 static const char _rcsid[] = "$Id$";
58
59 static const char DELIM[] = \
60 "----------------------------------------" \
61 "---------------------------------------\n";
62
63 /* global static vars */
64 static struct gl_t
65 {
66 int source_type;
67 char *access_mode;
68
69 /* Boolean values set by command-line options to reduce output.
70 Note: because these are used by popt, the datatype here has to be
71 int, not bool.
72 */
73 uint32_t debug_level;
74 int no_ext_psd_flag; /* Ignore information in /EXT/PSD_X.VCD */
75 int quiet_flag;
76 int suppress_warnings;
77
78 struct show_t
79 {
80 int all; /* True makes all of the below "show" variables true. */
81
82 struct no_t /* Switches that are on by default and you turn off. */
83 {
84 int banner; /* True supresses initial program banner and Id */
85 int delimiter; /* True supresses delimiters between sections */
86 int header; /* True supresses the section headers */
87 } no;
88
89 struct entries_t /* Switches for the ENTRIES section. */
90 {
91 int any; /* True if any of the below variables are set true. */
92 int all; /* True makes all of the below variables set true. */
93 int count; /* Show total number of entries. */
94 int data; /* Show all of the entry points . */
95 int id; /* Show INFO Id */
96 int prof; /* Show system profile tag. */
97 int vers; /* Show version */
98 } entries;
99
100 struct info_t /* Switches for the INFO section. */
101 {
102 int any;
103 int all;
104 int album; /* Show album description info. */
105 int cc; /* Show data cc. */
106 int count; /* Show volume count */
107 int id; /* Show ID */
108 int ofm; /* Show offset multiplier */
109 int lid2; /* Show start LID #2 */
110 int lidn; /* Show maximum LID */
111 int pal; /* Show PAL flags and reserved1 */
112 int pbc; /* Show reserved2 or extended pbc */
113 int prof; /* Show system profile flag */
114 int psds; /* Show PSD size. */
115 int res; /* Show restriction */
116 int seg; /* Show first segment address */
117 int segn; /* Show number of segments */
118 int segs; /* Show segments */
119 int spec; /* Show special info */
120 int start; /* Show volume start times */
121 int st2; /* Show start track #2 */
122 int vers; /* Show INFO version. */
123 int vol; /* Show volume number */
124 } info;
125
126 struct pvd_t /* Switches for the PVD section. */
127 {
128 int any; /* True if any of the below variables are set true. */
129 int all; /* True makes all of the below variables set true. */
130 int app; /* show application ID */
131 int id; /* show PVD ID */
132 int iso; /* Show ISO size */
133 int prep; /* Show preparer ID */
134 int pub; /* Show publisher ID */
135 int sys; /* Show system id */
136 int vers; /* Show version number */
137 int vol; /* Show volume ID */
138 int volset; /* Show volumeset ID */
139 int xa; /* Show if XA marker is present. */
140 } pvd;
141
142 int format; /* Show VCD format VCD 1.1, VCD 2.0, SVCD, ... */
143 int fs;
144 int lot;
145 int psd; /* Show PSD group -- needs to be broken out. */
146 int scandata; /* Show scan data group -- needs to broken out. */
147 int search;
148 int source; /* Show image source and size. */
149 int tracks;
150 } show;
151
152 }
153 gl; /* global variables */
154
155 poptContext optCon;
156
157 /* end of vars */
158
159
160 #define PRINTED_POINTS 15
161
162
163 static bool
_bitset_get_bit(const uint8_t bitvec[],int bit)164 _bitset_get_bit (const uint8_t bitvec[], int bit)
165 {
166 bool result = false;
167
168 if (_vcd_bit_set_p (bitvec[bit / 8], (bit % 8)))
169 result = true;
170
171 return result;
172 }
173
174 /******************************************************************************/
175 static void
_hexdump(const void * data,unsigned len)176 _hexdump (const void *data, unsigned len)
177 {
178 unsigned n;
179 const uint8_t *bytes = data;
180
181 for (n = 0; n < len; n++)
182 {
183 if (n % 8 == 0)
184 fprintf (stdout, " ");
185 fprintf (stdout, "%2.2x ", bytes[n]);
186 }
187 }
188
189 typedef enum {
190 PBC_VCD2_NO_PBC, /* NO PBC */
191 PBC_VCD2_EXT, /* Has extended PBC for VCD 2.0 */
192 PBC_VCD2_NOPE, /* Is not VCD 2.0 */
193 PBC_VCD2_NO_LOT_X, /* EXT/LOT_X.VCD doesn't exist */
194 PBC_VCD2_NO_PSD_X, /* EXT/PSD_X.VCD doesn't exist */
195 PBC_VCD2_BAD_LOT_SIZE /* LOT_VCD_SIZE*BLOCKSIZE != size */
196 } vcd2_ext_pbc_status_t;
197
198 static vcd2_ext_pbc_status_t
_has_vcd2_ext_pbc(const vcdinfo_obj_t * p_vcdinfo)199 _has_vcd2_ext_pbc (const vcdinfo_obj_t *p_vcdinfo)
200 {
201 iso9660_stat_t *statbuf;
202 CdIo_t *p_cdio;
203 vcd2_ext_pbc_status_t ret_status;
204
205 if (!vcdinfo_has_pbc(p_vcdinfo))
206 return PBC_VCD2_NO_PBC;
207
208 if (vcdinfo_get_VCD_type(p_vcdinfo) != VCD_TYPE_VCD2)
209 return PBC_VCD2_NOPE;
210
211 p_cdio = vcdinfo_get_cd_image(p_vcdinfo);
212 statbuf = iso9660_fs_stat (p_cdio, "EXT/LOT_X.VCD;1");
213 if (NULL == statbuf)
214 return PBC_VCD2_NO_LOT_X;
215 if (statbuf->size != ISO_BLOCKSIZE * LOT_VCD_SIZE) {
216 ret_status = PBC_VCD2_BAD_LOT_SIZE;
217 } else {
218 free(statbuf);
219 statbuf = iso9660_fs_stat (p_cdio, "EXT/PSD_X.VCD;1");
220 if (NULL != statbuf) {
221 ret_status = PBC_VCD2_EXT;
222 } else {
223 ret_status = PBC_VCD2_NO_PSD_X;
224 }
225 }
226 free(statbuf);
227 return ret_status;
228 }
229
230
231
232 static void
dump_lot(const vcdinfo_obj_t * p_vcdinfo,bool ext)233 dump_lot (const vcdinfo_obj_t *p_vcdinfo, bool ext)
234 {
235 const LotVcd_t *lot = ext
236 ? vcdinfo_get_lot_x(p_vcdinfo) : vcdinfo_get_lot(p_vcdinfo);
237
238 unsigned n, tmp;
239 const uint16_t max_lid = vcdinfo_get_num_LIDs(p_vcdinfo);
240 unsigned int mult = vcdinfo_get_offset_mult(p_vcdinfo);
241
242 if (!gl.show.no.header)
243 fprintf (stdout,
244 (vcdinfo_get_VCD_type(p_vcdinfo) == VCD_TYPE_SVCD
245 || vcdinfo_get_VCD_type(p_vcdinfo) == VCD_TYPE_HQVCD)
246 ? "SVCD/LOT.SVD\n"
247 : (ext ? "EXT/LOT_X.VCD\n": "VCD/LOT.VCD\n"));
248
249 if (lot->reserved)
250 fprintf (stdout, " RESERVED = 0x%4.4x (should be 0x0000)\n",
251 uint16_from_be (lot->reserved));
252
253 for (n = 0; n < LOT_VCD_OFFSETS; n++)
254 {
255 if ((tmp = uint16_from_be (lot->offset[n])) != PSD_OFS_DISABLED)
256 {
257 if (!n && tmp)
258 fprintf (stdout, "warning, LID[1] should have offset = 0!\n");
259
260 if (n >= max_lid)
261 fprintf (stdout,
262 "warning, the following entry is greater than the maximum lid field in info\n");
263 fprintf (stdout, " LID[%d]: offset = %d (0x%4.4x)\n",
264 n + 1, tmp * mult, tmp);
265 }
266 else if (n < max_lid)
267 fprintf (stdout, " LID[%d]: rejected\n", n + 1);
268 }
269 }
270
271 static void
dump_psd(const vcdinfo_obj_t * p_vcdinfo,bool ext)272 dump_psd (const vcdinfo_obj_t *p_vcdinfo, bool ext)
273 {
274 CdioListNode_t *node;
275 unsigned n = 0;
276 unsigned int mult;
277 uint8_t *psd;
278 CdioList_t *offset_list;
279
280 if (!p_vcdinfo) return;
281
282 mult = vcdinfo_get_offset_mult(p_vcdinfo);
283 psd = ext ? vcdinfo_get_psd_x(p_vcdinfo) : vcdinfo_get_psd(p_vcdinfo);
284 offset_list = ext
285 ? vcdinfo_get_offset_x_list(p_vcdinfo)
286 : vcdinfo_get_offset_list(p_vcdinfo);
287
288 fprintf (stdout,
289 (vcdinfo_get_VCD_type(p_vcdinfo) == VCD_TYPE_SVCD
290 || vcdinfo_get_VCD_type(p_vcdinfo) == VCD_TYPE_HQVCD)
291 ? "SVCD/PSD.SVD\n"
292 : (ext ? "EXT/PSD_X.VCD\n": "VCD/PSD.VCD\n"));
293
294 _CDIO_LIST_FOREACH (node, offset_list)
295 {
296 vcdinfo_offset_t *ofs = _cdio_list_node_data (node);
297 unsigned _rofs = ofs->offset * mult;
298
299 uint8_t type;
300
301 type = psd[_rofs];
302
303 switch (type)
304 {
305 case PSD_TYPE_PLAY_LIST:
306 {
307 const PsdPlayListDescriptor_t *pld = (const void *) (psd + _rofs);
308
309 int i;
310 uint16_t lid = vcdinf_pld_get_lid(pld);
311
312 fprintf (stdout,
313 " PSD[%.2d] (%s): play list descriptor\n"
314 " NOI: %d | LID#: %d (rejected: %s)\n"
315 " prev: %s | next: %s | return: %s\n"
316 " playtime: %d/15s | wait: %ds | autowait: %ds\n",
317 n, vcdinfo_ofs2str (p_vcdinfo, ofs->offset, ext),
318 pld->noi, lid,
319 _vcd_bool_str(vcdinfo_is_rejected(uint16_from_be(pld->lid))),
320 vcdinfo_ofs2str(p_vcdinfo,
321 vcdinf_pld_get_prev_offset(pld), ext),
322 vcdinfo_ofs2str(p_vcdinfo,
323 vcdinf_pld_get_next_offset(pld), ext),
324 vcdinfo_ofs2str(p_vcdinfo,
325 vcdinf_pld_get_return_offset(pld),
326 ext),
327 vcdinf_get_play_time(pld), vcdinf_get_wait_time (pld),
328 vcdinf_get_autowait_time(pld));
329
330 for (i = 0; i < pld->noi; i++) {
331 fprintf (stdout, " play-item[%d]: %s\n", i,
332 vcdinfo_pin2str(vcdinf_pld_get_play_item(pld,i)));
333 }
334 fprintf (stdout, "\n");
335 }
336 break;
337
338 case PSD_TYPE_END_LIST:
339 {
340 const PsdEndListDescriptor_t *d = (const void *) (psd + _rofs);
341 fprintf (stdout, " PSD[%.2d] (%s): end list descriptor\n", n,
342 vcdinfo_ofs2str (p_vcdinfo, ofs->offset, ext));
343 if (vcdinfo_get_VCD_type(p_vcdinfo) != VCD_TYPE_VCD2)
344 {
345 fprintf (stdout,
346 " next disc number: %d (if 0 stop PBC handling)\n",
347 d->next_disc);
348 fprintf (stdout,
349 " change picture item: %s\n",
350 vcdinfo_pin2str (uint16_from_be (d->change_pic)));
351 }
352 fprintf (stdout, "\n");
353 }
354 break;
355
356 case PSD_TYPE_EXT_SELECTION_LIST:
357 case PSD_TYPE_SELECTION_LIST:
358 {
359 const PsdSelectionListDescriptor_t *d =
360 (const void *) (psd + _rofs);
361 int i;
362 const unsigned int lid=vcdinf_psd_get_lid(d);
363
364 fprintf (stdout,
365 " PSD[%.2d] (%s): %sselection list descriptor\n"
366 " Flags: 0x%.2x | NOS: %d | BSN: %d | LID: %d (rejected: %s)\n"
367 " prev: %s | next: %s | return: %s\n"
368 " default: %s | timeout: %s\n"
369 " wait: %d secs | loop: %d (delayed: %s)\n"
370 " play-item: %s\n",
371 n, vcdinfo_ofs2str (p_vcdinfo, ofs->offset, ext),
372 (type == PSD_TYPE_EXT_SELECTION_LIST ? "extended " : ""),
373 *(uint8_t *) &d->flags,
374 vcdinf_get_num_selections(d),
375 vcdinf_get_bsn(d),
376 lid,
377 _vcd_bool_str (vcdinf_psd_get_lid_rejected(d)),
378 vcdinfo_ofs2str(p_vcdinfo,
379 vcdinf_psd_get_prev_offset(d), ext),
380 vcdinfo_ofs2str(p_vcdinfo,
381 vcdinf_psd_get_next_offset(d), ext),
382 vcdinfo_ofs2str(p_vcdinfo,
383 vcdinf_psd_get_return_offset(d), ext),
384 vcdinfo_ofs2str(p_vcdinfo,
385 vcdinf_psd_get_default_offset(d),ext),
386 vcdinfo_ofs2str(p_vcdinfo, vcdinf_get_timeout_offset(d),
387 ext),
388 vcdinf_get_timeout_time(d),
389 vcdinf_get_loop_count(d),
390 _vcd_bool_str (vcdinf_has_jump_delay(d)),
391 vcdinfo_pin2str (vcdinf_psd_get_itemid(d)));
392
393 for (i = 0; i < vcdinf_get_num_selections(d); i++)
394 fprintf (stdout, " ofs[%d]: %s\n", i,
395 vcdinfo_ofs2str (p_vcdinfo,
396 vcdinf_psd_get_offset(d, i),
397 ext));
398
399 if (type == PSD_TYPE_EXT_SELECTION_LIST
400 || d->flags.SelectionAreaFlag)
401 {
402 const PsdSelectionListDescriptorExtended_t *d2 =
403 (const void *) &(d->ofs[d->nos]);
404
405 fprintf (stdout, " prev_area: %s | next_area: %s\n",
406 vcdinf_area_str (&d2->prev_area),
407 vcdinf_area_str (&d2->next_area));
408
409
410 fprintf (stdout, " retn_area: %s | default_area: %s\n",
411 vcdinf_area_str (&d2->return_area),
412 vcdinf_area_str (&d2->default_area));
413
414 for (i = 0; i < vcdinf_get_num_selections(d); i++)
415 fprintf (stdout, " area[%d]: %s\n", i,
416 vcdinf_area_str (&d2->area[i]));
417 }
418
419 fprintf (stdout, "\n");
420 }
421 break;
422 default:
423 fprintf (stdout, " PSD[%2d] (%s): unkown descriptor type (0x%2.2x)\n",
424 n, vcdinfo_ofs2str (p_vcdinfo, ofs->offset, ext), type);
425
426 fprintf (stdout, " hexdump: ");
427 _hexdump (&psd[_rofs], 24);
428 fprintf (stdout, "\n");
429 break;
430 }
431
432 n++;
433 }
434 }
435
436 static void
dump_info(vcdinfo_obj_t * p_vcdinfo)437 dump_info (vcdinfo_obj_t *p_vcdinfo)
438 {
439 const InfoVcd_t *info = vcdinfo_get_infoVcd(p_vcdinfo);
440 segnum_t num_segments = vcdinfo_get_num_segments(p_vcdinfo);
441 int n;
442
443 if (!gl.show.no.header)
444 fprintf (stdout,
445 (vcdinfo_get_VCD_type(p_vcdinfo) == VCD_TYPE_SVCD
446 || vcdinfo_get_VCD_type(p_vcdinfo) == VCD_TYPE_HQVCD)
447 ? "SVCD/INFO.SVD\n"
448 : "VCD/INFO.VCD\n");
449
450 if (gl.show.info.id)
451 fprintf (stdout, " ID: `%.8s'\n", info->ID);
452 if (gl.show.info.vers)
453 fprintf (stdout, " version: 0x%2.2x\n", info->version);
454 if (gl.show.info.prof)
455 fprintf (stdout, " system profile tag: 0x%2.2x\n", info->sys_prof_tag);
456 if (gl.show.info.album)
457 fprintf (stdout, " album id: `%.16s'\n", vcdinfo_get_album_id(p_vcdinfo));
458 if (gl.show.info.count)
459 fprintf (stdout, " volume count: %d\n",
460 vcdinfo_get_volume_count(p_vcdinfo));
461 if (gl.show.info.vol)
462 fprintf (stdout, " volume number: %d\n",
463 vcdinfo_get_volume_num(p_vcdinfo));
464
465 if (gl.show.info.pal)
466 {
467 fprintf (stdout, " pal flags:");
468 for (n = 0; n < 98; n++)
469 {
470 if (n == 48)
471 fprintf (stdout, "\n (bslbf) ");
472
473 fprintf (stdout, n % 8 ? "%d" : " %d",
474 _bitset_get_bit (info->pal_flags, n));
475 }
476 fprintf (stdout, "\n");
477
478 fprintf (stdout, " flags:\n");
479 fprintf (stdout,
480 ((vcdinfo_get_VCD_type(p_vcdinfo) == VCD_TYPE_SVCD
481 || vcdinfo_get_VCD_type(p_vcdinfo) == VCD_TYPE_HQVCD)
482 ? " reserved1: %s\n"
483 : " karaoke area: %s\n"),
484 _vcd_bool_str (info->flags.reserved1));
485 }
486
487 if (gl.show.info.res)
488 fprintf (stdout, " restriction: %d\n", info->flags.restriction);
489 if (gl.show.info.spec)
490 fprintf (stdout, " special info: %s\n", _vcd_bool_str (info->flags.special_info));
491 if (gl.show.info.cc)
492 fprintf (stdout, " user data cc: %s\n", _vcd_bool_str (info->flags.user_data_cc));
493 if (gl.show.info.lid2)
494 fprintf (stdout, " start lid #2: %s\n", _vcd_bool_str (info->flags.use_lid2));
495 if (gl.show.info.st2)
496 fprintf (stdout, " start track #2: %s\n", _vcd_bool_str (info->flags.use_track3));
497 if (gl.show.info.pbc) {
498 fprintf (stdout,
499 ((vcdinfo_get_VCD_type(p_vcdinfo) == VCD_TYPE_SVCD
500 || vcdinfo_get_VCD_type(p_vcdinfo) == VCD_TYPE_HQVCD)
501 ? " reserved2: %s\n"
502 : " extended pbc: %s\n"),
503 _vcd_bool_str (info->flags.pbc_x));
504 switch (_has_vcd2_ext_pbc(p_vcdinfo))
505 {
506 case PBC_VCD2_NO_PBC:
507 fprintf(stdout, " No PBC info.\n");
508 break;
509 case PBC_VCD2_NO_LOT_X:
510 fprintf(stdout, " Missing EXT/LOT_X.VCD for extended PBC info.\n");
511 break;
512 case PBC_VCD2_NO_PSD_X:
513 fprintf(stdout, " Missing EXT/PSD_X.VCD for extended PBC info.\n");
514 break;
515 case PBC_VCD2_BAD_LOT_SIZE:
516 fprintf(stdout,
517 " Size of EXT/LOT_X.VCD != LOT_VCD_SIZE*ISO_BLOCKSIZE\n");
518 break;
519 case PBC_VCD2_EXT:
520 fprintf(stdout, " Detected extended VCD2.0 PBC files.\n");
521 break;
522 case PBC_VCD2_NOPE:
523 break;
524 }
525 }
526
527
528 if (gl.show.info.psds)
529 fprintf (stdout, " psd size: %u\n",
530 (unsigned int) uint32_from_be (info->psd_size));
531
532 if (gl.show.info.seg) {
533 char *psz_msf = cdio_msf_to_str(&info->first_seg_addr);
534 fprintf (stdout, " first segment addr: %s\n", psz_msf);
535 free(psz_msf);
536 }
537
538 if (gl.show.info.ofm)
539 fprintf (stdout, " offset multiplier: 0x%2.2x\n",
540 vcdinfo_get_offset_mult(p_vcdinfo));
541
542 if (gl.show.info.lidn)
543 fprintf (stdout, " maximum lid: %d\n",
544 uint16_from_be (info->lot_entries));
545
546 if (gl.show.info.segn)
547 fprintf (stdout, " number of segments: %d\n", num_segments);
548
549 if (gl.show.info.segs)
550 for (n = 0; n < num_segments; n++)
551 {
552 const lsn_t lsn = vcdinfo_get_seg_lsn(p_vcdinfo, n);
553 msf_t msf;
554 char *psz_msf;
555
556 cdio_lsn_to_msf(lsn, &msf);
557 psz_msf = cdio_msf_to_str(&msf);
558 fprintf (stdout, " SEGMENT[%4.4d]: track# 0, LSN %6u "
559 "(MSF %s), %2u sectors\n",
560 n, (unsigned int) lsn, psz_msf,
561 (unsigned int) vcdinfo_get_seg_sector_count(p_vcdinfo, n));
562 free(psz_msf);
563
564 fprintf (stdout, " audio: %s, video: %s, continuation %s%s %s\n",
565 vcdinfo_audio_type2str(p_vcdinfo,
566 vcdinfo_get_seg_audio_type(p_vcdinfo, n)),
567 vcdinfo_video_type2str(p_vcdinfo, n),
568 _vcd_bool_str (info->spi_contents[n].item_cont),
569 (vcdinfo_get_VCD_type(p_vcdinfo) == VCD_TYPE_VCD2)
570 ? "" : ",\n SVCD subtitle (OGT) substream:",
571 (vcdinfo_get_VCD_type(p_vcdinfo) == VCD_TYPE_VCD2)
572 ? "" : vcdinfo_ogt2str(p_vcdinfo, n));
573 }
574
575 if (gl.show.info.start)
576 if (vcdinfo_get_VCD_type(p_vcdinfo) == VCD_TYPE_SVCD
577 || vcdinfo_get_VCD_type(p_vcdinfo) == VCD_TYPE_HQVCD)
578 for (n = 0; n < 5; n++)
579 fprintf (stdout, " volume start time[%d]: %d secs\n",
580 n, uint16_from_be (info->playing_time[n]));
581 }
582
583 static void
dump_entries(vcdinfo_obj_t * obj)584 dump_entries (vcdinfo_obj_t *obj)
585 {
586 const EntriesVcd_t *entries = vcdinfo_get_entriesVcd(obj);
587 int num_entries, n;
588
589 num_entries = vcdinfo_get_num_entries(obj);
590
591 if (!gl.show.no.header)
592 fprintf (stdout,
593 (vcdinfo_get_VCD_type(obj) == VCD_TYPE_SVCD
594 || vcdinfo_get_VCD_type(obj) == VCD_TYPE_HQVCD)
595 ? "SVCD/ENTRIES.SVD\n"
596 : "VCD/ENTRIES.VCD\n");
597
598 if (!strncmp (entries->ID, ENTRIES_ID_VCD, sizeof (entries->ID)))
599 { /* noop */ }
600 else if (!strncmp (entries->ID, "ENTRYSVD", sizeof (entries->ID)))
601 vcd_warn ("found obsolete (S)VCD3.0 ENTRIES.SVD signature");
602 else
603 vcd_warn ("unexpected ID signature encountered");
604
605 if (gl.show.entries.id)
606 fprintf (stdout, " ID: `%.8s'\n", entries->ID);
607 if (gl.show.entries.vers)
608 fprintf (stdout, " version: 0x%2.2x\n", entries->version);
609 if (gl.show.entries.prof)
610 fprintf (stdout, " system profile tag: 0x%2.2x\n", entries->sys_prof_tag);
611
612 if (gl.show.entries.count)
613 fprintf (stdout, " entries: %d\n", num_entries);
614
615 if (gl.show.entries.data)
616 for (n = 0; n < num_entries; n++)
617 {
618 const lsn_t lsn = vcdinfo_get_entry_lsn(obj, n);
619 msf_t msf;
620 char *psz_msf;
621
622 cdio_lsn_to_msf(lsn, &msf);
623 psz_msf = cdio_msf_to_str(&msf);
624 fprintf (stdout, " ENTRY[%2.2d]: track# %2d (SEQUENCE[%d]), LSN %6u "
625 "(MSF %s)\n",
626 n, vcdinfo_get_track(obj, n),
627 vcdinfo_get_track(obj, n) - 1,
628 (unsigned int) lsn, psz_msf);
629 free(psz_msf);
630 }
631 }
632
633 /*
634 Dump the track contents using information from TRACKS.SVCD.
635 See also dump_tracks which gives similar information but doesn't
636 need TRACKS.SVCD
637 */
638 static void
dump_tracks_svd(vcdinfo_obj_t * obj)639 dump_tracks_svd (vcdinfo_obj_t *obj)
640 {
641 const TracksSVD_t *tracks = vcdinfo_get_tracksSVD(obj);
642 const TracksSVD2_t *tracks2 = (const void *) &(tracks->playing_time[tracks->tracks]);
643 const TracksSVD_v30_t *tracks_v30 = (TracksSVD_v30_t *) tracks;
644
645 unsigned j;
646
647 if (!gl.show.no.header)
648 fprintf (stdout, "SVCD/TRACKS.SVD\n");
649
650 fprintf (stdout, " ID: `%.8s'\n", tracks->file_id);
651 fprintf (stdout, " version: 0x%2.2x\n", tracks->version);
652
653 fprintf (stdout, " tracks: %d\n", tracks->tracks);
654
655 for (j = 0; j < tracks->tracks; j++)
656 {
657 const char *video_types[] =
658 {
659 "no stream",
660 "reserved (0x1)",
661 "reserved (0x2)",
662 "NTSC stream",
663 "reserved (0x4)",
664 "reserved (0x5)",
665 "reserved (0x6)",
666 "PAL stream",
667 };
668
669 const char *ogt_str[] =
670 {
671 "None",
672 "0 available",
673 "0 & 1 available",
674 "all available"
675 };
676 char *psz_msf = cdio_msf_to_str(&(tracks->playing_time[j]));
677
678 fprintf (stdout,
679 " track[%.2d]: %s,"
680 " audio: %s, video: %s,\n"
681 " SVCD subtitle (OGT) stream: %s\n",
682 j, psz_msf,
683 vcdinfo_audio_type2str(obj,
684 vcdinfo_get_track_audio_type(obj, j+1)),
685 video_types[tracks2->contents[j].video],
686 ogt_str[tracks2->contents[j].ogt]);
687 free(psz_msf);
688 }
689
690 fprintf (stdout, "\nCVD interpretation (probably)\n");
691 for (j = 0;j < tracks->tracks; j++)
692 {
693
694 char *psz_msf = cdio_msf_to_str(&(tracks_v30->track[j].cum_playing_time));
695 fprintf (stdout, "(track[%.2d]: %s (cumulated),"
696 " audio: %.2x, ogt: %.2x)\n",
697 j, psz_msf,
698 tracks_v30->track[j].audio_info,
699 tracks_v30->track[j].ogt_info);
700 free(psz_msf);
701
702 }
703 }
704
705 /*
706 Dump the track contents based on low-level CD datas.
707 See also dump_tracks which gives more information but requires
708 TRACKS.SVCD to exist on the medium.
709 */
710 static void
dump_tracks(const CdIo_t * cdio)711 dump_tracks (const CdIo_t *cdio)
712 {
713 track_t i;
714 track_t num_tracks = cdio_get_num_tracks(cdio);
715 track_t first_track_num = cdio_get_first_track_num(cdio);
716
717 if (!gl.show.no.header)
718 fprintf (stdout, "CD-ROM TRACKS (%i - %i)\n", first_track_num, num_tracks);
719
720 fprintf(stdout, " #: MSF LSN Type\n");
721
722 /* Read and possibly print track information. */
723 for (i = first_track_num; i <= CDIO_CDROM_LEADOUT_TRACK; i++) {
724 msf_t msf;
725 char *psz_msf;
726
727 if (!cdio_get_track_msf(cdio, i, &msf)) {
728 vcd_error("Error getting information for track %i.\n", i);
729 continue;
730 }
731
732 psz_msf = cdio_msf_to_str(&msf);
733 if (i == CDIO_CDROM_LEADOUT_TRACK) {
734 printf("%3d: %s %06u leadout\n",
735 (int) i, psz_msf,
736 (unsigned int) cdio_msf_to_lsn(&msf));
737 free(psz_msf);
738 break;
739 } else {
740 printf("%3d: %s %06u %s\n",
741 (int) i, psz_msf,
742 (unsigned int) cdio_msf_to_lsn(&msf),
743 track_format2str[cdio_get_track_format(cdio, i)]);
744
745 }
746 free(psz_msf);
747 /* skip to leadout? */
748 if (i == num_tracks) i = CDIO_CDROM_LEADOUT_TRACK-1;
749 }
750 }
751
752 static void
dump_scandata_dat(vcdinfo_obj_t * obj)753 dump_scandata_dat (vcdinfo_obj_t *obj)
754 {
755 const ScandataDat1_t *_sd1 = vcdinfo_get_scandata(obj);
756 const uint16_t scandata_count = uint16_from_be (_sd1->scandata_count);
757 const uint16_t track_count = uint16_from_be (_sd1->track_count);
758 const uint16_t spi_count = uint16_from_be (_sd1->spi_count);
759
760 fprintf (stdout, "EXT/SCANDATA.DAT\n");
761 fprintf (stdout, " ID: `%.8s'\n", _sd1->file_id);
762
763 fprintf (stdout, " version: 0x%2.2x\n", _sd1->version);
764 fprintf (stdout, " reserved: 0x%2.2x\n", _sd1->reserved);
765 fprintf (stdout, " scandata_count: %d\n", scandata_count);
766
767 if (_sd1->version == SCANDATA_VERSION_VCD2)
768 {
769 const ScandataDat_v2_t *_sd_v2 = (ScandataDat_v2_t *) _sd1;
770
771 int n;
772
773 for (n = 0; n < scandata_count; n++)
774 {
775 const msf_t *msf = &_sd_v2->points[n];
776 const uint32_t lsn = cdio_msf_to_lsn(msf);
777 char *psz_msf;
778
779 if (!(gl.debug_level >= 1)
780 && n > PRINTED_POINTS
781 && n < scandata_count - PRINTED_POINTS)
782 continue;
783
784 psz_msf = cdio_msf_to_str(msf);
785 fprintf (stdout, " scanpoint[%.4d]: LSN %lu (msf %s)\n",
786 n, (long unsigned int) lsn, psz_msf);
787
788 free(psz_msf);
789
790 if (!(gl.debug_level >= 1)
791 && n == PRINTED_POINTS
792 && scandata_count > (PRINTED_POINTS * 2))
793 fprintf (stdout, " [..skipping...]\n");
794 }
795 }
796 else if (_sd1->version == SCANDATA_VERSION_SVCD)
797 {
798 const ScandataDat2_t *_sd2 =
799 (const void *) &_sd1->cum_playtimes[track_count];
800
801 const ScandataDat3_t *_sd3 =
802 (const void *) &_sd2->spi_indexes[spi_count];
803
804 const ScandataDat4_t *_sd4 =
805 (const void *) &_sd3->mpeg_track_offsets[track_count];
806
807 const int scandata_ofs0 =
808 __cd_offsetof (ScandataDat3_t, mpeg_track_offsets[track_count])
809 - __cd_offsetof (ScandataDat3_t, mpeg_track_offsets);
810
811 int n;
812
813 fprintf (stdout, " sequence_count: %d\n", track_count);
814 fprintf (stdout, " segment_count: %d\n", spi_count);
815
816 for (n = 0; n < track_count; n++)
817 {
818 const msf_t *msf = &_sd1->cum_playtimes[n];
819 char *psz_msf = cdio_msf_to_str(msf);
820
821 fprintf (stdout, " cumulative_playingtime[%d]: %s\n", n, psz_msf);
822 free(psz_msf);
823 }
824
825 for (n = 0; n < spi_count; n++)
826 {
827 const int _ofs = uint16_from_be (_sd2->spi_indexes[n]);
828
829 fprintf (stdout, " segment scandata ofs[n]: %d\n", _ofs);
830 }
831
832 fprintf (stdout, " sequence scandata ofs: %d\n",
833 uint16_from_be (_sd3->mpegtrack_start_index));
834
835 for (n = 0; n < track_count; n++)
836 {
837 const int _ofs =
838 uint16_from_be (_sd3->mpeg_track_offsets[n].table_offset);
839 const int _toc = _sd3->mpeg_track_offsets[n].track_num;
840
841 fprintf (stdout, " track [%d]: TOC num: %d, sd offset: %d\n",
842 n, _toc, _ofs);
843 }
844
845 fprintf (stdout, " (scanpoint[0] offset = %d)\n", scandata_ofs0);
846
847 for (n = 0; n < scandata_count; n++)
848 {
849 const msf_t *msf = &_sd4->scandata_table[n];
850 const uint32_t lsn = cdio_msf_to_lsn(msf);
851 char *psz_msf = cdio_msf_to_str(msf);
852
853 if (!(gl.debug_level >= 1)
854 && n > PRINTED_POINTS
855 && n < scandata_count - PRINTED_POINTS) {
856 free(psz_msf);
857 continue;
858 }
859
860
861 fprintf (stdout,
862 " scanpoint[%.4d] (ofs:%5d): LSN %lu (MSF %s)\n",
863 n, scandata_ofs0 + (n * 3), (unsigned long int) lsn,
864 psz_msf);
865 free(psz_msf);
866
867 if (!(gl.debug_level >= 1)
868 && n == PRINTED_POINTS
869 && scandata_count > (PRINTED_POINTS * 2))
870 fprintf (stdout, " [..skipping...]\n");
871 }
872 }
873 else
874 fprintf (stdout, "!unsupported version!\n");
875 }
876
877 static void
dump_search_dat(vcdinfo_obj_t * obj)878 dump_search_dat (vcdinfo_obj_t *obj)
879 {
880 const SearchDat_t *searchdat = vcdinfo_get_searchDat(obj);
881 unsigned m;
882 uint32_t scan_points = uint16_from_be (searchdat->scan_points);
883
884 fprintf (stdout, "SVCD/SEARCH.DAT\n");
885 fprintf (stdout, " ID: `%.8s'\n", searchdat->file_id);
886 fprintf (stdout, " version: 0x%2.2x\n", searchdat->version);
887 fprintf (stdout, " scanpoints: %u\n", (unsigned int) scan_points);
888 fprintf (stdout, " scaninterval: %lu (in 0.5sec units -- must be `1')\n",
889 (unsigned long int) searchdat->time_interval);
890
891 for (m = 0; m < scan_points;m++)
892 {
893 unsigned hh, mm, ss, ss2;
894 const msf_t *msf = &(searchdat->points[m]);
895 const uint32_t lsn = cdio_msf_to_lsn(msf);
896 char *psz_msf;
897
898 if (!(gl.debug_level >= 1)
899 && m > PRINTED_POINTS
900 && m < (scan_points - PRINTED_POINTS))
901 continue;
902
903 psz_msf = cdio_msf_to_str(msf);
904 ss2 = m * searchdat->time_interval;
905
906 hh = ss2 / (2 * 60 * 60);
907 mm = (ss2 / (2 * 60)) % 60;
908 ss = (ss2 / 2) % 60;
909 ss2 = (ss2 % 2) * 5;
910
911 fprintf (stdout, " scanpoint[%.4d]: (real time: %.2d:%.2d:%.2d.%.1d) "
912 " sector: LSN %lu (MSF %s)\n", m, hh, mm, ss, ss2,
913 (unsigned long int) lsn, psz_msf);
914 free(psz_msf);
915
916 if (!(gl.debug_level >= 1)
917 && m == PRINTED_POINTS && scan_points > (PRINTED_POINTS * 2))
918 fprintf (stdout, " [..skipping...]\n");
919 }
920 }
921
922
923 static void
_dump_fs_recurse(const vcdinfo_obj_t * obj,const char pathname[])924 _dump_fs_recurse (const vcdinfo_obj_t *obj, const char pathname[])
925 {
926 CdioList_t *entlist;
927 CdioList_t *dirlist = _cdio_list_new ();
928 CdioListNode_t *entnode;
929 CdIo_t *cdio = vcdinfo_get_cd_image(obj);
930
931 entlist = iso9660_fs_readdir (cdio, pathname);
932
933 fprintf (stdout, " %s:\n", pathname);
934
935 vcd_assert (entlist != NULL);
936
937 /* just iterate */
938
939 _CDIO_LIST_FOREACH (entnode, entlist)
940 {
941 iso9660_stat_t *statbuf = _cdio_list_node_data (entnode);
942 char *_name = statbuf->filename;
943 char _fullname[4096] = { 0, };
944
945 snprintf (_fullname, sizeof (_fullname), "%s%s", pathname, _name);
946
947 strncat (_fullname, "/", sizeof (_fullname)-strlen(_fullname)-1);
948
949 if (statbuf->type == _STAT_DIR
950 && strcmp (_name, ".")
951 && strcmp (_name, ".."))
952 _cdio_list_append (dirlist, strdup (_fullname));
953
954 fprintf (stdout,
955 " %c %s %d %d [fn %.2d] [LSN %6lu] ",
956 (statbuf->type == _STAT_DIR) ? 'd' : '-',
957 iso9660_get_xa_attr_str (statbuf->xa.attributes),
958 uint16_from_be (statbuf->xa.user_id),
959 uint16_from_be (statbuf->xa.group_id),
960 statbuf->xa.filenum,
961 (unsigned long int) statbuf->lsn);
962
963 if (uint16_from_be(statbuf->xa.attributes) & XA_ATTR_MODE2FORM2) {
964 fprintf (stdout, "%9lu (%9lu)",
965 (unsigned long int) statbuf->secsize * M2F2_SECTOR_SIZE,
966 (unsigned long int) statbuf->size);
967 } else {
968 fprintf (stdout, "%9lu", (unsigned long int) statbuf->size);
969 }
970 fprintf (stdout, " %s\n", _name);
971
972 }
973
974 _cdio_list_free (entlist, true, NULL);
975
976 fprintf (stdout, "\n");
977
978 /* now recurse */
979
980 _CDIO_LIST_FOREACH (entnode, dirlist)
981 {
982 char *_fullname = _cdio_list_node_data (entnode);
983
984 _dump_fs_recurse (obj, _fullname);
985 }
986
987 _cdio_list_free (dirlist, true, NULL);
988 }
989
990 static void
dump_fs(vcdinfo_obj_t * obj)991 dump_fs (vcdinfo_obj_t *obj)
992 {
993 const iso9660_pvd_t *pvd = vcdinfo_get_pvd(obj);
994 const lsn_t extent = iso9660_get_root_lsn(pvd);
995
996 fprintf (stdout, "ISO9660 filesystem dump\n");
997 fprintf (stdout, " root directory in PVD set to LSN %lu\n\n",
998 (unsigned long int) extent);
999
1000 _dump_fs_recurse (obj, "/");
1001 }
1002
1003 static void
dump_pvd(vcdinfo_obj_t * p_vcdinfo)1004 dump_pvd (vcdinfo_obj_t *p_vcdinfo)
1005 {
1006 const iso9660_pvd_t *pvd = vcdinfo_get_pvd(p_vcdinfo);
1007
1008 if (!gl.show.no.header)
1009 fprintf (stdout, "ISO9660 primary volume descriptor\n");
1010
1011
1012 if (iso9660_get_pvd_type(pvd) != ISO_VD_PRIMARY)
1013 vcd_warn ("unexpected descriptor type");
1014
1015 if (strncmp (iso9660_get_pvd_id(pvd), ISO_STANDARD_ID,
1016 strlen (ISO_STANDARD_ID)))
1017 vcd_warn ("unexpected ID encountered (expected `" ISO_STANDARD_ID "'");
1018
1019 if (gl.show.pvd.id)
1020 fprintf (stdout, " ID: `%.5s'\n", iso9660_get_pvd_id(pvd));
1021
1022 if (gl.show.pvd.vers)
1023 fprintf (stdout, " version: %d\n", iso9660_get_pvd_version(pvd));
1024
1025 if (gl.show.pvd.sys) {
1026 char *psz = vcdinfo_get_system_id(p_vcdinfo);
1027 fprintf (stdout, " system id: `%s'\n", psz);
1028 free(psz);
1029 }
1030
1031
1032 if (gl.show.pvd.vol)
1033 fprintf (stdout, " volume id: `%s'\n",
1034 vcdinfo_get_volume_id(p_vcdinfo));
1035
1036 if (gl.show.pvd.volset)
1037 fprintf (stdout, " volumeset id: `%s'\n",
1038 vcdinfo_get_volumeset_id(p_vcdinfo));
1039
1040 if (gl.show.pvd.pub) {
1041 char *psz = vcdinfo_get_publisher_id(p_vcdinfo);
1042 fprintf (stdout, " publisher id: `%s'\n", psz);
1043 free(psz);
1044 }
1045
1046 if (gl.show.pvd.prep) {
1047 char *psz = vcdinfo_get_preparer_id(p_vcdinfo);
1048 fprintf (stdout, " preparer id: `%s'\n", psz);
1049 free(psz);
1050 }
1051
1052 if (gl.show.pvd.app) {
1053 char *psz = vcdinfo_get_application_id(p_vcdinfo);
1054 fprintf (stdout, " application id: `%s'\n", psz);
1055 free(psz);
1056 }
1057
1058 if (gl.show.pvd.iso)
1059 fprintf (stdout, " ISO size: %d blocks (logical blocksize: %d bytes)\n",
1060 iso9660_get_pvd_space_size(pvd),
1061 iso9660_get_pvd_block_size(pvd));
1062
1063 if (gl.show.pvd.xa)
1064 fprintf (stdout, " XA marker present: %s\n",
1065 _vcd_bool_str (vcdinfo_has_xa(p_vcdinfo)));
1066 }
1067
1068 static void
dump_all(vcdinfo_obj_t * p_vcdinfo)1069 dump_all (vcdinfo_obj_t *p_vcdinfo)
1070 {
1071 CdIo_t *p_cdio;
1072
1073 if (!p_vcdinfo) return;
1074
1075 p_cdio = vcdinfo_get_cd_image(p_vcdinfo);
1076
1077 if (gl.show.pvd.any)
1078 {
1079 if (!gl.show.no.delimiter) fprintf (stdout, DELIM);
1080 dump_pvd (p_vcdinfo);
1081 }
1082
1083 if (gl.show.fs)
1084 {
1085 if (!gl.show.no.delimiter) fprintf (stdout, DELIM);
1086 dump_fs (p_vcdinfo);
1087 }
1088
1089 if (gl.show.info.any)
1090 {
1091 if (!gl.show.no.delimiter) fprintf (stdout, DELIM);
1092 dump_info (p_vcdinfo);
1093 }
1094
1095 if (gl.show.entries.any)
1096 {
1097 if (!gl.show.no.delimiter) fprintf (stdout, DELIM);
1098 dump_entries (p_vcdinfo);
1099 }
1100
1101 if (gl.show.psd)
1102 {
1103 if (vcdinfo_get_psd_size (p_vcdinfo))
1104 {
1105 vcdinfo_visit_lot (p_vcdinfo, false);
1106 if (gl.show.lot)
1107 {
1108 if (!gl.show.no.delimiter) fprintf (stdout, DELIM);
1109 dump_lot (p_vcdinfo, false);
1110 }
1111
1112 if (!gl.show.no.delimiter) fprintf (stdout, DELIM);
1113 dump_psd (p_vcdinfo, false);
1114 }
1115
1116 if (vcdinfo_get_psd_x_size(p_vcdinfo) && ! gl.no_ext_psd_flag )
1117 {
1118 vcdinfo_visit_lot (p_vcdinfo, true);
1119 if (gl.show.lot)
1120 {
1121 if (!gl.show.no.delimiter) fprintf (stdout, DELIM);
1122 dump_lot (p_vcdinfo, true);
1123 }
1124 if (!gl.show.no.delimiter) fprintf (stdout, DELIM);
1125 dump_psd (p_vcdinfo, true);
1126 }
1127 }
1128
1129 if (gl.show.tracks)
1130 {
1131 if (vcdinfo_get_tracksSVD(p_vcdinfo))
1132 {
1133 if (!gl.show.no.delimiter) fprintf (stdout, DELIM);
1134 dump_tracks_svd (p_vcdinfo);
1135 }
1136 if (!gl.show.no.delimiter) fprintf (stdout, DELIM);
1137 dump_tracks (p_cdio);
1138 }
1139
1140 if (gl.show.search)
1141 {
1142 if (vcdinfo_get_searchDat(p_vcdinfo))
1143 {
1144 if (!gl.show.no.delimiter) fprintf (stdout, DELIM);
1145 dump_search_dat (p_vcdinfo);
1146 }
1147 }
1148
1149
1150 if (gl.show.scandata)
1151 {
1152 if (vcdinfo_get_scandata(p_vcdinfo))
1153 {
1154 if (!gl.show.no.delimiter) fprintf (stdout, DELIM);
1155 dump_scandata_dat (p_vcdinfo);
1156 }
1157
1158 }
1159 if (!gl.show.no.delimiter) fprintf (stdout, DELIM);
1160
1161 }
1162
1163 static void
dump(char * image_fname[])1164 dump (char *image_fname[])
1165 {
1166 unsigned size, psd_size;
1167 vcdinfo_obj_t *obj = NULL;
1168 CdIo_t *p_cdio;
1169 iso9660_stat_t *p_statbuf;
1170 vcdinfo_open_return_t open_rc;
1171
1172 if (!gl.show.no.banner)
1173 {
1174 if (!gl.show.no.delimiter)
1175 fprintf (stdout, DELIM);
1176
1177 fprintf (stdout, "vcd-info - GNU VCDImager - (Super) Video CD Report\n"
1178 "%s\n\n", _rcsid);
1179 }
1180
1181 open_rc = vcdinfo_open(&obj, image_fname, gl.source_type, gl.access_mode);
1182
1183 if (NULL == obj) {
1184 if (*image_fname == NULL) {
1185 fprintf (stdout, "Couldn't automatically find a Video CD.\n");
1186 } else {
1187 fprintf (stdout, "Error opening requested Video CD object %s\n",
1188 *image_fname);
1189 fprintf (stdout, "Perhaps this is not a Video CD\n");
1190 free(*image_fname);
1191 }
1192 goto err_exit;
1193 }
1194
1195 p_cdio = vcdinfo_get_cd_image(obj);
1196 if (open_rc==VCDINFO_OPEN_ERROR || p_cdio == NULL) {
1197 vcd_error ("Error determining place to read from");
1198 free(*image_fname);
1199 goto err_exit;
1200 }
1201
1202 size = cdio_get_disc_last_lsn (p_cdio);
1203
1204 if (gl.show.source)
1205 {
1206 if (NULL == *image_fname) {
1207 *image_fname = vcdinfo_get_default_device(obj);
1208 fprintf (stdout, "Source: default image file `%s'\n", *image_fname);
1209 } else {
1210 fprintf (stdout, "Source: image file `%s'\n", *image_fname);
1211 }
1212 fprintf (stdout, "Image size: %d sectors\n", size);
1213 }
1214
1215 if (open_rc == VCDINFO_OPEN_OTHER) {
1216 vcd_warn ("Medium is not VCD image");
1217 if (gl.show.fs)
1218 {
1219 if (vcdinfo_has_xa(obj))
1220 {
1221 /* Suppress XA warnings */
1222 int old_suppress_warnings = gl.suppress_warnings;
1223 if (!gl.show.no.delimiter) fprintf (stdout, DELIM);
1224 gl.suppress_warnings=1;
1225 dump_fs (obj);
1226 gl.suppress_warnings=old_suppress_warnings;
1227 }
1228 }
1229
1230 if (gl.show.tracks) {
1231 if (!gl.show.no.delimiter) fprintf (stdout, DELIM);
1232 dump_tracks (p_cdio);
1233 }
1234 goto err_exit;
1235 }
1236
1237 if (vcdinfo_get_format_version (obj) == VCD_TYPE_INVALID) {
1238 vcd_error ("VCD detection failed - aborting");
1239 goto err_exit;
1240 } else if (gl.show.format) {
1241 fprintf (stdout, "%s detected\n", vcdinfo_get_format_version_str(obj));
1242 }
1243
1244 psd_size = vcdinfo_get_psd_size (obj);
1245
1246 if (vcdinfo_read_psd (obj))
1247 {
1248 /* ISO9660 crosscheck */
1249 p_statbuf = iso9660_fs_stat (p_cdio,
1250 ((vcdinfo_get_VCD_type(obj) == VCD_TYPE_SVCD
1251 || vcdinfo_get_VCD_type(obj) == VCD_TYPE_HQVCD)
1252 ? "/SVCD/PSD.SVD;1"
1253 : "/VCD/PSD.VCD;1"));
1254 if (!p_statbuf)
1255 vcd_warn ("no PSD file entry found in ISO9660 fs");
1256 else {
1257 if (psd_size != p_statbuf->size)
1258 vcd_warn ("ISO9660 psd size != INFO psd size");
1259 if (p_statbuf->lsn != PSD_VCD_SECTOR)
1260 vcd_warn ("psd file entry in ISO9660 not at fixed LSN");
1261 free(p_statbuf);
1262 }
1263
1264 }
1265
1266 dump_all (obj);
1267 vcdinfo_close(obj);
1268 return;
1269
1270 err_exit:
1271 poptFreeContext(optCon);
1272 exit (EXIT_FAILURE);
1273 }
1274
1275 static vcd_log_handler_t gl_default_vcd_log_handler = NULL;
1276 static cdio_log_handler_t gl_default_cdio_log_handler = NULL;
1277
1278 static void
_vcd_log_handler(vcd_log_level_t level,const char message[])1279 _vcd_log_handler (vcd_log_level_t level, const char message[])
1280 {
1281 if (level == VCD_LOG_DEBUG && !(gl.debug_level >= 1))
1282 return;
1283
1284 if (level == VCD_LOG_INFO && gl.quiet_flag)
1285 return;
1286
1287 if (level == VCD_LOG_WARN && gl.suppress_warnings)
1288 return;
1289
1290 gl_default_vcd_log_handler (level, message);
1291 }
1292
1293 /* Configuration option codes */
1294 enum {
1295
1296 /* These correspond to driver_id_t in cdio.h and have to MATCH! */
1297 OP_SOURCE_UNDEF = DRIVER_UNKNOWN,
1298 OP_SOURCE_BINCUE = DRIVER_BINCUE,
1299 OP_SOURCE_NRG = DRIVER_NRG,
1300 OP_SOURCE_CDRDAO = DRIVER_CDRDAO,
1301 OP_SOURCE_DEVICE = DRIVER_DEVICE,
1302 OP_SOURCE_SECTOR_2336,
1303
1304 /* These are the remaining configuration options */
1305 OP_VERSION, OP_ENTRIES, OP_INFO, OP_PVD, OP_SHOW,
1306 OP_ACCESS_MODE
1307
1308 };
1309
1310 /* Initialize global variables. */
1311 static void
init()1312 init()
1313 {
1314 gl.debug_level = 0;
1315 gl.quiet_flag = false;
1316 gl.source_type = DRIVER_UNKNOWN;
1317 gl.access_mode = NULL;
1318
1319 /* Set all of show-flag entries false in one go. */
1320 memset(&gl.show, false, sizeof(gl.show));
1321 /* Actually this was a little too much. :-) The default behaviour is
1322 to show everything. So the one below assignment (if it persists
1323 until after options processing) negates, all of the work of the
1324 memset above! */
1325 gl.show.all = true;
1326 }
1327
1328 /* Structure used so we can binary sort and set a --show-xxx flag switch. */
1329 typedef struct
1330 {
1331 char name[30];
1332 int *flag;
1333 } subopt_entry_t;
1334
1335 /* Comparison function called by bearch() to find sub-option record. */
1336 static int
compare_subopts(const void * key1,const void * key2)1337 compare_subopts(const void *key1, const void *key2)
1338 {
1339 subopt_entry_t *a = (subopt_entry_t *) key1;
1340 subopt_entry_t *b = (subopt_entry_t *) key2;
1341 return (strncmp(a->name, b->name, 30));
1342 }
1343
1344 /* Do processing of a --show-xxx sub option.
1345 Basically we find the option in the array, set it's corresponding
1346 flag variable to true as well as the "show.all" false.
1347 */
1348 static void
process_suboption(const char * subopt,subopt_entry_t * sublist,const int num,const char * subopt_name,int * any_flag)1349 process_suboption(const char *subopt, subopt_entry_t *sublist, const int num,
1350 const char *subopt_name, int *any_flag)
1351 {
1352 subopt_entry_t *subopt_rec =
1353 bsearch(subopt, sublist, num, sizeof(subopt_entry_t),
1354 &compare_subopts);
1355 if (subopt_rec != NULL) {
1356 if (strcmp(subopt_name, "help") != 0) {
1357 gl.show.all = false;
1358 *(subopt_rec->flag) = true;
1359 *any_flag = true;
1360 return;
1361 }
1362 } else {
1363 unsigned int i;
1364 bool is_help=strcmp(subopt, "help")==0;
1365 if (is_help) {
1366 fprintf (stderr, "The list of sub options for \"%s\" are:\n",
1367 subopt_name);
1368 } else {
1369 fprintf (stderr, "Invalid option following \"%s\": %s.\n",
1370 subopt_name, subopt);
1371 fprintf (stderr, "Should be one of: ");
1372 }
1373 for (i=0; i<num-1; i++) {
1374 fprintf(stderr, "%s, ", sublist[i].name);
1375 }
1376 fprintf(stderr, "or %s.\n", sublist[num-1].name);
1377 exit (is_help ? EXIT_SUCCESS : EXIT_FAILURE);
1378 }
1379 }
1380
1381
1382 int
main(int argc,const char * argv[])1383 main (int argc, const char *argv[])
1384 {
1385 int terse_flag = false;
1386 int sector_2336_flag = 0;
1387 char *source_name = NULL;
1388 const char **args = NULL;
1389
1390 int opt;
1391 char *opt_arg;
1392
1393 /* Command-line options */
1394 struct poptOption optionsTable[] = {
1395
1396 {"access-mode", 'a',
1397 POPT_ARG_STRING, &gl.access_mode,
1398 OP_ACCESS_MODE,
1399 "set CD-ROM access mode (IOCTL, READ_10, READ_CD)", "ACCESS"},
1400
1401 {"bin-file", 'b', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, &source_name,
1402 OP_SOURCE_BINCUE, "set \"bin\" CD-ROM disk image file as source", "FILE"},
1403
1404 {"cue-file", 'c', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, &source_name,
1405 OP_SOURCE_BINCUE, "set \"cue\" CD-ROM disk image file as source", "FILE"},
1406
1407 {"nrg-file", 'N', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, &source_name,
1408 OP_SOURCE_NRG, "set Nero CD-ROM disk image file as source", "FILE"},
1409
1410 {"toc-file", '\0', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, &source_name,
1411 OP_SOURCE_CDRDAO, "set \"toc\" CD-ROM disk image file as source", "FILE"},
1412
1413 {"input", 'i', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, &source_name,
1414 OP_SOURCE_UNDEF,
1415 "set source and determine if \"bin\" image or device", "FILE"},
1416
1417 {"no-ext-psd", '\0', POPT_ARG_NONE, &gl.no_ext_psd_flag, 0,
1418 "ignore information in /EXT/PSD_X.VCD"},
1419
1420 {"sector-2336", '\0',
1421 POPT_ARG_NONE, §or_2336_flag,
1422 OP_SOURCE_SECTOR_2336,
1423 "use 2336 byte sector mode for image file"},
1424
1425 {"cdrom-device", 'C',
1426 POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, &source_name,
1427 OP_SOURCE_DEVICE,
1428 "set CD-ROM device as source", "DEVICE"},
1429
1430 {"debug", 'd', POPT_ARG_INT, &gl.debug_level, 0,
1431 "Set debugging output to LEVEL"},
1432
1433 {"terse", 't', POPT_ARG_NONE, &terse_flag, 0,
1434 "same as --no-header --no-banner --no-delimiter"},
1435
1436 {"no-banner", 'B', POPT_ARG_NONE, &gl.show.no.banner, 0,
1437 "do not show program banner header and RCS version string"},
1438
1439 {"no-delimiter", 'D', POPT_ARG_NONE, &gl.show.no.delimiter, 0,
1440 "do not show delimiter lines around various sections of output"},
1441
1442 {"no-header", 'H', POPT_ARG_NONE, &gl.show.no.header, 0,
1443 "do not show section header titles"},
1444
1445 {"show-entries", '\0', POPT_ARG_STRING, &opt_arg, OP_ENTRIES,
1446 "show specific entry of the ENTRIES section "},
1447
1448 {"show-entries-all", 'E', POPT_ARG_NONE, &gl.show.entries.all, OP_SHOW,
1449 "show ENTRIES section"},
1450
1451 {"show-filesystem", 'F', POPT_ARG_NONE, &gl.show.fs, OP_SHOW,
1452 "show filesystem info"},
1453
1454 {"show-info", '\0', POPT_ARG_STRING, &opt_arg, OP_INFO,
1455 "show specific entry of the INFO section "},
1456
1457 {"show-info-all", 'I', POPT_ARG_NONE, &gl.show.info.all, OP_SHOW,
1458 "show INFO section"},
1459
1460 {"show-lot", 'L', POPT_ARG_NONE, &gl.show.lot, OP_SHOW,
1461 "show LOT section"},
1462
1463 {"show-psd", 'p', POPT_ARG_NONE, &gl.show.psd, OP_SHOW,
1464 "show PSD section(s)"},
1465
1466 {"show-pvd-all", 'P', POPT_ARG_NONE, &gl.show.pvd.all, OP_SHOW,
1467 "show PVD section(s)"},
1468
1469 {"show-pvd", '\0', POPT_ARG_STRING, &opt_arg, OP_PVD,
1470 "show a specific entry of the Primary Volume Descriptor (PVD) section"},
1471
1472 {"show-scandata", 's', POPT_ARG_NONE, &gl.show.scandata, OP_SHOW,
1473 "show scan data"},
1474
1475 {"show-search", 'X', POPT_ARG_NONE, &gl.show.search, OP_SHOW,
1476 "show search data"},
1477
1478 {"show-source", 'S', POPT_ARG_NONE, &gl.show.source, OP_SHOW,
1479 "show source image filename and size"},
1480
1481 {"show-tracks", 'T', POPT_ARG_NONE, &gl.show.tracks, OP_SHOW,
1482 "show tracks"},
1483
1484 {"show-format", 'f', POPT_ARG_NONE, &gl.show.format, OP_SHOW,
1485 "show VCD format (VCD 1.1, VCD 2.0, SVCD, ...)"},
1486
1487 {"quiet", 'q', POPT_ARG_NONE, &gl.quiet_flag, 0,
1488 "show only critical messages"},
1489
1490 {"version", 'V', POPT_ARG_NONE, NULL, OP_VERSION,
1491 "display version and copyright information and exit"},
1492 POPT_AUTOHELP {NULL, 0, 0, NULL, 0}
1493 };
1494
1495 /* Sub-options of for --show-entries. Note: entries must be sorted! */
1496 subopt_entry_t entries_sublist[] = {
1497 {"count", &gl.show.entries.count},
1498 {"data", &gl.show.entries.data},
1499 {"id", &gl.show.entries.id},
1500 {"prof", &gl.show.entries.prof},
1501 {"vers", &gl.show.entries.vers}
1502 };
1503
1504 /* Sub-options of for --show-info. Note: entries must be sorted! */
1505 subopt_entry_t info_sublist[] = {
1506 {"album", &gl.show.info.album},
1507 {"cc", &gl.show.info.cc},
1508 {"count", &gl.show.info.count},
1509 {"id", &gl.show.info.id},
1510 {"ofm", &gl.show.info.ofm},
1511 {"lid2", &gl.show.info.lid2},
1512 {"lidn", &gl.show.info.lidn},
1513 {"pal", &gl.show.info.pal},
1514 {"pbc", &gl.show.info.pbc},
1515 {"prof", &gl.show.info.prof},
1516 {"psds", &gl.show.info.psds},
1517 {"res", &gl.show.info.res},
1518 {"seg", &gl.show.info.seg},
1519 {"segn", &gl.show.info.segn},
1520 {"segs", &gl.show.info.segs},
1521 {"spec", &gl.show.info.spec},
1522 {"start", &gl.show.info.start},
1523 {"st2", &gl.show.info.st2},
1524 {"vers", &gl.show.info.vers},
1525 {"vol", &gl.show.info.vol},
1526 };
1527
1528 /* Sub-options of for --show-pvd. Note: entries must be sorted! */
1529 subopt_entry_t pvd_sublist[] = {
1530 {"app", &gl.show.pvd.app},
1531 {"id", &gl.show.pvd.id},
1532 {"iso", &gl.show.pvd.iso},
1533 {"prep", &gl.show.pvd.prep},
1534 {"pub", &gl.show.pvd.pub},
1535 {"sys", &gl.show.pvd.sys},
1536 {"vers", &gl.show.pvd.vers},
1537 {"vol", &gl.show.pvd.vol},
1538 {"volset",&gl.show.pvd.volset},
1539 {"xa", &gl.show.pvd.xa},
1540 };
1541
1542 optCon = poptGetContext (NULL, argc, argv, optionsTable, 0);
1543
1544 init();
1545
1546 /* end of local declarations */
1547
1548 while ((opt = poptGetNextOpt (optCon)) != -1)
1549 switch (opt)
1550 {
1551 case OP_ENTRIES:
1552 {
1553 process_suboption(opt_arg, entries_sublist,
1554 sizeof(entries_sublist) / sizeof(subopt_entry_t),
1555 "--show-entries", &gl.show.entries.any);
1556 break;
1557 }
1558 case OP_INFO:
1559 {
1560 process_suboption(opt_arg, info_sublist,
1561 sizeof(info_sublist) / sizeof(subopt_entry_t),
1562 "--show-info", &gl.show.info.any);
1563 break;
1564 }
1565 case OP_PVD:
1566 {
1567 process_suboption(opt_arg, pvd_sublist,
1568 sizeof(pvd_sublist) / sizeof(subopt_entry_t),
1569 "--show-pvd", &gl.show.pvd.any);
1570 break;
1571 }
1572 case OP_SHOW:
1573 gl.show.all = false;
1574 break;
1575 case OP_VERSION:
1576 fprintf (stdout, vcd_version_string (true), "vcd-info");
1577 fflush (stdout);
1578 poptFreeContext(optCon);
1579 exit (EXIT_SUCCESS);
1580 break;
1581
1582 case OP_ACCESS_MODE:
1583 /* Make sure a we do only once? */
1584 break;
1585
1586 case OP_SOURCE_UNDEF:
1587 case OP_SOURCE_BINCUE:
1588 case OP_SOURCE_CDRDAO:
1589 case OP_SOURCE_NRG:
1590 case OP_SOURCE_DEVICE:
1591 case OP_SOURCE_SECTOR_2336:
1592 {
1593 /* Check that we didn't speciy both DEVICE and SECTOR */
1594 bool okay = false;
1595 switch (gl.source_type) {
1596 case OP_SOURCE_UNDEF:
1597 /* Nothing was set before - okay. */
1598 okay = true;
1599 gl.source_type = opt;
1600 break;
1601 case OP_SOURCE_BINCUE:
1602 /* Going from 2352 (default) to 2336 is okay. */
1603 okay = OP_SOURCE_SECTOR_2336 == opt;
1604 if (okay)
1605 gl.source_type = OP_SOURCE_SECTOR_2336;
1606 break;
1607 case OP_SOURCE_SECTOR_2336:
1608 /* Make sure a we didn't do a second device. FIX:
1609 This also allows two -bin options if we had -2336 in the middle
1610 */
1611 okay = OP_SOURCE_DEVICE != opt;
1612 break;
1613 case OP_SOURCE_NRG:
1614 case OP_SOURCE_CDRDAO:
1615 case OP_SOURCE_DEVICE:
1616 /* This case is implied, but we'll make it explicit anyway. */
1617 okay = false;
1618 break;
1619 }
1620
1621 if (!okay)
1622 {
1623 fprintf (stderr, "only one source allowed! - try --help\n");
1624 poptFreeContext(optCon);
1625 exit (EXIT_FAILURE);
1626 }
1627 break;
1628 }
1629
1630 default:
1631 fprintf (stderr, "%s: %s\n",
1632 poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
1633 poptStrerror(opt));
1634 fprintf (stderr, "error while parsing command line - try --help\n");
1635 poptFreeContext(optCon);
1636 exit (EXIT_FAILURE);
1637 }
1638
1639 if ((args = poptGetArgs (optCon)) != NULL)
1640 {
1641 if (args[1]) {
1642 fprintf ( stderr, "too many arguments - try --help");
1643 poptFreeContext(optCon);
1644 exit (EXIT_FAILURE);
1645 }
1646
1647 if (source_name) {
1648 fprintf ( stderr,
1649 "source file specified as an option and without "
1650 " - try --help\n");
1651 poptFreeContext(optCon);
1652 exit (EXIT_FAILURE);
1653 }
1654
1655 source_name = strdup(args[0]);
1656 gl.source_type = OP_SOURCE_UNDEF;
1657 }
1658
1659 if (gl.debug_level == 3) {
1660 vcd_loglevel_default = VCD_LOG_INFO;
1661 cdio_loglevel_default = CDIO_LOG_INFO;
1662 } else if (gl.debug_level >= 4) {
1663 vcd_loglevel_default = VCD_LOG_DEBUG;
1664 cdio_loglevel_default = CDIO_LOG_INFO;
1665 }
1666
1667 /* Handle massive show flag reversals below. */
1668 if (gl.show.all) {
1669 gl.show.entries.all = gl.show.pvd.all = gl.show.info.all
1670 = gl.show.format = gl.show.fs = gl.show.lot = gl.show.psd
1671 = gl.show.scandata = gl.show.search = gl.show.source
1672 = gl.show.tracks = true;
1673 }
1674
1675 if (gl.show.entries.all)
1676 memset(&gl.show.entries, true, sizeof(gl.show.entries));
1677
1678 if (gl.show.pvd.all)
1679 memset(&gl.show.pvd, true, sizeof(gl.show.pvd));
1680
1681 if (gl.show.info.all)
1682 memset(&gl.show.info, true, sizeof(gl.show.info));
1683
1684 if (terse_flag)
1685 memset(&gl.show.no, true, sizeof(gl.show.no));
1686
1687 gl_default_vcd_log_handler = vcd_log_set_handler (_vcd_log_handler);
1688 gl_default_cdio_log_handler =
1689 cdio_log_set_handler ( (cdio_log_handler_t) _vcd_log_handler);
1690
1691 dump (&source_name);
1692
1693 free(source_name);
1694 poptFreeContext(optCon);
1695 return EXIT_SUCCESS;
1696 }
1697
1698 /*
1699 * Local variables:
1700 * c-file-style: "gnu"
1701 * tab-width: 8
1702 * indent-tabs-mode: nil
1703 * End:
1704 */
1705