1 /* @(#)cd_extra.c	1.20 16/02/14 Copyright 2000-2001 Heiko Eissfeldt, Copyright 2004-2010 J. Schilling */
2 #ifndef lint
3 static	const char _sccsid[] =
4 "@(#)cd_extra.c	1.20 16/02/14 Copyright 2000-2001 Heiko Eissfeldt, Copyright 2004-2010 J. Schilling";
5 #endif
6 
7 /*
8  * This is an include file!
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 /**************** CD-Extra special treatment *********************************/
25 
26 #include <schily/ctype.h>
27 
28 static unsigned long Read_CD_Extra_File __PR((unsigned char *Extra_buf,
29 						unsigned long sector));
30 
31 static unsigned long
Read_CD_Extra_File(Extra_buf,sector)32 Read_CD_Extra_File(Extra_buf, sector)
33 	unsigned char	*Extra_buf;
34 	unsigned long	sector;
35 {
36 	unsigned long	mysec;
37 
38 	/* read PVD */
39 	ReadCdRomData(get_scsi_p(), Extra_buf, sector+16, 1);
40 
41 	/* check ISO signature */
42 	if (memcmp(Extra_buf, "\001CD001", 6) != 0)
43 		return (0);
44 
45 	/* get path_table */
46 	mysec = Extra_buf[148] << 24;
47 	mysec |= Extra_buf[149] << 16;
48 	mysec |= Extra_buf[150] << 8;
49 	mysec |= Extra_buf[151];
50 
51 	if (mysec <= sector)
52 		return (0);
53 
54 	/* read path table */
55 	ReadCdRomData(get_scsi_p(), Extra_buf, mysec, 1);
56 
57 	/* find cdplus subdirectory */
58 	{ unsigned char * p = Extra_buf;
59 		while (p+8 < Extra_buf + CD_FRAMESIZE_RAW) {
60 			int namelength;
61 
62 			namelength = p[0] | (p[1] << 8);
63 			if (namelength == 6 &&
64 			    !memcmp(p+8, "CDPLUS", 6)) break;
65 
66 			p += 8 + namelength + (namelength & 1);
67 		}
68 		if (p+8 >= Extra_buf + CD_FRAMESIZE_RAW)
69 			return (0);
70 
71 		/* get extent */
72 		mysec = p[2] << 24;
73 		mysec |= p[3] << 16;
74 		mysec |= p[4] << 8;
75 		mysec |= p[5];
76 	}
77 
78 	if (mysec <= sector)
79 		return (0);
80 
81 	ReadCdRomData(get_scsi_p(), Extra_buf, mysec, 1);
82 
83 	/* find file info.cdp */
84 	{ unsigned char * p = Extra_buf;
85 		while (p+33 < Extra_buf + CD_FRAMESIZE_RAW) {
86 			int namelength;
87 
88 			namelength = p[32];
89 			if (namelength < 1)	/* Not a valid filename	*/
90 				return (0);
91 			if (namelength == 10 &&
92 			    !memcmp(p+33, "INFO.CDP;1", 10)) break;
93 
94 			p += p[0];
95 			if (p[0] == 0)		/* Avoid endless loop	*/
96 				return (0);	/* with bad dir content	*/
97 		}
98 		if (p+33 >= Extra_buf + CD_FRAMESIZE_RAW)
99 			return (0);
100 
101 		/* get extent */
102 		mysec = p[6] << 24;
103 		mysec |= p[7] << 16;
104 		mysec |= p[8] << 8;
105 		mysec |= p[9];
106 	}
107 
108 	if (mysec <= sector)
109 		return (0);
110 
111 	/* read file info.cdp */
112 	ReadCdRomData(get_scsi_p(), Extra_buf, mysec, 1);
113 
114 	return (mysec - sector);
115 }
116 
117 static unsigned char Extra_buffer[CD_FRAMESIZE_RAW];
118 
119 /*
120  * Read the file cdplus/info.cdp from the cd extra disc.
121  * This file has to reside at exactly 75 sectors after start of
122  * the last session (according to Blue Book).
123  * Of course, there are a lot dubious cd extras, which don't care :-(((
124  * As an alternative method, we try reading through the iso9660 file system...
125  */
126 static int Read_CD_Extra_Info __PR((unsigned long sector));
Read_CD_Extra_Info(sector)127 static int Read_CD_Extra_Info(sector)
128 	unsigned long sector;
129 {
130 	unsigned	i;
131 static int		offsets[] = {
132 		75		/* this is what blue book says */
133 	};
134 
135 	for (i = 0; i < sizeof (offsets)/sizeof (int); i++) {
136 #ifdef DEBUG_XTRA
137 		fprintf(stderr,
138 			"debug: Read_CD_Extra_Info at sector %lu\n",
139 			sector+offsets[i]);
140 #endif
141 		ReadCdRomData(get_scsi_p(), Extra_buffer,
142 							sector+offsets[i], 1);
143 
144 		/*
145 		 * If we are unlucky the drive cannot handle XA sectors by
146 		 * default.
147 		 * We try to compensate by ignoring the first eight bytes.
148 		 * Of course then we lack the last 8 bytes of the sector...
149 		 */
150 		if (Extra_buffer[0] == 0)
151 			memmove(Extra_buffer, Extra_buffer +8,
152 							CD_FRAMESIZE - 8);
153 
154 		/*
155 		 * check for cd extra
156 		 */
157 		if (Extra_buffer[0] == 'C' && Extra_buffer[1] == 'D')
158 			return (sector+offsets[i]);
159 
160 	/*
161 	 * CD is not conforming to BlueBook!
162 	 * Read the file through ISO9660 file system.
163 	 */
164 	{
165 		unsigned long	offset = Read_CD_Extra_File(Extra_buffer,
166 								sector);
167 
168 		if (offset == 0)
169 			return (0);
170 
171 		if (Extra_buffer[0] == 0)
172 			memmove(Extra_buffer, Extra_buffer +8,
173 							CD_FRAMESIZE - 8);
174 
175 		/*
176 		 * check for cd extra
177 		 */
178 		if (Extra_buffer[0] == 'C' && Extra_buffer[1] == 'D')
179 			return (sector+offset);
180 		}
181 	}
182 
183 	return (0);
184 }
185 
186 static void Read_Subinfo __PR((unsigned pos, unsigned length));
187 static void
Read_Subinfo(pos,length)188 Read_Subinfo(pos, length)
189 	unsigned	pos;
190 	unsigned	length;
191 {
192 	unsigned	num_infos, num;
193 	unsigned char	*Subp, *orgSubp;
194 	unsigned	this_track = 0xff;
195 #ifdef DEBUG_XTRA
196 	unsigned char	*up;
197 	unsigned char	*sp;
198 	unsigned	u;
199 	unsigned short	s;
200 #endif
201 
202 	length += 8;
203 	length = (length + CD_FRAMESIZE_RAW-1) / CD_FRAMESIZE_RAW;
204 	length *= CD_FRAMESIZE_RAW;
205 	orgSubp = Subp = malloc(length);
206 
207 	if (Subp == NULL) {
208 		errmsg(_("Read_Subinfo no memory(%d).\n"), length);
209 		goto errorout;
210 	}
211 
212 	ReadCdRomData(get_scsi_p(), Subp, pos, 1);
213 
214 	num_infos = Subp[45]+(Subp[44] << 8);
215 #ifdef DEBUG_XTRA
216 	fprintf(stderr, "subinfo version %c%c.%c%c, %u info packets\n",
217 			Subp[8],
218 			Subp[9],
219 			Subp[10],
220 			Subp[11],
221 			num_infos);
222 #endif
223 	length -= 46;
224 	Subp += 46;
225 
226 	for (num = 0; num < num_infos && length > 0; num++) {
227 		unsigned	id = *Subp;
228 		unsigned	len = *(Subp +1);
229 #define	INFOPACKETTYPES	0x44
230 #ifdef	INFOPACKETSTRINGS
231 		static const char *infopacketID[INFOPACKETTYPES] = { "0",
232 			"track identifier",
233 			"album title",
234 			"universal product code",
235 			"international standard book number",
236 			"copyright",
237 			"track title",
238 			"notes",
239 			"main interpret",
240 			"secondary interpret",
241 			"composer",
242 			"original composer",
243 			"creation date",
244 			"release  date",
245 			"publisher",
246 			"0f",
247 			"isrc audio track",
248 			"isrc lyrics",
249 			"isrc pictures",
250 			"isrc MIDI data",
251 			"14", "15", "16", "17", "18", "19",
252 			"copyright state SUB_INFO",
253 			"copyright state intro lyrics",
254 			"copyright state lyrics",
255 			"copyright state MIDI data",
256 			"1e", "1f",
257 			"intro lyrics",
258 			"pointer to lyrics text file and length",
259 			"22", "23", "24", "25", "26", "27", "28",
260 			"29", "2a", "2b", "2c", "2d", "2e", "2f",
261 			"still picture descriptor",
262 			"31",
263 			"32", "33", "34", "35", "36", "37", "38",
264 			"39", "3a", "3b", "3c", "3d", "3e", "3f",
265 			"MIDI file descriptor",
266 			"genre code",
267 			"tempo",
268 			"key"
269 		};
270 #endif
271 
272 		if (id >= INFOPACKETTYPES) {
273 			fprintf(stderr,
274 			"Off=%4d, ind=%2u/%2u, unknown Id=%2u, len=%2u ",
275 				/*
276 				 * this pointer difference is assumed to be
277 				 * small enough for an int.
278 				 */
279 				(int)(Subp - orgSubp),
280 				num, num_infos, id, len);
281 			Subp += 2 + 1;
282 			length -= 2 + 1;
283 			break;
284 		}
285 #ifdef DEBUG_XTRA
286 		fprintf(stderr, "info packet %u\n", id);
287 #endif
288 
289 		switch (id) {
290 
291 		case 1:    /* track nummer or 0 */
292 			this_track = 10 * (*(Subp + 2) - '0') +
293 					(*(Subp + 3) - '0');
294 			break;
295 
296 		case 0x02: /* album title */
297 			if (global.disctitle == NULL) {
298 				global.disctitle = malloc(len + 1);
299 				if (global.disctitle != NULL) {
300 					memcpy(global.disctitle, Subp + 2,
301 									len);
302 					global.disctitle[len] = '\0';
303 				}
304 			}
305 			break;
306 
307 		case 0x03: /* media catalog number */
308 			if (Get_MCN()[0] == '\0' && Subp[2] != '\0' &&
309 			    len >= 13) {
310 				Set_MCN(Subp + 2);
311 			}
312 			break;
313 
314 		case 0x06: /* track title */
315 			if (this_track > 0 && this_track < 100 &&
316 			    global.tracktitle[this_track] == NULL) {
317 				global.tracktitle[this_track] = malloc(len+1);
318 				if (global.tracktitle[this_track] != NULL) {
319 					memcpy(global.tracktitle[this_track],
320 								Subp + 2, len);
321 					global.tracktitle[this_track][len] = '\0';
322 				}
323 			}
324 			break;
325 
326 		case 0x05: /* copyright message */
327 			if (global.copyright_message == NULL) {
328 				global.copyright_message = malloc(len + 1);
329 				if (global.copyright_message != NULL) {
330 					memcpy(global.copyright_message,
331 								Subp + 2, len);
332 					global.copyright_message[len] = '\0';
333 				}
334 			}
335 			break;
336 
337 		case 0x08: /* creator -> CD-Text performer */
338 			if (global.performer == NULL) {
339 				global.performer = malloc(len + 1);
340 				if (global.performer != NULL) {
341 					memcpy(global.performer, Subp + 2, len);
342 					global.performer[len] = '\0';
343 				}
344 			}
345 			break;
346 
347 		case 0x10: /* isrc */
348 			if (this_track > 0 && this_track < 100 &&
349 			    Get_ISRC(this_track)[0] == '\0' &&
350 			    Subp[2] != '\0' &&
351 			    len >= 15) {
352 				Set_ISRC(this_track, Subp + 2);
353 			}
354 			break;
355 
356 #if 0
357 		case 0x04:
358 		case 0x07:
359 		case 0x09:
360 		case 0x0a:
361 		case 0x0b:
362 		case 0x0c:
363 		case 0x0d:
364 		case 0x0e:
365 		case 0x0f:
366 #ifdef	INFOPACKETSTRINGS
367 			fprintf(outfp, "%s: %*.*s\n",
368 				infopacketID[id],
369 				(int) len, (int) len, (Subp +2));
370 #endif
371 			break;
372 
373 #ifdef DEBUG_XTRA
374 		case 0x1a:
375 		case 0x1b:
376 		case 0x1c:
377 		case 0x1d:
378 #ifdef	INFOPACKETSTRINGS
379 			fprintf(outfp, _("%s %scopyrighted\n"),
380 				infopacketID[id], *(Subp + 2) == 0 ?
381 								_("not ") : "");
382 #endif
383 			break;
384 
385 	case 0x21:
386 			fprintf(outfp, _("lyrics file beginning at sector %u"),
387 				(unsigned) GET_BE_UINT_FROM_CHARP(Subp + 2));
388 			if (len == 8)
389 				fprintf(outfp, _(", having length: %u\n"),
390 				(unsigned) GET_BE_UINT_FROM_CHARP(Subp + 6));
391 			else
392 				fputs("\n", outfp);
393 			break;
394 
395 		case 0x30:
396 			sp = Subp + 2;
397 			while (sp < Subp + 2 + len) {
398 			/*while (len >= 10) {*/
399 				s = be16_to_cpu((*(sp)) | (*(sp) << 8));
400 				fprintf(outfp, "%04x, ", s);
401 				sp += 2;
402 				up = sp;
403 				switch (s) {
404 				case 0:
405 					break;
406 				case 4:
407 					break;
408 				case 5:
409 					break;
410 				case 6:
411 					break;
412 				}
413 				u = GET_BE_UINT_FROM_CHARP(up);
414 				fprintf(outfp, "%04lx, ", (long) u);
415 				up += 4;
416 				u = GET_BE_UINT_FROM_CHARP(up);
417 				fprintf(outfp, "%04lx, ", (long) u);
418 				up += 4;
419 				sp += 8;
420 			}
421 			fputs("\n", outfp);
422 			break;
423 
424 		case 0x40:
425 			fprintf(outfp, _("MIDI file beginning at sector %u"),
426 				(unsigned) GET_BE_UINT_FROM_CHARP(Subp + 2));
427 			if (len == 8)
428 				fprintf(outfp, _(", having length: %u\n"),
429 				(unsigned) GET_BE_UINT_FROM_CHARP(Subp + 6));
430 			else
431 				fputs("\n", outfp);
432 			break;
433 
434 #ifdef	INFOPACKETSTRINGS
435 		case 0x42:
436 			fprintf(outfp, _("%s: %d beats per minute\n"),
437 					infopacketID[id], *(Subp + 2));
438 			break;
439 
440 		case 0x41:
441 			if (len == 8) {
442 				fprintf(outfp,
443 					"%s: %x, %x, %x, %x, %x, %x, %x, %x\n",
444 					infopacketID[id],
445 					*(Subp + 2),
446 					*(Subp + 3),
447 					*(Subp + 4),
448 					*(Subp + 5),
449 					*(Subp + 6),
450 					*(Subp + 7),
451 					*(Subp + 8),
452 					*(Subp + 9));
453 			} else {
454 				fprintf(outfp, "%s:\n", infopacketID[id]);
455 			}
456 			break;
457 
458 		case 0x43:
459 			fprintf(outfp,
460 				"%s: %x\n", infopacketID[id], *(Subp + 2));
461 			break;
462 
463 		default:
464 			fprintf(outfp,
465 				"%s: %*.*s\n", infopacketID[id],
466 				(int)len, (int)len, (Subp +2));
467 #endif
468 #endif
469 #endif
470 		}
471 
472 		if (len & 1)
473 			len++;
474 		Subp += 2 + len;
475 		length -= 2 + len;
476 	}
477 
478 	/*
479 	 * cleanup
480 	 */
481 	free(orgSubp);
482 
483 errorout:
484 	;
485 }
486