Audacity 3.2.0
src/effects/VST3/memorystream.cpp
Go to the documentation of this file.
1//-----------------------------------------------------------------------------
2// Project : SDK Core
3//
4// Category : Common Classes
5// Filename : public.sdk/source/common/memorystream.cpp
6// Created by : Steinberg, 03/2008
7// Description : IBStream Implementation for memory blocks
8//
9//-----------------------------------------------------------------------------
10// LICENSE
11// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved
12//-----------------------------------------------------------------------------
13// Redistribution and use in source and binary forms, with or without modification,
14// are permitted provided that the following conditions are met:
15//
16// * Redistributions of source code must retain the above copyright notice,
17// this list of conditions and the following disclaimer.
18// * Redistributions in binary form must reproduce the above copyright notice,
19// this list of conditions and the following disclaimer in the documentation
20// and/or other materials provided with the distribution.
21// * Neither the name of the Steinberg Media Technologies nor the names of its
22// contributors may be used to endorse or promote products derived from this
23// software without specific prior written permission.
24//
25// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
26// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
33// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34// OF THE POSSIBILITY OF SUCH DAMAGE.
35//-----------------------------------------------------------------------------
36
37#include "memorystream.h"
38#include "pluginterfaces/base/futils.h"
39#include <stdlib.h>
40
41namespace Steinberg {
42
43//-----------------------------------------------------------------------------
44IMPLEMENT_FUNKNOWN_METHODS (MemoryStream, IBStream, IBStream::iid)
45static const TSize kMemGrowAmount = 4096;
46
47//-----------------------------------------------------------------------------
48MemoryStream::MemoryStream (void* data, TSize length)
49: memory ((char*)data)
50, memorySize (length)
51, size (length)
52, cursor (0)
53, ownMemory (false)
54, allocationError (false)
55{
56 FUNKNOWN_CTOR
57}
58
59//-----------------------------------------------------------------------------
61: memory (nullptr)
62, memorySize (0)
63, size (0)
64, cursor (0)
65, ownMemory (true)
66, allocationError (false)
67{
68 FUNKNOWN_CTOR
69}
70
71//-----------------------------------------------------------------------------
73{
74 if (ownMemory && memory)
75 ::free (memory);
76
77 FUNKNOWN_DTOR
78}
79
80//-----------------------------------------------------------------------------
81tresult PLUGIN_API MemoryStream::read (void* data, int32 numBytes, int32* numBytesRead)
82{
83 if (memory == nullptr)
84 {
86 return kOutOfMemory;
87 numBytes = 0;
88 }
89 else
90 {
91 // Does read exceed size ?
92 if (cursor + numBytes > size)
93 {
94 int32 maxBytes = int32 (size - cursor);
95
96 // Has length become zero or negative ?
97 if (maxBytes <= 0)
98 {
99 cursor = size;
100 numBytes = 0;
101 }
102 else
103 numBytes = maxBytes;
104 }
105
106 if (numBytes)
107 {
108 memcpy (data, &memory[cursor], static_cast<size_t> (numBytes));
109 cursor += numBytes;
110 }
111 }
112
113 if (numBytesRead)
114 *numBytesRead = numBytes;
115
116 return kResultTrue;
117}
118
119//-----------------------------------------------------------------------------
120tresult PLUGIN_API MemoryStream::write (void* buffer, int32 numBytes, int32* numBytesWritten)
121{
122 if (allocationError)
123 return kOutOfMemory;
124 if (buffer == nullptr)
125 return kInvalidArgument;
126
127 // Does write exceed size ?
128 TSize requiredSize = cursor + numBytes;
129 if (requiredSize > size)
130 {
131 if (requiredSize > memorySize)
132 setSize (requiredSize);
133 else
134 size = requiredSize;
135 }
136
137 // Copy data
138 if (memory && cursor >= 0 && numBytes > 0)
139 {
140 memcpy (&memory[cursor], buffer, static_cast<size_t> (numBytes));
141 // Update cursor
142 cursor += numBytes;
143 }
144 else
145 numBytes = 0;
146
147 if (numBytesWritten)
148 *numBytesWritten = numBytes;
149
150 return kResultTrue;
151}
152
153//-----------------------------------------------------------------------------
154tresult PLUGIN_API MemoryStream::seek (int64 pos, int32 mode, int64* result)
155{
156 switch (mode)
157 {
158 case kIBSeekSet:
159 cursor = pos;
160 break;
161 case kIBSeekCur:
162 cursor = cursor + pos;
163 break;
164 case kIBSeekEnd:
165 cursor = size + pos;
166 break;
167 }
168
169 if (ownMemory == false)
170 if (cursor > memorySize)
172
173 if (result)
174 *result = cursor;
175
176 return kResultTrue;
177}
178
179//-----------------------------------------------------------------------------
180tresult PLUGIN_API MemoryStream::tell (int64* pos)
181{
182 if (!pos)
183 return kInvalidArgument;
184
185 *pos = cursor;
186 return kResultTrue;
187}
188
189//------------------------------------------------------------------------
191{
192 return size;
193}
194
195//------------------------------------------------------------------------
197{
198 if (s <= 0)
199 {
200 if (ownMemory && memory)
201 free (memory);
202
203 memory = nullptr;
204 memorySize = 0;
205 size = 0;
206 cursor = 0;
207 return;
208 }
209
210 TSize newMemorySize = (((Max (memorySize, s) - 1) / kMemGrowAmount) + 1) * kMemGrowAmount;
211 if (newMemorySize == memorySize)
212 {
213 size = s;
214 return;
215 }
216
217 if (memory && ownMemory == false)
218 {
219 allocationError = true;
220 return;
221 }
222
223 ownMemory = true;
224 char* newMemory = nullptr;
225
226 if (memory)
227 {
228 newMemory = (char*)realloc (memory, (size_t)newMemorySize);
229 if (newMemory == nullptr && newMemorySize > 0)
230 {
231 newMemory = (char*)malloc ((size_t)newMemorySize);
232 if (newMemory)
233 {
234 memcpy (newMemory, memory, (size_t)Min (newMemorySize, memorySize));
235 free (memory);
236 }
237 }
238 }
239 else
240 newMemory = (char*)malloc ((size_t)newMemorySize);
241
242 if (newMemory == nullptr)
243 {
244 if (newMemorySize > 0)
245 allocationError = true;
246
247 memory = nullptr;
248 memorySize = 0;
249 size = 0;
250 cursor = 0;
251 }
252 else
253 {
254 memory = newMemory;
255 memorySize = newMemorySize;
256 size = s;
257 }
258}
259
260//------------------------------------------------------------------------
262{
263 return memory;
264}
265
266//------------------------------------------------------------------------
268{
269 if (ownMemory)
270 {
271 char* result = memory;
272 memory = nullptr;
273 memorySize = 0;
274 size = 0;
275 cursor = 0;
276 return result;
277 }
278 return nullptr;
279}
280
281//------------------------------------------------------------------------
283{
284 if (ownMemory == false)
285 return false;
286
287 if (memorySize == size)
288 return true;
289
291
292 if (memorySize == 0)
293 {
294 if (memory)
295 {
296 free (memory);
297 memory = nullptr;
298 }
299 }
300 else
301 {
302 if (memory)
303 {
304 char* newMemory = (char*)realloc (memory, (size_t)memorySize);
305 if (newMemory)
306 memory = newMemory;
307 }
308 }
309 return true;
310}
311
312//------------------------------------------------------------------------
314{
315 size = cursor;
316 return truncate ();
317}
318
319} // namespace
IMPLEMENT_FUNKNOWN_METHODS(internal::ConnectionProxy, Steinberg::Vst::IConnectionPoint, Steinberg::Vst::IConnectionPoint::iid)
A low overhead memory stream with O(1) append, low heap fragmentation and a linear memory view.
void setSize(TSize size)
set the memory size, a realloc will occur if memory already used
char * detachData()
returns the memory pointer and give up ownership
tresult PLUGIN_API tell(int64 *pos) SMTG_OVERRIDE
tresult PLUGIN_API read(void *buffer, int32 numBytes, int32 *numBytesRead) SMTG_OVERRIDE
TSize getSize() const
returns the current memory size
char * getData() const
returns the memory pointer
tresult PLUGIN_API seek(int64 pos, int32 mode, int64 *result) SMTG_OVERRIDE
bool truncate()
realloc to the current use memory size if needed
bool truncateToCursor()
truncate memory at current cursor position
tresult PLUGIN_API write(void *buffer, int32 numBytes, int32 *numBytesWritten) SMTG_OVERRIDE
static const TSize kMemGrowAmount