/[debburn]/cdrkit/trunk/icedax/toc.c
ViewVC logotype

Contents of /cdrkit/trunk/icedax/toc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 458 - (show annotations) (download)
Thu Nov 23 23:51:49 2006 UTC (6 years, 6 months ago) by blade
File MIME type: text/plain
File size: 92904 byte(s)
  [ Lorenz Minder ]
  * user output junk filter in icedax/toc.c

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

  ViewVC Help
Powered by ViewVC 1.1.5