1 /***************************************************************************************** 2 CAPEInfo: 3 -a class to make working with APE files and getting information about them simple 4 *****************************************************************************************/ 5 #include "All.h" 6 #include "APEInfo.h" 7 #include IO_HEADER_FILE 8 #include "APECompress.h" 9 #include "APEHeader.h" 10 11 /***************************************************************************************** 12 Construction 13 *****************************************************************************************/ 14 CAPEInfo::CAPEInfo(int * pErrorCode, const wchar_t * pFilename, CAPETag * pTag) 15 { 16 *pErrorCode = ERROR_SUCCESS; 17 CloseFile(); 18 19 // open the file 20 m_spIO.Assign(new IO_CLASS_NAME); 21 22 if (m_spIO->Open(pFilename) != 0) 23 { 24 CloseFile(); 25 *pErrorCode = ERROR_INVALID_INPUT_FILE; 26 return; 27 } 28 29 // get the file information 30 if (GetFileInformation(TRUE) != 0) 31 { 32 CloseFile(); 33 *pErrorCode = ERROR_INVALID_INPUT_FILE; 34 return; 35 } 36 37 // get the tag (do this second so that we don't do it on failure) 38 if (pTag == NULL) 39 { 40 // we don't want to analyze right away for non-local files 41 // since a single I/O object is shared, we can't tag and read at the same time (i.e. in multiple threads) 42 BOOL bAnalyzeNow = TRUE; 43 if ((strncmp(pFilename, "http://", 7) == 0) || (strncmp(pFilename, "m01p://", 7) == 0)) // SHINTA: wchar_t -> char 44 bAnalyzeNow = FALSE; 45 46 m_spAPETag.Assign(new CAPETag(m_spIO, bAnalyzeNow)); 47 } 48 else 49 { 50 m_spAPETag.Assign(pTag); 51 } 52 53 } 54 55 CAPEInfo::CAPEInfo(int * pErrorCode, CIO * pIO, CAPETag * pTag) 56 { 57 *pErrorCode = ERROR_SUCCESS; 58 CloseFile(); 59 60 m_spIO.Assign(pIO, FALSE, FALSE); 61 62 // get the file information 63 if (GetFileInformation(TRUE) != 0) 64 { 65 CloseFile(); 66 *pErrorCode = ERROR_INVALID_INPUT_FILE; 67 return; 68 } 69 70 // get the tag (do this second so that we don't do it on failure) 71 if (pTag == NULL) 72 m_spAPETag.Assign(new CAPETag(m_spIO, TRUE)); 73 else 74 m_spAPETag.Assign(pTag); 75 } 76 77 78 /***************************************************************************************** 79 Destruction 80 *****************************************************************************************/ 81 CAPEInfo::~CAPEInfo() 82 { 83 CloseFile(); 84 } 85 86 /***************************************************************************************** 87 Close the file 88 *****************************************************************************************/ 89 int CAPEInfo::CloseFile() 90 { 91 m_spIO.Delete(); 92 m_APEFileInfo.spWaveHeaderData.Delete(); 93 m_APEFileInfo.spSeekBitTable.Delete(); 94 m_APEFileInfo.spSeekByteTable.Delete(); 95 m_APEFileInfo.spAPEDescriptor.Delete(); 96 97 m_spAPETag.Delete(); 98 99 // re-initialize variables 100 m_APEFileInfo.nSeekTableElements = 0; 101 m_bHasFileInformationLoaded = FALSE; 102 103 return ERROR_SUCCESS; 104 } 105 106 /***************************************************************************************** 107 Get the file information about the file 108 *****************************************************************************************/ 109 int CAPEInfo::GetFileInformation(BOOL bGetTagInformation) 110 { 111 // quit if there is no simple file 112 if (m_spIO == NULL) { return -1; } 113 114 // quit if the file information has already been loaded 115 if (m_bHasFileInformationLoaded) { return ERROR_SUCCESS; } 116 117 // use a CAPEHeader class to help us analyze the file 118 CAPEHeader APEHeader(m_spIO); 119 int nRetVal = APEHeader.Analyze(&m_APEFileInfo); 120 121 // update our internal state 122 if (nRetVal == ERROR_SUCCESS) 123 m_bHasFileInformationLoaded = TRUE; 124 125 // return 126 return nRetVal; 127 } 128 129 /***************************************************************************************** 130 Primary query function 131 *****************************************************************************************/ 132 int CAPEInfo::GetInfo(APE_DECOMPRESS_FIELDS Field, int nParam1, int nParam2) 133 { 134 int nRetVal = -1; 135 136 switch (Field) 137 { 138 case APE_INFO_FILE_VERSION: 139 nRetVal = m_APEFileInfo.nVersion; 140 break; 141 case APE_INFO_COMPRESSION_LEVEL: 142 nRetVal = m_APEFileInfo.nCompressionLevel; 143 break; 144 case APE_INFO_FORMAT_FLAGS: 145 nRetVal = m_APEFileInfo.nFormatFlags; 146 break; 147 case APE_INFO_SAMPLE_RATE: 148 nRetVal = m_APEFileInfo.nSampleRate; 149 break; 150 case APE_INFO_BITS_PER_SAMPLE: 151 nRetVal = m_APEFileInfo.nBitsPerSample; 152 break; 153 case APE_INFO_BYTES_PER_SAMPLE: 154 nRetVal = m_APEFileInfo.nBytesPerSample; 155 break; 156 case APE_INFO_CHANNELS: 157 nRetVal = m_APEFileInfo.nChannels; 158 break; 159 case APE_INFO_BLOCK_ALIGN: 160 nRetVal = m_APEFileInfo.nBlockAlign; 161 break; 162 case APE_INFO_BLOCKS_PER_FRAME: 163 nRetVal = m_APEFileInfo.nBlocksPerFrame; 164 break; 165 case APE_INFO_FINAL_FRAME_BLOCKS: 166 nRetVal = m_APEFileInfo.nFinalFrameBlocks; 167 break; 168 case APE_INFO_TOTAL_FRAMES: 169 nRetVal = m_APEFileInfo.nTotalFrames; 170 break; 171 case APE_INFO_WAV_HEADER_BYTES: 172 nRetVal = m_APEFileInfo.nWAVHeaderBytes; 173 break; 174 case APE_INFO_WAV_TERMINATING_BYTES: 175 nRetVal = m_APEFileInfo.nWAVTerminatingBytes; 176 break; 177 case APE_INFO_WAV_DATA_BYTES: 178 nRetVal = m_APEFileInfo.nWAVDataBytes; 179 break; 180 case APE_INFO_WAV_TOTAL_BYTES: 181 nRetVal = m_APEFileInfo.nWAVTotalBytes; 182 break; 183 case APE_INFO_APE_TOTAL_BYTES: 184 nRetVal = m_APEFileInfo.nAPETotalBytes; 185 break; 186 case APE_INFO_TOTAL_BLOCKS: 187 nRetVal = m_APEFileInfo.nTotalBlocks; 188 break; 189 case APE_INFO_LENGTH_MS: 190 nRetVal = m_APEFileInfo.nLengthMS; 191 break; 192 case APE_INFO_AVERAGE_BITRATE: 193 nRetVal = m_APEFileInfo.nAverageBitrate; 194 break; 195 case APE_INFO_FRAME_BITRATE: 196 { 197 int nFrame = nParam1; 198 199 nRetVal = 0; 200 201 int nFrameBytes = GetInfo(APE_INFO_FRAME_BYTES, nFrame); 202 int nFrameBlocks = GetInfo(APE_INFO_FRAME_BLOCKS, nFrame); 203 if ((nFrameBytes > 0) && (nFrameBlocks > 0) && m_APEFileInfo.nSampleRate > 0) 204 { 205 int nFrameMS = (nFrameBlocks * 1000) / m_APEFileInfo.nSampleRate; 206 if (nFrameMS != 0) 207 { 208 nRetVal = (nFrameBytes * 8) / nFrameMS; 209 } 210 } 211 break; 212 } 213 case APE_INFO_DECOMPRESSED_BITRATE: 214 nRetVal = m_APEFileInfo.nDecompressedBitrate; 215 break; 216 case APE_INFO_PEAK_LEVEL: 217 nRetVal = -1; // no longer supported 218 break; 219 case APE_INFO_SEEK_BIT: 220 { 221 int nFrame = nParam1; 222 if (GET_FRAMES_START_ON_BYTES_BOUNDARIES(this)) 223 { 224 nRetVal = 0; 225 } 226 else 227 { 228 if (nFrame < 0 || nFrame >= m_APEFileInfo.nTotalFrames) 229 nRetVal = 0; 230 else 231 nRetVal = m_APEFileInfo.spSeekBitTable[nFrame]; 232 } 233 break; 234 } 235 case APE_INFO_SEEK_BYTE: 236 { 237 int nFrame = nParam1; 238 if (nFrame < 0 || nFrame >= m_APEFileInfo.nTotalFrames) 239 nRetVal = 0; 240 else 241 nRetVal = m_APEFileInfo.spSeekByteTable[nFrame] + m_APEFileInfo.nJunkHeaderBytes; 242 break; 243 } 244 case APE_INFO_WAV_HEADER_DATA: 245 { 246 char * pBuffer = (char *) nParam1; 247 int nMaxBytes = nParam2; 248 249 if (m_APEFileInfo.nFormatFlags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER) 250 { 251 if (sizeof(WAVE_HEADER) > static_cast<uint32>(nMaxBytes)) 252 { 253 nRetVal = -1; 254 } 255 else 256 { 257 WAVEFORMATEX wfeFormat; GetInfo(APE_INFO_WAVEFORMATEX, (int) &wfeFormat, 0); 258 WAVE_HEADER WAVHeader; FillWaveHeader(&WAVHeader, m_APEFileInfo.nWAVDataBytes, &wfeFormat, 259 m_APEFileInfo.nWAVTerminatingBytes); 260 memcpy(pBuffer, &WAVHeader, sizeof(WAVE_HEADER)); 261 nRetVal = 0; 262 } 263 } 264 else 265 { 266 if (m_APEFileInfo.nWAVHeaderBytes > nMaxBytes) 267 { 268 nRetVal = -1; 269 } 270 else 271 { 272 memcpy(pBuffer, m_APEFileInfo.spWaveHeaderData, m_APEFileInfo.nWAVHeaderBytes); 273 nRetVal = 0; 274 } 275 } 276 break; 277 } 278 case APE_INFO_WAV_TERMINATING_DATA: 279 { 280 char * pBuffer = (char *) nParam1; 281 int nMaxBytes = nParam2; 282 283 if (m_APEFileInfo.nWAVTerminatingBytes > nMaxBytes) 284 { 285 nRetVal = -1; 286 } 287 else 288 { 289 if (m_APEFileInfo.nWAVTerminatingBytes > 0) 290 { 291 // variables 292 int nOriginalFileLocation = m_spIO->GetPosition(); 293 unsigned int nBytesRead = 0; 294 295 // check for a tag 296 m_spIO->Seek(-(m_spAPETag->GetTagBytes() + m_APEFileInfo.nWAVTerminatingBytes), FILE_END); 297 m_spIO->Read(pBuffer, m_APEFileInfo.nWAVTerminatingBytes, &nBytesRead); 298 299 // restore the file pointer 300 m_spIO->Seek(nOriginalFileLocation, FILE_BEGIN); 301 } 302 nRetVal = 0; 303 } 304 break; 305 } 306 case APE_INFO_WAVEFORMATEX: 307 { 308 WAVEFORMATEX * pWaveFormatEx = (WAVEFORMATEX *) nParam1; 309 FillWaveFormatEx(pWaveFormatEx, m_APEFileInfo.nSampleRate, m_APEFileInfo.nBitsPerSample, m_APEFileInfo.nChannels); 310 nRetVal = 0; 311 break; 312 } 313 case APE_INFO_IO_SOURCE: 314 nRetVal = (int) m_spIO.GetPtr(); 315 break; 316 case APE_INFO_FRAME_BYTES: 317 { 318 int nFrame = nParam1; 319 320 // bound-check the frame index 321 if ((nFrame < 0) || (nFrame >= m_APEFileInfo.nTotalFrames)) 322 { 323 nRetVal = -1; 324 } 325 else 326 { 327 if (nFrame != (m_APEFileInfo.nTotalFrames - 1)) 328 nRetVal = GetInfo(APE_INFO_SEEK_BYTE, nFrame + 1) - GetInfo(APE_INFO_SEEK_BYTE, nFrame); 329 else 330 nRetVal = m_spIO->GetSize() - m_spAPETag->GetTagBytes() - m_APEFileInfo.nWAVTerminatingBytes - GetInfo(APE_INFO_SEEK_BYTE, nFrame); 331 } 332 break; 333 } 334 case APE_INFO_FRAME_BLOCKS: 335 { 336 int nFrame = nParam1; 337 338 // bound-check the frame index 339 if ((nFrame < 0) || (nFrame >= m_APEFileInfo.nTotalFrames)) 340 { 341 nRetVal = -1; 342 } 343 else 344 { 345 if (nFrame != (m_APEFileInfo.nTotalFrames - 1)) 346 nRetVal = m_APEFileInfo.nBlocksPerFrame; 347 else 348 nRetVal = m_APEFileInfo.nFinalFrameBlocks; 349 } 350 break; 351 } 352 case APE_INFO_TAG: 353 nRetVal = (int) m_spAPETag.GetPtr(); 354 break; 355 case APE_INTERNAL_INFO: 356 nRetVal = (int) &m_APEFileInfo; 357 break; 358 default: 359 nRetVal=0; 360 } 361 362 return nRetVal; 363 } 364