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