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