diff options
Diffstat (limited to 'icedax/cd_extra.c')
-rw-r--r-- | icedax/cd_extra.c | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/icedax/cd_extra.c b/icedax/cd_extra.c new file mode 100644 index 0000000..fa17c5b --- /dev/null +++ b/icedax/cd_extra.c @@ -0,0 +1,417 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)cd_extra.c 1.8 02/11/21 Copyright 2000-2001 Heiko Eissfeldt */ + +/* This is an include file! */ +/**************** CD-Extra special treatment *********************************/ + +#include <ctype.h> + +static unsigned long Read_CD_Extra_File(unsigned char *Extra_buf, unsigned long sector); + +static unsigned long +Read_CD_Extra_File(unsigned char *Extra_buf, unsigned long sector) +{ + unsigned long mysec; + + /* read PVD */ + ReadCdRomData(get_scsi_p(), Extra_buf, sector+16, 1); + + /* check ISO signature */ + if (memcmp(Extra_buf, "\001CD001", 6) != 0) return 0; + + /* get path_table */ + mysec = Extra_buf[148] << 24; + mysec |= Extra_buf[149] << 16; + mysec |= Extra_buf[150] << 8; + mysec |= Extra_buf[151]; + + if (mysec <= sector) return 0; + + /* read path table */ + ReadCdRomData(get_scsi_p(), Extra_buf, mysec, 1); + + /* find cdplus subdirectory */ + { unsigned char * p = Extra_buf; + while (p+8 < Extra_buf + CD_FRAMESIZE_RAW) { + int namelength; + + namelength = p[0] | (p[1] << 8); + if (namelength == 6 && + !memcmp(p+8, "CDPLUS", 6)) break; + + p += 8 + namelength + (namelength & 1); + } + if (p+8 >= Extra_buf + CD_FRAMESIZE_RAW) return 0; + + /* get extent */ + mysec = p[2] << 24; + mysec |= p[3] << 16; + mysec |= p[4] << 8; + mysec |= p[5]; + } + + if (mysec <= sector) return 0; + + ReadCdRomData(get_scsi_p(), Extra_buf, mysec, 1); + + /* find file info.cdp */ + { unsigned char * p = Extra_buf; + while (p+33 < Extra_buf + CD_FRAMESIZE_RAW) { + int namelength; + + namelength = p[32]; + if (namelength == 10 && + !memcmp(p+33, "INFO.CDP;1", 10)) break; + + p += p[0]; + } + if (p+33 >= Extra_buf + CD_FRAMESIZE_RAW) return 0; + + /* get extent */ + mysec = p[6] << 24; + mysec |= p[7] << 16; + mysec |= p[8] << 8; + mysec |= p[9]; + } + + if (mysec <= sector) return 0; + + /* read file info.cdp */ + ReadCdRomData(get_scsi_p(), Extra_buf, mysec, 1); + + return mysec - sector; +} + +static unsigned char Extra_buffer[CD_FRAMESIZE_RAW]; + +/* + * Read the file cdplus/info.cdp from the cd extra disc. + * This file has to reside at exactly 75 sectors after start of + * the last session (according to Blue Book). + * Of course, there are a lot dubious cd extras, which don't care :-((( + * As an alternative method, we try reading through the iso9660 file system... + */ +static int Read_CD_Extra_Info(unsigned long sector); +static int Read_CD_Extra_Info(unsigned long sector) +{ + unsigned i; + static int offsets[] = { + 75 /* this is what blue book says */ + }; + + for (i = 0; i < sizeof(offsets)/sizeof(int); i++) { +#ifdef DEBUG_XTRA + fprintf(stderr, "debug: Read_CD_Extra_Info at sector %lu\n", sector+offsets[i]); +#endif + ReadCdRomData(get_scsi_p(), Extra_buffer, sector+offsets[i], 1); + + /* If we are unlucky the drive cannot handle XA sectors by default. + We try to compensate by ignoring the first eight bytes. + Of course then we lack the last 8 bytes of the sector... + */ + + if (Extra_buffer[0] == 0) + memmove(Extra_buffer, Extra_buffer +8, CD_FRAMESIZE - 8); + + /* check for cd extra */ + if (Extra_buffer[0] == 'C' && Extra_buffer[1] == 'D') + return sector+offsets[i]; + + /* + * CD is not conforming to BlueBook! + * Read the file through ISO9660 file system. + */ + { + unsigned long offset = Read_CD_Extra_File(Extra_buffer, sector); + + if (offset == 0) return 0; + + if (Extra_buffer[0] == 0) + memmove(Extra_buffer, Extra_buffer +8, CD_FRAMESIZE - 8); + + /* check for cd extra */ + if (Extra_buffer[0] == 'C' && Extra_buffer[1] == 'D') + return sector+offset; + } + } + + return 0; +} + +static void Read_Subinfo(unsigned pos, unsigned length); +static void Read_Subinfo(unsigned pos, unsigned length) +{ + unsigned num_infos, num; + unsigned char *Subp, *orgSubp; + unsigned this_track = 0xff; +#ifdef DEBUG_XTRA + unsigned char *up; + unsigned char *sp; + unsigned u; + unsigned short s; +#endif + + length += 8; + length = (length + CD_FRAMESIZE_RAW-1) / CD_FRAMESIZE_RAW; + length *= CD_FRAMESIZE_RAW; + orgSubp = Subp = malloc(length); + + if (Subp == NULL) { + fprintf(stderr, "Read_Subinfo no memory(%d)\n",length); + goto errorout; + } + + ReadCdRomData(get_scsi_p(), Subp, pos, 1); + + num_infos = Subp[45]+(Subp[44] << 8); +#ifdef DEBUG_XTRA + fprintf(stderr, "subinfo version %c%c.%c%c, %d info packets\n", + Subp[8], + Subp[9], + Subp[10], + Subp[11], + num_infos); +#endif + length -= 46; + Subp += 46; + for (num = 0; num < num_infos && length > 0; num++) { + unsigned id = *Subp; + unsigned len = *(Subp +1); +#define INFOPACKETTYPES 0x44 +#ifdef INFOPACKETSTRINGS + static const char *infopacketID[INFOPACKETTYPES] = { "0", + "track identifier", + "album title", + "universal product code", + "international standard book number", + "copyright", + "track title", + "notes", + "main interpret", + "secondary interpret", + "composer", + "original composer", + "creation date", + "release date", + "publisher", + "0f", + "isrc audio track", + "isrc lyrics", + "isrc pictures", + "isrc MIDI data", + "14", "15", "16", "17", "18", "19", + "copyright state SUB_INFO", + "copyright state intro lyrics", + "copyright state lyrics", + "copyright state MIDI data", + "1e", "1f", + "intro lyrics", + "pointer to lyrics text file and length", + "22", "23", "24", "25", "26", "27", "28", + "29", "2a", "2b", "2c", "2d", "2e", "2f", + "still picture descriptor", + "31", + "32", "33", "34", "35", "36", "37", "38", + "39", "3a", "3b", "3c", "3d", "3e", "3f", + "MIDI file descriptor", + "genre code", + "tempo", + "key" + }; +#endif + + if (id >= INFOPACKETTYPES) { + fprintf(stderr, "Off=%4d, ind=%2d/%2d, unknown Id=%2u, len=%2u ", + /* this pointer difference is assumed to be small enough for an int. */ + (int)(Subp - orgSubp) + , num, num_infos, id, len); + Subp += 2 + 1; + length -= 2 + 1; + break; + } +#ifdef DEBUG_XTRA + fprintf(stderr, "info packet %d\n", id); +#endif + + switch (id) { + case 1: /* track nummer or 0 */ + this_track = 10 * (*(Subp + 2) - '0') + (*(Subp + 3) - '0'); + break; + + case 0x02: /* album title */ + if (global.disctitle == NULL) { + global.disctitle = malloc(len + 1); + if (global.disctitle != NULL) { + memcpy(global.disctitle, Subp + 2, len); + global.disctitle[len] = '\0'; + } + } + break; + case 0x03: /* media catalog number */ + if (Get_MCN()[0] == '\0' && Subp[2] != '\0' && len >= 13) { + Set_MCN( Subp + 2); + } + break; + case 0x06: /* track title */ + if (this_track > 0 && this_track < 100 + && global.tracktitle[this_track] == NULL) { + global.tracktitle[this_track] = malloc(len + 1); + if (global.tracktitle[this_track] != NULL) { + memcpy(global.tracktitle[this_track], Subp + 2, len); + global.tracktitle[this_track][len] = '\0'; + } + } + break; + case 0x05: /* copyright message */ + if (global.copyright_message == NULL) { + global.copyright_message = malloc(len + 1); + if (global.copyright_message != NULL) { + memcpy(global.copyright_message, Subp + 2, len); + global.copyright_message[len] = '\0'; + } + } + break; + case 0x08: /* creator */ + if (global.creator == NULL) { + global.creator = malloc(len + 1); + if (global.creator != NULL) { + memcpy(global.creator, Subp + 2, len); + global.creator[len] = '\0'; + } + } + break; + case 0x10: /* isrc */ + if (this_track > 0 && this_track < 100 + && Get_ISRC(this_track)[0] == '\0' && Subp[2] != '\0' + && len >= 15) { + Set_ISRC(this_track, Subp + 2); + } + break; +#if 0 + case 0x04: + case 0x07: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: +#ifdef INFOPACKETSTRINGS + fprintf(stderr, "%s: %*.*s\n",infopacketID[id], (int) len, (int) len, (Subp +2)); +#endif + break; +#ifdef DEBUG_XTRA + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: +#ifdef INFOPACKETSTRINGS + fprintf(stderr, "%s %scopyrighted\n", infopacketID[id], *(Subp + 2) == 0 ? "not " : ""); +#endif + break; + + case 0x21: + fprintf(stderr, "lyrics file beginning at sector %u", + (unsigned) GET_BE_UINT_FROM_CHARP(Subp + 2)); + if (len == 8) + fprintf(stderr, ", having length: %u\n", + (unsigned) GET_BE_UINT_FROM_CHARP(Subp + 6)); + else + fputs("\n", stderr); + break; + + case 0x30: + sp = Subp + 2; + while (sp < Subp + 2 + len) { + /*while (len >= 10) {*/ + s = be16_to_cpu((*(sp)) | (*(sp) << 8)); + fprintf(stderr, "%04x, ", s); + sp += 2; + up = sp; + switch (s) { + case 0: + break; + case 4: + break; + case 5: + break; + case 6: + break; + } + u = GET_BE_UINT_FROM_CHARP(up); + fprintf(stderr, "%04lx, ", (long) u); + up += 4; + u = GET_BE_UINT_FROM_CHARP(up); + fprintf(stderr, "%04lx, ", (long) u); + up += 4; + sp += 8; + } + fputs("\n", stderr); + break; + + case 0x40: + fprintf(stderr, "MIDI file beginning at sector %u", + (unsigned) GET_BE_UINT_FROM_CHARP(Subp + 2)); + if (len == 8) + fprintf(stderr, ", having length: %u\n", + (unsigned) GET_BE_UINT_FROM_CHARP(Subp + 6)); + else + fputs("\n", stderr); + break; + +#ifdef INFOPACKETSTRINGS + case 0x42: + fprintf(stderr, "%s: %d beats per minute\n",infopacketID[id], *(Subp + 2)); + break; + case 0x41: + if (len == 8) + fprintf(stderr, "%s: %x, %x, %x, %x, %x, %x, %x, %x\n", + infopacketID[id], + *(Subp + 2), + *(Subp + 3), + *(Subp + 4), + *(Subp + 5), + *(Subp + 6), + *(Subp + 7), + *(Subp + 8), + *(Subp + 9) + ); + else + fprintf(stderr, "%s:\n",infopacketID[id]); + break; + case 0x43: + fprintf(stderr, "%s: %x\n",infopacketID[id], *(Subp + 2)); + break; + default: + fprintf(stderr, "%s: %*.*s\n",infopacketID[id], (int) len, (int) len, (Subp +2)); +#endif +#endif +#endif + } + + if (len & 1) len++; + Subp += 2 + len; + length -= 2 + len; + } + +/* cleanup */ + + free(orgSubp); + +errorout: + return; + +} + |