1 //------------------------------------------------------------------------
2 // Project     : SDK Base
3 // Version     : 1.0
4 //
5 // Category    : Helpers
6 // Filename    : base/source/fbuffer.cpp
7 // Created by  : Steinberg, 2008
8 // Description :
9 //
10 //-----------------------------------------------------------------------------
11 // LICENSE
12 // (c) 2019, Steinberg Media Technologies GmbH, All Rights Reserved
13 //-----------------------------------------------------------------------------
14 // Redistribution and use in source and binary forms, with or without modification,
15 // are permitted provided that the following conditions are met:
16 //
17 //   * Redistributions of source code must retain the above copyright notice,
18 //     this list of conditions and the following disclaimer.
19 //   * Redistributions in binary form must reproduce the above copyright notice,
20 //     this list of conditions and the following disclaimer in the documentation
21 //     and/or other materials provided with the distribution.
22 //   * Neither the name of the Steinberg Media Technologies nor the names of its
23 //     contributors may be used to endorse or promote products derived from this
24 //     software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
27 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
34 // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
35 // OF THE POSSIBILITY OF SUCH DAMAGE.
36 //-----------------------------------------------------------------------------
37 
38 #include "base/source/fbuffer.h"
39 #include "base/source/fstring.h"
40 #include <stdlib.h>
41 
42 namespace Steinberg {
43 
44 //-------------------------------------------------------------------------------------
Buffer()45 Buffer::Buffer ()
46 : buffer (nullptr)
47 , memSize (0)
48 , fillSize (0)
49 , delta (defaultDelta)
50 {}
51 
52 //-------------------------------------------------------------------------------------
Buffer(uint32 s,uint8 initVal)53 Buffer::Buffer (uint32 s, uint8 initVal)
54 : buffer (nullptr)
55 , memSize (s)
56 , fillSize (0)
57 , delta (defaultDelta)
58 {
59  	if (memSize == 0)
60 		return;
61 	buffer = (int8*)::malloc (memSize);
62 	if (buffer)
63 		memset (buffer, initVal, memSize);
64 	else
65 		memSize = 0;
66 }
67 
68 //-------------------------------------------------------------------------------------
Buffer(uint32 s)69 Buffer::Buffer (uint32 s)
70 : buffer (nullptr)
71 , memSize (s)
72 , fillSize (0)
73 , delta (defaultDelta)
74 {
75  	if (memSize == 0)
76 		return;
77  	buffer = (int8*)::malloc (memSize);
78 	if (!buffer)
79 		memSize = 0;
80 }
81 
82 //-------------------------------------------------------------------------------------
Buffer(const void * b,uint32 s)83 Buffer::Buffer (const void* b , uint32 s)
84 : buffer (nullptr)
85 , memSize (s)
86 , fillSize (s)
87 , delta (defaultDelta)
88 {
89  	if (memSize == 0)
90 		return;
91  	buffer = (int8*)::malloc (memSize);
92  	if (buffer)
93 		memcpy (buffer, b, memSize);
94 	else
95 	{
96 		memSize = 0;
97 		fillSize = 0;
98 	}
99 }
100 
101 //-------------------------------------------------------------------------------------
Buffer(const Buffer & bufferR)102 Buffer::Buffer (const Buffer& bufferR)
103 : buffer (nullptr)
104 , memSize (bufferR.memSize)
105 , fillSize (bufferR.fillSize)
106 , delta (bufferR.delta)
107 {
108  	if (memSize == 0)
109 		return;
110 
111  	buffer = (int8*)::malloc (memSize);
112  	if (buffer)
113 		memcpy (buffer, bufferR.buffer, memSize);
114 	else
115 		memSize = 0;
116 }
117 
118 //-------------------------------------------------------------------------------------
~Buffer()119 Buffer::~Buffer ()
120 {
121  	if (buffer)
122 		::free (buffer);
123  	buffer = nullptr;
124 }
125 
126 //-------------------------------------------------------------------------------------
operator =(const Buffer & b2)127 void Buffer::operator = (const Buffer& b2)
128 {
129  	if (&b2 != this)
130 	{
131 		setSize (b2.memSize);
132 		if (b2.memSize > 0 && buffer)
133 			memcpy (buffer, b2.buffer, b2.memSize);
134 		fillSize = b2.fillSize;
135 		delta = b2.delta;
136  	}
137 }
138 
139 //-------------------------------------------------------------------------------------
operator ==(const Buffer & b2) const140 bool Buffer::operator == (const Buffer& b2)const
141 {
142 	if (&b2 == this)
143 		return true;
144 	if (b2.getSize () != getSize ())
145 		return false;
146 	return memcmp (this->int8Ptr (), b2.int8Ptr (), getSize ()) == 0 ? true : false;
147 }
148 
149 //-------------------------------------------------------------------------------------
get(void * b,uint32 size)150 uint32 Buffer::get (void* b, uint32 size)
151 {
152 	uint32 maxGet = memSize - fillSize;
153 	if (size > maxGet)
154 		size = maxGet;
155 	if (size > 0)
156 		memcpy (b, buffer + fillSize, size);
157 	fillSize += size;
158 	return size;
159 }
160 
161 //-------------------------------------------------------------------------------------
put(char16 c)162 bool Buffer::put (char16 c)
163 {
164 	return put ((const void*)&c, sizeof (c));
165 }
166 
167 //-------------------------------------------------------------------------------------
put(uint8 byte)168 bool Buffer::put (uint8 byte)
169 {
170 	if (grow (fillSize + 1) == false)
171 		return false;
172 
173   	buffer [fillSize++] = byte;
174   	return true;
175 }
176 
177 //-------------------------------------------------------------------------------------
put(char c)178 bool Buffer::put (char c)
179 {
180 	if (grow (fillSize + 1) == false)
181 		return false;
182 
183   	buffer [fillSize++] = c;
184   	return true;
185 }
186 
187 //-------------------------------------------------------------------------------------
put(const void * toPut,uint32 s)188 bool Buffer::put (const void* toPut, uint32 s)
189 {
190 	if (!toPut)
191 		return false;
192 
193 	if (grow (fillSize + s) == false)
194 		return false;
195 
196 	memcpy (buffer + fillSize, toPut, s);
197 	fillSize += s;
198 	return true;
199 }
200 
201 //-------------------------------------------------------------------------------------
put(const String & str)202 bool Buffer::put (const String& str)
203 {
204 	return put ((const void*)str.text () , (str.length () + 1) * sizeof (tchar));
205 }
206 
207 //-------------------------------------------------------------------------------------
appendString8(const char8 * s)208 bool Buffer::appendString8 (const char8* s)
209 {
210 	if (!s)
211 		return false;
212 
213 	uint32 len = (uint32) strlen (s);
214 	return put (s, len);
215 }
216 
217 //-------------------------------------------------------------------------------------
appendString16(const char16 * s)218 bool Buffer::appendString16 (const char16* s)
219 {
220 	if (!s)
221 		return false;
222 	ConstString str (s);
223 	uint32 len = (uint32) str.length () * sizeof (char16);
224 	return put (s, len);
225 }
226 
227 //-------------------------------------------------------------------------------------
prependString8(const char8 * s)228 bool Buffer::prependString8 (const char8* s)
229 {
230 	if (!s)
231 		return false;
232 
233 	uint32 len = (uint32) strlen (s);
234 
235 	if (len > 0)
236 	{
237 		shiftStart (len);
238 		memcpy (buffer, s, len);
239 		return true;
240 	}
241 	return false;
242 }
243 
244 //-------------------------------------------------------------------------------------
prependString16(const char16 * s)245 bool Buffer::prependString16 (const char16* s)
246 {
247 	if (!s)
248 		return false;
249 
250 	ConstString str (s);
251 	uint32 len = (uint32) str.length () * sizeof (char16);
252 
253 	if (len > 0)
254 	{
255 		shiftStart (len);
256 		memcpy (buffer, s, len);
257 		return true;
258 	}
259 	return false;
260 }
261 
262 //-------------------------------------------------------------------------------------
prependString8(char8 c)263 bool Buffer::prependString8 (char8 c)
264 {
265 	shiftStart (sizeof (char));
266 	char* b = (char*)buffer;
267 	b [0] = c;
268 	return true;
269 }
270 
271 //-------------------------------------------------------------------------------------
prependString16(char16 c)272 bool Buffer::prependString16 (char16 c)
273 {
274 	shiftStart (sizeof (char16));
275 	char16* b = (char16*)buffer;
276 	b [0] = c;
277 	return true;
278 }
279 
280 //-------------------------------------------------------------------------------------
copy(uint32 from,uint32 to,uint32 bytes)281 bool Buffer::copy (uint32 from, uint32 to, uint32 bytes)
282 {
283 	if (from + bytes > memSize || bytes == 0)
284 		return false;
285 
286 	if (to + bytes > memSize)
287 		setSize (to + bytes);
288 
289 	if (from + bytes > to && from < to)
290 	{              // overlap
291 		Buffer tmp (buffer + from, bytes);
292 		memcpy (buffer + to, tmp, bytes);
293 	}
294 	else
295 		memcpy (buffer + to, buffer + from, bytes);
296 	return true;
297 }
298 
299 //-------------------------------------------------------------------------------------
makeHexString(String & result)300 bool Buffer::makeHexString (String& result)
301 {
302 	unsigned char* data = uint8Ptr ();
303 	uint32 bytes = getSize ();
304 
305 	if (data == nullptr || bytes == 0)
306 		return false;
307 
308 	char8* stringBuffer = (char8*)malloc ((bytes * 2) + 1);
309 	if (!stringBuffer)
310 		return false;
311 
312 	int32 count = 0;
313 	while (bytes > 0)
314 	{
315 		unsigned char t1 = ((*data) >> 4) & 0x0F;
316 		unsigned char t2 = (*data) & 0x0F;
317 		if (t1 < 10)
318 			t1 += '0';
319 		else
320 			t1 = t1 - 10 + 'A';
321 		if (t2 < 10)
322 			t2 += '0';
323 		else
324 			t2 = t2 - 10 + 'A';
325 
326 		stringBuffer [count++] = t1;
327 		stringBuffer [count++] = t2;
328 		data++;
329 		bytes--;
330 	}
331 	stringBuffer [count] = 0;
332 
333 	result.take ((void*)stringBuffer, false);
334 	return true;
335 }
336 
337 //-------------------------------------------------------------------------------------
fromHexString(const char8 * string)338 bool Buffer::fromHexString (const char8* string)
339 {
340 	flush ();
341 	if (string == nullptr)
342 		return false;
343 
344 	int32 len = strlen8 (string);
345 	if (len == 0 || ((len & 1) == 1)/*odd number*/ )
346 		return false;
347 
348 	setSize (len / 2);
349 	unsigned char* data = uint8Ptr ();
350 
351 	bool upper = true;
352 	int32 count = 0;
353 	while (count < len)
354 	{
355 		char c = string [count];
356 
357 		unsigned char d = 0;
358 		if (c >= '0' && c <= '9')		d += c - '0';
359 		else if (c >= 'A' && c <= 'F')	d += c - 'A' + 10;
360 		else if (c >= 'a' && c <= 'f')	d += c - 'a' + 10;
361 		else return false; // no hex string
362 
363 		if (upper)
364 			data [count >> 1] = d << 4;
365 		else
366 			data [count >> 1] += d;
367 
368 		upper = !upper;
369 		count++;
370 	}
371 	setFillSize (len / 2);
372 	return true;
373 }
374 
375 //------------------------------------------------------------------------
set(uint8 value)376 void Buffer::set (uint8 value)
377 {
378 	if (buffer)
379 		memset (buffer, value, memSize);
380 }
381 
382 //-------------------------------------------------------------------------------------
setFillSize(uint32 c)383 bool Buffer::setFillSize (uint32 c)
384 {
385 	if (c <= memSize)
386 	{
387 		fillSize = c;
388 		return true;
389 	}
390 	return false;
391 }
392 
393 //-------------------------------------------------------------------------------------
truncateToFillSize()394 bool Buffer::truncateToFillSize ()
395 {
396 	if (fillSize < memSize)
397 		setSize (fillSize);
398 
399 	return true;
400 }
401 
402 //-------------------------------------------------------------------------------------
grow(uint32 newSize)403 bool Buffer::grow (uint32 newSize)
404 {
405 	if (newSize > memSize)
406 	{
407 		if (delta == 0)
408 			delta = defaultDelta;
409 		uint32 s = ((newSize + delta - 1) / delta) * delta;
410 		return setSize (s);
411 	}
412 	return true;
413 }
414 
415 //------------------------------------------------------------------------
shiftAt(uint32 position,int32 amount)416 void Buffer::shiftAt (uint32 position, int32 amount)
417 {
418 	if (amount > 0)
419 	{
420 		if (grow (fillSize + amount))
421 		{
422 			if (position < fillSize)
423 				memmove (buffer + amount + position, buffer + position, fillSize - position);
424 
425 			fillSize += amount;
426 		}
427 	}
428 	else if (amount < 0 && fillSize > 0)
429 	{
430 		uint32 toRemove = -amount;
431 
432 		if (toRemove < fillSize)
433 		{
434 			if (position < fillSize)
435 				memmove (buffer + position, buffer + toRemove + position, fillSize - position - toRemove);
436 			fillSize -= toRemove;
437 		}
438 	}
439 }
440 
441 //-------------------------------------------------------------------------------------
move(int32 amount,uint8 initVal)442 void Buffer::move (int32 amount, uint8 initVal)
443 {
444 	if (memSize == 0)
445 		return;
446 
447 	if (amount > 0)
448 	{
449 		if ((uint32)amount < memSize)
450 		{
451 			memmove (buffer + amount, buffer, memSize - amount);
452 			memset (buffer, initVal, amount);
453 		}
454 		else
455 			memset (buffer, initVal, memSize);
456 	}
457 	else
458 	{
459 		uint32 toRemove = -amount;
460 		if (toRemove < memSize)
461 		{
462 			memmove (buffer, buffer + toRemove, memSize - toRemove);
463 			memset (buffer + memSize - toRemove, initVal, toRemove);
464 		}
465 		else
466 			memset (buffer, initVal, memSize);
467 	}
468 }
469 
470 //-------------------------------------------------------------------------------------
setSize(uint32 newSize)471 bool Buffer::setSize (uint32 newSize)
472 {
473 	if (memSize != newSize)
474 	{
475  		if (buffer)
476 		{
477 			if (newSize > 0)
478 			{
479 				int8* newBuffer = (int8*) ::realloc (buffer, newSize);
480 				if (newBuffer == nullptr)
481 				{
482 					newBuffer = (int8*)::malloc (newSize);
483 					if (newBuffer)
484 					{
485 						uint32 tmp = newSize;
486 						if (tmp > memSize)
487 							tmp = memSize;
488 						memcpy (newBuffer, buffer, tmp);
489 						::free (buffer);
490 						buffer = newBuffer;
491 					}
492 					else
493 					{
494 						::free (buffer);
495 						buffer = nullptr;
496 					}
497 				}
498 				else
499 					buffer = newBuffer;
500 			}
501 			else
502 			{
503 				::free (buffer);
504 				buffer = nullptr;
505 			}
506 		}
507 		else
508 			buffer = (int8*)::malloc (newSize);
509 
510 		if (newSize > 0 && !buffer)
511 			memSize = 0;
512 		else
513 			memSize = newSize;
514 		if (fillSize > memSize)
515 			fillSize = memSize;
516 	}
517 
518 	return (newSize > 0) == (buffer != nullptr);
519 }
520 
521 //-------------------------------------------------------------------------------------
fillup(uint8 value)522 void Buffer::fillup (uint8 value)
523 {
524 	if (getFree () > 0)
525 		memset (buffer + fillSize, value, getFree ());
526 }
527 
528 //-------------------------------------------------------------------------------------
operator +(uint32 i)529 int8* Buffer::operator + (uint32 i)
530 {
531 	if (i < memSize)
532 		return buffer + i;
533 	else
534 	{
535 		static int8 eof;
536 		eof = 0;
537 		return &eof;
538 	}
539 }
540 
541 //-------------------------------------------------------------------------------------
swap(int16 swapSize)542 bool Buffer::swap (int16 swapSize)
543 {
544 	return swap (buffer, memSize, swapSize);
545 }
546 
547 //-------------------------------------------------------------------------------------
swap(void * buffer,uint32 bufferSize,int16 swapSize)548 bool Buffer::swap (void* buffer, uint32 bufferSize, int16 swapSize)
549 {
550 	if (swapSize != kSwap16 && swapSize != kSwap32 && swapSize != kSwap64)
551 		return false;
552 
553 	if (swapSize == kSwap16)
554 	{
555 		for (uint32 count = 0 ; count < bufferSize ; count += 2)
556 		{
557 			SWAP_16 ( * (((int16*)buffer) + count) );
558 		}
559 	}
560 	else if (swapSize == kSwap32)
561 	{
562 		for (uint32 count = 0 ; count < bufferSize ; count += 4)
563 		{
564 			SWAP_32 ( * (((int32*)buffer) + count) );
565 		}
566 	}
567 	else if (swapSize == kSwap64)
568 	{
569 		for (uint32 count = 0 ; count < bufferSize ; count += 8)
570 		{
571 			SWAP_64 ( * (((int64*)buffer) + count) );
572 		}
573 	}
574 
575 	return true;
576 }
577 
578 //-------------------------------------------------------------------------------------
take(Buffer & from)579 void Buffer::take (Buffer& from)
580 {
581 	setSize (0);
582 	memSize = from.memSize;
583 	fillSize = from.fillSize;
584 	buffer = from.buffer;
585 	from.buffer = nullptr;
586 	from.memSize = 0;
587 	from.fillSize = 0;
588 }
589 
590 //-------------------------------------------------------------------------------------
pass()591 int8* Buffer::pass ()
592 {
593 	int8* res = buffer;
594 	buffer = nullptr;
595 	memSize = 0;
596 	fillSize = 0;
597 	return res;
598 }
599 
600 //-------------------------------------------------------------------------------------
toWideString(int32 sourceCodePage)601 bool Buffer::toWideString (int32 sourceCodePage)
602 {
603 	if (getFillSize () > 0)
604 	{
605 		if (str8 () [getFillSize () - 1] != 0) // multiByteToWideString only works with 0-terminated strings
606 			endString8 ();
607 
608 		Buffer dest (getFillSize () * sizeof (char16));
609 		int32 result = String::multiByteToWideString (dest.str16 (), buffer, dest.getFree () / sizeof (char16), sourceCodePage);
610 		if (result > 0)
611 		{
612 			dest.setFillSize ((result - 1) * sizeof (char16));
613 			take (dest);
614 			return true;
615 		}
616 		return false;
617 	}
618 	return true;
619 }
620 
621 //-------------------------------------------------------------------------------------
toMultibyteString(int32 destCodePage)622 bool Buffer::toMultibyteString (int32 destCodePage)
623 {
624 	if (getFillSize () > 0)
625 	{
626 		int32 textLength = getFillSize () / sizeof (char16); // wideStringToMultiByte only works with 0-terminated strings
627 		if (str16 () [textLength - 1] != 0)
628 			endString16 ();
629 
630 		Buffer dest (getFillSize ());
631 		int32 result = String::wideStringToMultiByte (dest.str8 (), str16 (), dest.getFree (), destCodePage);
632 		if (result > 0)
633 		{
634 			dest.setFillSize (result - 1);
635 			take (dest);
636 			return true;
637 		}
638 		return false;
639 	}
640 	return true;
641 }
642 
643 //------------------------------------------------------------------------
644 } // namespace Steinberg
645