1 /*****************************************************************************************
3 -a class to make working with APE files and getting information about them simple
4 *****************************************************************************************/
7 #include IO_HEADER_FILE
8 #include "APECompress.h"
11 /*****************************************************************************************
13 *****************************************************************************************/
14 CAPEInfo::CAPEInfo(int * pErrorCode
, const wchar_t * pFilename
, CAPETag
* pTag
)
16 *pErrorCode
= ERROR_SUCCESS
;
20 m_spIO
.Assign(new IO_CLASS_NAME
);
22 if (m_spIO
->Open(pFilename
) != 0)
25 *pErrorCode
= ERROR_INVALID_INPUT_FILE
;
29 // get the file information
30 if (GetFileInformation(TRUE
) != 0)
33 *pErrorCode
= ERROR_INVALID_INPUT_FILE
;
37 // get the tag (do this second so that we don't do it on failure)
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
46 m_spAPETag
.Assign(new CAPETag(m_spIO
, bAnalyzeNow
));
50 m_spAPETag
.Assign(pTag
);
55 CAPEInfo::CAPEInfo(int * pErrorCode
, CIO
* pIO
, CAPETag
* pTag
)
57 *pErrorCode
= ERROR_SUCCESS
;
60 m_spIO
.Assign(pIO
, FALSE
, FALSE
);
62 // get the file information
63 if (GetFileInformation(TRUE
) != 0)
66 *pErrorCode
= ERROR_INVALID_INPUT_FILE
;
70 // get the tag (do this second so that we don't do it on failure)
72 m_spAPETag
.Assign(new CAPETag(m_spIO
, TRUE
));
74 m_spAPETag
.Assign(pTag
);
78 /*****************************************************************************************
80 *****************************************************************************************/
86 /*****************************************************************************************
88 *****************************************************************************************/
89 int CAPEInfo::CloseFile()
92 m_APEFileInfo
.spWaveHeaderData
.Delete();
93 m_APEFileInfo
.spSeekBitTable
.Delete();
94 m_APEFileInfo
.spSeekByteTable
.Delete();
95 m_APEFileInfo
.spAPEDescriptor
.Delete();
99 // re-initialize variables
100 m_APEFileInfo
.nSeekTableElements
= 0;
101 m_bHasFileInformationLoaded
= FALSE
;
103 return ERROR_SUCCESS
;
106 /*****************************************************************************************
107 Get the file information about the file
108 *****************************************************************************************/
109 int CAPEInfo::GetFileInformation(BOOL bGetTagInformation
)
111 // quit if there is no simple file
112 if (m_spIO
== NULL
) { return -1; }
114 // quit if the file information has already been loaded
115 if (m_bHasFileInformationLoaded
) { return ERROR_SUCCESS
; }
117 // use a CAPEHeader class to help us analyze the file
118 CAPEHeader
APEHeader(m_spIO
);
119 int nRetVal
= APEHeader
.Analyze(&m_APEFileInfo
);
121 // update our internal state
122 if (nRetVal
== ERROR_SUCCESS
)
123 m_bHasFileInformationLoaded
= TRUE
;
129 /*****************************************************************************************
130 Primary query function
131 *****************************************************************************************/
132 int CAPEInfo::GetInfo(APE_DECOMPRESS_FIELDS Field
, int nParam1
, int nParam2
)
138 case APE_INFO_FILE_VERSION
:
139 nRetVal
= m_APEFileInfo
.nVersion
;
141 case APE_INFO_COMPRESSION_LEVEL
:
142 nRetVal
= m_APEFileInfo
.nCompressionLevel
;
144 case APE_INFO_FORMAT_FLAGS
:
145 nRetVal
= m_APEFileInfo
.nFormatFlags
;
147 case APE_INFO_SAMPLE_RATE
:
148 nRetVal
= m_APEFileInfo
.nSampleRate
;
150 case APE_INFO_BITS_PER_SAMPLE
:
151 nRetVal
= m_APEFileInfo
.nBitsPerSample
;
153 case APE_INFO_BYTES_PER_SAMPLE
:
154 nRetVal
= m_APEFileInfo
.nBytesPerSample
;
156 case APE_INFO_CHANNELS
:
157 nRetVal
= m_APEFileInfo
.nChannels
;
159 case APE_INFO_BLOCK_ALIGN
:
160 nRetVal
= m_APEFileInfo
.nBlockAlign
;
162 case APE_INFO_BLOCKS_PER_FRAME
:
163 nRetVal
= m_APEFileInfo
.nBlocksPerFrame
;
165 case APE_INFO_FINAL_FRAME_BLOCKS
:
166 nRetVal
= m_APEFileInfo
.nFinalFrameBlocks
;
168 case APE_INFO_TOTAL_FRAMES
:
169 nRetVal
= m_APEFileInfo
.nTotalFrames
;
171 case APE_INFO_WAV_HEADER_BYTES
:
172 nRetVal
= m_APEFileInfo
.nWAVHeaderBytes
;
174 case APE_INFO_WAV_TERMINATING_BYTES
:
175 nRetVal
= m_APEFileInfo
.nWAVTerminatingBytes
;
177 case APE_INFO_WAV_DATA_BYTES
:
178 nRetVal
= m_APEFileInfo
.nWAVDataBytes
;
180 case APE_INFO_WAV_TOTAL_BYTES
:
181 nRetVal
= m_APEFileInfo
.nWAVTotalBytes
;
183 case APE_INFO_APE_TOTAL_BYTES
:
184 nRetVal
= m_APEFileInfo
.nAPETotalBytes
;
186 case APE_INFO_TOTAL_BLOCKS
:
187 nRetVal
= m_APEFileInfo
.nTotalBlocks
;
189 case APE_INFO_LENGTH_MS
:
190 nRetVal
= m_APEFileInfo
.nLengthMS
;
192 case APE_INFO_AVERAGE_BITRATE
:
193 nRetVal
= m_APEFileInfo
.nAverageBitrate
;
195 case APE_INFO_FRAME_BITRATE
:
197 int nFrame
= nParam1
;
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)
205 int nFrameMS
= (nFrameBlocks
* 1000) / m_APEFileInfo
.nSampleRate
;
208 nRetVal
= (nFrameBytes
* 8) / nFrameMS
;
213 case APE_INFO_DECOMPRESSED_BITRATE
:
214 nRetVal
= m_APEFileInfo
.nDecompressedBitrate
;
216 case APE_INFO_PEAK_LEVEL
:
217 nRetVal
= -1; // no longer supported
219 case APE_INFO_SEEK_BIT
:
221 int nFrame
= nParam1
;
222 if (GET_FRAMES_START_ON_BYTES_BOUNDARIES(this))
228 if (nFrame
< 0 || nFrame
>= m_APEFileInfo
.nTotalFrames
)
231 nRetVal
= m_APEFileInfo
.spSeekBitTable
[nFrame
];
235 case APE_INFO_SEEK_BYTE
:
237 int nFrame
= nParam1
;
238 if (nFrame
< 0 || nFrame
>= m_APEFileInfo
.nTotalFrames
)
241 nRetVal
= m_APEFileInfo
.spSeekByteTable
[nFrame
] + m_APEFileInfo
.nJunkHeaderBytes
;
244 case APE_INFO_WAV_HEADER_DATA
:
246 char * pBuffer
= (char *) nParam1
;
247 int nMaxBytes
= nParam2
;
249 if (m_APEFileInfo
.nFormatFlags
& MAC_FORMAT_FLAG_CREATE_WAV_HEADER
)
251 if (sizeof(WAVE_HEADER
) > static_cast<uint32
>(nMaxBytes
))
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
));
266 if (m_APEFileInfo
.nWAVHeaderBytes
> nMaxBytes
)
272 memcpy(pBuffer
, m_APEFileInfo
.spWaveHeaderData
, m_APEFileInfo
.nWAVHeaderBytes
);
278 case APE_INFO_WAV_TERMINATING_DATA
:
280 char * pBuffer
= (char *) nParam1
;
281 int nMaxBytes
= nParam2
;
283 if (m_APEFileInfo
.nWAVTerminatingBytes
> nMaxBytes
)
289 if (m_APEFileInfo
.nWAVTerminatingBytes
> 0)
292 int nOriginalFileLocation
= m_spIO
->GetPosition();
293 unsigned int nBytesRead
= 0;
296 m_spIO
->Seek(-(m_spAPETag
->GetTagBytes() + m_APEFileInfo
.nWAVTerminatingBytes
), FILE_END
);
297 m_spIO
->Read(pBuffer
, m_APEFileInfo
.nWAVTerminatingBytes
, &nBytesRead
);
299 // restore the file pointer
300 m_spIO
->Seek(nOriginalFileLocation
, FILE_BEGIN
);
306 case APE_INFO_WAVEFORMATEX
:
308 WAVEFORMATEX
* pWaveFormatEx
= (WAVEFORMATEX
*) nParam1
;
309 FillWaveFormatEx(pWaveFormatEx
, m_APEFileInfo
.nSampleRate
, m_APEFileInfo
.nBitsPerSample
, m_APEFileInfo
.nChannels
);
313 case APE_INFO_IO_SOURCE
:
314 nRetVal
= (int) m_spIO
.GetPtr();
316 case APE_INFO_FRAME_BYTES
:
318 int nFrame
= nParam1
;
320 // bound-check the frame index
321 if ((nFrame
< 0) || (nFrame
>= m_APEFileInfo
.nTotalFrames
))
327 if (nFrame
!= (m_APEFileInfo
.nTotalFrames
- 1))
328 nRetVal
= GetInfo(APE_INFO_SEEK_BYTE
, nFrame
+ 1) - GetInfo(APE_INFO_SEEK_BYTE
, nFrame
);
330 nRetVal
= m_spIO
->GetSize() - m_spAPETag
->GetTagBytes() - m_APEFileInfo
.nWAVTerminatingBytes
- GetInfo(APE_INFO_SEEK_BYTE
, nFrame
);
334 case APE_INFO_FRAME_BLOCKS
:
336 int nFrame
= nParam1
;
338 // bound-check the frame index
339 if ((nFrame
< 0) || (nFrame
>= m_APEFileInfo
.nTotalFrames
))
345 if (nFrame
!= (m_APEFileInfo
.nTotalFrames
- 1))
346 nRetVal
= m_APEFileInfo
.nBlocksPerFrame
;
348 nRetVal
= m_APEFileInfo
.nFinalFrameBlocks
;
353 nRetVal
= (int) m_spAPETag
.GetPtr();
355 case APE_INTERNAL_INFO
:
356 nRetVal
= (int) &m_APEFileInfo
;