Game Accessibility Library logo SourceForge.net Logo
Game Accessibility Suite: CAT/CATString.cpp Source File

CATString.cpp

Go to the documentation of this file.
00001 /// \file    CATString.cpp
00002 /// \brief   String class
00003 /// \ingroup CAT
00004 ///
00005 /// Copyright (c) 2002-2008 by Michael Ellison.
00006 /// See COPYING.txt for the \ref gaslicense License (MIT License).
00007 ///
00008 // $Author: mikeellison $
00009 // $Date: 2008-01-27 01:25:54 -0600 (Sun, 27 Jan 2008) $
00010 // $Revision:   $
00011 // $NoKeywords: $
00012 
00013 
00014 #include "CATString.h"
00015 #include <stdlib.h>
00016 
00017 //---------------------------------------------------------------------------
00018 CATString::CATString()
00019 {
00020     Init();
00021 }
00022 //---------------------------------------------------------------------------
00023 CATString::CATString(const char* str)
00024 {      
00025     Init();
00026     *this = str;
00027 }
00028 //---------------------------------------------------------------------------
00029 CATString::CATString(const CATString& str)
00030 {
00031     if (&str == this)
00032         return;
00033     Init();   
00034     *this = str;
00035 }
00036 //---------------------------------------------------------------------------
00037 CATString::CATString(const CATWChar* str)
00038 {
00039     Init();
00040     *this = str;
00041 }
00042 //---------------------------------------------------------------------------
00043 void CATString::SetCodePage(CATUInt32 codePage)
00044 {   
00045     fCodePage = codePage;
00046 }
00047 //---------------------------------------------------------------------------
00048 // Destructor
00049 CATString::~CATString()
00050 {
00051     delete [] fBuffer;
00052     delete [] fUnicodeBuffer;
00053 }
00054 //---------------------------------------------------------------------------
00055 // Creates an empty string of specified length 
00056 bool CATString::Create(CATUInt32 length)
00057 {
00058     Destroy();
00059 
00060     if (!AllocBuffer(length))
00061     {
00062         return false;
00063     }
00064 
00065     return true;
00066 }
00067 //---------------------------------------------------------------------------
00068 CATUInt32 CATString::Length()
00069 {
00070     // If it isn't dirty, no need to recalc
00071     if (!fLenDirty)
00072     {
00073         return fStrLen;
00074     }
00075 
00076     fStrLen = this->LengthCalc();
00077     fLenDirty = false;
00078 
00079     return fStrLen;
00080 }
00081 //---------------------------------------------------------------------------
00082 CATUInt32 CATString::LengthCalc() const
00083 {
00084     CATASSERT( (fAsciiLocked == false) || (fUnicodeLocked == false), "Either ascii or unicode should be unlocked...");
00085 
00086     if (this->fAsciiLocked)
00087     {
00088         if (fBuffer == 0)
00089             return 0;
00090 
00091         return (CATUInt32)strlen(fBuffer);
00092     }
00093 
00094     if (fUnicodeBuffer == 0)
00095         return 0;
00096 
00097     return (CATUInt32)wcslen(fUnicodeBuffer);
00098 }
00099 
00100 //---------------------------------------------------------------------------
00101 char* CATString::GetAsciiBuffer(CATUInt32 minlength)
00102 {
00103     CATASSERT(fUnicodeLocked == false, "Can't get an ascii buffer while the unicode buffer is locked");
00104 
00105     CATUInt32 bufSize = CATMax(minlength, this->Length());
00106 
00107     if (bufSize == 0)
00108         bufSize = 1;
00109 
00110     if (bufSize > fBufferLength)
00111     {
00112         this->ExpandBuffer(bufSize+1);
00113     }
00114 
00115     // Create ascii buffer
00116     this->AsciiFromUnicode();
00117 
00118     this->fBufferSizeLocked = true;
00119     this->fAsciiLocked = true;
00120 
00121     return fBuffer;
00122 }
00123 //---------------------------------------------------------------------------
00124 CATWChar* CATString::GetUnicodeBuffer(CATUInt32 minlength)
00125 {
00126     CATASSERT(fAsciiLocked == false, "Can't get a unicode buffer while the ascii buffer is locked");
00127 
00128     CATUInt32 bufSize = CATMax(minlength, this->Length());
00129 
00130     if (bufSize > fBufferLength)
00131     {
00132         this->ExpandBuffer(bufSize+1);
00133     }
00134 
00135     this->fBufferSizeLocked = true;
00136     this->fUnicodeLocked = true;
00137 
00138     return fUnicodeBuffer;
00139 }
00140 
00141 //---------------------------------------------------------------------------
00142 void CATString::ReleaseBuffer()
00143 {
00144     // Should shrink the buffer here, but we don't yet. 
00145     this->fBufferSizeLocked = false;        
00146     this->fUnicodeLocked = false;   
00147 
00148     if (fAsciiLocked)
00149     {
00150         this->fAsciiLocked = false;
00151         this->UnicodeFromAscii();
00152     }
00153 
00154     fLenDirty = true;
00155 }
00156 //---------------------------------------------------------------------------
00157 CATInt32 CATString::Compare(const CATString& str, CATUInt32 cmpLen, CATUInt32 offset) const
00158 {    
00159     // Check for self.
00160     if (&str == this)
00161         return 0;
00162 
00163     CATInt32 retVal = 0;
00164 
00165     CATASSERT((fAsciiLocked == false) && (str.fAsciiLocked == false),               
00166         "Not supporting locked ascii strings for compares currently");
00167 
00168     CATASSERT((offset == 0) || (offset < this->LengthCalc()),"offset beyond length of string." );   
00169 
00170     // Bail if either string is 0....
00171     // not a good way to indicate failure... hmmm...
00172     if (fUnicodeBuffer == 0)
00173     {
00174         return -1;
00175     }
00176 
00177     if (str.fUnicodeBuffer == 0)
00178     {
00179         return 1;
00180     }
00181 
00182     // Return equal if both are empty...
00183     if (this->IsEmpty() && str.IsEmpty())
00184     {
00185         return 0;
00186     }
00187 
00188     // Bail if offset is passed length or greater (this also bails on 0 strings)
00189     if (offset >= this->LengthCalc())
00190     {
00191         return -1;
00192     }
00193 
00194     CATUInt32 i = 0;
00195 
00196     // Scan strings for differences. Quit when difference is found or when string
00197     // terminator (0) is found.
00198     while ((fUnicodeBuffer[i+offset] != 0) && (str.fUnicodeBuffer[i] != 0) && (retVal == 0) && ((cmpLen == 0) || (i < cmpLen)))
00199     {
00200         if (fUnicodeBuffer[i+offset] == str.fUnicodeBuffer[i])
00201         {
00202             i++;
00203         }
00204         else
00205         {
00206             if (fUnicodeBuffer[i+offset] < str.fUnicodeBuffer[i])
00207             {
00208                 retVal = -1;
00209             }
00210             else
00211             {
00212                 retVal = 1;
00213             }               
00214         }
00215     }
00216 
00217     // Check for longer strings - shorter string is <
00218     if ((retVal == 0) && ((cmpLen == 0) || (i < cmpLen)))
00219     {
00220         if (fUnicodeBuffer[i+offset] != 0)
00221         {
00222             retVal = 1;
00223         }
00224         else if (str.fUnicodeBuffer[i] != 0)
00225         {
00226             retVal = -1;
00227         }
00228     }
00229 
00230     return retVal;
00231 }
00232 //---------------------------------------------------------------------------
00233 // Ignores case - 
00234 // WARNING: currently only supports english char sets (even though it supports unicode)
00235 //          so lowercase/capital non-english chars are still mismatched. 
00236 //          example: an 'a' with an accent will not match an 'A' with an accent...
00237 //          This needs to be fixed.
00238 //
00239 CATInt32 CATString::CompareNoCase(const CATString& str,CATUInt32 cmpLen, CATUInt32 offset) const
00240 {
00241     // Check for self.
00242     if (&str == this)
00243         return 0;
00244 
00245     CATInt32 retVal = 0;
00246 
00247     CATASSERT((fAsciiLocked == false) && (str.fAsciiLocked == false),               
00248         "Not supporting locked or dirty ascii strings for compares currently");
00249 
00250     CATASSERT((offset == 0) || (offset < this->LengthCalc()),"offset beyond length of string." );   
00251 
00252     // Bail if either is locked... or either string is 0....
00253     // not a good way to indicate failure... hmmm...
00254     if (fUnicodeBuffer == 0)
00255     {
00256         return -1;
00257     }
00258 
00259     if (str.fUnicodeBuffer == 0)
00260     {
00261         return 1;
00262     }
00263 
00264     // Bail if offset is passed length
00265     if (offset >= this->LengthCalc())
00266     {
00267         return -1;
00268     }
00269 
00270     CATUInt32 i = 0;
00271 
00272     // Scan strings for differences. Quit when difference is found or when string
00273     // terminator (0) is found.
00274     while ((fUnicodeBuffer[i+offset] != 0) && (str.fUnicodeBuffer[i] != 0) && (retVal == 0) && ((cmpLen == 0) || (i < cmpLen)))
00275     {
00276         CATWChar c1, c2;
00277         c1 = fUnicodeBuffer[i+offset];
00278         c2 = str.fUnicodeBuffer[i];
00279 
00280         // Convert both to lower case
00281         if ((c1 >= (CATWChar)'A') && (c1 <= (CATWChar)'Z'))
00282         {
00283             c1 ^= 0x0020;
00284         }
00285 
00286         if ((c2 >= (CATWChar)'A') && (c2 <= (CATWChar)'Z'))
00287         {
00288             c2 ^= 0x0020;
00289         }
00290 
00291         if (c1 == c2)
00292         {
00293             i++;
00294         }
00295         else
00296         {
00297             if (c1 < c2)
00298             {
00299                 retVal = -1;
00300             }
00301             else
00302             {
00303                 retVal = 1;
00304             }               
00305         }
00306     }
00307 
00308     // Check for longer strings - shorter string is <
00309     if ((retVal == 0) && ((cmpLen == 0) || (i < cmpLen)))
00310     {
00311         if (fUnicodeBuffer[i+offset] != 0)
00312         {
00313             retVal = 1;
00314         }
00315         else if (str.fUnicodeBuffer[i] != 0)
00316         {
00317             retVal = -1;
00318         }
00319     }
00320 
00321     return retVal;
00322 }
00323 //---------------------------------------------------------------------------
00324 // Finds a substring within the string
00325 // Starts looking at the offset passed in. Returns offset found (if found) in offset as well.
00326 // returns true if found, or false otherwise.
00327 // NOTE: brute force right now.  should be migrated to a more efficient algorithm
00328 // if used for large strings.
00329 bool CATString::Find(const CATString& str, CATUInt32& offset) const
00330 {
00331     CATASSERT((fAsciiLocked == false) && (str.fAsciiLocked == false),               
00332         "Not supporting locked or dirty strings for searches currently");
00333 
00334     bool found = false;
00335 
00336     CATUInt32 i = 0;
00337     CATUInt32 j = 0;
00338 
00339     CATUInt32 len;
00340     CATUInt32 patlen;
00341 
00342     if (this->fLenDirty)
00343     {
00344         len = this->LengthCalc();
00345     }
00346     else
00347     {
00348         len = this->fStrLen;
00349     }
00350 
00351     if (str.fLenDirty)
00352     {
00353         patlen = str.LengthCalc();
00354     }
00355     else
00356     {
00357         patlen = str.fStrLen;
00358     }
00359 
00360 
00361     len -= offset;
00362 
00363     // Precalc as much of the pointers as possible
00364     CATWChar* data = this->fUnicodeBuffer + offset;
00365     CATWChar* pattern = str.fUnicodeBuffer;
00366 
00367     if (len > patlen)
00368     {
00369         while (i <= len - patlen)
00370         {
00371             if (data[i+j] == pattern[j])
00372             {
00373                 j++;
00374             }
00375             else
00376             {
00377                 j = 0;
00378                 i++;
00379             }
00380 
00381             if (j == patlen)
00382             {
00383                 found = true;
00384                 break;
00385             }
00386         }
00387     }
00388 
00389     if (found)
00390     {
00391         offset += i;
00392     }
00393 
00394     return found;
00395 }
00396 
00397 //---------------------------------------------------------------------------
00398 bool CATString::Find(CATWChar theChar, CATUInt32& offset) const
00399 {
00400     CATASSERT((fAsciiLocked == false),
00401         "Not supporting locked or dirty strings for searches currently");
00402 
00403     bool found = false;
00404 
00405     CATUInt32 i = 0;    
00406     CATUInt32 len = this->LengthCalc(); 
00407     len -= offset;
00408 
00409     while ( (i < len) && (!found))
00410     {
00411         if (this->fUnicodeBuffer[i+offset] == theChar)
00412         {
00413             found = true;
00414         }
00415         else
00416         {
00417             i++;
00418         }
00419     }
00420 
00421     if (found)
00422     {
00423         offset += i;
00424     }
00425 
00426     return found;
00427 }
00428 
00429 
00430 //---------------------------------------------------------------------------
00431 bool CATString::ReverseFind(const CATString& str, CATUInt32& offset) const
00432 {
00433     CATASSERT((fAsciiLocked == false) && (str.fAsciiLocked == false),               
00434         "Not supporting locked or dirty strings for searches currently");
00435 
00436     bool found = false;
00437 
00438     CATUInt32 i = 0;
00439     CATUInt32 j = 0;
00440 
00441     CATUInt32 len;
00442     CATUInt32 patlen;
00443     CATUInt32 locoffset = offset;
00444 
00445     if (this->fLenDirty)
00446     {
00447         len = this->LengthCalc();
00448     }
00449     else
00450     {
00451         len = this->fStrLen;
00452     }
00453 
00454     if (str.fLenDirty)
00455     {
00456         patlen = str.LengthCalc();
00457     }
00458     else
00459     {
00460         patlen = str.fStrLen;
00461     }
00462 
00463     if (locoffset == -1)
00464     {
00465         locoffset = len - patlen;
00466     }
00467 
00468     // i is the pointer to where we are in the string
00469     i = locoffset;
00470     if (i + patlen > len)
00471     {
00472         i = len - patlen;
00473     }   
00474 
00475     // Precalc as much of the pointers as possible
00476     CATWChar* data = this->fUnicodeBuffer;
00477     CATWChar* pattern = str.fUnicodeBuffer;
00478 
00479     if (len > patlen)
00480     {
00481         for ( ; ; )
00482         {
00483             if (data[i+j] == pattern[j])
00484             {
00485                 j++;
00486             }
00487             else
00488             {
00489                 j = 0;
00490                 // Bail if we've gotten to the start of the string w/o finding a match
00491                 if (i == 0)
00492                     break;
00493 
00494                 i--;
00495             }
00496 
00497             if (j == patlen)
00498             {
00499                 found = true;
00500                 break;
00501             }
00502         }
00503     }
00504 
00505     if (found)
00506     {
00507         offset = i;
00508     }
00509 
00510     return found;
00511 }
00512 
00513 //---------------------------------------------------------------------------
00514 bool CATString::ReverseFind(CATWChar theChar, CATUInt32& offset) const
00515 {
00516     CATASSERT((fAsciiLocked == false),
00517         "Not supporting locked or dirty strings for searches currently");
00518 
00519     bool found = false;
00520 
00521     CATUInt32 i = 0;    
00522     CATUInt32 len = this->GetLength(fUnicodeBuffer);    
00523 
00524 
00525     CATUInt32 locoffset = offset;
00526     if (locoffset == -1)
00527     {
00528         locoffset = len - 1;
00529     }
00530 
00531     i = locoffset;
00532 
00533     while (!found)
00534     {
00535         if (this->fUnicodeBuffer[i] == theChar)
00536         {
00537             found = true;
00538         }
00539         else
00540         {
00541             if (i == 0)
00542             {
00543                 // bail if we hit the beginning
00544                 break;
00545             }
00546             i--;
00547         }
00548     }
00549 
00550     if (found)
00551     {
00552         offset = i;
00553     }
00554 
00555     return found;
00556 }
00557 
00558 //---------------------------------------------------------------------------
00559 // Creates a string up to the specified character
00560 CATString CATString::Left(CATUInt32 maxlength) const
00561 {
00562     CATString newString;
00563 
00564     CATUInt32 newLen = CATMin(maxlength,this->LengthCalc());
00565     newString.Create( newLen + 1);
00566     this->CopyBuffer(newString.fUnicodeBuffer, this->fUnicodeBuffer, newLen);
00567 
00568     newString.fLenDirty = true;
00569     return newString;
00570 }
00571 //---------------------------------------------------------------------------
00572 // Creates a string starting at the specified location
00573 // If [start] is passed the end of the current string, the resulting
00574 // string will be empty.
00575 CATString CATString::Right(CATUInt32 start) const
00576 {   
00577     CATString newString;
00578 
00579     if (start >= this->LengthCalc())
00580     {
00581         return newString;
00582     }
00583 
00584     CATUInt32 length = this->LengthCalc() - start;
00585     newString.Create(length+1);
00586     this->CopyBuffer(newString.fUnicodeBuffer, this->fUnicodeBuffer + start, length);   
00587 
00588     newString.fLenDirty = true;
00589     return newString;
00590 }
00591 //---------------------------------------------------------------------------
00592 CATString CATString::FromRight(CATUInt32 length) const
00593 {
00594     return Right(LengthCalc() - length);
00595 }
00596 //---------------------------------------------------------------------------
00597 // Creates a substring of [length] size starting at [start]
00598 CATString CATString::Sub(CATUInt32 start, CATUInt32 length) const
00599 {
00600     CATString newString;
00601 
00602     CATUInt32 actualLength;
00603 
00604     if (start >= this->LengthCalc())
00605     {
00606         return newString;
00607     }
00608 
00609     actualLength = CATMin(length, this->LengthCalc() - start);
00610     newString.Create(length);
00611     CopyBuffer(newString.fUnicodeBuffer, this->fUnicodeBuffer + start, length);
00612 
00613     newString.fLenDirty = true;
00614 
00615     return newString;
00616 }
00617 //--------------------------------------------------------------------------
00618 // Numeric conversions
00619 //--------------------------------------------------------------------------
00620 CATString::CATString(CATUInt32 val)
00621 {
00622     Init();
00623     *this = val;
00624 }
00625 //---------------------------------------------------------------------------
00626 CATString::CATString(CATInt32 val)
00627 {
00628     Init();
00629     *this = val;
00630 }
00631 //---------------------------------------------------------------------------
00632 CATString::CATString(CATFloat32 val)
00633 {
00634     Init();
00635     *this = val;
00636 }
00637 
00638 //---------------------------------------------------------------------------
00639 CATString::CATString(CATFloat64 val)
00640 {
00641     Init();
00642     *this = val;
00643 }
00644 
00645 //---------------------------------------------------------------------------
00646 CATString::CATString(bool val)
00647 {
00648     Init();
00649     *this = val;
00650 }
00651 
00652 //---------------------------------------------------------------------------
00653 CATString::CATString(char val)
00654 {
00655     Init();
00656     *this = val;
00657 }
00658 
00659 //---------------------------------------------------------------------------
00660 CATString::CATString(CATWChar val)
00661 {
00662     Init();
00663     *this = val;
00664 }
00665 CATString::CATString(const GUID& guid)
00666 {
00667     Init();
00668     *this = guid;
00669 }
00670 
00671 CATString::CATString(const GUID* guid)
00672 {
00673     Init();
00674     *this = guid;
00675 }
00676 
00677 //---------------------------------------------------------------------------
00678 CATString& CATString::operator=(CATFloat32 val)
00679 {
00680     CATWChar tmpBuf[256];
00681     swprintf(tmpBuf,256,L"%.5f",val);
00682 
00683     int lastByte = (int)(wcslen(tmpBuf) - 1);
00684     while ((lastByte > 0) && (tmpBuf[lastByte] == '0') && (tmpBuf[lastByte - 1] != '.'))
00685     {
00686         tmpBuf[lastByte] = 0;
00687         lastByte--;
00688     }
00689 
00690     *this = tmpBuf; 
00691     return *this;
00692 }
00693 
00694 //---------------------------------------------------------------------------
00695 CATString& CATString::operator=(CATFloat64 val)
00696 {
00697     CATWChar tmpBuf[512];
00698     swprintf(tmpBuf,512,L"%.5f",val);
00699 
00700     int lastByte = (int)(wcslen(tmpBuf) - 1);
00701     while ((lastByte > 0) && (tmpBuf[lastByte] == '0') && (tmpBuf[lastByte - 1] != '.'))
00702     {
00703         tmpBuf[lastByte] = 0;
00704         lastByte--;
00705     }
00706 
00707     *this = tmpBuf; 
00708     return *this;
00709 }
00710 
00711 CATString& CATString::operator=(const GUID& guid)
00712 {
00713     CATWChar tmpBuf[512];   
00714     swprintf(tmpBuf,512,L"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
00715         guid.Data1, guid.Data2,guid.Data3,
00716         guid.Data4[0], 
00717         guid.Data4[1], 
00718         guid.Data4[2], 
00719         guid.Data4[3], 
00720         guid.Data4[4], 
00721         guid.Data4[5], 
00722         guid.Data4[6], 
00723         guid.Data4[7]
00724         );
00725     *this = tmpBuf;
00726     return *this;
00727 }
00728 
00729 CATString& CATString::operator=(const GUID* guid)
00730 {
00731     *this = (*guid);
00732     return *this;
00733 }
00734 
00735 //---------------------------------------------------------------------------
00736 CATString& CATString::operator=(CATUInt32 val)
00737 {
00738     CATWChar tmpBuf[32];
00739     swprintf(tmpBuf,32,L"%u",val);
00740     *this = tmpBuf; 
00741     return *this;
00742 }
00743 
00744 //---------------------------------------------------------------------------
00745 CATString& CATString::operator=(bool val)
00746 {
00747 
00748     if (val)
00749     {
00750         *this = (const CATWChar*)L"True";
00751     }
00752     else
00753     {
00754         *this = (const CATWChar*)L"False";
00755     }
00756 
00757     return *this;
00758 }
00759 
00760 //---------------------------------------------------------------------------
00761 CATString& CATString::operator=(char val)
00762 {   
00763     char tmpBuf[2];
00764     tmpBuf[0] = val;
00765     tmpBuf[1] = 0;  
00766     *this = tmpBuf; 
00767     return *this;
00768 }
00769 
00770 //---------------------------------------------------------------------------
00771 CATString& CATString::operator=(CATWChar val)
00772 {   
00773     CATWChar tmpBuf[2];
00774     tmpBuf[0] = val;
00775     tmpBuf[1] = 0;  
00776     *this = tmpBuf; 
00777     return *this;
00778 }
00779 
00780 //---------------------------------------------------------------------------
00781 CATString& CATString::operator=(CATInt32 val)
00782 {       
00783     this->ExpandBuffer(33);
00784     swprintf(fUnicodeBuffer,33,L"%d",val);
00785     this->fLenDirty = true;
00786     return *this;
00787 }
00788 
00789 //---------------------------------------------------------------------------
00790 CATString::operator CATInt32() const
00791 {
00792     if (fUnicodeBuffer == 0)
00793         return 0;
00794 
00795     if ((fUnicodeBuffer[0] == '0') && (fUnicodeBuffer[1] == 'x'))
00796     {
00797         return (CATInt32)this->FromHex();
00798     }
00799 
00800     CATWChar* endPtr = 0;
00801     return wcstol(fUnicodeBuffer,&endPtr,10);
00802 }
00803 
00804 CATString::operator CATInt64() const
00805 {
00806     CATWChar* endPtr = 0;
00807 
00808     if (fUnicodeBuffer == 0)
00809         return 0;
00810 
00811     if ((fUnicodeBuffer[0] == '0') && (fUnicodeBuffer[1] == 'x'))
00812     {
00813         return (CATInt64)_wcstoui64(fUnicodeBuffer,&endPtr,16);
00814     }
00815     
00816     return (CATInt64)_wcstoui64(fUnicodeBuffer,&endPtr,10);    
00817 }
00818 //---------------------------------------------------------------------------
00819 CATString::operator bool() const
00820 {
00821     if (fUnicodeBuffer == 0)
00822         return false;
00823 
00824     CATWChar firstChar = this->GetWChar(0);
00825 
00826     // Scan for true/false and yes/no
00827     switch (firstChar)
00828     {
00829         // [T]rue / [Y]es
00830     case 'T':
00831     case 't':
00832     case 'y':
00833     case 'Y':      
00834         return true;
00835     case 'F':
00836     case 'f':
00837     case 'n':
00838     case 'N':      
00839         return false;
00840     }
00841 
00842     // true numerics
00843     if ((CATInt32)*this)
00844     {
00845         return true;
00846     }
00847 
00848     return false;
00849 }
00850 
00851 //---------------------------------------------------------------------------
00852 CATString::operator CATFloat32() const
00853 {
00854     if (fUnicodeBuffer == 0)
00855         return 0;
00856 
00857     return  (CATFloat32)_wtof(fUnicodeBuffer);  
00858 }
00859 
00860 //---------------------------------------------------------------------------
00861 CATString::operator CATFloat64() const
00862 {
00863     if (fUnicodeBuffer == 0)
00864         return 0;
00865     
00866     return _wtof(fUnicodeBuffer);    
00867 }
00868 
00869 //---------------------------------------------------------------------------
00870 CATString::operator CATUInt32() const
00871 {
00872     if (fUnicodeBuffer == 0)
00873         return 0;
00874 
00875     if ((fUnicodeBuffer[0] == '0') && (fUnicodeBuffer[1] == 'x'))
00876     {
00877         return this->FromHex();
00878     }
00879     
00880     CATWChar* endPtr = 0;
00881     return wcstoul(fUnicodeBuffer,&endPtr,10);        
00882 }
00883 //--------------------------------------------------------------------------
00884 // Operators
00885 //--------------------------------------------------------------------------
00886 CATString& CATString::operator=(const CATString& str)
00887 {
00888     if (&str == this)
00889         return *this;
00890 
00891     if (str.IsEmpty())
00892     {
00893         *this = "";
00894         return *this;
00895     }
00896 
00897     CATASSERT((str.fUnicodeLocked != true) && (str.fAsciiLocked != true), "Can't copy locked strings right now");
00898     Destroy();
00899 
00900     CATUInt32 newlen = str.LengthCalc();
00901 
00902     this->Create(newlen+1);
00903     this->CopyBuffer(this->fUnicodeBuffer,str.fUnicodeBuffer,newlen);       
00904 
00905     fLenDirty = true;
00906 
00907     return *this;
00908 }
00909 
00910 //---------------------------------------------------------------------------
00911 CATString& CATString::operator=(const CATWChar* unistr)
00912 {
00913     Destroy();
00914     if (unistr == 0)
00915         return *this;
00916 
00917     CATUInt32 newlen = (CATUInt32)(wcslen(unistr));
00918     this->AllocBuffer(newlen+1);
00919 
00920     if (fUnicodeBuffer == 0)
00921     {
00922         CATASSERT(fUnicodeBuffer != 0,"Make sure we could allocate it");    
00923         throw;
00924     }
00925 
00926     this->CopyBuffer(this->fUnicodeBuffer,unistr,newlen);
00927 
00928     fLenDirty = true;
00929     return *this;
00930 }
00931 
00932 //---------------------------------------------------------------------------
00933 CATString& CATString::operator=(const char* asciistr)
00934 {
00935     Destroy();  
00936     this->ImportAscii(asciistr);    
00937     return *this;
00938 }
00939 
00940 //---------------------------------------------------------------------------
00941 CATString::operator const char *() const
00942 {
00943     CATASSERT(fUnicodeLocked != true,"Getting pointer to ascii while unicode is locked - dangerous.");  
00944     this->AsciiFromUnicode();
00945     return fBuffer;
00946 }
00947 
00948 //---------------------------------------------------------------------------
00949 CATString::operator const CATWChar*() const
00950 {
00951     CATASSERT(fAsciiLocked != true,"Getting pointer to unicode while ascii is locked - dangerous.");
00952     return fUnicodeBuffer;
00953 }
00954 
00955 
00956 //---------------------------------------------------------------------------
00957 CATString& CATString::operator+=(const CATString& str)
00958 {   
00959     CATASSERT(this->fBufferSizeLocked != true, "Performing operations that modify the string length after locking buffer with GetBuffer() is dangerous. Use ReleaseBuffer first!");
00960     // Check for self
00961     if (this == &str)
00962     {
00963         CATString temp = str + str;
00964         *this = temp;
00965         return *this;
00966     }
00967 
00968 
00969     CATUInt32 newLength = Length();
00970 
00971     // If we can avoid recalc'ing w/o using a non-const function of the string,
00972     // then do it to save time...
00973     if (str.fLenDirty)
00974     {
00975         newLength += str.LengthCalc() + 1;
00976     }
00977     else
00978     {
00979         newLength += str.fStrLen + 1;
00980     }
00981 
00982     if (fUnicodeBuffer == 0)
00983     {
00984         this->AllocBuffer(newLength);
00985     }
00986     else
00987     {
00988         this->ExpandBuffer(newLength);  
00989     }
00990 
00991     CopyBuffer(this->fUnicodeBuffer + this->Length(),str.fUnicodeBuffer,newLength);
00992 
00993     fStrLen  = newLength-1;
00994     fLenDirty = false;  
00995     return *this;
00996 }
00997 
00998 //--------------------------------------------------------------------------
00999 // Protected functions
01000 //--------------------------------------------------------------------------
01001 bool CATString::AsciiFromUnicode() const
01002 {
01003     // The first call is just to get the string length necessary
01004     CATUInt32 asciiLen = 0;
01005     if (fCodePage == CP_UTF8)
01006     {
01007         asciiLen = WideCharToMultiByte( fCodePage,0,fUnicodeBuffer, -1,
01008             0, 0, 0, 0);    
01009     }
01010     else
01011     {
01012         asciiLen = WideCharToMultiByte( fCodePage,WC_COMPOSITECHECK | WC_DISCARDNS,fUnicodeBuffer, -1,
01013             0, 0, 0, 0);    
01014     }
01015 
01016     if (fBuffer)
01017         delete [] fBuffer;
01018 
01019     // Now generate one 
01020     fBuffer = new char[CATMax(asciiLen+1,fBufferLength)];
01021 
01022     memset(fBuffer,0,CATMax(asciiLen+1,fBufferLength));
01023 
01024     // Now translate        
01025     if (fCodePage == CP_UTF8)
01026     {
01027         WideCharToMultiByte(    fCodePage,0,fUnicodeBuffer, -1,
01028             fBuffer, asciiLen, 0, 0);   
01029     }
01030     else
01031     {
01032         WideCharToMultiByte(    fCodePage,WC_COMPOSITECHECK | WC_DISCARDNS,fUnicodeBuffer, -1,
01033             fBuffer, asciiLen, 0, 0);   
01034     }
01035 
01036 
01037     return true;
01038 }
01039 
01040 bool CATString::UnicodeFromAscii()
01041 {
01042     if (fBuffer == 0)
01043     {
01044         if (fUnicodeBuffer)
01045             delete [] fUnicodeBuffer;
01046         fBufferLength = 0;
01047         fStrLen = 0;
01048         fLenDirty = 0;
01049         return true;
01050     }
01051 
01052     // The first call is just to get the string length necessary
01053     CATUInt32 uniLen = 0;
01054     uniLen = MultiByteToWideChar( fCodePage,
01055         MB_PRECOMPOSED,
01056         fBuffer, 
01057         -1,
01058         0, 
01059         0); 
01060 
01061 
01062     if (fUnicodeBuffer)
01063         delete [] fUnicodeBuffer;
01064 
01065     // Now generate one 
01066     fBufferLength = CATMax(uniLen+1,fBufferLength);
01067     fUnicodeBuffer = new CATWChar[fBufferLength];
01068     memset(fUnicodeBuffer,0,fBufferLength * sizeof(CATWChar));
01069 
01070     // Now translate    
01071     ::MultiByteToWideChar(  fCodePage,
01072         MB_PRECOMPOSED,
01073         fBuffer,
01074         -1,
01075         fUnicodeBuffer, 
01076         uniLen);
01077     this->fLenDirty = true; 
01078     return true;
01079 }
01080 
01081 bool CATString::ImportAscii(const char* ascii)
01082 {
01083     if (ascii == 0)
01084     {
01085         if (fUnicodeBuffer)
01086             delete [] fUnicodeBuffer;
01087         fBufferLength = 0;
01088         fStrLen = 0;
01089         fLenDirty = 0;
01090         return true;
01091     }
01092 
01093     if (fBuffer)
01094     {
01095         delete [] fBuffer;
01096         fBuffer = 0;
01097     }
01098 
01099     // The first call is just to get the string length necessary
01100     CATUInt32 uniLen = 0;
01101     uniLen = MultiByteToWideChar( fCodePage,
01102         MB_PRECOMPOSED,
01103         ascii, 
01104         -1,
01105         0, 
01106         0); 
01107 
01108 
01109     if (fUnicodeBuffer)
01110         delete [] fUnicodeBuffer;
01111 
01112     // Now generate one 
01113     fBufferLength = CATMax(uniLen+1,fBufferLength);
01114     fUnicodeBuffer = new CATWChar[fBufferLength];
01115     memset(fUnicodeBuffer,0,fBufferLength * sizeof(CATWChar));
01116 
01117     // Now translate    
01118     ::MultiByteToWideChar(  fCodePage,
01119         MB_PRECOMPOSED,
01120         ascii,
01121         -1,
01122         fUnicodeBuffer, 
01123         uniLen);
01124     this->fLenDirty = true; 
01125     return true;
01126 }
01127 
01128 
01129 
01130 //---------------------------------------------------------------------------
01131 bool CATString::AllocBuffer(CATUInt32 minLength)
01132 {
01133     // This should only be called when fBuffer is 0 and the string is
01134     // not locked.
01135     CATASSERT(!fBufferSizeLocked,"Buffer size shouldn't be locked here...");    
01136 
01137     if ((fBufferSizeLocked == true) || (fUnicodeBuffer != 0) )
01138     {
01139         return false;
01140     }
01141 
01142     if (fBuffer)
01143     {
01144         delete [] fBuffer;
01145         fBuffer = 0;
01146     }
01147 
01148     CATUInt32 realLength = 0;
01149 
01150     // Allocate a buffer with some space to spare if the string is < 1k
01151     // Always make sure there's enough room for a 0.
01152     if (minLength < 32)
01153     {
01154         realLength = 32;
01155     }
01156     else if (minLength < 64)
01157     {
01158         realLength = 64;
01159     }
01160     else if (minLength < 128)
01161     {
01162         realLength = 128;
01163     }
01164     else if (minLength < 256)
01165     {
01166         realLength = 256;
01167     }
01168     else if (minLength < 1024)
01169     {
01170         realLength = 1024;
01171     }
01172     else
01173     {
01174         // On first allocation, if the allocation is > 1k, allocate only what we need.
01175         realLength = minLength + 1;
01176     }
01177 
01178     fUnicodeBuffer = new CATWChar[realLength];
01179     memset(fUnicodeBuffer,0,realLength*sizeof(CATWChar));
01180     CATASSERT(fUnicodeBuffer != 0, "Got a null string buffer when we tried to allocate it.");
01181     if (fUnicodeBuffer == 0)
01182     {
01183         fBufferLength = 0;
01184         return false;
01185     }
01186 
01187     fBufferLength = realLength; 
01188 
01189     return true;
01190 }
01191 
01192 //---------------------------------------------------------------------------
01193 bool CATString::ExpandBuffer(CATUInt32 minLength)
01194 {
01195     // This should only be called when fUnicodeBuffer exists and the string
01196     // is not locked.
01197 
01198     CATASSERT(this->fBufferSizeLocked != true,"Always use ReleaseBuffer() before performing operations that could change the string size!!!");
01199 
01200     if (fBufferSizeLocked)
01201     {
01202         return false;
01203     }
01204 
01205     if (this->fUnicodeBuffer == 0)
01206     {
01207         return this->AllocBuffer(minLength);
01208     }
01209 
01210     // Decide on our minimum size - either minLength + 1, or our current size
01211     CATUInt32 realLength = this->Length() + 1;
01212 
01213     if (minLength >= realLength)
01214     {
01215         realLength = minLength + 1;
01216     }
01217 
01218     // If we've already got the amount requested or more, just exit 
01219     // with success
01220     if (realLength <= fBufferLength)
01221     {
01222         return true;
01223     }
01224 
01225     // Otherwise, allocate to nearest reasonable block size, or 
01226     // the current amount + 1k if > 1k.
01227     if (realLength < 16)
01228     {
01229         realLength = 16;
01230     }
01231     else if (realLength < 32)
01232     {
01233         realLength = 32;
01234     }
01235     else if (realLength < 64)
01236     {
01237         realLength = 64;
01238     }
01239     else if (realLength < 128)
01240     {
01241         realLength = 128;
01242     }
01243     else if (realLength < 256)
01244     {
01245         realLength = 256;
01246     }
01247     else if (realLength < 1024)
01248     {
01249         realLength = 1024;
01250     }
01251     else if (realLength < 1024*10)
01252     {   
01253         // If the requested length is > 1k, always allocate 1k extra so we're not constantly
01254         // reallocating the string...
01255         realLength = realLength + 1024;
01256     }
01257     else
01258     {
01259         realLength = realLength + 1024*10;
01260     }
01261 
01262     CATWChar *tmpBuf = fUnicodeBuffer;
01263 
01264     // Nuke ascii string - it's unreliable for conversions
01265     if (fBuffer != 0)
01266     {
01267         delete [] fBuffer;
01268         fBuffer = 0;
01269     }
01270 
01271     // Allocate new string
01272     fUnicodeBuffer = new CATWChar[realLength];
01273     CATASSERT(fUnicodeBuffer != 0, "Got a null buffer when reallocating a string");
01274     if (!fUnicodeBuffer)
01275     {
01276         return false;
01277     }
01278     memset(fUnicodeBuffer,0,realLength*sizeof(CATWChar));
01279     fBufferLength = realLength;
01280 
01281     // Copy in our new string
01282     CopyIn(tmpBuf);
01283 
01284     // Delete old string
01285     delete [] tmpBuf;
01286 
01287     fStrLen = (CATUInt32)(wcslen(fUnicodeBuffer));
01288     fLenDirty = false;  
01289     return true;
01290 }
01291 
01292 //---------------------------------------------------------------------------
01293 void CATString::CopyIn(const CATWChar* str)
01294 {   
01295     if (str == 0)
01296     {
01297         if (fUnicodeBuffer)
01298         {
01299             fUnicodeBuffer[0] = 0;
01300         }
01301         return;
01302     }
01303 
01304     CATUInt32 i = 0;
01305 
01306     while ((str[i] != 0) && (i < fBufferLength - 1))
01307     {
01308         fUnicodeBuffer[i] = str[i];
01309         i++;
01310     }
01311 
01312     fUnicodeBuffer[i] = 0;      
01313 
01314 
01315     fLenDirty = true;
01316 }
01317 
01318 
01319 //---------------------------------------------------------------------------
01320 bool CATString::IsEmpty() const
01321 {
01322     // If we're in ascii mode, then use ascii. otherwise, default to unicode
01323     if (this->fAsciiLocked)
01324     {
01325         if ((this->fBuffer == 0) || (this->fBuffer[0] == 0))
01326         {
01327             return true;
01328         }
01329 
01330         return false;
01331     }
01332 
01333     if ((this->fUnicodeBuffer == 0) || (fUnicodeBuffer[0] == 0))
01334     {
01335         return true;
01336     }
01337 
01338     return false;
01339 }
01340 
01341 //---------------------------------------------------------------------------
01342 CATString& CATString::AppendHex(CATUInt32 hexValue, bool addX)
01343 {
01344     // 0x12345678
01345     if (addX)
01346         *this << L"0x";
01347 
01348     for (CATUInt32 i = 0; i < 8; i++)
01349     {   
01350         CATUInt32 shift = ((7 - i)*4);
01351         char nibble = (char)( ((hexValue & (0xf << shift)) >> shift) );
01352         if (nibble >= 0x0a)
01353         {
01354             nibble += 'A' - 0x0a;
01355         }
01356         else
01357         {
01358             nibble += '0';
01359         }
01360 
01361         *this << nibble;
01362     }
01363     return *this;
01364 }
01365 
01366 //---------------------------------------------------------------------------
01367 CATString& CATString::AppendHexByte(CATUInt8 hexValue, bool addX)
01368 {   
01369     if (addX)
01370     {
01371         *this << L"0x";
01372     }
01373     char nibble = (char)((hexValue & 0xf0) >> 4);
01374     if (nibble >= 0x0a)
01375     {
01376         nibble += 'A' - 0x0a;
01377     }
01378     else
01379     {
01380         nibble += '0';
01381     }
01382 
01383     *this << nibble;
01384 
01385     nibble = (char)(hexValue & 0xf);
01386     if (nibble >= 0x0a)
01387     {
01388         nibble += 'A' - 0x0a;
01389     }
01390     else
01391     {
01392         nibble += '0';
01393     }
01394 
01395     *this << nibble;
01396 
01397     return *this;
01398 }
01399 
01400 //---------------------------------------------------------------------------
01401 CATString& CATString::operator<<(const CATString& str)
01402 {
01403     // str == this is okay, since += takes care of it.
01404     *this += str;
01405     return *this;
01406 }
01407 
01408 //---------------------------------------------------------------------------
01409 CATString& CATString::operator<<(const char* str)
01410 {
01411     *this += str;
01412     return *this;
01413 }
01414 
01415 
01416 //---------------------------------------------------------------------------
01417 CATString& CATString::operator<<(const CATWChar* str)
01418 {
01419     *this += str;
01420     return *this;
01421 }
01422 
01423 
01424 //---------------------------------------------------------------------------
01425 CATString& CATString::operator<<(char strChar)
01426 {
01427     char tmpBuf[2];
01428     tmpBuf[1] = 0;
01429     tmpBuf[0] = strChar;
01430     *this += tmpBuf;
01431     return *this;
01432 }
01433 
01434 //---------------------------------------------------------------------------
01435 CATString& CATString::operator<<(CATWChar strChar)
01436 {
01437     CATWChar tmpBuf[2];
01438     tmpBuf[1] = 0;
01439     tmpBuf[0] = strChar;
01440     *this += tmpBuf;
01441     return *this;
01442 }
01443 
01444 //---------------------------------------------------------------------------
01445 CATString& CATString::operator<<(CATUInt32 val)
01446 {
01447     CATWChar tmpBuf[32];
01448     swprintf(tmpBuf,32,L"%u",val);
01449     *this += tmpBuf;
01450     return *this;
01451 }
01452 
01453 //---------------------------------------------------------------------------
01454 CATString& CATString::operator<<(CATInt32 val)
01455 {
01456     CATWChar tmpBuf[32];
01457     swprintf(tmpBuf,32,L"%d",val);
01458     *this += tmpBuf;
01459     return *this;
01460 }
01461 
01462 //---------------------------------------------------------------------------
01463 CATString& CATString::operator<<(CATFloat32 val)
01464 {
01465     CATWChar tmpBuf[256];
01466     swprintf(tmpBuf,256,L"%.5f",val);
01467 
01468     CATInt32 lastByte = (CATInt32)(wcslen(tmpBuf) - 1);
01469     while ((lastByte > 0) && (tmpBuf[lastByte] == '0') && (tmpBuf[lastByte - 1] != '.'))
01470     {
01471         tmpBuf[lastByte] = 0;
01472         lastByte--;
01473     }
01474 
01475     *this += tmpBuf;
01476     return *this;
01477 }
01478 
01479 //---------------------------------------------------------------------------
01480 CATString& CATString::operator<<(CATFloat64 val)
01481 {
01482     CATWChar tmpBuf[512];
01483     swprintf(tmpBuf,512,L"%.5f",val);
01484 
01485     CATInt32 lastByte = (CATInt32)(wcslen(tmpBuf) - 1);
01486     while ((lastByte > 0) && (tmpBuf[lastByte] == '0') && (tmpBuf[lastByte - 1] != '.'))
01487     {
01488         tmpBuf[lastByte] = 0;
01489         lastByte--;
01490     }
01491 
01492     *this += tmpBuf;
01493     return *this;
01494 }
01495 
01496 CATString& CATString::operator<<(const GUID& guid)
01497 {
01498     CATWChar tmpBuf[512];   
01499     swprintf(tmpBuf,512,L"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
01500         guid.Data1, guid.Data2,guid.Data3,
01501         guid.Data4[0], 
01502         guid.Data4[1], 
01503         guid.Data4[2], 
01504         guid.Data4[3], 
01505         guid.Data4[4], 
01506         guid.Data4[5], 
01507         guid.Data4[6], 
01508         guid.Data4[7]
01509         );
01510     *this += tmpBuf;
01511     return *this;
01512 }
01513 
01514 CATString& CATString::operator<<(const GUID* guid)
01515 {
01516     *this << *guid;
01517     return *this;
01518 }
01519 //---------------------------------------------------------------------------
01520 CATWChar CATString::GetWChar(CATUInt32 offset) const
01521 {
01522     CATASSERT( (!fUnicodeLocked) && (!fAsciiLocked), "Unlock the string before playing with it.");
01523     CATASSERT( offset < fBufferLength, "Offset is invalid.");
01524     // If offset is past the end of the buffer, then bail
01525     if (offset >= fBufferLength)
01526     {
01527         return 0;
01528     }
01529     // if offset is past the end of the string, bail
01530     if (offset > GetLength(fUnicodeBuffer))
01531     {
01532         return 0;
01533     }
01534 
01535     // return the wchar at the offset
01536     return fUnicodeBuffer[offset];
01537 }
01538 
01539 //---------------------------------------------------------------------------
01540 bool CATString::SetWChar(CATUInt32 offset, CATWChar theChar)
01541 {
01542     CATASSERT( (!fUnicodeLocked) && (!fAsciiLocked), "Unlock the string before playing with it.");
01543     if (fUnicodeLocked || fAsciiLocked)
01544     {
01545         return false;
01546     }
01547 
01548     CATASSERT( offset < fBufferLength, "Offset is invalid.");       
01549     if (offset >= fBufferLength)
01550     {
01551         return false;
01552     }
01553 
01554     fUnicodeBuffer[offset] = theChar;
01555 
01556     return true;
01557 }
01558 
01559 //---------------------------------------------------------------------------
01560 // Pull Next Token...
01561 //
01562 // Finds the first instance of any of the characters in 'splitTokens'.
01563 // Then, sets "token" to be everything to the left of that char.
01564 // The string object becomes everything to the right of the char.
01565 // If no more tokenizers remain in the string, then the command returns
01566 // false and any remaining string is placed into 'token', and the string
01567 // is left empty.
01568 //
01569 // example:
01570 // CATString test = "Beer:Whiskey!Sex";
01571 // CATString token;
01572 //
01573 // while (!test.IsEmpty())
01574 // {
01575 //       if (!test.PullNextToken(token,":!"))
01576 //         printf("(Last token....)\n");
01577 //     printf("%s\n",(const char*)token);
01578 // }
01579 //
01580 //
01581 // Output:
01582 //    Beer
01583 //    Whiskey
01584 //    (Last token....)
01585 //    Sex
01586 //
01587 bool CATString::PullNextToken(CATString& token, const CATString& splitTokens)
01588 {
01589     CATASSERT((fAsciiLocked == false),
01590         "Not supporting locked or dirty strings for searches currently");
01591     this->Trim();
01592 
01593     for (CATUInt32 i=0; i<this->fStrLen; i++)
01594     {
01595         for (CATUInt32 tIndex = 0; tIndex < splitTokens.LengthCalc(); tIndex++)
01596         {
01597             if (fUnicodeBuffer[i] == splitTokens.GetWChar(tIndex))
01598             {
01599                 // Found a tokenizer.
01600                 token = this->Left(i);
01601                 *this = this->Right(i+1);
01602                 token.Trim();
01603                 this->Trim();
01604                 return true;
01605             }
01606         }
01607     }
01608 
01609     // Didn't find a tokenizer, just return the whole string as token and clear this
01610     token = *this;
01611     token.Trim();
01612     *this = L"";    
01613     return false;
01614 }
01615 
01616 
01617 void CATString::Pad(CATUInt32 length, CATWChar theChar)
01618 {
01619     CATUInt32 curLen = this->Length();
01620 
01621     if (curLen >= length)
01622         return;
01623 
01624     CATWChar* buffer = this->GetUnicodeBuffer(length+1);
01625     for (CATUInt32 i = curLen; i < length; i++)
01626     {
01627         buffer[i] = theChar;
01628     }
01629     buffer[length] = 0;
01630     this->ReleaseBuffer();
01631 }
01632 //---------------------------------------------------------------------------
01633 // Trims whitespace chars off both ends of the string
01634 void CATString::Trim()
01635 {
01636     CATASSERT( (!fUnicodeLocked) && (!fAsciiLocked), "Unlock the string before playing with it.");  
01637     CATUInt32 start = 0;
01638     CATUInt32 end   = this->Length();
01639 
01640     // find starting point
01641     bool done = false;
01642     while ( (!done) && (start <= end))
01643     {
01644         switch (fUnicodeBuffer[start])
01645         {
01646         case 0x0a:
01647         case 0x0d:
01648         case 0x20:
01649         case 0x00:
01650         case 0x09:
01651             start++;
01652             break;
01653         default:
01654             done = true;
01655         }
01656     }
01657 
01658     done = false;
01659     while ( (!done) && (end >= start))
01660     {
01661         switch (fUnicodeBuffer[end])
01662         {
01663         case 0x0a:
01664         case 0x0d:
01665         case 0x20:
01666         case 0x00:
01667         case 0x09:
01668             end--;
01669             break;
01670         default:                
01671             done = true;
01672         }
01673     }
01674 
01675     // check for empty
01676     if ( end < start)
01677     {
01678         *this = L"";
01679         return;
01680     }
01681 
01682     // Trim the string
01683     *this = this->Sub(start, (end - start) + 1);
01684 }
01685 
01686 //------------------------------------------------------------------------------
01687 // FromHex() converts from text to a CATUInt32
01688 CATUInt32 CATString::FromHex() const
01689 {
01690     CATUInt32 resultVal = 0;
01691     CATUInt32 start = 0;
01692 
01693     CATUInt32 length = this->LengthCalc();
01694     if (  (length > 2) &&
01695         (this->GetWChar(0) == '0') && 
01696         ((this->GetWChar(1) | (char)0x20) == 'x'))
01697     {
01698         start = 2;
01699     }
01700 
01701 
01702     for (CATUInt32 i = start; i < length; i++)
01703     {
01704         resultVal = resultVal << 4;
01705         CATUInt8 curChar = (CATUInt8)this->GetWChar(i);
01706 
01707         if ((curChar >= 'A') && (curChar <= 'F'))
01708         {
01709             resultVal |= ((curChar - 'A') + (CATUInt8)0x0a);
01710         }
01711         else if ((curChar >= 'a') && (curChar <= 'f'))
01712         {
01713             resultVal |= ((curChar - 'a') + (CATUInt8)0x0a);
01714         }
01715         else if ((curChar >= '0') && (curChar <= '9'))
01716         {
01717             resultVal |= (curChar - '0');
01718         }
01719         else
01720         {
01721             CATASSERT(false,"Invalid hex number.");
01722             return 0;
01723         }      
01724     }
01725 
01726     return resultVal;
01727 }
01728 
01729 //------------------------------------------------------------------------------
01730 // ToUpper() converts the string to upper case
01731 void CATString::ToUpper()
01732 {
01733     CATUInt32 length = this->Length();
01734     CATWChar* buffer = this->GetUnicodeBuffer();
01735     for (CATUInt32 i = 0; i < length; i++)
01736     {
01737         if ((buffer[i] >= 'a') && (buffer[i] <= 'z'))      
01738         {
01739             buffer[i] &= ~((CATWChar)0x20);
01740         }
01741     }
01742     ReleaseBuffer();
01743 }
01744 
01745 //------------------------------------------------------------------------------
01746 // ToLower() converts the string to upper case
01747 void CATString::ToLower()
01748 {
01749     CATUInt32 length = this->Length();
01750     CATWChar* buffer = this->GetUnicodeBuffer();
01751     for (CATUInt32 i = 0; i < length; i++)
01752     {
01753         if ((buffer[i] >= 'A') && (buffer[i] <= 'Z'))
01754         {
01755             buffer[i] |= (CATWChar)0x20;
01756         }
01757     }
01758     ReleaseBuffer();
01759 }
01760 
01761 
01762 const CATString& CATString::Format(const CATWChar* formatSpecs, ...)
01763 {
01764     va_list fmtArgs;
01765     va_start(fmtArgs, formatSpecs);
01766 
01767     CATString testString;
01768     int testLen = 1024;
01769     CATWChar* testBuf = testString.GetUnicodeBuffer(testLen);
01770 
01771     // Win32 only, but hopefully *very* similar on other platforms!
01772     // Otherwise, will have to predetermine length with something like using the file handle version
01773     // to a null file (e.g. fsprintf -> /dev/null).
01774     int length = _vsnwprintf(testBuf,testLen - 1, formatSpecs,fmtArgs);
01775 
01776     testString.ReleaseBuffer();
01777 
01778     while (length == -1)
01779     {
01780         testLen *= 2;
01781         testBuf = testString.GetUnicodeBuffer(testLen);
01782         length = _vsnwprintf(testBuf,testLen - 1,formatSpecs,fmtArgs);
01783         testString.ReleaseBuffer();
01784     }
01785 
01786     va_end(fmtArgs);
01787 
01788     *this = testString;
01789     return *this;
01790 }
01791 
01792 // char* version
01793 const CATString& CATString::Format(const char* formatSpecs, ...)
01794 {
01795     va_list fmtArgs;
01796     va_start(fmtArgs, formatSpecs);
01797 
01798     CATString testString;
01799     int testLen = 1024;
01800     char* testBuf = testString.GetAsciiBuffer(testLen);
01801 
01802     // Win32 only, but hopefully *very* similar on other platforms!
01803     // Otherwise, will have to predetermine length with something like using the file handle version
01804     // to a null file (e.g. fsprintf -> /dev/null).
01805     int length = vsnprintf(testBuf,testLen - 1,formatSpecs, fmtArgs);
01806 
01807     testString.ReleaseBuffer();
01808 
01809     while (length == -1)
01810     {
01811         testLen *= 2;
01812         testBuf = testString.GetAsciiBuffer(testLen + 1);
01813         length = vsnprintf(testBuf,testLen - 1,formatSpecs, fmtArgs );
01814         testString.ReleaseBuffer();
01815     }
01816 
01817     va_end(fmtArgs);
01818 
01819     *this = testString;
01820     return *this;
01821 }
01822 
01823 const CATString& CATString::FormatArgs(const CATWChar* formatSpecs, va_list fmtArgs)
01824 {
01825     CATString testString;
01826     int testLen = 1024;
01827     CATWChar* testBuf = testString.GetUnicodeBuffer(testLen);
01828 
01829     // Win32 only, but hopefully *very* similar on other platforms!
01830     // Otherwise, will have to predetermine length with something like using the file handle version
01831     // to a null file (e.g. fsprintf -> /dev/null).
01832     
01833     int length = _vsnwprintf(testBuf,testLen - 1, formatSpecs,fmtArgs);
01834     testString.ReleaseBuffer();
01835 
01836     while (length == -1)
01837     {
01838         testLen *= 2;
01839         testBuf = testString.GetUnicodeBuffer(testLen);
01840         length = _vsnwprintf(testBuf,testLen - 1,formatSpecs,fmtArgs);
01841         testString.ReleaseBuffer();
01842     }
01843 
01844     *this = testString;
01845     return *this;
01846 }
01847 
01848 // char* version
01849 const CATString& CATString::FormatArgs(const char* formatSpecs, va_list fmtArgs)
01850 {
01851     CATString testString;
01852     int testLen = 1024;
01853     char* testBuf = testString.GetAsciiBuffer(testLen);
01854 
01855     // Win32 only, but hopefully *very* similar on other platforms!
01856     // Otherwise, will have to predetermine length with something like using the file handle version
01857     // to a null file (e.g. fsprintf -> /dev/null).
01858     int length = vsnprintf(testBuf,testLen - 1,formatSpecs, fmtArgs);
01859 
01860     testString.ReleaseBuffer();
01861 
01862     while (length == -1)
01863     {
01864         testLen *= 2;
01865         testBuf = testString.GetAsciiBuffer(testLen);
01866         length = vsnprintf(testBuf,testLen,formatSpecs, fmtArgs );
01867         testString.ReleaseBuffer();
01868     }
01869 
01870     *this = testString;
01871     return *this;
01872 }
01873 
01874 CATUInt32 CATString::GetLength(const char* asciistr) const
01875 {
01876     return (CATUInt32)strlen(asciistr);
01877 }
01878 
01879 CATUInt32 CATString::GetLength(const CATWChar* unistr) const
01880 {
01881     return (CATUInt32)wcslen(unistr);
01882 }
01883 
01884 void CATString::CopyBuffer(char* str1, const char* str2, CATUInt32 length)
01885 {
01886     if (str1 == 0 || str2 == 0)
01887     {
01888         return;
01889     }
01890 
01891     CATUInt32 i = 0;
01892     while ((str2[i] != 0) && (i < length))
01893     {
01894         str1[i] = str2[i];
01895         i++;
01896     }
01897 
01898     str1[i] = 0;
01899 }
01900 
01901 
01902 //---------------------------------------------------------------------------
01903 void CATString::CopyBuffer(CATWChar* str1, const CATWChar* str2, CATUInt32 length)
01904 {
01905     if (str1 == 0 || str2 == 0)
01906     {
01907         return;
01908     }
01909 
01910     CATUInt32 i = 0;
01911     while ((str2[i] != 0) && (i < length))
01912     {
01913         str1[i] = str2[i];
01914         i++;
01915     }
01916 
01917     str1[i] = 0;
01918 }
01919 
01920 CATString CATString::Escape() const
01921 {
01922     CATString retString;
01923     CATUInt32 length = LengthCalc();
01924     CATUInt32 i;
01925 
01926     for (i = 0; i < length; i++)
01927     {
01928         CATWChar curChar = GetWChar(i);
01929         switch (curChar)
01930         {
01931             case 0x0a:
01932                 retString << "&#x0a;";
01933                 break;
01934             case 0x0d:
01935                 retString << "&#x0d;";
01936                 break;
01937             case 0x09:
01938                 retString << "&#x09;";
01939                 break;
01940             case '-':
01941                 if (i < length - 1)
01942                 {
01943                     if (GetWChar(i+1) == '-')
01944                     {
01945                         retString << "&#x2D;";
01946                     }
01947                     else
01948                     {
01949                         retString << curChar;
01950                     }
01951                 }
01952                 break;
01953             case '&':
01954                 retString << "&amp;";
01955                 break;
01956             case '<':
01957                 retString << "&lt;";
01958                 break;
01959             case '>':
01960                 retString << "&gt;";
01961                 break;
01962             case '\"':
01963                 retString << "&quot;";
01964                 break;
01965             case '\'':
01966                 retString << "&apos;";
01967                 break;
01968             default:
01969                 retString << curChar;
01970                 break;
01971         }
01972     }
01973 
01974     // Set to utf-8 for xml
01975     retString.SetCodePage(CP_UTF8);
01976     return retString;
01977 }
01978 
01979 
01980 bool CATString::GetGUID(GUID& guid) const
01981 {
01982     CATASSERT( (fAsciiLocked == false) || (fUnicodeLocked == false), "Either ascii or unicode should be unlocked...");
01983     
01984     int numEntries = 0;
01985     GUID tmpGuid;
01986 
01987     if (this->LengthCalc() < 35)
01988         return false;
01989 
01990     int data0, data1,data2,data3,data4,data5,data6,data7;
01991 
01992     if (this->fAsciiLocked)
01993     {
01994         if (fBuffer == 0)
01995             return 0;
01996         
01997         numEntries = sscanf(fBuffer, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
01998             &tmpGuid.Data1, 
01999             &tmpGuid.Data2, 
02000             &tmpGuid.Data3, 
02001             &data0,
02002             &data1,
02003             &data2,
02004             &data3,
02005             &data4,
02006             &data5,
02007             &data6,
02008             &data7);
02009 
02010         if (numEntries != 11)
02011         {
02012             numEntries = sscanf(fBuffer, "%08X-%04X-%04X-%02X%02X%02X%02X%02X%02X%02X%02X",
02013                 &tmpGuid.Data1, 
02014                 &tmpGuid.Data2, 
02015                 &tmpGuid.Data3, 
02016                 &data0,
02017                 &data1,
02018                 &data2,
02019                 &data3,
02020                 &data4,
02021                 &data5,
02022                 &data6,
02023                 &data7);
02024         }
02025 
02026     }
02027     else
02028     {
02029         if (fUnicodeBuffer == 0)
02030             return 0;
02031      
02032         numEntries = swscanf(fUnicodeBuffer, L"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
02033             &tmpGuid.Data1, 
02034             &tmpGuid.Data2, 
02035             &tmpGuid.Data3, 
02036             &data0,
02037             &data1,
02038             &data2,
02039             &data3,
02040             &data4,
02041             &data5,
02042             &data6,
02043             &data7);
02044 
02045         if (numEntries != 11)
02046         {
02047             numEntries = swscanf(fUnicodeBuffer, L"%08X-%04X-%04X-%02X%02X%02X%02X%02X%02X%02X%02X",
02048                 &tmpGuid.Data1, 
02049                 &tmpGuid.Data2, 
02050                 &tmpGuid.Data3, 
02051                 &data0,
02052                 &data1,
02053                 &data2,
02054                 &data3,
02055                 &data4,
02056                 &data5,
02057                 &data6,
02058                 &data7);
02059         }
02060     }
02061 
02062     if (numEntries == 11)
02063     {
02064         tmpGuid.Data4[0] = (BYTE)data0;
02065         tmpGuid.Data4[1] = (BYTE)data1;
02066         tmpGuid.Data4[2] = (BYTE)data2;
02067         tmpGuid.Data4[3] = (BYTE)data3;
02068         tmpGuid.Data4[4] = (BYTE)data4;
02069         tmpGuid.Data4[5] = (BYTE)data5;
02070         tmpGuid.Data4[6] = (BYTE)data6;
02071         tmpGuid.Data4[7] = (BYTE)data7;
02072 
02073         guid = tmpGuid;
02074         return true;
02075     }
02076     
02077     return false;
02078 }
02079 
02080 bool CATString::SplitPath(CATString* drive, CATString* path, CATString* filename, CATString* ext) const
02081 {
02082     if (drive)      *drive    = L"";
02083     if (path)       *path     = L"";
02084     if (filename)   *filename = L"";   
02085     if (ext)        *ext      = L"";
02086     
02087     CATUInt32 curPos  = 0;
02088     CATUInt32 filePos = (CATUInt32)-1;
02089     CATUInt32 length = LengthCalc();
02090     
02091     if (length == 0)
02092         return false;
02093 
02094     if (length >= 2)
02095     {
02096         if (GetWChar(1) == CAT_DRIVESEPERATOR)
02097         {
02098             if (drive)
02099                 (*drive) << GetWChar(0) << GetWChar(1);
02100 
02101             curPos = 2;
02102         }        
02103     }    
02104 
02105     CATUInt32 lastPath = (CATUInt32)-1;
02106     ReverseFind(CAT_PATHSEPERATOR,lastPath);    
02107     CATUInt32 lastPath2 = (CATUInt32)-1;
02108     ReverseFind(CAT_OPTPATHSEPERATOR,lastPath2);
02109 
02110     if (lastPath != (CATUInt32)-1)
02111         filePos = lastPath;
02112     if (lastPath2 != (CATUInt32)-1)
02113     {
02114         if (lastPath == -1)
02115             filePos = lastPath2;
02116         else if (lastPath2 > lastPath)
02117             filePos = lastPath2;
02118     }    
02119     
02120     if (filePos != -1)
02121     {
02122         if (path)
02123             (*path) = Sub(curPos,(filePos-curPos)+1);
02124 
02125         curPos = filePos + 1;
02126     }
02127 
02128     while (curPos < length)
02129     {
02130         if (GetWChar(curPos) != CAT_EXTSEPERATOR)
02131         {
02132             if (filename)
02133                 (*filename) << GetWChar(curPos);
02134         }
02135         else
02136         {
02137             break;
02138         }
02139         curPos++;
02140     }
02141 
02142     if ((curPos < length) && (GetWChar(curPos) == CAT_EXTSEPERATOR))
02143     {
02144         while (curPos < length)
02145         {
02146             if (ext)
02147                 (*ext) << GetWChar(curPos);
02148             curPos++;
02149         }
02150     }
02151 
02152     // Change all path seperators to the 'proper' one.
02153     if (path)
02154     {
02155         CATUInt32 pathLen = path->LengthCalc();
02156         for (CATUInt32 i = 0; i < pathLen; i++)
02157         {
02158             if ( path->GetWChar(i) == CAT_OPTPATHSEPERATOR)
02159             {
02160                 path->SetWChar(i,CAT_PATHSEPERATOR);
02161             }
02162         }
02163     }
02164 
02165 
02166     return true;
02167 }
02168 
02169 CATString CATString::GetDriveDirectory() const
02170 {
02171     CATString drive,directory;
02172     CATString path;
02173     if (this->SplitPath(&drive,&directory,0,0))
02174     {
02175         path << drive << directory;
02176     }
02177     return path;
02178 }
02179 
02180 CATString CATString::GetFilenameExt() const
02181 {
02182     CATString filename,ext;
02183     CATString fullfile;
02184     if (this->SplitPath(0,0,&filename,&ext))
02185     {
02186         fullfile << filename << ext;
02187     }
02188     return fullfile;
02189 }
02190 
02191 CATString CATString::GetFilenameNoExt() const
02192 {
02193     CATString filename;
02194     this->SplitPath(0,0,&filename,0);
02195     return filename;
02196 }
02197 
02198 // Escape a string for use in a URL.
02199 CATString CATString::EncodeURL() const
02200 {
02201     CATString retString;
02202     CATUInt32 length = LengthCalc();
02203     CATUInt32 i;
02204 
02205     for (i = 0; i < length; i++)
02206     {
02207         CATWChar curChar = GetWChar(i);
02208         if ((curChar >= 0x7f) || (curChar <= 0x20))
02209         {
02210             // Escape the char - out of range
02211             retString << L"%";
02212             retString.AppendHexByte((CATUInt8)curChar,false);
02213         }
02214         else
02215         {
02216             switch (curChar)
02217             {                                
02218                 case 0x22: case 0x23: // " #
02219                 case 0x24: case 0x25: // $ %
02220                 case 0x26: case 0x2B: // & +
02221                 case 0x2C: case 0x2F: // , /
02222                 case 0x3A: case 0x3B: // : ;
02223                 case 0x3C: case 0x3D: // < =
02224                 case 0x3E: case 0x3F: // > ?
02225                 case 0x40: case 0x5B: // @ [
02226                 case 0x5C: case 0x5D: // \ ]
02227                 case 0x5E: case 0x60: // ^ `
02228                 case 0x7B: case 0x7C: // { |
02229                 case 0x7D: case 0x7E: // } ~
02230                     retString << L"%";
02231                     retString.AppendHexByte((CATUInt8)curChar,false);
02232                     break;
02233                 default:
02234                     retString << curChar;
02235                     break;
02236             }
02237         }
02238     }
02239     return retString;
02240 }
02241 
02242 // Unescape a string from URL encoding.
02243 CATString CATString::DecodeURL() const
02244 {
02245     CATString retString;
02246     CATUInt32 length = LengthCalc();
02247     CATUInt32 i;
02248 
02249     for (i = 0; i < length; i++)
02250     {
02251         CATWChar curChar = GetWChar(i);        
02252         if (curChar == '%')
02253         {
02254             if (i < (length-2))
02255             {
02256                 CATString hexByte;
02257                 hexByte   << GetWChar(i+1) << GetWChar(i+2);
02258                 retString << (char)hexByte.FromHex();
02259             }
02260             i+=2;
02261         }
02262         else
02263         {
02264             retString << curChar;
02265         }                              
02266     }
02267     return retString;
02268 }
02269 

Generated on Mon Feb 11 04:09:48 2008 for Game Accessibility Suite by doxygen 1.5.4