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
CAPEHeader(CIO * pIO)8 CAPEHeader::CAPEHeader(CIO * pIO)
9 {
10 m_pIO = pIO;
11 }
12
~CAPEHeader()13 CAPEHeader::~CAPEHeader()
14 {
15
16 }
17
FindDescriptor(BOOL bSeek)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
Analyze(APE_FILE_INFO * pInfo)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
AnalyzeCurrent(APE_FILE_INFO * pInfo)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
AnalyzeOld(APE_FILE_INFO * pInfo)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