1 /* @(#)toc.c 1.107 20/07/16 Copyright 1998-2003,2017 Heiko Eissfeldt, Copyright 2004-2020 J. Schilling */
2 #include "config.h"
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)toc.c 1.107 20/07/16 Copyright 1998-2003,2017 Heiko Eissfeldt, Copyright 2004-2020 J. Schilling";
6 #endif
7 /*
8 * CDDA2WAV (C) Heiko Eissfeldt heiko@hexco.de
9 * Copyright (c) 2004-2020 J. Schilling, Heiko Eissfeldt
10 *
11 * The CDDB routines are compatible to cddbd (C) Ti Kan and Steve Scherf
12 */
13 /*
14 * The contents of this file are subject to the terms of the
15 * Common Development and Distribution License, Version 1.0 only
16 * (the "License"). You may not use this file except in compliance
17 * with the License.
18 *
19 * See the file CDDL.Schily.txt in this distribution for details.
20 * A copy of the CDDL is also available via the Internet at
21 * http://www.opensource.org/licenses/cddl1.txt
22 *
23 * When distributing Covered Code, include this CDDL HEADER in each
24 * file and include the License file CDDL.Schily.txt from this distribution.
25 */
26
27 #include "config.h"
28 #include <schily/stdio.h>
29 #include <schily/standard.h>
30 #include <schily/stdlib.h>
31 #include <schily/string.h>
32 #include <schily/utypes.h>
33 #include <schily/intcvt.h>
34 #include <schily/unistd.h> /* sleep */
35 #include <schily/ctype.h>
36 #include <schily/errno.h>
37 #include <schily/fcntl.h>
38 #include <schily/varargs.h>
39 #include <schily/nlsdefs.h>
40 #include <schily/hostname.h>
41 #include <schily/ioctl.h>
42 #include <schily/sha1.h>
43
44 #include <scg/scsitransp.h>
45
46 /* tcp stuff */
47 /* fix OS/2 compilation */
48 #ifdef __EMX__
49 #define gethostid nogethostid
50 #endif
51
52 #include <schily/socket.h>
53 #undef gethostid
54 #include <schily/in.h>
55 #include <schily/netdb.h>
56
57 #include "mytype.h"
58 #include "byteorder.h"
59 #include "interface.h"
60 #include "cdda2wav.h"
61 #include "global.h"
62 #include "base64.h"
63 #include "toc.h"
64 #include "exitcodes.h"
65 #include "ringbuff.h"
66 #include "version.h"
67
68 #include <schily/schily.h>
69
70 #define CD_TEXT
71 #define CD_EXTRA
72 #undef DEBUG_XTRA
73 #undef DEBUG_CDTEXT
74 #undef DEBUG_CDDBP
75
76
77 int have_CD_text;
78 int have_multisession;
79 int have_CD_extra;
80 int have_CDDB;
81
82 struct iterator;
83
84 int Get_Mins __PR((unsigned long p_track));
85 int Get_Secs __PR((unsigned long p_track));
86 int Get_Frames __PR((unsigned long p_track));
87 int Get_Flags __PR((unsigned long p_track));
88 int Get_SCMS __PR((unsigned long p_track));
89
90 LOCAL void UpdateTrackData __PR((int p_num));
91 LOCAL void UpdateIndexData __PR((int p_num));
92 LOCAL void UpdateTimeData __PR((int p_min, int p_sec, int p_frm));
93 LOCAL unsigned int is_multisession __PR((void));
94 LOCAL unsigned int get_end_of_last_audio_track __PR((unsigned mult_off));
95 LOCAL void check_hidden __PR((void));
96 LOCAL int cddb_sum __PR((int n));
97 LOCAL void dump_extra_info __PR((unsigned from));
98 LOCAL int GetIndexOfSector __PR((unsigned sec, unsigned track));
99 LOCAL int patch_cd_extra __PR((unsigned track, unsigned long sector));
100 LOCAL void patch_to_audio __PR((unsigned long p_track));
101 LOCAL int restrict_tracks_illleadout __PR((void));
102
103 LOCAL void Set_MCN __PR((unsigned char *MCN_arg));
104 LOCAL void Set_ISRC __PR((unsigned track,
105 const unsigned char *ISRC_arg));
106
107 LOCAL unsigned char g_track = 0xff; /* current track */
108 LOCAL unsigned char g_index = 0xff; /* current index */
109
110
111 LOCAL void InitIterator __PR((struct iterator *iter, unsigned long p_track));
112
113
114 /*
115 * Conversion function: from logical block addresses to minute,second,frame
116 */
117 int
lba_2_msf(lba,m,s,f)118 lba_2_msf(lba, m, s, f)
119 long lba;
120 int *m;
121 int *s;
122 int *f;
123 {
124 #ifdef __follow_redbook__
125 if (lba >= -150 && lba < 405000) { /* lba <= 404849 */
126 #else
127 if (lba >= -150) {
128 #endif
129 lba += 150;
130 } else if (lba >= -45150 && lba <= -151) {
131 lba += 450150;
132 } else
133 return (1);
134
135 *m = lba / 60 / 75;
136 lba -= (*m)*60*75;
137 *s = lba / 75;
138 lba -= (*s)*75;
139 *f = lba;
140
141 return (0);
142 }
143
144 /*
145 * print the track currently read
146 */
147 LOCAL void
UpdateTrackData(p_num)148 UpdateTrackData(p_num)
149 int p_num;
150 {
151 if (global.quiet == 0) {
152 fprintf(outfp, _("\ntrack: %.2d, "), p_num); fflush(outfp);
153 }
154 g_track = (unsigned char) p_num;
155 }
156
157
158 /*
159 * print the index currently read
160 */
161 LOCAL void
UpdateIndexData(p_num)162 UpdateIndexData(p_num)
163 int p_num;
164 {
165 if (global.quiet == 0) {
166 fprintf(outfp, _("index: %.2d\n"), p_num); fflush(outfp);
167 }
168 g_index = (unsigned char) p_num;
169 }
170
171
172 /*
173 * print the time of track currently read
174 */
175 LOCAL void
UpdateTimeData(p_min,p_sec,p_frm)176 UpdateTimeData(p_min, p_sec, p_frm)
177 int p_min;
178 int p_sec;
179 int p_frm;
180 {
181 if (global.quiet == 0) {
182 fprintf(outfp, _("time: %.2d:%.2d.%.2d\r"), p_min, p_sec, p_frm);
183 fflush(outfp);
184 }
185 }
186
187 void
AnalyzeQchannel(frame)188 AnalyzeQchannel(frame)
189 unsigned frame;
190 {
191 if (trackindex_disp != 0) {
192 subq_chnl *sub_ch;
193
194 sub_ch = ReadSubQ(get_scsi_p(), GET_POSITIONDATA, 0);
195
196 /*
197 * analyze sub Q-channel data
198 */
199 if (sub_ch->track != g_track ||
200 sub_ch->index != g_index) {
201 UpdateTrackData(sub_ch->track);
202 UpdateIndexData(sub_ch->index);
203 }
204 }
205 frame += 150;
206 UpdateTimeData((unsigned char) (frame / (60*75)),
207 (unsigned char) ((frame % (60*75)) / 75),
208 (unsigned char) (frame % 75));
209 }
210
211 unsigned cdtracks = 0;
212 LOCAL int have_hiddenAudioTrack = 0;
213
214 int
no_disguised_audiotracks()215 no_disguised_audiotracks()
216 {
217 /*
218 * we can assume no audio tracks according to toc here.
219 * read a data sector from the first data track
220 */
221 unsigned char p[3000];
222 int retval;
223
224 get_scsi_p()->silent++;
225 retval = 1 == ReadCdRomData(get_scsi_p(), p, Get_StartSector(1), 1);
226 get_scsi_p()->silent--;
227 if (retval == 0) {
228 int i;
229
230 errmsgno(EX_BAD,
231 _("Warning: wrong track types found: patching to audio...\n"));
232 for (i = 0; i < cdtracks; i++)
233 patch_to_audio(i);
234 }
235 return (retval);
236 }
237
238
239 #undef SIM_ILLLEADOUT
240 int
ReadToc()241 ReadToc()
242 {
243 int retval = (*doReadToc)(get_scsi_p());
244
245 #if defined SIM_ILLLEADOUT
246 extern TOC g_toc[MAXTRK+1]; /* hidden track + 100 regular tracks */
247
248 g_toc[cdtracks+1] = 20*75;
249 #endif
250 return (retval);
251 }
252
253 LOCAL int can_read_illleadout __PR((void));
254
255 LOCAL int
can_read_illleadout()256 can_read_illleadout()
257 {
258 SCSI *scgp = get_scsi_p();
259
260 UINT4 buffer [CD_FRAMESIZE_RAW/4];
261 if (global.illleadout_cd == 0)
262 return (0);
263
264 scgp->silent++;
265 global.reads_illleadout =
266 ReadCdRom(scgp, buffer, Get_AudioStartSector(CDROM_LEADOUT), 1);
267 scgp->silent--;
268 return (global.reads_illleadout);
269 }
270
271
272 unsigned find_an_off_sector __PR((unsigned lSector,
273 unsigned SectorBurstVal));
274
275 unsigned
find_an_off_sector(lSector,SectorBurstVal)276 find_an_off_sector(lSector, SectorBurstVal)
277 unsigned lSector;
278 unsigned SectorBurstVal;
279 {
280 long track_of_start = Get_Track(lSector);
281 long track_of_end = Get_Track(lSector + SectorBurstVal -1);
282 long start = Get_AudioStartSector(track_of_start);
283 long end = Get_EndSector(track_of_end);
284
285 if (lSector - start > end - lSector + SectorBurstVal -1)
286 return (start);
287 else
288 return (end);
289 }
290
291 #ifdef CD_TEXT
292 #include "scsi_cmds.h"
293 #endif
294
295
296 int handle_cdtext __PR((void));
297
298 int
handle_cdtext()299 handle_cdtext()
300 {
301 #ifdef CD_TEXT
302 if (global.buf[0] == 0 && global.buf[1] == 0) {
303 have_CD_text = 0;
304 return (have_CD_text);
305 }
306
307 /*
308 * do a quick scan over all pack type indicators
309 */
310 {
311 int i;
312 int count_fails = 0;
313 int len = ((global.buf[0] & 0xFF) << 8) | (global.buf[1] & 0xFF);
314
315 len += 2;
316 len = min(len, global.bufsize);
317 for (i = 0; i < len-4; i += 18) {
318 if ((global.buf[4+i] & 0xFF) < 0x80 ||
319 (global.buf[4+i] & 0xFF) > 0x8f) {
320 count_fails++;
321 }
322 }
323 have_CD_text = len > 4 && count_fails < 3;
324 }
325
326 #else
327 have_CD_text = 0;
328 #endif
329 return (have_CD_text);
330 }
331
332
333 #ifdef CD_TEXT
334 #include "cd_text.c"
335 #endif
336
337
338 #if defined CDROMMULTISESSION
339 LOCAL int tmp_fd;
340 #endif
341
342 #ifdef CD_EXTRA
343 #include "cd_extra.c"
344 #endif
345
346 LOCAL unsigned session_start;
347 /*
348 * A Cd-Extra is detected, if it is a multisession CD with
349 * only audio tracks in the first session and a data track
350 * in the last session.
351 */
352 LOCAL unsigned
is_multisession()353 is_multisession()
354 {
355 unsigned mult_off;
356 #if defined CDROMMULTISESSION
357 /*
358 * FIXME: we would have to do a ioctl (CDROMMULTISESSION)
359 * for the cdrom device associated with the generic device
360 * not just AUX_DEVICE
361 */
362 struct cdrom_multisession ms_str;
363
364 if (interface == GENERIC_SCSI)
365 tmp_fd = open(global.aux_name, O_RDONLY);
366 else
367 tmp_fd = global.cooked_fd;
368
369 if (tmp_fd != -1) {
370 int result;
371
372 ms_str.addr_format = CDROM_LBA;
373 result = ioctl(tmp_fd, CDROMMULTISESSION, &ms_str);
374 if (result == -1) {
375 if (global.verbose != 0)
376 errmsg(_("Multi session ioctl not supported.\n"));
377 } else {
378 #ifdef DEBUG_XTRA
379 fprintf(outfp,
380 _("current ioctl multisession_offset = %u\n"),
381 ms_str.addr.lba);
382 #endif
383 if (interface == GENERIC_SCSI)
384 close(tmp_fd);
385 if (ms_str.addr.lba > 0)
386 return (ms_str.addr.lba);
387 }
388 }
389 #endif
390 mult_off = 0;
391 if (LastAudioTrack() + 1 == FirstDataTrack()) {
392 mult_off = Get_StartSector(FirstDataTrack());
393 }
394
395 #ifdef DEBUG_XTRA
396 fprintf(outfp,
397 _("current guessed multisession_offset = %u\n"),
398 mult_off);
399 #endif
400 return (mult_off);
401 }
402
403 #define SESSIONSECTORS (152*75)
404 /*
405 * The solution is to read the Table of Contents of the first
406 * session only (if the drive permits that) and directly use
407 * the start of the leadout. If this is not supported, we subtract
408 * a constant of SESSIONSECTORS sectors (found heuristically).
409 */
410 LOCAL unsigned
get_end_of_last_audio_track(mult_off)411 get_end_of_last_audio_track(mult_off)
412 unsigned mult_off;
413 {
414 unsigned retval;
415
416 /*
417 * Try to read the first session table of contents.
418 * This works for Sony and mmc type drives.
419 */
420 if (ReadLastAudio && (retval = ReadLastAudio(get_scsi_p())) != 0) {
421 return (retval);
422 } else {
423 return (mult_off - SESSIONSECTORS);
424 }
425 }
426
427 LOCAL void dump_cdtext_info __PR((void));
428
429 #if defined CDDB_SUPPORT
430 LOCAL void emit_cddb_form __PR((char *fname_baseval));
431 #endif
432
433 #if defined CDINDEX_SUPPORT
434 LOCAL void emit_cdindex_form __PR((char *fname_baseval));
435 #endif
436
437
438 typedef struct TOC { /* structure of table of contents (cdrom) */
439 unsigned char reserved1;
440 unsigned char bFlags;
441 unsigned char bTrack;
442 unsigned char reserved2;
443 unsigned int dwStartSector;
444 int mins;
445 int secs;
446 int frms;
447 unsigned char ISRC[16];
448 int SCMS;
449 } TOC;
450
451
452 /*
453 * Flags contains two fields:
454 * bits 7-4 (ADR)
455 * : 0 no sub-q-channel information
456 * : 1 sub-q-channel contains current position
457 * : 2 sub-q-channel contains media catalog number
458 * : 3 sub-q-channel contains International Standard
459 * Recording Code ISRC
460 * : other values reserved
461 * bits 3-0 (Control) :
462 * bit 3 : when set indicates there are 4 audio channels else 2 channels
463 * bit 2 : when set indicates this is a data track else an audio track
464 * bit 1 : when set indicates digital copy is permitted else prohibited
465 * bit 0 : when set indicates pre-emphasis is present else not present
466 */
467
468 #define GETFLAGS(x) ((x)->bFlags)
469 #define GETTRACK(x) ((x)->bTrack)
470 #define GETSTART(x) ((x)->dwStartSector)
471 #define GETMINS(x) ((x)->mins)
472 #define GETSECS(x) ((x)->secs)
473 #define GETFRAMES(x) ((x)->frms)
474 #define GETISRC(x) ((x)->ISRC)
475
476 #define IS__PREEMPHASIZED(p) ((GETFLAGS(p) & 0x10) != 0)
477 #define IS__INCREMENTAL(p) ((GETFLAGS(p) & 0x10) != 0)
478 #define IS__COPYRESTRICTED(p) ((GETFLAGS(p) & 0x20) == 0)
479 #define IS__COPYRIGHTED(p) ((GETFLAGS(p) & 0x20) == 0)
480 #define IS__DATA(p) ((GETFLAGS(p) & 0x40) != 0)
481 #define IS__AUDIO(p) ((GETFLAGS(p) & 0x40) == 0)
482 #define IS__QUADRO(p) ((GETFLAGS(p) & 0x80) != 0)
483
484 /*
485 * Iterator interface inspired from Java
486 */
487 struct iterator {
488 int index;
489 int startindex;
490 void (*reset) __PR((struct iterator *this));
491 struct TOC *(*getNextTrack) __PR((struct iterator *this));
492 int (*hasNextTrack) __PR((struct iterator *this));
493 };
494
495
496 /*
497 * The Table of Contents needs to be corrected if we
498 * have a CD-Extra. In this case all audio tracks are
499 * followed by a data track (in the second session).
500 * Unlike for single session CDs the end of the last audio
501 * track cannot be set to the start of the following
502 * track, since the lead-out and lead-in would then
503 * errenously be part of the audio track. This would
504 * lead to read errors when trying to read into the
505 * lead-out area.
506 * So the length of the last track in case of Cd-Extra
507 * has to be fixed.
508 */
509 unsigned
FixupTOC(no_tracks)510 FixupTOC(no_tracks)
511 unsigned no_tracks;
512 {
513 unsigned mult_off;
514 unsigned offset = 0;
515 int j = -1;
516 unsigned real_end = 2000000;
517
518 /*
519 * get the multisession offset in sectors
520 */
521 mult_off = is_multisession();
522
523 /*
524 * if the first track address had been the victim of an underflow,
525 * set it to zero.
526 */
527 if (Get_StartSector(1) > Get_StartSector(LastTrack())) {
528 errmsgno(EX_BAD,
529 _("Warning: first track has negative start sector! Setting to zero.\n"));
530 toc_entry(1, Get_Flags(1), Get_Tracknumber(1),
531 Get_ISRC(1), 0, 0, 2, 0);
532 }
533
534 #ifdef DEBUG_XTRA
535 fprintf(outfp, "current multisession_offset = %u\n", mult_off);
536 #endif
537 dump_cdtext_info();
538
539 if (mult_off > 100) { /* the offset has to have a minimum size */
540
541 /*
542 * believe the multisession offset :-)
543 * adjust end of last audio track to be in the first session
544 */
545 real_end = get_end_of_last_audio_track(mult_off);
546 #ifdef DEBUG_XTRA
547 fprintf(outfp, "current end = %u\n", real_end);
548 #endif
549
550 j = FirstDataTrack();
551 if (LastAudioTrack() + 1 == j) {
552 long sj = Get_StartSector(j);
553
554 if (sj > (long)real_end) {
555 session_start = mult_off;
556 have_multisession = sj;
557
558 #ifdef CD_EXTRA
559 offset = Read_CD_Extra_Info(sj);
560
561 if (offset != 0) {
562 have_CD_extra = sj;
563 dump_extra_info(offset);
564 }
565 #endif
566 }
567 }
568 }
569 if (global.cddbp) {
570 #if defined USE_REMOTE
571 if (global.disctitle == NULL) {
572 have_CDDB = !request_titles();
573 }
574 #else
575 errmsgno(EX_BAD,
576 _("Cannot lookup titles: no cddbp support included!\n"));
577 #endif
578 }
579 #if defined CDINDEX_SUPPORT || defined CDDB_SUPPORT
580 if (have_CD_text || have_CD_extra || have_CDDB) {
581 unsigned long count_audio_tracks = 0;
582 struct iterator i;
583
584 InitIterator(&i, 1);
585
586 while (i.hasNextTrack(&i)) {
587 struct TOC *p = i.getNextTrack(&i);
588 if (IS__AUDIO(p))
589 count_audio_tracks++;
590 }
591
592 if (count_audio_tracks > 0 && global.no_cddbfile == 0) {
593 #if defined CDINDEX_SUPPORT
594 emit_cdindex_form(global.fname_base);
595 #endif
596 #if defined CDDB_SUPPORT
597 emit_cddb_form(global.fname_base);
598 #endif
599 }
600 }
601 #endif
602 if (have_multisession) {
603 /*
604 * set start of track to beginning of lead-out
605 */
606 patch_cd_extra(j, real_end);
607 #if defined CD_EXTRA && defined DEBUG_XTRA
608 fprintf(outfp,
609 "setting end of session (track %d) to %u\n",
610 j, real_end);
611 #endif
612 }
613 check_hidden();
614 return (offset);
615 }
616
617 LOCAL void
check_hidden()618 check_hidden()
619 {
620 long sect;
621
622 if (!global.no_hidden_track &&
623 (sect = Get_AudioStartSector(FirstAudioTrack())) > 0) {
624 myringbuff *p = RB_BASE; /* Not yet initialized */
625 int i;
626 int n;
627 BOOL isdata = TRUE;
628
629 get_scsi_p()->silent++;
630 /*
631 * switch cdrom to data mode
632 */
633 EnableCdda(get_scsi_p(), 0, 0);
634 i = ReadCdRomData(get_scsi_p(), (Uchar *)p->data, 0, 1);
635 if (i != 1) {
636 have_hiddenAudioTrack = 1;
637 isdata = FALSE;
638 }
639 if (global.quiet == 0) {
640 fprintf(outfp,
641 _("%ld sectors of %sdata before track #%ld"),
642 sect, !isdata ? _("audio "):"", FirstAudioTrack());
643 }
644 /*
645 * switch cdrom to audio mode
646 */
647 EnableCdda(get_scsi_p(), 1, CD_FRAMESIZE_RAW);
648 i = ReadCdRom(get_scsi_p(), p->data, 0, 1);
649 if (isdata && i != 1) {
650 if (global.quiet == 0) {
651 fprintf(outfp,
652 _(", ignoring.\n"));
653 }
654 } else if (i != 1) {
655 if (global.quiet == 0) {
656 fprintf(outfp,
657 _(", unreadable by this drive.\n"));
658 }
659 have_hiddenAudioTrack = 0;
660 } else {
661 for (n = 0; n < sect; n += global.nsectors) {
662 int o;
663
664 fillbytes(p->data, CD_FRAMESIZE_RAW, '\0');
665 i = ReadCdRom(get_scsi_p(), p->data, n, global.nsectors);
666 if (i != global.nsectors)
667 break;
668 if ((o = cmpnullbytes(p->data, global.nsectors * CD_FRAMESIZE_RAW)) <
669 global.nsectors * CD_FRAMESIZE_RAW) {
670 if (global.quiet == 0) {
671 fprintf(outfp,
672 _(", audible data at sector %d.\n"),
673 n + o / CD_FRAMESIZE_RAW);
674 }
675 break;
676 }
677 }
678 if (n >= sect) {
679 have_hiddenAudioTrack = 0;
680 if (global.quiet == 0)
681 fprintf(outfp, "\n");
682 } else {
683 if (global.quiet == 0)
684 fprintf(outfp,
685 _("Hidden audio track with %ld sectors found.\n"), sect);
686 }
687 }
688 get_scsi_p()->silent--;
689 }
690 }
691
692 LOCAL int
cddb_sum(n)693 cddb_sum(n)
694 int n;
695 {
696 int ret;
697
698 for (ret = 0; n > 0; n /= 10) {
699 ret += (n % 10);
700 }
701
702 return (ret);
703 }
704
705 void
calc_cddb_id()706 calc_cddb_id()
707 {
708 UINT4 i;
709 UINT4 t = 0;
710 UINT4 n = 0;
711
712 for (i = 1; i <= cdtracks; i++) {
713 n += cddb_sum(Get_StartSector(i)/75 + 2);
714 }
715
716 t = Get_StartSector(i)/75 - Get_StartSector(1)/75;
717
718 global.cddb_id = (n % 0xff) << 24 | (t << 8) | cdtracks;
719 }
720
721
722 #undef TESTCDINDEX
723 #ifdef TESTCDINDEX
724 void
TestGenerateId()725 TestGenerateId()
726 {
727 SHA1_CTX sha;
728 unsigned char digest[20], *base64;
729 unsigned long size;
730
731 SHA1Init(&sha);
732 SHA1Update(&sha, (unsigned char *)"0123456789", 10);
733 SHA1Final(digest, &sha);
734
735 base64 = rfc822_binary((char *)digest, 20, &size);
736 if (strncmp((char *) base64, "h6zsF82dzSCnFsws9nQXtxyKcBY-", size)) {
737 free(base64);
738
739 fprintf(outfp,
740 "The SHA-1 hash function failed to properly generate the\n");
741 fprintf(outfp, "test key.\n");
742 exit(INTERNAL_ERROR);
743 }
744 free(base64);
745 }
746 #endif
747
748 void
calc_cdindex_id()749 calc_cdindex_id()
750 {
751 SHA1_CTX sha;
752 unsigned char digest[20], *base64;
753 unsigned long size;
754 unsigned i;
755 char temp[9];
756
757 #ifdef TESTCDINDEX
758 extern TOC g_toc[MAXTRK+1]; /* hidden track + 100 regular tracks */
759
760 TestGenerateId();
761 g_toc[1].bTrack = 1;
762 cdtracks = 15;
763 g_toc[cdtracks].bTrack = 15;
764 i = 1;
765 g_toc[i++].dwStartSector = 0U;
766 g_toc[i++].dwStartSector = 18641U;
767 g_toc[i++].dwStartSector = 34667U;
768 g_toc[i++].dwStartSector = 56350U;
769 g_toc[i++].dwStartSector = 77006U;
770 g_toc[i++].dwStartSector = 106094U;
771 g_toc[i++].dwStartSector = 125729U;
772 g_toc[i++].dwStartSector = 149785U;
773 g_toc[i++].dwStartSector = 168885U;
774 g_toc[i++].dwStartSector = 185910U;
775 g_toc[i++].dwStartSector = 205829U;
776 g_toc[i++].dwStartSector = 230142U;
777 g_toc[i++].dwStartSector = 246659U;
778 g_toc[i++].dwStartSector = 265614U;
779 g_toc[i++].dwStartSector = 289479U;
780 g_toc[i++].dwStartSector = 325732U;
781 #endif
782 SHA1Init(&sha);
783 sprintf(temp, "%02X", Get_Tracknumber(1));
784 SHA1Update(&sha, (unsigned char *)temp, 2);
785 sprintf(temp, "%02X", Get_Tracknumber(cdtracks));
786 SHA1Update(&sha, (unsigned char *)temp, 2);
787
788 /* the position of the leadout comes first. */
789 sprintf(temp, "%08lX", 150 + Get_StartSector(CDROM_LEADOUT));
790 SHA1Update(&sha, (unsigned char *)temp, 8);
791
792 /* now 99 tracks follow with their positions. */
793 for (i = 1; i <= cdtracks; i++) {
794 sprintf(temp, "%08lX", 150+Get_StartSector(i));
795 SHA1Update(&sha, (unsigned char *)temp, 8);
796 }
797 for (i++; i <= 100; i++) {
798 SHA1Update(&sha, (unsigned char *)"00000000", 8);
799 }
800 SHA1Final(digest, &sha);
801
802 base64 = rfc822_binary((char *)digest, 20, &size);
803 global.cdindex_id = base64;
804 }
805
806
807 #if defined CDDB_SUPPORT
808
809 #ifdef PROTOTYPES
810 LOCAL void
escape_and_split(FILE * channel,const char * args,...)811 escape_and_split(FILE *channel, const char *args, ...)
812 #else
813 /*VARARGS3*/
814 LOCAL void
815 escape_and_split(channel, args, va_alist)
816 FILE *channel;
817 const char *args;
818 va_dcl
819 #endif
820 {
821 va_list marker;
822
823 int prefixlen;
824 int len;
825 char *q;
826
827 #ifdef PROTOTYPES
828 va_start(marker, args);
829 #else
830 va_start(marker);
831 #endif
832
833 prefixlen = strlen(args);
834 len = prefixlen;
835 fputs(args, channel);
836
837 q = va_arg(marker, char *);
838 while (*q != '\0') {
839 while (*q != '\0') {
840 len += 2;
841 if (*q == '\\')
842 fputs("\\\\", channel);
843 else if (*q == '\t')
844 fputs("\\t", channel);
845 else if (*q == '\n')
846 fputs("\\n", channel);
847 else {
848 fputc(*q, channel);
849 len--;
850 }
851 if (len > 78) {
852 fputc('\n', channel);
853 fputs(args, channel);
854 len = prefixlen;
855 }
856 q++;
857 }
858 q = va_arg(marker, char *);
859 }
860 fputc('\n', channel);
861
862 va_end(marker);
863 }
864
865 LOCAL void
emit_cddb_form(fname_baseval)866 emit_cddb_form(fname_baseval)
867 char *fname_baseval;
868 {
869 struct iterator i;
870 unsigned first_audio;
871 FILE *cddb_form;
872 char fname[200];
873 char *pp;
874
875 if (fname_baseval == NULL || fname_baseval[0] == 0)
876 return;
877
878 if (strcmp(fname_baseval, "standard_output") == 0)
879 return;
880 InitIterator(&i, 1);
881
882 strncpy(fname, fname_baseval, sizeof (fname) -1);
883 fname[sizeof (fname) -1] = 0;
884 pp = strrchr(fname, '.');
885 if (pp == NULL) {
886 pp = fname + strlen(fname);
887 }
888 strncpy(pp, ".cddb", sizeof (fname) - 1 - (pp - fname));
889
890 cddb_form = fopen(fname, "w");
891 if (cddb_form == NULL)
892 return;
893
894 first_audio = FirstAudioTrack();
895 fprintf(cddb_form, "# xmcd\n#\n");
896 fprintf(cddb_form, "# Track frame offsets:\n#\n");
897
898 while (i.hasNextTrack(&i)) {
899 struct TOC *p = i.getNextTrack(&i);
900
901 if (GETTRACK(p) == CDROM_LEADOUT)
902 break;
903 fprintf(cddb_form, "# %lu\n",
904 150 + Get_AudioStartSector(GETTRACK(p)));
905 }
906
907 fprintf(cddb_form, "#\n# Disc length: %lu seconds\n#\n",
908 (150 + Get_StartSector(CDROM_LEADOUT)) / 75);
909 fprintf(cddb_form, "# Revision: %u\n", global.cddb_revision);
910 fprintf(cddb_form, "# Submitted via: cdda2wav ");
911 fprintf(cddb_form, VERSION);
912 fprintf(cddb_form, VERSION_OS);
913 fprintf(cddb_form, "\n");
914
915 fprintf(cddb_form, "DISCID=%08lx\n", (unsigned long)global.cddb_id);
916
917 if (global.disctitle == NULL && global.performer == NULL) {
918 fprintf(cddb_form, "DTITLE=\n");
919 } else {
920 if (global.performer == NULL) {
921 escape_and_split(cddb_form, "DTITLE=",
922 global.disctitle, "");
923 } else if (global.disctitle == NULL) {
924 escape_and_split(cddb_form, "DTITLE=",
925 global.performer, "");
926 } else {
927 escape_and_split(cddb_form, "DTITLE=",
928 global.performer, " / ",
929 global.disctitle, "");
930 }
931 }
932 if (global.cddb_year != 0)
933 fprintf(cddb_form, "DYEAR=%4u\n", global.cddb_year);
934 else
935 fprintf(cddb_form, "DYEAR=\n");
936 fprintf(cddb_form, "DGENRE=%s\n", global.cddb_genre);
937
938 InitIterator(&i, 1);
939 while (i.hasNextTrack(&i)) {
940 struct TOC *p = i.getNextTrack(&i);
941 int ii;
942
943 ii = GETTRACK(p);
944 if (ii == CDROM_LEADOUT)
945 break;
946
947 if (global.tracktitle[ii] != NULL) {
948 char prefix[10];
949
950 sprintf(prefix, "TTITLE%d=", ii-1);
951 escape_and_split(cddb_form, prefix,
952 global.tracktitle[ii], "");
953 } else {
954 fprintf(cddb_form, "TTITLE%d=\n", ii-1);
955 }
956 }
957
958 if (global.copyright_message == NULL) {
959 fprintf(cddb_form, "EXTD=\n");
960 } else {
961 escape_and_split(cddb_form, "EXTD=", "Copyright ",
962 global.copyright_message, "");
963 }
964
965 InitIterator(&i, 1);
966 while (i.hasNextTrack(&i)) {
967 struct TOC *p = i.getNextTrack(&i);
968 int ii;
969
970 ii = GETTRACK(p);
971
972 if (ii == CDROM_LEADOUT)
973 break;
974
975 fprintf(cddb_form, "EXTT%d=\n", ii-1);
976 }
977 fprintf(cddb_form, "PLAYORDER=\n");
978 fclose(cddb_form);
979 }
980
981 #if defined USE_REMOTE
982 #include <schily/pwd.h>
983
984 LOCAL int readn __PR((register int fd, register char *ptr,
985 register int nbytes));
986 LOCAL int writen __PR((register int fd, register char *ptr,
987 register int nbytes));
988
989 LOCAL int
readn(fd,ptr,nbytes)990 readn(fd, ptr, nbytes)
991 register int fd;
992 register char *ptr;
993 register int nbytes;
994 {
995 int nread;
996
997 nread = _niread(fd, ptr, nbytes);
998 #ifdef DEBUG_CDDBP
999 if (nread > 0) {
1000 fprintf(outfp, "READ :(%d)", nread);
1001 write(2, ptr, nread);
1002 }
1003 #endif
1004 if (nread < 0) {
1005 errmsg(_("Socket read error: fd=%d, ptr=%p, nbytes=%d.\n"),
1006 fd, ptr, nbytes);
1007 ptr[0] = '\0';
1008 }
1009
1010 return (nread);
1011 }
1012
1013 LOCAL int
writen(fd,ptr,nbytes)1014 writen(fd, ptr, nbytes)
1015 register int fd;
1016 register char *ptr;
1017 register int nbytes;
1018 {
1019 int nwritten;
1020
1021 nwritten = _nixwrite(fd, ptr, nbytes);
1022 #ifdef DEBUG_CDDBP
1023 if (nwritten <= 0)
1024 fprintf(outfp, "WRITE:%s\n", ptr);
1025 #endif
1026 if (nwritten < 0) {
1027 errmsg(_("Socket write error: fd=%d, ptr=%p, nbytes=%d.\n"),
1028 fd, ptr, nbytes);
1029 }
1030 return (nwritten);
1031 }
1032
1033 #define SOCKBUFF 2048
1034
1035 LOCAL int process_cddb_titles __PR((int sock_fd, char *inbuff,
1036 int readbytes));
1037 LOCAL int
process_cddb_titles(sock_fd,inbuff,readbytes)1038 process_cddb_titles(sock_fd, inbuff, readbytes)
1039 int sock_fd;
1040 char *inbuff;
1041 int readbytes;
1042 {
1043 int finished = 0;
1044 char *p = inbuff;
1045 int ind = 0;
1046 char **target = (char **)&global.performer;
1047
1048 do {
1049 while (readbytes > 0) {
1050 /*
1051 * do we have a complete line in the buffer?
1052 */
1053 p = (char *)memchr(inbuff+ind, '\n', readbytes);
1054 if (p == NULL)
1055 break;
1056
1057 /*
1058 * look for the terminator first
1059 */
1060 if (strncmp(".\r\n", inbuff+ind, 3) == 0) {
1061 finished = 1;
1062 break;
1063 }
1064 /*
1065 * kill carriage return
1066 */
1067 if (p > inbuff+ind && *(p-1) == '\r') {
1068 *(p-1) = '\0';
1069 }
1070 /*
1071 * kill line feed
1072 */
1073 *p = '\0';
1074
1075 /*
1076 * handle escaped characters
1077 */
1078 {
1079 char *q = inbuff+ind;
1080
1081 while (*q) {
1082 if (*q++ == '\\' && *q != '\0') {
1083 if (*q == '\\') {
1084 readbytes--;
1085 p--;
1086 memmove(q, q+1, readbytes - (q-inbuff-ind));
1087 } else if (*q == 'n') {
1088 *(q-1) = '\n';
1089 readbytes--;
1090 p--;
1091 memmove(q, q+1, readbytes - (q-inbuff-ind));
1092 } else if (*q == 't') {
1093 *(q-1) = '\t';
1094 readbytes--;
1095 p--;
1096 memmove(q, q+1, readbytes - (q-inbuff-ind));
1097 }
1098 }
1099 }
1100 }
1101
1102 /*
1103 * handle multi line entries concatenate fields
1104 *
1105 * TODO if the delimiter is split into two lines,
1106 * it is not recognized.
1107 */
1108 if (strncmp(inbuff+ind, "DTITLE=", 7) == 0) {
1109 char *res = strstr(inbuff+ind+7, " / ");
1110 int clen;
1111 char *q;
1112
1113 if (res == NULL) {
1114 /*
1115 * no limiter found yet
1116 * copy until the end
1117 */
1118 q = p;
1119 } else {
1120 /*
1121 * limiter found
1122 * copy until the limiter
1123 */
1124 q = res;
1125 *q = '\0';
1126 }
1127
1128 clen = q - (inbuff+ind+7);
1129 if (*target == NULL) {
1130 *target = malloc(clen+1);
1131 if (*target != NULL)
1132 **target = '\0';
1133 } else {
1134 *target = realloc(*target,
1135 strlen(*target) + clen + 1);
1136 }
1137 if (*target != NULL) {
1138 strcat((char *)*target, inbuff+ind+7);
1139 }
1140
1141 /*
1142 * handle part after the delimiter, if present
1143 */
1144 if (res != NULL) {
1145 target = (char **)&global.disctitle;
1146 /*
1147 * skip the delimiter
1148 */
1149 q += 3;
1150 clen = p - q;
1151 if (*target == NULL) {
1152 *target = malloc(clen+1);
1153 if (*target != NULL)
1154 **target = '\0';
1155 }
1156 if (*target != NULL) {
1157 strcat((char *)*target, q);
1158 }
1159 }
1160 } else if (strncmp(inbuff+ind, "TTITLE", 6) == 0) {
1161 char *q = (char *)memchr(inbuff+ind, '=', readbytes);
1162 unsigned tno;
1163
1164 if (q != NULL) {
1165 *q = '\0';
1166 tno = (unsigned)atoi(inbuff+ind+6);
1167 tno++;
1168 if (tno < 100) {
1169 if (global.tracktitle[tno] == NULL) {
1170 global.tracktitle[tno] = malloc(p - q + 1);
1171 if (global.tracktitle[tno] != NULL)
1172 *(global.tracktitle[tno]) = '\0';
1173 } else {
1174 global.tracktitle[tno] =
1175 realloc(global.tracktitle[tno],
1176 strlen((char *)global.tracktitle[tno]) +
1177 p - q + 1);
1178 }
1179 if (global.tracktitle[tno] != NULL) {
1180 strcat((char *)global.tracktitle[tno], q+1);
1181 }
1182 }
1183 }
1184 } else if (strncmp(inbuff+ind, "DYEAR", 5) == 0) {
1185 char *q = (char *)memchr(inbuff+ind, '=', readbytes);
1186 if (q++ != NULL) {
1187 sscanf(q, "%d", &global.cddb_year);
1188 }
1189 } else if (strncmp(inbuff+ind, "DGENRE", 6) == 0) {
1190 char *q = (char *)memchr(inbuff+ind, '=', readbytes);
1191 if (q++ != NULL) {
1192 /*
1193 * patch from Joe Nuzman, thanks
1194 * might have significant whitespace
1195 */
1196 strncpy(global.cddb_genre, q, sizeof (global.cddb_genre)-1);
1197 /*
1198 * always have a terminator
1199 */
1200 global.cddb_genre[sizeof (global.cddb_genre)-1] = '\0';
1201 }
1202 } else if (strncmp(inbuff+ind, "# Revision: ", 12) == 0) {
1203 char *q = inbuff+ind+11;
1204 sscanf(q, "%d", &global.cddb_revision);
1205 global.cddb_revision++;
1206 }
1207 readbytes -= (p - inbuff -ind) + 1;
1208 ind = (p - inbuff) + 1;
1209 }
1210 if (!finished) {
1211 int newbytes;
1212 memmove(inbuff, inbuff+ind, readbytes);
1213 newbytes = readn(sock_fd, inbuff+readbytes, SOCKBUFF-readbytes);
1214 if (newbytes <= 0)
1215 break;
1216 readbytes += newbytes;
1217 ind = 0;
1218 }
1219 } while (!(finished || readbytes == 0));
1220 return (finished);
1221 }
1222
1223 LOCAL int handle_userchoice __PR((char *p, unsigned size));
1224
1225 LOCAL int
handle_userchoice(p,size)1226 handle_userchoice(p, size)
1227 char *p;
1228 unsigned size;
1229 {
1230 unsigned nr = 0;
1231 unsigned user_choice;
1232 int i;
1233 char *q;
1234 char *o;
1235
1236 /*
1237 * count lines.
1238 */
1239 q = p;
1240 while ((q = (char *)memchr(q, '\n', size - (q-p))) != NULL) {
1241 nr++;
1242 q++;
1243 }
1244 if (nr > 1)
1245 nr--;
1246
1247 /*
1248 * handle escaped characters
1249 */
1250 {
1251 char *r = p;
1252
1253 while (*r) {
1254 if (*r++ == '\\' && *r != '\0') {
1255 if (*r == '\\') {
1256 size--;
1257 memmove(r, r+1, size - (r-p));
1258 } else if (*r == 'n') {
1259 *(r-1) = '\n';
1260 size--;
1261 memmove(r, r+1, size - (r-p));
1262 } else if (*r == 't') {
1263 *(r-1) = '\t';
1264 size--;
1265 memmove(r, r+1, size - (r-p));
1266 }
1267 }
1268 }
1269 }
1270
1271 /*
1272 * list entries.
1273 */
1274 q = p;
1275 fprintf(outfp, _("%u entries found:\n"), nr);
1276 for (q = (char *)memchr(q, '\n', size - (q-p)), o = p, i = 0;
1277 i < nr; i++) {
1278 *q = '\0';
1279 fprintf(outfp, "%02u: %s\n", i, o);
1280 o = q+1;
1281 q = (char *)memchr(q, '\n', size - (q-p));
1282 }
1283 fprintf(outfp, _("%02u: ignore\n"), i);
1284
1285 /*
1286 * get user response.
1287 * Some OS seem to misshandle stderr and make it buffered, so we
1288 * call fflush(outfp) here.
1289 */
1290 do {
1291 fprintf(outfp, _("please choose one (0-%u): "), nr);
1292 fflush(outfp);
1293 if (scanf("%u", &user_choice) != 1)
1294 user_choice = nr;
1295 } while (user_choice > nr);
1296
1297 if (user_choice == nr)
1298 return (-1);
1299
1300 /*
1301 * skip to choice.
1302 */
1303 q = p;
1304 for (i = 0; i <= (int)user_choice - 1; i++) {
1305 q = (char *)memchr(q, '\0', size - (q-p)) + 1;
1306 }
1307 return (q-p);
1308 }
1309
1310 /*
1311 * request disc and track titles from a cddbp server.
1312 *
1313 * return values:
1314 * 0 titles have been found exactly (success)
1315 * -1 some communication error happened.
1316 * 1 titles have not been found.
1317 * 2 multiple fuzzy matches have been found.
1318 */
1319 EXPORT int
request_titles()1320 request_titles()
1321 {
1322 int retval = 0;
1323 int sock_fd;
1324 struct sockaddr_in sa;
1325 struct hostent *he;
1326 struct servent *se;
1327 struct passwd *pw = getpwuid(getuid());
1328 char hostname[MAXHOSTNAMELEN+1];
1329 char inbuff[SOCKBUFF];
1330 char outbuff[SOCKBUFF];
1331 int i;
1332 char category[64];
1333 unsigned cat_offset;
1334 unsigned disc_id;
1335 ssize_t readbytes;
1336
1337 sock_fd = socket(AF_INET, SOCK_STREAM, 0);
1338 if (sock_fd < 0) {
1339 errmsg(_("Cddb socket failed.\n"));
1340 retval = -1;
1341 goto errout;
1342 }
1343
1344 /*
1345 * TODO fallbacks
1346 * freedb.freedb.org
1347 * de.freedb.org
1348 * at.freedb.org
1349 */
1350 if (global.cddbp_server != NULL)
1351 he = gethostbyname(global.cddbp_server);
1352 else
1353 he = gethostbyname(CDDBHOST /*"freedb.freedb.org"*/);
1354
1355 /*
1356 * save result data IMMEDIATELY!!
1357 */
1358 memset(&sa, 0, sizeof (struct sockaddr_in));
1359
1360 if (he != NULL) {
1361 sa.sin_family = he->h_addrtype; /* AF_INET; */
1362 sa.sin_addr.s_addr = ((struct in_addr *)((he->h_addr_list)[0]))->s_addr;
1363 } else {
1364 errmsg(_("Cddb cannot resolve freedb host.\n"));
1365 sa.sin_family = AF_INET;
1366 sa.sin_addr.s_addr = htonl(UINT_C(0x526256aa)); /* freedb.freedb.de */
1367 }
1368
1369 se = NULL;
1370 if (global.cddbp_port != NULL) {
1371 sa.sin_port = htons(atoi(global.cddbp_port));
1372 } else {
1373 se = getservbyname("cddbp-alt", "tcp");
1374
1375 if (se == NULL) {
1376 if (global.cddbp_port == NULL) {
1377 se = getservbyname("cddbp", "tcp");
1378 }
1379 }
1380 if (se != NULL) {
1381 sa.sin_port = se->s_port;
1382 } else {
1383 #if 0
1384 errmsg("Cddb cannot resolve cddbp or cddbp-alt port.\n");
1385 #endif
1386 sa.sin_port = htons(CDDBPORT /*8880*/);
1387 }
1388 }
1389
1390 /* TODO timeout */
1391 if (0 > connect(sock_fd, (struct sockaddr *)&sa,
1392 sizeof (struct sockaddr_in))) {
1393 errmsg(_("Cddb connect failed.\n"));
1394 retval = -1;
1395 goto errout;
1396 }
1397
1398 /*
1399 * read banner
1400 */
1401 readbytes = readn(sock_fd, inbuff, sizeof (inbuff));
1402 if (readbytes < 0) {
1403 retval = -1;
1404 goto errout;
1405 }
1406 if (strncmp(inbuff, "200 ", 4) && strncmp(inbuff, "201 ", 4)) {
1407 errmsgno(EX_BAD,
1408 _("Bad status from freedb server during sign-on banner: %s.\n"), inbuff);
1409 retval = -1;
1410 goto errout;
1411 }
1412
1413 /*
1414 * say hello
1415 */
1416 hostname[0] = '\0';
1417 if (0 > gethostname(hostname, sizeof (hostname)))
1418 strcpy(hostname, "unknown_host");
1419 hostname[sizeof (hostname)-1] = '\0';
1420 writen(sock_fd, "cddb hello ", 11);
1421 if (pw != NULL) {
1422 BOOL space_err = FALSE;
1423 BOOL ascii_err = FALSE;
1424 /*
1425 * change spaces to underscores
1426 */
1427 char *q = pw->pw_name;
1428 while (*q != '\0') {
1429 if (*q == ' ') {
1430 if (!space_err) {
1431 space_err = TRUE;
1432 errmsgno(EX_BAD,
1433 _("Warning: Space in user name '%s'.\n"),
1434 pw->pw_name);
1435 }
1436 *q = '_';
1437 }
1438 if (*q < ' ' || *q > '~') {
1439 if (!ascii_err) {
1440 ascii_err = TRUE;
1441 errmsgno(EX_BAD,
1442 _("Warning: Nonascii character in user name '%s'.\n"),
1443 pw->pw_name);
1444 }
1445 *q = '_';
1446 }
1447 q++;
1448 }
1449 writen(sock_fd, pw->pw_name, strlen(pw->pw_name));
1450 } else {
1451 writen(sock_fd, "unknown", 7);
1452 }
1453 writen(sock_fd, " ", 1);
1454
1455 /* change spaces to underscores */
1456 {
1457 char *q = hostname;
1458 BOOL space_err = FALSE;
1459 BOOL ascii_err = FALSE;
1460
1461 while (*q != '\0') {
1462 if (*q == ' ') {
1463 if (!space_err) {
1464 space_err = TRUE;
1465 errmsgno(EX_BAD,
1466 _("Warning: Space in hostname '%s'.\n"),
1467 hostname);
1468 }
1469 *q = '_';
1470 }
1471 if (*q < ' ' || *q > '~') {
1472 if (!ascii_err) {
1473 ascii_err = TRUE;
1474 errmsgno(EX_BAD,
1475 _("Warning: Nonascii character in hostname '%s'.\n"),
1476 hostname);
1477 }
1478 *q = '_';
1479 }
1480 q++;
1481 }
1482 }
1483
1484 writen(sock_fd, hostname, strlen(hostname));
1485 writen(sock_fd, " cdda2wav ", 10);
1486 writen(sock_fd, VERSION, strlen(VERSION));
1487 writen(sock_fd, VERSION_OS, strlen(VERSION_OS));
1488 writen(sock_fd, "\n", 1);
1489
1490 readbytes = readn(sock_fd, inbuff, sizeof (inbuff));
1491 if (readbytes < 0) {
1492 retval = -1;
1493 goto signoff;
1494 }
1495 if (strncmp(inbuff, "200 ", 4)) {
1496 inbuff[readbytes] = '\0';
1497 errmsgno(EX_BAD,
1498 _("Bad status from freedb server during hello: %s.\n"), inbuff);
1499 retval = -1;
1500 goto signoff;
1501 }
1502
1503 /*
1504 * enable new protocol variant. Weird command here, no cddb prefix ?!?!
1505 */
1506 writen(sock_fd, "proto\n", 6);
1507 readbytes = readn(sock_fd, inbuff, sizeof (inbuff));
1508 if (readbytes < 0) {
1509 retval = -1;
1510 goto signoff;
1511 }
1512 /*
1513 * check for errors and maximum supported protocol level
1514 */
1515 if (strncmp(inbuff, "201 ", 4) > 0) {
1516 inbuff[readbytes] = '\0';
1517 errmsgno(EX_BAD,
1518 _("Bad status from freedb server during proto command: %s.\n"),
1519 inbuff);
1520 retval = -1;
1521 goto signoff;
1522 }
1523
1524 /*
1525 * check the supported protocol level
1526 */
1527 if (!memcmp(inbuff, "200 CDDB protocol level: current 1, supported ",
1528 46)) {
1529 char *q = strstr(inbuff, " supported ");
1530 unsigned pr_level;
1531
1532 if (q != NULL) {
1533 q += 11;
1534 sscanf(q, "%u\n", &pr_level);
1535 if (pr_level > 1) {
1536 if (pr_level > 5)
1537 pr_level = 5;
1538 sprintf(inbuff, "proto %1u\n", pr_level);
1539 writen(sock_fd, inbuff, 8);
1540 readbytes = readn(sock_fd, inbuff,
1541 sizeof (inbuff));
1542 if (readbytes < 0) {
1543 retval = -1;
1544 goto signoff;
1545 }
1546 /*
1547 * check for errors and maximum supported
1548 * protocol level
1549 */
1550 if (strncmp(inbuff, "201 ", 4) > 0) {
1551 inbuff[readbytes] = '\0';
1552 errmsgno(EX_BAD,
1553 _("Bad status from freedb server during proto x: %s.\n"),
1554 inbuff);
1555 retval = -1;
1556 goto signoff;
1557 }
1558 }
1559 }
1560 }
1561
1562 /*
1563 * format query string
1564 */
1565 /*
1566 * query
1567 */
1568 #define CDDPB_INCLUDING_DATATRACKS
1569 #ifdef CDDPB_INCLUDING_DATATRACKS
1570 sprintf(outbuff, "cddb query %08lx %ld ",
1571 (unsigned long)global.cddb_id, LastTrack() - FirstTrack() + 1);
1572 /*
1573 * first all leading datatracks
1574 */
1575 {
1576 int j = FirstAudioTrack();
1577 if (j < 0)
1578 j = LastTrack() +1;
1579 for (i = FirstTrack(); i < j; i++) {
1580 sprintf(outbuff + strlen(outbuff), "%ld ",
1581 150 + Get_StartSector(i));
1582 }
1583 }
1584 #else
1585 sprintf(outbuff, "cddb query %08lx %ld ",
1586 global.cddb_id,
1587 LastAudioTrack() - FirstAudioTrack() + 1);
1588 #endif
1589 /*
1590 * all audio tracks
1591 */
1592 for (i = FirstAudioTrack(); i != -1 && i <= LastAudioTrack(); i++) {
1593 sprintf(outbuff + strlen(outbuff), "%ld ",
1594 150 + Get_AudioStartSector(i));
1595 }
1596 #ifdef CDDPB_INCLUDING_DATATRACKS
1597 /*
1598 * now all trailing datatracks
1599 */
1600 for (; i != -1 && i <= LastTrack(); i++) {
1601 sprintf(outbuff + strlen(outbuff), "%ld ",
1602 150 + Get_StartSector(i));
1603 }
1604 sprintf(outbuff + strlen(outbuff), "%lu\n",
1605 (150 + Get_StartSector(CDROM_LEADOUT)) / 75);
1606 #else
1607 sprintf(outbuff + strlen(outbuff), "%lu\n",
1608 (150 + Get_LastSectorOnCd(FirstAudioTrack())) / 75);
1609 #endif
1610 /* strcpy(outbuff, */
1611 /* "cddb query 9709210c 12 150 12010 33557 50765 65380 81467 93235 109115 124135 137732 152575 166742 2339\n"); */
1612 /* strcpy(outbuff, "cddb query 03015501 1 296 344\n"); */
1613 /*
1614 * The next line is a CD with Tracktitle= 'Au fond d'un r�ve dor�'
1615 */
1616 /* sprintf(outbuff, "cddb query %s\n", "35069e05 5 150 12471 25528 35331 56166 1696");*/
1617
1618 writen(sock_fd, outbuff, strlen(outbuff));
1619
1620 readbytes = readn(sock_fd, inbuff, sizeof (inbuff));
1621 if (readbytes < 0) {
1622 retval = -1;
1623 goto signoff;
1624 }
1625 inbuff[readbytes] = '\0';
1626 cat_offset = 4;
1627 if (strncmp(inbuff, "210 ", 4) == 0 ||
1628 strncmp(inbuff, "211 ", 4) == 0) {
1629 /*
1630 * Check if there are really multiple entries.
1631 */
1632 char *p = (char *)memchr(inbuff, '\n', readbytes-1);
1633
1634 if (p != NULL)
1635 cat_offset = p+1 - inbuff;
1636 /*
1637 * first entry
1638 */
1639 if (p)
1640 p = (char *)memchr(p+1, '\n', inbuff+readbytes - p);
1641 /*
1642 * second entry
1643 */
1644 if (p)
1645 p = (char *)memchr(p+1, '\n', inbuff+readbytes - p);
1646 /*
1647 * .
1648 */
1649 if (p)
1650 p = (char *)memchr(p+1, '\n', inbuff+readbytes - p);
1651 if (p) {
1652 /* multiple entries */
1653 switch (global.cddbp) {
1654 case 2: /* take the first entry */
1655 break;
1656 case 1: /* ask user */
1657 if (!global.gui) {
1658 int userret = handle_userchoice(inbuff+cat_offset, readbytes - cat_offset);
1659 if (userret == -1) {
1660 /*
1661 * ignore any selection
1662 */
1663 retval = -1;
1664 goto signoff;
1665 }
1666 cat_offset += userret;
1667 }
1668 break;
1669 default:
1670 errmsgno(EX_BAD,
1671 _("Multiple entries found: %s.\n"), inbuff);
1672 retval = 2;
1673 goto signoff;
1674 }
1675 }
1676
1677 } else if (strncmp(inbuff, "200 ", 4)) {
1678 if (strncmp(inbuff, "202 ", 4) == 0) {
1679 errmsgno(EX_BAD, _("No cddb entry found: %s.\n"), inbuff);
1680 retval = 1;
1681 } else {
1682 errmsgno(EX_BAD,
1683 _("Bad status from freedb server during query: %s.\n%s"),
1684 inbuff, outbuff);
1685 retval = -1;
1686 }
1687 goto signoff;
1688 }
1689 sscanf(inbuff + cat_offset, "%s %x", category, &disc_id);
1690
1691
1692 /*
1693 * read
1694 */
1695 sprintf(inbuff, "cddb read %s %08x\n", category, disc_id);
1696 /*
1697 * The next line is a CD with Tracktitle= 'Au fond d'un r�ve dor�'
1698 */
1699 /* sprintf(inbuff, "cddb read %s %08x\n", category, 0x35069e05);*/
1700 writen(sock_fd, inbuff, strlen(inbuff));
1701
1702 /*
1703 * read status and first buffer size.
1704 */
1705 readbytes = readn(sock_fd, inbuff, sizeof (inbuff));
1706 if (readbytes < 0) {
1707 retval = -1;
1708 goto signoff;
1709 }
1710 if (strncmp(inbuff, "210 ", 4)) {
1711 inbuff[readbytes] = '\0';
1712 errmsgno(EX_BAD,
1713 _("Bad status from freedb server during read: %s.\n"),
1714 inbuff);
1715 retval = -1;
1716 goto signoff;
1717 }
1718
1719 if (1 != process_cddb_titles(sock_fd, inbuff, readbytes)) {
1720 errmsgno(EX_BAD, _("Cddb read finished not correctly!\n"));
1721 }
1722
1723 signoff:
1724 /*
1725 * sign-off
1726 */
1727 writen(sock_fd, "quit\n", 5);
1728 readbytes = readn(sock_fd, inbuff, sizeof (inbuff));
1729 if (readbytes < 0) {
1730 retval = -1;
1731 goto errout;
1732 }
1733 if (strncmp(inbuff, "230 ", 4)) {
1734 inbuff[readbytes] = '\0';
1735 errmsgno(EX_BAD,
1736 _("Bad status from freedb server during quit: %s.\n"),
1737 inbuff);
1738 goto errout;
1739 }
1740
1741 errout:
1742 close(sock_fd);
1743 return (retval);
1744 }
1745 #endif
1746 #endif
1747
1748 #if defined CDINDEX_SUPPORT
1749
1750 LOCAL int IsSingleArtist __PR((void));
1751
1752 /*
1753 * check, if there are more than one track performers
1754 */
1755 LOCAL int
IsSingleArtist()1756 IsSingleArtist()
1757 {
1758 struct iterator i;
1759
1760 InitIterator(&i, 1);
1761
1762 while (i.hasNextTrack(&i)) {
1763 struct TOC *p = i.getNextTrack(&i);
1764 int ii;
1765
1766 if (IS__DATA(p) || GETTRACK(p) == CDROM_LEADOUT)
1767 continue;
1768
1769 ii = GETTRACK(p);
1770 if (global.performer && global.trackperformer[ii] &&
1771 strcmp((char *) global.performer,
1772 (char *) global.trackperformer[ii]) != 0)
1773 return (0);
1774 }
1775 return (1);
1776 }
1777
1778 LOCAL const char *a2h[255-191] = {
1779 "À",
1780 "Á",
1781 "Â",
1782 "Ã",
1783 "Ä",
1784 "Å",
1785 "Æ",
1786 "Ç",
1787 "È",
1788 "É",
1789 "Ê",
1790 "Ë",
1791 "Ì",
1792 "Í",
1793 "Î",
1794 "Ï",
1795 "Ð",
1796 "Ñ",
1797 "Ò",
1798 "Ó",
1799 "Ô",
1800 "Õ",
1801 "Ö",
1802 "×",
1803 "Ø",
1804 "Ù",
1805 "Ú",
1806 "Û",
1807 "Ü",
1808 "Ý",
1809 "Þ",
1810 "ß",
1811 "à",
1812 "á",
1813 "â",
1814 "ã",
1815 "ä",
1816 "å",
1817 "æ",
1818 "ç",
1819 "è",
1820 "é",
1821 "ê",
1822 "ë",
1823 "ì",
1824 "í",
1825 "î",
1826 "ï",
1827 "ð",
1828 "ñ",
1829 "ò",
1830 "ó",
1831 "ô",
1832 "õ",
1833 "ö",
1834 "÷",
1835 "ø",
1836 "ù",
1837 "ú",
1838 "û",
1839 "ü",
1840 "ý",
1841 "þ",
1842 "ÿ",
1843 };
1844
1845 LOCAL char *ascii2html __PR((unsigned char *inp));
1846
1847 LOCAL char *
ascii2html(inp)1848 ascii2html(inp)
1849 unsigned char *inp;
1850 {
1851 static unsigned char outline[300];
1852 unsigned char *outp = outline;
1853
1854 #define copy_translation(a, b) else if (*inp == (a)) \
1855 { strcpy((char *)outp, (b)); \
1856 outp += sizeof ((b))-1; }
1857
1858 while (*inp != '\0') {
1859 if (0);
1860 copy_translation('"', """)
1861 copy_translation('&', "&")
1862 copy_translation('<', "<")
1863 copy_translation('>', ">")
1864 copy_translation(160, " ")
1865 else if (*inp < 192) {
1866 *outp++ = *inp;
1867 } else {
1868 strcpy((char *)outp, a2h[*inp-192]);
1869 outp += strlen(a2h[*inp-192]);
1870 }
1871 inp++;
1872 }
1873 *outp = '\0';
1874 return ((char *) outline);
1875 }
1876 #undef copy_translation
1877
1878 LOCAL void
emit_cdindex_form(fname_baseval)1879 emit_cdindex_form(fname_baseval)
1880 char *fname_baseval;
1881 {
1882 FILE *cdindex_form;
1883 char fname[200];
1884 char *pp;
1885
1886 if (fname_baseval == NULL || fname_baseval[0] == 0)
1887 return;
1888
1889 strncpy(fname, fname_baseval, sizeof (fname) -1);
1890 fname[sizeof (fname) -1] = 0;
1891 pp = strrchr(fname, '.');
1892 if (pp == NULL) {
1893 pp = fname + strlen(fname);
1894 }
1895 strncpy(pp, ".cdindex", sizeof (fname) - 1 - (pp - fname));
1896
1897 cdindex_form = fopen(fname, "w");
1898 if (cdindex_form == NULL)
1899 return;
1900
1901 #define CDINDEX_URL "http://www.musicbrainz.org/dtd/CDInfo.dtd"
1902
1903 /*
1904 * format XML page according to cdindex DTD (see www.musicbrainz.org)
1905 */
1906 fprintf(cdindex_form,
1907 "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<!DOCTYPE CDInfo SYSTEM \"%s\">\n\n<CDInfo>\n",
1908 CDINDEX_URL);
1909
1910 fprintf(cdindex_form, " <Title>%s</Title>\n",
1911 global.disctitle ? ascii2html(global.disctitle) : "");
1912 /*
1913 * In case of mixed mode and Extra-CD, nonaudio tracks are included!
1914 */
1915 fprintf(cdindex_form,
1916 " <NumTracks>%d</NumTracks>\n\n",
1917 cdtracks);
1918 fprintf(cdindex_form,
1919 " <IdInfo>\n <DiskId>\n <Id>%s</Id>\n </DiskId>\n",
1920 global.cdindex_id);
1921 fprintf(cdindex_form,
1922 " </IdInfo>\n\n");
1923
1924 if (IsSingleArtist()) {
1925 struct iterator i;
1926
1927 InitIterator(&i, 1);
1928
1929 fprintf(cdindex_form,
1930 " <SingleArtistCD>\n <Artist>%s</Artist>\n",
1931 global.performer ? ascii2html(global.performer) : "");
1932
1933 while (i.hasNextTrack(&i)) {
1934 struct TOC *p = i.getNextTrack(&i);
1935 unsigned int ii = GETTRACK(p);
1936
1937 if (ii == CDROM_LEADOUT)
1938 break;
1939 if (IS__AUDIO(p)) {
1940 fprintf(cdindex_form,
1941 " <Track Num=\"%u\">\n <Name>%s</Name>\n </Track>\n",
1942 ii, global.tracktitle[ii] ? ascii2html(global.tracktitle[ii]) : "");
1943 } else {
1944 fprintf(cdindex_form,
1945 " <Track Num=\"%u\">\n <Name>data track</Name>\n </Track>\n",
1946 ii);
1947 }
1948 }
1949 fprintf(cdindex_form, " </SingleArtistCD>\n");
1950 } else {
1951 struct iterator i;
1952
1953 InitIterator(&i, 1);
1954
1955 fprintf(cdindex_form, " <MultipleArtistCD>\n");
1956
1957 while (i.hasNextTrack(&i)) {
1958 struct TOC *p = i.getNextTrack(&i);
1959 unsigned int ii = GETTRACK(p);
1960
1961 if (ii == CDROM_LEADOUT)
1962 break;
1963 if (IS__AUDIO(p)) {
1964 fprintf(cdindex_form, " <Artist>%s</Artist>\n",
1965 global.trackperformer[ii] ? ascii2html(global.trackperformer[ii]) : "");
1966 fprintf(cdindex_form,
1967 " <Name>%s</Name>\n </Track>\n",
1968 global.tracktitle[ii] ?
1969 ascii2html(global.tracktitle[ii]) : "");
1970 } else {
1971 fprintf(cdindex_form,
1972 " <Artist>data track</Artist>\n <Name>data track</Name>\n </Track>\n");
1973 }
1974 }
1975 fprintf(cdindex_form, " </MultipleArtistCD>\n");
1976 }
1977 fprintf(cdindex_form, "</CDInfo>\n");
1978
1979 fclose(cdindex_form);
1980 }
1981 #endif
1982
1983 LOCAL void
dump_cdtext_info()1984 dump_cdtext_info()
1985 {
1986 #ifdef CD_TEXT
1987 /*
1988 * interpret the contents of CD Text information based on an early
1989 * draft of SCSI-3 mmc version 2 from jan 2, 1998
1990 * CD Text information consists of a text group containing up to
1991 * 8 language blocks containing up to
1992 * 255 Pack data chunks of
1993 * 18 bytes each.
1994 * So we have at most 36720 bytes to cope with.
1995 */
1996 short int datalength;
1997 int fulllength;
1998 BOOL text_ok = TRUE;
1999 unsigned char *p = (unsigned char *)global.buf;
2000 unsigned char lastline[255*12];
2001 int lastitem = -1;
2002 int itemcount = 0;
2003 int inlinecount = 0;
2004 int outlinecount = 0;
2005
2006 if (p == NULL) {
2007 comerrno(EX_BAD, "CD-text only works with SCSI transport.\n");
2008 }
2009 lastline[0] = '\0';
2010 datalength = ((p[0] << 8) + p[1]) + 2;
2011 datalength = min(datalength, global.bufsize);
2012 fulllength = datalength;
2013 p += 4;
2014 datalength -= 4;
2015 for (; datalength > 0;
2016 datalength -= sizeof (cdtextpackdata),
2017 p += sizeof (cdtextpackdata)) {
2018 unsigned char *zeroposition;
2019
2020 /*
2021 * handle one packet of CD Text Information Descriptor Pack Data
2022 * this is raw R-W subchannel data converted to 8 bit values.
2023 */
2024 cdtextpackdata *c = (cdtextpackdata *)p;
2025 int dbcc;
2026 int crc_error;
2027 unsigned tracknr;
2028
2029 #ifdef DEBUG_CDTEXT
2030 fprintf(outfp, "datalength =%d\n", datalength);
2031 #endif
2032 crc_error = !cdtext_crc_ok(c);
2033 if (crc_error)
2034 text_ok = FALSE;
2035
2036 if (lastitem != c->headerfield[0]) {
2037 itemcount = 0;
2038 lastitem = c->headerfield[0];
2039 }
2040
2041 tracknr = c->headerfield[1] & 0x7f;
2042 dbcc = ((unsigned)(c->headerfield[3] & 0x80)) >> 7; /* double byte character code */
2043
2044 #if defined DEBUG_CDTEXT
2045 {
2046 int extension_flag;
2047 int sequence_number;
2048 int block_number;
2049 int character_position;
2050
2051 extension_flag = ((unsigned)(c->headerfield[1] & 0x80)) >> 7;
2052 sequence_number = c->headerfield[2];
2053 block_number = ((unsigned)(c->headerfield[3] & 0x30)) >> 4; /* language */
2054 character_position = c->headerfield[3] & 0x0f;
2055
2056 fprintf(outfp, _("CDText: ext_fl=%d, trnr=%u, seq_nr=%d, dbcc=%d, block_nr=%d, char_pos=%d\n"),
2057 extension_flag, tracknr, sequence_number, dbcc, block_number, character_position);
2058 }
2059 #endif
2060
2061 /*
2062 * print ASCII information
2063 */
2064 memcpy(lastline+inlinecount, c->textdatafield, 12);
2065 inlinecount += 12;
2066 zeroposition = (unsigned char *)memchr(lastline+outlinecount, '\0', inlinecount-outlinecount);
2067 while (zeroposition != NULL) {
2068 process_header(c, tracknr, dbcc, lastline+outlinecount);
2069 outlinecount += zeroposition - (lastline+outlinecount) + 1;
2070
2071 #if defined DEBUG_CDTEXT
2072 fprintf(outfp,
2073 "\tin=%d, out=%d, items=%d, trcknum=%u\n",
2074 inlinecount, outlinecount, itemcount, tracknr);
2075 { int q;
2076
2077 for (q = outlinecount; q < inlinecount; q++)
2078 fprintf(outfp, "%c",
2079 lastline[q] ? lastline[q] : '�');
2080 fputs("\n", outfp);
2081 }
2082 #else
2083 if (DETAILED) {
2084 if (crc_error)
2085 fputs(_(" ! uncorr. CRC-Error"), outfp);
2086 fputs("\n", outfp);
2087 }
2088 #endif
2089
2090 itemcount++;
2091 if (itemcount > (int)cdtracks ||
2092 (c->headerfield[0] == 0x8f ||
2093 (c->headerfield[0] <= 0x8d &&
2094 c->headerfield[0] >= 0x86))) {
2095 outlinecount = inlinecount;
2096 break;
2097 }
2098 tracknr++;
2099 zeroposition = (unsigned char *)memchr(lastline+outlinecount, '\0', inlinecount-outlinecount);
2100 }
2101 }
2102 if (!global.no_textfile && text_ok && fulllength > 4) {
2103 char fname[200];
2104 char *pp;
2105 FILE *f;
2106
2107 strncpy(fname, global.fname_base, sizeof (fname) -1);
2108 fname[sizeof (fname) -1] = 0;
2109 pp = strrchr(fname, '.');
2110 if (pp == NULL)
2111 pp = fname + strlen(fname);
2112 strncpy(pp, ".cdtext", sizeof (fname) - 1 - (pp - fname));
2113
2114 f = fileopen(fname, "wctb");
2115 if (f) {
2116 filewrite(f, global.buf, fulllength);
2117 fclose(f);
2118 global.did_textfile = 1;
2119 }
2120 }
2121 #endif
2122 }
2123
2124 LOCAL void
dump_extra_info(from)2125 dump_extra_info(from)
2126 unsigned int from;
2127 {
2128 #ifdef CD_EXTRA
2129 unsigned char *p;
2130
2131 if (from == 0)
2132 return;
2133
2134 p = Extra_buffer + 48;
2135 while (*p != '\0') {
2136 unsigned pos;
2137 unsigned length;
2138
2139 pos = GET_BE_UINT_FROM_CHARP(p+2);
2140 length = GET_BE_UINT_FROM_CHARP(p+6);
2141 if (pos == (unsigned)-1) {
2142 pos = from+1;
2143 } else {
2144 pos += session_start;
2145 }
2146
2147 #ifdef DEBUG_XTRA
2148 if (global.gui == 0 && global.verbose != 0) {
2149 fprintf(outfp,
2150 "Language: %c%c (as defined by ISO 639)",
2151 *p, *(p+1));
2152 fprintf(outfp,
2153 " at sector %u, len=%u (sessionstart=%u)",
2154 pos, length, session_start);
2155 fputs("\n", outfp);
2156 }
2157 #endif
2158 /*
2159 * dump this entry
2160 */
2161 Read_Subinfo(pos, length);
2162 p += 10;
2163
2164 if (p + 9 > (Extra_buffer + CD_FRAMESIZE))
2165 break;
2166 }
2167 #endif
2168 }
2169
2170 LOCAL char *quote __PR((unsigned char *string));
2171
2172 LOCAL char *
quote(string)2173 quote(string)
2174 unsigned char *string;
2175 {
2176 static char result[200];
2177 unsigned char *p = (unsigned char *)result;
2178
2179 while (*string) {
2180 if (*string == '\'' || *string == '\\') {
2181 *p++ = '\\';
2182 }
2183 *p++ = *string++;
2184 }
2185 *p = '\0';
2186
2187 return (result);
2188 }
2189
2190
2191
2192 LOCAL void DisplayToc_with_gui __PR((unsigned long dw));
2193
2194 LOCAL void
DisplayToc_with_gui(dw)2195 DisplayToc_with_gui(dw)
2196 unsigned long dw;
2197 {
2198 unsigned mins;
2199 unsigned secnds;
2200 unsigned frames;
2201 int count_audio_trks;
2202 struct iterator i;
2203
2204 InitIterator(&i, 1);
2205
2206 mins = dw / (60*75);
2207 secnds = (dw % (60*75)) / 75;
2208 frames = (dw % 75);
2209
2210 /*
2211 * summary
2212 */
2213 count_audio_trks = 0;
2214
2215 if ((global.verbose & SHOW_STARTPOSITIONS) != 0) {
2216 if (global.illleadout_cd != 0 && have_CD_extra == 0) {
2217 fprintf(outfp,
2218 _("Tracks:%u > %u:%02u.%02u\n"),
2219 cdtracks, mins, secnds, frames);
2220 } else {
2221 fprintf(outfp,
2222 _("Tracks:%u %u:%02u.%02u\n"),
2223 cdtracks, mins, secnds, frames);
2224 }
2225 }
2226
2227 if (global.quiet == 0) {
2228 fprintf(outfp, _("CDINDEX discid: %s\n"), global.cdindex_id);
2229 fprintf(outfp, _("CDDB discid: 0x%08lx"),
2230 (unsigned long) global.cddb_id);
2231
2232 if (have_CDDB != 0) {
2233 fprintf(outfp, _(" CDDBP titles: resolved\n"));
2234 } else {
2235 fprintf(outfp, "\n");
2236 }
2237 if (have_CD_text != 0) {
2238 fprintf(outfp, _("CD-Text: detected\n"));
2239 dump_cdtext_info();
2240 } else {
2241 fprintf(outfp, _("CD-Text: not detected\n"));
2242 }
2243 if (have_CD_extra != 0) {
2244 fprintf(outfp, _("CD-Extra: detected\n"));
2245 dump_extra_info(have_CD_extra);
2246 } else {
2247 fprintf(outfp, _("CD-Extra: not detected\n"));
2248 }
2249
2250 fprintf(outfp,
2251 _("Album title: '%s'"), (void *)global.disctitle != NULL
2252 ? quote(global.disctitle) : "");
2253
2254 fprintf(outfp, _(" from '%s'\n"), (void *)global.performer != NULL
2255 ? quote(global.performer) : "");
2256 }
2257 count_audio_trks = 0;
2258
2259
2260 if ((global.verbose &
2261 (SHOW_TOC | SHOW_STARTPOSITIONS |
2262 SHOW_SUMMARY | SHOW_TITLES)) != 0 &&
2263 i.hasNextTrack(&i)) {
2264 TOC *o = i.getNextTrack(&i);
2265 while (i.hasNextTrack(&i)) {
2266 TOC *p = i.getNextTrack(&i);
2267 int from;
2268 from = GETTRACK(o);
2269
2270 fprintf(outfp, "T%02d:", from);
2271
2272 if (IS__DATA(o)) {
2273 /*
2274 * Special case of cd extra
2275 */
2276 unsigned int real_start = have_CD_extra
2277 ? have_CD_extra : GETSTART(o);
2278
2279
2280 dw = (unsigned long) (GETSTART(p) - real_start);
2281
2282 mins = dw / (60*75);
2283 secnds = (dw % (60*75)) / 75;
2284 frames = (dw % 75);
2285
2286 if (global.verbose & SHOW_STARTPOSITIONS)
2287 fprintf(outfp,
2288 " %7u",
2289 real_start);
2290
2291 if (global.verbose & SHOW_TOC)
2292 fprintf(outfp,
2293 " %2u:%02u.%02u",
2294 mins, secnds, frames);
2295
2296 if (global.verbose & SHOW_SUMMARY)
2297 fprintf(outfp,
2298 _(" data %s %s N/A"),
2299
2300 /* how recorded */
2301 IS__INCREMENTAL(o)
2302 ? _("incremental") :
2303 _("uninterrupted"),
2304
2305 /* copy-permission */
2306 IS__COPYRIGHTED(o)
2307 ? _("copydenied") :
2308 _("copyallowed"));
2309 fputs("\n", outfp);
2310 } else {
2311 dw = (unsigned long) (GETSTART(p) -
2312 GETSTART(o));
2313 mins = dw / (60*75);
2314 secnds = (dw % (60*75)) / 75;
2315 frames = (dw % 75);
2316
2317 if (global.verbose & SHOW_STARTPOSITIONS)
2318 fprintf(outfp,
2319 " %7u",
2320 GETSTART(o));
2321
2322 if (global.verbose & SHOW_TOC)
2323 fprintf(outfp,
2324 " %2u:%02u.%02u",
2325 mins, secnds, frames);
2326
2327 if (global.verbose & SHOW_SUMMARY)
2328 fprintf(outfp,
2329 _(" audio %s %s %s"),
2330
2331 /* how recorded */
2332 IS__PREEMPHASIZED(o)
2333 ? _("pre-emphasized") : _("linear"),
2334
2335 /* copy-permission */
2336 IS__COPYRIGHTED(o)
2337 ? _("copydenied") : _("copyallowed"),
2338
2339 /* channels */
2340 IS__QUADRO(o)
2341 ? _("quadro") : _("stereo"));
2342
2343 /* Title */
2344 if (global.verbose & SHOW_TITLES) {
2345 fprintf(outfp,
2346 _(" title '%s' from "),
2347
2348 (void *) global.tracktitle[GETTRACK(o)] != NULL
2349 ? quote(global.tracktitle[GETTRACK(o)]) : "");
2350
2351 fprintf(outfp,
2352 "'%s'",
2353
2354 (void *) global.trackperformer[GETTRACK(o)] != NULL
2355 ? quote(global.trackperformer[GETTRACK(o)]) : "");
2356 }
2357 fputs("\n", outfp);
2358 count_audio_trks++;
2359 }
2360 o = p;
2361 } /* while */
2362 if (global.verbose & SHOW_STARTPOSITIONS)
2363 if (GETTRACK(o) == CDROM_LEADOUT) {
2364 fprintf(outfp, _("Leadout: %7u\n"), GETSTART(o));
2365 }
2366 } /* if */
2367 }
2368
2369 LOCAL void DisplayToc_no_gui __PR((unsigned long dw));
2370
2371 LOCAL void
DisplayToc_no_gui(dw)2372 DisplayToc_no_gui(dw)
2373 unsigned long dw;
2374 {
2375 unsigned mins;
2376 unsigned secnds;
2377 unsigned frames;
2378 int count_audio_trks;
2379 unsigned ii = 0;
2380 struct iterator i;
2381 InitIterator(&i, 1);
2382
2383 mins = dw / (60*75);
2384 secnds = (dw % (60*75)) / 75;
2385 frames = (dw % 75);
2386
2387 /* summary */
2388 count_audio_trks = 0;
2389
2390 if (i.hasNextTrack(&i)) {
2391 TOC *o = i.getNextTrack(&i);
2392 while (i.hasNextTrack(&i)) {
2393 TOC *p = i.getNextTrack(&i);
2394 int from;
2395 from = GETTRACK(o);
2396
2397
2398 while (p != NULL && GETTRACK(p) != CDROM_LEADOUT &&
2399 GETFLAGS(o) == GETFLAGS(p)) {
2400 o = p;
2401 p = i.getNextTrack(&i);
2402 }
2403 if ((global.verbose & SHOW_SUMMARY) == 0)
2404 continue;
2405
2406 if (IS__DATA(o)) {
2407 fputs(_(" DATAtrack recorded copy-permitted tracktype\n"), outfp);
2408 fprintf(outfp,
2409 _(" %2d-%2d %13.13s %14.14s data\n"),
2410 from,
2411 GETTRACK(o),
2412 /* how recorded */
2413 IS__INCREMENTAL(o)
2414 ? _("incremental") : _("uninterrupted"),
2415
2416 /* copy-perm */
2417 IS__COPYRIGHTED(o) ? _("no") : _("yes"));
2418 } else {
2419 fputs(_("AUDIOtrack pre-emphasis copy-permitted tracktype channels\n"), outfp);
2420 fprintf(outfp,
2421 _(" %2d-%2d %12.12s %14.14s audio %1c\n"),
2422 from,
2423 GETTRACK(o),
2424 IS__PREEMPHASIZED(o)
2425 ? _("yes") : _("no"),
2426 IS__COPYRIGHTED(o) ? _("no") : _("yes"),
2427 IS__QUADRO(o) ? '4' : '2');
2428 count_audio_trks++;
2429 }
2430 o = p;
2431 }
2432 }
2433 if ((global.verbose & SHOW_STARTPOSITIONS) != 0) {
2434 if (global.illleadout_cd != 0 && have_multisession == 0) {
2435
2436 fprintf(outfp,
2437 _("Table of Contents: total tracks:%u, (total time more than %u:%02u.%02u)\n"),
2438 cdtracks, mins, secnds, frames);
2439 } else {
2440 fprintf(outfp,
2441 _("Table of Contents: total tracks:%u, (total time %u:%02u.%02u)\n"),
2442 cdtracks, mins, secnds, frames);
2443 }
2444 }
2445
2446 InitIterator(&i, 1);
2447 if ((global.verbose & SHOW_TOC) != 0 &&
2448 i.hasNextTrack(&i)) {
2449 TOC *o = i.getNextTrack(&i);
2450
2451 for (; i.hasNextTrack(&i); ) {
2452 TOC *p = i.getNextTrack(&i);
2453
2454 if (GETTRACK(o) <= MAXTRK) {
2455 unsigned char brace1, brace2;
2456 unsigned trackbeg;
2457 trackbeg = have_multisession && IS__DATA(o) ?
2458 have_multisession : GETSTART(o);
2459
2460 dw = (unsigned long) (GETSTART(p) - trackbeg);
2461 mins = dw / (60*75);
2462 secnds = (dw % (60*75)) / 75;
2463 frames = (dw % 75);
2464
2465 if (IS__DATA(o)) {
2466 /*
2467 * data track display
2468 */
2469 brace1 = '[';
2470 brace2 = ']';
2471 } else if (have_multisession &&
2472 GETTRACK(o) == LastAudioTrack()) {
2473 /*
2474 * corrected length of
2475 * last audio track in cd extra
2476 */
2477 brace1 = '|';
2478 brace2 = '|';
2479 } else {
2480 /*
2481 * audio track display
2482 */
2483 brace1 = '(';
2484 brace2 = ')';
2485 }
2486 fprintf(outfp,
2487 " %2u.%c%2u:%02u.%02u%c",
2488 GETTRACK(o),
2489 brace1,
2490 mins, secnds, frames,
2491 brace2);
2492 ii++;
2493
2494 if (ii % 5 == 0)
2495 fputs(",\n", outfp);
2496 else if (ii != cdtracks)
2497 fputc(',', outfp);
2498 }
2499 o = p;
2500 } /* for */
2501 if ((ii % 5) != 0)
2502 fputs("\n", outfp);
2503 } /* if */
2504
2505 if ((global.verbose & SHOW_STARTPOSITIONS) != 0) {
2506 fputs(_("\nTable of Contents: starting sectors\n"), outfp);
2507
2508 ii = 0;
2509 InitIterator(&i, 1);
2510 if (i.hasNextTrack(&i)) {
2511 TOC *o = i.getNextTrack(&i);
2512 for (; i.hasNextTrack(&i); ) {
2513 TOC *p = i.getNextTrack(&i);
2514 fprintf(outfp,
2515 " %2u.(%8u)",
2516 GETTRACK(o),
2517 have_multisession &&
2518 GETTRACK(o) == FirstDataTrack()
2519 ? have_multisession
2520 : GETSTART(o)
2521 #ifdef DEBUG_CDDB
2522 +150)
2523 #else
2524 +0);
2525 #endif
2526
2527 ii++;
2528 if ((ii) % 5 == 0)
2529 fputs(",\n", outfp);
2530 else
2531 fputc(',', outfp);
2532 o = p;
2533 }
2534 fprintf(outfp, _(" lead-out(%8u)"), GETSTART(o));
2535 fputs("\n", outfp);
2536 }
2537 }
2538 if (global.quiet == 0) {
2539 fprintf(outfp, _("CDINDEX discid: %s\n"), global.cdindex_id);
2540 fprintf(outfp, _("CDDB discid: 0x%08lx"),
2541 (unsigned long) global.cddb_id);
2542
2543 if (have_CDDB != 0) {
2544 fprintf(outfp, _(" CDDBP titles: resolved\n"));
2545 } else {
2546 fprintf(outfp, "\n");
2547 }
2548 if (have_CD_text != 0) {
2549 fprintf(outfp, _("CD-Text: detected\n"));
2550 } else {
2551 fprintf(outfp, _("CD-Text: not detected\n"));
2552 }
2553 if (have_CD_extra != 0) {
2554 fprintf(outfp, _("CD-Extra: detected\n"));
2555 } else {
2556 fprintf(outfp, _("CD-Extra: not detected\n"));
2557 }
2558 }
2559 if ((global.verbose & SHOW_TITLES) != 0) {
2560 unsigned int maxlen = 0;
2561
2562 if (global.disctitle != NULL) {
2563 fprintf(outfp, _("Album title: '%s'"), global.disctitle);
2564 if (global.performer != NULL) {
2565 fprintf(outfp, _("\t[from %s]"), global.performer);
2566 }
2567 fputs("\n", outfp);
2568 }
2569
2570 InitIterator(&i, 1);
2571 for (; i.hasNextTrack(&i); ) {
2572 TOC *p = i.getNextTrack(&i);
2573 unsigned int jj = GETTRACK(p);
2574
2575 if (global.tracktitle[jj] != NULL) {
2576 unsigned int len;
2577
2578 len = strlen((char *)global.tracktitle[jj]);
2579 maxlen = max(maxlen, len);
2580 }
2581 }
2582 maxlen = (maxlen + 12 + 8 + 7)/8;
2583
2584 InitIterator(&i, 1);
2585 for (; i.hasNextTrack(&i); ) {
2586 TOC *p = i.getNextTrack(&i);
2587 unsigned int jj;
2588
2589 if (IS__DATA(p))
2590 continue;
2591
2592 jj = GETTRACK(p);
2593
2594 if (jj == CDROM_LEADOUT)
2595 break;
2596
2597 if (maxlen != 3) {
2598 if (global.tracktitle[jj] != NULL) {
2599 fprintf(outfp, _("Track %2u: '%s'"),
2600 jj, global.tracktitle[jj]);
2601 } else {
2602 fprintf(outfp, _("Track %2u: '%s'"),
2603 jj, "");
2604 }
2605 if (global.trackperformer[jj] != NULL &&
2606 #if 1
2607 global.trackperformer[jj][0] != '\0' &&
2608 (global.performer == NULL ||
2609 0 != strcmp((char *)global.performer, (char *)global.trackperformer[jj]))) {
2610 #else
2611 global.trackperformer[jj][0] != '\0') {
2612
2613 #endif
2614 int j;
2615 char *o = global.tracktitle[jj] != NULL
2616 ? (char *)global.tracktitle[jj]
2617 : "";
2618
2619 for (j = 0;
2620 j < (maxlen - ((int)strlen(o) + 12)/8);
2621 j++) {
2622 fprintf(outfp, "\t");
2623 }
2624 fprintf(outfp,
2625 _("[from %s]"),
2626 global.trackperformer[jj]);
2627 }
2628 fputs("\n", outfp);
2629 }
2630 }
2631 }
2632 }
2633
2634 void
DisplayToc()2635 DisplayToc()
2636 {
2637 unsigned long dw;
2638
2639 /*
2640 * special handling of pseudo-red-book-audio cds
2641 */
2642 if (cdtracks > 1 &&
2643 Get_StartSector(CDROM_LEADOUT) < Get_StartSector(cdtracks)) {
2644 global.illleadout_cd = 1;
2645 can_read_illleadout();
2646 }
2647
2648
2649 /*
2650 * get total time
2651 */
2652 if (global.illleadout_cd == 0)
2653 dw = (unsigned long) Get_StartSector(CDROM_LEADOUT) - Get_StartSector(1);
2654 else
2655 dw = (unsigned long) Get_StartSector(cdtracks) - Get_StartSector(1);
2656
2657 if (global.gui == 0) {
2658 /*
2659 * table formatting when in cmdline mode
2660 */
2661 DisplayToc_no_gui(dw);
2662 } else if (global.gui == 1) {
2663 /*
2664 * line formatting when in gui mode
2665 */
2666 DisplayToc_with_gui(dw);
2667 }
2668
2669 if (global.illleadout_cd != 0) {
2670 if (global.quiet == 0) {
2671 errmsgno(EX_BAD, _("CD with illegal leadout position detected!\n"));
2672 }
2673
2674 if (global.reads_illleadout == 0) {
2675 /*
2676 * limit accessible tracks
2677 * to lowered leadout position
2678 */
2679 restrict_tracks_illleadout();
2680
2681 if (global.quiet == 0) {
2682 errmsgno(EX_BAD,
2683 _("The cdrom drive firmware does not permit access beyond the leadout position!\n"));
2684 }
2685 if (global.verbose & (SHOW_ISRC | SHOW_INDICES)) {
2686 global.verbose &= ~(SHOW_ISRC | SHOW_INDICES);
2687 fprintf(outfp, _("Switching index scan and ISRC scan off!\n"));
2688 }
2689
2690 if (global.quiet == 0) {
2691 fprintf(outfp,
2692 _("Audio extraction will be limited to track %ld with maximal %ld sectors...\n"),
2693 LastTrack(),
2694 Get_EndSector(LastTrack())+1);
2695 }
2696 } else {
2697 /*
2698 * The cdrom drive can read beyond the
2699 * indicated leadout. We patch a new leadout
2700 * position to the maximum:
2701 * 99 minutes, 59 seconds, 74 frames
2702 */
2703 patch_real_end(150 + (99*60+59)*75 + 74);
2704 if (global.quiet == 0) {
2705 fprintf(outfp,
2706 _("Restrictions apply, since the size of the last track is unknown!\n"));
2707 }
2708 }
2709 }
2710 }
2711
2712 LOCAL void Read_MCN_toshiba __PR((subq_chnl **sub_ch));
2713
2714 LOCAL void
Read_MCN_toshiba(sub_ch)2715 Read_MCN_toshiba(sub_ch)
2716 subq_chnl **sub_ch;
2717 {
2718 if (Toshiba3401() != 0 && global.quiet == 0 &&
2719 ((*sub_ch) != 0 &&
2720 (((subq_catalog *)(*sub_ch)->data)->mc_valid & 0x80))) {
2721 /*
2722 * no valid MCN yet. do more searching
2723 */
2724 long h = Get_AudioStartSector(1);
2725
2726 while (h <= Get_AudioStartSector(1) + 100) {
2727 if (Toshiba3401())
2728 ReadCdRom(get_scsi_p(), RB_BASE->data, h, global.nsectors);
2729 (*sub_ch) = ReadSubQ(get_scsi_p(), GET_CATALOGNUMBER, 0);
2730 if ((*sub_ch) != NULL) {
2731 subq_catalog *subq_cat;
2732
2733 subq_cat = (subq_catalog *) (*sub_ch)->data;
2734 if ((subq_cat->mc_valid & 0x80) != 0) {
2735 break;
2736 }
2737 }
2738 h += global.nsectors;
2739 }
2740 }
2741 }
2742
2743 LOCAL void Get_Set_MCN __PR((void));
2744
2745 LOCAL void
Get_Set_MCN()2746 Get_Set_MCN()
2747 {
2748 subq_chnl *sub_ch;
2749 subq_catalog *subq_cat = NULL;
2750
2751 fprintf(outfp, _("scanning for MCN..."));
2752 fflush(outfp);
2753
2754 sub_ch = ReadSubQ(get_scsi_p(), GET_CATALOGNUMBER, 0);
2755
2756 #define EXPLICIT_READ_MCN_ISRC 1
2757 #if EXPLICIT_READ_MCN_ISRC == 1 /* TOSHIBA HACK */
2758 Read_MCN_toshiba(&sub_ch);
2759 #endif
2760
2761 if (sub_ch != NULL)
2762 subq_cat = (subq_catalog *)sub_ch->data;
2763
2764 if (sub_ch != NULL &&
2765 (subq_cat->mc_valid & 0x80) != 0 &&
2766 global.quiet == 0) {
2767
2768 /*
2769 * unified format guesser:
2770 * format MCN all digits in bcd
2771 * 01 13
2772 * A: ab cd ef gh ij kl m0 0 0 0 0 0 0 Plextor 6x Rel. 1.02
2773 * B: 0a 0b 0c 0d 0e 0f 0g 0h 0i 0j 0k 0l 0m Toshiba 3401
2774 * C: AS AS AS AS AS AS AS AS AS AS AS AS AS ASCII SCSI-2 Plextor 4.5x and 6x Rel. 1.06
2775 */
2776 unsigned char *cp = subq_cat->media_catalog_number;
2777 if (!(cp[8] | cp[9] | cp[10] | cp[11] | cp[12]) &&
2778 ((cp[0] & 0xf0) | (cp[1] & 0xf0)
2779 | (cp[2] & 0xf0) | (cp[3] & 0xf0)
2780 | (cp[4] & 0xf0) | (cp[5] & 0xf0)
2781 | (cp[6] & 0xf0))) {
2782 /* reformat A: to B: */
2783 cp[12] = cp[6] >> 4; cp[11] = cp[5] & 0xf;
2784 cp[10] = cp[5] >> 4; cp[ 9] = cp[4] & 0xf;
2785 cp[ 8] = cp[4] >> 4; cp[ 7] = cp[3] & 0xf;
2786 cp[ 6] = cp[3] >> 4; cp[ 5] = cp[2] & 0xf;
2787 cp[ 4] = cp[2] >> 4; cp[ 3] = cp[1] & 0xf;
2788 cp[ 2] = cp[1] >> 4; cp[ 1] = cp[0] & 0xf;
2789 cp[ 0] = cp[0] >> 4;
2790 }
2791
2792 if (!isdigit(cp[0]) &&
2793 (memcmp(subq_cat->media_catalog_number,
2794 "\0\0\0\0\0\0\0\0\0\0\0\0\0", 13) != 0)) {
2795 sprintf((char *)
2796 subq_cat->media_catalog_number,
2797 "%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X",
2798 subq_cat->media_catalog_number [0],
2799 subq_cat->media_catalog_number [1],
2800 subq_cat->media_catalog_number [2],
2801 subq_cat->media_catalog_number [3],
2802 subq_cat->media_catalog_number [4],
2803 subq_cat->media_catalog_number [5],
2804 subq_cat->media_catalog_number [6],
2805 subq_cat->media_catalog_number [7],
2806 subq_cat->media_catalog_number [8],
2807 subq_cat->media_catalog_number [9],
2808 subq_cat->media_catalog_number [10],
2809 subq_cat->media_catalog_number [11],
2810 subq_cat->media_catalog_number [12]);
2811 }
2812
2813 if (memcmp(subq_cat->media_catalog_number, "0000000000000", 13)
2814 != 0) {
2815 Set_MCN(subq_cat->media_catalog_number);
2816 }
2817 }
2818 }
2819
2820
2821 LOCAL void Read_ISRC_toshiba __PR((subq_chnl **sub_ch, unsigned tr));
2822
2823 LOCAL void
Read_ISRC_toshiba(sub_ch,tr)2824 Read_ISRC_toshiba(sub_ch, tr)
2825 subq_chnl **sub_ch;
2826 unsigned tr;
2827 {
2828 if (Toshiba3401() != 0) {
2829 int j;
2830 j = (Get_AudioStartSector(tr)/100 + 1) * 100;
2831 do {
2832 ReadCdRom(get_scsi_p(), RB_BASE->data, j,
2833 global.nsectors);
2834 *sub_ch = ReadSubQ(get_scsi_p(), GET_TRACK_ISRC,
2835 Get_Tracknumber(tr));
2836 if (*sub_ch != NULL) {
2837 subq_track_isrc * subq_tr;
2838
2839 subq_tr = (subq_track_isrc *) (*sub_ch)->data;
2840 if (subq_tr != NULL && (subq_tr->tc_valid & 0x80) != 0)
2841 break;
2842 }
2843 j += global.nsectors;
2844 } while (j < (Get_AudioStartSector(tr)/100 + 1) * 100 + 100);
2845 }
2846 }
2847
2848
2849 LOCAL void Get_Set_ISRC __PR((unsigned tr));
2850
2851 LOCAL void
Get_Set_ISRC(tr)2852 Get_Set_ISRC(tr)
2853 unsigned tr;
2854 {
2855 subq_chnl *sub_ch;
2856 subq_track_isrc *subq_tr;
2857
2858 fprintf(outfp, _("\rscanning for ISRCs: %u ..."), tr);
2859 fflush(outfp);
2860
2861 subq_tr = NULL;
2862 sub_ch = ReadSubQ(get_scsi_p(), GET_TRACK_ISRC, tr);
2863
2864 #if EXPLICIT_READ_MCN_ISRC == 1 /* TOSHIBA HACK */
2865 Read_ISRC_toshiba(&sub_ch, tr);
2866 #endif
2867
2868 if (sub_ch != NULL)
2869 subq_tr = (subq_track_isrc *)sub_ch->data;
2870
2871 if (sub_ch != NULL && (subq_tr->tc_valid & 0x80) &&
2872 global.quiet == 0) {
2873 unsigned char p_start[16];
2874 unsigned char *p = p_start;
2875 unsigned char *cp = subq_tr->track_isrc;
2876
2877 /*
2878 * unified format guesser:
2879 * there are 60 bits and 15 bytes available.
2880 * 5 * 6bit-items + two zero fill bits + 7 * 4bit-items
2881 *
2882 * A: ab cd ef gh ij kl mn o0 0 0 0 0 0 0 0 Plextor 6x Rel. 1.02
2883 * B: 0a 0b 0c 0d 0e 0f 0g 0h 0i 0j 0k 0l 0m 0n 0o Toshiba 3401
2884 * C: AS AS AS AS AS AS AS AS AS AS AS AS AS AS AS ASCII SCSI-2
2885 * eg 'G''B''-''A''0''7''-''6''8''-''0''0''2''7''0' makes most sense
2886 * D: 'G''B''A''0''7''6''8''0''0''2''7''0'0 0 0 Plextor 6x Rel. 1.06 and 4.5x R. 1.01 and 1.04
2887 */
2888
2889 /* Check for format A: */
2890 if (!(cp[8] | cp[9] | cp[10] | cp[11] | cp[12] | cp[13] | cp[14]) &&
2891 ((cp[0] & 0xf0) | (cp[1] & 0xf0) | (cp[2] & 0xf0) |
2892 (cp[3] & 0xf0) | (cp[4] & 0xf0) | (cp[5] & 0xf0) |
2893 (cp[6] & 0xf0) | (cp[7] & 0xf0))) {
2894 #if DEBUG_ISRC
2895 fprintf(outfp, "a!\t");
2896 #endif
2897 /* reformat A: to B: */
2898 cp[14] = cp[7] >> 4; cp[13] = cp[6] & 0xf;
2899 cp[12] = cp[6] >> 4; cp[11] = cp[5] & 0xf;
2900 cp[10] = cp[5] >> 4; cp[ 9] = cp[4] & 0xf;
2901 cp[ 8] = cp[4] >> 4; cp[ 7] = cp[3] & 0xf;
2902 cp[ 6] = cp[3] >> 4; cp[ 5] = cp[2] & 0xf;
2903 cp[ 4] = cp[2] >> 4; cp[ 3] = cp[1] & 0xf;
2904 cp[ 2] = cp[1] >> 4; cp[ 1] = cp[0] & 0xf;
2905 cp[ 0] = cp[0] >> 4;
2906 #if DEBUG_ISRC
2907 fprintf(outfp, "a->b: %15.15s\n", cp);
2908 #endif
2909 }
2910
2911 /*
2912 * Check for format B:
2913 * If not yet in ASCII format, do the conversion
2914 */
2915 if (cp[0] < '0' && cp[1] < '0') {
2916 /*
2917 * coding table for International Standard
2918 * Recording Code
2919 */
2920 /* BEGIN CSTYLED */
2921 static char bin2ISRC[] = {
2922 '0','1','2','3','4','5','6','7','8','9', /* 10 */
2923 ':',';','<','=','>','?','@', /* 17 */
2924 'A','B','C','D','E','F','G','H','I','J','K', /* 28 */
2925 'L','M','N','O','P','Q','R','S','T','U','V', /* 39 */
2926 'W','X','Y','Z', /* 43 */
2927 #if 1
2928 '[','\\',']','^','_','`', /* 49 */
2929 'a','b','c','d','e','f','g','h','i','j','k', /* 60 */
2930 'l','m','n','o' /* 64 */
2931 #endif
2932 };
2933 /* END CSTYLED */
2934
2935 /*
2936 * build 6-bit vector of coded values
2937 */
2938 unsigned ind;
2939 int bits;
2940
2941 #if DEBUG_ISRC
2942 fprintf(outfp, "b!\n");
2943 #endif
2944 ind = (cp[0] << 26) +
2945 (cp[1] << 22) +
2946 (cp[2] << 18) +
2947 (cp[3] << 14) +
2948 (cp[4] << 10) +
2949 (cp[5] << 6) +
2950 (cp[6] << 2) +
2951 (cp[7] >> 2);
2952
2953 if ((cp[7] & 3) == 3) {
2954 if (global.verbose) {
2955 fprintf(outfp,
2956 _("Recorder-ID encountered: "));
2957 for (bits = 0; bits < 30; bits += 6) {
2958 unsigned binval = (ind & (ULONG_C(0x3f) << (24-bits)))
2959 >> (24-bits);
2960 if ((binval < sizeof (bin2ISRC)) &&
2961 (binval <= 9 || binval >= 16)) {
2962 fprintf(outfp,
2963 "%X",
2964 bin2ISRC[binval]);
2965 }
2966 }
2967
2968 fprintf(outfp,
2969 "%.1X%.1X%.1X%.1X%.1X%.1X%.1X",
2970 subq_tr->track_isrc [8] & 0x0f,
2971 subq_tr->track_isrc [9] & 0x0f,
2972 subq_tr->track_isrc [10] & 0x0f,
2973 subq_tr->track_isrc [11] & 0x0f,
2974 subq_tr->track_isrc [12] & 0x0f,
2975 subq_tr->track_isrc [13] & 0x0f,
2976 subq_tr->track_isrc [14] & 0x0f);
2977 fprintf(outfp, "\n");
2978 }
2979 return;
2980 }
2981 if ((cp[7] & 3) != 0) {
2982 fprintf(outfp,
2983 _("unknown mode 3 entry C1=0x%02x, C2=0x%02x\n"),
2984 (cp[7] >> 1) & 1, cp[7] & 1);
2985 return;
2986 }
2987
2988 /*
2989 * decode ISRC due to IEC 908
2990 */
2991 for (bits = 0; bits < 30; bits += 6) {
2992 unsigned binval = (ind & ((unsigned long) 0x3fL << (24L-bits))) >> (24L-bits);
2993 if ((binval >= sizeof (bin2ISRC)) ||
2994 (binval > 9 && binval < 16)) {
2995 /*
2996 * Illegal ISRC, dump and skip
2997 */
2998 int y;
2999
3000 Get_ISRC(tr)[0] = '\0';
3001 fprintf(outfp,
3002 _("\nIllegal ISRC for track %u, skipped: "),
3003 tr);
3004 for (y = 0; y < 15; y++) {
3005 fprintf(outfp, "%02x ",
3006 cp[y]);
3007 }
3008 fputs("\n", outfp);
3009 return;
3010 }
3011 *p++ = bin2ISRC[binval];
3012
3013 /*
3014 * insert a dash after two country
3015 * characters for legibility
3016 */
3017 if (bits == 6)
3018 *p++ = '-';
3019 }
3020
3021 /*
3022 * format year and serial number
3023 */
3024 sprintf((char *)p, "-%.1X%.1X-%.1X%.1X%.1X%.1X%.1X",
3025 subq_tr->track_isrc [8] & 0x0f,
3026 subq_tr->track_isrc [9] & 0x0f,
3027 subq_tr->track_isrc [10] & 0x0f,
3028 subq_tr->track_isrc [11] & 0x0f,
3029 subq_tr->track_isrc [12] & 0x0f,
3030 subq_tr->track_isrc [13] & 0x0f,
3031 subq_tr->track_isrc [14] & 0x0f);
3032 #if DEBUG_ISRC
3033 fprintf(outfp, "b: %15.15s!\n", p_start);
3034 #endif
3035 } else {
3036 /*
3037 * It might be in ASCII, surprise
3038 */
3039 int ii;
3040 for (ii = 0; ii < 12; ii++) {
3041 if (cp[ii] < '0' || cp[ii] > 'Z') {
3042 break;
3043 }
3044 }
3045 if (ii != 12) {
3046 int y;
3047
3048 Get_ISRC(ii)[0] = '\0';
3049 fprintf(outfp, _("\nIllegal ISRC for track %d, skipped: "), ii+1);
3050 for (y = 0; y < 15; y++) {
3051 fprintf(outfp, "%02x ", cp[y]);
3052 }
3053 fputs("\n", outfp);
3054 return;
3055 }
3056
3057 #if DEBUG_ISRC
3058 fprintf(outfp, "ascii: %15.15s!\n", cp);
3059 #endif
3060 for (ii = 0; ii < 12; ii++) {
3061 #if 1
3062 if ((ii == 2 || ii == 5 || ii == 7) &&
3063 cp[ii] != ' ')
3064 *p++ = '-';
3065 #endif
3066 *p++ = cp[ii];
3067 }
3068 if (p - p_start >= 16)
3069 *(p_start + 15) = '\0';
3070 else
3071 *p = '\0';
3072 }
3073
3074 if (memcmp(p_start, "00-000-00-00000", 15) != 0) {
3075 Set_ISRC(tr, p_start);
3076 }
3077 }
3078 }
3079
3080 /*
3081 * get and display Media Catalog Number (one per disc)
3082 * and Track International Standard Recording Codes (for each track)
3083 */
3084 void
Read_MCN_ISRC(startTrack,endTrack)3085 Read_MCN_ISRC(startTrack, endTrack)
3086 unsigned startTrack;
3087 unsigned endTrack;
3088 {
3089 int old_hidden = have_hiddenAudioTrack;
3090
3091 have_hiddenAudioTrack = 0; /* Don'tcheck track #0 here */
3092
3093 if ((global.verbose & SHOW_MCN) != 0) {
3094
3095 if (Get_MCN()[0] == '\0') {
3096 Get_Set_MCN();
3097 }
3098
3099 if (Get_MCN()[0] != '\0') {
3100 fprintf(outfp,
3101 _("\rMedia catalog number: %13.13s\n"),
3102 Get_MCN());
3103 } else {
3104 fprintf(outfp,
3105 _("\rNo media catalog number present.\n"));
3106 }
3107 }
3108
3109
3110
3111 if ((global.verbose & SHOW_ISRC) != 0) {
3112 struct iterator i;
3113
3114 InitIterator(&i, 1);
3115
3116 while (i.hasNextTrack(&i)) {
3117 struct TOC *p = i.getNextTrack(&i);
3118 unsigned ii = GETTRACK(p);
3119
3120 if (ii == CDROM_LEADOUT)
3121 break;
3122
3123 if (ii < startTrack || ii > endTrack)
3124 continue;
3125
3126 if (!IS__AUDIO(p))
3127 continue;
3128
3129 if (GETISRC(p)[0] == '\0') {
3130 Get_Set_ISRC(ii);
3131 }
3132
3133 if (GETISRC(p)[0] != '\0') {
3134 fprintf(outfp,
3135 "\rT: %2u ISRC: %15.15s\n",
3136 ii, GETISRC(p));
3137 fflush(outfp);
3138 }
3139 } /* for all tracks */
3140
3141 fputs("\n", outfp);
3142 } /* if SHOW_ISRC */
3143
3144 have_hiddenAudioTrack = old_hidden; /* Restore old value */
3145 }
3146
3147 LOCAL int playing = 0;
3148
3149 LOCAL subq_chnl *ReadSubChannel __PR((unsigned sec));
3150
3151 LOCAL subq_chnl *
ReadSubChannel(sec)3152 ReadSubChannel(sec)
3153 unsigned sec;
3154 {
3155 subq_chnl *sub_ch;
3156
3157 /*
3158 * For modern drives implement a direct method. If the drive supports
3159 * reading of subchannel data, do direct reads.
3160 */
3161 if (ReadSubChannels != NULL) {
3162 get_scsi_p()->silent++;
3163 sub_ch = ReadSubChannels(get_scsi_p(), sec);
3164 get_scsi_p()->silent--;
3165 if (sub_ch == NULL /*&& (scg_sense_key(get_scsi_p()) == 5)*/) {
3166 /*
3167 * command is not implemented
3168 */
3169 ReadSubChannels = NULL;
3170 #if defined DEBUG_SUB
3171 fprintf(outfp,
3172 "\nCommand not implemented: switching ReadSubChannels off !\n");
3173 #endif
3174 goto fallback;
3175 }
3176
3177 /*
3178 * check the address mode field
3179 */
3180 if ((sub_ch->control_adr & 0x0f) == 0) {
3181 /*
3182 * no Q mode information present at all, weird
3183 */
3184 sub_ch->control_adr = 0xAA;
3185 }
3186
3187 if ((int)(sub_ch->control_adr & 0x0f) > 0x01) {
3188 /*
3189 * this sector just has no position information.
3190 * we try the one before and then the one after.
3191 */
3192 if (sec > 1) {
3193 sec -= 1;
3194 sub_ch = ReadSubChannels(get_scsi_p(), sec);
3195 if (sub_ch == NULL)
3196 return (NULL);
3197 sec += 1;
3198 }
3199 if ((sub_ch->control_adr & 0x0f) != 0x01) {
3200 sec += 2;
3201 sub_ch = ReadSubChannels(get_scsi_p(), sec);
3202 if (sub_ch == NULL)
3203 return (NULL);
3204 sec -= 2;
3205 }
3206 }
3207
3208 /*
3209 * check address mode field for position information
3210 */
3211 if ((sub_ch->control_adr & 0x0f) == 0x01) {
3212 return (sub_ch);
3213 }
3214 ReadSubChannels = NULL;
3215 fprintf(outfp,
3216 _("\nCould not get position information (%02x) for sectors %u, %u, %u: switching ReadSubChannels off !\n"),
3217 sub_ch->control_adr &0x0f, sec-1, sec, sec+2);
3218 }
3219
3220 /*
3221 * We rely on audio sectors here!!!
3222 * The only method that worked even with my antique Toshiba 3401,
3223 * is playing the sector and then request the subchannel afterwards.
3224 */
3225 fallback:
3226 /*
3227 * We need a conformed audio track here!
3228 *
3229 * Fallback to ancient method
3230 */
3231 if (-1 == Play_at(get_scsi_p(), sec, 1)) {
3232 return (NULL);
3233 }
3234 playing = 1;
3235 sub_ch = ReadSubQ(get_scsi_p(), GET_POSITIONDATA, 0);
3236 return (sub_ch);
3237 }
3238
3239 LOCAL int ReadSubControl __PR((unsigned sec));
3240 LOCAL int
ReadSubControl(sec)3241 ReadSubControl(sec)
3242 unsigned sec;
3243 {
3244 subq_chnl *sub_ch = ReadSubChannel(sec);
3245 if (sub_ch == NULL)
3246 return (-1);
3247
3248 return (sub_ch->control_adr & 0xf0);
3249 }
3250
3251 LOCAL int HaveSCMS __PR((unsigned StartSector));
3252 LOCAL int
HaveSCMS(StartSector)3253 HaveSCMS(StartSector)
3254 unsigned StartSector;
3255 {
3256 int i;
3257 int copy_bits_set = 0;
3258
3259 for (i = 0; i < 8; i++) {
3260 int cr;
3261
3262 cr = ReadSubControl(StartSector + i);
3263 if (cr == -1)
3264 continue;
3265 (cr & 0x20) ? copy_bits_set++ : 0;
3266 }
3267 return (copy_bits_set >= 1 && copy_bits_set < 8);
3268 }
3269
3270 void
Check_Toc()3271 Check_Toc()
3272 {
3273 /*
3274 * detect layout
3275 * detect tracks
3276 */
3277 }
3278
3279 LOCAL int
GetIndexOfSector(sec,track)3280 GetIndexOfSector(sec, track)
3281 unsigned sec;
3282 unsigned track;
3283 {
3284 subq_chnl *sub_ch = ReadSubChannel(sec);
3285
3286 if (sub_ch == NULL) {
3287 if ((long)sec == Get_EndSector(track)) {
3288 errmsgno(EX_BAD,
3289 _("Driver and/or firmware bug detected! Drive cannot play the very last sector (%u)!\n"),
3290 sec);
3291 }
3292 return (-1);
3293 }
3294
3295 /*
3296 * can we trust that these values are hex and NOT bcd?
3297 */
3298 if ((sub_ch->track >= 0x10) && (sub_ch->track - track > 5)) {
3299 /* change all values from bcd to hex */
3300 sub_ch->track = (sub_ch->track >> 4)*10 + (sub_ch->track & 0x0f);
3301 sub_ch->index = (sub_ch->index >> 4)*10 + (sub_ch->index & 0x0f);
3302 }
3303
3304 #if 1
3305 /*
3306 * compare tracks
3307 */
3308 if (sub_ch->index != 0 && track != sub_ch->track) {
3309 if (global.verbose)
3310 fprintf(outfp,
3311 _("\ntrack mismatch: %1u, in-track subchannel: %1u (index %1u, sector %1u)\n"),
3312 track, sub_ch->track, sub_ch->index, sec);
3313 }
3314 #endif
3315
3316 /*
3317 * compare control field with the one from the TOC
3318 */
3319 if ((Get_Flags(track) & 0xf0) != (sub_ch->control_adr & 0xf0)) {
3320 int diffbits = (Get_Flags(track) & 0xf0) ^ (sub_ch->control_adr & 0xf0);
3321
3322 if ((diffbits & 0x80) == 0x80) {
3323 /*
3324 * broadcast difference
3325 */
3326 if (global.verbose) {
3327 fprintf(outfp,
3328 _("broadcast type conflict detected -> TOC:%s, subchannel:%s\n"),
3329 (sub_ch->control_adr & 0x80) == 0 ? _("broadcast") : _("nonbroadcast"),
3330 (sub_ch->control_adr & 0x80) != 0 ? _("broadcast") : _("nonbroadcast"));
3331 }
3332 }
3333 if ((diffbits & 0x40) == 0x40) {
3334 /*
3335 * track type difference
3336 */
3337 if (global.verbose) {
3338 fprintf(outfp,
3339 _("track type conflict detected -> TOC:%s, subchannel:%s\n"),
3340 (sub_ch->control_adr & 0x40) == 0 ? _("data") : _("audio"),
3341 (sub_ch->control_adr & 0x40) != 0 ? _("data") : _("audio"));
3342 }
3343 }
3344 if ((diffbits & 0x20) == 0x20 && !Get_SCMS(track)) {
3345 /*
3346 * copy permission difference is a sign for SCMS
3347 * and is treated elsewhere.
3348 */
3349 if (global.verbose) {
3350 fprintf(outfp,
3351 _("difference: TOC:%s, subchannel:%s\ncorrecting TOC...\n"),
3352 (sub_ch->control_adr & 0x20) == 0 ? _("unprotected") : _("copyright protected"),
3353 (sub_ch->control_adr & 0x20) != 0 ? _("unprotected") : _("copyright protected"));
3354 }
3355
3356 toc_entry(track,
3357 (Get_Flags(track) & 0xDF) | (sub_ch->control_adr & 0x20),
3358 Get_Tracknumber(track),
3359 Get_ISRC(track),
3360 Get_AudioStartSector(track),
3361 Get_Mins(track),
3362 Get_Secs(track),
3363 Get_Frames(track));
3364 }
3365 if ((diffbits & 0x10) == 0x10) {
3366 /*
3367 * preemphasis difference
3368 */
3369 if (global.verbose)
3370 fprintf(outfp,
3371 _("difference: TOC:%s, subchannel:%s preemphasis\ncorrecting TOC...\n"),
3372 (sub_ch->control_adr & 0x10) == 0 ? _("with") : _("without"),
3373 (sub_ch->control_adr & 0x10) != 0 ? _("with") : _("without"));
3374
3375 toc_entry(track,
3376 (Get_Flags(track) & 0xEF) | (sub_ch->control_adr & 0x10),
3377 Get_Tracknumber(track),
3378 Get_ISRC(track),
3379 Get_AudioStartSector(track),
3380 Get_Mins(track),
3381 Get_Secs(track),
3382 Get_Frames(track));
3383 }
3384
3385 }
3386
3387 return (sub_ch ? sub_ch->index == 244 ? 1 : sub_ch->index : -1);
3388 }
3389
3390 LOCAL int ScanBackwardFrom __PR((unsigned sec, unsigned limit,
3391 int *where, unsigned track));
3392
3393 LOCAL int
ScanBackwardFrom(sec,limit,where,track)3394 ScanBackwardFrom(sec, limit, where, track)
3395 unsigned sec;
3396 unsigned limit;
3397 int *where;
3398 unsigned track;
3399 {
3400 unsigned lastindex = 0;
3401 unsigned mysec = sec;
3402
3403 /*
3404 * try to find the transition of index n to index 0,
3405 * if the track ends with an index 0.
3406 */
3407 while ((lastindex = GetIndexOfSector(mysec, track)) == 0) {
3408 if (mysec < limit+75) {
3409 break;
3410 }
3411 mysec -= 75;
3412 }
3413 if (mysec == sec) {
3414 /*
3415 * there is no pre-gap in this track
3416 */
3417 if (where != NULL)
3418 *where = -1;
3419 } else {
3420 /*
3421 * we have a pre-gap in this track
3422 */
3423 if (lastindex == 0) {
3424 /*
3425 * we did not cross the transition yet -> search
3426 * backward
3427 */
3428 do {
3429 if (mysec < limit+1) {
3430 break;
3431 }
3432 mysec --;
3433 } while ((lastindex = GetIndexOfSector(mysec, track)) == 0);
3434 if (lastindex != 0) {
3435 /*
3436 * successful
3437 */
3438 mysec ++;
3439 /*
3440 * register mysec as transition
3441 */
3442 if (where != NULL)
3443 *where = (int) mysec;
3444 } else {
3445 /*
3446 * could not find transition
3447 */
3448 if (!global.quiet)
3449 errmsgno(EX_BAD,
3450 _("Could not find index transition for pre-gap.\n"));
3451 if (where != NULL)
3452 *where = -1;
3453 }
3454 } else {
3455 int myindex = -1;
3456 /*
3457 * we have crossed the transition -> search forward
3458 */
3459 do {
3460 if (mysec >= sec) {
3461 break;
3462 }
3463 mysec ++;
3464 } while ((myindex = GetIndexOfSector(mysec, track)) != 0);
3465 if (myindex == 0) {
3466 /*
3467 * successful
3468 * register mysec as transition
3469 */
3470 if (where != NULL)
3471 *where = (int) mysec;
3472 } else {
3473 /*
3474 * could not find transition
3475 */
3476 if (!global.quiet)
3477 errmsgno(EX_BAD,
3478 _("Could not find index transition for pre-gap.\n"));
3479 if (where != NULL)
3480 *where = -1;
3481 }
3482 }
3483 }
3484 return (lastindex);
3485 }
3486
3487 #ifdef USE_LINEAR_SEARCH
3488 LOCAL int linear_search __PR((int searchInd, unsigned int Start,
3489 unsigned int End, unsigned track));
3490 LOCAL int
linear_search(searchInd,Start,End,track)3491 linear_search(searchInd, Start, End, track)
3492 int searchInd;
3493 unsigned Start;
3494 unsigned End;
3495 unsigned track;
3496 {
3497 int l = Start;
3498 int r = End;
3499
3500 for (; l <= r; l++) {
3501 int ind;
3502
3503 ind = GetIndexOfSector(l, track);
3504 if (searchInd == ind) {
3505 break;
3506 }
3507 }
3508 if (l <= r) {
3509 /*
3510 * Index found.
3511 */
3512 return (l);
3513 }
3514 return (-1);
3515 }
3516 #endif
3517
3518 #ifndef USE_LINEAR_SEARCH
3519 #undef DEBUG_BINSEARCH
3520 LOCAL int binary_search __PR((int searchInd, unsigned int Start,
3521 unsigned int End, unsigned track));
3522 LOCAL int
binary_search(searchInd,Start,End,track)3523 binary_search(searchInd, Start, End, track)
3524 int searchInd;
3525 unsigned Start;
3526 unsigned End;
3527 unsigned track;
3528 {
3529 int l = Start;
3530 int r = End;
3531 int x = 0;
3532 int ind;
3533
3534 while (l <= r) {
3535 x = (l + r) / 2;
3536 /*
3537 * try to avoid seeking
3538 */
3539 ind = GetIndexOfSector(x, track);
3540 if (searchInd == ind) {
3541 break;
3542 } else {
3543 if (searchInd < ind)
3544 r = x - 1;
3545 else
3546 l = x + 1;
3547 }
3548 }
3549 #ifdef DEBUG_BINSEARCH
3550 fprintf(outfp, "(%d,%d,%d > ", l, x, r);
3551 #endif
3552 if (l <= r) {
3553 /*
3554 * Index found. Now find the first position of this index
3555 *
3556 * l=LastPos x=found r=NextPos
3557 */
3558 r = x;
3559 while (l < r-1) {
3560 x = (l + r) / 2;
3561 /*
3562 * try to avoid seeking
3563 */
3564 ind = GetIndexOfSector(x, track);
3565 if (searchInd == ind) {
3566 r = x;
3567 } else {
3568 l = x;
3569 }
3570 #ifdef DEBUG_BINSEARCH
3571 fprintf(outfp, "%d -> ", x);
3572 #endif
3573 }
3574 #ifdef DEBUG_BINSEARCH
3575 fprintf(outfp, "%d,%d)\n", l, r);
3576 #endif
3577 if (searchInd == GetIndexOfSector(l, track))
3578 return (l);
3579 else
3580 return (r);
3581 }
3582 return (-1);
3583 }
3584 #endif
3585
3586
3587 LOCAL void register_index_position __PR((int IndexOffset,
3588 index_list **last_index_entry));
3589
3590 LOCAL void
register_index_position(IndexOffset,last_index_entry)3591 register_index_position(IndexOffset, last_index_entry)
3592 int IndexOffset;
3593 index_list **last_index_entry;
3594 {
3595 index_list *indexentry;
3596
3597 /*
3598 * register higher index entries
3599 */
3600 if (*last_index_entry != NULL) {
3601 indexentry = (index_list *) malloc(sizeof (index_list));
3602 } else {
3603 indexentry = NULL;
3604 }
3605 if (indexentry != NULL) {
3606 indexentry->next = NULL;
3607 (*last_index_entry)->next = indexentry;
3608 *last_index_entry = indexentry;
3609 indexentry->frameoffset = IndexOffset;
3610 #if defined INFOFILES
3611 } else {
3612 fprintf(outfp,
3613 _("No memory for index lists. Index positions\nwill not be written in info file!\n"));
3614 #endif
3615 }
3616 }
3617
3618 LOCAL void Set_SCMS __PR((unsigned long p_track));
3619
3620 #undef DEBUG_INDLIST
3621 /*
3622 * experimental code
3623 * search for indices (audio mode required)
3624 */
3625 unsigned
ScanIndices(track,cd_index,bulk)3626 ScanIndices(track, cd_index, bulk)
3627 unsigned track;
3628 unsigned cd_index;
3629 int bulk;
3630 {
3631 /*
3632 * scan for indices.
3633 * look at last sector of track.
3634 * when the index is not equal 1 scan by bipartition
3635 * for offsets of all indices
3636 */
3637 unsigned starttrack;
3638 unsigned endtrack;
3639 unsigned startindex;
3640 unsigned endindex;
3641
3642 unsigned j;
3643 int LastIndex = 0;
3644 int n_0_transition;
3645 unsigned StartSector;
3646 unsigned retval = 0;
3647
3648 index_list *baseindex_pool;
3649 index_list *last_index_entry;
3650
3651 SCSI *scgp = get_scsi_p();
3652
3653 int old_hidden = have_hiddenAudioTrack;
3654
3655 struct iterator i;
3656
3657 have_hiddenAudioTrack = 0; /* Don'tcheck track #0 here */
3658 InitIterator(&i, 1);
3659
3660 EnableCdda(scgp, 0, 0);
3661 EnableCdda(scgp, 1, CD_FRAMESIZE_RAW + 16);
3662
3663 if (!global.quiet && !(global.verbose & SHOW_INDICES))
3664 fprintf(outfp, _("seeking index start ..."));
3665
3666 starttrack = track;
3667 endtrack = global.endtrack;
3668
3669 baseindex_pool = (index_list *) malloc(sizeof (index_list) * (endtrack - starttrack + 1));
3670 #ifdef DEBUG_INDLIST
3671 fprintf(outfp, "index0-mem-pool %p\n", baseindex_pool);
3672 #endif
3673
3674
3675 while (i.hasNextTrack(&i)) {
3676 struct TOC *p = i.getNextTrack(&i);
3677 unsigned ii = GETTRACK(p);
3678
3679 if (ii < starttrack || IS__DATA(p))
3680 continue; /* skip nonaudio tracks */
3681
3682 if (ii > endtrack)
3683 break;
3684
3685 if (global.verbose & SHOW_INDICES) {
3686 if (global.illleadout_cd && global.reads_illleadout &&
3687 ii == endtrack) {
3688 fprintf(outfp,
3689 _("Analysis of track %u skipped due to unknown length\n"), ii);
3690 }
3691 }
3692 if (global.illleadout_cd && global.reads_illleadout &&
3693 ii == endtrack)
3694 continue;
3695
3696 StartSector = Get_AudioStartSector(ii);
3697 if (HaveSCMS(StartSector)) {
3698 Set_SCMS(ii);
3699 }
3700 if (global.verbose & SHOW_INDICES) {
3701 fprintf(outfp, _("\rindex scan: %u..."), ii);
3702 fflush(outfp);
3703 }
3704 LastIndex = ScanBackwardFrom(Get_EndSector(ii), StartSector,
3705 &n_0_transition, ii);
3706 if (LastIndex > 99)
3707 continue;
3708
3709 if (baseindex_pool != NULL) {
3710 #ifdef DEBUG_INDLIST
3711 #endif
3712 /*
3713 * register first index entry for this track
3714 */
3715 baseindex_pool[ii - starttrack].next = NULL;
3716 baseindex_pool[ii - starttrack].frameoffset = StartSector;
3717 global.trackindexlist[ii] = &baseindex_pool[ii -
3718 starttrack];
3719 #ifdef DEBUG_INDLIST
3720 #endif
3721 } else {
3722 global.trackindexlist[ii] = NULL;
3723 }
3724 last_index_entry = global.trackindexlist[ii];
3725
3726 if (LastIndex < 2) {
3727 register_index_position(n_0_transition,
3728 &last_index_entry);
3729 continue;
3730 }
3731
3732 if ((global.verbose & SHOW_INDICES) && LastIndex > 1) {
3733 fprintf(outfp,
3734 _("\rtrack %2u has %d indices, index table (pairs of 'index: frame offset')\n"),
3735 ii, LastIndex);
3736 }
3737 startindex = 0;
3738 endindex = LastIndex;
3739
3740 for (j = startindex; j <= endindex; j++) {
3741 int IndexOffset;
3742
3743 /*
3744 * this track has indices
3745 */
3746
3747 #ifdef USE_LINEAR_SEARCH
3748 /*
3749 * do a linear search
3750 */
3751 IndexOffset = linear_search(j, StartSector,
3752 Get_EndSector(ii), ii);
3753 #else
3754 /*
3755 * do a binary search
3756 */
3757 IndexOffset = binary_search(j, StartSector,
3758 Get_EndSector(ii), ii);
3759 #endif
3760
3761 if (IndexOffset != -1) {
3762 StartSector = IndexOffset;
3763 }
3764
3765 if (j == 1)
3766 last_index_entry->frameoffset = IndexOffset;
3767 else if (j > 1)
3768 register_index_position(IndexOffset,
3769 &last_index_entry);
3770
3771 if (IndexOffset == -1) {
3772 if (global.verbose & SHOW_INDICES) {
3773 if (global.gui == 0) {
3774 fprintf(outfp,
3775 "%2u: N/A ", j);
3776 if (((j + 1) % 8) == 0)
3777 fputs("\n", outfp);
3778 } else {
3779 fprintf(outfp,
3780 "\rT%02u I%02u N/A\n",
3781 ii, j);
3782 }
3783 }
3784 } else {
3785 if (global.verbose & SHOW_INDICES) {
3786 if (global.gui == 0) {
3787 fprintf(outfp,
3788 "%2u:%6lu ",
3789 j,
3790 IndexOffset-
3791 Get_AudioStartSector(ii));
3792 if (((j + 1) % 8) == 0)
3793 fputs("\n", outfp);
3794 } else {
3795 fprintf(outfp,
3796 "\rT%02u I%02u %06lu\n",
3797 ii,
3798 j,
3799 IndexOffset-
3800 Get_AudioStartSector(ii));
3801 }
3802 }
3803
3804 if (track == ii && cd_index == j) {
3805 retval = IndexOffset-
3806 Get_AudioStartSector(ii);
3807 }
3808 } /* if IndexOffset */
3809 } /* for index */
3810 register_index_position(n_0_transition, &last_index_entry);
3811
3812 /*
3813 * sanity check. clear all consecutive nonindex
3814 * entries (frameoffset -1) from the end.
3815 */
3816 {
3817 index_list *ip = global.trackindexlist[ii];
3818 index_list *iq = NULL;
3819 index_list *lastgood = iq;
3820
3821 while (ip != NULL) {
3822 if (ip->frameoffset == -1) {
3823 /*
3824 * no index available
3825 */
3826 if (lastgood == NULL) {
3827 /*
3828 * if this is the first one in a
3829 * sequence, store predecessor
3830 * unless it is the last entry and
3831 * there is no index 0 transition
3832 */
3833 if (!(ip->next == NULL &&
3834 ip->frameoffset == n_0_transition))
3835 lastgood = iq;
3836 }
3837 } else {
3838 /*
3839 * this is a valid index, reset marker
3840 */
3841 lastgood = NULL;
3842 }
3843
3844 iq = ip;
3845 ip = ip->next;
3846 }
3847 /*
3848 * terminate chain at the last well defined entry.
3849 */
3850 if (lastgood != NULL)
3851 lastgood->next = NULL;
3852 }
3853
3854 if (global.gui == 0 && (global.verbose & SHOW_INDICES) &&
3855 ii != endtrack)
3856 fputs("\n", outfp);
3857 } /* for tracks */
3858
3859 if (global.gui == 0 && (global.verbose & SHOW_INDICES))
3860 fputs("\n", outfp);
3861 if (playing != 0)
3862 StopPlay(get_scsi_p());
3863
3864 EnableCdda(scgp, 0, 0);
3865 EnableCdda(scgp, 1, CD_FRAMESIZE_RAW);
3866
3867 have_hiddenAudioTrack = old_hidden; /* Restore old value */
3868
3869 return (retval);
3870 }
3871
3872 LOCAL unsigned char MCN[14];
3873
3874 LOCAL void
Set_MCN(MCN_arg)3875 Set_MCN(MCN_arg)
3876 unsigned char *MCN_arg;
3877 {
3878 memcpy(MCN, MCN_arg, 14);
3879 MCN[13] = '\0';
3880 }
3881
3882 unsigned char *
Get_MCN()3883 Get_MCN()
3884 {
3885 return (MCN);
3886 }
3887
3888
3889 LOCAL TOC g_toc[MAXTRK+1]; /* hidden track + 100 regular tracks */
3890
3891 /*#define IS_AUDIO(i) (!(g_toc[i].bFlags & 0x40))*/
3892
3893 int
TOC_entries(tracks,a,b,binvalid)3894 TOC_entries(tracks, a, b, binvalid)
3895 unsigned tracks;
3896 unsigned char *a;
3897 unsigned char *b;
3898 int binvalid;
3899 {
3900 int i;
3901
3902 for (i = 1; i <= (int)tracks; i++) {
3903 unsigned char *p;
3904
3905 if (binvalid) {
3906 unsigned long dwStartSector;
3907
3908 p = a + 8*(i-1);
3909
3910 g_toc[i].bFlags = p[1];
3911 g_toc[i].bTrack = p[2];
3912 g_toc[i].ISRC[0] = 0;
3913 dwStartSector = a_to_u_4_byte(p+4);
3914 g_toc[i].dwStartSector = dwStartSector;
3915 lba_2_msf((long)dwStartSector,
3916 &g_toc[i].mins,
3917 &g_toc[i].secs,
3918 &g_toc[i].frms);
3919 } else {
3920 p = b + 8*(i-1);
3921 g_toc[i].bFlags = p[1];
3922 g_toc[i].bTrack = p[2];
3923 g_toc[i].ISRC[0] = 0;
3924 if ((int)((p[5]*60 + p[6])*75 + p[7]) >= 150) {
3925 g_toc[i].dwStartSector = (p[5]*60 + p[6])*75 +
3926 p[7] -150;
3927 } else {
3928 g_toc[i].dwStartSector = 0;
3929 }
3930 g_toc[i].mins = p[5];
3931 g_toc[i].secs = p[6];
3932 g_toc[i].frms = p[7];
3933 }
3934 }
3935 return (0);
3936 }
3937
3938 void
toc_entry(nr,flag,tr,ISRC,lba,m,s,f)3939 toc_entry(nr, flag, tr, ISRC, lba, m, s, f)
3940 unsigned nr;
3941 unsigned flag;
3942 unsigned tr;
3943 unsigned char *ISRC;
3944 unsigned long lba;
3945 int m;
3946 int s;
3947 int f;
3948 {
3949 if (nr > MAXTRK)
3950 return;
3951
3952 g_toc[nr].bFlags = flag;
3953 g_toc[nr].bTrack = tr;
3954 if (ISRC && (char *)g_toc[nr].ISRC != (char *)ISRC) {
3955 strncpy((char *)g_toc[nr].ISRC, (char *)ISRC,
3956 sizeof (g_toc[nr].ISRC) -1);
3957 g_toc[nr].ISRC[sizeof (g_toc[nr].ISRC) -1] = '\0';
3958 }
3959 g_toc[nr].dwStartSector = lba;
3960 g_toc[nr].mins = m;
3961 g_toc[nr].secs = s;
3962 g_toc[nr].frms = f;
3963 }
3964
3965 int
patch_real_end(sector)3966 patch_real_end(sector)
3967 unsigned long sector;
3968 {
3969 g_toc[cdtracks+1].dwStartSector = sector;
3970 return (0);
3971 }
3972
3973 LOCAL int
patch_cd_extra(track,sector)3974 patch_cd_extra(track, sector)
3975 unsigned track;
3976 unsigned long sector;
3977 {
3978 if (track <= cdtracks)
3979 g_toc[track].dwStartSector = sector;
3980 return (0);
3981 }
3982
3983 LOCAL int
restrict_tracks_illleadout()3984 restrict_tracks_illleadout()
3985 {
3986 struct TOC *o = &g_toc[cdtracks+1];
3987 int i;
3988
3989 for (i = cdtracks; i >= 0; i--) {
3990 struct TOC *p = &g_toc[i];
3991 if (GETSTART(o) > GETSTART(p))
3992 break;
3993 }
3994 patch_cd_extra(i+1, GETSTART(o));
3995 cdtracks = i;
3996
3997 return (0);
3998 }
3999
4000 LOCAL void
Set_ISRC(track,ISRC_arg)4001 Set_ISRC(track, ISRC_arg)
4002 unsigned track;
4003 const unsigned char *ISRC_arg;
4004 {
4005 if (track <= (int)cdtracks) {
4006 memcpy(Get_ISRC(track), ISRC_arg, 16);
4007 }
4008 }
4009
4010
4011 unsigned char *
Get_ISRC(p_track)4012 Get_ISRC(p_track)
4013 unsigned long p_track;
4014 {
4015 if (p_track <= cdtracks)
4016 return (g_toc[p_track].ISRC);
4017 return (NULL);
4018 }
4019
4020 LOCAL void
patch_to_audio(p_track)4021 patch_to_audio(p_track)
4022 unsigned long p_track;
4023 {
4024 if (p_track <= cdtracks)
4025 g_toc[p_track].bFlags &= ~0x40;
4026 }
4027
4028 int
Get_Flags(p_track)4029 Get_Flags(p_track)
4030 unsigned long p_track;
4031 {
4032 if (p_track <= cdtracks)
4033 return (g_toc[p_track].bFlags);
4034 return (-1);
4035 }
4036
4037 int
Get_Mins(p_track)4038 Get_Mins(p_track)
4039 unsigned long p_track;
4040 {
4041 if (p_track <= cdtracks)
4042 return (g_toc[p_track].mins);
4043 return (-1);
4044 }
4045
4046 int
Get_Secs(p_track)4047 Get_Secs(p_track)
4048 unsigned long p_track;
4049 {
4050 if (p_track <= cdtracks)
4051 return (g_toc[p_track].secs);
4052 return (-1);
4053 }
4054
4055 int
Get_Frames(p_track)4056 Get_Frames(p_track)
4057 unsigned long p_track;
4058 {
4059 if (p_track <= cdtracks)
4060 return (g_toc[p_track].frms);
4061 return (-1);
4062 }
4063
4064 int
Get_Preemphasis(p_track)4065 Get_Preemphasis(p_track)
4066 unsigned long p_track;
4067 {
4068 if (p_track <= cdtracks)
4069 return (g_toc[p_track].bFlags & 0x10);
4070 return (-1);
4071 }
4072
4073 LOCAL void
Set_SCMS(p_track)4074 Set_SCMS(p_track)
4075 unsigned long p_track;
4076 {
4077 g_toc[p_track].SCMS = 1;
4078 }
4079
4080 int
Get_SCMS(p_track)4081 Get_SCMS(p_track)
4082 unsigned long p_track;
4083 {
4084 if (p_track <= cdtracks)
4085 return (g_toc[p_track].SCMS);
4086 return (-1);
4087 }
4088
4089 int
Get_Copyright(p_track)4090 Get_Copyright(p_track)
4091 unsigned long p_track;
4092 {
4093 if (p_track <= cdtracks) {
4094 if (g_toc[p_track].SCMS)
4095 return (1);
4096 return (((int)g_toc[p_track].bFlags & 0x20) >> 4);
4097 }
4098 return (-1);
4099 }
4100
4101 int
Get_Datatrack(p_track)4102 Get_Datatrack(p_track)
4103 unsigned long p_track;
4104 {
4105 if (p_track <= cdtracks)
4106 return (g_toc[p_track].bFlags & 0x40);
4107 return (-1);
4108 }
4109
4110 int
Get_Channels(p_track)4111 Get_Channels(p_track)
4112 unsigned long p_track;
4113 {
4114 if (p_track <= cdtracks)
4115 return (g_toc[p_track].bFlags & 0x80);
4116 return (-1);
4117 }
4118
4119 int
Get_Tracknumber(p_track)4120 Get_Tracknumber(p_track)
4121 unsigned long p_track;
4122 {
4123 if (p_track <= cdtracks)
4124 return (g_toc[p_track].bTrack);
4125 return (-1);
4126 }
4127
4128 int useHiddenTrack __PR((void));
4129
4130 int
useHiddenTrack()4131 useHiddenTrack()
4132 {
4133 if (global.no_hidden_track)
4134 return (0);
4135 return (have_hiddenAudioTrack);
4136 }
4137
4138
4139
4140 LOCAL void it_reset __PR((struct iterator *this));
4141
4142 LOCAL void
it_reset(this)4143 it_reset(this)
4144 struct iterator *this;
4145 {
4146 this->index = this->startindex;
4147 }
4148
4149
4150 LOCAL int it_hasNextTrack __PR((struct iterator *this));
4151 LOCAL struct TOC *it_getNextTrack __PR((struct iterator *this));
4152
4153 LOCAL int
it_hasNextTrack(this)4154 it_hasNextTrack(this)
4155 struct iterator *this;
4156 {
4157 return (this->index <= (int)cdtracks+1);
4158 }
4159
4160
4161
4162 LOCAL struct TOC *
it_getNextTrack(this)4163 it_getNextTrack(this)
4164 struct iterator *this;
4165 {
4166 /* if ((*this->hasNextTrack)(this) == 0) return (NULL); */
4167 if (this->index > (int)cdtracks+1)
4168 return (NULL);
4169
4170 return (&g_toc[this->index++]);
4171 }
4172
4173
4174 LOCAL void
InitIterator(iter,p_track)4175 InitIterator(iter, p_track)
4176 struct iterator *iter;
4177 unsigned long p_track;
4178 {
4179 if (iter == NULL)
4180 return;
4181
4182 iter->startindex = useHiddenTrack() ? 0 : p_track;
4183 iter->reset = it_reset;
4184 iter->getNextTrack = it_getNextTrack;
4185 iter->hasNextTrack = it_hasNextTrack;
4186 iter->reset(iter);
4187 }
4188
4189 #if 0
4190 LOCAL struct iterator *NewIterator __PR((void));
4191
4192 LOCAL struct iterator *
4193 NewIterator()
4194 {
4195 struct iterator *retval;
4196
4197 retval = malloc(sizeof (struct iterator));
4198 if (retval != NULL) {
4199 InitIterator(retval, 1);
4200 }
4201 return (retval);
4202 }
4203 #endif
4204
4205 long
Get_AudioStartSector(p_track)4206 Get_AudioStartSector(p_track)
4207 unsigned long p_track;
4208 {
4209 #if 1
4210 if (p_track == CDROM_LEADOUT)
4211 p_track = cdtracks + 1;
4212
4213 if (p_track <= cdtracks +1 &&
4214 IS__AUDIO(&g_toc[p_track]))
4215 return (GETSTART(&g_toc[p_track]));
4216 #else
4217 struct iterator i;
4218
4219 InitIterator(&i, p_track);
4220
4221 if (p_track == cdtracks + 1)
4222 p_track = CDROM_LEADOUT;
4223
4224 while (i.hasNextTrack(&i)) {
4225 TOC *p = i.getNextTrack(&i);
4226
4227 if (GETTRACK(p) == p_track) {
4228 if (IS__DATA(p)) {
4229 return (-1);
4230 }
4231 return (GETSTART(p));
4232 }
4233 }
4234 #endif
4235 return (-1);
4236 }
4237
4238
4239 long
Get_StartSector(p_track)4240 Get_StartSector(p_track)
4241 unsigned long p_track;
4242 {
4243 #if 1
4244 if (p_track == CDROM_LEADOUT)
4245 p_track = cdtracks + 1;
4246
4247 if (p_track <= cdtracks +1)
4248 return (GETSTART(&g_toc[p_track]));
4249 #else
4250 struct iterator i;
4251
4252 InitIterator(&i, p_track);
4253
4254 if (p_track == cdtracks + 1)
4255 p_track = CDROM_LEADOUT;
4256
4257 while (i.hasNextTrack(&i)) {
4258 TOC *p = i.getNextTrack(&i);
4259
4260 if (GETTRACK(p) == p_track) {
4261 return (GETSTART(p));
4262 }
4263 }
4264 #endif
4265 return (-1);
4266 }
4267
4268
4269 long
Get_EndSector(p_track)4270 Get_EndSector(p_track)
4271 unsigned long p_track;
4272 {
4273 #if 1
4274 if (p_track <= cdtracks)
4275 return (GETSTART(&g_toc[p_track+1])-1);
4276 #else
4277 struct iterator i;
4278
4279 InitIterator(&i, p_track);
4280
4281 if (p_track == cdtracks + 1)
4282 p_track = CDROM_LEADOUT;
4283
4284 while (i.hasNextTrack(&i)) {
4285 TOC *p = i.getNextTrack(&i);
4286
4287 if (GETTRACK(p) == p_track) {
4288 p = i.getNextTrack(&i);
4289 if (p == NULL) {
4290 return (-1);
4291 }
4292 return (GETSTART(p)-1);
4293 }
4294 }
4295 #endif
4296 return (-1);
4297 }
4298
4299 long
FirstTrack()4300 FirstTrack()
4301 {
4302 struct iterator i;
4303
4304 InitIterator(&i, 1);
4305
4306 if (i.hasNextTrack(&i)) {
4307 return (GETTRACK(i.getNextTrack(&i)));
4308 }
4309 return (-1);
4310 }
4311
4312 long
FirstAudioTrack()4313 FirstAudioTrack()
4314 {
4315 struct iterator i;
4316
4317 InitIterator(&i, 1);
4318
4319 while (i.hasNextTrack(&i)) {
4320 TOC *p = i.getNextTrack(&i);
4321 unsigned ii = GETTRACK(p);
4322
4323 if (ii == CDROM_LEADOUT)
4324 break;
4325 if (IS__AUDIO(p)) {
4326 return (ii);
4327 }
4328 }
4329 return (-1);
4330 }
4331
4332 long
FirstDataTrack()4333 FirstDataTrack()
4334 {
4335 struct iterator i;
4336
4337 InitIterator(&i, 1);
4338
4339 while (i.hasNextTrack(&i)) {
4340 TOC *p = i.getNextTrack(&i);
4341 if (IS__DATA(p)) {
4342 return (GETTRACK(p));
4343 }
4344 }
4345 return (-1);
4346 }
4347
4348 long
LastTrack()4349 LastTrack()
4350 {
4351 return (g_toc[cdtracks].bTrack);
4352 }
4353
4354 long
LastAudioTrack()4355 LastAudioTrack()
4356 {
4357 long j = -1;
4358 struct iterator i;
4359
4360 InitIterator(&i, 1);
4361
4362 while (i.hasNextTrack(&i)) {
4363 TOC *p = i.getNextTrack(&i);
4364
4365 if (IS__AUDIO(p) && (GETTRACK(p) != CDROM_LEADOUT)) {
4366 j = GETTRACK(p);
4367 }
4368 }
4369 return (j);
4370 }
4371
4372 long
Get_LastSectorOnCd(p_track)4373 Get_LastSectorOnCd(p_track)
4374 unsigned long p_track;
4375 {
4376 long LastSec = 0;
4377 struct iterator i;
4378
4379 if (global.illleadout_cd && global.reads_illleadout)
4380 return (150+(99*60+59)*75+74);
4381
4382 InitIterator(&i, p_track);
4383
4384 if (p_track == cdtracks + 1)
4385 p_track = CDROM_LEADOUT;
4386
4387 while (i.hasNextTrack(&i)) {
4388 TOC *p = i.getNextTrack(&i);
4389
4390 if (GETTRACK(p) < p_track)
4391 continue;
4392
4393 LastSec = GETSTART(p);
4394
4395 if (IS__DATA(p))
4396 break;
4397 }
4398 return (LastSec);
4399 }
4400
4401 int
Get_Track(sector)4402 Get_Track(sector)
4403 unsigned long sector;
4404 {
4405 struct iterator i;
4406
4407 InitIterator(&i, 1);
4408
4409 if (i.hasNextTrack(&i)) {
4410 TOC *o = i.getNextTrack(&i);
4411
4412 while (i.hasNextTrack(&i)) {
4413 TOC *p = i.getNextTrack(&i);
4414
4415 if ((GETSTART(o) <= sector) && (GETSTART(p) > sector)) {
4416 if (IS__DATA(o)) {
4417 return (-1);
4418 } else {
4419 return (GETTRACK(o));
4420 }
4421 }
4422 o = p;
4423 }
4424 }
4425 return (-1);
4426 }
4427
4428 int
CheckTrackrange(from,upto)4429 CheckTrackrange(from, upto)
4430 unsigned long from;
4431 unsigned long upto;
4432 {
4433 struct iterator i;
4434
4435 InitIterator(&i, from);
4436
4437 while (i.hasNextTrack(&i)) {
4438 TOC *p = i.getNextTrack(&i);
4439
4440 if (GETTRACK(p) < from)
4441 continue;
4442
4443 if (GETTRACK(p) == upto)
4444 return (1);
4445
4446 /*
4447 * data tracks terminate the search
4448 */
4449 if (IS__DATA(p))
4450 return (0);
4451 }
4452 /*
4453 * track not found
4454 */
4455 return (0);
4456 }
4457
4458 #ifdef USE_PARANOIA
4459 long cdda_disc_firstsector __PR((void *d));
4460
4461 long
cdda_disc_firstsector(d)4462 cdda_disc_firstsector(d)
4463 void *d;
4464 {
4465 return (Get_StartSector(FirstAudioTrack()));
4466 }
4467
4468 int cdda_tracks __PR((void *d));
4469
4470 int
cdda_tracks(d)4471 cdda_tracks(d)
4472 void *d;
4473 {
4474 return (LastAudioTrack() - FirstAudioTrack() +1);
4475 }
4476
4477 int cdda_track_audiop __PR((void *d, int track));
4478
4479 int
cdda_track_audiop(d,track)4480 cdda_track_audiop(d, track)
4481 void *d;
4482 int track;
4483 {
4484 return (Get_Datatrack(track) == 0);
4485 }
4486
4487 long cdda_track_firstsector __PR((void *d, int track));
4488
4489 long
cdda_track_firstsector(d,track)4490 cdda_track_firstsector(d, track)
4491 void *d;
4492 int track;
4493 {
4494 return (Get_AudioStartSector(track));
4495 }
4496
4497 long cdda_track_lastsector __PR((void *d, int track));
4498
4499 long
cdda_track_lastsector(d,track)4500 cdda_track_lastsector(d, track)
4501 void *d;
4502 int track;
4503 {
4504 return (Get_EndSector(track));
4505 }
4506
4507 long cdda_disc_lastsector __PR((void *d));
4508
4509 long
cdda_disc_lastsector(d)4510 cdda_disc_lastsector(d)
4511 void *d;
4512 {
4513 return (Get_LastSectorOnCd(cdtracks) - 1);
4514 }
4515
4516 int cdda_sector_gettrack __PR((void *d, long sector));
4517
4518 int
cdda_sector_gettrack(d,sector)4519 cdda_sector_gettrack(d, sector)
4520 void *d;
4521 long sector;
4522 {
4523 return (Get_Track(sector));
4524 }
4525
4526 #endif
4527