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