------------------------------------------------------------------------------------------------------------ The Mp3Wrap format http://mp3wrap.sourceforge.net by Matteo Trotta ------------------------------------------------------------------------------------------------------------ A file created with Mp3Wrap should contain the string "_MP3WRAP.mp3" in filename for easy identification by users and by extractor programs. Each file consists of (in order): 1) ID3v2 2) INDEX 3) DATA 4) One 0x00 end byte ------------------------------------------------------------------------------------------------------------ 1) ID3v2 ID3v2 is an unnecessary element to the correct working of Mp3Wrap format. Change, removal or addition of an ID3v2 tag does not compromise informations about how to split file. ---- You might ask: Q: Why do you think is better to put informations outside ID3? Real purists would say there AREN'T any meta data in MPEG streams! A: Yes, you are right. But I can assure that ID3 is the main reason of AlbumWrap failure. User too often changes/remove ID3 (and permanently damages file). So I think that it's better to make index independent of ID3v2 and keep index as little as possible to let players to easily discard junk data. OR THIS CAN BE ANOTHER SOLUTION: To add a new 'official' field in ID3v2 wich will contain index informations, but we have also to assure that all id3 edit programs should warn about wrap informations loss on ID3 removal. ---- However ID3v2 has the important rule to let the user understand that file has been created with Mp3Wrap and that it is possible to extract original files. So, ID3v2 should contain those informations: TRACK #: number of wrapped files TITLE: "Use Mp3Splt to obtain original tracks" ARTIST: "File wrapped with Mp3Wrap" ALBUM: "http://mp3splt.sourceforge.net" --> COMMENT: "This file is wrapped with Mp3Wrap. Get mp3splt, the free tool to split original files at http://mp3splt.sourceforge.net. Please do not remove this comment." URL: "http://mp3wrap.sourceforge.net" ENCODED by: "Mp3Wrap v. " + VERSION User can in case change TITLE, ARTIST and ALBUM informations (even if they should be leaved unchanged to increase probabilty of identification, for example while playing file). Instead COMMENT must not be changed ------------------------------------------------------------------------------------------------------------- 2) INDEX (version 1) Index is of course the most important part of an Mp3Wrap file. It contains all necessary informations, structured in the easiest way and with the minimal size possible (minimal size reduce also the risk of possible damage by third part programs!). Here is an example of index with 3 files. 0000000000 57 52 41 50 30 35 01 03 19 c6 ee c7 00 00 00 4a | WRAP05...ÆîÇ...J 0000000016 66 69 6c 65 6e 61 6d 65 31 2e 6d 70 33 00 00 00 | filename1.mp3... 0000000032 bd 14 66 69 6c 65 6e 61 6d 65 32 2e 6d 70 33 00 | ½.filename2.mp3. 0000000048 00 01 79 de 66 69 6c 65 6e 61 6d 65 33 2e 6d 70 | ..yÞfilename3.mp 0000000064 33 00 00 02 36 a8 00 00 00 00 | 3...6¨ Index has a variable length but you can distinguish 4 parts: a) HEADER (12 bytes in order): - 4 bytes: "WRAP" string. The capture pattern to simplify identification - 2 bytes: ASCII code of VERSION (1 byte) and SUBVERSION (1 byte) of creating program. Useful for debugging. Example: "05" stands for 0.5 - 1 byte: index version (non ASCII). For future compatibility. - 1 byte: number of wrapped files (non ASCII). For the moment the max number is 0xFF (255 decimal) - 4 bytes (big endian): CRC sum of all data after these 4 bytes and the end of file in order to protect index and data. If an ID3v1 is added at the end, we must not consider it when calculating CRC. First crc initialization: 0xFFFFFFFF. Read APPENDIX A for an example of algorithm. b) SPLITPOINTS and FILENAMES (variable size): For each file these informations are written in index: - 4 bytes (big endian): BEGIN offset from the BEGINNING OF INDEX. It's important that offset is relative to index because this allows to be independent of ID3v2. 4 bytes are type "unsigned long" (in C) that allows use to addres up to 2^32 bytes, which is the size limit of a Mp3Wrap file. It's useful to note that begin offset of the FIRST file corresponds also to index size. - FILENAME: ASCII filename null (0x00) terminated. Can be of variable length, no limits. IMPORTANT NOTE: filename can contain the character '/' or '\' for subfolder info. Infact it is possible to wrap file with path name informations; extractor program will do necessary operations to extract files with correct directory. c) DATA END OFFSET (4 bytes): - 4 bytes (big endian): END OFFSET of last file from the BEGINNING OF INDEX. To keep information on last file size and on end of Mp3Wrap file. All additional data over this limit will be discarded. d) PADDING (4 bytes): 4 bytes of 0x00 to separate index from data. Here is a scheme: HEADER BEGIN OFFSET file1 FILENAME #1 BEGIN OFFSET file2 FILENAME #2 BEGIN OFFSET file3 FILENAME #3 ...... ...... BEGIN OFFSET file n FILENAME #n END OFFSET file n PADDING ------------------------------------------------------------------------------------------------------------- 3) DATA This section is made of real mp3 data, beginning immediately after index. Each file must be appended in the order that appear in index without any kind of separation. For the moment there isn't the necessity to check if data is a valide MPEG stream, with the possibility to add other non-mp3 files. ------------------------------------------------------------------------------------------------------------- 4) 0x00 terminator byte This byte has only one task: to protect file from being damaged. (by Schwarznegger :) Infact if last file has an ID3v1, it will be visible to player or ID3 edit program, and can be edited, or worse removed. This would imply the damage of all Mp3Wrap file, since CRC and END offset will be wrong, and nevertheless last file damaged. With this byte, user can in case add an global ID3v1, that can be edited/removed without fear (of Schwarznegger ;) ------------------------------------------------------------------------------------------------------------- APPENDIX A CRC algorithm static const unsigned long crctab[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, }; unsigned long c_crc (FILE *in, unsigned long begin, unsigned long end) { register unsigned long crc; int c; crc = 0xFFFFFFFF; if (fseek(in, begin, SEEK_SET) == -1) { perror("fseek"); exit(1); } while( begin++ < end) { c = fgetc(in); crc = ((crc >> 8) & 0x00FFFFFF) ^ crctab[(crc ^ c) & 0xFF]; } return (crc ^ 0xFFFFFFFF); }