Files
mcpe/thirdparty/raknet/RakString.cpp
iProgramInCpp 9642818a88 * Initial commit.
:)
2023-07-30 22:22:02 +03:00

1691 lines
38 KiB
C++

/*
* Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#include "RakString.h"
#include "RakAssert.h"
#include "RakMemoryOverride.h"
#include "BitStream.h"
#include <stdarg.h>
#include <string.h>
#include "LinuxStrings.h"
#include "StringCompressor.h"
#include "SimpleMutex.h"
#include <stdlib.h>
#include "Itoa.h"
using namespace RakNet;
//DataStructures::MemoryPool<RakString::SharedString> RakString::pool;
RakString::SharedString RakString::emptyString={0,0,0,(char*) "",(char*) ""};
//RakString::SharedString *RakString::sharedStringFreeList=0;
//unsigned int RakString::sharedStringFreeListAllocationCount=0;
DataStructures::List<RakString::SharedString*> RakString::freeList;
class RakStringCleanup
{
public:
~RakStringCleanup()
{
RakNet::RakString::FreeMemoryNoMutex();
}
};
static RakStringCleanup cleanup;
SimpleMutex& GetPoolMutex(void)
{
static SimpleMutex poolMutex;
return poolMutex;
}
int RakNet::RakString::RakStringComp( RakString const &key, RakString const &data )
{
return key.StrCmp(data);
}
RakString::RakString()
{
sharedString=&emptyString;
}
RakString::RakString( RakString::SharedString *_sharedString )
{
sharedString=_sharedString;
}
RakString::RakString(char input)
{
char str[2];
str[0]=input;
str[1]=0;
Assign(str);
}
RakString::RakString(unsigned char input)
{
char str[2];
str[0]=(char) input;
str[1]=0;
Assign(str);
}
RakString::RakString(const unsigned char *format, ...){
va_list ap;
va_start(ap, format);
Assign((const char*) format,ap);
}
RakString::RakString(const char *format, ...){
va_list ap;
va_start(ap, format);
Assign(format,ap);
}
RakString::RakString( const RakString & rhs)
{
if (rhs.sharedString==&emptyString)
{
sharedString=&emptyString;
return;
}
rhs.sharedString->refCountMutex->Lock();
if (rhs.sharedString->refCount==0)
{
sharedString=&emptyString;
}
else
{
rhs.sharedString->refCount++;
sharedString=rhs.sharedString;
}
rhs.sharedString->refCountMutex->Unlock();
}
RakString::~RakString()
{
Free();
}
RakString& RakString::operator = ( const RakString& rhs )
{
Free();
if (rhs.sharedString==&emptyString)
return *this;
rhs.sharedString->refCountMutex->Lock();
if (rhs.sharedString->refCount==0)
{
sharedString=&emptyString;
}
else
{
sharedString=rhs.sharedString;
sharedString->refCount++;
}
rhs.sharedString->refCountMutex->Unlock();
return *this;
}
RakString& RakString::operator = ( const char *str )
{
Free();
Assign(str);
return *this;
}
RakString& RakString::operator = ( char *str )
{
return operator = ((const char*)str);
}
RakString& RakString::operator = ( const unsigned char *str )
{
return operator = ((const char*)str);
}
RakString& RakString::operator = ( char unsigned *str )
{
return operator = ((const char*)str);
}
RakString& RakString::operator = ( const char c )
{
char buff[2];
buff[0]=c;
buff[1]=0;
return operator = ((const char*)buff);
}
void RakString::Realloc(SharedString *sharedString, size_t bytes)
{
if (bytes<=sharedString->bytesUsed)
return;
RakAssert(bytes>0);
size_t oldBytes = sharedString->bytesUsed;
size_t newBytes;
const size_t smallStringSize = 128-sizeof(unsigned int)-sizeof(size_t)-sizeof(char*)*2;
newBytes = GetSizeToAllocate(bytes);
if (oldBytes <=(size_t) smallStringSize && newBytes > (size_t) smallStringSize)
{
sharedString->bigString=(char*) rakMalloc_Ex(newBytes, _FILE_AND_LINE_);
strcpy(sharedString->bigString, sharedString->smallString);
sharedString->c_str=sharedString->bigString;
}
else if (oldBytes > smallStringSize)
{
sharedString->bigString=(char*) rakRealloc_Ex(sharedString->bigString,newBytes, _FILE_AND_LINE_);
sharedString->c_str=sharedString->bigString;
}
sharedString->bytesUsed=newBytes;
}
RakString& RakString::operator +=( const RakString& rhs)
{
if (rhs.IsEmpty())
return *this;
if (IsEmpty())
{
return operator=(rhs);
}
else
{
Clone();
size_t strLen=rhs.GetLength()+GetLength()+1;
Realloc(sharedString, strLen+GetLength());
strcat(sharedString->c_str,rhs.C_String());
}
return *this;
}
RakString& RakString::operator +=( const char *str )
{
if (str==0 || str[0]==0)
return *this;
if (IsEmpty())
{
Assign(str);
}
else
{
Clone();
size_t strLen=strlen(str)+GetLength()+1;
Realloc(sharedString, strLen);
strcat(sharedString->c_str,str);
}
return *this;
}
RakString& RakString::operator +=( char *str )
{
return operator += ((const char*)str);
}
RakString& RakString::operator +=( const unsigned char *str )
{
return operator += ((const char*)str);
}
RakString& RakString::operator +=( unsigned char *str )
{
return operator += ((const char*)str);
}
RakString& RakString::operator +=( const char c )
{
char buff[2];
buff[0]=c;
buff[1]=0;
return operator += ((const char*)buff);
}
unsigned char RakString::operator[] ( const unsigned int position ) const
{
RakAssert(position<GetLength());
return sharedString->c_str[position];
}
bool RakString::operator==(const RakString &rhs) const
{
return strcmp(sharedString->c_str,rhs.sharedString->c_str)==0;
}
bool RakString::operator==(const char *str) const
{
return strcmp(sharedString->c_str,str)==0;
}
bool RakString::operator==(char *str) const
{
return strcmp(sharedString->c_str,str)==0;
}
bool RakString::operator < ( const RakString& right ) const
{
return strcmp(sharedString->c_str,right.C_String()) < 0;
}
bool RakString::operator <= ( const RakString& right ) const
{
return strcmp(sharedString->c_str,right.C_String()) <= 0;
}
bool RakString::operator > ( const RakString& right ) const
{
return strcmp(sharedString->c_str,right.C_String()) > 0;
}
bool RakString::operator >= ( const RakString& right ) const
{
return strcmp(sharedString->c_str,right.C_String()) >= 0;
}
bool RakString::operator!=(const RakString &rhs) const
{
return strcmp(sharedString->c_str,rhs.sharedString->c_str)!=0;
}
bool RakString::operator!=(const char *str) const
{
return strcmp(sharedString->c_str,str)!=0;
}
bool RakString::operator!=(char *str) const
{
return strcmp(sharedString->c_str,str)!=0;
}
const RakNet::RakString operator+(const RakNet::RakString &lhs, const RakNet::RakString &rhs)
{
if (lhs.IsEmpty() && rhs.IsEmpty())
{
return RakString(&RakString::emptyString);
}
if (lhs.IsEmpty())
{
rhs.sharedString->refCountMutex->Lock();
if (rhs.sharedString->refCount==0)
{
rhs.sharedString->refCountMutex->Unlock();
lhs.sharedString->refCountMutex->Lock();
lhs.sharedString->refCount++;
lhs.sharedString->refCountMutex->Unlock();
return RakString(lhs.sharedString);
}
else
{
rhs.sharedString->refCount++;
rhs.sharedString->refCountMutex->Unlock();
return RakString(rhs.sharedString);
}
// rhs.sharedString->refCountMutex->Unlock();
}
if (rhs.IsEmpty())
{
lhs.sharedString->refCountMutex->Lock();
lhs.sharedString->refCount++;
lhs.sharedString->refCountMutex->Unlock();
return RakString(lhs.sharedString);
}
size_t len1 = lhs.GetLength();
size_t len2 = rhs.GetLength();
size_t allocatedBytes = len1 + len2 + 1;
allocatedBytes = RakString::GetSizeToAllocate(allocatedBytes);
RakString::SharedString *sharedString;
RakString::LockMutex();
// sharedString = RakString::pool.Allocate( _FILE_AND_LINE_ );
if (RakString::freeList.Size()==0)
{
//RakString::sharedStringFreeList=(RakString::SharedString*) rakRealloc_Ex(RakString::sharedStringFreeList,(RakString::sharedStringFreeListAllocationCount+1024)*sizeof(RakString::SharedString), _FILE_AND_LINE_);
unsigned i;
for (i=0; i < 128; i++)
{
// RakString::freeList.Insert(RakString::sharedStringFreeList+i+RakString::sharedStringFreeListAllocationCount);
RakString::SharedString *ss;
ss = (RakString::SharedString*) rakMalloc_Ex(sizeof(RakString::SharedString), _FILE_AND_LINE_);
ss->refCountMutex=RakNet::OP_NEW<SimpleMutex>(_FILE_AND_LINE_);
RakString::freeList.Insert(ss, _FILE_AND_LINE_);
}
//RakString::sharedStringFreeListAllocationCount+=1024;
}
sharedString = RakString::freeList[RakString::freeList.Size()-1];
RakString::freeList.RemoveAtIndex(RakString::freeList.Size()-1);
RakString::UnlockMutex();
const int smallStringSize = 128-sizeof(unsigned int)-sizeof(size_t)-sizeof(char*)*2;
sharedString->bytesUsed=allocatedBytes;
sharedString->refCount=1;
if (allocatedBytes <= (size_t) smallStringSize)
{
sharedString->c_str=sharedString->smallString;
}
else
{
sharedString->bigString=(char*)rakMalloc_Ex(sharedString->bytesUsed, _FILE_AND_LINE_);
sharedString->c_str=sharedString->bigString;
}
strcpy(sharedString->c_str, lhs);
strcat(sharedString->c_str, rhs);
return RakString(sharedString);
}
const char * RakString::ToLower(void)
{
Clone();
size_t strLen = strlen(sharedString->c_str);
unsigned i;
for (i=0; i < strLen; i++)
sharedString->c_str[i]=ToLower(sharedString->c_str[i]);
return sharedString->c_str;
}
const char * RakString::ToUpper(void)
{
Clone();
size_t strLen = strlen(sharedString->c_str);
unsigned i;
for (i=0; i < strLen; i++)
sharedString->c_str[i]=ToUpper(sharedString->c_str[i]);
return sharedString->c_str;
}
void RakString::Set(const char *format, ...)
{
va_list ap;
va_start(ap, format);
Clear();
Assign(format,ap);
}
bool RakString::IsEmpty(void) const
{
return sharedString==&emptyString;
}
size_t RakString::GetLength(void) const
{
return strlen(sharedString->c_str);
}
// http://porg.es/blog/counting-characters-in-utf-8-strings-is-faster
int porges_strlen2(char *s)
{
int i = 0;
int iBefore = 0;
int count = 0;
while (s[i] > 0)
ascii: i++;
count += i-iBefore;
while (s[i])
{
if (s[i] > 0)
{
iBefore = i;
goto ascii;
}
else
switch (0xF0 & s[i])
{
case 0xE0: i += 3; break;
case 0xF0: i += 4; break;
default: i += 2; break;
}
++count;
}
return count;
}
size_t RakString::GetLengthUTF8(void) const
{
return porges_strlen2(sharedString->c_str);
}
void RakString::Replace(unsigned index, unsigned count, unsigned char c)
{
RakAssert(index+count < GetLength());
Clone();
unsigned countIndex=0;
while (countIndex<count)
{
sharedString->c_str[index]=c;
index++;
countIndex++;
}
}
void RakString::SetChar( unsigned index, unsigned char c )
{
RakAssert(index < GetLength());
Clone();
sharedString->c_str[index]=c;
}
void RakString::SetChar( unsigned index, RakNet::RakString s )
{
RakAssert(index < GetLength());
Clone();
RakNet::RakString firstHalf = SubStr(0, index);
RakNet::RakString secondHalf = SubStr(index+1, (unsigned int)-1);
*this = firstHalf;
*this += s;
*this += secondHalf;
}
#ifdef _WIN32
static WCHAR EmptyString[] = L"";
WCHAR * RakString::ToWideChar(void)
{
//
// Special case of NULL or empty input string
//
if ( (sharedString->c_str == NULL) || (*sharedString->c_str == '\0') )
{
// Return empty string
return EmptyString;
}
//
// Get size of destination UTF-16 buffer, in WCHAR's
//
int cchUTF16 = ::MultiByteToWideChar(
CP_UTF8, // convert from UTF-8
0, // Flags
sharedString->c_str, // source UTF-8 string
GetLength()+1, // total length of source UTF-8 string,
// in CHAR's (= bytes), including end-of-string \0
NULL, // unused - no conversion done in this step
0 // request size of destination buffer, in WCHAR's
);
if ( cchUTF16 == 0 )
{
RakAssert("RakString::ToWideChar exception from cchUTF16==0" && 0);
return 0;
}
//
// Allocate destination buffer to store UTF-16 string
//
WCHAR * pszUTF16 = RakNet::OP_NEW_ARRAY<WCHAR>(cchUTF16,__FILE__,__LINE__);
//
// Do the conversion from UTF-8 to UTF-16
//
int result = ::MultiByteToWideChar(
CP_UTF8, // convert from UTF-8
0, // Buffer
sharedString->c_str, // source UTF-8 string
GetLength()+1, // total length of source UTF-8 string,
// in CHAR's (= bytes), including end-of-string \0
pszUTF16, // destination buffer
cchUTF16 // size of destination buffer, in WCHAR's
);
if ( result == 0 )
{
RakAssert("RakString::ToWideChar exception from MultiByteToWideChar" && 0);
return 0;
}
return pszUTF16;
}
void RakString::DeallocWideChar(WCHAR * w)
{
RakNet::OP_DELETE_ARRAY(w,__FILE__,__LINE__);
}
void RakString::FromWideChar(const wchar_t *source)
{
Clear();
int bufSize = wcslen(source)*4;
Allocate(bufSize);
WideCharToMultiByte ( CP_ACP, // ANSI code page
WC_COMPOSITECHECK, // Check for accented characters
source, // Source Unicode string
-1, // -1 means string is zero-terminated
sharedString->c_str, // Destination char string
bufSize, // Size of buffer
NULL, // No default character
NULL ); // Don't care about this flag
}
RakNet::RakString RakString::FromWideChar_S(const wchar_t *source)
{
RakNet::RakString rs;
rs.FromWideChar(source);
return rs;
}
#endif
size_t RakString::Find(const char *stringToFind,size_t pos)
{
size_t len=GetLength();
if (pos>=len || stringToFind==0 || stringToFind[0]==0)
{
return (size_t) -1;
}
size_t matchLen= strlen(stringToFind);
size_t matchPos=0;
size_t iStart=0;
for (size_t i=pos;i<len;i++)
{
if (stringToFind[matchPos]==sharedString->c_str[i])
{
if(matchPos==0)
{
iStart=i;
}
matchPos++;
}
else
{
matchPos=0;
}
if (matchPos>=matchLen)
{
return iStart;
}
}
return (size_t) -1;
}
void RakString::TruncateUTF8(unsigned int length)
{
int i = 0;
unsigned int count = 0;
while (sharedString->c_str[i]!=0)
{
if (count==length)
{
sharedString->c_str[i]=0;
return;
}
else if (sharedString->c_str[i]>0)
{
i++;
}
else
{
switch (0xF0 & sharedString->c_str[i])
{
case 0xE0: i += 3; break;
case 0xF0: i += 4; break;
default: i += 2; break;
}
}
count++;
}
}
void RakString::Truncate(unsigned int length)
{
if (length < GetLength())
{
SetChar(length, 0);
}
}
RakString RakString::SubStr(unsigned int index, unsigned int count) const
{
size_t length = GetLength();
if (index >= length || count==0)
return RakString();
RakString copy;
size_t numBytes = length-index;
if (count < numBytes)
numBytes=count;
copy.Allocate(numBytes+1);
size_t i;
for (i=0; i < numBytes; i++)
copy.sharedString->c_str[i]=sharedString->c_str[index+i];
copy.sharedString->c_str[i]=0;
return copy;
}
void RakString::Erase(unsigned int index, unsigned int count)
{
size_t len = GetLength();
RakAssert(index+count <= len);
Clone();
unsigned i;
for (i=index; i < len-count; i++)
{
sharedString->c_str[i]=sharedString->c_str[i+count];
}
sharedString->c_str[i]=0;
}
void RakString::TerminateAtLastCharacter(char c)
{
int i, len=(int) GetLength();
for (i=len-1; i >= 0; i--)
{
if (sharedString->c_str[i]==c)
{
Clone();
sharedString->c_str[i]=0;
return;
}
}
}
void RakString::StartAfterLastCharacter(char c)
{
int i, len=(int) GetLength();
for (i=len-1; i >= 0; i--)
{
if (sharedString->c_str[i]==c)
{
++i;
if (i < len)
{
*this = SubStr(i,GetLength()-i);
}
return;
}
}
}
void RakString::TerminateAtFirstCharacter(char c)
{
unsigned int i, len=(unsigned int) GetLength();
for (i=0; i < len; i++)
{
if (sharedString->c_str[i]==c)
{
if (i > 0)
{
Clone();
sharedString->c_str[i]=0;
}
}
}
}
void RakString::StartAfterFirstCharacter(char c)
{
unsigned int i, len=(unsigned int) GetLength();
for (i=0; i < len; i++)
{
if (sharedString->c_str[i]==c)
{
++i;
if (i < len)
{
*this = SubStr(i,GetLength()-i);
}
return;
}
}
}
int RakString::GetCharacterCount(char c)
{
int count=0;
unsigned int i, len=(unsigned int) GetLength();
for (i=0; i < len; i++)
{
if (sharedString->c_str[i]==c)
{
++count;
}
}
return count;
}
void RakString::RemoveCharacter(char c)
{
if (c==0)
return;
unsigned int readIndex, writeIndex=0;
for (readIndex=0; sharedString->c_str[readIndex]; readIndex++)
{
if (sharedString->c_str[readIndex]!=c)
sharedString->c_str[writeIndex++]=sharedString->c_str[readIndex];
else
Clone();
}
sharedString->c_str[writeIndex]=0;
if (writeIndex==0)
Clear();
}
int RakString::StrCmp(const RakString &rhs) const
{
return strcmp(sharedString->c_str, rhs.C_String());
}
int RakString::StrNCmp(const RakString &rhs, size_t num) const
{
return strncmp(sharedString->c_str, rhs.C_String(), num);
}
int RakString::StrICmp(const RakString &rhs) const
{
return _stricmp(sharedString->c_str, rhs.C_String());
}
void RakString::Printf(void)
{
RAKNET_DEBUG_PRINTF("%s", sharedString->c_str);
}
void RakString::FPrintf(FILE *fp)
{
fprintf(fp,"%s", sharedString->c_str);
}
bool RakString::IPAddressMatch(const char *IP)
{
unsigned characterIndex;
if ( IP == 0 || IP[ 0 ] == 0 || strlen( IP ) > 15 )
return false;
characterIndex = 0;
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
while ( true )
{
if (sharedString->c_str[ characterIndex ] == IP[ characterIndex ] )
{
// Equal characters
if ( IP[ characterIndex ] == 0 )
{
// End of the string and the strings match
return true;
}
characterIndex++;
}
else
{
if ( sharedString->c_str[ characterIndex ] == 0 || IP[ characterIndex ] == 0 )
{
// End of one of the strings
break;
}
// Characters do not match
if ( sharedString->c_str[ characterIndex ] == '*' )
{
// Domain is banned.
return true;
}
// Characters do not match and it is not a *
break;
}
}
// No match found.
return false;
}
bool RakString::ContainsNonprintableExceptSpaces(void) const
{
size_t strLen = strlen(sharedString->c_str);
unsigned i;
for (i=0; i < strLen; i++)
{
if (sharedString->c_str[i] < ' ' || sharedString->c_str[i] >126)
return true;
}
return false;
}
bool RakString::IsEmailAddress(void) const
{
if (IsEmpty())
return false;
size_t strLen = strlen(sharedString->c_str);
if (strLen < 6) // a@b.de
return false;
if (sharedString->c_str[strLen-4]!='.' && sharedString->c_str[strLen-3]!='.') // .com, .net., .org, .de
return false;
unsigned i;
// Has non-printable?
for (i=0; i < strLen; i++)
{
if (sharedString->c_str[i] <= ' ' || sharedString->c_str[i] >126)
return false;
}
int atCount=0;
for (i=0; i < strLen; i++)
{
if (sharedString->c_str[i]=='@')
{
atCount++;
}
}
if (atCount!=1)
return false;
int dotCount=0;
for (i=0; i < strLen; i++)
{
if (sharedString->c_str[i]=='.')
{
dotCount++;
}
}
if (dotCount==0)
return false;
// There's more I could check, but this is good enough
return true;
}
RakNet::RakString& RakString::URLEncode(void)
{
RakString result;
size_t strLen = strlen(sharedString->c_str);
result.Allocate(strLen*3);
char *output=result.sharedString->c_str;
unsigned int outputIndex=0;
unsigned i;
unsigned char c;
for (i=0; i < strLen; i++)
{
c=sharedString->c_str[i];
if (
(c<=47) ||
(c>=58 && c<=64) ||
(c>=91 && c<=96) ||
(c>=123)
)
{
char buff[3];
Itoa(c, buff, 16);
output[outputIndex++]='%';
output[outputIndex++]=buff[0];
output[outputIndex++]=buff[1];
}
else
{
output[outputIndex++]=c;
}
}
output[outputIndex]=0;
*this = result;
return *this;
}
RakNet::RakString& RakString::URLDecode(void)
{
RakString result;
size_t strLen = strlen(sharedString->c_str);
result.Allocate(strLen);
char *output=result.sharedString->c_str;
unsigned int outputIndex=0;
char c;
char hexDigits[2];
char hexValues[2];
unsigned int i;
for (i=0; i < strLen; i++)
{
c=sharedString->c_str[i];
if (c=='%')
{
hexDigits[0]=sharedString->c_str[++i];
hexDigits[1]=sharedString->c_str[++i];
if (hexDigits[0]==' ')
hexValues[0]=0;
if (hexDigits[0]>='A' && hexDigits[0]<='F')
hexValues[0]=hexDigits[0]-'A'+10;
if (hexDigits[0]>='a' && hexDigits[0]<='f')
hexValues[0]=hexDigits[0]-'a'+10;
else
hexValues[0]=hexDigits[0]-'0';
if (hexDigits[1]>='A' && hexDigits[1]<='F')
hexValues[1]=hexDigits[1]-'A'+10;
if (hexDigits[1]>='a' && hexDigits[1]<='f')
hexValues[1]=hexDigits[1]-'a'+10;
else
hexValues[1]=hexDigits[1]-'0';
output[outputIndex++]=hexValues[0]*16+hexValues[1];
}
else
{
output[outputIndex++]=c;
}
}
output[outputIndex]=0;
*this = result;
return *this;
}
void RakString::SplitURI(RakNet::RakString &header, RakNet::RakString &domain, RakNet::RakString &path)
{
header.Clear();
domain.Clear();
path.Clear();
size_t strLen = strlen(sharedString->c_str);
char c;
unsigned int i=0;
if (strncmp(sharedString->c_str, "http://", 7)==0)
i+=(unsigned int) strlen("http://");
else if (strncmp(sharedString->c_str, "https://", 8)==0)
i+=(unsigned int) strlen("https://");
if (strncmp(sharedString->c_str, "www.", 4)==0)
i+=(unsigned int) strlen("www.");
if (i!=0)
{
header.Allocate(i+1);
strncpy(header.sharedString->c_str, sharedString->c_str, i);
header.sharedString->c_str[i]=0;
}
domain.Allocate(strLen-i+1);
char *domainOutput=domain.sharedString->c_str;
unsigned int outputIndex=0;
for (; i < strLen; i++)
{
c=sharedString->c_str[i];
if (c=='/')
{
break;
}
else
{
domainOutput[outputIndex++]=sharedString->c_str[i];
}
}
domainOutput[outputIndex]=0;
path.Allocate(strLen-header.GetLength()-outputIndex+1);
outputIndex=0;
char *pathOutput=path.sharedString->c_str;
for (; i < strLen; i++)
{
pathOutput[outputIndex++]=sharedString->c_str[i];
}
pathOutput[outputIndex]=0;
}
RakNet::RakString& RakString::SQLEscape(void)
{
int strLen=(int)GetLength();
int escapedCharacterCount=0;
int index;
for (index=0; index < strLen; index++)
{
if (sharedString->c_str[index]=='\'' ||
sharedString->c_str[index]=='"' ||
sharedString->c_str[index]=='\\')
escapedCharacterCount++;
}
if (escapedCharacterCount==0)
return *this;
Clone();
Realloc(sharedString, strLen+escapedCharacterCount);
int writeIndex, readIndex;
writeIndex = strLen+escapedCharacterCount;
readIndex=strLen;
while (readIndex>=0)
{
if (sharedString->c_str[readIndex]=='\'' ||
sharedString->c_str[readIndex]=='"' ||
sharedString->c_str[readIndex]=='\\')
{
sharedString->c_str[writeIndex--]=sharedString->c_str[readIndex--];
sharedString->c_str[writeIndex--]='\\';
}
else
{
sharedString->c_str[writeIndex--]=sharedString->c_str[readIndex--];
}
}
return *this;
}
RakNet::RakString RakString::FormatForPUTOrPost(const char* type, const char* uri, const char* contentType, const char* body, const char* extraHeaders)
{
RakString out;
RakString host;
RakString remotePath;
RakNet::RakString header;
RakString uriRs;
uriRs = uri;
uriRs.SplitURI(header, host, remotePath);
if (host.IsEmpty() || remotePath.IsEmpty())
return out;
// RakString bodyEncoded = body;
// bodyEncoded.URLEncode();
if (extraHeaders!=0 && extraHeaders[0])
{
out.Set("%s %s HTTP/1.1\r\n"
"%s\r\n"
"Host: %s\r\n"
"Content-Type: %s\r\n"
"Content-Length: %u\r\n"
"\r\n"
"%s",
type,
remotePath.C_String(),
extraHeaders,
host.C_String(),
contentType,
//bodyEncoded.GetLength(),
//bodyEncoded.C_String());
strlen(body),
body);
}
else
{
out.Set("%s %s HTTP/1.1\r\n"
"Host: %s\r\n"
"Content-Type: %s\r\n"
"Content-Length: %u\r\n"
"\r\n"
"%s",
type,
remotePath.C_String(),
host.C_String(),
contentType,
//bodyEncoded.GetLength(),
//bodyEncoded.C_String());
strlen(body),
body);
}
return out;
}
RakString RakString::FormatForPOST(const char* uri, const char* contentType, const char* body, const char* extraHeaders)
{
return FormatForPUTOrPost("POST", uri, contentType, body, extraHeaders);
}
RakString RakString::FormatForPUT(const char* uri, const char* contentType, const char* body, const char* extraHeaders)
{
return FormatForPUTOrPost("PUT", uri, contentType, body, extraHeaders);
}
RakString RakString::FormatForGET(const char* uri, const char* extraHeaders)
{
RakString out;
RakString host;
RakString remotePath;
RakNet::RakString header;
RakNet::RakString uriRs;
uriRs = uri;
uriRs.SplitURI(header, host, remotePath);
if (host.IsEmpty() || remotePath.IsEmpty())
return out;
if (extraHeaders && extraHeaders[0])
{
out.Set("GET %s HTTP/1.1\r\n"
"%s\r\n"
"Host: %s\r\n"
"\r\n",
remotePath.C_String(),
extraHeaders,
host.C_String());
}
else
{
out.Set("GET %s HTTP/1.1\r\n"
"Host: %s\r\n"
"\r\n",
remotePath.C_String(),
host.C_String());
}
return out;
}
RakString RakString::FormatForDELETE(const char* uri, const char* extraHeaders)
{
RakString out;
RakString host;
RakString remotePath;
RakNet::RakString header;
RakNet::RakString uriRs;
uriRs = uri;
uriRs.SplitURI(header, host, remotePath);
if (host.IsEmpty() || remotePath.IsEmpty())
return out;
if (extraHeaders && extraHeaders[0])
{
out.Set("DELETE %s HTTP/1.1\r\n"
"%s\r\n"
"Content-Length: 0\r\n"
"Host: %s\r\n"
"Connection: close\r\n"
"\r\n",
remotePath.C_String(),
extraHeaders,
host.C_String());
}
else
{
out.Set("DELETE %s HTTP/1.1\r\n"
"Content-Length: 0\r\n"
"Host: %s\r\n"
"Connection: close\r\n"
"\r\n",
remotePath.C_String(),
host.C_String());
}
return out;
}
RakNet::RakString& RakString::MakeFilePath(void)
{
if (IsEmpty())
return *this;
RakNet::RakString fixedString = *this;
fixedString.Clone();
for (int i=0; fixedString.sharedString->c_str[i]; i++)
{
#ifdef _WIN32
if (fixedString.sharedString->c_str[i]=='/')
fixedString.sharedString->c_str[i]='\\';
#else
if (fixedString.sharedString->c_str[i]=='\\')
fixedString.sharedString->c_str[i]='/';
#endif
}
#ifdef _WIN32
if (fixedString.sharedString->c_str[strlen(fixedString.sharedString->c_str)-1]!='\\')
{
fixedString+='\\';
}
#else
if (fixedString.sharedString->c_str[strlen(fixedString.sharedString->c_str)-1]!='/')
{
fixedString+='/';
}
#endif
if (fixedString!=*this)
*this = fixedString;
return *this;
}
void RakString::FreeMemory(void)
{
LockMutex();
FreeMemoryNoMutex();
UnlockMutex();
}
void RakString::FreeMemoryNoMutex(void)
{
for (unsigned int i=0; i < freeList.Size(); i++)
{
RakNet::OP_DELETE(freeList[i]->refCountMutex,_FILE_AND_LINE_);
rakFree_Ex(freeList[i], _FILE_AND_LINE_ );
}
freeList.Clear(false, _FILE_AND_LINE_);
}
void RakString::Serialize(BitStream *bs) const
{
Serialize(sharedString->c_str, bs);
}
void RakString::Serialize(const char *str, BitStream *bs)
{
unsigned short l = (unsigned short) strlen(str);
bs->Write(l);
bs->WriteAlignedBytes((const unsigned char*) str, (const unsigned int) l);
}
void RakString::SerializeCompressed(BitStream *bs, uint8_t languageId, bool writeLanguageId) const
{
SerializeCompressed(C_String(), bs, languageId, writeLanguageId);
}
void RakString::SerializeCompressed(const char *str, BitStream *bs, uint8_t languageId, bool writeLanguageId)
{
if (writeLanguageId)
bs->WriteCompressed(languageId);
StringCompressor::Instance()->EncodeString(str,0xFFFF,bs,languageId);
}
bool RakString::Deserialize(BitStream *bs)
{
Clear();
bool b;
unsigned short l;
b=bs->Read(l);
if (l>0)
{
Allocate(((unsigned int) l)+1);
b=bs->ReadAlignedBytes((unsigned char*) sharedString->c_str, l);
if (b)
sharedString->c_str[l]=0;
else
Clear();
}
else
bs->AlignReadToByteBoundary();
return b;
}
bool RakString::Deserialize(char *str, BitStream *bs)
{
bool b;
unsigned short l;
b=bs->Read(l);
if (b && l>0)
b=bs->ReadAlignedBytes((unsigned char*) str, l);
if (b==false)
str[0]=0;
str[l]=0;
return b;
}
bool RakString::DeserializeCompressed(BitStream *bs, bool readLanguageId)
{
uint8_t languageId;
if (readLanguageId)
bs->ReadCompressed(languageId);
else
languageId=0;
return StringCompressor::Instance()->DecodeString(this,0xFFFF,bs,languageId);
}
bool RakString::DeserializeCompressed(char *str, BitStream *bs, bool readLanguageId)
{
uint8_t languageId;
if (readLanguageId)
bs->ReadCompressed(languageId);
else
languageId=0;
return StringCompressor::Instance()->DecodeString(str,0xFFFF,bs,languageId);
}
const char *RakString::ToString(int64_t i)
{
static int index=0;
static char buff[64][64];
#if defined(_WIN32)
sprintf(buff[index], "%I64d", i);
#else
sprintf(buff[index], "%lld", (long long unsigned int) i);
#endif
int lastIndex=index;
if (++index==64)
index=0;
return buff[lastIndex];
}
const char *RakString::ToString(uint64_t i)
{
static int index=0;
static char buff[64][64];
#if defined(_WIN32)
sprintf(buff[index], "%I64u", i);
#else
sprintf(buff[index], "%llu", (long long unsigned int) i);
#endif
int lastIndex=index;
if (++index==64)
index=0;
return buff[lastIndex];
}
void RakString::Clear(void)
{
Free();
}
void RakString::Allocate(size_t len)
{
RakString::LockMutex();
// sharedString = RakString::pool.Allocate( _FILE_AND_LINE_ );
if (RakString::freeList.Size()==0)
{
//RakString::sharedStringFreeList=(RakString::SharedString*) rakRealloc_Ex(RakString::sharedStringFreeList,(RakString::sharedStringFreeListAllocationCount+1024)*sizeof(RakString::SharedString), _FILE_AND_LINE_);
unsigned i;
for (i=0; i < 128; i++)
{
// RakString::freeList.Insert(RakString::sharedStringFreeList+i+RakString::sharedStringFreeListAllocationCount);
// RakString::freeList.Insert((RakString::SharedString*)rakMalloc_Ex(sizeof(RakString::SharedString), _FILE_AND_LINE_), _FILE_AND_LINE_);
RakString::SharedString *ss;
ss = (RakString::SharedString*) rakMalloc_Ex(sizeof(RakString::SharedString), _FILE_AND_LINE_);
ss->refCountMutex=RakNet::OP_NEW<SimpleMutex>(_FILE_AND_LINE_);
RakString::freeList.Insert(ss, _FILE_AND_LINE_);
}
//RakString::sharedStringFreeListAllocationCount+=1024;
}
sharedString = RakString::freeList[RakString::freeList.Size()-1];
RakString::freeList.RemoveAtIndex(RakString::freeList.Size()-1);
RakString::UnlockMutex();
const size_t smallStringSize = 128-sizeof(unsigned int)-sizeof(size_t)-sizeof(char*)*2;
sharedString->refCount=1;
if (len <= smallStringSize)
{
sharedString->bytesUsed=smallStringSize;
sharedString->c_str=sharedString->smallString;
}
else
{
sharedString->bytesUsed=len<<1;
sharedString->bigString=(char*)rakMalloc_Ex(sharedString->bytesUsed, _FILE_AND_LINE_);
sharedString->c_str=sharedString->bigString;
}
}
void RakString::Assign(const char *str)
{
if (str==0 || str[0]==0)
{
sharedString=&emptyString;
return;
}
size_t len = strlen(str)+1;
Allocate(len);
memcpy(sharedString->c_str, str, len);
}
void RakString::Assign(const char *str, va_list ap)
{
if (str==0 || str[0]==0)
{
sharedString=&emptyString;
return;
}
char stackBuff[512];
if (_vsnprintf(stackBuff, 512, str, ap)!=-1
#ifndef _WIN32
// Here Windows will return -1 if the string is too long; Linux just truncates the string.
&& strlen(str) <511
#endif
)
{
Assign(stackBuff);
return;
}
char *buff=0, *newBuff;
size_t buffSize=8096;
while (1)
{
newBuff = (char*) rakRealloc_Ex(buff, buffSize,__FILE__,__LINE__);
if (newBuff==0)
{
notifyOutOfMemory(_FILE_AND_LINE_);
if (buff!=0)
{
Assign(buff);
rakFree_Ex(buff,__FILE__,__LINE__);
}
else
{
Assign(stackBuff);
}
return;
}
buff=newBuff;
if (_vsnprintf(buff, buffSize, str, ap)!=-1)
{
Assign(buff);
rakFree_Ex(buff,__FILE__,__LINE__);
return;
}
buffSize*=2;
}
}
RakNet::RakString RakString::Assign(const char *str,size_t pos, size_t n )
{
size_t incomingLen=strlen(str);
Clone();
if (str==0 || str[0]==0||pos>=incomingLen)
{
sharedString=&emptyString;
return (*this);
}
if (pos+n>=incomingLen)
{
n=incomingLen-pos;
}
const char * tmpStr=&(str[pos]);
size_t len = n+1;
Allocate(len);
memcpy(sharedString->c_str, tmpStr, len);
sharedString->c_str[n]=0;
return (*this);
}
RakNet::RakString RakString::NonVariadic(const char *str)
{
RakNet::RakString rs;
rs=str;
return rs;
}
unsigned long RakString::ToInteger(const char *str)
{
unsigned long hash = 0;
int c;
while ((c = *str++))
hash = c + (hash << 6) + (hash << 16) - hash;
return hash;
}
unsigned long RakString::ToInteger(const RakString &rs)
{
return RakString::ToInteger(rs.C_String());
}
int RakString::ReadIntFromSubstring(const char *str, size_t pos, size_t n)
{
char tmp[32];
if (n >= 32)
return 0;
for (size_t i=0; i < n; i++)
tmp[i]=str[i+pos];
return atoi(tmp);
}
void RakString::AppendBytes(const char *bytes, unsigned int count)
{
if (IsEmpty())
{
Allocate(count);
memcpy(sharedString->c_str, bytes, count+1);
sharedString->c_str[count]=0;
}
else
{
Clone();
unsigned int length=(unsigned int) GetLength();
Realloc(sharedString, count+length+1);
memcpy(sharedString->c_str+length, bytes, count);
sharedString->c_str[length+count]=0;
}
}
void RakString::Clone(void)
{
RakAssert(sharedString!=&emptyString);
if (sharedString==&emptyString)
{
return;
}
// Empty or solo then no point to cloning
sharedString->refCountMutex->Lock();
if (sharedString->refCount==1)
{
sharedString->refCountMutex->Unlock();
return;
}
sharedString->refCount--;
sharedString->refCountMutex->Unlock();
Assign(sharedString->c_str);
}
void RakString::Free(void)
{
if (sharedString==&emptyString)
return;
sharedString->refCountMutex->Lock();
sharedString->refCount--;
if (sharedString->refCount==0)
{
sharedString->refCountMutex->Unlock();
const size_t smallStringSize = 128-sizeof(unsigned int)-sizeof(size_t)-sizeof(char*)*2;
if (sharedString->bytesUsed>smallStringSize)
rakFree_Ex(sharedString->bigString, _FILE_AND_LINE_ );
/*
poolMutex->Lock();
pool.Release(sharedString);
poolMutex->Unlock();
*/
RakString::LockMutex();
RakString::freeList.Insert(sharedString, _FILE_AND_LINE_);
RakString::UnlockMutex();
sharedString=&emptyString;
}
else
{
sharedString->refCountMutex->Unlock();
}
sharedString=&emptyString;
}
unsigned char RakString::ToLower(unsigned char c)
{
if (c >= 'A' && c <= 'Z')
return c-'A'+'a';
return c;
}
unsigned char RakString::ToUpper(unsigned char c)
{
if (c >= 'a' && c <= 'z')
return c-'a'+'A';
return c;
}
void RakString::LockMutex(void)
{
GetPoolMutex().Lock();
}
void RakString::UnlockMutex(void)
{
GetPoolMutex().Unlock();
}
/*
#include "RakString.h"
#include <string>
#include "GetTime.h"
using namespace RakNet;
int main(void)
{
RakString s3("Hello world");
RakString s5=s3;
RakString s1;
RakString s2('a');
RakString s4("%i %f", 5, 6.0);
RakString s6=s3;
RakString s7=s6;
RakString s8=s6;
RakString s9;
s9=s9;
RakString s10(s3);
RakString s11=s10 + s4 + s9 + s2;
s11+=RakString("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
RakString s12("Test");
s12+=s11;
bool b1 = s12==s12;
s11=s5;
s12.ToUpper();
s12.ToLower();
RakString s13;
bool b3 = s13.IsEmpty();
s13.Set("blah %s", s12.C_String());
bool b4 = s13.IsEmpty();
size_t i1=s13.GetLength();
s3.Clear(_FILE_AND_LINE_);
s4.Clear(_FILE_AND_LINE_);
s5.Clear(_FILE_AND_LINE_);
s5.Clear(_FILE_AND_LINE_);
s6.Printf();
s7.Printf();
RAKNET_DEBUG_PRINTF("\n");
static const int repeatCount=750;
DataStructures::List<RakString> rakStringList;
DataStructures::List<std::string> stdStringList;
DataStructures::List<char*> referenceStringList;
char *c;
unsigned i;
RakNet::TimeMS beforeReferenceList, beforeRakString, beforeStdString, afterStdString;
unsigned loop;
for (loop=0; loop<2; loop++)
{
beforeReferenceList=RakNet::GetTimeMS();
for (i=0; i < repeatCount; i++)
{
c = RakNet::OP_NEW_ARRAY<char >(56,_FILE_AND_LINE_ );
strcpy(c, "Aalsdkj alsdjf laksdjf ;lasdfj ;lasjfd");
referenceStringList.Insert(c);
}
beforeRakString=RakNet::GetTimeMS();
for (i=0; i < repeatCount; i++)
rakStringList.Insert("Aalsdkj alsdjf laksdjf ;lasdfj ;lasjfd");
beforeStdString=RakNet::GetTimeMS();
for (i=0; i < repeatCount; i++)
stdStringList.Insert("Aalsdkj alsdjf laksdjf ;lasdfj ;lasjfd");
afterStdString=RakNet::GetTimeMS();
RAKNET_DEBUG_PRINTF("Insertion 1 Ref=%i Rak=%i, Std=%i\n", beforeRakString-beforeReferenceList, beforeStdString-beforeRakString, afterStdString-beforeStdString);
beforeReferenceList=RakNet::GetTimeMS();
for (i=0; i < repeatCount; i++)
{
RakNet::OP_DELETE_ARRAY(referenceStringList[0], _FILE_AND_LINE_);
referenceStringList.RemoveAtIndex(0);
}
beforeRakString=RakNet::GetTimeMS();
for (i=0; i < repeatCount; i++)
rakStringList.RemoveAtIndex(0);
beforeStdString=RakNet::GetTimeMS();
for (i=0; i < repeatCount; i++)
stdStringList.RemoveAtIndex(0);
afterStdString=RakNet::GetTimeMS();
RAKNET_DEBUG_PRINTF("RemoveHead Ref=%i Rak=%i, Std=%i\n", beforeRakString-beforeReferenceList, beforeStdString-beforeRakString, afterStdString-beforeStdString);
beforeReferenceList=RakNet::GetTimeMS();
for (i=0; i < repeatCount; i++)
{
c = RakNet::OP_NEW_ARRAY<char >(56, _FILE_AND_LINE_ );
strcpy(c, "Aalsdkj alsdjf laksdjf ;lasdfj ;lasjfd");
referenceStringList.Insert(0);
}
beforeRakString=RakNet::GetTimeMS();
for (i=0; i < repeatCount; i++)
rakStringList.Insert("Aalsdkj alsdjf laksdjf ;lasdfj ;lasjfd");
beforeStdString=RakNet::GetTimeMS();
for (i=0; i < repeatCount; i++)
stdStringList.Insert("Aalsdkj alsdjf laksdjf ;lasdfj ;lasjfd");
afterStdString=RakNet::GetTimeMS();
RAKNET_DEBUG_PRINTF("Insertion 2 Ref=%i Rak=%i, Std=%i\n", beforeRakString-beforeReferenceList, beforeStdString-beforeRakString, afterStdString-beforeStdString);
beforeReferenceList=RakNet::GetTimeMS();
for (i=0; i < repeatCount; i++)
{
RakNet::OP_DELETE_ARRAY(referenceStringList[referenceStringList.Size()-1], _FILE_AND_LINE_);
referenceStringList.RemoveAtIndex(referenceStringList.Size()-1);
}
beforeRakString=RakNet::GetTimeMS();
for (i=0; i < repeatCount; i++)
rakStringList.RemoveAtIndex(rakStringList.Size()-1);
beforeStdString=RakNet::GetTimeMS();
for (i=0; i < repeatCount; i++)
stdStringList.RemoveAtIndex(stdStringList.Size()-1);
afterStdString=RakNet::GetTimeMS();
RAKNET_DEBUG_PRINTF("RemoveTail Ref=%i Rak=%i, Std=%i\n", beforeRakString-beforeReferenceList, beforeStdString-beforeRakString, afterStdString-beforeStdString);
}
printf("Done.");
char str[128];
Gets(str, sizeof(str));
return 1;
}
*/