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