644 lines
15 KiB
C++
644 lines
15 KiB
C++
//------------------------------------------------------------------------
|
|
// Project : SDK Base
|
|
// Version : 1.0
|
|
//
|
|
// Category : Helpers
|
|
// Filename : base/source/fbuffer.cpp
|
|
// Created by : Steinberg, 2008
|
|
// Description :
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
// LICENSE
|
|
// (c) 2018, Steinberg Media Technologies GmbH, All Rights Reserved
|
|
//-----------------------------------------------------------------------------
|
|
// Redistribution and use in source and binary forms, with or without modification,
|
|
// are permitted provided that the following conditions are met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright notice,
|
|
// this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
|
// this list of conditions and the following disclaimer in the documentation
|
|
// and/or other materials provided with the distribution.
|
|
// * Neither the name of the Steinberg Media Technologies nor the names of its
|
|
// contributors may be used to endorse or promote products derived from this
|
|
// software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "base/source/fbuffer.h"
|
|
#include "base/source/fstring.h"
|
|
#include <stdlib.h>
|
|
|
|
namespace Steinberg {
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
Buffer::Buffer ()
|
|
: buffer (0)
|
|
, memSize (0)
|
|
, fillSize (0)
|
|
, delta (defaultDelta)
|
|
{}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
Buffer::Buffer (uint32 s, uint8 initVal)
|
|
: buffer (0)
|
|
, memSize (s)
|
|
, fillSize (0)
|
|
, delta (defaultDelta)
|
|
{
|
|
if (memSize == 0)
|
|
return;
|
|
buffer = (int8*)::malloc (memSize);
|
|
if (buffer)
|
|
memset (buffer, initVal, memSize);
|
|
else
|
|
memSize = 0;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
Buffer::Buffer (uint32 s)
|
|
: buffer (0)
|
|
, memSize (s)
|
|
, fillSize (0)
|
|
, delta (defaultDelta)
|
|
{
|
|
if (memSize == 0)
|
|
return;
|
|
buffer = (int8*)::malloc (memSize);
|
|
if (!buffer)
|
|
memSize = 0;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
Buffer::Buffer (const void* b , uint32 s)
|
|
: buffer (0)
|
|
, memSize (s)
|
|
, fillSize (s)
|
|
, delta (defaultDelta)
|
|
{
|
|
if (memSize == 0)
|
|
return;
|
|
buffer = (int8*)::malloc (memSize);
|
|
if (buffer)
|
|
memcpy (buffer, b, memSize);
|
|
else
|
|
{
|
|
memSize = 0;
|
|
fillSize = 0;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
Buffer::Buffer (const Buffer& bufferR)
|
|
: buffer (0)
|
|
, memSize (bufferR.memSize)
|
|
, fillSize (bufferR.fillSize)
|
|
, delta (bufferR.delta)
|
|
{
|
|
if (memSize == 0)
|
|
return;
|
|
|
|
buffer = (int8*)::malloc (memSize);
|
|
if (buffer)
|
|
memcpy (buffer, bufferR.buffer, memSize);
|
|
else
|
|
memSize = 0;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
Buffer::~Buffer ()
|
|
{
|
|
if (buffer)
|
|
::free (buffer);
|
|
buffer = 0;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
void Buffer::operator = (const Buffer& b2)
|
|
{
|
|
if (&b2 != this)
|
|
{
|
|
setSize (b2.memSize);
|
|
if (b2.memSize > 0 && buffer)
|
|
memcpy (buffer, b2.buffer, b2.memSize);
|
|
fillSize = b2.fillSize;
|
|
delta = b2.delta;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::operator == (const Buffer& b2)const
|
|
{
|
|
if (&b2 == this)
|
|
return true;
|
|
if (b2.getSize () != getSize ())
|
|
return false;
|
|
return memcmp (this->int8Ptr (), b2.int8Ptr (), getSize ()) == 0 ? true : false;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
uint32 Buffer::get (void* b, uint32 size)
|
|
{
|
|
uint32 maxGet = memSize - fillSize;
|
|
if (size > maxGet)
|
|
size = maxGet;
|
|
if (size > 0)
|
|
memcpy (b, buffer + fillSize, size);
|
|
fillSize += size;
|
|
return size;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::put (char16 c)
|
|
{
|
|
return put ((const void*)&c, sizeof (c));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::put (uint8 byte)
|
|
{
|
|
if (grow (fillSize + 1) == false)
|
|
return false;
|
|
|
|
buffer [fillSize++] = byte;
|
|
return true;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::put (char c)
|
|
{
|
|
if (grow (fillSize + 1) == false)
|
|
return false;
|
|
|
|
buffer [fillSize++] = c;
|
|
return true;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::put (const void* toPut, uint32 s)
|
|
{
|
|
if (!toPut)
|
|
return false;
|
|
|
|
if (grow (fillSize + s) == false)
|
|
return false;
|
|
|
|
memcpy (buffer + fillSize, toPut, s);
|
|
fillSize += s;
|
|
return true;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::put (const String& str)
|
|
{
|
|
return put ((const void*)str.text () , (str.length () + 1) * sizeof (tchar));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::appendString8 (const char8* s)
|
|
{
|
|
if (!s)
|
|
return false;
|
|
|
|
uint32 len = (uint32) strlen (s);
|
|
return put (s, len);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::appendString16 (const char16* s)
|
|
{
|
|
if (!s)
|
|
return false;
|
|
ConstString str (s);
|
|
uint32 len = (uint32) str.length () * sizeof (char16);
|
|
return put (s, len);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::prependString8 (const char8* s)
|
|
{
|
|
if (!s)
|
|
return false;
|
|
|
|
uint32 len = (uint32) strlen (s);
|
|
|
|
if (len > 0)
|
|
{
|
|
shiftStart (len);
|
|
memcpy (buffer, s, len);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::prependString16 (const char16* s)
|
|
{
|
|
if (!s)
|
|
return false;
|
|
|
|
ConstString str (s);
|
|
uint32 len = (uint32) str.length () * sizeof (char16);
|
|
|
|
if (len > 0)
|
|
{
|
|
shiftStart (len);
|
|
memcpy (buffer, s, len);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::prependString8 (char8 c)
|
|
{
|
|
shiftStart (sizeof (char));
|
|
char* b = (char*)buffer;
|
|
b [0] = c;
|
|
return true;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::prependString16 (char16 c)
|
|
{
|
|
shiftStart (sizeof (char16));
|
|
char16* b = (char16*)buffer;
|
|
b [0] = c;
|
|
return true;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::copy (uint32 from, uint32 to, uint32 bytes)
|
|
{
|
|
if (from + bytes > memSize || bytes == 0)
|
|
return false;
|
|
|
|
if (to + bytes > memSize)
|
|
setSize (to + bytes);
|
|
|
|
if (from + bytes > to && from < to)
|
|
{ // overlap
|
|
Buffer tmp (buffer + from, bytes);
|
|
memcpy (buffer + to, tmp, bytes);
|
|
}
|
|
else
|
|
memcpy (buffer + to, buffer + from, bytes);
|
|
return true;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::makeHexString (String& result)
|
|
{
|
|
unsigned char* data = uint8Ptr ();
|
|
uint32 bytes = getSize ();
|
|
|
|
if (data == 0 || bytes == 0)
|
|
return false;
|
|
|
|
char8* stringBuffer = (char8*)malloc ((bytes * 2) + 1);
|
|
if (!stringBuffer)
|
|
return false;
|
|
|
|
int32 count = 0;
|
|
while (bytes > 0)
|
|
{
|
|
unsigned char t1 = ((*data) >> 4) & 0x0F;
|
|
unsigned char t2 = (*data) & 0x0F;
|
|
if (t1 < 10)
|
|
t1 += '0';
|
|
else
|
|
t1 = t1 - 10 + 'A';
|
|
if (t2 < 10)
|
|
t2 += '0';
|
|
else
|
|
t2 = t2 - 10 + 'A';
|
|
|
|
stringBuffer [count++] = t1;
|
|
stringBuffer [count++] = t2;
|
|
data++;
|
|
bytes--;
|
|
}
|
|
stringBuffer [count] = 0;
|
|
|
|
result.take ((void*)stringBuffer, false);
|
|
return true;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::fromHexString (const char8* string)
|
|
{
|
|
flush ();
|
|
if (string == 0)
|
|
return false;
|
|
|
|
int32 len = strlen8 (string);
|
|
if (len == 0 || ((len & 1) == 1)/*odd number*/ )
|
|
return false;
|
|
|
|
setSize (len / 2);
|
|
unsigned char* data = uint8Ptr ();
|
|
|
|
bool upper = true;
|
|
int32 count = 0;
|
|
while (count < len)
|
|
{
|
|
char c = string [count];
|
|
|
|
unsigned char d = 0;
|
|
if (c >= '0' && c <= '9') d += c - '0';
|
|
else if (c >= 'A' && c <= 'F') d += c - 'A' + 10;
|
|
else if (c >= 'a' && c <= 'f') d += c - 'a' + 10;
|
|
else return false; // no hex string
|
|
|
|
if (upper)
|
|
data [count >> 1] = d << 4;
|
|
else
|
|
data [count >> 1] += d;
|
|
|
|
upper = !upper;
|
|
count++;
|
|
}
|
|
setFillSize (len / 2);
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void Buffer::set (uint8 value)
|
|
{
|
|
if (buffer)
|
|
memset (buffer, value, memSize);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::setFillSize (uint32 c)
|
|
{
|
|
if (c <= memSize)
|
|
{
|
|
fillSize = c;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::truncateToFillSize ()
|
|
{
|
|
if (fillSize < memSize)
|
|
setSize (fillSize);
|
|
|
|
return true;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::grow (uint32 newSize)
|
|
{
|
|
if (newSize > memSize)
|
|
{
|
|
if (delta == 0)
|
|
delta = defaultDelta;
|
|
uint32 s = ((newSize + delta - 1) / delta) * delta;
|
|
return setSize (s);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void Buffer::shiftAt (uint32 position, int32 amount)
|
|
{
|
|
if (amount > 0)
|
|
{
|
|
if (grow (fillSize + amount))
|
|
{
|
|
if (position < fillSize)
|
|
memmove (buffer + amount + position, buffer + position, fillSize - position);
|
|
|
|
fillSize += amount;
|
|
}
|
|
}
|
|
else if (amount < 0 && fillSize > 0)
|
|
{
|
|
uint32 toRemove = -amount;
|
|
|
|
if (toRemove < fillSize)
|
|
{
|
|
if (position < fillSize)
|
|
memmove (buffer + position, buffer + toRemove + position, fillSize - position - toRemove);
|
|
fillSize -= toRemove;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
void Buffer::move (int32 amount, uint8 initVal)
|
|
{
|
|
if (memSize == 0)
|
|
return;
|
|
|
|
if (amount > 0)
|
|
{
|
|
if ((uint32)amount < memSize)
|
|
{
|
|
memmove (buffer + amount, buffer, memSize - amount);
|
|
memset (buffer, initVal, amount);
|
|
}
|
|
else
|
|
memset (buffer, initVal, memSize);
|
|
}
|
|
else
|
|
{
|
|
uint32 toRemove = -amount;
|
|
if (toRemove < memSize)
|
|
{
|
|
memmove (buffer, buffer + toRemove, memSize - toRemove);
|
|
memset (buffer + memSize - toRemove, initVal, toRemove);
|
|
}
|
|
else
|
|
memset (buffer, initVal, memSize);
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::setSize (uint32 newSize)
|
|
{
|
|
if (memSize != newSize)
|
|
{
|
|
if (buffer)
|
|
{
|
|
if (newSize > 0)
|
|
{
|
|
int8* newBuffer = (int8*) ::realloc (buffer, newSize);
|
|
if (newBuffer == 0)
|
|
{
|
|
newBuffer = (int8*)::malloc (newSize);
|
|
if (newBuffer)
|
|
{
|
|
uint32 tmp = newSize;
|
|
if (tmp > memSize)
|
|
tmp = memSize;
|
|
memcpy (newBuffer, buffer, tmp);
|
|
::free (buffer);
|
|
buffer = newBuffer;
|
|
}
|
|
else
|
|
{
|
|
::free (buffer);
|
|
buffer = 0;
|
|
}
|
|
}
|
|
else
|
|
buffer = newBuffer;
|
|
}
|
|
else
|
|
{
|
|
::free (buffer);
|
|
buffer = 0;
|
|
}
|
|
}
|
|
else
|
|
buffer = (int8*)::malloc (newSize);
|
|
|
|
if (newSize > 0 && !buffer)
|
|
memSize = 0;
|
|
else
|
|
memSize = newSize;
|
|
if (fillSize > memSize)
|
|
fillSize = memSize;
|
|
}
|
|
|
|
return (newSize > 0) == (buffer != 0);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
void Buffer::fillup (uint8 value)
|
|
{
|
|
if (getFree () > 0)
|
|
memset (buffer + fillSize, value, getFree ());
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
int8* Buffer::operator + (uint32 i)
|
|
{
|
|
if (i < memSize)
|
|
return buffer + i;
|
|
else
|
|
{
|
|
static int8 eof;
|
|
eof = 0;
|
|
return &eof;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::swap (int16 swapSize)
|
|
{
|
|
return swap (buffer, memSize, swapSize);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::swap (void* buffer, uint32 bufferSize, int16 swapSize)
|
|
{
|
|
if (swapSize != kSwap16 && swapSize != kSwap32 && swapSize != kSwap64)
|
|
return false;
|
|
|
|
if (swapSize == kSwap16)
|
|
{
|
|
for (uint32 count = 0 ; count < bufferSize ; count += 2)
|
|
{
|
|
SWAP_16 ( * (((int16*)buffer) + count) );
|
|
}
|
|
}
|
|
else if (swapSize == kSwap32)
|
|
{
|
|
for (uint32 count = 0 ; count < bufferSize ; count += 4)
|
|
{
|
|
SWAP_32 ( * (((int32*)buffer) + count) );
|
|
}
|
|
}
|
|
else if (swapSize == kSwap64)
|
|
{
|
|
for (uint32 count = 0 ; count < bufferSize ; count += 8)
|
|
{
|
|
SWAP_64 ( * (((int64*)buffer) + count) );
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
void Buffer::take (Buffer& from)
|
|
{
|
|
setSize (0);
|
|
memSize = from.memSize;
|
|
fillSize = from.fillSize;
|
|
buffer = from.buffer;
|
|
from.buffer = 0;
|
|
from.memSize = 0;
|
|
from.fillSize = 0;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
int8* Buffer::pass ()
|
|
{
|
|
int8* res = buffer;
|
|
buffer = 0;
|
|
memSize = 0;
|
|
fillSize = 0;
|
|
return res;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::toWideString (int32 sourceCodePage)
|
|
{
|
|
if (getFillSize () > 0)
|
|
{
|
|
if (str8 () [getFillSize () - 1] != 0) // multiByteToWideString only works with 0-terminated strings
|
|
endString8 ();
|
|
|
|
Buffer dest (getFillSize () * sizeof (char16));
|
|
int32 result = String::multiByteToWideString (dest.str16 (), buffer, dest.getFree () / sizeof (char16), sourceCodePage);
|
|
if (result > 0)
|
|
{
|
|
dest.setFillSize ((result - 1) * sizeof (char16));
|
|
take (dest);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
bool Buffer::toMultibyteString (int32 destCodePage)
|
|
{
|
|
if (getFillSize () > 0)
|
|
{
|
|
int32 textLength = getFillSize () / sizeof (char16); // wideStringToMultiByte only works with 0-terminated strings
|
|
if (str16 () [textLength - 1] != 0)
|
|
endString16 ();
|
|
|
|
Buffer dest (getFillSize ());
|
|
int32 result = String::wideStringToMultiByte (dest.str8 (), str16 (), dest.getFree (), destCodePage);
|
|
if (result > 0)
|
|
{
|
|
dest.setFillSize (result - 1);
|
|
take (dest);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
} // namespace Steinberg
|