1 #include "RakString.h"
2 #include "RakAssert.h"
3 #include "RakMemoryOverride.h"
4 #include "BitStream.h"
5 #include <stdarg.h>
6 #include <string.h>
7 #include "LinuxStrings.h"
8 #include "StringCompressor.h"
9 #include "SimpleMutex.h"
10 
11 using namespace RakNet;
12 
13 //DataStructures::MemoryPool<RakString::SharedString> RakString::pool;
14 unsigned int RakString::nPos=(unsigned int) -1;
15 RakString::SharedString RakString::emptyString={0,0,0,(char*) "",(char*) ""};
16 //RakString::SharedString *RakString::sharedStringFreeList=0;
17 //unsigned int RakString::sharedStringFreeListAllocationCount=0;
18 DataStructures::List<RakString::SharedString*> RakString::freeList;
19 
20 class RakStringCleanup
21 {
22 public:
~RakStringCleanup()23 	~RakStringCleanup()
24 	{
25 		RakNet::RakString::FreeMemoryNoMutex();
26 	}
27 };
28 
29 static RakStringCleanup cleanup;
30 
GetPoolMutex(void)31 SimpleMutex& GetPoolMutex(void)
32 {
33 	static SimpleMutex poolMutex;
34 	return poolMutex;
35 }
36 
RakStringComp(RakString const & key,RakString const & data)37 int RakString::RakStringComp( RakString const &key, RakString const &data )
38 {
39 	return key.StrCmp(data);
40 }
41 
RakString()42 RakString::RakString()
43 {
44 	sharedString=&emptyString;
45 }
RakString(RakString::SharedString * _sharedString)46 RakString::RakString( RakString::SharedString *_sharedString )
47 {
48 	sharedString=_sharedString;
49 }
RakString(char input)50 RakString::RakString(char input)
51 {
52 	char str[2];
53 	str[0]=input;
54 	str[1]=0;
55 	Assign(str);
56 }
RakString(unsigned char input)57 RakString::RakString(unsigned char input)
58 {
59 	char str[2];
60 	str[0]=(char) input;
61 	str[1]=0;
62 	Assign(str);
63 }
RakString(const unsigned char * format,...)64 RakString::RakString(const unsigned char *format, ...){
65 	va_list ap;
66 	va_start(ap, format);
67 	Assign((const char*) format,ap);
68 }
RakString(const char * format,...)69 RakString::RakString(const char *format, ...){
70 	va_list ap;
71 	va_start(ap, format);
72 	Assign(format,ap);
73 }
RakString(const RakString & rhs)74 RakString::RakString( const RakString & rhs)
75 {
76 	if (rhs.sharedString==&emptyString)
77 	{
78 		sharedString=&emptyString;
79 		return;
80 	}
81 
82 	rhs.sharedString->refCountMutex->Lock();
83 	if (rhs.sharedString->refCount==0)
84 	{
85 		sharedString=&emptyString;
86 	}
87 	else
88 	{
89 		rhs.sharedString->refCount++;
90 		sharedString=rhs.sharedString;
91 	}
92 	rhs.sharedString->refCountMutex->Unlock();
93 }
~RakString()94 RakString::~RakString()
95 {
96 	Free();
97 }
operator =(const RakString & rhs)98 RakString& RakString::operator = ( const RakString& rhs )
99 {
100 	Free();
101 	if (rhs.sharedString==&emptyString)
102 		return *this;
103 
104 	rhs.sharedString->refCountMutex->Lock();
105 	if (rhs.sharedString->refCount==0)
106 	{
107 		sharedString=&emptyString;
108 	}
109 	else
110 	{
111 		sharedString=rhs.sharedString;
112 		sharedString->refCount++;
113 	}
114 	rhs.sharedString->refCountMutex->Unlock();
115 	return *this;
116 }
operator =(const char * str)117 RakString& RakString::operator = ( const char *str )
118 {
119 	Free();
120 	Assign(str);
121 	return *this;
122 }
operator =(char * str)123 RakString& RakString::operator = ( char *str )
124 {
125 	return operator = ((const char*)str);
126 }
operator =(const unsigned char * str)127 RakString& RakString::operator = ( const unsigned char *str )
128 {
129 	return operator = ((const char*)str);
130 }
operator =(char unsigned * str)131 RakString& RakString::operator = ( char unsigned *str )
132 {
133 	return operator = ((const char*)str);
134 }
operator =(const char c)135 RakString& RakString::operator = ( const char c )
136 {
137 	char buff[2];
138 	buff[0]=c;
139 	buff[1]=0;
140 	return operator = ((const char*)buff);
141 }
Realloc(SharedString * sharedString,size_t bytes)142 void RakString::Realloc(SharedString *sharedString, size_t bytes)
143 {
144 	if (bytes<=sharedString->bytesUsed)
145 		return;
146 	RakAssert(bytes>0);
147 	size_t oldBytes = sharedString->bytesUsed;
148 	size_t newBytes;
149 	const size_t smallStringSize = 128-sizeof(unsigned int)-sizeof(size_t)-sizeof(char*)*2;
150 	newBytes = GetSizeToAllocate(bytes);
151 	if (oldBytes <=(size_t) smallStringSize && newBytes > (size_t) smallStringSize)
152 	{
153 		sharedString->bigString=(char*) rakMalloc_Ex(newBytes, __FILE__, __LINE__);
154 		strcpy(sharedString->bigString, sharedString->smallString);
155 		sharedString->c_str=sharedString->bigString;
156 	}
157 	else if (oldBytes > smallStringSize)
158 	{
159 		sharedString->bigString=(char*) rakRealloc_Ex(sharedString->bigString,newBytes, __FILE__, __LINE__);
160 		sharedString->c_str=sharedString->bigString;
161 	}
162 	sharedString->bytesUsed=newBytes;
163 }
operator +=(const RakString & rhs)164 RakString& RakString::operator +=( const RakString& rhs)
165 {
166 	if (rhs.IsEmpty())
167 		return *this;
168 
169 	if (IsEmpty())
170 	{
171 		return operator=(rhs);
172 	}
173 	else
174 	{
175 		Clone();
176 		size_t strLen=rhs.GetLength()+GetLength()+1;
177 		Realloc(sharedString, strLen+GetLength());
178 		strcat(sharedString->c_str,rhs.C_String());
179 	}
180 	return *this;
181 }
operator +=(const char * str)182 RakString& RakString::operator +=( const char *str )
183 {
184 	if (str==0 || str[0]==0)
185 		return *this;
186 
187 	if (IsEmpty())
188 	{
189 		Assign(str);
190 	}
191 	else
192 	{
193 		Clone();
194 		size_t strLen=strlen(str)+GetLength()+1;
195 		Realloc(sharedString, strLen);
196 		strcat(sharedString->c_str,str);
197 	}
198 	return *this;
199 }
operator +=(char * str)200 RakString& RakString::operator +=( char *str )
201 {
202 	return operator += ((const char*)str);
203 }
operator +=(const unsigned char * str)204 RakString& RakString::operator +=( const unsigned char *str )
205 {
206 	return operator += ((const char*)str);
207 }
operator +=(unsigned char * str)208 RakString& RakString::operator +=( unsigned char *str )
209 {
210 	return operator += ((const char*)str);
211 }
operator +=(const char c)212 RakString& RakString::operator +=( const char c )
213 {
214 	char buff[2];
215 	buff[0]=c;
216 	buff[1]=0;
217 	return operator += ((const char*)buff);
218 }
operator [](const unsigned int position) const219 unsigned char RakString::operator[] ( const unsigned int position ) const
220 {
221 	RakAssert(position<GetLength());
222 	return sharedString->c_str[position];
223 }
operator ==(const RakString & rhs) const224 bool RakString::operator==(const RakString &rhs) const
225 {
226 	return strcmp(sharedString->c_str,rhs.sharedString->c_str)==0;
227 }
operator ==(const char * str) const228 bool RakString::operator==(const char *str) const
229 {
230 	return strcmp(sharedString->c_str,str)==0;
231 }
operator ==(char * str) const232 bool RakString::operator==(char *str) const
233 {
234 	return strcmp(sharedString->c_str,str)==0;
235 }
operator <(const RakString & right) const236 bool RakString::operator < ( const RakString& right ) const
237 {
238 	return strcmp(sharedString->c_str,right.C_String()) < 0;
239 }
operator <=(const RakString & right) const240 bool RakString::operator <= ( const RakString& right ) const
241 {
242 	return strcmp(sharedString->c_str,right.C_String()) <= 0;
243 }
operator >(const RakString & right) const244 bool RakString::operator > ( const RakString& right ) const
245 {
246 	return strcmp(sharedString->c_str,right.C_String()) > 0;
247 }
operator >=(const RakString & right) const248 bool RakString::operator >= ( const RakString& right ) const
249 {
250 	return strcmp(sharedString->c_str,right.C_String()) >= 0;
251 }
operator !=(const RakString & rhs) const252 bool RakString::operator!=(const RakString &rhs) const
253 {
254 	return strcmp(sharedString->c_str,rhs.sharedString->c_str)!=0;
255 }
operator !=(const char * str) const256 bool RakString::operator!=(const char *str) const
257 {
258 	return strcmp(sharedString->c_str,str)!=0;
259 }
operator !=(char * str) const260 bool RakString::operator!=(char *str) const
261 {
262 	return strcmp(sharedString->c_str,str)!=0;
263 }
operator +(const RakNet::RakString & lhs,const RakNet::RakString & rhs)264 const RakNet::RakString operator+(const RakNet::RakString &lhs, const RakNet::RakString &rhs)
265 {
266 	if (lhs.IsEmpty() && rhs.IsEmpty())
267 	{
268 		return RakString(&RakString::emptyString);
269 	}
270 	if (lhs.IsEmpty())
271 	{
272 		rhs.sharedString->refCountMutex->Lock();
273 		if (rhs.sharedString->refCount==0)
274 		{
275 			rhs.sharedString->refCountMutex->Unlock();
276 			lhs.sharedString->refCountMutex->Lock();
277 			lhs.sharedString->refCount++;
278 			lhs.sharedString->refCountMutex->Unlock();
279 			return RakString(lhs.sharedString);
280 		}
281 		else
282 		{
283 			rhs.sharedString->refCount++;
284 			rhs.sharedString->refCountMutex->Unlock();
285 			return RakString(rhs.sharedString);
286 		}
287 		// rhs.sharedString->refCountMutex->Unlock();
288 	}
289 	if (rhs.IsEmpty())
290 	{
291 		lhs.sharedString->refCountMutex->Lock();
292 		lhs.sharedString->refCount++;
293 		lhs.sharedString->refCountMutex->Unlock();
294 		return RakString(lhs.sharedString);
295 	}
296 
297 	size_t len1 = lhs.GetLength();
298 	size_t len2 = rhs.GetLength();
299 	size_t allocatedBytes = len1 + len2 + 1;
300 	allocatedBytes = RakString::GetSizeToAllocate(allocatedBytes);
301 	RakString::SharedString *sharedString;
302 
303 	RakString::LockMutex();
304 	// sharedString = RakString::pool.Allocate( __FILE__, __LINE__ );
305 	if (RakString::freeList.Size()==0)
306 	{
307 		//RakString::sharedStringFreeList=(RakString::SharedString*) rakRealloc_Ex(RakString::sharedStringFreeList,(RakString::sharedStringFreeListAllocationCount+1024)*sizeof(RakString::SharedString), __FILE__, __LINE__);
308 		unsigned i;
309 		for (i=0; i < 128; i++)
310 		{
311 		//	RakString::freeList.Insert(RakString::sharedStringFreeList+i+RakString::sharedStringFreeListAllocationCount);
312 			RakString::SharedString *ss;
313 			ss = (RakString::SharedString*) rakMalloc_Ex(sizeof(RakString::SharedString), __FILE__, __LINE__);
314 			ss->refCountMutex=RakNet::OP_NEW<SimpleMutex>(__FILE__,__LINE__);
315 			RakString::freeList.Insert(ss, __FILE__, __LINE__);
316 
317 		}
318 		//RakString::sharedStringFreeListAllocationCount+=1024;
319 	}
320 	sharedString = RakString::freeList[RakString::freeList.Size()-1];
321 	RakString::freeList.RemoveAtIndex(RakString::freeList.Size()-1);
322 	RakString::UnlockMutex();
323 
324 	const int smallStringSize = 128-sizeof(unsigned int)-sizeof(size_t)-sizeof(char*)*2;
325 	sharedString->bytesUsed=allocatedBytes;
326 	sharedString->refCount=1;
327 	if (allocatedBytes <= (size_t) smallStringSize)
328 	{
329 		sharedString->c_str=sharedString->smallString;
330 	}
331 	else
332 	{
333 		sharedString->bigString=(char*)rakMalloc_Ex(sharedString->bytesUsed, __FILE__, __LINE__);
334 		sharedString->c_str=sharedString->bigString;
335 	}
336 
337 	strcpy(sharedString->c_str, lhs);
338 	strcat(sharedString->c_str, rhs);
339 
340 	return RakString(sharedString);
341 }
ToLower(void)342 const char * RakString::ToLower(void)
343 {
344 	Clone();
345 
346 	size_t strLen = strlen(sharedString->c_str);
347 	unsigned i;
348 	for (i=0; i < strLen; i++)
349 		sharedString->c_str[i]=ToLower(sharedString->c_str[i]);
350 	return sharedString->c_str;
351 }
ToUpper(void)352 const char * RakString::ToUpper(void)
353 {
354 	Clone();
355 
356 	size_t strLen = strlen(sharedString->c_str);
357 	unsigned i;
358 	for (i=0; i < strLen; i++)
359 		sharedString->c_str[i]=ToUpper(sharedString->c_str[i]);
360 	return sharedString->c_str;
361 }
Set(const char * format,...)362 void RakString::Set(const char *format, ...)
363 {
364 	va_list ap;
365 	va_start(ap, format);
366 	Clear();
367 	Assign(format,ap);
368 }
IsEmpty(void) const369 bool RakString::IsEmpty(void) const
370 {
371 	return sharedString==&emptyString;
372 }
GetLength(void) const373 size_t RakString::GetLength(void) const
374 {
375 	return strlen(sharedString->c_str);
376 }
Replace(unsigned index,unsigned count,unsigned char c)377 void RakString::Replace(unsigned index, unsigned count, unsigned char c)
378 {
379 	RakAssert(index+count < GetLength());
380 	Clone();
381 	unsigned countIndex=0;
382 	while (countIndex<count)
383 	{
384 		sharedString->c_str[index]=c;
385 		index++;
386 		countIndex++;
387 	}
388 }
SetChar(unsigned index,unsigned char c)389 void RakString::SetChar( unsigned index, unsigned char c )
390 {
391 	RakAssert(index < GetLength());
392 	Clone();
393 	sharedString->c_str[index]=c;
394 }
SetChar(unsigned index,RakNet::RakString s)395 void RakString::SetChar( unsigned index, RakNet::RakString s )
396 {
397 	RakAssert(index < GetLength());
398 	Clone();
399 	RakNet::RakString firstHalf = SubStr(0, index);
400 	RakNet::RakString secondHalf = SubStr(index+1, (unsigned int)-1);
401 	*this = firstHalf;
402 	*this += s;
403 	*this += secondHalf;
404 }
405 
Find(const char * stringToFind,size_t pos)406 size_t RakString::Find(const char *stringToFind,size_t pos)
407 {
408 	size_t len=GetLength();
409 	if (pos>=len || stringToFind==0 || stringToFind[0]==0)
410 	{
411 		return nPos;
412 	}
413 	size_t matchLen= strlen(stringToFind);
414 	size_t matchPos=0;
415 	size_t iStart=0;
416 
417 	for (size_t i=pos;i<len;i++)
418 	{
419 		if (stringToFind[matchPos]==sharedString->c_str[i])
420 		{
421 			if(matchPos==0)
422 			{
423 				iStart=i;
424 			}
425 			matchPos++;
426 		}
427 		else
428 		{
429 			matchPos=0;
430 		}
431 
432 		if (matchPos>=matchLen)
433 		{
434 			return iStart;
435 		}
436 	}
437 
438 	return nPos;
439 }
440 
Truncate(unsigned length)441 void RakString::Truncate(unsigned length)
442 {
443 	if (length < GetLength())
444 	{
445 		SetChar(length, 0);
446 	}
447 }
SubStr(unsigned int index,unsigned int count) const448 RakString RakString::SubStr(unsigned int index, unsigned int count) const
449 {
450 	size_t length = GetLength();
451 	if (index >= length || count==0)
452 		return RakString();
453 	RakString copy;
454 	size_t numBytes = length-index;
455 	if (count < numBytes)
456 		numBytes=count;
457 	copy.Allocate(numBytes+1);
458 	size_t i;
459 	for (i=0; i < numBytes; i++)
460 		copy.sharedString->c_str[i]=sharedString->c_str[index+i];
461 	copy.sharedString->c_str[i]=0;
462 	return copy;
463 }
Erase(unsigned int index,unsigned int count)464 void RakString::Erase(unsigned int index, unsigned int count)
465 {
466 	size_t len = GetLength();
467 	RakAssert(index+count <= len);
468 
469 	Clone();
470 	unsigned i;
471 	for (i=index; i < len-count; i++)
472 	{
473 		sharedString->c_str[i]=sharedString->c_str[i+count];
474 	}
475 	sharedString->c_str[i]=0;
476 }
TerminateAtLastCharacter(char c)477 void RakString::TerminateAtLastCharacter(char c)
478 {
479 	int i, len=(int) GetLength();
480 	for (i=len-1; i >= 0; i--)
481 	{
482 		if (sharedString->c_str[i]==c)
483 		{
484 			Clone();
485 			sharedString->c_str[i]=0;
486 			return;
487 		}
488 	}
489 }
TerminateAtFirstCharacter(char c)490 void RakString::TerminateAtFirstCharacter(char c)
491 {
492 	unsigned int i, len=(unsigned int) GetLength();
493 	for (i=0; i < len; i++)
494 	{
495 		if (sharedString->c_str[i]==c)
496 		{
497 			Clone();
498 			sharedString->c_str[i]=0;
499 			return;
500 		}
501 	}
502 }
RemoveCharacter(char c)503 void RakString::RemoveCharacter(char c)
504 {
505 	if (c==0)
506 		return;
507 
508 	unsigned int readIndex, writeIndex=0;
509 	for (readIndex=0; sharedString->c_str[readIndex]; readIndex++)
510 	{
511 		if (sharedString->c_str[readIndex]!=c)
512 			sharedString->c_str[writeIndex++]=sharedString->c_str[readIndex];
513 		else
514 			Clone();
515 	}
516 	sharedString->c_str[writeIndex]=0;
517 }
StrCmp(const RakString & rhs) const518 int RakString::StrCmp(const RakString &rhs) const
519 {
520 	return strcmp(sharedString->c_str, rhs);
521 }
StrICmp(const RakString & rhs) const522 int RakString::StrICmp(const RakString &rhs) const
523 {
524 	return _stricmp(sharedString->c_str, rhs);
525 }
Printf(void)526 void RakString::Printf(void)
527 {
528 	RAKNET_DEBUG_PRINTF("%s", sharedString->c_str);
529 }
FPrintf(FILE * fp)530 void RakString::FPrintf(FILE *fp)
531 {
532 	fprintf(fp,"%s", sharedString->c_str);
533 }
IPAddressMatch(const char * IP)534 bool RakString::IPAddressMatch(const char *IP)
535 {
536 	unsigned characterIndex;
537 
538 	if ( IP == 0 || IP[ 0 ] == 0 || strlen( IP ) > 15 )
539 		return false;
540 
541 	characterIndex = 0;
542 
543 #ifdef _MSC_VER
544 #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
545 #endif
546 	while ( true )
547 	{
548 		if (sharedString->c_str[ characterIndex ] == IP[ characterIndex ] )
549 		{
550 			// Equal characters
551 			if ( IP[ characterIndex ] == 0 )
552 			{
553 				// End of the string and the strings match
554 
555 				return true;
556 			}
557 
558 			characterIndex++;
559 		}
560 
561 		else
562 		{
563 			if ( sharedString->c_str[ characterIndex ] == 0 || IP[ characterIndex ] == 0 )
564 			{
565 				// End of one of the strings
566 				break;
567 			}
568 
569 			// Characters do not match
570 			if ( sharedString->c_str[ characterIndex ] == '*' )
571 			{
572 				// Domain is banned.
573 				return true;
574 			}
575 
576 			// Characters do not match and it is not a *
577 			break;
578 		}
579 	}
580 
581 
582 	// No match found.
583 	return false;
584 }
ContainsNonprintableExceptSpaces(void) const585 bool RakString::ContainsNonprintableExceptSpaces(void) const
586 {
587 	size_t strLen = strlen(sharedString->c_str);
588 	unsigned i;
589 	for (i=0; i < strLen; i++)
590 	{
591 		if (sharedString->c_str[i] < ' ' || sharedString->c_str[i] >126)
592 			return true;
593 	}
594 	return false;
595 }
IsEmailAddress(void) const596 bool RakString::IsEmailAddress(void) const
597 {
598 	if (IsEmpty())
599 		return false;
600 	size_t strLen = strlen(sharedString->c_str);
601 	if (strLen < 6) // a@b.de
602 		return false;
603 	if (sharedString->c_str[strLen-4]!='.' && sharedString->c_str[strLen-3]!='.') // .com, .net., .org, .de
604 		return false;
605 	unsigned i;
606 	// Has non-printable?
607 	for (i=0; i < strLen; i++)
608 	{
609 		if (sharedString->c_str[i] <= ' ' || sharedString->c_str[i] >126)
610 			return false;
611 	}
612 	int atCount=0;
613 	for (i=0; i < strLen; i++)
614 	{
615 		if (sharedString->c_str[i]=='@')
616 		{
617 			atCount++;
618 		}
619 	}
620 	if (atCount!=1)
621 		return false;
622 	int dotCount=0;
623 	for (i=0; i < strLen; i++)
624 	{
625 		if (sharedString->c_str[i]=='.')
626 		{
627 			dotCount++;
628 		}
629 	}
630 	if (dotCount==0)
631 		return false;
632 
633 	// There's more I could check, but this is good enough
634 	return true;
635 }
URLEncode(void)636 RakNet::RakString& RakString::URLEncode(void)
637 {
638 	RakString result;
639 	size_t strLen = strlen(sharedString->c_str);
640 	result.Allocate(strLen*3);
641 	char *output=result.sharedString->c_str;
642 	unsigned int outputIndex=0;
643 	unsigned i;
644 	char c;
645 	for (i=0; i < strLen; i++)
646 	{
647 		c=sharedString->c_str[i];
648 		if (
649 			(c<=47) ||
650 			(c>=58 && c<=64) ||
651 			(c>=91 && c<=96) ||
652 			(c>=123)
653 			)
654 		{
655 			RakNet::RakString tmp("%2X", c);
656 			output[outputIndex++]='%';
657 			output[outputIndex++]=tmp.sharedString->c_str[0];
658 			output[outputIndex++]=tmp.sharedString->c_str[1];
659 		}
660 		else
661 		{
662 			output[outputIndex++]=c;
663 		}
664 	}
665 
666 	output[outputIndex]=0;
667 
668 	*this = result;
669 	return *this;
670 }
URLDecode(void)671 RakNet::RakString& RakString::URLDecode(void)
672 {
673 	RakString result;
674 	size_t strLen = strlen(sharedString->c_str);
675 	result.Allocate(strLen);
676 	char *output=result.sharedString->c_str;
677 	unsigned int outputIndex=0;
678 	char c;
679 	char hexDigits[2];
680 	char hexValues[2];
681 	unsigned int i;
682 	for (i=0; i < strLen; i++)
683 	{
684 		c=sharedString->c_str[i];
685 		if (c=='%')
686 		{
687 			hexDigits[0]=sharedString->c_str[++i];
688 			hexDigits[1]=sharedString->c_str[++i];
689 			if (hexDigits[0]==' ')
690 				hexValues[0]=0;
691 			else if (hexDigits[0]>='A')
692 				hexValues[0]=hexDigits[0]-'A'+10;
693 			else
694 				hexValues[0]=hexDigits[0]-'0';
695 			if (hexDigits[1]>='A')
696 				hexValues[1]=hexDigits[1]-'A'+10;
697 			else
698 				hexValues[1]=hexDigits[1]-'0';
699 			output[outputIndex++]=hexValues[0]*16+hexValues[1];
700 		}
701 		else
702 		{
703 			output[outputIndex++]=c;
704 		}
705 	}
706 
707 	output[outputIndex]=0;
708 
709 	*this = result;
710 	return *this;
711 }
SQLEscape(void)712 RakNet::RakString& RakString::SQLEscape(void)
713 {
714 	int strLen=(int)GetLength();
715 	int escapedCharacterCount=0;
716 	int index;
717 	for (index=0; index < strLen; index++)
718 	{
719 		if (sharedString->c_str[index]=='\'' ||
720 			sharedString->c_str[index]=='"' ||
721 			sharedString->c_str[index]=='\\')
722 			escapedCharacterCount++;
723 	}
724 	if (escapedCharacterCount==0)
725 		return *this;
726 
727 	Clone();
728 	Realloc(sharedString, strLen+escapedCharacterCount);
729 	int writeIndex, readIndex;
730 	writeIndex = strLen+escapedCharacterCount;
731 	readIndex=strLen;
732 	while (readIndex>=0)
733 	{
734 		if (sharedString->c_str[readIndex]=='\'' ||
735 			sharedString->c_str[readIndex]=='"' ||
736 			sharedString->c_str[readIndex]=='\\')
737 		{
738 			sharedString->c_str[writeIndex--]=sharedString->c_str[readIndex--];
739 			sharedString->c_str[writeIndex--]='\\';
740 		}
741 		else
742 		{
743 			sharedString->c_str[writeIndex--]=sharedString->c_str[readIndex--];
744 		}
745 	}
746 	return *this;
747 }
MakeFilePath(void)748 RakNet::RakString& RakString::MakeFilePath(void)
749 {
750 	if (IsEmpty())
751 		return *this;
752 
753 	RakNet::RakString fixedString = *this;
754 	fixedString.Clone();
755 	for (int i=0; fixedString.sharedString->c_str[i]; i++)
756 	{
757 #ifdef _WIN32
758 		if (fixedString.sharedString->c_str[i]=='/')
759 			fixedString.sharedString->c_str[i]='\\';
760 #else
761 		if (fixedString.sharedString->c_str[i]=='\\')
762 			fixedString.sharedString->c_str[i]='/';
763 #endif
764 	}
765 
766 #ifdef _WIN32
767 	if (fixedString.sharedString->c_str[strlen(fixedString.sharedString->c_str)-1]!='\\')
768 	{
769 		fixedString+='\\';
770 	}
771 #else
772 	if (fixedString.sharedString->c_str[strlen(fixedString.sharedString->c_str)-1]!='/')
773 	{
774 		fixedString+='/';
775 	}
776 #endif
777 
778 	if (fixedString!=*this)
779 		*this = fixedString;
780 	return *this;
781 }
FreeMemory(void)782 void RakString::FreeMemory(void)
783 {
784 	LockMutex();
785 	FreeMemoryNoMutex();
786 	UnlockMutex();
787 }
FreeMemoryNoMutex(void)788 void RakString::FreeMemoryNoMutex(void)
789 {
790 	for (unsigned int i=0; i < freeList.Size(); i++)
791 	{
792 		RakNet::OP_DELETE(freeList[i]->refCountMutex,__FILE__,__LINE__);
793 		rakFree_Ex(freeList[i], __FILE__, __LINE__ );
794 	}
795 	freeList.Clear(false, __FILE__, __LINE__);
796 }
Serialize(BitStream * bs) const797 void RakString::Serialize(BitStream *bs) const
798 {
799 	Serialize(sharedString->c_str, bs);
800 }
Serialize(const char * str,BitStream * bs)801 void RakString::Serialize(const char *str, BitStream *bs)
802 {
803 	unsigned short l = (unsigned short) strlen(str);
804 	bs->Write(l);
805 	bs->WriteAlignedBytes((const unsigned char*) str, (const unsigned int) l);
806 }
SerializeCompressed(BitStream * bs,int languageId,bool writeLanguageId) const807 void RakString::SerializeCompressed(BitStream *bs, int languageId, bool writeLanguageId) const
808 {
809 	SerializeCompressed(C_String(), bs, languageId, writeLanguageId);
810 }
SerializeCompressed(const char * str,BitStream * bs,int languageId,bool writeLanguageId)811 void RakString::SerializeCompressed(const char *str, BitStream *bs, int languageId, bool writeLanguageId)
812 {
813 	if (writeLanguageId)
814 		bs->WriteCompressed(languageId);
815 	stringCompressor->EncodeString(str,0xFFFF,bs,languageId);
816 }
Deserialize(BitStream * bs)817 bool RakString::Deserialize(BitStream *bs)
818 {
819 	Clear();
820 
821 	bool b;
822 	unsigned short l;
823 	b=bs->Read(l);
824 	if (l>0)
825 	{
826 		Allocate(((unsigned int) l)+1);
827 		b=bs->ReadAlignedBytes((unsigned char*) sharedString->c_str, l);
828 		if (b)
829 			sharedString->c_str[l]=0;
830 		else
831 			Clear();
832 	}
833 	else
834 		bs->AlignReadToByteBoundary();
835 	return b;
836 }
Deserialize(char * str,BitStream * bs)837 bool RakString::Deserialize(char *str, BitStream *bs)
838 {
839 	bool b;
840 	unsigned short l;
841 	b=bs->Read(l);
842 	if (b && l>0)
843 		b=bs->ReadAlignedBytes((unsigned char*) str, l);
844 
845 	if (b==false)
846 		str[0]=0;
847 
848 	str[l]=0;
849 	return b;
850 }
DeserializeCompressed(BitStream * bs,bool readLanguageId)851 bool RakString::DeserializeCompressed(BitStream *bs, bool readLanguageId)
852 {
853 	unsigned int languageId;
854 	if (readLanguageId)
855 		bs->ReadCompressed(languageId);
856 	else
857 		languageId=0;
858 	return stringCompressor->DecodeString(this,0xFFFF,bs,languageId);
859 }
DeserializeCompressed(char * str,BitStream * bs,bool readLanguageId)860 bool RakString::DeserializeCompressed(char *str, BitStream *bs, bool readLanguageId)
861 {
862 	unsigned int languageId;
863 	if (readLanguageId)
864 		bs->ReadCompressed(languageId);
865 	else
866 		languageId=0;
867 	return stringCompressor->DecodeString(str,0xFFFF,bs,languageId);
868 }
ToString(int64_t i)869 const char *RakString::ToString(int64_t i)
870 {
871 	static int index=0;
872 	static char buff[64][64];
873 #if defined(_WIN32)
874 	sprintf(buff[index], "%I64d", i);
875 #else
876 	sprintf(buff[index], "%lld", (long long unsigned int) i);
877 #endif
878 	int lastIndex=index;
879 	if (++index==64)
880 		index=0;
881 	return buff[lastIndex];
882 }
ToString(uint64_t i)883 const char *RakString::ToString(uint64_t i)
884 {
885 	static int index=0;
886 	static char buff[64][64];
887 #if defined(_WIN32)
888 	sprintf(buff[index], "%I64u", i);
889 #else
890 	sprintf(buff[index], "%llu", (long long unsigned int) i);
891 #endif
892 	int lastIndex=index;
893 	if (++index==64)
894 		index=0;
895 	return buff[lastIndex];
896 }
Clear(void)897 void RakString::Clear(void)
898 {
899 	Free();
900 }
Allocate(size_t len)901 void RakString::Allocate(size_t len)
902 {
903 	RakString::LockMutex();
904 	// sharedString = RakString::pool.Allocate( __FILE__, __LINE__ );
905 	if (RakString::freeList.Size()==0)
906 	{
907 		//RakString::sharedStringFreeList=(RakString::SharedString*) rakRealloc_Ex(RakString::sharedStringFreeList,(RakString::sharedStringFreeListAllocationCount+1024)*sizeof(RakString::SharedString), __FILE__, __LINE__);
908 		unsigned i;
909 		for (i=0; i < 128; i++)
910 		{
911 			//	RakString::freeList.Insert(RakString::sharedStringFreeList+i+RakString::sharedStringFreeListAllocationCount);
912 	//		RakString::freeList.Insert((RakString::SharedString*)rakMalloc_Ex(sizeof(RakString::SharedString), __FILE__, __LINE__), __FILE__, __LINE__);
913 
914 			RakString::SharedString *ss;
915 			ss = (RakString::SharedString*) rakMalloc_Ex(sizeof(RakString::SharedString), __FILE__, __LINE__);
916 			ss->refCountMutex=RakNet::OP_NEW<SimpleMutex>(__FILE__,__LINE__);
917 			RakString::freeList.Insert(ss, __FILE__, __LINE__);
918 		}
919 		//RakString::sharedStringFreeListAllocationCount+=1024;
920 	}
921 	sharedString = RakString::freeList[RakString::freeList.Size()-1];
922 	RakString::freeList.RemoveAtIndex(RakString::freeList.Size()-1);
923 	RakString::UnlockMutex();
924 
925 	const size_t smallStringSize = 128-sizeof(unsigned int)-sizeof(size_t)-sizeof(char*)*2;
926 	sharedString->refCount=1;
927 	if (len <= smallStringSize)
928 	{
929 		sharedString->bytesUsed=smallStringSize;
930 		sharedString->c_str=sharedString->smallString;
931 	}
932 	else
933 	{
934 		sharedString->bytesUsed=len<<1;
935 		sharedString->bigString=(char*)rakMalloc_Ex(sharedString->bytesUsed, __FILE__, __LINE__);
936 		sharedString->c_str=sharedString->bigString;
937 	}
938 }
Assign(const char * str)939 void RakString::Assign(const char *str)
940 {
941 	if (str==0 || str[0]==0)
942 	{
943 		sharedString=&emptyString;
944 		return;
945 	}
946 
947 	size_t len = strlen(str)+1;
948 	Allocate(len);
949 	memcpy(sharedString->c_str, str, len);
950 }
Assign(const char * str,va_list ap)951 void RakString::Assign(const char *str, va_list ap)
952 {
953 	char stackBuff[512];
954 	if (_vsnprintf(stackBuff, 512, str, ap)!=-1
955 #ifndef _WIN32
956 		// Here Windows will return -1 if the string is too long; Linux just truncates the string.
957 		&& strlen(str) <511
958 #endif
959 		)
960 	{
961 		Assign(stackBuff);
962 		return;
963 	}
964 	char *buff=0, *newBuff;
965 	size_t buffSize=8096;
966 	while (1)
967 	{
968 		newBuff = (char*) rakRealloc_Ex(buff, buffSize,__FILE__,__LINE__);
969 		if (newBuff==0)
970 		{
971 			notifyOutOfMemory(__FILE__, __LINE__);
972 			if (buff!=0)
973 			{
974 				Assign(buff);
975 				rakFree_Ex(buff,__FILE__,__LINE__);
976 			}
977 			else
978 			{
979 				Assign(stackBuff);
980 			}
981 			return;
982 		}
983 		buff=newBuff;
984 		if (_vsnprintf(buff, buffSize, str, ap)!=-1)
985 		{
986 			Assign(buff);
987 			rakFree_Ex(buff,__FILE__,__LINE__);
988 			return;
989 		}
990 		buffSize*=2;
991 	}
992 }
Assign(const char * str,size_t pos,size_t n)993 RakNet::RakString RakString::Assign(const char *str,size_t pos, size_t n )
994 {
995 	size_t incomingLen=strlen(str);
996 
997 	Clone();
998 
999 	if (str==0 || str[0]==0||pos>=incomingLen)
1000 	{
1001 		sharedString=&emptyString;
1002 		return (*this);
1003 	}
1004 
1005 	if (pos+n>=incomingLen)
1006 	{
1007 	n=incomingLen-pos;
1008 
1009 	}
1010 	const char * tmpStr=&(str[pos]);
1011 
1012 	size_t len = n+1;
1013 	Allocate(len);
1014 	memcpy(sharedString->c_str, tmpStr, len);
1015 	sharedString->c_str[n]=0;
1016 
1017 	return (*this);
1018 }
1019 
NonVariadic(const char * str)1020 RakNet::RakString RakString::NonVariadic(const char *str)
1021 {
1022 	RakNet::RakString rs;
1023 	rs=str;
1024 	return rs;
1025 }
ToInteger(const char * str)1026 unsigned long RakString::ToInteger(const char *str)
1027 {
1028 	unsigned long hash = 0;
1029 	int c;
1030 
1031 	while (c = *str++)
1032 		hash = c + (hash << 6) + (hash << 16) - hash;
1033 
1034 	return hash;
1035 }
ToInteger(const RakString & rs)1036 unsigned long RakString::ToInteger(const RakString &rs)
1037 {
1038 	return RakString::ToInteger(rs.C_String());
1039 }
AppendBytes(const char * bytes,unsigned int count)1040 void RakString::AppendBytes(const char *bytes, unsigned int count)
1041 {
1042 	Clone();
1043 	Realloc(sharedString, count);
1044 	unsigned int length=(unsigned int) GetLength();
1045 	memcpy(sharedString->c_str+length, bytes, count);
1046 	sharedString->c_str[length+count]=0;
1047 }
Clone(void)1048 void RakString::Clone(void)
1049 {
1050 	if (sharedString==&emptyString)
1051 	{
1052 		return;
1053 	}
1054 
1055 	// Empty or solo then no point to cloning
1056 	sharedString->refCountMutex->Lock();
1057 	if (sharedString->refCount==1)
1058 	{
1059 		sharedString->refCountMutex->Unlock();
1060 		return;
1061 	}
1062 
1063 	sharedString->refCount--;
1064 	sharedString->refCountMutex->Unlock();
1065 	Assign(sharedString->c_str);
1066 }
Free(void)1067 void RakString::Free(void)
1068 {
1069 	if (sharedString==&emptyString)
1070 		return;
1071 	sharedString->refCountMutex->Lock();
1072 	sharedString->refCount--;
1073 	if (sharedString->refCount==0)
1074 	{
1075 		sharedString->refCountMutex->Unlock();
1076 		const size_t smallStringSize = 128-sizeof(unsigned int)-sizeof(size_t)-sizeof(char*)*2;
1077 		if (sharedString->bytesUsed>smallStringSize)
1078 			rakFree_Ex(sharedString->bigString, __FILE__, __LINE__ );
1079 		/*
1080 		poolMutex->Lock();
1081 		pool.Release(sharedString);
1082 		poolMutex->Unlock();
1083 		*/
1084 
1085 		RakString::LockMutex();
1086 		RakString::freeList.Insert(sharedString, __FILE__, __LINE__);
1087 		RakString::UnlockMutex();
1088 
1089 		sharedString=&emptyString;
1090 	}
1091 	else
1092 	{
1093 		sharedString->refCountMutex->Unlock();
1094 	}
1095 	sharedString=&emptyString;
1096 }
ToLower(unsigned char c)1097 unsigned char RakString::ToLower(unsigned char c)
1098 {
1099 	if (c >= 'A' && c <= 'Z')
1100 		return c-'A'+'a';
1101 	return c;
1102 }
ToUpper(unsigned char c)1103 unsigned char RakString::ToUpper(unsigned char c)
1104 {
1105 	if (c >= 'a' && c <= 'z')
1106 		return c-'a'+'A';
1107 	return c;
1108 }
LockMutex(void)1109 void RakString::LockMutex(void)
1110 {
1111 	GetPoolMutex().Lock();
1112 }
UnlockMutex(void)1113 void RakString::UnlockMutex(void)
1114 {
1115 	GetPoolMutex().Unlock();
1116 }
1117 
1118 /*
1119 #include "RakString.h"
1120 #include <string>
1121 #include "GetTime.h"
1122 
1123 using namespace RakNet;
1124 
1125 int main(void)
1126 {
1127 	RakString s3("Hello world");
1128 	RakString s5=s3;
1129 
1130 	RakString s1;
1131 	RakString s2('a');
1132 
1133 	RakString s4("%i %f", 5, 6.0);
1134 
1135 	RakString s6=s3;
1136 	RakString s7=s6;
1137 	RakString s8=s6;
1138 	RakString s9;
1139 	s9=s9;
1140 	RakString s10(s3);
1141 	RakString s11=s10 + s4 + s9 + s2;
1142 	s11+=RakString("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
1143 	RakString s12("Test");
1144 	s12+=s11;
1145 	bool b1 = s12==s12;
1146 	s11=s5;
1147 	s12.ToUpper();
1148 	s12.ToLower();
1149 	RakString s13;
1150 	bool b3 = s13.IsEmpty();
1151 	s13.Set("blah %s", s12.C_String());
1152 	bool b4 = s13.IsEmpty();
1153 	size_t i1=s13.GetLength();
1154 	s3.Clear(__FILE__, __LINE__);
1155 	s4.Clear(__FILE__, __LINE__);
1156 	s5.Clear(__FILE__, __LINE__);
1157 	s5.Clear(__FILE__, __LINE__);
1158 	s6.Printf();
1159 	s7.Printf();
1160 	RAKNET_DEBUG_PRINTF("\n");
1161 
1162 	static const int repeatCount=750;
1163 	DataStructures::List<RakString> rakStringList;
1164 	DataStructures::List<std::string> stdStringList;
1165 	DataStructures::List<char*> referenceStringList;
1166 	char *c;
1167 	unsigned i;
1168 	RakNetTime beforeReferenceList, beforeRakString, beforeStdString, afterStdString;
1169 
1170 	unsigned loop;
1171 	for (loop=0; loop<2; loop++)
1172 	{
1173 		beforeReferenceList=RakNet::GetTime();
1174 		for (i=0; i < repeatCount; i++)
1175 		{
1176 			c = RakNet::OP_NEW_ARRAY<char >(56,__FILE__, __LINE__ );
1177 			strcpy(c, "Aalsdkj alsdjf laksdjf ;lasdfj ;lasjfd");
1178 			referenceStringList.Insert(c);
1179 		}
1180 		beforeRakString=RakNet::GetTime();
1181 		for (i=0; i < repeatCount; i++)
1182 			rakStringList.Insert("Aalsdkj alsdjf laksdjf ;lasdfj ;lasjfd");
1183 		beforeStdString=RakNet::GetTime();
1184 
1185 		for (i=0; i < repeatCount; i++)
1186 			stdStringList.Insert("Aalsdkj alsdjf laksdjf ;lasdfj ;lasjfd");
1187 		afterStdString=RakNet::GetTime();
1188 		RAKNET_DEBUG_PRINTF("Insertion 1 Ref=%i Rak=%i, Std=%i\n", beforeRakString-beforeReferenceList, beforeStdString-beforeRakString, afterStdString-beforeStdString);
1189 
1190 		beforeReferenceList=RakNet::GetTime();
1191 		for (i=0; i < repeatCount; i++)
1192 		{
1193 			RakNet::OP_DELETE_ARRAY(referenceStringList[0], __FILE__, __LINE__);
1194 			referenceStringList.RemoveAtIndex(0);
1195 		}
1196 		beforeRakString=RakNet::GetTime();
1197 		for (i=0; i < repeatCount; i++)
1198 			rakStringList.RemoveAtIndex(0);
1199 		beforeStdString=RakNet::GetTime();
1200 		for (i=0; i < repeatCount; i++)
1201 			stdStringList.RemoveAtIndex(0);
1202 		afterStdString=RakNet::GetTime();
1203 		RAKNET_DEBUG_PRINTF("RemoveHead Ref=%i Rak=%i, Std=%i\n", beforeRakString-beforeReferenceList, beforeStdString-beforeRakString, afterStdString-beforeStdString);
1204 
1205 		beforeReferenceList=RakNet::GetTime();
1206 		for (i=0; i < repeatCount; i++)
1207 		{
1208 			c = RakNet::OP_NEW_ARRAY<char >(56, __FILE__, __LINE__ );
1209 			strcpy(c, "Aalsdkj alsdjf laksdjf ;lasdfj ;lasjfd");
1210 			referenceStringList.Insert(0);
1211 		}
1212 		beforeRakString=RakNet::GetTime();
1213 		for (i=0; i < repeatCount; i++)
1214 			rakStringList.Insert("Aalsdkj alsdjf laksdjf ;lasdfj ;lasjfd");
1215 		beforeStdString=RakNet::GetTime();
1216 		for (i=0; i < repeatCount; i++)
1217 			stdStringList.Insert("Aalsdkj alsdjf laksdjf ;lasdfj ;lasjfd");
1218 		afterStdString=RakNet::GetTime();
1219 		RAKNET_DEBUG_PRINTF("Insertion 2 Ref=%i Rak=%i, Std=%i\n", beforeRakString-beforeReferenceList, beforeStdString-beforeRakString, afterStdString-beforeStdString);
1220 
1221 		beforeReferenceList=RakNet::GetTime();
1222 		for (i=0; i < repeatCount; i++)
1223 		{
1224 			RakNet::OP_DELETE_ARRAY(referenceStringList[referenceStringList.Size()-1], __FILE__, __LINE__);
1225 			referenceStringList.RemoveAtIndex(referenceStringList.Size()-1);
1226 		}
1227 		beforeRakString=RakNet::GetTime();
1228 		for (i=0; i < repeatCount; i++)
1229 			rakStringList.RemoveAtIndex(rakStringList.Size()-1);
1230 		beforeStdString=RakNet::GetTime();
1231 		for (i=0; i < repeatCount; i++)
1232 			stdStringList.RemoveAtIndex(stdStringList.Size()-1);
1233 		afterStdString=RakNet::GetTime();
1234 		RAKNET_DEBUG_PRINTF("RemoveTail Ref=%i Rak=%i, Std=%i\n", beforeRakString-beforeReferenceList, beforeStdString-beforeRakString, afterStdString-beforeStdString);
1235 
1236 	}
1237 
1238 	printf("Done.");
1239 	char str[128];
1240 	gets(str);
1241 	return 1;
1242 }
1243 */
1244