/* > cdbx.c * 2.00 arb Thu Jan 22 13:21:31 GMT 2004 - added support for V200 format files, * thanks to a format description by Alex Yakovlev. * 1.03 arb Mon Mar 25 10:20:20 GMT 2002 - added -d option. * 1.02 arb Sun Nov 11 18:05:02 GMT 2001 - more validity checks, and * use discoffset instead of assuming no gaps. * 1.01 arb Sun Aug 5 00:13:56 BST 2001 - bug fix allocating memory, * thanks to Igor Dontsov. * 1.00 arb Mon May 7 15:11:03 BST 2001 * Extract CD Database information from WinAmp's local copy * WinAmp\Plugins\IN_CDDA.cdb * Usage: cdbx [-d] [-v] [/path/to/in_cdda.cdb] */ /* * Configuration: */ #ifdef unix #define DEFAULT_FILENAME "IN_CDDA.cdb" #else #define DEFAULT_FILENAME "C:\\Program Files\\WinAmp\\plugins\\IN_CDDA.cdb" #endif static int debug = 0; static int verbose = 0; #include #include #include #include /* System dependent stuff: byte order and uint32_t definition */ #if defined sun #include #elif defined linux #include # if __BYTE_ORDER == __LITTLE_ENDIAN # define _LITTLE_ENDIAN # else # define _BIG_ENDIAN # endif #elif defined WIN32 #define _LITTLE_ENDIAN typedef unsigned long uint32_t; #else #error unknown byte sex #endif #define HEADER_SIZE (3*sizeof(uint32_t)) typedef enum { V100=100, V110a=110, V200=200, V300=300 } version_t; /* Swap little- to big-endian */ void swap4(void *vp) { unsigned char c, *p = (unsigned char *)vp; c = p[0]; p[0] = p[3]; p[3] = c; c = p[1]; p[1] = p[2]; p[2] = c; } /* Read a little-endian 32-bit unsigned integer */ uint32_t readuint32(FILE*fp) { uint32_t v; fread(&v, sizeof(uint32_t), 1, fp); #ifdef _BIG_ENDIAN swap4(&v); #endif return v; } /* Read a string terminated by a nul character */ char *fgets0(char *blk, int max, FILE *fp) { int c; char *blkstart = blk; while (max-- > 0) { if ((c = getc(fp)) == EOF) break; *blk++ = (char)c; if (!c) break; } if (ferror(fp)) return(NULL); return(blkstart); } /* Structure to hold values stored in trailer: 3 integers per CD */ typedef struct { uint32_t discid, unknown, discoffset; } trailer_t; int cdbx(const char *filename) { FILE *fp; uint32_t ll; uint32_t discid; trailer_t *trailer; version_t version; char title[256], artist[256], discidstr[16], genre[256], year[256]; int ii, jj, numcd, numtrk; /* Open WinAmp file */ fp = fopen(filename, "r"); if (!fp) { fprintf(stderr, "Cannot open %s\n", filename); return(-1); } /* Check for WinAmp's magic string */ ll = readuint32(fp); /* magic */ switch (ll) { case 0xDEADBEEF: version = V100; break; case 0xDEADBEAD: version = V110a; break; case 0xBEEFF00D: version = V200; break; case 0xBEEFF00E: version = V300; break; /* WinAmp 5 */ default: fprintf(stderr, "Not a WinAmp CD Database\n"); exit(1); } /* Read header */ ll = readuint32(fp); /* unknown */ ll = readuint32(fp); /* trailersize */ numcd = ll / (3*sizeof(uint32_t)); if (debug) printf("version %d file contains %d albums\n", version, numcd); /* Read trailer to get discids */ trailer = (trailer_t*)malloc(numcd*sizeof(trailer_t)); fseek(fp, -ll, SEEK_END); for (ii=0; ii= V300) fgets0(genre, 256, fp); if (version >= V300) fgets0(year, 256, fp); if (version >= V200) { fgets0(discidstr, 16, fp); discid = sscanf(discidstr, "%lx", &discid); } printf("DiscID: %s (%08x)\n", discidstr, discid); if (version >= V110a) { ll = readuint32(fp); /* numtracks */ numtrk = ll; } else { numtrk = discid & 0xff; } if (discid && (numtrk != (discid & 0xff))) fprintf(stderr, "Warning: Bad DiscID %8x for %s / %s\n", discid, artist, title); if (numtrk > 99) { fprintf(stderr, "Error: too many tracks (%d) for %s / %s\n", numtrk, artist, title); return(-1); } for (jj=0; jj