opennurbs_wstring.cpp
Go to the documentation of this file.
00001 /* $NoKeywords: $ */
00002 /*
00003 //
00004 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
00005 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
00006 // McNeel & Associates.
00007 //
00008 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
00009 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
00010 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
00011 //                              
00012 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
00013 //
00015 */
00016 
00017 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
00018 
00019 // wide char (unicode) <-> char (ascii) converter
00020 static int w2c_size( int, const wchar_t* ); // gets minimum "c_count" arg for w2c().
00021 static int w2c( int,            // w_count = number of wide chars to convert
00022                 const wchar_t*, // source wide char string
00023                 int,            // c_count, 
00024                 char*           // array of at least c_count+1 characters
00025                 );
00026 static int c2w( int,           // c_count = number of chars to convert
00027                 const char*,   // source byte char string
00028                 int,           // w_count, 
00029                 wchar_t*       // array of at least c_count+1 wide characters
00030                 );
00031 static wchar_t c2w( char );
00032 
00033 static int w2c_size( int w_count, const wchar_t* w )
00034 {
00035   // returns number of bytes used in wide conversion.  Does not
00036   // include NULL terminator.
00037   int rc = 0;
00038   if ( w ) {
00039     unsigned int error_status = 0;
00040     rc = ON_ConvertWideCharToUTF8(false,w,w_count,0,0,&error_status,0,0,0);
00041     if ( error_status )
00042     {
00043       ON_ERROR("Wide char string is not valid.");
00044     }
00045     if ( rc < 0 )
00046       rc = 0;
00047   }
00048   return rc;
00049 }
00050 
00051 static int w2c( int w_count, 
00052                 const wchar_t* w, 
00053                 int c_count, 
00054                 char* c // array of at least c_count+1 characters
00055                 )
00056 {
00057   // convert UTF-16 string to UTF-8 string
00058   int rc = 0;
00059   if ( c ) 
00060     c[0] = 0;
00061   // returns length of converted c[]
00062   if ( c_count > 0 && c )
00063   {
00064     c[0] = 0;
00065     if ( w ) 
00066     {
00067       unsigned int error_status = 0;
00068       unsigned int error_mask = 0xFFFFFFFF;
00069       ON__UINT32 error_code_point = 0xFFFD;
00070       const wchar_t* p1 = 0;
00071       rc = ON_ConvertWideCharToUTF8(false,w,w_count,c, c_count, &error_status,error_mask,error_code_point,&p1);
00072       if ( error_status )
00073       {
00074         ON_ERROR("Error converting UTF-16 encoded wchar_t string to UTF-8 encoded char string.");
00075       }
00076       if ( rc > 0 && rc <= c_count )
00077         c[rc] = 0;
00078       else 
00079       {
00080         c[c_count] = 0;
00081         rc = 0;
00082       }
00083     }
00084   }
00085         return rc;
00086 }
00087 
00088 static wchar_t c2w( char c )
00089 {
00090   // NOTE: 
00091   //   Single character conversion of char values 0x80 to 0xFF 
00092   //   get mapped to unicode code points U+0080 U+00FF
00093   //   In particular, this is NOT UTF-8 conversion. 
00094   wchar_t w = ((unsigned char)c);
00095   return w;
00096 }
00097 
00098 static int c2w( int c_count, 
00099                 const char* c, 
00100                 int w_count, 
00101                 wchar_t* w // array of at least w_count+1 wide characters
00102                 )
00103 {
00104   // convert UTF-8 string to UTF-16 string
00105   int rc = 0;
00106   if ( w ) 
00107     w[0] = 0;
00108   // returns length of converted c[]
00109   if ( w_count > 0 && w && c_count > 0 && c && c[0] ) {
00110     w[0] = 0;
00111     if ( c ) 
00112     {
00113       unsigned int error_status = 0;
00114       unsigned int error_mask = 0xFFFFFFFF;
00115       ON__UINT32 error_code_point = 0xFFFD;
00116       const char* p1 = 0;
00117       rc = ON_ConvertUTF8ToWideChar(c,c_count,w,w_count,&error_status,error_mask,error_code_point,&p1);
00118       if ( rc > 0 && rc <= w_count )
00119         w[rc] = 0;
00120       else {
00121         w[w_count] = 0;
00122         rc = 0;
00123       }
00124       if ( 0 != error_status )
00125       {
00126         ON_ERROR("Error converting UTF-8 encoded char string to UTF-16 encoded wchar_t string.");
00127       }
00128     }
00129   }
00130         return rc;
00131 }
00132 
00133 
00134 void ON_String::CopyToArray( int w_count, const wchar_t* w )
00135 {
00136   // if sizeof(wchar_t) is 2, this converts a UTF-16 string to UTF-8 string
00137   // if sizeof(wchar_t) is 4, this converts a UTF-32 string to UTF-8 string
00138   int c_count = w2c_size( w_count, w );
00139   char* c = (char*)onmalloc(c_count+1);
00140   memset( c, 0, c_count+1 );
00141   const int c_length = w2c( w_count, w, c_count, c );
00142   c[c_length] = 0;
00143   CopyToArray( c_count, c );
00144   onfree(c);
00145 }
00146 
00147 
00148 
00150 // Empty strings point at empty_wstring
00151 
00152 struct ON_wStringHeader
00153 {
00154         int    ref_count;       // reference count (>=0 or -1 for empty string)
00155         int    string_length;   // does not include any terminators
00156         int    string_capacity; // does not include any terminators
00157         wchar_t* string_array() {return (wchar_t*)(this+1);}
00158 };
00159 
00160 static struct {
00161   ON_wStringHeader header;
00162   wchar_t           s;  
00163 } empty_wstring = { {-1, 0, 0}, 0 }; // ref_count=-1, length=0, capacity=0, s=0 
00164 static ON_wStringHeader* pEmptyStringHeader = &empty_wstring.header;
00165 static const wchar_t* pEmptywString = &empty_wstring.s;
00166 
00168 // protected helpers
00169 
00170 void ON_wString::Create()
00171 {
00172   m_s = (wchar_t*)pEmptywString;
00173 }
00174 
00175 ON_wStringHeader* ON_wString::Header() const
00176 {
00177   ON_wStringHeader* p = (ON_wStringHeader*)m_s;
00178   if (p)
00179     p--;
00180   else
00181     p = pEmptyStringHeader;
00182   return p;
00183 }
00184 
00185 void ON_wString::CreateArray( int capacity )
00186 {
00187   Destroy();
00188   if ( capacity > 0 ) {
00189                 ON_wStringHeader* p =
00190                         (ON_wStringHeader*)onmalloc( sizeof(ON_wStringHeader) + (capacity+1)*sizeof(*m_s) );
00191                 p->ref_count = 1;
00192                 p->string_length = 0;
00193                 p->string_capacity = capacity;
00194                 m_s = p->string_array();
00195     memset( m_s, 0, (capacity+1)*sizeof(*m_s) );
00196   }
00197 }
00198 
00199 void ON_wString::Destroy()
00200 {
00201   ON_wStringHeader* p = Header();
00202   if ( p != pEmptyStringHeader && p->ref_count > 0 ) {
00203     p->ref_count--;
00204                 if ( p->ref_count == 0 )
00205                         onfree(p);
00206   }
00207         Create();
00208 }
00209 
00210 void ON_wString::Empty()
00211 {
00212   ON_wStringHeader* p = Header();
00213   if ( p != pEmptyStringHeader ) {
00214     if ( p->ref_count > 1 ) {
00215       // string memory is shared
00216       p->ref_count--;
00217             Create();
00218     }
00219     else if ( p->ref_count == 1 ) {
00220       // string memory is not shared - reuse it
00221       if (m_s && p->string_capacity>0)
00222         *m_s = 0;
00223       p->string_length = 0;
00224     }
00225     else {
00226       // should not happen
00227       ON_ERROR("ON_wString::Empty() encountered invalid header - fixed.");
00228       Create();
00229     }
00230   }
00231   else {
00232     // initialized again
00233           Create();
00234   }
00235 }
00236 
00237 void ON_wString::EmergencyDestroy()
00238 {
00239         Create();
00240 }
00241 
00242 void ON_wString::EnableReferenceCounting( bool bEnable )
00243 {
00244   // TODO fill this in;
00245 }
00246 
00247 bool ON_wString::IsReferenceCounted() const
00248 {
00249   return true;
00250 }
00251 
00252 
00253 void ON_wString::CopyArray()
00254 {
00255   // If 2 or more string are using array, it is duplicated.
00256   // Call CopyArray() before modifying array contents.
00257   ON_wStringHeader* p = Header();
00258   if ( p != pEmptyStringHeader && p && p->ref_count > 1 ) 
00259   {
00260     const wchar_t* s = m_s;
00261     // p and s remain valid after Destroy() because
00262     // will simply be decremented and no deallocation
00263     // will happen.
00264     Destroy();
00265     Create();
00266     CopyToArray( p->string_capacity, s );
00267     if ( p->string_length < p->string_capacity )
00268     {
00269       Header()->string_length = p->string_length;
00270     }
00271   }
00272 }
00273 
00274 void ON_wString::ReserveArray( size_t array_capacity )
00275 {
00276   ON_wStringHeader* p = Header();
00277   const int capacity = (int)array_capacity; // for 64 bit compiler
00278   if ( p == pEmptyStringHeader ) 
00279   {
00280                 CreateArray(capacity);
00281   }
00282   else if ( p->ref_count > 1 ) 
00283   {
00284                 CreateArray(capacity);
00285     ON_wStringHeader* p1 = Header();
00286     const int size = (capacity < p->string_length) ? capacity : p->string_length;
00287     if ( size > 0 ) 
00288     {
00289       memcpy( p1->string_array(), p->string_array(), size*sizeof(*m_s) );
00290       p1->string_length = size;
00291     }
00292   }
00293         else if ( capacity > p->string_capacity ) 
00294   {
00295                 p = (ON_wStringHeader*)onrealloc( p, sizeof(ON_wStringHeader) + (capacity+1)*sizeof(*m_s) );
00296     m_s = p->string_array();
00297     memset( &m_s[p->string_capacity], 0, (1+capacity-p->string_capacity)*sizeof(*m_s) );
00298     p->string_capacity = capacity;
00299         }
00300 }
00301 
00302 void ON_wString::ShrinkArray()
00303 {
00304   ON_wStringHeader* p = Header();
00305   if ( p != pEmptyStringHeader ) {
00306     if ( p->string_length < 1 ) {
00307       Destroy();
00308     }
00309     else if ( p->ref_count > 1 ) {
00310       // shared string
00311       CreateArray(p->string_length);
00312                   ON_wStringHeader* p1 = Header();
00313       memcpy( m_s, p->string_array(), p->string_length*sizeof(*m_s));
00314       p1->string_length = p->string_length;
00315       m_s[p1->string_length] = 0;
00316     }
00317           else if ( p->string_length < p->string_capacity ) {
00318       // onrealloc string
00319                   p = (ON_wStringHeader*)onrealloc( p, sizeof(ON_wStringHeader) + (p->string_length+1)*sizeof(*m_s) );
00320       p->string_capacity = p->string_length;
00321       m_s = p->string_array();
00322       m_s[p->string_length] = 0;
00323           }
00324   }
00325 }
00326 
00327 void ON_wString::CopyToArray( const ON_wString& s )
00328 {
00329   CopyToArray( s.Length(), s.Array() );
00330 }
00331 
00332 void ON_wString::CopyToArray( int size, const char* s )
00333 {
00334   if ( size > 0 && s && s[0] ) {
00335           ReserveArray(size);
00336     Header()->string_length = c2w( size, s, Header()->string_capacity, m_s );
00337     m_s[Header()->string_length] = 0;
00338   }
00339   else {
00340     if ( Header()->ref_count > 1 )
00341       Destroy();
00342     else {
00343       Header()->string_length = 0;
00344       m_s[0] = 0;
00345     }
00346   }
00347 }
00348 
00349 void ON_wString::CopyToArray( int size, const unsigned char* s )
00350 {
00351   CopyToArray( size, ((char*)s) );
00352 }
00353 
00354 void ON_wString::CopyToArray( int size, const wchar_t* s )
00355 {
00356   if ( size > 0 && s && s[0] ) {
00357           ReserveArray(size);
00358           memcpy(m_s, s, size*sizeof(*m_s));
00359           Header()->string_length = size;
00360     m_s[Header()->string_length] = 0;
00361   }
00362   else {
00363     if ( Header()->ref_count != 1 )
00364       Destroy();
00365     else {
00366       Header()->string_length = 0;
00367       m_s[0] = 0;
00368     }
00369   }
00370 }
00371 
00372 void ON_wString::AppendToArray( const ON_wString& s )
00373 {
00374   AppendToArray( s.Length(), s.Array() );
00375 }
00376 
00377 void ON_wString::AppendToArray( int size, const char* s )
00378 {
00379   if ( size > 0 && s && s[0] ) {
00380           ReserveArray(size + Header()->string_length );
00381     Header()->string_length += c2w( size, s, Header()->string_capacity-Header()->string_length, &m_s[Header()->string_length] );
00382     m_s[Header()->string_length] = 0;
00383   }
00384 }
00385 
00386 void ON_wString::AppendToArray( int size, const unsigned char* s )
00387 {
00388   AppendToArray( size, ((char*)s) );
00389 }
00390 
00391 void ON_wString::AppendToArray( int size, const wchar_t* s )
00392 {
00393   if ( size > 0 && s && s[0] ) {
00394           ReserveArray(size + Header()->string_length );
00395           memcpy(&m_s[Header()->string_length], s, size*sizeof(*m_s));
00396           Header()->string_length += size;
00397     m_s[Header()->string_length] = 0;
00398   }
00399 }
00400 
00401 
00402 int ON_wString::Length( const char* s )
00403 {
00404   size_t slen = s ? strlen(s) : 0;
00405   int n = ((0 < slen && slen <= 2147483645) ?((int)slen) : 0); // the (int) cast is for 64 bit size_t conversion
00406   return n;
00407 }
00408 
00409 int ON_wString::Length( const unsigned char* s )
00410 {
00411   return ON_wString::Length((const char*)s);
00412 }
00413 
00414 int ON_wString::Length( const wchar_t* s )
00415 {
00416   size_t slen =  s ? wcslen(s) : 0;
00417   int n = ((0 < slen && slen <= 2147483645) ?((int)slen) : 0); // the (int) cast is for 64 bit size_t conversion
00418   return n;
00419 }
00420 
00422 // Construction/Destruction
00423 
00424 ON_wString::ON_wString()
00425 {
00426         Create();
00427 }
00428 
00429 ON_wString::~ON_wString()
00430 {
00431   Destroy();
00432 }
00433 
00434 ON_wString::ON_wString(const ON_wString& src)
00435 {
00436         if (    src.Header()->ref_count > 0 
00437        && 0 == ON_WorkerMemoryPool()
00438        )        
00439   {
00440                 m_s = src.m_s;
00441     src.Header()->ref_count++;
00442         }
00443         else 
00444   {
00445                 Create();
00446                 *this = src.m_s; // use operator=(const wchar_t*) to copy
00447         }
00448 }
00449 
00450 ON_wString::ON_wString(const ON_String& src)
00451 {
00452         Create();
00453         *this = src;
00454 }
00455 
00456 ON_wString::ON_wString( const char* s )
00457 {
00458         Create();
00459   if ( s && s[0] ) 
00460   {
00461     CopyToArray( (int)strlen(s), s ); // the (int) is for 64 bit size_t conversion
00462   }
00463 }
00464 
00465 ON_wString::ON_wString( const char* s, int length )
00466 {
00467         Create();
00468   if ( s && length > 0 ) {
00469     CopyToArray(length,s);
00470         }
00471 }
00472 
00473 ON_wString::ON_wString( char c, int repeat_count )
00474 {
00475   Create();
00476   if ( repeat_count > 0 ) {
00477     char* s = (char*)onmalloc((repeat_count+1)*sizeof(*s));
00478     s[repeat_count] = 0;
00479     memset( s, c, repeat_count*sizeof(*s) );
00480     CopyToArray( repeat_count, s );
00481     onfree(s);
00482     m_s[repeat_count] = 0;
00483     Header()->string_length = repeat_count;
00484   }
00485 }
00486 
00487 ON_wString::ON_wString( const unsigned char* s )
00488 {
00489         Create();
00490   if ( s && s[0] ) {
00491     CopyToArray( (int)strlen((const char*)s), (const char*)s ); // the (int) is for 64 bit size_t conversion
00492   }
00493 }
00494 
00495 ON_wString::ON_wString( const unsigned char* s, int length )
00496 {
00497         Create();
00498   if ( s && length > 0 ) {
00499     CopyToArray(length,s);
00500         }
00501 }
00502 
00503 ON_wString::ON_wString( unsigned char c, int repeat_count )
00504 {
00505   Create();
00506   if ( repeat_count > 0 ) {
00507     char* s = (char*)onmalloc((repeat_count+1)*sizeof(*s));
00508     s[repeat_count] = 0;
00509     memset( s, c, repeat_count*sizeof(*s) );
00510     CopyToArray( repeat_count, s );
00511     onfree(s);
00512     m_s[repeat_count] = 0;
00513     Header()->string_length = repeat_count;
00514   }
00515 }
00516 
00517 
00518 ON_wString::ON_wString( const wchar_t* s )
00519 {
00520         Create();
00521   if ( s && s[0] ) {
00522     CopyToArray( (int)wcslen(s), s ); // the (int) is for 64 bit size_t conversion
00523   }
00524 }
00525 
00526 ON_wString::ON_wString( const wchar_t* s, int length )
00527 {
00528         Create();
00529   if ( s && length > 0 ) {
00530     CopyToArray( length, s );
00531         }
00532 }
00533 
00534 ON_wString::ON_wString( wchar_t c, int repeat_count )
00535 {
00536   int i;
00537   Create();
00538   if ( repeat_count > 0 ) {
00539     ReserveArray(repeat_count);
00540     for (i=0;i<repeat_count;i++)
00541       m_s[i] = c;
00542     m_s[repeat_count] = 0;
00543     Header()->string_length = repeat_count;
00544   }
00545 }
00546 
00547 #if defined(ON_OS_WINDOWS)
00548 bool ON_wString::LoadResourceString(HINSTANCE instance, UINT id )
00549 {
00550   bool rc = false;
00551   wchar_t s[2048]; // room for 2047 characters
00552   int length;
00553 
00554   Destroy();
00555   length = ::LoadStringW( instance, id, s, 2047 );
00556   if ( length > 0 && length < 2048 ) {
00557     CopyToArray( length, s );
00558     rc = true;
00559   }
00560   return rc;
00561 }
00562 #endif
00563 
00564 int ON_wString::Length() const
00565 {
00566   return Header()->string_length;
00567 }
00568 
00569 wchar_t& ON_wString::operator[](int i)
00570 {
00571   CopyArray();
00572   return m_s[i];
00573 }
00574 
00575 wchar_t ON_wString::operator[](int i) const
00576 {
00577   return m_s[i];
00578 }
00579 
00580 bool ON_wString::IsEmpty() const
00581 {
00582   return (Header()->string_length <= 0 ) ? true : false;
00583 }
00584 
00585 const ON_wString& ON_wString::operator=(const ON_wString& src)
00586 {
00587         if (m_s != src.m_s)     
00588   {
00589     if ( src.IsEmpty() ) 
00590     {
00591       Destroy();
00592       Create();
00593     }
00594     else if (    src.Header()->ref_count > 0 
00595               && 0 == ON_WorkerMemoryPool()
00596             ) 
00597     {
00598       Destroy();
00599       src.Header()->ref_count++;
00600       m_s = src.m_s;
00601     }
00602     else 
00603     {
00604       ReserveArray(src.Length());
00605       memcpy( m_s, src.Array(), src.Length()*sizeof(*m_s));
00606       Header()->string_length = src.Length();
00607     }
00608   }
00609         return *this;
00610 }
00611 
00612 const ON_wString& ON_wString::operator=(const ON_String& src)
00613 {
00614   *this = src.Array();
00615   return *this;
00616 }
00617 
00618 const ON_wString& ON_wString::operator=( char c )
00619 {
00620         CopyToArray( 1, &c );
00621         return *this;
00622 }
00623 
00624 const ON_wString& ON_wString::operator=( const char* s )
00625 {
00626   if ( (void*)s != (void*)m_s )
00627           CopyToArray( Length(s), s);
00628         return *this;
00629 }
00630 
00631 const ON_wString& ON_wString::operator=( unsigned char c )
00632 {
00633         CopyToArray( 1, &c );
00634         return *this;
00635 }
00636 
00637 const ON_wString& ON_wString::operator=( const unsigned char* s )
00638 {
00639   if ( (void*)s != (void*)m_s )
00640           CopyToArray( Length(s), s);
00641         return *this;
00642 }
00643 
00644 const ON_wString& ON_wString::operator=( wchar_t c )
00645 {
00646         CopyToArray( 1, &c );
00647         return *this;
00648 }
00649 
00650 const ON_wString& ON_wString::operator=( const wchar_t* s )
00651 {
00652   if ( (void*)s != (void*)m_s )
00653           CopyToArray( Length(s), s);
00654         return *this;
00655 }
00656 
00657 ON_wString ON_wString::operator+(const ON_wString& s2) const
00658 {
00659         ON_wString s(*this);
00660   s.AppendToArray( s2 );
00661         return s;
00662 }
00663 
00664 ON_wString ON_wString::operator+(const ON_String& s2) const
00665 {
00666         ON_wString s(*this);
00667   s.AppendToArray( s2.Length(), s2.Array() );
00668         return s;
00669 }
00670 
00671 ON_wString ON_wString::operator+(char s2 ) const
00672 {
00673         ON_wString s(*this);
00674   s.AppendToArray( 1, &s2 );
00675         return s;
00676 }
00677 
00678 ON_wString ON_wString::operator+(unsigned char s2 ) const
00679 {
00680         ON_wString s(*this);
00681   s.AppendToArray( 1, &s2 );
00682         return s;
00683 }
00684 
00685 ON_wString ON_wString::operator+( wchar_t s2 ) const
00686 {
00687         ON_wString s(*this);
00688   s.AppendToArray( 1, &s2 );
00689         return s;
00690 }
00691 
00692 ON_wString ON_wString::operator+(const char* s2) const
00693 {
00694         ON_wString s(*this);
00695   s.AppendToArray( ON_wString::Length(s2), s2 );
00696         return s;
00697 }
00698 
00699 ON_wString ON_wString::operator+(const unsigned char* s2) const
00700 {
00701         ON_wString s(*this);
00702   s.AppendToArray( ON_wString::Length(s2), s2 );
00703         return s;
00704 }
00705 
00706 ON_wString ON_wString::operator+(const wchar_t* s2) const
00707 {
00708         ON_wString s(*this);
00709   s.AppendToArray( ON_wString::Length(s2), s2 );
00710         return s;
00711 }
00712 
00714 // operator+=()
00715 
00716 void ON_wString::Append( const char* s , int count )
00717 {
00718   // append specified number of characters
00719   if ( s && count > 0 )
00720     AppendToArray(count,s);
00721 }
00722 
00723 void ON_wString::Append( const unsigned char* s , int count )
00724 {
00725   // append specified number of characters
00726   if ( s && count > 0 )
00727     AppendToArray(count,s);
00728 }
00729 
00730 
00731 void ON_wString::Append( const wchar_t* s, int count )
00732 {
00733   // append specified number of characters
00734   if ( s && count > 0 )
00735     AppendToArray(count,s);
00736 }
00737 
00738 const ON_wString& ON_wString::operator+=(const ON_wString& s)
00739 {
00740   AppendToArray(s);
00741         return *this;
00742 }
00743 
00744 const ON_wString& ON_wString::operator+=(const ON_String& s)
00745 {
00746   AppendToArray( s.Length(), s.Array() );
00747         return *this;
00748 }
00749 
00750 const ON_wString& ON_wString::operator+=( char s )
00751 {
00752   AppendToArray(1,&s);
00753         return *this;
00754 }
00755 
00756 const ON_wString& ON_wString::operator+=( unsigned char s )
00757 {
00758   AppendToArray(1,&s);
00759         return *this;
00760 }
00761 
00762 const ON_wString& ON_wString::operator+=( wchar_t s )
00763 {
00764   AppendToArray(1,&s);
00765         return *this;
00766 }
00767 
00768 const ON_wString& ON_wString::operator+=( const char* s )
00769 {
00770   AppendToArray(Length(s),s);
00771         return *this;
00772 }
00773 
00774 const ON_wString& ON_wString::operator+=( const unsigned char* s )
00775 {
00776   AppendToArray(Length(s),s);
00777         return *this;
00778 }
00779 
00780 const ON_wString& ON_wString::operator+=( const wchar_t* s )
00781 {
00782   AppendToArray(Length(s),s);
00783         return *this;
00784 }
00785 
00786 void ON_wString::SetLength(size_t string_length)
00787 {
00788   int length = (int)string_length; // for 64 bit compilers
00789   if ( length >= Header()->string_capacity ) {
00790     ReserveArray(length);
00791   }
00792   if ( length >= 0 && length <= Header()->string_capacity ) {
00793     CopyArray();
00794     Header()->string_length = length;
00795     m_s[length] = 0;
00796   }
00797 }
00798 
00799 wchar_t* ON_wString::Array()
00800 {
00801   CopyArray();
00802   return ( Header()->string_capacity > 0 ) ? m_s : 0;
00803 }
00804 
00805 const wchar_t* ON_wString::Array() const
00806 {
00807   return ( Header()->string_capacity > 0 ) ? m_s : 0;
00808 }
00809 
00810 /*
00811 Returns:
00812   Total number of bytes of memory used by this class.
00813   (For use in ON_Object::SizeOf() overrides.
00814 */
00815 unsigned int ON_wString::SizeOf() const
00816 {
00817   size_t sz = sizeof(*this);
00818   if ( ((const void*)m_s) != ((const void*)pEmptywString) )
00819     sz += (sizeof(ON_wStringHeader) + sizeof(wchar_t)*(Header()->string_capacity+1));
00820   return ((unsigned int)sz);
00821 }
00822 
00823 ON__UINT32 ON_wString::DataCRC(ON__UINT32 current_remainder) const
00824 {
00825   int string_length = Header()->string_length;
00826   if ( string_length > 0 )
00827   {
00828     current_remainder = ON_CRC32(current_remainder,string_length*sizeof(*m_s),m_s);
00829   }
00830   return current_remainder;
00831 }
00832 
00833 ON__UINT32 ON_wString::DataCRCLower(ON__UINT32 current_remainder) const
00834 {
00835   int string_length = Header()->string_length;
00836   if ( string_length > 0 )
00837   {
00838     ON_wString s(*this);
00839     s.MakeLower();
00840     current_remainder = s.DataCRC(current_remainder);
00841   }
00842   return current_remainder;
00843 }
00844 
00845 
00846 int ON_wString::Compare( const char* s ) const
00847 {
00848   int rc = 0;
00849   if ( s && s[0] ) {
00850     if ( IsEmpty() ) {
00851       rc = -1;
00852     }
00853     else {
00854       int c_count = w2c_size( Length(m_s), m_s );
00855       char* c = (char*)onmalloc((c_count+1)*sizeof(*c));
00856       w2c( Length(m_s), m_s, c_count, c );
00857       c[c_count] = 0;
00858       rc = strcmp( c, s );
00859       onfree(c);
00860     }
00861   }
00862   else {
00863     rc = IsEmpty() ? 0 : 1;
00864   }
00865   return rc;
00866 }
00867 
00868 int ON_wString::Compare( const unsigned char* s) const
00869 {
00870   return ON_wString::Compare((const char*)s);
00871 }
00872 
00873 int ON_wString::Compare( const wchar_t* s ) const
00874 {
00875   int rc = 0;
00876   if ( s && s[0] ) {
00877     if ( IsEmpty() ) {
00878       rc = -1;
00879     }
00880     else {
00881       rc = wcscmp( m_s, s );
00882     }
00883   }
00884   else {
00885     rc = IsEmpty() ? 0 : 1;
00886   }
00887   return rc;
00888 }
00889 
00890 int ON_wString::CompareNoCase( const char* s) const
00891 {
00892   int rc = 0;
00893   if ( s && s[0] ) {
00894     if ( IsEmpty() ) {
00895       rc = -1;
00896     }
00897     else {
00898       int c_count = w2c_size( Length(m_s), m_s );
00899       char* c = (char*)onmalloc((c_count+1)*sizeof(*c));
00900       w2c( Length(m_s), m_s, c_count, c );
00901       c[c_count] = 0;
00902       rc = on_stricmp( c, s );
00903       onfree(c);
00904     }
00905   }
00906   else {
00907     rc = IsEmpty() ? 0 : 1;
00908   }
00909   return rc;
00910 }
00911 
00912 int ON_wString::CompareNoCase( const unsigned char* s) const
00913 {
00914   return ON_wString::CompareNoCase((const char*)s);
00915 }
00916 
00917 int ON_wString::CompareNoCase( const wchar_t* s) const
00918 {
00919   int rc = 0;
00920   if ( s && s[0] ) {
00921     if ( IsEmpty() ) {
00922       rc = -1;
00923     }
00924     else {
00925       rc = on_wcsicmp( m_s, s );
00926     }
00927   }
00928   else {
00929     rc = IsEmpty() ? 0 : 1;
00930   }
00931   return rc;
00932 }
00933 
00934 
00935 bool ON_WildCardMatch(const wchar_t* s, const wchar_t* pattern)
00936 {
00937   if ( !pattern || !pattern[0] ) {
00938     return ( !s || !s[0] ) ? true : false;
00939   }
00940 
00941   if ( *pattern == '*' ) {
00942     pattern++;
00943     while ( *pattern == '*' )
00944       pattern++;
00945     
00946     if ( !pattern[0] )
00947       return true;
00948 
00949     while (*s) {
00950       if ( ON_WildCardMatch(s,pattern) )
00951         return true;
00952       s++;
00953     }
00954 
00955     return false;
00956   }
00957 
00958   while ( *pattern != '*' )
00959   {
00960     if ( *pattern == '?' ) {
00961       if ( *s) {
00962         pattern++;
00963         s++;
00964         continue;
00965       }
00966       return false;
00967     }
00968     
00969     if ( *pattern == '\\' ) {
00970       switch( pattern[1] )
00971       {
00972       case '*':
00973       case '?':
00974         pattern++;
00975         break;
00976       }
00977     }
00978     if ( *pattern != *s ) {
00979       return false;
00980     }
00981 
00982     if ( *s == 0 )
00983       return true;
00984 
00985     pattern++;
00986     s++;
00987   }
00988   
00989   return ON_WildCardMatch(s,pattern);
00990 }
00991 
00992 
00993 bool ON_WildCardMatchNoCase(const wchar_t* s, const wchar_t* pattern)
00994 {
00995   if ( !pattern || !pattern[0] ) {
00996     return ( !s || !s[0] ) ? true : false;
00997   }
00998 
00999   if ( *pattern == '*' ) 
01000   {
01001     pattern++;
01002     while ( *pattern == '*' )
01003       pattern++;
01004     
01005     if ( !pattern[0] )
01006       return true;
01007 
01008     while (*s) {
01009       if ( ON_WildCardMatchNoCase(s,pattern) )
01010         return true;
01011       s++;
01012     }
01013 
01014     return false;
01015   }
01016 
01017   while ( *pattern != '*' )
01018   {
01019     if ( *pattern == '?' )
01020     {
01021       if ( *s) {
01022         pattern++;
01023         s++;
01024         continue;
01025       }
01026       return false;
01027     }
01028     
01029     if ( *pattern == '\\' )
01030     {
01031       switch( pattern[1] )
01032       {
01033       case '*':
01034       case '?':
01035         pattern++;
01036         break;
01037       }
01038     }
01039     if ( towupper(*pattern) != towupper(*s) )
01040     {
01041       return false;
01042     }
01043 
01044     if ( *s == 0 )
01045       return true;
01046 
01047     pattern++;
01048     s++;
01049   }
01050   
01051   return ON_WildCardMatchNoCase(s,pattern);
01052 }
01053 
01054 bool ON_wString::WildCardMatch( const wchar_t* pattern ) const
01055 {
01056   return ON_WildCardMatch(m_s,pattern);
01057 }
01058 
01059 
01060 bool ON_wString::WildCardMatchNoCase( const wchar_t* pattern ) const
01061 {
01062   return ON_WildCardMatchNoCase(m_s,pattern);
01063 }
01064 
01065 /*
01066 static TestReplace( ON_TextLog* text_log )
01067 {
01068   int len, len1, len2, i, count, gap, k, i0, repcount, replen;
01069   ON_wString str;
01070 
01071   bool bRepeat = false;
01072 
01073   wchar_t ws[1024], wsToken1[1024], wsToken2[1024];
01074 
01075   memset(ws,     0,sizeof(ws));
01076   memset(wsToken1,0,sizeof(wsToken1));
01077   memset(wsToken2,0,sizeof(wsToken2));
01078 
01079         for ( len = 1; len < 32; len++ )
01080   {
01081     for ( len1 = 1; len1 < len+1; len1++ )
01082     {
01083       if ( len1 > 0 )
01084         wsToken1[0] = '<';
01085       for ( i = 1; i < len1-1; i++ )
01086         wsToken1[i] = '-';
01087       if ( len1 > 1 )
01088         wsToken1[len1-1] = '>';
01089       wsToken1[len1] = 0;
01090 
01091       for ( len2 = 1; len2 < len1+5; len2++ )
01092       {
01093         if ( len2 > 0 )
01094           wsToken2[0] = '+';
01095         for ( i = 1; i < len2-1; i++ )
01096           wsToken2[i] = '=';
01097         if ( len2 > 1 )
01098           wsToken2[len2-1] = '*';
01099         wsToken2[len2] = 0;
01100 
01101         for ( k = 1; k*len1 <= len+1; k++ )
01102         {
01103           gap = (len/k) - len1;
01104           if (0 == len1 && gap < 1 )
01105             gap = 1;
01106           else if ( gap < 0 )
01107             gap = 0;
01108           bRepeat = false;
01109           for ( i0 = 0; i0 < 2*len1 + gap; i0++ )
01110           {
01111             for ( i = 0; i < len; i++ )
01112             {
01113               ws[i] = (wchar_t)('a' + (i%26));
01114             }
01115             ws[len] = 0;
01116             count = 0;
01117             for ( i = i0; i+len1 <= len; i += (gap+len1) )
01118             {
01119               memcpy(&ws[i],wsToken1,len1*sizeof(ws[0]));
01120               count++;
01121             }
01122             str = ws;
01123             repcount = str.Replace(wsToken1,wsToken2);
01124             replen = str.Length();
01125             if ( repcount != count || replen != len + count*(len2-len1) )
01126             {
01127               if ( text_log )
01128               {
01129                 text_log->Print("%ls -> %ls failed\n",wsToken1,wsToken2);
01130                 text_log->Print("%ls (%d tokens, %d chars)\n",ws,count,len);
01131                 text_log->Print("%ls (%d tokens, %d chars)\n",str.Array(),repcount,replen);
01132               }
01133               if ( bRepeat )
01134               {
01135                 bRepeat = false;
01136               }
01137               else
01138               {
01139                 bRepeat = true;
01140                 i0--;
01141               }
01142             }
01143           }
01144           bRepeat = false;
01145         }
01146       }
01147     }
01148   }
01149 }
01150 */
01151 
01152 int ON_wString::Replace( const wchar_t* token1, const wchar_t* token2 )
01153 {
01154   int count = 0;
01155 
01156   if ( 0 != token1 && 0 != token1[0] )
01157   {
01158     if ( 0 == token2 )
01159       token2 = L"";
01160     const int len1 = (int)wcslen(token1);
01161     if ( len1 > 0 )
01162     {
01163       const int len2 = (int)wcslen(token2);
01164       int len = Length();
01165       if ( len >= len1 )
01166       {
01167         // in-place
01168         ON_SimpleArray<int> n(32);
01169         const wchar_t* s = m_s;
01170         int i;
01171         for ( i = 0; i <= len-len1; /*empty*/ )
01172         {
01173           if ( wcsncmp(s,token1,len1) )
01174           {
01175             s++;
01176             i++;
01177           }
01178           else
01179           {
01180             n.Append(i);
01181             i += len1;
01182             s += len1;
01183           }
01184         }
01185 
01186         count = n.Count();
01187 
01188         // reserve array space - must be done even when len2 <= len1
01189         // so that shared arrays are not corrupted.
01190         const int newlen = len + (count*(len2-len1));
01191         if ( 0 == newlen )
01192         {
01193           Destroy();
01194           return count;
01195         }
01196 
01197         CopyArray();
01198 
01199         // 24 August 2006 Dale Lear
01200         //    This used to say
01201         //       ReserveArray(newlen);
01202         //    but when newlen < len and the string had multiple
01203         //    references, the ReserveArray(newlen) call truncated
01204         //    the input array.  
01205         ReserveArray( (newlen<len) ? len : newlen );
01206 
01207         int i0, i1, ni, j;
01208 
01209         if ( len2 > len1 )
01210         {
01211           // copy from back to front
01212           i1 = newlen;
01213           i0 = len;
01214           for ( ni =0; ni < count; ni++ )
01215             n[ni] = n[ni] + len1;
01216           for ( ni = count-1; ni >= 0; ni-- )
01217           {
01218             j = n[ni];
01219             while ( i0 > j )
01220             {
01221               i0--;
01222               i1--;
01223               m_s[i1] = m_s[i0];
01224             }
01225             i1 -= len2;
01226             i0 -= len1;
01227             memcpy(&m_s[i1],token2,len2*sizeof(m_s[0]));
01228           }
01229         }
01230         else
01231         {
01232           // copy from front to back
01233           i0 = i1 = n[0];
01234           n.Append(len);
01235           for ( ni = 0; ni < count; ni++ )
01236           {
01237             if ( len2 > 0 )
01238             {
01239               memcpy(&m_s[i1],token2,len2*sizeof(m_s[0]));
01240               i1 += len2;
01241             }
01242             i0 += len1;
01243             j = n[ni+1];
01244             while ( i0 < j )
01245             {
01246               m_s[i1++] = m_s[i0++];
01247             }
01248           }
01249         }
01250         Header()->string_length = newlen;
01251         m_s[newlen] = 0;
01252       }
01253     }
01254   }
01255 
01256   return count;
01257 }
01258 
01259 int ON_wString::Replace( wchar_t token1, wchar_t token2 )
01260 {
01261   int count = 0;
01262   int i = Length();
01263   while (i--)
01264   {
01265     if ( token1 == m_s[i] )
01266     {
01267       if ( 0 == count )
01268         CopyArray();
01269       m_s[i] = token2;
01270       count++;
01271     }
01272   }
01273   return count;
01274 }
01275 
01276 
01277 void ON_wString::UrlEncode()
01278 {
01279   wchar_t c, c0, c1;
01280   wchar_t* buffer = 0;
01281   wchar_t* s1 = 0;
01282   const wchar_t* s = Array();
01283   const int count = Length();
01284   int i;
01285 
01286   for ( i = 0; i < count; i++ )
01287   {
01288     c = *s++;
01289     if ( 0 == c )
01290       break;
01291     if ('0' <= c && c <= '9')
01292     {
01293       if ( s1 )
01294         *s1++ = c;
01295       continue;
01296     }
01297     if ('a' <= c && c <= 'z')
01298     {
01299       if ( s1 )
01300         *s1++ = c;
01301       continue;
01302     }
01303     if ('A' <= c && c <= 'Z')
01304     {
01305       if ( s1 )
01306         *s1++ = c;
01307       continue;
01308     }
01309     if (c >= 256)
01310     {
01311       if ( s1 )
01312         *s1++ = c;
01313       continue;
01314     }
01315 
01316     // convert this character to %xx
01317     if ( !s1 )
01318     {
01319       buffer = (wchar_t*)onmalloc((count*3 + 1)*sizeof(buffer[0]));
01320       if ( i > 0 )
01321         memcpy(buffer,Array(),i*sizeof(buffer[0]));
01322       s1 = buffer+i;
01323     }
01324     c0 = ((c/16)%16) + '0';
01325     if ( c0 > '9' )
01326       c0 += ('A'-'9'-1);
01327     c1 = (c%16) + '0';
01328     if ( c1 > '9' )
01329       c1 += ('A'-'9'-1);
01330     *s1++ = '%';
01331     *s1++ = c0;
01332     *s1++ = c1;
01333   }
01334   if ( s1 )
01335   {
01336     *s1 = 0;
01337     *this = buffer;
01338     onfree(buffer);
01339   }
01340 }
01341 
01342 static bool UrlDecodeHelper( wchar_t* s)
01343 {
01344   // if s[0] and s[1] are hex digits, then s[1] is
01345   // set to the wchar_t with that hex value.
01346   if ( !s )
01347     return false;
01348 
01349   wchar_t c0 = *s++;
01350   if ( c0 >= '0' && c0 <= '9' )
01351     c0 -= '0';
01352   else if ( c0 >= 'A' && c0 <= 'F' )
01353     c0 -= 'A' - 0x0A;
01354   else if ( c0 >= 'a' && c0 <= 'f' )
01355     c0 -= 'a' - 0x0A;
01356   else
01357     return false;
01358 
01359   wchar_t c1 = *s;
01360   if ( c1 >= '0' && c1 <= '9' )
01361     c1 -= '0';
01362   else if ( c1 >= 'A' && c1 <= 'F' )
01363     c1 -= 'A' - 0x0A;
01364   else if ( c1 >= 'a' && c1 <= 'f' )
01365     c1 -= 'a' - 0x0A;
01366   else
01367     return false;
01368 
01369   *s = c0*0x10 + c1;
01370   return true;
01371 }
01372 
01373 static bool IsValidUrlChar(wchar_t c)
01374 {
01375   if ( c >= '0' && c <= '9' )
01376     return true;
01377   if ( c >= 'A' && c <= 'Z' )
01378     return true;
01379   if ( c >= 'A' && c <= 'z' )
01380     return true;
01381 
01382   // ON_wString::UrlEncode() encodes assumes the following
01383   // characters are literal and encodes them.  However,
01384   // it is permitted for these characters to appear in
01385   // a URL.
01386   switch(c)
01387   {
01388   case '$':
01389   case '-':
01390   case '_':
01391   case '.':
01392   case '+':
01393   case '!':
01394   case '*':
01395   case '\'':
01396   case '(':
01397   case ')':
01398     // RFC 1738 character
01399     return true;
01400   case '&':
01401   case ',':
01402   case '/':
01403   case ':':
01404   case ';':
01405   case '=':
01406   case '?':
01407   case '@':
01408     // permitted URL syntax character
01409     return true;
01410   case '#':
01411     //  URL bookmark character
01412     return true;
01413   }
01414 
01415   return false;
01416 }
01417 
01418 bool ON_wString::UrlDecode()
01419 {
01420   CopyArray();
01421 
01422   bool rc = true;
01423   wchar_t c;
01424   wchar_t* s0 = Array();
01425   if ( !s0 )
01426     return true;
01427   wchar_t* s1 = s0;
01428   //const wchar_t* debg = s1;
01429   int i;
01430   for (i = Length(); i > 0; i-- )
01431   {
01432     c = *s0++;
01433     if (0==c)
01434       break;
01435     if (i >= 3 && '%' == c && UrlDecodeHelper(s0) )
01436     {
01437       s0++;
01438       *s1++ = *s0++;
01439       i -= 2;
01440     }
01441     else
01442     {
01443       *s1++ = c;
01444       if (rc)
01445         rc = IsValidUrlChar(c);
01446     }
01447   }
01448   *s1 = 0;
01449   SetLength(s1 - Array());
01450   return rc;
01451 }
01452 
01453 
01454 
01455 static bool IsWhiteSpaceHelper( wchar_t c, const wchar_t* whitespace )
01456 {
01457   while ( *whitespace )
01458   {
01459     if ( c == *whitespace++ )
01460       return true;
01461   }
01462   return false;
01463 }
01464 
01465 int ON_wString::ReplaceWhiteSpace( wchar_t token, const wchar_t* whitespace )
01466 {
01467   wchar_t* s0;
01468   wchar_t* s1;
01469   int n;
01470   wchar_t c;
01471 
01472   if ( 0 == (s0 = m_s) )
01473     return 0;
01474   s1 = s0 + Length();
01475   if ( whitespace && *whitespace )
01476   {
01477     while( s0 < s1 )
01478     {
01479       if (IsWhiteSpaceHelper(*s0++,whitespace))
01480       {
01481         // need to modify this string
01482         n = ((int)(s0 - m_s)); // keep win64 happy with (int) cast
01483         CopyArray(); // may change m_s if string has multiple refs
01484         s0 = m_s + n;
01485         s1 = m_s + Length();
01486         s0[-1] = token;
01487         n = 1;
01488         while ( s0 < s1 )
01489         {
01490           if ( IsWhiteSpaceHelper(*s0++,whitespace) )
01491           {
01492             s0[-1] = token;
01493             n++;
01494           }
01495         }
01496         return n;
01497       }
01498     }
01499   }
01500   else
01501   {
01502     while( s0 < s1 )
01503     {
01504       c = *s0++;
01505       if ( (1 <= c && c <= 32) || 127 == c )
01506       {
01507         // need to modify this string
01508         n = ((int)(s0 - m_s)); // keep win64 happy with (int) cast
01509         CopyArray(); // may change m_s if string has multiple refs
01510         s0 = m_s + n;
01511         s1 = m_s + Length();
01512         s0[-1] = token;
01513         n = 1;
01514         while ( s0 < s1 )
01515         {
01516           c = *s0++;
01517           if ( (1 <= c && c <= 32) || 127 == c )
01518           {
01519             s0[-1] = token;
01520             n++;
01521           }
01522         }
01523         return n;
01524       }
01525     }
01526   }
01527   return 0;
01528 }
01529 
01530 int ON_wString::RemoveWhiteSpace( const wchar_t* whitespace )
01531 {
01532   wchar_t* s0;
01533   wchar_t* s1;
01534   wchar_t* s;
01535   int n;
01536   wchar_t c;
01537 
01538   if ( 0 == (s0 = m_s) )
01539     return 0;
01540   s1 = s0 + Length();
01541   if ( whitespace && *whitespace )
01542   {
01543     while( s0 < s1 )
01544     {
01545       if (IsWhiteSpaceHelper(*s0++,whitespace))
01546       {
01547         // need to modify this string
01548         n = ((int)(s0 - m_s)); // keep win64 happy with (int) cast
01549         CopyArray(); // may change m_s if string has multiple refs
01550         s0 = m_s + n;
01551         s = s0-1;
01552         s1 = m_s + Length();
01553         while ( s0 < s1 )
01554         {
01555           if ( !IsWhiteSpaceHelper(*s0,whitespace) )
01556           {
01557             *s++ = *s0;
01558           }
01559           s0++;
01560         }
01561         *s = 0;
01562         n = ((int)(s1 - s)); // keep win64 happy with (int) cast
01563         Header()->string_length -= n;
01564         return n;
01565       }
01566     }
01567   }
01568   else
01569   {
01570     while( s0 < s1 )
01571     {
01572       c = *s0++;
01573       if ( (1 <= c && c <= 32) || 127 == c )
01574       {
01575         // need to modify this string
01576         n = ((int)(s0 - m_s)); // keep win64 happy with (int) cast
01577         CopyArray(); // may change m_s if string has multiple refs
01578         s0 = m_s + n;
01579         s = s0-1;
01580         s1 = m_s + Length();
01581         while ( s0 < s1 )
01582         {
01583           c = *s0;
01584           if ( c < 1 || (c > 32 && 127 != c) )
01585           {
01586             *s++ = *s0;
01587           }
01588           s0++;
01589         }
01590         *s = 0;
01591         n = ((int)(s1 - s)); // keep win64 happy with (int) cast
01592         Header()->string_length -= n;
01593         return n;
01594       }
01595     }
01596   }
01597   return 0;
01598 }
01599 
01600 
01602 
01603 ON_wString::operator const wchar_t*() const
01604 {
01605   return ( m_s == pEmptywString ) ? NULL : m_s;
01606 }
01607 
01608 int ON_wString::Find( char c ) const
01609 {
01610         // find first single character
01611   char s[2];
01612   s[0] = c;
01613   s[1] = 0;
01614   return Find( s );
01615 }
01616 
01617 int ON_wString::Find( unsigned char c ) const
01618 {
01619   return Find( (char)c );
01620 }
01621 
01622 int ON_wString::Find( wchar_t c ) const
01623 {
01624         // find first single character
01625   wchar_t s[2];
01626   s[0] = c;
01627   s[1] = 0;
01628   return Find( s );
01629 }
01630 
01631 int ON_wString::ReverseFind( char c ) const
01632 {
01633   wchar_t w = c2w(c);
01634   return ReverseFind( w );
01635 }
01636 
01637 int ON_wString::ReverseFind( unsigned char c ) const
01638 {
01639   wchar_t w = c2w((char)c);
01640   return ReverseFind( w );
01641 }
01642 
01643 int ON_wString::ReverseFind( wchar_t c ) const
01644 {
01645         // find first single character
01646   if ( IsEmpty() )
01647     return -1;
01648   int i;
01649   const int length = Length();
01650   for ( i = length-1; i >= 0; i-- ) {
01651     if ( c == m_s[i] )
01652       return i;
01653   }
01654   return -1;
01655 }
01656 
01657 int ON_wString::Find( const char* s ) const
01658 {
01659   int rc = -1;
01660   if ( s && s[0] && !IsEmpty() ) {
01661     const int s_count = (int)strlen(s); // the (int) is for 64 bit size_t conversion
01662     wchar_t* w = (wchar_t*)onmalloc( (s_count+2)*sizeof(w[0]) );
01663     c2w( s_count, s, s_count+1, w );
01664     const wchar_t* p;
01665     p = wcsstr( m_s, w );
01666     if ( p )
01667     {
01668       rc = ((int)(p-m_s)); // the (int) cast is for 64 bit compilers
01669     }
01670     onfree( w );
01671   }
01672   return rc;
01673 }
01674 
01675 int ON_wString::Find( const unsigned char* s ) const
01676 {
01677   return Find( (const char*)s );
01678 }
01679 
01680 int ON_wString::Find( const wchar_t* s ) const
01681 {
01682   int rc = -1;
01683   if ( s && s[0] && !IsEmpty() ) {
01684     const wchar_t* p;
01685     p = wcsstr( m_s, s );
01686     if ( p )
01687     {
01688       rc = ((int)(p-m_s)); // the (int) is for 64 bit size_t conversion
01689     }
01690   }
01691   return rc;
01692 }
01693 
01694 void ON_wString::MakeReverse()
01695 {
01696   if ( !IsEmpty() ) {
01697         CopyArray();
01698     on_wcsrev(m_s);
01699   }
01700 }
01701 
01702 void ON_wString::TrimLeft(const wchar_t* s)
01703 {
01704   wchar_t c;
01705   const wchar_t* sc;
01706   wchar_t* dc;
01707   int i;
01708   if ( !IsEmpty() ) {
01709     if ( !s )
01710       s = L" \t\n";
01711     for ( i = 0; 0 != (c=m_s[i]); i++ )
01712     {
01713       for (sc = s;*sc;sc++) {
01714         if ( *sc == c )
01715           break;
01716       }
01717       if (!(*sc))
01718         break;
01719     }
01720     if ( i > 0 ) {
01721       if ( m_s[i] ) {
01722         CopyArray();
01723         dc = m_s;
01724         sc = m_s+i;
01725         while( 0 != (*dc++ = *sc++) );
01726         Header()->string_length -= i;
01727       }
01728       else
01729         Destroy();
01730     }
01731   }
01732 }
01733 
01734 void ON_wString::TrimRight(const wchar_t* s)
01735 {
01736   wchar_t c;
01737   const wchar_t* sc;
01738   int i = Header()->string_length;
01739   if ( i > 0 ) {
01740     if ( !s )
01741       s = L" \t\n";
01742     for (i--; i >= 0 && 0 != (c=m_s[i]); i-- )
01743     {
01744       for (sc = s;*sc;sc++) {
01745         if ( *sc == c )
01746           break;
01747       }
01748       if (!(*sc))
01749         break;
01750     }
01751     if ( i < 0 )
01752       Destroy();
01753     else if ( m_s[i+1] ) {
01754       CopyArray();
01755       m_s[i+1] = 0;
01756       Header()->string_length = i+1;
01757     }
01758   }
01759 }
01760 
01761 void ON_wString::TrimLeftAndRight(const wchar_t* s)
01762 {
01763   TrimRight(s);
01764   TrimLeft(s);
01765 }
01766 
01767 
01768 int ON_wString::Remove( wchar_t c)
01769 {
01770   wchar_t* s0;
01771   wchar_t* s1;
01772   wchar_t* s;
01773   int n;
01774 
01775   if ( 0 == (s0 = m_s) )
01776     return 0;
01777   s1 = s0 + Length();
01778   while( s0 < s1 )
01779   {
01780     if (c == *s0++)
01781     {
01782       // need to modify this string
01783       n = ((int)(s0 - m_s)); // keep win64 happy with (int) cast
01784       CopyArray(); // may change m_s if string has multiple refs
01785       s0 = m_s + n;
01786       s = s0-1;
01787       s1 = m_s + Length();
01788       while ( s0 < s1 )
01789       {
01790         if ( c != *s0 )
01791         {
01792           *s++ = *s0;
01793         }
01794         s0++;
01795       }
01796       *s = 0;
01797       n = ((int)(s1 - s)); // keep win64 happy with (int) cast
01798       Header()->string_length -= n;
01799       return n;
01800     }
01801   }
01802   return 0;
01803 }
01804 
01805 wchar_t ON_wString::GetAt( int i ) const
01806 {
01807   return m_s[i];
01808 }
01809 
01810 
01811 void ON_wString::SetAt( int i, char c )
01812 {
01813   if ( i >= 0 && i < Header()->string_length ) {
01814           CopyArray();
01815           m_s[i] = c2w(c);
01816   }
01817 }
01818 
01819 void ON_wString::SetAt( int i, unsigned char c )
01820 {
01821   SetAt( i, (char)c );
01822 }
01823 
01824 void ON_wString::SetAt( int i, wchar_t c )
01825 {
01826   if ( i >= 0 && i < Header()->string_length ) {
01827           CopyArray();
01828           m_s[i] = c;
01829   }
01830 }
01831 
01832 ON_wString ON_wString::Mid(int i, int count) const
01833 {
01834   ON_wString(s);
01835   if ( i >= 0 && i < Length() && count > 0 ) {
01836     if ( count > Length() - i )
01837       count = Length() - i;
01838     s.CopyToArray( count, &m_s[i] );
01839   }
01840   return s;
01841 }
01842 
01843 ON_wString ON_wString::Mid(int i) const
01844 {
01845   return Mid( i, Length() - i );
01846 }
01847 
01848 ON_wString ON_wString::Left(int count) const
01849 {
01850   ON_wString s;
01851   if ( count > Length() )
01852     count = Length();
01853   if ( count > 0 ) {
01854     s.CopyToArray( count, m_s );
01855   }
01856   return s;
01857 }
01858 
01859 ON_wString ON_wString::Right(int count) const
01860 {
01861   ON_wString s;
01862   if ( count > Length() )
01863     count = Length();
01864   if ( count > 0 ) {
01865     s.CopyToArray( count, &m_s[Length()-count] );
01866   }
01867   return s;
01868 }
01869 
01870 void ON_MSC_CDECL ON_wString::Format( const char* sFormat, ...)
01871 {
01872 #define MAX_MSG_LENGTH 2048
01873   char sMessage[MAX_MSG_LENGTH];
01874   va_list args;
01875 
01876   /* put formatted message in sMessage */
01877   memset(sMessage,0,sizeof(sMessage));
01878   if (sFormat) {
01879     va_start(args, sFormat);
01880     on_vsnprintf(sMessage, MAX_MSG_LENGTH-1, sFormat, args);
01881     sMessage[MAX_MSG_LENGTH-1] = 0;
01882     va_end(args);
01883   }
01884   const int len = Length(sMessage);
01885   if ( len < 1 ) {
01886     Destroy();
01887     Create();
01888   }
01889   else {
01890     ReserveArray( len );
01891     CopyToArray( len, sMessage );
01892   }
01893 }
01894 
01895 void ON_MSC_CDECL ON_wString::Format( const unsigned char* sFormat, ...)
01896 {
01897 #define MAX_MSG_LENGTH 2048
01898   char sMessage[MAX_MSG_LENGTH];
01899   va_list args;
01900 
01901   /* put formatted message in sMessage */
01902   memset(sMessage,0,sizeof(sMessage));
01903   if (sFormat) {
01904     va_start(args, sFormat);
01905     on_vsnprintf(sMessage, MAX_MSG_LENGTH-1, (const char*)sFormat, args);
01906     sMessage[MAX_MSG_LENGTH-1] = 0;
01907     va_end(args);
01908   }
01909   const int len = Length(sMessage);
01910   if ( len < 1 ) {
01911     Destroy();
01912     Create();
01913   }
01914   else {
01915     ReserveArray( len );
01916     CopyToArray( len, sMessage );
01917   }
01918 }
01919 
01920 void ON_MSC_CDECL ON_wString::Format( const wchar_t* sFormat, ...)
01921 {
01922 #define MAX_MSG_LENGTH 2048
01923   wchar_t sMessage[MAX_MSG_LENGTH];
01924   va_list args;
01925 
01926   /* put formatted message in sMessage */
01927   memset(sMessage,0,sizeof(sMessage));
01928   if (sFormat) {
01929     va_start(args, sFormat);
01930     on_vsnwprintf(sMessage, MAX_MSG_LENGTH-1, sFormat, args);
01931     sMessage[MAX_MSG_LENGTH-1] = 0;
01932     va_end(args);
01933   }
01934   const int len = Length(sMessage);
01935   if ( len < 1 ) {
01936     Destroy();
01937     Create();
01938   }
01939   else {
01940     ReserveArray( len );
01941     CopyToArray( len, sMessage );
01942   }
01943 }
01944 
01946 
01947 bool ON_wString::operator==(const ON_wString& s2) const
01948 {
01949   return (Compare(s2) == 0) ? true : false;
01950 }
01951 
01952 bool ON_wString::operator==(const wchar_t* s2) const
01953 {
01954   return (Compare(s2) == 0) ? true : false;
01955 }
01956 
01957 bool ON_wString::operator!=(const ON_wString& s2) const
01958 {
01959   return (Compare(s2) != 0) ? true : false;
01960 }
01961 
01962 bool ON_wString::operator!=(const wchar_t* s2) const
01963 {
01964   return (Compare(s2) != 0) ? true : false;
01965 }
01966 
01967 bool ON_wString::operator<(const ON_wString& s2) const
01968 {
01969   return (Compare(s2) < 0) ? true : false;
01970 }
01971 
01972 bool ON_wString::operator<(const wchar_t* s2) const
01973 {
01974   return (Compare(s2) < 0) ? true : false;
01975 }
01976 
01977 bool ON_wString::operator>(const ON_wString& s2) const
01978 {
01979   return (Compare(s2) > 0) ? true : false;
01980 }
01981 
01982 bool ON_wString::operator>(const wchar_t* s2) const
01983 {
01984   return (Compare(s2) > 0) ? true : false;
01985 }
01986 
01987 bool ON_wString::operator<=(const ON_wString& s2) const
01988 {
01989   return (Compare(s2) <= 0) ? true : false;
01990 }
01991 
01992 bool ON_wString::operator<=(const wchar_t* s2) const
01993 {
01994   return (Compare(s2) <= 0) ? true : false;
01995 }
01996 
01997 bool ON_wString::operator>=(const ON_wString& s2) const
01998 {
01999   return (Compare(s2) >= 0) ? true : false;
02000 }
02001 
02002 bool ON_wString::operator>=(const wchar_t* s2) const
02003 {
02004   return (Compare(s2) >= 0) ? true : false;
02005 }
02006 
02007 
02008 void ON_String::SplitPath( 
02009     const char* path,
02010     ON_String* drive,
02011     ON_String* dir,
02012     ON_String* fname,
02013     ON_String* ext
02014     )
02015 {
02016   const char* dr = 0;
02017   const char* d = 0;
02018   const char* f = 0;
02019   const char* e = 0;
02020 
02021   on_splitpath(path,&dr,&d,&f,&e);
02022 
02023   if ( 0 != drive )
02024   {
02025     if ( 0 != dr )
02026     {
02027       if ( 0 != d )
02028         drive->CopyToArray((int)(d-dr),dr);
02029       else if ( 0 != f )
02030         drive->CopyToArray((int)(f-dr),dr);
02031       else if ( 0 != e )
02032         drive->CopyToArray((int)(e-dr),dr);
02033       else
02034         *drive = dr;
02035     }
02036     else
02037       drive->Empty();
02038   }
02039 
02040   if ( 0 != dir )
02041   {
02042     if ( 0 != d )
02043     {
02044       if ( 0 != f )
02045         dir->CopyToArray((int)(f-d),d);
02046       else if ( 0 != e )
02047         dir->CopyToArray((int)(e-d),d);
02048       else
02049         *dir = d;
02050     }
02051     else
02052       dir->Empty();
02053   }
02054 
02055   if ( 0 != fname )
02056   {
02057     if ( 0 != f )
02058     {
02059       if ( 0 != e )
02060         fname->CopyToArray((int)(e-f),f);
02061       else
02062         *fname = f;
02063     }
02064     else
02065       fname->Empty();
02066   }
02067 
02068   if ( 0 != ext )
02069   {
02070     *ext = e;
02071   }
02072 }
02073 
02074 void ON_wString::SplitPath( 
02075     const char* path,
02076     ON_wString* drive,
02077     ON_wString* dir,
02078     ON_wString* fname,
02079     ON_wString* ext
02080     )
02081 {
02082   const char* dr = 0;
02083   const char* d = 0;
02084   const char* f = 0;
02085   const char* e = 0;
02086 
02087   on_splitpath(path,&dr,&d,&f,&e);
02088 
02089   if ( 0 != drive )
02090   {
02091     if ( 0 != dr )
02092     {
02093       if ( 0 != d )
02094         drive->CopyToArray((int)(d-dr),dr);
02095       else if ( 0 != f )
02096         drive->CopyToArray((int)(f-dr),dr);
02097       else if ( 0 != e )
02098         drive->CopyToArray((int)(e-dr),dr);
02099       else
02100         *drive = dr;
02101     }
02102     else
02103       drive->Empty();
02104   }
02105 
02106   if ( 0 != dir )
02107   {
02108     if ( 0 != d )
02109     {
02110       if ( 0 != f )
02111         dir->CopyToArray((int)(f-d),d);
02112       else if ( 0 != e )
02113         dir->CopyToArray((int)(e-d),d);
02114       else
02115         *dir = d;
02116     }
02117     else
02118       dir->Empty();
02119   }
02120 
02121   if ( 0 != fname )
02122   {
02123     if ( 0 != f )
02124     {
02125       if ( 0 != e )
02126         fname->CopyToArray((int)(e-f),f);
02127       else
02128         *fname = f;
02129     }
02130     else
02131       fname->Empty();
02132   }
02133 
02134   if ( 0 != ext )
02135   {
02136     *ext = e;
02137   }
02138 }
02139 
02140 void ON_wString::SplitPath( 
02141     const wchar_t* path,
02142     ON_wString* drive,
02143     ON_wString* dir,
02144     ON_wString* fname,
02145     ON_wString* ext
02146     )
02147 {
02148   const wchar_t* dr = 0;
02149   const wchar_t* d = 0;
02150   const wchar_t* f = 0;
02151   const wchar_t* e = 0;
02152 
02153   on_wsplitpath(path,&dr,&d,&f,&e);
02154 
02155   if ( 0 != drive )
02156   {
02157     if ( 0 != dr )
02158     {
02159       if ( 0 != d )
02160         drive->CopyToArray((int)(d-dr),dr);
02161       else if ( 0 != f )
02162         drive->CopyToArray((int)(f-dr),dr);
02163       else if ( 0 != e )
02164         drive->CopyToArray((int)(e-dr),dr);
02165       else
02166         *drive = dr;
02167     }
02168     else
02169       drive->Empty();
02170   }
02171 
02172   if ( 0 != dir )
02173   {
02174     if ( 0 != d )
02175     {
02176       if ( 0 != f )
02177         dir->CopyToArray((int)(f-d),d);
02178       else if ( 0 != e )
02179         dir->CopyToArray((int)(e-d),d);
02180       else
02181         *dir = d;
02182     }
02183     else
02184       dir->Empty();
02185   }
02186 
02187   if ( 0 != fname )
02188   {
02189     if ( 0 != f )
02190     {
02191       if ( 0 != e )
02192         fname->CopyToArray((int)(e-f),f);
02193       else
02194         *fname = f;
02195     }
02196     else
02197       fname->Empty();
02198   }
02199 
02200   if ( 0 != ext )
02201   {
02202     *ext = e;
02203   }
02204 }
02205 


pcl
Author(s): Open Perception
autogenerated on Wed Aug 26 2015 15:27:03