vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / media / plugins / ape_reader / MAClib / APECompress.cpp
blob6dfe0e5e294e6dfdd1467890797f18ef1e2adc09
1 #include "All.h"
2 #include "APECompress.h"
3 #include IO_HEADER_FILE
4 #include "APECompressCreate.h"
5 #include "WAVInputSource.h"
7 CAPECompress::CAPECompress()
9 m_nBufferHead = 0;
10 m_nBufferTail = 0;
11 m_nBufferSize = 0;
12 m_bBufferLocked = FALSE;
13 m_bOwnsOutputIO = FALSE;
14 m_pioOutput = NULL;
16 m_spAPECompressCreate.Assign(new CAPECompressCreate());
18 m_pBuffer = NULL;
21 CAPECompress::~CAPECompress()
23 SAFE_ARRAY_DELETE(m_pBuffer)
25 if (m_bOwnsOutputIO)
27 SAFE_DELETE(m_pioOutput)
31 int CAPECompress::Start(const wchar_t * pOutputFilename, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel, const void * pHeaderData, int nHeaderBytes)
33 m_pioOutput = new IO_CLASS_NAME;
34 m_bOwnsOutputIO = TRUE;
36 if (m_pioOutput->Create(pOutputFilename) != 0)
38 return ERROR_INVALID_OUTPUT_FILE;
41 m_spAPECompressCreate->Start(m_pioOutput, pwfeInput, nMaxAudioBytes, nCompressionLevel,
42 pHeaderData, nHeaderBytes);
44 SAFE_ARRAY_DELETE(m_pBuffer)
45 m_nBufferSize = m_spAPECompressCreate->GetFullFrameBytes();
46 m_pBuffer = new unsigned char [m_nBufferSize];
47 memcpy(&m_wfeInput, pwfeInput, sizeof(WAVEFORMATEX));
49 return ERROR_SUCCESS;
52 int CAPECompress::StartEx(CIO * pioOutput, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel, const void * pHeaderData, int nHeaderBytes)
54 m_pioOutput = pioOutput;
55 m_bOwnsOutputIO = FALSE;
57 m_spAPECompressCreate->Start(m_pioOutput, pwfeInput, nMaxAudioBytes, nCompressionLevel,
58 pHeaderData, nHeaderBytes);
60 SAFE_ARRAY_DELETE(m_pBuffer)
61 m_nBufferSize = m_spAPECompressCreate->GetFullFrameBytes();
62 m_pBuffer = new unsigned char [m_nBufferSize];
63 memcpy(&m_wfeInput, pwfeInput, sizeof(WAVEFORMATEX));
65 return ERROR_SUCCESS;
68 int CAPECompress::GetBufferBytesAvailable()
70 return m_nBufferSize - m_nBufferTail;
73 int CAPECompress::UnlockBuffer(int nBytesAdded, BOOL bProcess)
75 if (m_bBufferLocked == FALSE)
76 return ERROR_UNDEFINED;
78 m_nBufferTail += nBytesAdded;
79 m_bBufferLocked = FALSE;
81 if (bProcess)
83 int nRetVal = ProcessBuffer();
84 if (nRetVal != 0) { return nRetVal; }
87 return ERROR_SUCCESS;
90 unsigned char * CAPECompress::LockBuffer(int * pBytesAvailable)
92 if (m_pBuffer == NULL) { return NULL; }
94 if (m_bBufferLocked)
95 return NULL;
97 m_bBufferLocked = TRUE;
99 if (pBytesAvailable)
100 *pBytesAvailable = GetBufferBytesAvailable();
102 return &m_pBuffer[m_nBufferTail];
105 int CAPECompress::AddData(unsigned char * pData, int nBytes)
107 if (m_pBuffer == NULL) return ERROR_INSUFFICIENT_MEMORY;
109 int nBytesDone = 0;
111 while (nBytesDone < nBytes)
113 // lock the buffer
114 int nBytesAvailable = 0;
115 unsigned char * pBuffer = LockBuffer(&nBytesAvailable);
116 if (pBuffer == NULL || nBytesAvailable <= 0)
117 return ERROR_UNDEFINED;
119 // calculate how many bytes to copy and add that much to the buffer
120 int nBytesToProcess = min(nBytesAvailable, nBytes - nBytesDone);
121 memcpy(pBuffer, &pData[nBytesDone], nBytesToProcess);
123 // unlock the buffer (fail if not successful)
124 int nRetVal = UnlockBuffer(nBytesToProcess);
125 if (nRetVal != ERROR_SUCCESS)
126 return nRetVal;
128 // update our progress
129 nBytesDone += nBytesToProcess;
132 return ERROR_SUCCESS;
135 int CAPECompress::Finish(unsigned char * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes)
137 RETURN_ON_ERROR(ProcessBuffer(TRUE))
138 return m_spAPECompressCreate->Finish(pTerminatingData, nTerminatingBytes, nWAVTerminatingBytes);
141 int CAPECompress::Kill()
143 return ERROR_SUCCESS;
146 int CAPECompress::ProcessBuffer(BOOL bFinalize)
148 if (m_pBuffer == NULL) { return ERROR_UNDEFINED; }
152 // process as much as possible
153 int nThreshold = (bFinalize) ? 0 : m_spAPECompressCreate->GetFullFrameBytes();
155 while ((m_nBufferTail - m_nBufferHead) >= nThreshold)
157 int nFrameBytes = min(m_spAPECompressCreate->GetFullFrameBytes(), m_nBufferTail - m_nBufferHead);
159 if (nFrameBytes == 0)
160 break;
162 int nRetVal = m_spAPECompressCreate->EncodeFrame(&m_pBuffer[m_nBufferHead], nFrameBytes);
163 if (nRetVal != 0) { return nRetVal; }
165 m_nBufferHead += nFrameBytes;
168 // shift the buffer
169 if (m_nBufferHead != 0)
171 int nBytesLeft = m_nBufferTail - m_nBufferHead;
173 if (nBytesLeft != 0)
174 memmove(m_pBuffer, &m_pBuffer[m_nBufferHead], nBytesLeft);
176 m_nBufferTail -= m_nBufferHead;
177 m_nBufferHead = 0;
180 catch(...)
182 return ERROR_UNDEFINED;
185 return ERROR_SUCCESS;
188 int CAPECompress::AddDataFromInputSource(CInputSource * pInputSource, int nMaxBytes, int * pBytesAdded)
190 // error check the parameters
191 if (pInputSource == NULL) return ERROR_BAD_PARAMETER;
193 // initialize
194 if (pBytesAdded) *pBytesAdded = 0;
196 // lock the buffer
197 int nBytesAvailable = 0;
198 unsigned char * pBuffer = LockBuffer(&nBytesAvailable);
199 if ((pBuffer == NULL) || (nBytesAvailable == 0))
200 return ERROR_INSUFFICIENT_MEMORY;
202 // calculate the 'ideal' number of bytes
203 unsigned int nBytesRead = 0;
205 int nIdealBytes = m_spAPECompressCreate->GetFullFrameBytes() - (m_nBufferTail - m_nBufferHead);
206 if (nIdealBytes > 0)
208 // get the data
209 int nBytesToAdd = nBytesAvailable;
211 if (nMaxBytes > 0)
213 if (nBytesToAdd > nMaxBytes) nBytesToAdd = nMaxBytes;
216 if (nBytesToAdd > nIdealBytes) nBytesToAdd = nIdealBytes;
218 // always make requests along block boundaries
219 while ((nBytesToAdd % m_wfeInput.nBlockAlign) != 0)
220 nBytesToAdd--;
222 int nBlocksToAdd = nBytesToAdd / m_wfeInput.nBlockAlign;
224 // get data
225 int nBlocksAdded = 0;
226 int nRetVal = pInputSource->GetData(pBuffer, nBlocksToAdd, &nBlocksAdded);
227 if (nRetVal != 0)
228 return ERROR_IO_READ;
229 else
230 nBytesRead = (nBlocksAdded * m_wfeInput.nBlockAlign);
232 // store the bytes read
233 if (pBytesAdded)
234 *pBytesAdded = nBytesRead;
237 // unlock the data and process
238 int nRetVal = UnlockBuffer(nBytesRead, TRUE);
239 if (nRetVal != 0)
241 return nRetVal;
244 return ERROR_SUCCESS;