#include // For unicode type stuffs only... #include // Unicode conversions #include #include #include #include typedef struct { unsigned char pad[2]; // No NULL term!! unsigned char code[2]; // No NULL term!! unsigned long jump; unsigned long myLen; unsigned long count; } fsbbStruct; typedef struct { unsigned long res1; unsigned long strlength; unsigned long res2[2]; } stringParam; typedef struct { unsigned long item_id; unsigned long res1[3]; } propertyParam; typedef struct { unsigned long res1[2]; unsigned long item_ref; unsigned short res2[2]; } playlistParam; char dumpCode( int code ) { switch( code ) { case 1: printf("Title:"); break; case 2: printf("Filename:"); break; case 3: printf("Album:"); break; case 4: printf("Artist:"); break; case 5: printf("Genre:"); break; case 6: printf("Filetype:"); break; case 7: printf("Unknown:"); break; case 8: printf("Comment:"); break; case 100: printf("Unknown:"); break; default: return FALSE; } return TRUE; } // Similar to dumpiTunesDB however, it does everything in memory BOOL dumpiTunesDBmem( char *filename ) { FILE *fp; int filesize; int filepos; unsigned char *contents; fsbbStruct fsbb; // First sixteen byte buffer /////////////////////////////// int readback; /////////////////////////////// fp = fopen( filename, "rb" ); if(!fp) return FALSE; fseek( fp, 0, SEEK_END ); filesize = ftell( fp ); fseek( fp, 0, SEEK_SET ); contents = (unsigned char *)malloc( filesize ); if(!contents) { fclose(fp); return FALSE; } readback = fread( contents, sizeof(unsigned char), filesize, fp ); if( readback != filesize ) printf("WARNING: Unable to read full file (%ld Bytes / Read %ld Bytes)\n", filesize, readback ); filepos = 0; while(filepos < filesize) { // Copy a "header" of sorts memcpy( &fsbb, &contents[filepos], 16 ); //memcpy( ssbb, &contents[filepos+16], 16 ); if( memcmp( fsbb.code, "bd", 2 ) == 0 ) // Start code { printf("%.6x Beginning of database\n", filepos ); } else if( memcmp( fsbb.code, "sd", 2 ) == 0 ) // a list starter { if( fsbb.count == 1) printf("%.6x List of Songs:\n", filepos ); else if( fsbb.count == 2 ) printf("%.6x List of Playlists:\n", filepos ); else printf("%.6x Unknown (%ld)\n", filepos, fsbb.count ); } else if( memcmp( fsbb.code, "lt", 2 ) == 0 ) // a list starter { printf("%.6x %ld-item list:\n", filepos, fsbb.myLen ); } else if( memcmp( fsbb.code, "ip", 2 ) == 0 ) // a playlist item { playlistParam playlist; memcpy( &playlist, &contents[filepos+16], 16 ); printf("%.6x itemref (%ld): XXX\n", filepos, playlist.item_ref ); } else if( memcmp( fsbb.code, "it", 2 ) == 0 ) // a song list item { // item_id propertyParam prop; memcpy( &prop, &contents[filepos+16], 16 ); printf("%.6x %ld-property item (%ld):\n", filepos, fsbb.count, prop.item_id ); } else if( memcmp( fsbb.code, "od", 2 ) == 0 ) // a unicode string, usually { stringParam sp; unsigned short buf[1000]; // I think I saw cut offs around 100 characters char string[500]; printf("%.6x Unicode String(%c%c) %ld %ld %ld\t", filepos, fsbb.code[0], fsbb.code[1], fsbb.jump, fsbb.myLen, fsbb.count ); memcpy( &sp, &contents[filepos+16], 16 ); if( fsbb.myLen == 0 ) // Bad something, skip outta here continue; if( sp.strlength != 0 ) { // memcpy( buf, &contents[filepos+40], fsbb.myLen ); // buf[sizeof(buf)-1] = '\0'; // printf("\t%s\n", buf ); } else { //printf("\tStrlength is 0\n"); memcpy( buf, &contents[filepos+40], (fsbb.myLen-40) ); //buf[sizeof(buf)-1] = '\0'; //WideCharToMultiByte( CP_MACCP, 0, buf, fsbb.myLen, string, sizeof(string), "x", &used ); WideCharToMultiByte( CP_MACCP, 0, buf, (fsbb.myLen-40)/2, string, sizeof(string), "x", NULL ); string[(fsbb.myLen-40)/2] = '\0'; // String now contains a standard ANSI string //printf("\t"); dumpCode( fsbb.count ); printf(" \"%s\"\n\n", string ); } fsbb.jump = fsbb.myLen; } else { printf("%.6x %c%c %ld %ld %ld\n", filepos, fsbb.code[0], fsbb.code[1], fsbb.jump, fsbb.myLen, fsbb.count ); } filepos += fsbb.jump; } free( contents ); return TRUE; } int main(int argc, char* argv[]) { if( argc >= 2 ) { dumpiTunesDBmem( argv[1] ); } else { printf("Usage: itunesdb \n"); } return 0; }