1 #include "All.h" 2 #include "APEHeader.h" 3 #include "MACLib.h" 4 #include "APEInfo.h" 5 6 // TODO: should push and pop the file position 7 8 CAPEHeader::CAPEHeader(CIO * pIO) 9 { 10 m_pIO = pIO; 11 } 12 13 CAPEHeader::~CAPEHeader() 14 { 15 16 } 17 18 int CAPEHeader::FindDescriptor(BOOL bSeek) 19 { 20 // store the original location and seek to the beginning 21 int nOriginalFileLocation = m_pIO->GetPosition(); 22 m_pIO->Seek(0, FILE_BEGIN); 23 24 // set the default junk bytes to 0 25 int nJunkBytes = 0; 26 27 // skip an ID3v2 tag (which we really don't support anyway...) 28 unsigned int nBytesRead = 0; 29 unsigned char cID3v2Header[10]; 30 m_pIO->Read((unsigned char *) cID3v2Header, 10, &nBytesRead); 31 if (cID3v2Header[0] == 'I' && cID3v2Header[1] == 'D' && cID3v2Header[2] == '3') 32 { 33 // why is it so hard to figure the lenght of an ID3v2 tag ?!? 34 // unsigned int nLength = *((unsigned int *) &cID3v2Header[6]); 35 36 unsigned int nSyncSafeLength = 0; 37 nSyncSafeLength = (cID3v2Header[6] & 127) << 21; 38 nSyncSafeLength += (cID3v2Header[7] & 127) << 14; 39 nSyncSafeLength += (cID3v2Header[8] & 127) << 7; 40 nSyncSafeLength += (cID3v2Header[9] & 127); 41 42 BOOL bHasTagFooter = FALSE; 43 44 if (cID3v2Header[5] & 16) 45 { 46 bHasTagFooter = TRUE; 47 nJunkBytes = nSyncSafeLength + 20; 48 } 49 else 50 { 51 nJunkBytes = nSyncSafeLength + 10; 52 } 53 54 // error check 55 if (cID3v2Header[5] & 64) 56 { 57 // this ID3v2 length calculator algorithm can't cope with extended headers 58 // we should be ok though, because the scan for the MAC header below should 59 // really do the trick 60 } 61 62 m_pIO->Seek(nJunkBytes, FILE_BEGIN); 63 64 // scan for padding (slow and stupid, but who cares here...) 65 if (!bHasTagFooter) 66 { 67 char cTemp = 0; 68 m_pIO->Read((unsigned char *) &cTemp, 1, &nBytesRead); 69 while (cTemp == 0 && nBytesRead == 1) 70 { 71 nJunkBytes++; 72 m_pIO->Read((unsigned char *) &cTemp, 1, &nBytesRead); 73 } 74 } 75 } 76 m_pIO->Seek(nJunkBytes, FILE_BEGIN); 77 78 // scan until we hit the APE_DESCRIPTOR, the end of the file, or 1 MB later 79 unsigned int nGoalID = (' ' << 24) | ('C' << 16) | ('A' << 8) | ('M'); 80 unsigned int nReadID = 0; 81 int nRetVal = m_pIO->Read(&nReadID, 4, &nBytesRead); 82 if (nRetVal != 0 || nBytesRead != 4) return ERROR_UNDEFINED; 83 84 // SHINTA --> 85 nBytesRead = 1; 86 int nScanBytes = 0; 87 while ( (nGoalID != nReadID) && (nBytesRead > 0) && (nScanBytes < (1024*1024)) ) { 88 unsigned char cTemp[1024]; 89 m_pIO->Read(&cTemp, sizeof(cTemp), &nBytesRead); 90 for ( unsigned int i = 0 ; i < sizeof(cTemp) ; i++ ) { 91 nReadID = (((unsigned int)cTemp[i]) << 24) | (nReadID >> 8); 92 nJunkBytes++; 93 if ( nGoalID == nReadID ) 94 break; 95 } 96 nScanBytes += sizeof(cTemp); 97 } 98 // <-- SHINTA 99 100 if (nGoalID != nReadID) 101 nJunkBytes = -1; 102 103 // seek to the proper place (depending on result and settings) 104 if (bSeek && (nJunkBytes != -1)) 105 { 106 // successfully found the start of the file (seek to it and return) 107 m_pIO->Seek(nJunkBytes, FILE_BEGIN); 108 } 109 else 110 { 111 // restore the original file pointer 112 m_pIO->Seek(nOriginalFileLocation, FILE_BEGIN); 113 } 114 115 return nJunkBytes; 116 } 117 118 int CAPEHeader::Analyze(APE_FILE_INFO * pInfo) 119 { 120 // error check 121 if ((m_pIO == NULL) || (pInfo == NULL)) 122 return ERROR_INVALID_PARAMETER; 123 124 // variables 125 unsigned int nBytesRead = 0; 126 127 // find the descriptor 128 pInfo->nJunkHeaderBytes = FindDescriptor(TRUE); 129 if (pInfo->nJunkHeaderBytes < 0) 130 return ERROR_UNDEFINED; 131 132 // read the first 8 bytes of the descriptor (ID and version) 133 APE_COMMON_HEADER CommonHeader; memset(&CommonHeader, 0, sizeof(APE_COMMON_HEADER)); 134 m_pIO->Read(&CommonHeader, sizeof(APE_COMMON_HEADER), &nBytesRead); 135 136 // make sure we're at the ID 137 if (CommonHeader.cID[0] != 'M' || CommonHeader.cID[1] != 'A' || CommonHeader.cID[2] != 'C' || CommonHeader.cID[3] != ' ') 138 return ERROR_UNDEFINED; 139 140 int nRetVal = ERROR_UNDEFINED; 141 142 if (CommonHeader.nVersion >= 3980) 143 { 144 // current header format 145 nRetVal = AnalyzeCurrent(pInfo); 146 } 147 else 148 { 149 // legacy support 150 nRetVal = AnalyzeOld(pInfo); 151 } 152 153 return nRetVal; 154 } 155 156 int CAPEHeader::AnalyzeCurrent(APE_FILE_INFO * pInfo) 157 { 158 // variable declares 159 unsigned int nBytesRead = 0; 160 pInfo->spAPEDescriptor.Assign(new APE_DESCRIPTOR); memset(pInfo->spAPEDescriptor, 0, sizeof(APE_DESCRIPTOR)); 161 APE_HEADER APEHeader; memset(&APEHeader, 0, sizeof(APEHeader)); 162 163 // read the descriptor 164 m_pIO->Seek(pInfo->nJunkHeaderBytes, FILE_BEGIN); 165 m_pIO->Read(pInfo->spAPEDescriptor, sizeof(APE_DESCRIPTOR), &nBytesRead); 166 167 if ((pInfo->spAPEDescriptor->nDescriptorBytes - nBytesRead) > 0) 168 m_pIO->Seek(pInfo->spAPEDescriptor->nDescriptorBytes - nBytesRead, FILE_CURRENT); 169 170 // read the header 171 m_pIO->Read(&APEHeader, sizeof(APEHeader), &nBytesRead); 172 173 if ((pInfo->spAPEDescriptor->nHeaderBytes - nBytesRead) > 0) 174 m_pIO->Seek(pInfo->spAPEDescriptor->nHeaderBytes - nBytesRead, FILE_CURRENT); 175 176 // fill the APE info structure 177 pInfo->nVersion = int(pInfo->spAPEDescriptor->nVersion); 178 pInfo->nCompressionLevel = int(APEHeader.nCompressionLevel); 179 pInfo->nFormatFlags = int(APEHeader.nFormatFlags); 180 pInfo->nTotalFrames = int(APEHeader.nTotalFrames); 181 pInfo->nFinalFrameBlocks = int(APEHeader.nFinalFrameBlocks); 182 pInfo->nBlocksPerFrame = int(APEHeader.nBlocksPerFrame); 183 pInfo->nChannels = int(APEHeader.nChannels); 184 pInfo->nSampleRate = int(APEHeader.nSampleRate); 185 pInfo->nBitsPerSample = int(APEHeader.nBitsPerSample); 186 pInfo->nBytesPerSample = pInfo->nBitsPerSample / 8; 187 pInfo->nBlockAlign = pInfo->nBytesPerSample * pInfo->nChannels; 188 pInfo->nTotalBlocks = (APEHeader.nTotalFrames == 0) ? 0 : ((APEHeader.nTotalFrames - 1) * pInfo->nBlocksPerFrame) + APEHeader.nFinalFrameBlocks; 189 pInfo->nWAVHeaderBytes = (APEHeader.nFormatFlags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER) ? sizeof(WAVE_HEADER) : pInfo->spAPEDescriptor->nHeaderDataBytes; 190 pInfo->nWAVTerminatingBytes = pInfo->spAPEDescriptor->nTerminatingDataBytes; 191 pInfo->nWAVDataBytes = pInfo->nTotalBlocks * pInfo->nBlockAlign; 192 pInfo->nWAVTotalBytes = pInfo->nWAVDataBytes + pInfo->nWAVHeaderBytes + pInfo->nWAVTerminatingBytes; 193 pInfo->nAPETotalBytes = m_pIO->GetSize(); 194 pInfo->nLengthMS = int((double(pInfo->nTotalBlocks) * double(1000)) / double(pInfo->nSampleRate)); 195 pInfo->nAverageBitrate = (pInfo->nLengthMS <= 0) ? 0 : int((double(pInfo->nAPETotalBytes) * double(8)) / double(pInfo->nLengthMS)); 196 pInfo->nDecompressedBitrate = (pInfo->nBlockAlign * pInfo->nSampleRate * 8) / 1000; 197 pInfo->nSeekTableElements = pInfo->spAPEDescriptor->nSeekTableBytes / 4; 198 199 // get the seek tables (really no reason to get the whole thing if there's extra) 200 pInfo->spSeekByteTable.Assign(new uint32 [pInfo->nSeekTableElements], TRUE); 201 if (pInfo->spSeekByteTable == NULL) { return ERROR_UNDEFINED; } 202 203 m_pIO->Read((unsigned char *) pInfo->spSeekByteTable.GetPtr(), 4 * pInfo->nSeekTableElements, &nBytesRead); 204 205 // get the wave header 206 if (!(APEHeader.nFormatFlags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER)) 207 { 208 pInfo->spWaveHeaderData.Assign(new unsigned char [pInfo->nWAVHeaderBytes], TRUE); 209 if (pInfo->spWaveHeaderData == NULL) { return ERROR_UNDEFINED; } 210 m_pIO->Read((unsigned char *) pInfo->spWaveHeaderData, pInfo->nWAVHeaderBytes, &nBytesRead); 211 } 212 213 return ERROR_SUCCESS; 214 } 215 216 int CAPEHeader::AnalyzeOld(APE_FILE_INFO * pInfo) 217 { 218 // variable declares 219 unsigned int nBytesRead = 0; 220 221 // read the MAC header from the file 222 APE_HEADER_OLD APEHeader; 223 m_pIO->Seek(pInfo->nJunkHeaderBytes, FILE_BEGIN); 224 m_pIO->Read((unsigned char *) &APEHeader, sizeof(APEHeader), &nBytesRead); 225 226 // fail on 0 length APE files (catches non-finalized APE files) 227 if (APEHeader.nTotalFrames == 0) 228 return ERROR_UNDEFINED; 229 230 int nPeakLevel = -1; 231 if (APEHeader.nFormatFlags & MAC_FORMAT_FLAG_HAS_PEAK_LEVEL) 232 m_pIO->Read((unsigned char *) &nPeakLevel, 4, &nBytesRead); 233 234 if (APEHeader.nFormatFlags & MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS) 235 m_pIO->Read((unsigned char *) &pInfo->nSeekTableElements, 4, &nBytesRead); 236 else 237 pInfo->nSeekTableElements = APEHeader.nTotalFrames; 238 239 // fill the APE info structure 240 pInfo->nVersion = int(APEHeader.nVersion); 241 pInfo->nCompressionLevel = int(APEHeader.nCompressionLevel); 242 pInfo->nFormatFlags = int(APEHeader.nFormatFlags); 243 pInfo->nTotalFrames = int(APEHeader.nTotalFrames); 244 pInfo->nFinalFrameBlocks = int(APEHeader.nFinalFrameBlocks); 245 pInfo->nBlocksPerFrame = ((APEHeader.nVersion >= 3900) || ((APEHeader.nVersion >= 3800) && (APEHeader.nCompressionLevel == COMPRESSION_LEVEL_EXTRA_HIGH))) ? 73728 : 9216; 246 if ((APEHeader.nVersion >= 3950)) pInfo->nBlocksPerFrame = 73728 * 4; 247 pInfo->nChannels = int(APEHeader.nChannels); 248 pInfo->nSampleRate = int(APEHeader.nSampleRate); 249 pInfo->nBitsPerSample = (pInfo->nFormatFlags & MAC_FORMAT_FLAG_8_BIT) ? 8 : ((pInfo->nFormatFlags & MAC_FORMAT_FLAG_24_BIT) ? 24 : 16); 250 pInfo->nBytesPerSample = pInfo->nBitsPerSample / 8; 251 pInfo->nBlockAlign = pInfo->nBytesPerSample * pInfo->nChannels; 252 pInfo->nTotalBlocks = (APEHeader.nTotalFrames == 0) ? 0 : ((APEHeader.nTotalFrames - 1) * pInfo->nBlocksPerFrame) + APEHeader.nFinalFrameBlocks; 253 pInfo->nWAVHeaderBytes = (APEHeader.nFormatFlags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER) ? sizeof(WAVE_HEADER) : APEHeader.nHeaderBytes; 254 pInfo->nWAVTerminatingBytes = int(APEHeader.nTerminatingBytes); 255 pInfo->nWAVDataBytes = pInfo->nTotalBlocks * pInfo->nBlockAlign; 256 pInfo->nWAVTotalBytes = pInfo->nWAVDataBytes + pInfo->nWAVHeaderBytes + pInfo->nWAVTerminatingBytes; 257 pInfo->nAPETotalBytes = m_pIO->GetSize(); 258 pInfo->nLengthMS = int((double(pInfo->nTotalBlocks) * double(1000)) / double(pInfo->nSampleRate)); 259 pInfo->nAverageBitrate = (pInfo->nLengthMS <= 0) ? 0 : int((double(pInfo->nAPETotalBytes) * double(8)) / double(pInfo->nLengthMS)); 260 pInfo->nDecompressedBitrate = (pInfo->nBlockAlign * pInfo->nSampleRate * 8) / 1000; 261 262 // get the wave header 263 if (!(APEHeader.nFormatFlags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER)) 264 { 265 pInfo->spWaveHeaderData.Assign(new unsigned char [APEHeader.nHeaderBytes], TRUE); 266 if (pInfo->spWaveHeaderData == NULL) { return ERROR_UNDEFINED; } 267 m_pIO->Read((unsigned char *) pInfo->spWaveHeaderData, APEHeader.nHeaderBytes, &nBytesRead); 268 } 269 270 // get the seek tables (really no reason to get the whole thing if there's extra) 271 pInfo->spSeekByteTable.Assign(new uint32 [pInfo->nSeekTableElements], TRUE); 272 if (pInfo->spSeekByteTable == NULL) { return ERROR_UNDEFINED; } 273 274 m_pIO->Read((unsigned char *) pInfo->spSeekByteTable.GetPtr(), 4 * pInfo->nSeekTableElements, &nBytesRead); 275 276 if (APEHeader.nVersion <= 3800) 277 { 278 pInfo->spSeekBitTable.Assign(new unsigned char [pInfo->nSeekTableElements], TRUE); 279 if (pInfo->spSeekBitTable == NULL) { return ERROR_UNDEFINED; } 280 281 m_pIO->Read((unsigned char *) pInfo->spSeekBitTable, pInfo->nSeekTableElements, &nBytesRead); 282 } 283 284 return ERROR_SUCCESS; 285 } 286