nuclear@1: /************************************************************************************ nuclear@1: nuclear@1: Filename : OVR_String.cpp nuclear@1: Content : String UTF8 string implementation with copy-on-write semantics nuclear@1: (thread-safe for assignment but not modification). nuclear@1: Created : September 19, 2012 nuclear@1: Notes : nuclear@1: nuclear@1: Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. nuclear@1: nuclear@1: Use of this software is subject to the terms of the Oculus license nuclear@1: agreement provided at the time of installation or download, or which nuclear@1: otherwise accompanies this software in either electronic or hard copy form. nuclear@1: nuclear@1: ************************************************************************************/ nuclear@1: nuclear@1: #include "OVR_String.h" nuclear@1: nuclear@1: #include nuclear@1: #include nuclear@1: nuclear@1: #ifdef OVR_OS_QNX nuclear@1: # include nuclear@1: #endif nuclear@1: nuclear@1: namespace OVR { nuclear@1: nuclear@1: #define String_LengthIsSize (UPInt(1) << String::Flag_LengthIsSizeShift) nuclear@1: nuclear@1: String::DataDesc String::NullData = {String_LengthIsSize, 1, {0} }; nuclear@1: nuclear@1: nuclear@1: String::String() nuclear@1: { nuclear@1: pData = &NullData; nuclear@1: pData->AddRef(); nuclear@1: }; nuclear@1: nuclear@1: String::String(const char* pdata) nuclear@1: { nuclear@1: // Obtain length in bytes; it doesn't matter if _data is UTF8. nuclear@1: UPInt size = pdata ? OVR_strlen(pdata) : 0; nuclear@1: pData = AllocDataCopy1(size, 0, pdata, size); nuclear@1: }; nuclear@1: nuclear@1: String::String(const char* pdata1, const char* pdata2, const char* pdata3) nuclear@1: { nuclear@1: // Obtain length in bytes; it doesn't matter if _data is UTF8. nuclear@1: UPInt size1 = pdata1 ? OVR_strlen(pdata1) : 0; nuclear@1: UPInt size2 = pdata2 ? OVR_strlen(pdata2) : 0; nuclear@1: UPInt size3 = pdata3 ? OVR_strlen(pdata3) : 0; nuclear@1: nuclear@1: DataDesc *pdataDesc = AllocDataCopy2(size1 + size2 + size3, 0, nuclear@1: pdata1, size1, pdata2, size2); nuclear@1: memcpy(pdataDesc->Data + size1 + size2, pdata3, size3); nuclear@1: pData = pdataDesc; nuclear@1: } nuclear@1: nuclear@1: String::String(const char* pdata, UPInt size) nuclear@1: { nuclear@1: OVR_ASSERT((size == 0) || (pdata != 0)); nuclear@1: pData = AllocDataCopy1(size, 0, pdata, size); nuclear@1: }; nuclear@1: nuclear@1: nuclear@1: String::String(const InitStruct& src, UPInt size) nuclear@1: { nuclear@1: pData = AllocData(size, 0); nuclear@1: src.InitString(GetData()->Data, size); nuclear@1: } nuclear@1: nuclear@1: String::String(const String& src) nuclear@1: { nuclear@1: pData = src.GetData(); nuclear@1: pData->AddRef(); nuclear@1: } nuclear@1: nuclear@1: String::String(const StringBuffer& src) nuclear@1: { nuclear@1: pData = AllocDataCopy1(src.GetSize(), 0, src.ToCStr(), src.GetSize()); nuclear@1: } nuclear@1: nuclear@1: String::String(const wchar_t* data) nuclear@1: { nuclear@1: pData = &NullData; nuclear@1: pData->AddRef(); nuclear@1: // Simplified logic for wchar_t constructor. nuclear@1: if (data) nuclear@1: *this = data; nuclear@1: } nuclear@1: nuclear@1: nuclear@1: String::DataDesc* String::AllocData(UPInt size, UPInt lengthIsSize) nuclear@1: { nuclear@1: String::DataDesc* pdesc; nuclear@1: nuclear@1: if (size == 0) nuclear@1: { nuclear@1: pdesc = &NullData; nuclear@1: pdesc->AddRef(); nuclear@1: return pdesc; nuclear@1: } nuclear@1: nuclear@1: pdesc = (DataDesc*)OVR_ALLOC(sizeof(DataDesc)+ size); nuclear@1: pdesc->Data[size] = 0; nuclear@1: pdesc->RefCount = 1; nuclear@1: pdesc->Size = size | lengthIsSize; nuclear@1: return pdesc; nuclear@1: } nuclear@1: nuclear@1: nuclear@1: String::DataDesc* String::AllocDataCopy1(UPInt size, UPInt lengthIsSize, nuclear@1: const char* pdata, UPInt copySize) nuclear@1: { nuclear@1: String::DataDesc* pdesc = AllocData(size, lengthIsSize); nuclear@1: memcpy(pdesc->Data, pdata, copySize); nuclear@1: return pdesc; nuclear@1: } nuclear@1: nuclear@1: String::DataDesc* String::AllocDataCopy2(UPInt size, UPInt lengthIsSize, nuclear@1: const char* pdata1, UPInt copySize1, nuclear@1: const char* pdata2, UPInt copySize2) nuclear@1: { nuclear@1: String::DataDesc* pdesc = AllocData(size, lengthIsSize); nuclear@1: memcpy(pdesc->Data, pdata1, copySize1); nuclear@1: memcpy(pdesc->Data + copySize1, pdata2, copySize2); nuclear@1: return pdesc; nuclear@1: } nuclear@1: nuclear@1: nuclear@1: UPInt String::GetLength() const nuclear@1: { nuclear@1: // Optimize length accesses for non-UTF8 character strings. nuclear@1: DataDesc* pdata = GetData(); nuclear@1: UPInt length, size = pdata->GetSize(); nuclear@1: nuclear@1: if (pdata->LengthIsSize()) nuclear@1: return size; nuclear@1: nuclear@1: length = (UPInt)UTF8Util::GetLength(pdata->Data, (UPInt)size); nuclear@1: nuclear@1: if (length == size) nuclear@1: pdata->Size |= String_LengthIsSize; nuclear@1: nuclear@1: return length; nuclear@1: } nuclear@1: nuclear@1: nuclear@1: //static UInt32 String_CharSearch(const char* buf, ) nuclear@1: nuclear@1: nuclear@1: UInt32 String::GetCharAt(UPInt index) const nuclear@1: { nuclear@1: SPInt i = (SPInt) index; nuclear@1: DataDesc* pdata = GetData(); nuclear@1: const char* buf = pdata->Data; nuclear@1: UInt32 c; nuclear@1: nuclear@1: if (pdata->LengthIsSize()) nuclear@1: { nuclear@1: OVR_ASSERT(index < pdata->GetSize()); nuclear@1: buf += i; nuclear@1: return UTF8Util::DecodeNextChar_Advance0(&buf); nuclear@1: } nuclear@1: nuclear@1: c = UTF8Util::GetCharAt(index, buf, pdata->GetSize()); nuclear@1: return c; nuclear@1: } nuclear@1: nuclear@1: UInt32 String::GetFirstCharAt(UPInt index, const char** offset) const nuclear@1: { nuclear@1: DataDesc* pdata = GetData(); nuclear@1: SPInt i = (SPInt) index; nuclear@1: const char* buf = pdata->Data; nuclear@1: const char* end = buf + pdata->GetSize(); nuclear@1: UInt32 c; nuclear@1: nuclear@1: do nuclear@1: { nuclear@1: c = UTF8Util::DecodeNextChar_Advance0(&buf); nuclear@1: i--; nuclear@1: nuclear@1: if (buf >= end) nuclear@1: { nuclear@1: // We've hit the end of the string; don't go further. nuclear@1: OVR_ASSERT(i == 0); nuclear@1: return c; nuclear@1: } nuclear@1: } while (i >= 0); nuclear@1: nuclear@1: *offset = buf; nuclear@1: nuclear@1: return c; nuclear@1: } nuclear@1: nuclear@1: UInt32 String::GetNextChar(const char** offset) const nuclear@1: { nuclear@1: return UTF8Util::DecodeNextChar(offset); nuclear@1: } nuclear@1: nuclear@1: nuclear@1: nuclear@1: void String::AppendChar(UInt32 ch) nuclear@1: { nuclear@1: DataDesc* pdata = GetData(); nuclear@1: UPInt size = pdata->GetSize(); nuclear@1: char buff[8]; nuclear@1: SPInt encodeSize = 0; nuclear@1: nuclear@1: // Converts ch into UTF8 string and fills it into buff. nuclear@1: UTF8Util::EncodeChar(buff, &encodeSize, ch); nuclear@1: OVR_ASSERT(encodeSize >= 0); nuclear@1: nuclear@1: SetData(AllocDataCopy2(size + (UPInt)encodeSize, 0, nuclear@1: pdata->Data, size, buff, (UPInt)encodeSize)); nuclear@1: pdata->Release(); nuclear@1: } nuclear@1: nuclear@1: nuclear@1: void String::AppendString(const wchar_t* pstr, SPInt len) nuclear@1: { nuclear@1: if (!pstr) nuclear@1: return; nuclear@1: nuclear@1: DataDesc* pdata = GetData(); nuclear@1: UPInt oldSize = pdata->GetSize(); nuclear@1: UPInt encodeSize = (UPInt)UTF8Util::GetEncodeStringSize(pstr, len); nuclear@1: nuclear@1: DataDesc* pnewData = AllocDataCopy1(oldSize + (UPInt)encodeSize, 0, nuclear@1: pdata->Data, oldSize); nuclear@1: UTF8Util::EncodeString(pnewData->Data + oldSize, pstr, len); nuclear@1: nuclear@1: SetData(pnewData); nuclear@1: pdata->Release(); nuclear@1: } nuclear@1: nuclear@1: nuclear@1: void String::AppendString(const char* putf8str, SPInt utf8StrSz) nuclear@1: { nuclear@1: if (!putf8str || !utf8StrSz) nuclear@1: return; nuclear@1: if (utf8StrSz == -1) nuclear@1: utf8StrSz = (SPInt)OVR_strlen(putf8str); nuclear@1: nuclear@1: DataDesc* pdata = GetData(); nuclear@1: UPInt oldSize = pdata->GetSize(); nuclear@1: nuclear@1: SetData(AllocDataCopy2(oldSize + (UPInt)utf8StrSz, 0, nuclear@1: pdata->Data, oldSize, putf8str, (UPInt)utf8StrSz)); nuclear@1: pdata->Release(); nuclear@1: } nuclear@1: nuclear@1: void String::AssignString(const InitStruct& src, UPInt size) nuclear@1: { nuclear@1: DataDesc* poldData = GetData(); nuclear@1: DataDesc* pnewData = AllocData(size, 0); nuclear@1: src.InitString(pnewData->Data, size); nuclear@1: SetData(pnewData); nuclear@1: poldData->Release(); nuclear@1: } nuclear@1: nuclear@1: void String::AssignString(const char* putf8str, UPInt size) nuclear@1: { nuclear@1: DataDesc* poldData = GetData(); nuclear@1: SetData(AllocDataCopy1(size, 0, putf8str, size)); nuclear@1: poldData->Release(); nuclear@1: } nuclear@1: nuclear@1: void String::operator = (const char* pstr) nuclear@1: { nuclear@1: AssignString(pstr, pstr ? OVR_strlen(pstr) : 0); nuclear@1: } nuclear@1: nuclear@1: void String::operator = (const wchar_t* pwstr) nuclear@1: { nuclear@1: DataDesc* poldData = GetData(); nuclear@1: UPInt size = pwstr ? (UPInt)UTF8Util::GetEncodeStringSize(pwstr) : 0; nuclear@1: nuclear@1: DataDesc* pnewData = AllocData(size, 0); nuclear@1: UTF8Util::EncodeString(pnewData->Data, pwstr); nuclear@1: SetData(pnewData); nuclear@1: poldData->Release(); nuclear@1: } nuclear@1: nuclear@1: nuclear@1: void String::operator = (const String& src) nuclear@1: { nuclear@1: DataDesc* psdata = src.GetData(); nuclear@1: DataDesc* pdata = GetData(); nuclear@1: nuclear@1: SetData(psdata); nuclear@1: psdata->AddRef(); nuclear@1: pdata->Release(); nuclear@1: } nuclear@1: nuclear@1: nuclear@1: void String::operator = (const StringBuffer& src) nuclear@1: { nuclear@1: DataDesc* polddata = GetData(); nuclear@1: SetData(AllocDataCopy1(src.GetSize(), 0, src.ToCStr(), src.GetSize())); nuclear@1: polddata->Release(); nuclear@1: } nuclear@1: nuclear@1: void String::operator += (const String& src) nuclear@1: { nuclear@1: DataDesc *pourData = GetData(), nuclear@1: *psrcData = src.GetData(); nuclear@1: UPInt ourSize = pourData->GetSize(), nuclear@1: srcSize = psrcData->GetSize(); nuclear@1: UPInt lflag = pourData->GetLengthFlag() & psrcData->GetLengthFlag(); nuclear@1: nuclear@1: SetData(AllocDataCopy2(ourSize + srcSize, lflag, nuclear@1: pourData->Data, ourSize, psrcData->Data, srcSize)); nuclear@1: pourData->Release(); nuclear@1: } nuclear@1: nuclear@1: nuclear@1: String String::operator + (const char* str) const nuclear@1: { nuclear@1: String tmp1(*this); nuclear@1: tmp1 += (str ? str : ""); nuclear@1: return tmp1; nuclear@1: } nuclear@1: nuclear@1: String String::operator + (const String& src) const nuclear@1: { nuclear@1: String tmp1(*this); nuclear@1: tmp1 += src; nuclear@1: return tmp1; nuclear@1: } nuclear@1: nuclear@1: void String::Remove(UPInt posAt, SPInt removeLength) nuclear@1: { nuclear@1: DataDesc* pdata = GetData(); nuclear@1: UPInt oldSize = pdata->GetSize(); nuclear@1: // Length indicates the number of characters to remove. nuclear@1: UPInt length = GetLength(); nuclear@1: nuclear@1: // If index is past the string, nothing to remove. nuclear@1: if (posAt >= length) nuclear@1: return; nuclear@1: // Otherwise, cap removeLength to the length of the string. nuclear@1: if ((posAt + removeLength) > length) nuclear@1: removeLength = length - posAt; nuclear@1: nuclear@1: // Get the byte position of the UTF8 char at position posAt. nuclear@1: SPInt bytePos = UTF8Util::GetByteIndex(posAt, pdata->Data, oldSize); nuclear@1: SPInt removeSize = UTF8Util::GetByteIndex(removeLength, pdata->Data + bytePos, oldSize-bytePos); nuclear@1: nuclear@1: SetData(AllocDataCopy2(oldSize - removeSize, pdata->GetLengthFlag(), nuclear@1: pdata->Data, bytePos, nuclear@1: pData->Data + bytePos + removeSize, (oldSize - bytePos - removeSize))); nuclear@1: pdata->Release(); nuclear@1: } nuclear@1: nuclear@1: nuclear@1: String String::Substring(UPInt start, UPInt end) const nuclear@1: { nuclear@1: UPInt length = GetLength(); nuclear@1: if ((start >= length) || (start >= end)) nuclear@1: return String(); nuclear@1: nuclear@1: DataDesc* pdata = GetData(); nuclear@1: nuclear@1: // If size matches, we know the exact index range. nuclear@1: if (pdata->LengthIsSize()) nuclear@1: return String(pdata->Data + start, end - start); nuclear@1: nuclear@1: // Get position of starting character. nuclear@1: SPInt byteStart = UTF8Util::GetByteIndex(start, pdata->Data, pdata->GetSize()); nuclear@1: SPInt byteSize = UTF8Util::GetByteIndex(end - start, pdata->Data + byteStart, pdata->GetSize()-byteStart); nuclear@1: return String(pdata->Data + byteStart, (UPInt)byteSize); nuclear@1: } nuclear@1: nuclear@1: void String::Clear() nuclear@1: { nuclear@1: NullData.AddRef(); nuclear@1: GetData()->Release(); nuclear@1: SetData(&NullData); nuclear@1: } nuclear@1: nuclear@1: nuclear@1: String String::ToUpper() const nuclear@1: { nuclear@1: UInt32 c; nuclear@1: const char* psource = GetData()->Data; nuclear@1: const char* pend = psource + GetData()->GetSize(); nuclear@1: String str; nuclear@1: SPInt bufferOffset = 0; nuclear@1: char buffer[512]; nuclear@1: nuclear@1: while(psource < pend) nuclear@1: { nuclear@1: do { nuclear@1: c = UTF8Util::DecodeNextChar_Advance0(&psource); nuclear@1: UTF8Util::EncodeChar(buffer, &bufferOffset, OVR_towupper(wchar_t(c))); nuclear@1: } while ((psource < pend) && (bufferOffset < SPInt(sizeof(buffer)-8))); nuclear@1: nuclear@1: // Append string a piece at a time. nuclear@1: str.AppendString(buffer, bufferOffset); nuclear@1: bufferOffset = 0; nuclear@1: } nuclear@1: nuclear@1: return str; nuclear@1: } nuclear@1: nuclear@1: String String::ToLower() const nuclear@1: { nuclear@1: UInt32 c; nuclear@1: const char* psource = GetData()->Data; nuclear@1: const char* pend = psource + GetData()->GetSize(); nuclear@1: String str; nuclear@1: SPInt bufferOffset = 0; nuclear@1: char buffer[512]; nuclear@1: nuclear@1: while(psource < pend) nuclear@1: { nuclear@1: do { nuclear@1: c = UTF8Util::DecodeNextChar_Advance0(&psource); nuclear@1: UTF8Util::EncodeChar(buffer, &bufferOffset, OVR_towlower(wchar_t(c))); nuclear@1: } while ((psource < pend) && (bufferOffset < SPInt(sizeof(buffer)-8))); nuclear@1: nuclear@1: // Append string a piece at a time. nuclear@1: str.AppendString(buffer, bufferOffset); nuclear@1: bufferOffset = 0; nuclear@1: } nuclear@1: nuclear@1: return str; nuclear@1: } nuclear@1: nuclear@1: nuclear@1: nuclear@1: String& String::Insert(const char* substr, UPInt posAt, SPInt strSize) nuclear@1: { nuclear@1: DataDesc* poldData = GetData(); nuclear@1: UPInt oldSize = poldData->GetSize(); nuclear@1: UPInt insertSize = (strSize < 0) ? OVR_strlen(substr) : (UPInt)strSize; nuclear@1: UPInt byteIndex = (poldData->LengthIsSize()) ? nuclear@1: posAt : (UPInt)UTF8Util::GetByteIndex(posAt, poldData->Data, oldSize); nuclear@1: nuclear@1: OVR_ASSERT(byteIndex <= oldSize); nuclear@1: nuclear@1: DataDesc* pnewData = AllocDataCopy2(oldSize + insertSize, 0, nuclear@1: poldData->Data, byteIndex, substr, insertSize); nuclear@1: memcpy(pnewData->Data + byteIndex + insertSize, nuclear@1: poldData->Data + byteIndex, oldSize - byteIndex); nuclear@1: SetData(pnewData); nuclear@1: poldData->Release(); nuclear@1: return *this; nuclear@1: } nuclear@1: nuclear@1: /* nuclear@1: String& String::Insert(const UInt32* substr, UPInt posAt, SPInt len) nuclear@1: { nuclear@1: for (SPInt i = 0; i < len; ++i) nuclear@1: { nuclear@1: UPInt charw = InsertCharAt(substr[i], posAt); nuclear@1: posAt += charw; nuclear@1: } nuclear@1: return *this; nuclear@1: } nuclear@1: */ nuclear@1: nuclear@1: UPInt String::InsertCharAt(UInt32 c, UPInt posAt) nuclear@1: { nuclear@1: char buf[8]; nuclear@1: SPInt index = 0; nuclear@1: UTF8Util::EncodeChar(buf, &index, c); nuclear@1: OVR_ASSERT(index >= 0); nuclear@1: buf[(UPInt)index] = 0; nuclear@1: nuclear@1: Insert(buf, posAt, index); nuclear@1: return (UPInt)index; nuclear@1: } nuclear@1: nuclear@1: nuclear@1: int String::CompareNoCase(const char* a, const char* b) nuclear@1: { nuclear@1: return OVR_stricmp(a, b); nuclear@1: } nuclear@1: nuclear@1: int String::CompareNoCase(const char* a, const char* b, SPInt len) nuclear@1: { nuclear@1: if (len) nuclear@1: { nuclear@1: SPInt f,l; nuclear@1: SPInt slen = len; nuclear@1: const char *s = b; nuclear@1: do { nuclear@1: f = (SPInt)OVR_tolower((int)(*(a++))); nuclear@1: l = (SPInt)OVR_tolower((int)(*(b++))); nuclear@1: } while (--len && f && (f == l) && *b != 0); nuclear@1: nuclear@1: if (f == l && (len != 0 || *b != 0)) nuclear@1: { nuclear@1: f = (SPInt)slen; nuclear@1: l = (SPInt)OVR_strlen(s); nuclear@1: return int(f - l); nuclear@1: } nuclear@1: nuclear@1: return int(f - l); nuclear@1: } nuclear@1: else nuclear@1: return (0-(int)OVR_strlen(b)); nuclear@1: } nuclear@1: nuclear@1: // ***** Implement hash static functions nuclear@1: nuclear@1: // Hash function nuclear@1: UPInt String::BernsteinHashFunction(const void* pdataIn, UPInt size, UPInt seed) nuclear@1: { nuclear@1: const UByte* pdata = (const UByte*) pdataIn; nuclear@1: UPInt h = seed; nuclear@1: while (size > 0) nuclear@1: { nuclear@1: size--; nuclear@1: h = ((h << 5) + h) ^ (unsigned) pdata[size]; nuclear@1: } nuclear@1: nuclear@1: return h; nuclear@1: } nuclear@1: nuclear@1: // Hash function, case-insensitive nuclear@1: UPInt String::BernsteinHashFunctionCIS(const void* pdataIn, UPInt size, UPInt seed) nuclear@1: { nuclear@1: const UByte* pdata = (const UByte*) pdataIn; nuclear@1: UPInt h = seed; nuclear@1: while (size > 0) nuclear@1: { nuclear@1: size--; nuclear@1: h = ((h << 5) + h) ^ OVR_tolower(pdata[size]); nuclear@1: } nuclear@1: nuclear@1: // Alternative: "sdbm" hash function, suggested at same web page above. nuclear@1: // h = 0; nuclear@1: // for bytes { h = (h << 16) + (h << 6) - hash + *p; } nuclear@1: return h; nuclear@1: } nuclear@1: nuclear@1: nuclear@1: nuclear@1: // ***** String Buffer used for Building Strings nuclear@1: nuclear@1: nuclear@1: #define OVR_SBUFF_DEFAULT_GROW_SIZE 512 nuclear@1: // Constructors / Destructor. nuclear@1: StringBuffer::StringBuffer() nuclear@1: : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false) nuclear@1: { nuclear@1: } nuclear@1: nuclear@1: StringBuffer::StringBuffer(UPInt growSize) nuclear@1: : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false) nuclear@1: { nuclear@1: SetGrowSize(growSize); nuclear@1: } nuclear@1: nuclear@1: StringBuffer::StringBuffer(const char* data) nuclear@1: : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false) nuclear@1: { nuclear@1: *this = data; nuclear@1: } nuclear@1: nuclear@1: StringBuffer::StringBuffer(const char* data, UPInt dataSize) nuclear@1: : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false) nuclear@1: { nuclear@1: AppendString(data, dataSize); nuclear@1: } nuclear@1: nuclear@1: StringBuffer::StringBuffer(const String& src) nuclear@1: : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false) nuclear@1: { nuclear@1: AppendString(src.ToCStr(), src.GetSize()); nuclear@1: } nuclear@1: nuclear@1: StringBuffer::StringBuffer(const StringBuffer& src) nuclear@1: : pData(NULL), Size(0), BufferSize(src.GetGrowSize()), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false) nuclear@1: { nuclear@1: AppendString(src.ToCStr(), src.GetSize()); nuclear@1: LengthIsSize = src.LengthIsSize; nuclear@1: } nuclear@1: nuclear@1: StringBuffer::StringBuffer(const wchar_t* data) nuclear@1: : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false) nuclear@1: { nuclear@1: *this = data; nuclear@1: } nuclear@1: nuclear@1: StringBuffer::~StringBuffer() nuclear@1: { nuclear@1: if (pData) nuclear@1: OVR_FREE(pData); nuclear@1: } nuclear@1: void StringBuffer::SetGrowSize(UPInt growSize) nuclear@1: { nuclear@1: if (growSize <= 16) nuclear@1: GrowSize = 16; nuclear@1: else nuclear@1: { nuclear@1: UByte bits = Alg::UpperBit(UInt32(growSize-1)); nuclear@1: UPInt size = 1<= BufferSize) // >= because of trailing zero! (!AB) nuclear@1: { nuclear@1: BufferSize = (_size + 1 + GrowSize - 1)& ~(GrowSize-1); nuclear@1: if (!pData) nuclear@1: pData = (char*)OVR_ALLOC(BufferSize); nuclear@1: else nuclear@1: pData = (char*)OVR_REALLOC(pData, BufferSize); nuclear@1: } nuclear@1: } nuclear@1: void StringBuffer::Resize(UPInt _size) nuclear@1: { nuclear@1: Reserve(_size); nuclear@1: LengthIsSize = false; nuclear@1: Size = _size; nuclear@1: if (pData) nuclear@1: pData[Size] = 0; nuclear@1: } nuclear@1: nuclear@1: void StringBuffer::Clear() nuclear@1: { nuclear@1: Resize(0); nuclear@1: /* nuclear@1: if (pData != pEmptyNullData) nuclear@1: { nuclear@1: OVR_FREE(pHeap, pData); nuclear@1: pData = pEmptyNullData; nuclear@1: Size = BufferSize = 0; nuclear@1: LengthIsSize = false; nuclear@1: } nuclear@1: */ nuclear@1: } nuclear@1: // Appends a character nuclear@1: void StringBuffer::AppendChar(UInt32 ch) nuclear@1: { nuclear@1: char buff[8]; nuclear@1: UPInt origSize = GetSize(); nuclear@1: nuclear@1: // Converts ch into UTF8 string and fills it into buff. Also increments index according to the number of bytes nuclear@1: // in the UTF8 string. nuclear@1: SPInt srcSize = 0; nuclear@1: UTF8Util::EncodeChar(buff, &srcSize, ch); nuclear@1: OVR_ASSERT(srcSize >= 0); nuclear@1: nuclear@1: UPInt size = origSize + srcSize; nuclear@1: Resize(size); nuclear@1: memcpy(pData + origSize, buff, srcSize); nuclear@1: } nuclear@1: nuclear@1: // Append a string nuclear@1: void StringBuffer::AppendString(const wchar_t* pstr, SPInt len) nuclear@1: { nuclear@1: if (!pstr) nuclear@1: return; nuclear@1: nuclear@1: SPInt srcSize = UTF8Util::GetEncodeStringSize(pstr, len); nuclear@1: UPInt origSize = GetSize(); nuclear@1: UPInt size = srcSize + origSize; nuclear@1: nuclear@1: Resize(size); nuclear@1: UTF8Util::EncodeString(pData + origSize, pstr, len); nuclear@1: } nuclear@1: nuclear@1: void StringBuffer::AppendString(const char* putf8str, SPInt utf8StrSz) nuclear@1: { nuclear@1: if (!putf8str || !utf8StrSz) nuclear@1: return; nuclear@1: if (utf8StrSz == -1) nuclear@1: utf8StrSz = (SPInt)OVR_strlen(putf8str); nuclear@1: nuclear@1: UPInt origSize = GetSize(); nuclear@1: UPInt size = utf8StrSz + origSize; nuclear@1: nuclear@1: Resize(size); nuclear@1: memcpy(pData + origSize, putf8str, utf8StrSz); nuclear@1: } nuclear@1: nuclear@1: nuclear@1: void StringBuffer::operator = (const char* pstr) nuclear@1: { nuclear@1: pstr = pstr ? pstr : ""; nuclear@1: UPInt size = OVR_strlen(pstr); nuclear@1: Resize(size); nuclear@1: memcpy(pData, pstr, size); nuclear@1: } nuclear@1: nuclear@1: void StringBuffer::operator = (const wchar_t* pstr) nuclear@1: { nuclear@1: pstr = pstr ? pstr : L""; nuclear@1: UPInt size = (UPInt)UTF8Util::GetEncodeStringSize(pstr); nuclear@1: Resize(size); nuclear@1: UTF8Util::EncodeString(pData, pstr); nuclear@1: } nuclear@1: nuclear@1: void StringBuffer::operator = (const String& src) nuclear@1: { nuclear@1: Resize(src.GetSize()); nuclear@1: memcpy(pData, src.ToCStr(), src.GetSize()); nuclear@1: } nuclear@1: nuclear@1: nuclear@1: // Inserts substr at posAt nuclear@1: void StringBuffer::Insert(const char* substr, UPInt posAt, SPInt len) nuclear@1: { nuclear@1: UPInt oldSize = Size; nuclear@1: UPInt insertSize = (len < 0) ? OVR_strlen(substr) : (UPInt)len; nuclear@1: UPInt byteIndex = LengthIsSize ? posAt : nuclear@1: (UPInt)UTF8Util::GetByteIndex(posAt, pData, (SPInt)Size); nuclear@1: nuclear@1: OVR_ASSERT(byteIndex <= oldSize); nuclear@1: Reserve(oldSize + insertSize); nuclear@1: nuclear@1: memmove(pData + byteIndex + insertSize, pData + byteIndex, oldSize - byteIndex + 1); nuclear@1: memcpy (pData + byteIndex, substr, insertSize); nuclear@1: LengthIsSize = false; nuclear@1: Size = oldSize + insertSize; nuclear@1: pData[Size] = 0; nuclear@1: } nuclear@1: nuclear@1: // Inserts character at posAt nuclear@1: UPInt StringBuffer::InsertCharAt(UInt32 c, UPInt posAt) nuclear@1: { nuclear@1: char buf[8]; nuclear@1: SPInt len = 0; nuclear@1: UTF8Util::EncodeChar(buf, &len, c); nuclear@1: OVR_ASSERT(len >= 0); nuclear@1: buf[(UPInt)len] = 0; nuclear@1: nuclear@1: Insert(buf, posAt, len); nuclear@1: return (UPInt)len; nuclear@1: } nuclear@1: nuclear@1: } // OVR