vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / media / plugins / ape_reader / MAClib / APEInfo.cpp
blob4e54964711f8a71652ccbc311c4c2843ab29a699
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"
11 /*****************************************************************************************
12 Construction
13 *****************************************************************************************/
14 CAPEInfo::CAPEInfo(int * pErrorCode, const wchar_t * pFilename, CAPETag * pTag)
16 *pErrorCode = ERROR_SUCCESS;
17 CloseFile();
19 // open the file
20 m_spIO.Assign(new IO_CLASS_NAME);
22 if (m_spIO->Open(pFilename) != 0)
24 CloseFile();
25 *pErrorCode = ERROR_INVALID_INPUT_FILE;
26 return;
29 // get the file information
30 if (GetFileInformation(TRUE) != 0)
32 CloseFile();
33 *pErrorCode = ERROR_INVALID_INPUT_FILE;
34 return;
37 // get the tag (do this second so that we don't do it on failure)
38 if (pTag == NULL)
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;
46 m_spAPETag.Assign(new CAPETag(m_spIO, bAnalyzeNow));
48 else
50 m_spAPETag.Assign(pTag);
55 CAPEInfo::CAPEInfo(int * pErrorCode, CIO * pIO, CAPETag * pTag)
57 *pErrorCode = ERROR_SUCCESS;
58 CloseFile();
60 m_spIO.Assign(pIO, FALSE, FALSE);
62 // get the file information
63 if (GetFileInformation(TRUE) != 0)
65 CloseFile();
66 *pErrorCode = ERROR_INVALID_INPUT_FILE;
67 return;
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);
78 /*****************************************************************************************
79 Destruction
80 *****************************************************************************************/
81 CAPEInfo::~CAPEInfo()
83 CloseFile();
86 /*****************************************************************************************
87 Close the file
88 *****************************************************************************************/
89 int CAPEInfo::CloseFile()
91 m_spIO.Delete();
92 m_APEFileInfo.spWaveHeaderData.Delete();
93 m_APEFileInfo.spSeekBitTable.Delete();
94 m_APEFileInfo.spSeekByteTable.Delete();
95 m_APEFileInfo.spAPEDescriptor.Delete();
97 m_spAPETag.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;
125 // return
126 return nRetVal;
129 /*****************************************************************************************
130 Primary query function
131 *****************************************************************************************/
132 int CAPEInfo::GetInfo(APE_DECOMPRESS_FIELDS Field, int nParam1, int nParam2)
134 int nRetVal = -1;
136 switch (Field)
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:
197 int nFrame = nParam1;
199 nRetVal = 0;
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;
206 if (nFrameMS != 0)
208 nRetVal = (nFrameBytes * 8) / nFrameMS;
211 break;
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:
221 int nFrame = nParam1;
222 if (GET_FRAMES_START_ON_BYTES_BOUNDARIES(this))
224 nRetVal = 0;
226 else
228 if (nFrame < 0 || nFrame >= m_APEFileInfo.nTotalFrames)
229 nRetVal = 0;
230 else
231 nRetVal = m_APEFileInfo.spSeekBitTable[nFrame];
233 break;
235 case APE_INFO_SEEK_BYTE:
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;
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))
253 nRetVal = -1;
255 else
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;
264 else
266 if (m_APEFileInfo.nWAVHeaderBytes > nMaxBytes)
268 nRetVal = -1;
270 else
272 memcpy(pBuffer, m_APEFileInfo.spWaveHeaderData, m_APEFileInfo.nWAVHeaderBytes);
273 nRetVal = 0;
276 break;
278 case APE_INFO_WAV_TERMINATING_DATA:
280 char * pBuffer = (char *) nParam1;
281 int nMaxBytes = nParam2;
283 if (m_APEFileInfo.nWAVTerminatingBytes > nMaxBytes)
285 nRetVal = -1;
287 else
289 if (m_APEFileInfo.nWAVTerminatingBytes > 0)
291 // variables
292 int nOriginalFileLocation = m_spIO->GetPosition();
293 unsigned int nBytesRead = 0;
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);
299 // restore the file pointer
300 m_spIO->Seek(nOriginalFileLocation, FILE_BEGIN);
302 nRetVal = 0;
304 break;
306 case APE_INFO_WAVEFORMATEX:
308 WAVEFORMATEX * pWaveFormatEx = (WAVEFORMATEX *) nParam1;
309 FillWaveFormatEx(pWaveFormatEx, m_APEFileInfo.nSampleRate, m_APEFileInfo.nBitsPerSample, m_APEFileInfo.nChannels);
310 nRetVal = 0;
311 break;
313 case APE_INFO_IO_SOURCE:
314 nRetVal = (int) m_spIO.GetPtr();
315 break;
316 case APE_INFO_FRAME_BYTES:
318 int nFrame = nParam1;
320 // bound-check the frame index
321 if ((nFrame < 0) || (nFrame >= m_APEFileInfo.nTotalFrames))
323 nRetVal = -1;
325 else
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);
332 break;
334 case APE_INFO_FRAME_BLOCKS:
336 int nFrame = nParam1;
338 // bound-check the frame index
339 if ((nFrame < 0) || (nFrame >= m_APEFileInfo.nTotalFrames))
341 nRetVal = -1;
343 else
345 if (nFrame != (m_APEFileInfo.nTotalFrames - 1))
346 nRetVal = m_APEFileInfo.nBlocksPerFrame;
347 else
348 nRetVal = m_APEFileInfo.nFinalFrameBlocks;
350 break;
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;
362 return nRetVal;