SLikeNet  0.1.3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
RakString.cpp
Go to the documentation of this file.
1 /*
2  * Original work: Copyright (c) 2014, Oculus VR, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * RakNet License.txt file in the licenses directory of this source tree. An additional grant
7  * of patent rights can be found in the RakNet Patents.txt file in the same directory.
8  *
9  *
10  * Modified work: Copyright (c) 2016-2018, SLikeSoft UG (haftungsbeschränkt)
11  *
12  * This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
13  * license found in the license.txt file in the root directory of this source tree.
14  */
15 
16 #include "slikenet/string.h"
17 #include "slikenet/assert.h"
19 #include "slikenet/BitStream.h"
20 #include <stdarg.h>
21 #include <string.h>
22 #include "slikenet/LinuxStrings.h"
24 #include "slikenet/SimpleMutex.h"
25 #include <stdlib.h>
26 #include "slikenet/Itoa.h"
27 #include <limits>
28 #include "slikenet/linux_adapter.h"
29 #include "slikenet/osx_adapter.h"
30 
31 using namespace SLNet;
32 
33 //DataStructures::MemoryPool<RakString::SharedString> RakString::pool;
34 RakString::SharedString RakString::emptyString={0,0,0,(char*) "",(char*) ""};
35 //RakString::SharedString *RakString::sharedStringFreeList=0;
36 //unsigned int RakString::sharedStringFreeListAllocationCount=0;
38 
39 class RakStringCleanup
40 {
41 public:
42  ~RakStringCleanup()
43  {
45  }
46 };
47 
48 static RakStringCleanup cleanup;
49 
51 {
52  static SimpleMutex poolMutex;
53  return poolMutex;
54 }
55 
56 int SLNet::RakString::RakStringComp( RakString const &key, RakString const &data )
57 {
58  return key.StrCmp(data);
59 }
60 
62 {
64 }
66 {
67  sharedString=_sharedString;
68 }
70 {
71  char str[2];
72  str[0]=input;
73  str[1]=0;
74  Assign(str);
75 }
76 RakString::RakString(unsigned char input)
77 {
78  char str[2];
79  str[0]=(char) input;
80  str[1]=0;
81  Assign(str);
82 }
83 RakString::RakString(const unsigned char *format, ...){
84  va_list ap;
85  va_start(ap, format);
86  Assign((const char*) format,ap);
87  va_end(ap);
88 }
89 RakString::RakString(const char *format, ...){
90  va_list ap;
91  va_start(ap, format);
92  Assign(format,ap);
93  va_end(ap);
94 }
96 {
97  if (rhs.sharedString==&emptyString)
98  {
100  return;
101  }
102 
104  if (rhs.sharedString->refCount==0)
105  {
107  }
108  else
109  {
110  rhs.sharedString->refCount++;
112  }
114 }
116 {
117  Free();
118 }
120 {
121  Free();
122  if (rhs.sharedString==&emptyString)
123  return *this;
124 
126  if (rhs.sharedString->refCount==0)
127  {
129  }
130  else
131  {
134  }
136  return *this;
137 }
139 {
140  Free();
141  Assign(str);
142  return *this;
143 }
145 {
146  return operator = ((const char*)str);
147 }
148 RakString& RakString::operator = ( const unsigned char *str )
149 {
150  return operator = ((const char*)str);
151 }
152 RakString& RakString::operator = ( char unsigned *str )
153 {
154  return operator = ((const char*)str);
155 }
157 {
158  char buff[2];
159  buff[0]=c;
160  buff[1]=0;
161  return operator = ((const char*)buff);
162 }
163 void RakString::Realloc(SharedString *inSharedString, size_t bytes)
164 {
165  if (bytes<= inSharedString->bytesUsed)
166  return;
167 
168  RakAssert(bytes>0);
169  size_t oldBytes = inSharedString->bytesUsed;
170  size_t newBytes;
171  const size_t smallStringSize = 128-sizeof(unsigned int)-sizeof(size_t)-sizeof(char*)*2;
172  newBytes = GetSizeToAllocate(bytes);
173  if (oldBytes <=(size_t) smallStringSize && newBytes > (size_t) smallStringSize)
174  {
175  inSharedString->bigString=(char*) rakMalloc_Ex(newBytes, _FILE_AND_LINE_);
176  strcpy_s(inSharedString->bigString, newBytes, inSharedString->smallString);
177  inSharedString->c_str= inSharedString->bigString;
178  }
179  else if (oldBytes > smallStringSize)
180  {
181  inSharedString->bigString=(char*) rakRealloc_Ex(inSharedString->bigString,newBytes, _FILE_AND_LINE_);
182  inSharedString->c_str= inSharedString->bigString;
183  }
184  inSharedString->bytesUsed=newBytes;
185 }
187 {
188  if (rhs.IsEmpty())
189  return *this;
190 
191  if (IsEmpty())
192  {
193  return operator=(rhs);
194  }
195  else
196  {
197  Clone();
198  size_t strLen=rhs.GetLength()+GetLength()+1;
199  Realloc(sharedString, strLen+GetLength());
201  }
202  return *this;
203 }
205 {
206  if (str==0 || str[0]==0)
207  return *this;
208 
209  if (IsEmpty())
210  {
211  Assign(str);
212  }
213  else
214  {
215  Clone();
216  size_t strLen=strlen(str)+GetLength()+1;
217  Realloc(sharedString, strLen);
218  strcat_s(sharedString->c_str,sharedString->bytesUsed,str);
219  }
220  return *this;
221 }
223 {
224  return operator += ((const char*)str);
225 }
226 RakString& RakString::operator +=( const unsigned char *str )
227 {
228  return operator += ((const char*)str);
229 }
230 RakString& RakString::operator +=( unsigned char *str )
231 {
232  return operator += ((const char*)str);
233 }
235 {
236  char buff[2];
237  buff[0]=c;
238  buff[1]=0;
239  return operator += ((const char*)buff);
240 }
241 unsigned char RakString::operator[] ( const unsigned int position ) const
242 {
243  RakAssert(position<GetLength());
244  return sharedString->c_str[position];
245 }
246 bool RakString::operator==(const RakString &rhs) const
247 {
248  return strcmp(sharedString->c_str,rhs.sharedString->c_str)==0;
249 }
250 bool RakString::operator==(const char *str) const
251 {
252  return strcmp(sharedString->c_str,str)==0;
253 }
254 bool RakString::operator==(char *str) const
255 {
256  return strcmp(sharedString->c_str,str)==0;
257 }
258 bool RakString::operator < ( const RakString& right ) const
259 {
260  return strcmp(sharedString->c_str,right.C_String()) < 0;
261 }
262 bool RakString::operator <= ( const RakString& right ) const
263 {
264  return strcmp(sharedString->c_str,right.C_String()) <= 0;
265 }
266 bool RakString::operator > ( const RakString& right ) const
267 {
268  return strcmp(sharedString->c_str,right.C_String()) > 0;
269 }
270 bool RakString::operator >= ( const RakString& right ) const
271 {
272  return strcmp(sharedString->c_str,right.C_String()) >= 0;
273 }
274 bool RakString::operator!=(const RakString &rhs) const
275 {
276  return strcmp(sharedString->c_str,rhs.sharedString->c_str)!=0;
277 }
278 bool RakString::operator!=(const char *str) const
279 {
280  return strcmp(sharedString->c_str,str)!=0;
281 }
282 bool RakString::operator!=(char *str) const
283 {
284  return strcmp(sharedString->c_str,str)!=0;
285 }
287 {
288  if (lhs.IsEmpty() && rhs.IsEmpty())
289  {
291  }
292  if (lhs.IsEmpty())
293  {
295  if (rhs.sharedString->refCount==0)
296  {
299  lhs.sharedString->refCount++;
301  return RakString(lhs.sharedString);
302  }
303  else
304  {
305  rhs.sharedString->refCount++;
307  return RakString(rhs.sharedString);
308  }
309  // rhs.sharedString->refCountMutex->Unlock();
310  }
311  if (rhs.IsEmpty())
312  {
314  lhs.sharedString->refCount++;
316  return RakString(lhs.sharedString);
317  }
318 
319  size_t len1 = lhs.GetLength();
320  size_t len2 = rhs.GetLength();
321  size_t allocatedBytes = len1 + len2 + 1;
322  allocatedBytes = RakString::GetSizeToAllocate(allocatedBytes);
323  RakString::SharedString *sharedString;
324 
326  // sharedString = RakString::pool.Allocate( _FILE_AND_LINE_ );
327  if (RakString::freeList.Size()==0)
328  {
329  //RakString::sharedStringFreeList=(RakString::SharedString*) rakRealloc_Ex(RakString::sharedStringFreeList,(RakString::sharedStringFreeListAllocationCount+1024)*sizeof(RakString::SharedString), _FILE_AND_LINE_);
330  unsigned i;
331  for (i=0; i < 128; i++)
332  {
333  // RakString::freeList.Insert(RakString::sharedStringFreeList+i+RakString::sharedStringFreeListAllocationCount);
336  ss->refCountMutex= SLNet::OP_NEW<SimpleMutex>(_FILE_AND_LINE_);
338 
339  }
340  //RakString::sharedStringFreeListAllocationCount+=1024;
341  }
342  sharedString = RakString::freeList[RakString::freeList.Size()-1];
345 
346  const int smallStringSize = 128-sizeof(unsigned int)-sizeof(size_t)-sizeof(char*)*2;
347  sharedString->bytesUsed=allocatedBytes;
348  sharedString->refCount=1;
349  if (allocatedBytes <= (size_t) smallStringSize)
350  {
351  sharedString->c_str=sharedString->smallString;
352  }
353  else
354  {
355  sharedString->bigString=(char*)rakMalloc_Ex(sharedString->bytesUsed, _FILE_AND_LINE_);
356  sharedString->c_str=sharedString->bigString;
357  }
358 
359  strcpy_s(sharedString->c_str, sharedString->bytesUsed, lhs);
360  strcat_s(sharedString->c_str, sharedString->bytesUsed, rhs);
361 
362  return RakString(sharedString);
363 }
364 const char * RakString::ToLower(void)
365 {
366  Clone();
367 
368  size_t strLen = strlen(sharedString->c_str);
369  unsigned i;
370  for (i=0; i < strLen; i++)
372  return sharedString->c_str;
373 }
374 const char * RakString::ToUpper(void)
375 {
376  Clone();
377 
378  size_t strLen = strlen(sharedString->c_str);
379  unsigned i;
380  for (i=0; i < strLen; i++)
382  return sharedString->c_str;
383 }
384 void RakString::Set(const char *format, ...)
385 {
386  va_list ap;
387  va_start(ap, format);
388  Clear();
389  Assign(format,ap);
390  va_end(ap);
391 }
392 bool RakString::IsEmpty(void) const
393 {
394  return sharedString==&emptyString;
395 }
396 size_t RakString::GetLength(void) const
397 {
398  return strlen(sharedString->c_str);
399 }
400 // http://porg.es/blog/counting-characters-in-utf-8-strings-is-faster
401 int porges_strlen2(char *s)
402 {
403  int i = 0;
404  int iBefore = 0;
405  int count = 0;
406 
407  while (s[i] > 0)
408 ascii: i++;
409 
410  count += i-iBefore;
411  while (s[i])
412  {
413  if (s[i] > 0)
414  {
415  iBefore = i;
416  goto ascii;
417  }
418  else
419  switch (0xF0 & s[i])
420  {
421  case 0xE0: i += 3; break;
422  case 0xF0: i += 4; break;
423  default: i += 2; break;
424  }
425  ++count;
426  }
427  return count;
428 }
429 size_t RakString::GetLengthUTF8(void) const
430 {
432 }
433 void RakString::Replace(unsigned index, unsigned count, unsigned char c)
434 {
435  RakAssert(index+count < GetLength());
436  Clone();
437  unsigned countIndex=0;
438  while (countIndex<count)
439  {
440  sharedString->c_str[index]=c;
441  index++;
442  countIndex++;
443  }
444 
445 }
446 void RakString::SetChar( unsigned index, unsigned char c )
447 {
448  RakAssert(index < GetLength());
449  Clone();
450  sharedString->c_str[index]=c;
451 }
452 void RakString::SetChar( unsigned index, SLNet::RakString s )
453 {
454  RakAssert(index < GetLength());
455  Clone();
456  SLNet::RakString firstHalf = SubStr(0, index);
457  SLNet::RakString secondHalf = SubStr(index+1, (unsigned int)-1);
458  *this = firstHalf;
459  *this += s;
460  *this += secondHalf;
461 }
462 
463 #ifdef _WIN32
464 WCHAR * RakString::ToWideChar(void)
465 {
466  //
467  // Special case of NULL or empty input string
468  //
469  if ( (sharedString->c_str == NULL) || (*sharedString->c_str == '\0') )
470  {
471  // Return empty string
472  WCHAR* buf = SLNet::OP_NEW_ARRAY<WCHAR>(1, __FILE__, __LINE__);
473  buf[0] = L'\0';
474  return buf;
475  }
476 
477  //
478  // Get size of destination UTF-16 buffer, in WCHAR's
479  //
480  int cchUTF16 = ::MultiByteToWideChar(
481  CP_UTF8, // convert from UTF-8
482  0, // Flags
483  sharedString->c_str, // source UTF-8 string
484  -1, // -1 means string is zero-terminated
485  NULL, // unused - no conversion done in this step
486  0 // request size of destination buffer, in WCHAR's
487  );
488 
489  if ( cchUTF16 == 0 )
490  {
491  RakAssert("RakString::ToWideChar exception from cchUTF16==0" && 0);
492  return 0;
493  }
494 
495  //
496  // Allocate destination buffer to store UTF-16 string
497  //
498  WCHAR * pszUTF16 = SLNet::OP_NEW_ARRAY<WCHAR>(cchUTF16,__FILE__,__LINE__);
499 
500  //
501  // Do the conversion from UTF-8 to UTF-16
502  //
503  int result = ::MultiByteToWideChar(
504  CP_UTF8, // convert from UTF-8
505  0, // Buffer
506  sharedString->c_str, // source UTF-8 string
507  -1, // -1 means string is zero-terminated
508  pszUTF16, // destination buffer
509  cchUTF16 // size of destination buffer, in WCHAR's
510  );
511 
512  if ( result == 0 )
513  {
514  RakAssert("RakString::ToWideChar exception from MultiByteToWideChar" && 0);
515  return 0;
516  }
517 
518  return pszUTF16;
519 }
520 void RakString::DeallocWideChar(WCHAR * w)
521 {
522  SLNet::OP_DELETE_ARRAY(w,__FILE__,__LINE__);
523 }
524 void RakString::FromWideChar(const wchar_t *source)
525 {
526  Clear();
527  size_t bufSize = wcslen(source)*4;
528 
529  // #low - add return value indicating to the caller whether we succeeded (and then handle error case / or thrown an exception)
530  if (bufSize > static_cast<size_t>(std::numeric_limits<int>::max())) {
531  RakAssert("RakString::FromWideChar given string is too long and cannot be converted");
532  return;
533  }
534 
535  Allocate(bufSize);
536  WideCharToMultiByte ( CP_ACP, // ANSI code page
537 
538 
539 
540  WC_COMPOSITECHECK, // Check for accented characters
541 
542  source, // Source Unicode string
543  -1, // -1 means string is zero-terminated
544  sharedString->c_str, // Destination char string
545  static_cast<int>(bufSize), // Size of buffer
546  NULL, // No default character
547  NULL ); // Don't care about this flag
548 
549 
550 }
551 SLNet::RakString RakString::FromWideChar_S(const wchar_t *source)
552 {
553  SLNet::RakString rs;
554  rs.FromWideChar(source);
555  return rs;
556 }
557 #endif
558 size_t RakString::Find(const char *stringToFind,size_t pos)
559 {
560  size_t len=GetLength();
561  if (pos>=len || stringToFind==0 || stringToFind[0]==0)
562  {
563  return (size_t) -1;
564  }
565  size_t matchLen= strlen(stringToFind);
566  size_t matchPos=0;
567  size_t iStart=0;
568 
569  for (size_t i=pos;i<len;i++)
570  {
571  if (stringToFind[matchPos]==sharedString->c_str[i])
572  {
573  if(matchPos==0)
574  {
575  iStart=i;
576  }
577  matchPos++;
578  }
579  else
580  {
581  matchPos=0;
582  }
583 
584  if (matchPos>=matchLen)
585  {
586  return iStart;
587  }
588  }
589 
590  return (size_t) -1;
591 }
592 
593 void RakString::TruncateUTF8(unsigned int length)
594 {
595  int i = 0;
596  unsigned int count = 0;
597 
598  while (sharedString->c_str[i]!=0)
599  {
600  if (count==length)
601  {
602  sharedString->c_str[i]=0;
603  return;
604  }
605  else if (sharedString->c_str[i]>0)
606  {
607  i++;
608  }
609  else
610  {
611  switch (0xF0 & sharedString->c_str[i])
612  {
613  case 0xE0: i += 3; break;
614  case 0xF0: i += 4; break;
615  default: i += 2; break;
616  }
617  }
618 
619  count++;
620  }
621 }
622 
623 void RakString::Truncate(unsigned int length)
624 {
625  if (length < GetLength())
626  {
627  SetChar(length, 0);
628  }
629 }
630 
631 RakString RakString::SubStr(unsigned int index, size_t count) const
632 {
633  size_t length = GetLength();
634  if (index >= length || count==0)
635  return RakString();
636  RakString copy;
637  size_t numBytes = length-index;
638  if (count < numBytes)
639  numBytes=count;
640  copy.Allocate(numBytes+1);
641  size_t i;
642  for (i=0; i < numBytes; i++)
643  copy.sharedString->c_str[i]=sharedString->c_str[index+i];
644  copy.sharedString->c_str[i]=0;
645  return copy;
646 }
647 void RakString::Erase(unsigned int index, unsigned int count)
648 {
649  size_t len = GetLength();
650  RakAssert(index+count <= len);
651 
652  Clone();
653  unsigned i;
654  for (i=index; i < len-count; i++)
655  {
656  sharedString->c_str[i]=sharedString->c_str[i+count];
657  }
658  sharedString->c_str[i]=0;
659 }
661 {
662  int i, len=(int) GetLength();
663  for (i=len-1; i >= 0; i--)
664  {
665  if (sharedString->c_str[i]==c)
666  {
667  Clone();
668  sharedString->c_str[i]=0;
669  return;
670  }
671  }
672 }
674 {
675  int i, len=(int) GetLength();
676  for (i=len-1; i >= 0; i--)
677  {
678  if (sharedString->c_str[i]==c)
679  {
680  ++i;
681  if (i < len)
682  {
683  *this = SubStr(i,GetLength()-i);
684  }
685  return;
686  }
687  }
688 }
690 {
691  unsigned int i, len=(unsigned int) GetLength();
692  for (i=0; i < len; i++)
693  {
694  if (sharedString->c_str[i]==c)
695  {
696  if (i > 0)
697  {
698  Clone();
699  sharedString->c_str[i]=0;
700  }
701  }
702  }
703 }
705 {
706  unsigned int i, len=(unsigned int) GetLength();
707  for (i=0; i < len; i++)
708  {
709  if (sharedString->c_str[i]==c)
710  {
711  ++i;
712  if (i < len)
713  {
714  *this = SubStr(i,GetLength()-i);
715  }
716  return;
717  }
718  }
719 }
721 {
722  int count=0;
723  unsigned int i, len=(unsigned int) GetLength();
724  for (i=0; i < len; i++)
725  {
726  if (sharedString->c_str[i]==c)
727  {
728  ++count;
729  }
730  }
731  return count;
732 }
734 {
735  if (c==0)
736  return;
737 
738  unsigned int readIndex, writeIndex=0;
739  for (readIndex=0; sharedString->c_str[readIndex]; readIndex++)
740  {
741  if (sharedString->c_str[readIndex]!=c)
742  sharedString->c_str[writeIndex++]=sharedString->c_str[readIndex];
743  else
744  Clone();
745  }
746  sharedString->c_str[writeIndex]=0;
747  if (writeIndex==0)
748  Clear();
749 }
750 int RakString::StrCmp(const RakString &rhs) const
751 {
752  return strcmp(sharedString->c_str, rhs.C_String());
753 }
754 int RakString::StrNCmp(const RakString &rhs, size_t num) const
755 {
756  return strncmp(sharedString->c_str, rhs.C_String(), num);
757 }
758 int RakString::StrICmp(const RakString &rhs) const
759 {
760  return _stricmp(sharedString->c_str, rhs.C_String());
761 }
763 {
765 }
766 void RakString::FPrintf(FILE *fp)
767 {
768  fprintf(fp,"%s", sharedString->c_str);
769 }
770 bool RakString::IPAddressMatch(const char *IP)
771 {
772  unsigned characterIndex;
773 
774  if ( IP == 0 || IP[ 0 ] == 0 || strlen( IP ) > 15 )
775  return false;
776 
777  characterIndex = 0;
778 
779  for(;;)
780  {
781  if (sharedString->c_str[ characterIndex ] == IP[ characterIndex ] )
782  {
783  // Equal characters
784  if ( IP[ characterIndex ] == 0 )
785  {
786  // End of the string and the strings match
787 
788  return true;
789  }
790 
791  characterIndex++;
792  }
793 
794  else
795  {
796  if ( sharedString->c_str[ characterIndex ] == 0 || IP[ characterIndex ] == 0 )
797  {
798  // End of one of the strings
799  break;
800  }
801 
802  // Characters do not match
803  if ( sharedString->c_str[ characterIndex ] == '*' )
804  {
805  // Domain is banned.
806  return true;
807  }
808 
809  // Characters do not match and it is not a *
810  break;
811  }
812  }
813 
814 
815  // No match found.
816  return false;
817 }
819 {
820  size_t strLen = strlen(sharedString->c_str);
821  unsigned i;
822  for (i=0; i < strLen; i++)
823  {
824  if (sharedString->c_str[i] < ' ' || sharedString->c_str[i] >126)
825  return true;
826  }
827  return false;
828 }
830 {
831  if (IsEmpty())
832  return false;
833  size_t strLen = strlen(sharedString->c_str);
834  if (strLen < 6) // a@b.de
835  return false;
836  if (sharedString->c_str[strLen-4]!='.' && sharedString->c_str[strLen-3]!='.') // .com, .net., .org, .de
837  return false;
838  unsigned i;
839  // Has non-printable?
840  for (i=0; i < strLen; i++)
841  {
842  if (sharedString->c_str[i] <= ' ' || sharedString->c_str[i] >126)
843  return false;
844  }
845  int atCount=0;
846  for (i=0; i < strLen; i++)
847  {
848  if (sharedString->c_str[i]=='@')
849  {
850  atCount++;
851  }
852  }
853  if (atCount!=1)
854  return false;
855  int dotCount=0;
856  for (i=0; i < strLen; i++)
857  {
858  if (sharedString->c_str[i]=='.')
859  {
860  dotCount++;
861  }
862  }
863  if (dotCount==0)
864  return false;
865 
866  // There's more I could check, but this is good enough
867  return true;
868 }
870 {
871  RakString result;
872  size_t strLen = strlen(sharedString->c_str);
873  result.Allocate(strLen*3);
874  char *output=result.sharedString->c_str;
875  unsigned int outputIndex=0;
876  unsigned i;
877  unsigned char c;
878  for (i=0; i < strLen; i++)
879  {
880  c=sharedString->c_str[i];
881  if (
882  (c<=47) ||
883  (c>=58 && c<=64) ||
884  (c>=91 && c<=96) ||
885  (c>=123)
886  )
887  {
888  char buff[3];
889  Itoa(c, buff, 16);
890  output[outputIndex++]='%';
891  output[outputIndex++]=buff[0];
892  output[outputIndex++]=buff[1];
893  }
894  else
895  {
896  output[outputIndex++]=c;
897  }
898  }
899 
900  output[outputIndex]=0;
901 
902  *this = result;
903  return *this;
904 }
906 {
907  RakString result;
908  size_t strLen = strlen(sharedString->c_str);
909  result.Allocate(strLen);
910  char *output=result.sharedString->c_str;
911  unsigned int outputIndex=0;
912  char c;
913  char hexDigits[2];
914  char hexValues[2];
915  unsigned int i;
916  for (i=0; i < strLen; i++)
917  {
918  c=sharedString->c_str[i];
919  if (c=='%')
920  {
921  hexDigits[0]=sharedString->c_str[++i];
922  hexDigits[1]=sharedString->c_str[++i];
923 
924  if (hexDigits[0]==' ')
925  hexValues[0]=0;
926 
927  if (hexDigits[0]>='A' && hexDigits[0]<='F')
928  hexValues[0]=hexDigits[0]-'A'+10;
929  if (hexDigits[0]>='a' && hexDigits[0]<='f')
930  hexValues[0]=hexDigits[0]-'a'+10;
931  else
932  hexValues[0]=hexDigits[0]-'0';
933 
934  if (hexDigits[1]>='A' && hexDigits[1]<='F')
935  hexValues[1]=hexDigits[1]-'A'+10;
936  if (hexDigits[1]>='a' && hexDigits[1]<='f')
937  hexValues[1]=hexDigits[1]-'a'+10;
938  else
939  hexValues[1]=hexDigits[1]-'0';
940 
941  output[outputIndex++]=hexValues[0]*16+hexValues[1];
942  }
943  else
944  {
945  output[outputIndex++]=c;
946  }
947  }
948 
949  output[outputIndex]=0;
950 
951  *this = result;
952  return *this;
953 }
955 {
956  header.Clear();
957  domain.Clear();
958  path.Clear();
959 
960  size_t strLen = strlen(sharedString->c_str);
961 
962  char c;
963  unsigned int i=0;
964  if (strncmp(sharedString->c_str, "http://", 7)==0)
965  i+=(unsigned int) strlen("http://");
966  else if (strncmp(sharedString->c_str, "https://", 8)==0)
967  i+=(unsigned int) strlen("https://");
968 
969  if (strncmp(sharedString->c_str, "www.", 4)==0)
970  i+=(unsigned int) strlen("www.");
971 
972  if (i!=0)
973  {
974  header.Allocate(i+1);
975  strncpy_s(header.sharedString->c_str, header.sharedString->bytesUsed, sharedString->c_str, i);
976  header.sharedString->c_str[i]=0;
977  }
978 
979 
980  domain.Allocate(strLen-i+1);
981  char *domainOutput=domain.sharedString->c_str;
982  unsigned int outputIndex=0;
983  for (; i < strLen; i++)
984  {
985  c=sharedString->c_str[i];
986  if (c=='/')
987  {
988  break;
989  }
990  else
991  {
992  domainOutput[outputIndex++]=sharedString->c_str[i];
993  }
994  }
995 
996  domainOutput[outputIndex]=0;
997 
998  path.Allocate(strLen-header.GetLength()-outputIndex+1);
999  outputIndex=0;
1000  char *pathOutput=path.sharedString->c_str;
1001  for (; i < strLen; i++)
1002  {
1003  pathOutput[outputIndex++]=sharedString->c_str[i];
1004  }
1005  pathOutput[outputIndex]=0;
1006 }
1008 {
1009  int strLen=(int)GetLength();
1010  int escapedCharacterCount=0;
1011  int index;
1012  for (index=0; index < strLen; index++)
1013  {
1014  if (sharedString->c_str[index]=='\'' ||
1015  sharedString->c_str[index]=='"' ||
1016  sharedString->c_str[index]=='\\')
1017  escapedCharacterCount++;
1018  }
1019  if (escapedCharacterCount==0)
1020  return *this;
1021 
1022  Clone();
1023  Realloc(sharedString, strLen+escapedCharacterCount);
1024  int writeIndex, readIndex;
1025  writeIndex = strLen+escapedCharacterCount;
1026  readIndex=strLen;
1027  while (readIndex>=0)
1028  {
1029  if (sharedString->c_str[readIndex]=='\'' ||
1030  sharedString->c_str[readIndex]=='"' ||
1031  sharedString->c_str[readIndex]=='\\')
1032  {
1033  sharedString->c_str[writeIndex--]=sharedString->c_str[readIndex--];
1034  sharedString->c_str[writeIndex--]='\\';
1035  }
1036  else
1037  {
1038  sharedString->c_str[writeIndex--]=sharedString->c_str[readIndex--];
1039  }
1040  }
1041  return *this;
1042 }
1043 SLNet::RakString RakString::FormatForPUTOrPost(const char* type, const char* uri, const char* contentType, const char* body, const char* extraHeaders)
1044 {
1045  RakString out;
1046  RakString host;
1047  RakString remotePath;
1048  SLNet::RakString header;
1049  RakString uriRs;
1050  uriRs = uri;
1051  uriRs.SplitURI(header, host, remotePath);
1052 
1053  if (host.IsEmpty() || remotePath.IsEmpty())
1054  return out;
1055 
1056 // RakString bodyEncoded = body;
1057 // bodyEncoded.URLEncode();
1058 
1059  if (extraHeaders!=0 && extraHeaders[0])
1060  {
1061  out.Set("%s %s HTTP/1.1\r\n"
1062  "%s\r\n"
1063  "Host: %s\r\n"
1064  "Content-Type: %s\r\n"
1065  "Content-Length: %u\r\n"
1066  "\r\n"
1067  "%s",
1068  type,
1069  remotePath.C_String(),
1070  extraHeaders,
1071  host.C_String(),
1072  contentType,
1073  //bodyEncoded.GetLength(),
1074  //bodyEncoded.C_String());
1075  strlen(body),
1076  body);
1077  }
1078  else
1079  {
1080  out.Set("%s %s HTTP/1.1\r\n"
1081  "Host: %s\r\n"
1082  "Content-Type: %s\r\n"
1083  "Content-Length: %u\r\n"
1084  "\r\n"
1085  "%s",
1086  type,
1087  remotePath.C_String(),
1088  host.C_String(),
1089  contentType,
1090  //bodyEncoded.GetLength(),
1091  //bodyEncoded.C_String());
1092  strlen(body),
1093  body);
1094  }
1095 
1096  return out;
1097 }
1098 RakString RakString::FormatForPOST(const char* uri, const char* contentType, const char* body, const char* extraHeaders)
1099 {
1100  return FormatForPUTOrPost("POST", uri, contentType, body, extraHeaders);
1101 }
1102 RakString RakString::FormatForPUT(const char* uri, const char* contentType, const char* body, const char* extraHeaders)
1103 {
1104  return FormatForPUTOrPost("PUT", uri, contentType, body, extraHeaders);
1105 }
1106 RakString RakString::FormatForGET(const char* uri, const char* extraHeaders)
1107 {
1108  RakString out;
1109  RakString host;
1110  RakString remotePath;
1111  SLNet::RakString header;
1112  SLNet::RakString uriRs;
1113  uriRs = uri;
1114 
1115  uriRs.SplitURI(header, host, remotePath);
1116  if (host.IsEmpty() || remotePath.IsEmpty())
1117  return out;
1118 
1119  if (extraHeaders && extraHeaders[0])
1120  {
1121  out.Set("GET %s HTTP/1.1\r\n"
1122  "%s\r\n"
1123  "Host: %s\r\n"
1124  "\r\n",
1125  remotePath.C_String(),
1126  extraHeaders,
1127  host.C_String());
1128  }
1129  else
1130  {
1131  out.Set("GET %s HTTP/1.1\r\n"
1132  "Host: %s\r\n"
1133  "\r\n",
1134  remotePath.C_String(),
1135  host.C_String());
1136 
1137  }
1138 
1139 
1140  return out;
1141 }
1142 RakString RakString::FormatForDELETE(const char* uri, const char* extraHeaders)
1143 {
1144  RakString out;
1145  RakString host;
1146  RakString remotePath;
1147  SLNet::RakString header;
1148  SLNet::RakString uriRs;
1149  uriRs = uri;
1150 
1151  uriRs.SplitURI(header, host, remotePath);
1152  if (host.IsEmpty() || remotePath.IsEmpty())
1153  return out;
1154 
1155  if (extraHeaders && extraHeaders[0])
1156  {
1157  out.Set("DELETE %s HTTP/1.1\r\n"
1158  "%s\r\n"
1159  "Content-Length: 0\r\n"
1160  "Host: %s\r\n"
1161  "Connection: close\r\n"
1162  "\r\n",
1163  remotePath.C_String(),
1164  extraHeaders,
1165  host.C_String());
1166  }
1167  else
1168  {
1169  out.Set("DELETE %s HTTP/1.1\r\n"
1170  "Content-Length: 0\r\n"
1171  "Host: %s\r\n"
1172  "Connection: close\r\n"
1173  "\r\n",
1174  remotePath.C_String(),
1175  host.C_String());
1176  }
1177 
1178  return out;
1179 }
1181 {
1182  if (IsEmpty())
1183  return *this;
1184 
1185  SLNet::RakString fixedString = *this;
1186  fixedString.Clone();
1187  for (int i=0; fixedString.sharedString->c_str[i]; i++)
1188  {
1189 #ifdef _WIN32
1190  if (fixedString.sharedString->c_str[i]=='/')
1191  fixedString.sharedString->c_str[i]='\\';
1192 #else
1193  if (fixedString.sharedString->c_str[i]=='\\')
1194  fixedString.sharedString->c_str[i]='/';
1195 #endif
1196  }
1197 
1198 #ifdef _WIN32
1199  if (fixedString.sharedString->c_str[strlen(fixedString.sharedString->c_str)-1]!='\\')
1200  {
1201  fixedString+='\\';
1202  }
1203 #else
1204  if (fixedString.sharedString->c_str[strlen(fixedString.sharedString->c_str)-1]!='/')
1205  {
1206  fixedString+='/';
1207  }
1208 #endif
1209 
1210  if (fixedString!=*this)
1211  *this = fixedString;
1212  return *this;
1213 }
1215 {
1216  LockMutex();
1218  UnlockMutex();
1219 }
1221 {
1222  for (unsigned int i=0; i < freeList.Size(); i++)
1223  {
1224  SLNet::OP_DELETE(freeList[i]->refCountMutex,_FILE_AND_LINE_);
1226  }
1227  freeList.Clear(false, _FILE_AND_LINE_);
1228 }
1230 {
1232 }
1233 void RakString::Serialize(const char *str, BitStream *bs)
1234 {
1235  unsigned short l = (unsigned short) strlen(str);
1236  bs->Write(l);
1237  bs->WriteAlignedBytes((const unsigned char*) str, (const unsigned int) l);
1238 }
1239 void RakString::SerializeCompressed(BitStream *bs, uint8_t languageId, bool writeLanguageId) const
1240 {
1241  SerializeCompressed(C_String(), bs, languageId, writeLanguageId);
1242 }
1243 void RakString::SerializeCompressed(const char *str, BitStream *bs, uint8_t languageId, bool writeLanguageId)
1244 {
1245  if (writeLanguageId)
1246  bs->WriteCompressed(languageId);
1247  StringCompressor::Instance()->EncodeString(str,0xFFFF,bs,languageId);
1248 }
1250 {
1251  Clear();
1252 
1253  bool b;
1254  unsigned short l;
1255  b=bs->Read(l);
1256  if (l>0)
1257  {
1258  Allocate(((unsigned int) l)+1);
1259  b=bs->ReadAlignedBytes((unsigned char*) sharedString->c_str, l);
1260  if (b)
1261  sharedString->c_str[l]=0;
1262  else
1263  Clear();
1264  }
1265  else
1267  return b;
1268 }
1269 bool RakString::Deserialize(char *str, BitStream *bs)
1270 {
1271  bool b;
1272  unsigned short l;
1273  b=bs->Read(l);
1274  if (b && l>0)
1275  b=bs->ReadAlignedBytes((unsigned char*) str, l);
1276 
1277  if (b==false)
1278  str[0]=0;
1279 
1280  str[l]=0;
1281  return b;
1282 }
1283 bool RakString::DeserializeCompressed(BitStream *bs, bool readLanguageId)
1284 {
1285  uint8_t languageId;
1286  if (readLanguageId)
1287  bs->ReadCompressed(languageId);
1288  else
1289  languageId=0;
1290  return StringCompressor::Instance()->DecodeString(this,0xFFFF,bs,languageId);
1291 }
1292 bool RakString::DeserializeCompressed(char *str, BitStream *bs, bool readLanguageId)
1293 {
1294  uint8_t languageId;
1295  if (readLanguageId)
1296  bs->ReadCompressed(languageId);
1297  else
1298  languageId=0;
1299  return StringCompressor::Instance()->DecodeString(str,0xFFFF,bs,languageId);
1300 }
1302 {
1303  static int index=0;
1304  static char buff[64][64];
1305 #if defined(_WIN32)
1306  sprintf_s(buff[index], "%I64d", i);
1307 #else
1308  sprintf_s(buff[index], "%lld", (long long unsigned int) i);
1309 #endif
1310  int lastIndex=index;
1311  if (++index==64)
1312  index=0;
1313  return buff[lastIndex];
1314 }
1316 {
1317  static int index=0;
1318  static char buff[64][64];
1319 #if defined(_WIN32)
1320  sprintf_s(buff[index], "%I64u", i);
1321 #else
1322  sprintf_s(buff[index], "%llu", (long long unsigned int) i);
1323 #endif
1324  int lastIndex=index;
1325  if (++index==64)
1326  index=0;
1327  return buff[lastIndex];
1328 }
1330 {
1331  Free();
1332 }
1333 void RakString::Allocate(size_t len)
1334 {
1336  // sharedString = RakString::pool.Allocate( _FILE_AND_LINE_ );
1337  if (RakString::freeList.Size()==0)
1338  {
1339  //RakString::sharedStringFreeList=(RakString::SharedString*) rakRealloc_Ex(RakString::sharedStringFreeList,(RakString::sharedStringFreeListAllocationCount+1024)*sizeof(RakString::SharedString), _FILE_AND_LINE_);
1340  unsigned i;
1341  for (i=0; i < 128; i++)
1342  {
1343  // RakString::freeList.Insert(RakString::sharedStringFreeList+i+RakString::sharedStringFreeListAllocationCount);
1344  // RakString::freeList.Insert((RakString::SharedString*)rakMalloc_Ex(sizeof(RakString::SharedString), _FILE_AND_LINE_), _FILE_AND_LINE_);
1345 
1348  ss->refCountMutex= SLNet::OP_NEW<SimpleMutex>(_FILE_AND_LINE_);
1350  }
1351  //RakString::sharedStringFreeListAllocationCount+=1024;
1352  }
1356 
1357  const size_t smallStringSize = 128-sizeof(unsigned int)-sizeof(size_t)-sizeof(char*)*2;
1359  if (len <= smallStringSize)
1360  {
1361  sharedString->bytesUsed=smallStringSize;
1363  }
1364  else
1365  {
1366  sharedString->bytesUsed=len<<1;
1369  }
1370 }
1371 void RakString::Assign(const char *str)
1372 {
1373  if (str==0 || str[0]==0)
1374  {
1376  return;
1377  }
1378 
1379  size_t len = strlen(str)+1;
1380  Allocate(len);
1381  memcpy(sharedString->c_str, str, len);
1382 }
1383 void RakString::Assign(const char *str, va_list ap)
1384 {
1385  if (str==0 || str[0]==0)
1386  {
1388  return;
1389  }
1390 
1391  char stackBuff[512];
1392  int numChars = vsnprintf_s(stackBuff, 511, str, ap);
1393  if (numChars != -1)
1394  {
1395  Assign(stackBuff);
1396  return;
1397  }
1398  char *buff=0, *newBuff;
1399  size_t buffSize=8096;
1400  for(;;)
1401  {
1402  newBuff = (char*) rakRealloc_Ex(buff, buffSize,__FILE__,__LINE__);
1403  if (newBuff==0)
1404  {
1406  if (buff!=0)
1407  {
1408  Assign(buff);
1409  rakFree_Ex(buff,__FILE__,__LINE__);
1410  }
1411  else
1412  {
1413  Assign(stackBuff);
1414  }
1415  return;
1416  }
1417  buff=newBuff;
1418  if (vsnprintf_s(buff, buffSize, buffSize-1, str, ap)!=-1)
1419  {
1420  Assign(buff);
1421  rakFree_Ex(buff,__FILE__,__LINE__);
1422  return;
1423  }
1424  buffSize*=2;
1425  }
1426 }
1427 SLNet::RakString RakString::Assign(const char *str,size_t pos, size_t n )
1428 {
1429  size_t incomingLen=strlen(str);
1430 
1431  Clone();
1432 
1433  if (str==0 || str[0]==0||pos>=incomingLen)
1434  {
1436  return (*this);
1437  }
1438 
1439  if (pos+n>=incomingLen)
1440  {
1441  n=incomingLen-pos;
1442 
1443  }
1444  const char * tmpStr=&(str[pos]);
1445 
1446  size_t len = n+1;
1447  Allocate(len);
1448  memcpy(sharedString->c_str, tmpStr, len);
1449  sharedString->c_str[n]=0;
1450 
1451  return (*this);
1452 }
1453 
1455 {
1456  SLNet::RakString rs;
1457  rs=str;
1458  return rs;
1459 }
1460 unsigned long RakString::ToInteger(const char *str)
1461 {
1462  unsigned long hash = 0;
1463  int c;
1464 
1465  while ((c = *str++))
1466  hash = c + (hash << 6) + (hash << 16) - hash;
1467 
1468  return hash;
1469 }
1470 unsigned long RakString::ToInteger(const RakString &rs)
1471 {
1472  return RakString::ToInteger(rs.C_String());
1473 }
1474 int RakString::ReadIntFromSubstring(const char *str, size_t pos, size_t n)
1475 {
1476  char tmp[32];
1477  if (n >= 32)
1478  return 0;
1479  for (size_t i=0; i < n; i++)
1480  tmp[i]=str[i+pos];
1481  return atoi(tmp);
1482 }
1483 void RakString::AppendBytes(const char *bytes, size_t count)
1484 {
1485  if (IsEmpty())
1486  {
1487  Allocate(count);
1488  memcpy(sharedString->c_str, bytes, count+1);
1489  sharedString->c_str[count]=0;
1490  }
1491  else
1492  {
1493  Clone();
1494  unsigned int length=(unsigned int) GetLength();
1495  Realloc(sharedString, count+length+1);
1496  memcpy(sharedString->c_str+length, bytes, count);
1497  sharedString->c_str[length+count]=0;
1498  }
1499 
1500 
1501 }
1503 {
1505  if (sharedString==&emptyString)
1506  {
1507  return;
1508  }
1509 
1510  // Empty or solo then no point to cloning
1512  if (sharedString->refCount==1)
1513  {
1515  return;
1516  }
1517 
1521 }
1523 {
1524  if (sharedString==&emptyString)
1525  return;
1528  if (sharedString->refCount==0)
1529  {
1531  const size_t smallStringSize = 128-sizeof(unsigned int)-sizeof(size_t)-sizeof(char*)*2;
1532  if (sharedString->bytesUsed>smallStringSize)
1534  /*
1535  poolMutex->Lock();
1536  pool.Release(sharedString);
1537  poolMutex->Unlock();
1538  */
1539 
1543 
1545  }
1546  else
1547  {
1549  }
1551 }
1552 unsigned char RakString::ToLower(unsigned char c)
1553 {
1554  if (c >= 'A' && c <= 'Z')
1555  return c-'A'+'a';
1556  return c;
1557 }
1558 unsigned char RakString::ToUpper(unsigned char c)
1559 {
1560  if (c >= 'a' && c <= 'z')
1561  return c-'a'+'A';
1562  return c;
1563 }
1565 {
1566  GetPoolMutex().Lock();
1567 }
1569 {
1570  GetPoolMutex().Unlock();
1571 }
1572 
1573 /*
1574 #include "slikenet/string.h"
1575 #include <string>
1576 #include "slikenet/GetTime.h"
1577 
1578 using namespace SLNet;
1579 
1580 int main(void)
1581 {
1582  RakString s3("Hello world");
1583  RakString s5=s3;
1584 
1585  RakString s1;
1586  RakString s2('a');
1587 
1588  RakString s4("%i %f", 5, 6.0);
1589 
1590  RakString s6=s3;
1591  RakString s7=s6;
1592  RakString s8=s6;
1593  RakString s9;
1594  s9=s9;
1595  RakString s10(s3);
1596  RakString s11=s10 + s4 + s9 + s2;
1597  s11+=RakString("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
1598  RakString s12("Test");
1599  s12+=s11;
1600  bool b1 = s12==s12;
1601  s11=s5;
1602  s12.ToUpper();
1603  s12.ToLower();
1604  RakString s13;
1605  bool b3 = s13.IsEmpty();
1606  s13.Set("blah %s", s12.C_String());
1607  bool b4 = s13.IsEmpty();
1608  size_t i1=s13.GetLength();
1609  s3.Clear(_FILE_AND_LINE_);
1610  s4.Clear(_FILE_AND_LINE_);
1611  s5.Clear(_FILE_AND_LINE_);
1612  s5.Clear(_FILE_AND_LINE_);
1613  s6.Printf();
1614  s7.Printf();
1615  RAKNET_DEBUG_PRINTF("\n");
1616 
1617  static const int repeatCount=750;
1618  DataStructures::List<RakString> rakStringList;
1619  DataStructures::List<std::string> stdStringList;
1620  DataStructures::List<char*> referenceStringList;
1621  char *c;
1622  unsigned i;
1623  SLNet::TimeMS beforeReferenceList, beforeRakString, beforeStdString, afterStdString;
1624 
1625  unsigned loop;
1626  for (loop=0; loop<2; loop++)
1627  {
1628  beforeReferenceList=SLNet::GetTimeMS();
1629  for (i=0; i < repeatCount; i++)
1630  {
1631  c = SLNet::OP_NEW_ARRAY<char >(56,_FILE_AND_LINE_ );
1632  strcpy_s(c, 56, "Aalsdkj alsdjf laksdjf ;lasdfj ;lasjfd");
1633  referenceStringList.Insert(c);
1634  }
1635  beforeRakString=SLNet::GetTimeMS();
1636  for (i=0; i < repeatCount; i++)
1637  rakStringList.Insert("Aalsdkj alsdjf laksdjf ;lasdfj ;lasjfd");
1638  beforeStdString=SLNet::GetTimeMS();
1639 
1640  for (i=0; i < repeatCount; i++)
1641  stdStringList.Insert("Aalsdkj alsdjf laksdjf ;lasdfj ;lasjfd");
1642  afterStdString=SLNet::GetTimeMS();
1643  RAKNET_DEBUG_PRINTF("Insertion 1 Ref=%i Rak=%i, Std=%i\n", beforeRakString-beforeReferenceList, beforeStdString-beforeRakString, afterStdString-beforeStdString);
1644 
1645  beforeReferenceList=SLNet::GetTimeMS();
1646  for (i=0; i < repeatCount; i++)
1647  {
1648  SLNet::OP_DELETE_ARRAY(referenceStringList[0], _FILE_AND_LINE_);
1649  referenceStringList.RemoveAtIndex(0);
1650  }
1651  beforeRakString=SLNet::GetTimeMS();
1652  for (i=0; i < repeatCount; i++)
1653  rakStringList.RemoveAtIndex(0);
1654  beforeStdString=SLNet::GetTimeMS();
1655  for (i=0; i < repeatCount; i++)
1656  stdStringList.RemoveAtIndex(0);
1657  afterStdString=SLNet::GetTimeMS();
1658  RAKNET_DEBUG_PRINTF("RemoveHead Ref=%i Rak=%i, Std=%i\n", beforeRakString-beforeReferenceList, beforeStdString-beforeRakString, afterStdString-beforeStdString);
1659 
1660  beforeReferenceList=SLNet::GetTimeMS();
1661  for (i=0; i < repeatCount; i++)
1662  {
1663  c = SLNet::OP_NEW_ARRAY<char >(56, _FILE_AND_LINE_ );
1664  strcpy_s(c, 56, "Aalsdkj alsdjf laksdjf ;lasdfj ;lasjfd");
1665  referenceStringList.Insert(0);
1666  }
1667  beforeRakString=SLNet::GetTimeMS();
1668  for (i=0; i < repeatCount; i++)
1669  rakStringList.Insert("Aalsdkj alsdjf laksdjf ;lasdfj ;lasjfd");
1670  beforeStdString=SLNet::GetTimeMS();
1671  for (i=0; i < repeatCount; i++)
1672  stdStringList.Insert("Aalsdkj alsdjf laksdjf ;lasdfj ;lasjfd");
1673  afterStdString=SLNet::GetTimeMS();
1674  RAKNET_DEBUG_PRINTF("Insertion 2 Ref=%i Rak=%i, Std=%i\n", beforeRakString-beforeReferenceList, beforeStdString-beforeRakString, afterStdString-beforeStdString);
1675 
1676  beforeReferenceList=SLNet::GetTimeMS();
1677  for (i=0; i < repeatCount; i++)
1678  {
1679  SLNet::OP_DELETE_ARRAY(referenceStringList[referenceStringList.Size()-1], _FILE_AND_LINE_);
1680  referenceStringList.RemoveAtIndex(referenceStringList.Size()-1);
1681  }
1682  beforeRakString=SLNet::GetTimeMS();
1683  for (i=0; i < repeatCount; i++)
1684  rakStringList.RemoveAtIndex(rakStringList.Size()-1);
1685  beforeStdString=SLNet::GetTimeMS();
1686  for (i=0; i < repeatCount; i++)
1687  stdStringList.RemoveAtIndex(stdStringList.Size()-1);
1688  afterStdString=SLNet::GetTimeMS();
1689  RAKNET_DEBUG_PRINTF("RemoveTail Ref=%i Rak=%i, Std=%i\n", beforeRakString-beforeReferenceList, beforeStdString-beforeRakString, afterStdString-beforeStdString);
1690 
1691  }
1692 
1693  printf("Done.");
1694  char str[128];
1695  Gets(str, sizeof(str));
1696  return 1;
1697 }
1698 */