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