1 /* @(#)auinfo.c	1.33 10/12/19 Copyright 1998-2010 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)auinfo.c	1.33 10/12/19 Copyright 1998-2010 J. Schilling";
6 #endif
7 /*
8  *	Copyright (c) 1998-2010 J. Schilling
9  */
10 /*
11  * The contents of this file are subject to the terms of the
12  * Common Development and Distribution License, Version 1.0 only
13  * (the "License").  You may not use this file except in compliance
14  * with the License.
15  *
16  * See the file CDDL.Schily.txt in this distribution for details.
17  * A copy of the CDDL is also available via the Internet at
18  * http://www.opensource.org/licenses/cddl1.txt
19  *
20  * When distributing Covered Code, include this CDDL HEADER in each
21  * file and include the License file CDDL.Schily.txt from this distribution.
22  */
23 
24 #include <schily/mconfig.h>
25 #include <schily/stdlib.h>
26 #include <schily/unistd.h>
27 #include <schily/stat.h>
28 #include <schily/stdio.h>
29 #include <schily/standard.h>
30 #include <schily/string.h>
31 #include <schily/deflts.h>
32 #include <schily/utypes.h>
33 #include <schily/schily.h>
34 #include <schily/nlsdefs.h>
35 
36 #include "cdtext.h"
37 #include "cdrecord.h"
38 
39 extern	int	debug;
40 extern	int	xdebug;
41 
42 LOCAL	int	auinfopen	__PR((char *name));
43 EXPORT	BOOL	auinfosize	__PR((char *name, track_t *trackp));
44 EXPORT	BOOL	auinfhidden	__PR((char *name, int track, track_t *trackp));
45 EXPORT	void	auinfo		__PR((char *name, int track, track_t *trackp));
46 EXPORT	textptr_t *gettextptr	__PR((int track, track_t *trackp));
47 LOCAL	char 	*savestr	__PR((char *name));
48 LOCAL	char 	*readtag	__PR((char *name));
49 LOCAL	char 	*readtstr	__PR((char *name));
50 EXPORT	void	setmcn		__PR((char *mcn, track_t *trackp));
51 LOCAL	void	isrc_illchar	__PR((char *isrc, int c));
52 EXPORT	void	setisrc		__PR((char *isrc, track_t *trackp));
53 EXPORT	void	setindex	__PR((char *tindex, track_t *trackp));
54 
55 #ifdef	XXX
main(ac,av)56 main(ac, av)
57 	int	ac;
58 	char	*av[];
59 {
60 /*	auinfo("/etc/default/cdrecord");*/
61 /*	auinfo("/mnt2/CD3/audio_01.inf");*/
62 	auinfo("/mnt2/CD3/audio_01.wav");
63 }
64 #endif
65 
66 LOCAL int
auinfopen(name)67 auinfopen(name)
68 	char	*name;
69 {
70 	char	infname[1024];
71 	char	*p;
72 
73 	strncpy(infname, name, sizeof (infname)-1);
74 	infname[sizeof (infname)-1] = '\0';
75 	p = strrchr(infname, '.');
76 	if (p != 0 && &p[4] < &name[sizeof (infname)]) {
77 		strcpy(&p[1], "inf");
78 	}
79 
80 	return (defltopen(infname));
81 }
82 
83 EXPORT BOOL
auinfosize(name,trackp)84 auinfosize(name, trackp)
85 	char	*name;
86 	track_t	*trackp;
87 {
88 	const	char	*p;
89 	const	char	*tlp;
90 	struct stat	sb;
91 	long		secs;
92 	long		nsamples;
93 	Llong		tracksize;
94 
95 	if (!is_audio(trackp))
96 		return (FALSE);
97 
98 	if ((trackp->flags & TI_USEINFO) == 0)
99 		return (FALSE);
100 
101 	if ((p = strrchr(name, '.')) == NULL)
102 		return (FALSE);
103 	if (!streql(p, ".inf") && !streql(p, ".INF"))
104 		return (FALSE);
105 
106 	/*
107 	 * First check if a bad guy tries to call auinfosize()
108 	 * while STDIN_FILENO is a TTY.
109 	 */
110 	if (isatty(STDIN_FILENO)) {
111 		errmsgno(EX_BAD,
112 			_("WARNING: Stdin is connected to a terminal.\n"));
113 		return (FALSE);
114 	}
115 
116 	if (stat(name, &sb) < 0)	/* *.inf file not found		*/
117 		return (FALSE);
118 
119 	if (sb.st_size > 10000)		/* Too large for a *.inf file	*/
120 		return (FALSE);
121 
122 	if (defltopen(name) < 0)	/* Cannot open *.inf file	*/
123 		return (FALSE);
124 
125 	tlp = p = readtag("Tracklength=");
126 	if (p == NULL) {		/* Tracklength= Tag not found	*/
127 		errmsgno(EX_BAD,
128 			_("WARNING: %s does not contain a 'Tracklength=' tag.\n"),
129 			name);
130 		defltclose();
131 		return (FALSE);
132 	}
133 
134 	p = astol(p, &secs);
135 	if (*p != '\0' && *p != ',') {
136 		errmsgno(EX_BAD,
137 			_("WARNING: %s: 'Tracklength=' contains illegal parameter '%s'.\n"),
138 			name, tlp);
139 		defltclose();
140 		return (FALSE);
141 	}
142 	if (*p == ',')
143 		p++;
144 	p = astol(p, &nsamples);
145 	if (*p != '\0') {
146 		errmsgno(EX_BAD,
147 			_("WARNING: %s: 'Tracklength=' contains illegal parameter '%s'.\n"),
148 			name, tlp);
149 		defltclose();
150 		return (FALSE);
151 	}
152 	tracksize = (secs * 2352) + (nsamples * 4);
153 	if (xdebug > 0) {
154 		error(_("%s: Tracksize %lld bytes (%ld sectors, %ld samples)\n"),
155 			name, tracksize, secs, nsamples);
156 	}
157 	trackp->itracksize = tracksize;
158 	defltclose();
159 	return (TRUE);
160 }
161 
162 EXPORT BOOL
auinfhidden(name,track,trackp)163 auinfhidden(name, track, trackp)
164 	char	*name;
165 	int	track;
166 	track_t	*trackp;
167 {
168 	char	*p;
169 	long	l;
170 	long	tr = -1;
171 	long	tno = -1;
172 	BOOL	isdao = !is_tao(&trackp[0]);
173 
174 	if (auinfopen(name) != 0)
175 		return (FALSE);
176 
177 	p = readtag("Track=");		/* Track no, first track is 1 */
178 	if (p && isdao)
179 		astol(p, &tr);
180 	if (tr != 0)
181 		return (FALSE);
182 	p = readtag("Tracknumber=");	/* Track no, first track >= 1 */
183 	if (p && isdao)
184 		astol(p, &tno);
185 
186 	p = readtag("Trackstart=");
187 	if (p && isdao) {
188 		l = -1L;
189 		astol(p, &l);
190 		if (track == 1 && tno == 0 && l == 0)
191 			return (TRUE);
192 	}
193 	return (FALSE);
194 }
195 
196 EXPORT void
auinfo(name,track,trackp)197 auinfo(name, track, trackp)
198 	char	*name;
199 	int	track;
200 	track_t	*trackp;
201 {
202 	char	*p;
203 	track_t	*tp = &trackp[track];
204 	textptr_t *txp;
205 	long	l;
206 	long	tr = -1;
207 	long	tno = -1;
208 	BOOL	isdao = !is_tao(&trackp[0]);
209 
210 	if (auinfopen(name) != 0)
211 		return;
212 
213 	p = readtstr("CDINDEX_DISCID=");
214 	p = readtag("CDDB_DISKID=");
215 
216 	p = readtag("MCN=");
217 	if (p && *p) {
218 		setmcn(p, &trackp[0]);
219 		txp = gettextptr(0, trackp); /* MCN is isrc for trk 0*/
220 		txp->tc_isrc = savestr(p);
221 	}
222 
223 	p = readtag("ISRC=");
224 	if (p && *p && track > 0) {
225 		setisrc(p, &trackp[track]);
226 		txp = gettextptr(track, trackp);
227 		txp->tc_isrc = savestr(p);
228 	}
229 
230 	p = readtstr("Albumperformer=");
231 	if (p && *p) {
232 		txp = gettextptr(0, trackp); /* Album perf. in trk 0*/
233 		txp->tc_performer = savestr(p);
234 	}
235 	p = readtstr("Performer=");
236 	if (p && *p && track > 0) {
237 		txp = gettextptr(track, trackp);
238 		txp->tc_performer = savestr(p);
239 	}
240 	p = readtstr("Albumtitle=");
241 	if (p && *p) {
242 		txp = gettextptr(0, trackp); /* Album title in trk 0*/
243 		txp->tc_title = savestr(p);
244 	}
245 	p = readtstr("Tracktitle=");
246 	if (p && *p && track > 0) {
247 		txp = gettextptr(track, trackp);
248 		txp->tc_title = savestr(p);
249 	}
250 	p = readtstr("Albumsongwriter=");
251 	if (p && *p) {
252 		txp = gettextptr(0, trackp);
253 		txp->tc_songwriter = savestr(p);
254 	}
255 	p = readtstr("Songwriter=");
256 	if (p && *p && track > 0) {
257 		txp = gettextptr(track, trackp);
258 		txp->tc_songwriter = savestr(p);
259 	}
260 	p = readtstr("Albumcomposer=");
261 	if (p && *p) {
262 		txp = gettextptr(0, trackp);
263 		txp->tc_composer = savestr(p);
264 	}
265 	p = readtstr("Composer=");
266 	if (p && *p && track > 0) {
267 		txp = gettextptr(track, trackp);
268 		txp->tc_composer = savestr(p);
269 	}
270 	p = readtstr("Albumarranger=");
271 	if (p && *p) {
272 		txp = gettextptr(0, trackp);
273 		txp->tc_arranger = savestr(p);
274 	}
275 	p = readtstr("Arranger=");
276 	if (p && *p && track > 0) {
277 		txp = gettextptr(track, trackp);
278 		txp->tc_arranger = savestr(p);
279 	}
280 	p = readtstr("Albummessage=");
281 	if (p && *p) {
282 		txp = gettextptr(0, trackp);
283 		txp->tc_message = savestr(p);
284 	}
285 	p = readtstr("Message=");
286 	if (p && *p && track > 0) {
287 		txp = gettextptr(track, trackp);
288 		txp->tc_message = savestr(p);
289 	}
290 	p = readtstr("Diskid=");
291 	if (p && *p) {
292 		txp = gettextptr(0, trackp); /* Disk id is in trk 0*/
293 		txp->tc_diskid = savestr(p);
294 	}
295 	p = readtstr("Albumclosed_info=");
296 	if (p && *p) {
297 		txp = gettextptr(0, trackp);
298 		txp->tc_closed_info = savestr(p);
299 	}
300 	p = readtstr("Closed_info=");
301 	if (p && *p && track > 0) {
302 		txp = gettextptr(track, trackp);
303 		txp->tc_closed_info = savestr(p);
304 	}
305 
306 	p = readtag("Track=");		/* Track no, first track is 1 */
307 	if (p && isdao)
308 		astol(p, &tr);
309 	p = readtag("Tracknumber=");	/* Track no, first track >= 1 */
310 	if (p && isdao)
311 		astol(p, &tno);
312 	if (tr < 0 && tno > 0)		/* Support old inf files	*/
313 		tr = tno;
314 
315 	p = readtag("Trackstart=");
316 	if (p && isdao) {
317 		l = -1L;
318 		astol(p, &l);
319 		if (track == 1 && tr == 1 && l > 0) {
320 			trackp[1].pregapsize = 150 + l;
321 			printf(_("Track1 Start: '%s' (%ld)\n"), p, l);
322 		}
323 	}
324 
325 	p = readtag("Tracklength=");
326 
327 	p = readtag("Pre-emphasis=");
328 	if (p && *p) {
329 		if (strncmp(p, "yes", 3) == 0) {
330 			tp->flags |= TI_PREEMP;
331 			if ((tp->tracktype & TOC_MASK) == TOC_DA)
332 				tp->sectype = SECT_AUDIO_PRE;
333 
334 		} else if (strncmp(p, "no", 2) == 0) {
335 			tp->flags &= ~TI_PREEMP;
336 			if ((tp->tracktype & TOC_MASK) == TOC_DA)
337 				tp->sectype = SECT_AUDIO_NOPRE;
338 		}
339 	}
340 
341 	p = readtag("Channels=");
342 	p = readtag("Copy_permitted=");
343 	if (p && *p) {
344 		/*
345 		 * -useinfo always wins
346 		 */
347 		tp->flags &= ~(TI_COPY|TI_SCMS);
348 
349 		if (strncmp(p, "yes", 3) == 0)
350 			tp->flags |= TI_COPY;
351 		else if (strncmp(p, "no", 2) == 0)
352 			tp->flags |= TI_SCMS;
353 		else if (strncmp(p, "once", 2) == 0)
354 			tp->flags &= ~(TI_COPY|TI_SCMS);
355 	}
356 	p = readtag("Endianess=");
357 	p = readtag("Index=");
358 	if (p && *p && isdao)
359 		setindex(p, &trackp[track]);
360 
361 	p = readtag("Index0=");
362 	if (p && isdao) {
363 		Llong ts;
364 		Llong ps;
365 
366 		l = -2L;
367 		astol(p, &l);
368 		if (l == -1) {
369 			trackp[track+1].pregapsize = 0;
370 		} else if (l > 0) {
371 			ts = tp->itracksize / tp->isecsize;
372 			ps = ts - l;
373 			if (ps > 0)
374 				trackp[track+1].pregapsize = ps;
375 		}
376 	}
377 }
378 
379 EXPORT textptr_t *
gettextptr(track,trackp)380 gettextptr(track, trackp)
381 	int	track;
382 	track_t	*trackp;
383 {
384 	register textptr_t *txp;
385 
386 	txp = (textptr_t *)trackp[track].text;
387 	if (txp == NULL) {
388 		txp = malloc(sizeof (textptr_t));
389 		if (txp == NULL)
390 			comerr(_("Cannot malloc CD-Text structure.\n"));
391 		fillbytes(txp, sizeof (textptr_t), '\0');
392 		trackp[track].text = txp;
393 	}
394 	return (txp);
395 }
396 
397 LOCAL char *
savestr(str)398 savestr(str)
399 	char	*str;
400 {
401 	char	*ret;
402 
403 	ret = malloc(strlen(str)+1);
404 	if (ret)
405 		strcpy(ret, str);
406 	else
407 		comerr(_("Cannot malloc auinfo string.\n"));
408 	return (ret);
409 }
410 
411 LOCAL char *
readtag(name)412 readtag(name)
413 	char	*name;
414 {
415 	register char	*p;
416 
417 	p = defltread(name);
418 	if (p) {
419 		while (*p == ' ' || *p == '\t')
420 			p++;
421 		if (debug)
422 			printf("%s	'%s'\n", name, p);
423 	}
424 	return (p);
425 }
426 
427 LOCAL char *
readtstr(name)428 readtstr(name)
429 	char	*name;
430 {
431 	register char	*p;
432 	register char	*p2;
433 
434 	p = readtag(name);
435 	if (p && *p == '\'') {
436 		p2 = ++p;
437 		while (*p2 != '\0')
438 			p2++;
439 		while (p2 > p && *p2 != '\'')
440 			p2--;
441 		*p2 = '\0';
442 		if (debug)
443 			printf("%s	'%s'\n", name, p);
444 	}
445 	return (p);
446 }
447 
448 /*
449  * Media catalog number is a 13 digit number.
450  */
451 EXPORT void
setmcn(mcn,trackp)452 setmcn(mcn, trackp)
453 	char	*mcn;
454 	track_t	*trackp;
455 {
456 	register char	*p;
457 
458 	if (strlen(mcn) != 13)
459 		comerrno(EX_BAD, _("MCN '%s' has illegal length.\n"), mcn);
460 
461 	for (p = mcn; *p; p++) {
462 		if (*p < '0' || *p > '9')
463 			comerrno(EX_BAD, _("MCN '%s' contains illegal character '%c'.\n"), mcn, *p);
464 	}
465 	p = malloc(14);
466 	strcpy(p, mcn);
467 	trackp->isrc = p;
468 
469 	if (debug)
470 		printf(_("Track %d MCN: '%s'\n"), (int)trackp->trackno, trackp->isrc);
471 }
472 
473 LOCAL	char	upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
474 
475 LOCAL void
isrc_illchar(isrc,c)476 isrc_illchar(isrc, c)
477 	char	*isrc;
478 	int	c;
479 {
480 	errmsgno(EX_BAD, _("ISRC '%s' contains illegal character '%c'.\n"), isrc, c);
481 }
482 
483 /*
484  * ISRC is 12 Byte:
485  *
486  *	Country code   'C' (alpha)	  2 Bytes
487  *	Owner code     'O' (alphanumeric) 3 Bytes
488  *	Year of record 'Y' (numeric)	  2 Bytes
489  *	Serial number  'S' (numeric)	  5 Bytes
490  *
491  *	CC-OOO-YY-SSSSS
492  */
493 EXPORT void
setisrc(isrc,trackp)494 setisrc(isrc, trackp)
495 	char	*isrc;
496 	track_t	*trackp;
497 {
498 	char	ibuf[13];
499 	char	*ip;
500 	char	*p;
501 	int	i;
502 	int	len;
503 
504 	if ((len = strlen(isrc)) != 12) {
505 		for (p = isrc, i = 0; *p; p++) {
506 			if (*p == '-')
507 				i++;
508 		}
509 		if (((len - i) != 12) || i > 3)
510 			comerrno(EX_BAD, _("ISRC '%s' has illegal length.\n"), isrc);
511 	}
512 
513 	/*
514 	 * The country code.
515 	 */
516 	for (p = isrc, ip = ibuf, i = 0; i < 2; p++, i++) {
517 		*ip++ = *p;
518 		if (!strchr(upper, *p)) {
519 /*			goto illchar;*/
520 			/*
521 			 * Flag numbers but accept them.
522 			 */
523 			isrc_illchar(isrc, *p);
524 			if (*p >= '0' && *p <= '9')
525 				continue;
526 			exit(EX_BAD);
527 		}
528 	}
529 	if (*p == '-')
530 		p++;
531 
532 	/*
533 	 * The owner code.
534 	 */
535 	for (i = 0; i < 3; p++, i++) {
536 		*ip++ = *p;
537 		if (strchr(upper, *p))
538 			continue;
539 		if (*p >= '0' && *p <= '9')
540 			continue;
541 		goto illchar;
542 	}
543 	if (*p == '-')
544 		p++;
545 
546 	/*
547 	 * The Year and the recording number (2 + 5 numbers).
548 	 */
549 	for (i = 0; i < 7; p++, i++) {
550 		*ip++ = *p;
551 		if (*p >= '0' && *p <= '9')
552 			continue;
553 		if (*p == '-' && i == 2) {
554 			ip--;
555 			i--;
556 			continue;
557 		}
558 		goto illchar;
559 	}
560 	*ip = '\0';
561 	p = malloc(13);
562 	strcpy(p, ibuf);
563 	trackp->isrc = p;
564 
565 	if (debug)
566 		printf(_("Track %d ISRC: '%s'\n"), (int)trackp->trackno, trackp->isrc);
567 	return;
568 illchar:
569 	isrc_illchar(isrc, *p);
570 	exit(EX_BAD);
571 }
572 
573 EXPORT void
setindex(tindex,trackp)574 setindex(tindex, trackp)
575 	char	*tindex;
576 	track_t	*trackp;
577 {
578 	char	*p;
579 	int	i;
580 	int	nindex;
581 	long	idx;
582 	long	*idxlist;
583 
584 	idxlist = malloc(100*sizeof (long));
585 	p = tindex;
586 	idxlist[0] = 0;
587 	i = 0;
588 	while (*p) {
589 		p = astol(p, &idx);
590 		if (*p != '\0' && *p != ' ' && *p != '\t' && *p != ',')
591 			goto illchar;
592 		i++;
593 		if (i > 99)
594 			comerrno(EX_BAD, _("Too many indices for track %d\n"), (int)trackp->trackno);
595 		idxlist[i] = idx;
596 		if (*p == ',')
597 			p++;
598 		while (*p == ' ' || *p == '\t')
599 			p++;
600 	}
601 	nindex = i;
602 
603 	if (debug)
604 		printf(_("Track %d %d Index: '%s'\n"), (int)trackp->trackno, i, tindex);
605 
606 	if (debug) {
607 		for (i = 0; i <= nindex; i++)
608 			printf("%d: %ld\n", i, idxlist[i]);
609 	}
610 
611 	trackp->nindex = nindex;
612 	trackp->tindex = idxlist;
613 	return;
614 illchar:
615 	comerrno(EX_BAD, _("Index '%s' contains illegal character '%c'.\n"), tindex, *p);
616 }
617