PageRenderTime 50ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/paplayer/mac-3.99-u4-b5/src/MACLib/APEHeader.cpp

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