1 /* @(#)cd_text.c	1.11 10/12/19 Copyright 2000-2001 Heiko Eissfeldt, Copyright 2006-2010 J. Schilling */
2 
3 /*
4  * This is an include file!
5  */
6 /*
7  * The contents of this file are subject to the terms of the
8  * Common Development and Distribution License, Version 1.0 only
9  * (the "License").  You may not use this file except in compliance
10  * with the License.
11  *
12  * See the file CDDL.Schily.txt in this distribution for details.
13  * A copy of the CDDL is also available via the Internet at
14  * http://www.opensource.org/licenses/cddl1.txt
15  *
16  * When distributing Covered Code, include this CDDL HEADER in each
17  * file and include the License file CDDL.Schily.txt from this distribution.
18  */
19 
20 /* *************** CD-Text special treatment ******************************* */
21 
22 typedef struct {
23 	unsigned char headerfield[4];
24 	unsigned char textdatafield[12];
25 	unsigned char crcfield[2];
26 } cdtextpackdata;
27 
28 static unsigned short crctab[1<<8] = { /* as calculated by initcrctab() */
29     0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
30     0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
31     0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
32     0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
33     0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
34     0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
35     0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
36     0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
37     0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
38     0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
39     0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
40     0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
41     0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
42     0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
43     0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
44     0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
45     0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
46     0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
47     0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
48     0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
49     0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
50     0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
51     0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
52     0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
53     0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
54     0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
55     0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
56     0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
57     0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
58     0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
59     0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
60     0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0,
61 };
62 
63 #define	SUBSIZE	18*8
64 
65 static unsigned short	updcrc	__PR((unsigned int p_crc,
66 					unsigned char   *cp,
67 					size_t  cnt));
68 
69 static unsigned short
updcrc(p_crc,cp,cnt)70 updcrc(p_crc, cp, cnt)
71 	unsigned int		p_crc;
72 	register unsigned char	*cp;
73 	register size_t		cnt;
74 {
75 	register unsigned short	crc = (unsigned short)p_crc;
76 
77 	while (cnt--) {
78 		crc = (crc<<8) ^ crctab[(crc>>(16-8)) ^ (*cp++)];
79 	}
80 	return (crc);
81 }
82 
83 static unsigned short	calcCRC	__PR((unsigned char *buf, unsigned bsize));
84 
85 static unsigned short
calcCRC(buf,bsize)86 calcCRC(buf, bsize)
87 	unsigned char	*buf;
88 	unsigned	bsize;
89 {
90 	return (updcrc(0x0, (unsigned char *)buf, bsize));
91 }
92 
93 static unsigned char    fliptab[8] = {
94 				0x01,
95 				0x02,
96 				0x04,
97 				0x08,
98 				0x10,
99 				0x20,
100 				0x40,
101 				0x80,
102 };
103 
104 static int	flip_error_corr	__PR((unsigned char *b, int crc));
105 
106 static int
flip_error_corr(b,crc)107 flip_error_corr(b, crc)
108 	unsigned char	*b;
109 	int		crc;
110 {
111 	if (crc != 0) {
112 		int	i;
113 
114 		for (i = 0; i < SUBSIZE; i++) {
115 			char	c;
116 
117 			c = fliptab[i%8];
118 			b[i / 8] ^= c;
119 			if ((crc = calcCRC(b, SUBSIZE/8)) == 0) {
120 				return (crc);
121 			}
122 			b[i / 8] ^= c;
123 		}
124 	}
125 	return (crc & 0xffff);
126 }
127 
128 
129 static int	cdtext_crc_ok	__PR((cdtextpackdata *c));
130 
131 static int
cdtext_crc_ok(c)132 cdtext_crc_ok(c)
133 	cdtextpackdata	*c;
134 {
135 	int	crc;
136 	int	retval;
137 
138 	c->crcfield[0] ^= 0xff;
139 	c->crcfield[1] ^= 0xff;
140 	crc = calcCRC(((unsigned char *)c), 18);
141 	retval = (0 == flip_error_corr((unsigned char *)c, crc));
142 	c->crcfield[0] ^= 0xff;
143 	c->crcfield[1] ^= 0xff;
144 #if	0
145 	fprintf(stderr, "%02x %02x %02x %02x  ",
146 		c->headerfield[0], c->headerfield[1],
147 		c->headerfield[2], c->headerfield[3]);
148 	fprintf(stderr,
149 		"%c %c %c %c %c %c %c %c %c %c %c %c  ",
150 		c->textdatafield[0],
151 		c->textdatafield[1],
152 		c->textdatafield[2],
153 		c->textdatafield[3],
154 		c->textdatafield[4],
155 		c->textdatafield[5],
156 		c->textdatafield[6],
157 		c->textdatafield[7],
158 		c->textdatafield[8],
159 		c->textdatafield[9],
160 		c->textdatafield[10],
161 		c->textdatafield[11]);
162 	fprintf(stderr, "%02x %02x \n",
163 		c->crcfield[0],
164 		c->crcfield[1]);
165 #endif
166 	return (retval);
167 }
168 
169 #define	DETAILED	0
170 
171 #if	DETAILED
172 static void	dump_binary	__PR((cdtextpackdata *c));
173 
174 static void
dump_binary(c)175 dump_binary(c)
176 	cdtextpackdata	*c;
177 {
178 	fprintf(stderr, _(": header fields %02x %02x %02x  "),
179 		c->headerfield[1], c->headerfield[2], c->headerfield[3]);
180 	fprintf(stderr,
181 		"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
182 		c->textdatafield[0],
183 		c->textdatafield[1],
184 		c->textdatafield[2],
185 		c->textdatafield[3],
186 		c->textdatafield[4],
187 		c->textdatafield[5],
188 		c->textdatafield[6],
189 		c->textdatafield[7],
190 		c->textdatafield[8],
191 		c->textdatafield[9],
192 		c->textdatafield[10],
193 		c->textdatafield[11]);
194 }
195 #endif
196 
197 static int	process_header	__PR((cdtextpackdata *c, unsigned tracknr,
198 					int dbcc, unsigned char *line));
199 
200 static int
process_header(c,tracknr,dbcc,line)201 process_header(c, tracknr, dbcc, line)
202 	cdtextpackdata	*c;
203 	unsigned	tracknr;
204 	int		dbcc;
205 	unsigned char	*line;
206 {
207 	switch ((int)c->headerfield[0]) {
208 
209 	case 0x80:	/* Title of album or track */
210 #if	DETAILED
211 		fprintf(stderr, _("Title"));
212 #endif
213 		if (tracknr > 0 && tracknr < 100 &&
214 		    global.tracktitle[tracknr] == NULL) {
215 			unsigned	len;
216 
217 			len = strlen((char *)line);
218 
219 			if (len > 0)
220 				global.tracktitle[tracknr] = malloc(len + 1);
221 			if (global.tracktitle[tracknr] != NULL) {
222 				memcpy(global.tracktitle[tracknr], line, len);
223 				global.tracktitle[tracknr][len] = '\0';
224 			}
225 		} else if (tracknr == 0 &&
226 			    global.disctitle == NULL) {
227 			unsigned	len;
228 
229 			len = strlen((char *)line);
230 
231 			if (len > 0)
232 				global.disctitle = malloc(len + 1);
233 			if (global.disctitle != NULL) {
234 				memcpy(global.disctitle, line, len);
235 				global.disctitle[len] = '\0';
236 			}
237 		}
238 		break;
239 
240 	case 0x81:	/* Name(s) of the performer(s) */
241 #if	DETAILED
242 		fprintf(stderr, _("Performer(s)"));
243 #endif
244 		if (tracknr > 0 && tracknr < 100 &&
245 		    global.trackperformer[tracknr] == NULL) {
246 			unsigned	len;
247 
248 			len = strlen((char *)line);
249 
250 			if (len > 0)
251 				global.trackperformer[tracknr] = malloc(len + 1);
252 
253 			if (global.trackperformer[tracknr] != NULL) {
254 				memcpy(global.trackperformer[tracknr], line,
255 									len);
256 				global.trackperformer[tracknr][len] = '\0';
257 			}
258 		} else if (tracknr == 0 &&
259 			    global.performer == NULL) {
260 			unsigned	len;
261 
262 			len = strlen((char *)line);
263 
264 			if (len > 0)
265 				global.performer = malloc(len + 1);
266 			if (global.performer != NULL) {
267 				memcpy(global.performer, line, len);
268 				global.performer[len] = '\0';
269 			}
270 		}
271 		break;
272 
273 	case 0x82:	/* Name(s) of the songwriter(s) */
274 #if	DETAILED
275 		fprintf(stderr, _("Songwriter(s)"));
276 #endif
277 		if (tracknr > 0 && tracknr < 100 &&
278 		    global.tracksongwriter[tracknr] == NULL) {
279 			unsigned	len;
280 
281 			len = strlen((char *)line);
282 
283 			if (len > 0)
284 				global.tracksongwriter[tracknr] = malloc(len + 1);
285 
286 			if (global.tracksongwriter[tracknr] != NULL) {
287 				memcpy(global.tracksongwriter[tracknr], line,
288 									len);
289 				global.tracksongwriter[tracknr][len] = '\0';
290 			}
291 		} else if (tracknr == 0 &&
292 			    global.songwriter == NULL) {
293 			unsigned	len;
294 
295 			len = strlen((char *)line);
296 
297 			if (len > 0)
298 				global.songwriter = malloc(len + 1);
299 			if (global.songwriter != NULL) {
300 				memcpy(global.songwriter, line, len);
301 				global.songwriter[len] = '\0';
302 			}
303 		}
304 		break;
305 
306 	case 0x83:	/* Name(s) of the composer(s) */
307 #if	DETAILED
308 		fprintf(stderr, _("Composer(s)"));
309 #endif
310 		if (tracknr > 0 && tracknr < 100 &&
311 		    global.trackcomposer[tracknr] == NULL) {
312 			unsigned	len;
313 
314 			len = strlen((char *)line);
315 
316 			if (len > 0)
317 				global.trackcomposer[tracknr] = malloc(len + 1);
318 
319 			if (global.trackcomposer[tracknr] != NULL) {
320 				memcpy(global.trackcomposer[tracknr], line,
321 									len);
322 				global.trackcomposer[tracknr][len] = '\0';
323 			}
324 		} else if (tracknr == 0 &&
325 			    global.composer == NULL) {
326 			unsigned	len;
327 
328 			len = strlen((char *)line);
329 
330 			if (len > 0)
331 				global.composer = malloc(len + 1);
332 			if (global.composer != NULL) {
333 				memcpy(global.composer, line, len);
334 				global.composer[len] = '\0';
335 			}
336 		}
337 		break;
338 
339 	case 0x84:	/* Name(s) of the arranger(s) */
340 #if	DETAILED
341 		fprintf(stderr, _("Arranger(s)"));
342 #endif
343 		if (tracknr > 0 && tracknr < 100 &&
344 		    global.trackarranger[tracknr] == NULL) {
345 			unsigned	len;
346 
347 			len = strlen((char *)line);
348 
349 			if (len > 0)
350 				global.trackarranger[tracknr] = malloc(len + 1);
351 
352 			if (global.trackarranger[tracknr] != NULL) {
353 				memcpy(global.trackarranger[tracknr], line,
354 									len);
355 				global.trackarranger[tracknr][len] = '\0';
356 			}
357 		} else if (tracknr == 0 &&
358 			    global.arranger == NULL) {
359 			unsigned	len;
360 
361 			len = strlen((char *)line);
362 
363 			if (len > 0)
364 				global.arranger = malloc(len + 1);
365 			if (global.arranger != NULL) {
366 				memcpy(global.arranger, line, len);
367 				global.arranger[len] = '\0';
368 			}
369 		}
370 		break;
371 
372 	case 0x85:	/* Message from content provider and/or artist */
373 #if	DETAILED
374 		fprintf(stderr, _("Message"));
375 #endif
376 		if (tracknr > 0 && tracknr < 100 &&
377 		    global.trackmessage[tracknr] == NULL) {
378 			unsigned	len;
379 
380 			len = strlen((char *)line);
381 
382 			if (len > 0)
383 				global.trackmessage[tracknr] = malloc(len + 1);
384 
385 			if (global.trackmessage[tracknr] != NULL) {
386 				memcpy(global.trackmessage[tracknr], line,
387 									len);
388 				global.trackmessage[tracknr][len] = '\0';
389 			}
390 		} else if (tracknr == 0 &&
391 			    global.message == NULL) {
392 			unsigned	len;
393 
394 			len = strlen((char *)line);
395 
396 			if (len > 0)
397 				global.message = malloc(len + 1);
398 			if (global.message != NULL) {
399 				memcpy(global.message, line, len);
400 				global.message[len] = '\0';
401 			}
402 		}
403 		break;
404 
405 	case 0x86:	/* Disc Identification and information */
406 #if	DETAILED
407 		fprintf(stderr, _("Disc identification"));
408 #endif
409 		if (tracknr == 0 && line[0] != '\0') {
410 			fprintf(stderr, _("Disc identification: %s\n"), line);
411 		}
412 		break;
413 
414 	case 0x87:	/* Genre Identification and information */
415 #if	DETAILED
416 		fprintf(stderr, _("Genre identification"));
417 #endif
418 		break;
419 
420 	case 0x8d:	/* Closed information */
421 #if	DETAILED
422 		fprintf(stderr, _("Closed information"));
423 #endif
424 		if (tracknr > 0 && tracknr < 100 &&
425 		    global.trackclosed_info[tracknr] == NULL) {
426 			unsigned	len;
427 
428 			len = strlen((char *)line);
429 
430 			if (len > 0)
431 				global.trackclosed_info[tracknr] = malloc(len + 1);
432 
433 			if (global.trackclosed_info[tracknr] != NULL) {
434 				memcpy(global.trackclosed_info[tracknr], line,
435 									len);
436 				global.trackclosed_info[tracknr][len] = '\0';
437 			}
438 		} else if (tracknr == 0 &&
439 			    global.closed_info == NULL) {
440 			unsigned	len;
441 
442 			len = strlen((char *)line);
443 
444 			if (len > 0)
445 				global.closed_info = malloc(len + 1);
446 			if (global.closed_info != NULL) {
447 				memcpy(global.closed_info, line, len);
448 				global.closed_info[len] = '\0';
449 			}
450 		}
451 		break;
452 
453 	case 0x8e:	/* UPC/EAN code or ISRC code */
454 #if	DETAILED
455 		fprintf(stderr, _("UPC or ISRC"));
456 #endif
457 		if (tracknr > 0 && tracknr < 100) {
458 			Set_ISRC(tracknr, line);
459 		} else if (tracknr == 0 && line[0] != '\0') {
460 			Set_MCN(line);
461 		}
462 		break;
463 
464 	case 0x88:	/* Table of Content information */
465 #if	DETAILED
466 		fprintf(stderr, _("Table of Content identification"));
467 		dump_binary(c);
468 #endif
469 		return (0);
470 
471 	case 0x89:	/* Second Table of Content information */
472 #if	DETAILED
473 		fprintf(stderr, _("Second Table of Content identification"));
474 		dump_binary(c);
475 #endif
476 		return (0);
477 
478 	case 0x8f:	/* Size information of the block */
479 #if	DETAILED == 0
480 		break;
481 #else
482 		switch (tracknr) {
483 
484 		case 0:
485 			fprintf(outfp,
486 				_("first track is %d, last track is %d\n"),
487 				c->textdatafield[1],
488 				c->textdatafield[2]);
489 			if (c->textdatafield[3] & 0x80) {
490 				fprintf(outfp,
491 				_("Program Area CD Text information available\n"));
492 				if (c->textdatafield[3] & 0x40) {
493 					fprintf(outfp, _("Program Area copy protection available\n"));
494 				}
495 			}
496 			if (c->textdatafield[3] & 0x07) {
497 				fprintf(outfp,
498 				_("message information is %scopyrighted\n"),
499 					c->textdatafield[3] & 0x04 ?
500 							"": _("not "));
501 				fprintf(outfp,
502 				_("Names of performer/songwriter/composer/arranger(s) are %scopyrighted\n"),
503 					c->textdatafield[3] & 0x02 ?
504 							"": _("not "));
505 				fprintf(outfp,
506 				_("album and track names are %scopyrighted\n"),
507 					c->textdatafield[3] & 0x01 ?
508 							"": _("not "));
509 			}
510 			fprintf(outfp,
511 				_("%d packs with album/track names\n"),
512 				c->textdatafield[4]);
513 			fprintf(outfp,
514 				_("%d packs with performer names\n"),
515 				c->textdatafield[5]);
516 			fprintf(outfp,
517 				_("%d packs with songwriter names\n"),
518 				c->textdatafield[6]);
519 			fprintf(outfp,
520 				_("%d packs with composer names\n"),
521 				c->textdatafield[7]);
522 			fprintf(outfp,
523 				_("%d packs with arranger names\n"),
524 				c->textdatafield[8]);
525 			fprintf(outfp,
526 				_("%d packs with artist or content provider messages\n"),
527 				c->textdatafield[9]);
528 			fprintf(outfp,
529 				_("%d packs with disc identification information\n"),
530 				c->textdatafield[10]);
531 			fprintf(outfp,
532 			_("%d packs with genre identification/information\n"),
533 				c->textdatafield[11]);
534 			break;
535 
536 		case 1:
537 			fprintf(outfp,
538 			_("%d packs with table of contents information\n"),
539 				c->textdatafield[0]);
540 			fprintf(outfp,
541 			_("%d packs with second table of contents information\n"),
542 				c->textdatafield[1]);
543 			fprintf(outfp,
544 				_("%d packs with reserved information\n"),
545 				c->textdatafield[2]);
546 			fprintf(outfp,
547 				_("%d packs with reserved information\n"),
548 				c->textdatafield[3]);
549 			fprintf(outfp,
550 				_("%d packs with reserved information\n"),
551 				c->textdatafield[4]);
552 			fprintf(outfp,
553 				_("%d packs with closed information\n"),
554 				c->textdatafield[5]);
555 			fprintf(outfp,
556 				_("%d packs with UPC/EAN ISRC information\n"),
557 				c->textdatafield[6]);
558 			fprintf(outfp,
559 				_("%d packs with size information\n"),
560 				c->textdatafield[7]);
561 			fprintf(outfp,
562 			_("last sequence numbers for blocks 1-8: %d %d %d %d "),
563 				c->textdatafield[8],
564 				c->textdatafield[9],
565 				c->textdatafield[10],
566 				c->textdatafield[11]);
567 			break;
568 
569 		case 2:
570 			fprintf(outfp, "%d %d %d %d\n",
571 				c->textdatafield[0],
572 				c->textdatafield[1],
573 				c->textdatafield[2],
574 				c->textdatafield[3]);
575 			fprintf(outfp,
576 			_("Language codes for blocks 1-8: %d %d %d %d %d %d %d %d\n"),
577 				c->textdatafield[4],
578 				c->textdatafield[5],
579 				c->textdatafield[6],
580 				c->textdatafield[7],
581 				c->textdatafield[8],
582 				c->textdatafield[9],
583 				c->textdatafield[10],
584 				c->textdatafield[11]);
585 			break;
586 		}
587 
588 		fprintf(stderr, _("Blocksize"));
589 		dump_binary(c);
590 		return (0);
591 
592 #if !defined DEBUG_CDTEXT
593 	default:
594 #else
595 	}
596 #endif
597 
598 		fprintf(stderr, _(": header fields %02x %02x %02x  "),
599 			c->headerfield[1], c->headerfield[2],
600 			c->headerfield[3]);
601 #endif /* DETAILED */
602 
603 #if !defined DEBUG_CDTEXT
604 	}
605 #if	DETAILED
606 	if (tracknr == 0) {
607 		fprintf(stderr, _(" for album   : ->"));
608 	} else {
609 		fprintf(stderr, _(" for track %2u: ->"), tracknr);
610 	}
611 	fputs((char *)line, stderr);
612 	fputs("<-", stderr);
613 #endif
614 
615 	if (dbcc != 0) {
616 #else
617 	{
618 #endif
619 		/* EMPTY */
620 #if	DETAILED
621 		fprintf(stderr,
622 		"  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
623 			c->textdatafield[0],
624 			c->textdatafield[1],
625 			c->textdatafield[2],
626 			c->textdatafield[3],
627 			c->textdatafield[4],
628 			c->textdatafield[5],
629 			c->textdatafield[6],
630 			c->textdatafield[7],
631 			c->textdatafield[8],
632 			c->textdatafield[9],
633 			c->textdatafield[10],
634 			c->textdatafield[11]);
635 #endif
636 	}
637 	return (0);
638 }
639