opennurbs_string.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 
00020 // Empty strings point at empty_astring
00021 
00022 
00023 struct ON_aStringHeader
00024 {
00025         int   ref_count;       // reference count (>=0 or -1 for empty string)
00026         int   string_length;   // does not include NULL terminator
00027         int   string_capacity; // does not include NULL terminator
00028   char* string_array() {return (char*)(this+1);}
00029 };
00030 
00031 static struct {
00032   ON_aStringHeader header;
00033   char           s;  
00034 } empty_astring = { {-1, 0, 0}, 0 }; // ref_count=-1, length=0, capacity=0, s=0 
00035 static ON_aStringHeader* pEmptyStringHeader = &empty_astring.header;
00036 static const char* pEmptyaString = &empty_astring.s;
00037 
00039 // protected helpers
00040 
00041 void ON_String::Create()
00042 {
00043   m_s = (char*)pEmptyaString;
00044 }
00045 
00046 void ON_String::Destroy()
00047 {
00048   ON_aStringHeader* p = Header();
00049   if ( p != pEmptyStringHeader && p->ref_count > 0 ) {
00050     p->ref_count--;
00051                 if ( p->ref_count == 0 )
00052                         onfree(p);
00053   }
00054         Create();
00055 }
00056 
00057 void ON_String::Empty()
00058 {
00059   ON_aStringHeader* p = Header();
00060   if ( p != pEmptyStringHeader ) {
00061     if ( p->ref_count > 1 ) {
00062       // string memory is shared
00063       p->ref_count--;
00064             Create();
00065     }
00066     else if ( p->ref_count == 1 ) {
00067       // string memory is not shared - reuse it
00068       if (m_s && p->string_capacity>0)
00069         *m_s = 0;
00070       p->string_length = 0;
00071     }
00072     else {
00073       // should not happen
00074       ON_ERROR("ON_String::Empty() encountered invalid header - fixed.");
00075       Create();
00076     }
00077   }
00078   else {
00079     // initialized again
00080           Create();
00081   }
00082 }
00083 
00084 void ON_String::EmergencyDestroy()
00085 {
00086         Create();
00087 }
00088 
00089 void ON_String::EnableReferenceCounting( bool bEnable )
00090 {
00091   // TODO fill this in;
00092 }
00093 
00094 bool ON_String::IsReferenceCounted() const
00095 {
00096   return true;
00097 }
00098 
00099 
00100 ON_aStringHeader* ON_String::Header() const
00101 {
00102   ON_aStringHeader* p = (ON_aStringHeader*)m_s;
00103   if (p)
00104     p--;
00105   else
00106     p = pEmptyStringHeader;
00107   return p;
00108 }
00109 
00110 void ON_String::CreateArray( int capacity )
00111 {
00112   Destroy();
00113   if ( capacity > 0 ) {
00114                 ON_aStringHeader* p =
00115                         (ON_aStringHeader*)onmalloc( sizeof(ON_aStringHeader) + (capacity+1)*sizeof(*m_s) );
00116                 p->ref_count = 1;
00117                 p->string_length = 0;
00118                 p->string_capacity = capacity;
00119                 m_s = p->string_array();
00120     memset( m_s, 0, (capacity+1)*sizeof(*m_s) );
00121   }
00122 }
00123 
00124 void ON_String::CopyArray()
00125 {
00126   // If 2 or more strings are using the array, it is duplicated.
00127   // Call CopyArray() before modifying array contents.
00128   ON_aStringHeader* p = Header();
00129   if ( p != pEmptyStringHeader && p && p->ref_count > 1 ) 
00130   {
00131     const char* s = m_s;
00132     // p and s remain valid after Destroy() because
00133     // will simply be decremented and no deallocation
00134     // will happen.
00135     Destroy();
00136     CopyToArray( p->string_capacity, s );
00137     if ( p->string_length < p->string_capacity )
00138     {
00139       Header()->string_length = p->string_length;
00140     }
00141   }
00142 }
00143 
00144 void ON_String::ReserveArray( size_t array_capacity )
00145 {
00146   ON_aStringHeader* p = Header();
00147   const int capacity = (int) array_capacity;
00148   if ( p == pEmptyStringHeader ) 
00149   {
00150                 CreateArray(capacity);
00151   }
00152   else if ( p->ref_count > 1 ) 
00153   {
00154                 CreateArray(capacity);
00155     ON_aStringHeader* p1 = Header();
00156     const int size = (capacity < p->string_length) ? capacity : p->string_length;
00157     if ( size > 0 ) 
00158     {
00159       memcpy( p1->string_array(), p->string_array(), size*sizeof(*m_s) );
00160       p1->string_length = size;
00161     }
00162   }
00163         else if ( capacity > p->string_capacity ) 
00164   {
00165                 p = (ON_aStringHeader*)onrealloc( p, sizeof(ON_aStringHeader) + (capacity+1)*sizeof(*m_s) );
00166     m_s = p->string_array();
00167     memset( &m_s[p->string_capacity], 0, (1+capacity-p->string_capacity)*sizeof(*m_s) );
00168     p->string_capacity = capacity;
00169         }
00170 }
00171 
00172 void ON_String::ShrinkArray()
00173 {
00174   ON_aStringHeader* p = Header();
00175   if ( p != pEmptyStringHeader ) {
00176     if ( p->string_length < 1 ) {
00177       Destroy();
00178     }
00179     else if ( p->ref_count > 1 ) {
00180       // shared string
00181       CreateArray(p->string_length);
00182                   ON_aStringHeader* p1 = Header();
00183       memcpy( m_s, p->string_array(), p->string_length*sizeof(*m_s));
00184       p1->string_length = p->string_length;
00185       m_s[p1->string_length] = 0;
00186     }
00187           else if ( p->string_length < p->string_capacity ) {
00188       // onrealloc string
00189                   p = (ON_aStringHeader*)onrealloc( p, sizeof(ON_aStringHeader) + (p->string_length+1)*sizeof(*m_s) );
00190       p->string_capacity = p->string_length;
00191       m_s = p->string_array();
00192       m_s[p->string_length] = 0;
00193           }
00194   }
00195 }
00196 
00197 void ON_String::CopyToArray( const ON_String& s )
00198 {
00199   CopyToArray( s.Length(), s.Array() );
00200 }
00201 
00202 void ON_String::CopyToArray( int size, const char* s )
00203 {
00204   if ( size > 0 && s && s[0] ) {
00205           ReserveArray(size);
00206           memcpy(m_s, s, size*sizeof(*m_s));
00207           Header()->string_length = size;
00208     m_s[Header()->string_length] = 0;
00209   }
00210   else {
00211     if ( Header()->ref_count > 1 )
00212       Destroy();
00213     else {
00214       Header()->string_length = 0;
00215       m_s[0] = 0;
00216     }
00217   }
00218 }
00219 
00220 void ON_String::CopyToArray( int size, const unsigned char* s )
00221 {
00222   CopyToArray( size, ((char*)s) );
00223 }
00224 
00225 void ON_String::AppendToArray( const ON_String& s )
00226 {
00227   AppendToArray( s.Length(), s.Array() );
00228 }
00229 
00230 void ON_String::AppendToArray( int size, const char* s )
00231 {
00232   if ( size > 0 && s && s[0] ) {
00233           ReserveArray(size + Header()->string_length );
00234     // m_s = char array
00235           memcpy(&m_s[Header()->string_length], s, size*sizeof(*m_s));
00236           Header()->string_length += size;
00237     m_s[Header()->string_length] = 0;
00238   }
00239 }
00240 
00241 void ON_String::AppendToArray( int size, const unsigned char* s )
00242 {
00243   AppendToArray( size, ((char*)s) );
00244 }
00245 
00246 int ON_String::Length( const char* s )
00247 {
00248   size_t slen = s ? strlen(s) : 0;
00249   int n = ((0 < slen && slen <= 2147483645) ?((int)slen) : 0); // the (int) cast is for 64 bit size_t conversion
00250   return n;
00251 }
00252 
00253 int ON_String::Length( const unsigned char* s )
00254 {
00255   return ON_String::Length((const char*)s);
00256 }
00257 
00259 // Construction/Destruction
00260 
00261 ON_String::ON_String()
00262 {
00263         Create();
00264 }
00265 
00266 ON_String::~ON_String()
00267 {
00268   Destroy();
00269 }
00270 
00271 ON_String::ON_String(const ON_String& src)
00272 {
00273         if (    src.Header()->ref_count > 0 
00274        && 0 == ON_WorkerMemoryPool()
00275      )  
00276   {
00277                 m_s = src.m_s;
00278     src.Header()->ref_count++;
00279         }
00280         else 
00281   {
00282                 Create();
00283                 *this = src.m_s; // use operator=(const char*) to copy
00284         }
00285 }
00286 
00287 ON_String::ON_String( const char* s )
00288 {
00289         Create();
00290   if ( s && s[0] ) {
00291     CopyToArray( (int)strlen(s), s ); // the (int) is for 64 bit size_t conversion
00292   }
00293 }
00294 
00295 ON_String::ON_String( const char* s, int length )
00296 {
00297         Create();
00298   if ( s && length > 0 ) {
00299     CopyToArray(length,s);
00300         }
00301 }
00302 
00303 ON_String::ON_String( char c, int repeat_count )
00304 {
00305   Create();
00306   if ( repeat_count > 0 ) {
00307     ReserveArray(repeat_count);
00308     memset( m_s, c, repeat_count*sizeof(*m_s) );
00309     m_s[repeat_count] = 0;
00310     Header()->string_length = repeat_count;
00311   }
00312 }
00313 
00314 ON_String::ON_String( const unsigned char* s )
00315 {
00316         Create();
00317   if ( s && s[0] ) 
00318   {
00319     CopyToArray( (int)strlen((const char*)s), (const char*)s ); // the (int) is for 64 bit size_t conversion
00320   }
00321 }
00322 
00323 ON_String::ON_String( const unsigned char* s, int length )
00324 {
00325         Create();
00326   if ( s && length > 0 ) {
00327     CopyToArray(length,s);
00328         }
00329 }
00330 
00331 ON_String::ON_String( unsigned char c, int repeat_count )
00332 {
00333   Create();
00334   if ( repeat_count > 0 ) {
00335     ReserveArray(repeat_count);
00336     memset( m_s, c, repeat_count*sizeof(*m_s) );
00337     m_s[repeat_count] = 0;
00338     Header()->string_length = repeat_count;
00339   }
00340 }
00341 
00342 
00343 ON_String::ON_String( const wchar_t* w)
00344 {
00345   Create();
00346   if ( w && w[0] ) {
00347     *this = w;
00348   }
00349 }
00350 
00351 ON_String::ON_String( const wchar_t* w, int w_length )
00352 {
00353   // from substring
00354   Create();
00355   if ( w && w[0] ) {
00356     CopyToArray( w_length, w );
00357   }
00358 }
00359 
00360 
00361 ON_String::ON_String( const ON_wString& w )
00362 {
00363   Create();
00364   *this = w;
00365 }
00366 
00367 
00368 
00369 #if defined (ON_OS_WINDOWS)
00370 bool ON_String::LoadResourceString( HINSTANCE instance, UINT id )
00371 {
00372   char s[2048]; // room for 2047 characters
00373   int length;
00374 
00375   Destroy();
00376   length = ::LoadStringA( instance, id, s, 2047 );
00377   if ( length > 0 && length < 2048 ) {
00378     CopyToArray( length, s );
00379   }
00380   return (length > 0 );
00381 }
00382 #endif
00383 
00384 int ON_String::Length() const
00385 {
00386   return Header()->string_length;
00387 }
00388 
00389 // 25 October 2007 Dale Lear - remove bogus decl and defn
00390 //void Destroy();
00391 //void EmergencyDestroy()
00392 //{
00393 //}
00394 
00395 char& ON_String::operator[](int i)
00396 {
00397   CopyArray();
00398   return m_s[i];
00399 }
00400 
00401 char ON_String::operator[](int i) const
00402 {
00403   return m_s[i];
00404 }
00405 
00406 bool ON_String::IsEmpty() const
00407 {
00408   return (Header()->string_length <= 0 ) ? true : false;
00409 }
00410 
00411 ON_String& ON_String::operator=(const ON_String& src)
00412 {
00413         if (m_s != src.m_s)     
00414   {
00415     if ( src.IsEmpty() ) 
00416     {
00417       Destroy();
00418       Create();
00419     }
00420     else if (    src.Header()->ref_count > 0 
00421               && 0 == ON_WorkerMemoryPool()
00422             ) 
00423     {
00424       Destroy();
00425       src.Header()->ref_count++;
00426       m_s = src.m_s;
00427     }
00428     else 
00429     {
00430       ReserveArray(src.Length());
00431       memcpy( m_s, src.Array(), src.Length()*sizeof(*m_s));
00432       Header()->string_length = src.Length();
00433     }
00434   }
00435         return *this;
00436 }
00437 
00438 ON_String& ON_String::operator=( char c )
00439 {
00440         CopyToArray( 1, &c );
00441         return *this;
00442 }
00443 
00444 ON_String& ON_String::operator=( const char* s )
00445 {
00446   if ( (void*)s != (void*)m_s )
00447           CopyToArray( Length(s), s);
00448         return *this;
00449 }
00450 
00451 ON_String& ON_String::operator=( unsigned char c )
00452 {
00453         CopyToArray( 1, &c );
00454         return *this;
00455 }
00456 
00457 ON_String& ON_String::operator=( const unsigned char* s )
00458 {
00459   if ( (void*)s != (void*)m_s )
00460           CopyToArray( Length(s), s);
00461         return *this;
00462 }
00463 
00464 ON_String& ON_String::operator=( const wchar_t* w )
00465 {
00466   // converts wide string to byt string
00467   int w_length = 0;
00468   if ( w ) while ( w[w_length] ) w_length++;
00469   CopyToArray( w_length, w);
00470         return *this;
00471 }
00472 
00473 ON_String& ON_String::operator=( const ON_wString& w )
00474 {
00475   *this = w.Array();
00476   return *this;
00477 }
00478 
00479 
00480 ON_String ON_String::operator+(const ON_String& s2) const
00481 {
00482         ON_String s(*this);
00483   s.AppendToArray( s2 );
00484         return s;
00485 }
00486 
00487 ON_String ON_String::operator+( char s2 ) const
00488 {
00489         ON_String s(*this);
00490   s.AppendToArray( 1, &s2 );
00491         return s;
00492 }
00493 
00494 ON_String ON_String::operator+( unsigned char s2 ) const
00495 {
00496         ON_String s(*this);
00497   s.AppendToArray( 1, &s2 );
00498         return s;
00499 }
00500 
00501 ON_String ON_String::operator+(const char* s2) const
00502 {
00503         ON_String s(*this);
00504   s.AppendToArray( ON_String::Length(s2), s2 );
00505         return s;
00506 }
00507 
00508 ON_String ON_String::operator+( const unsigned char* s2) const
00509 {
00510         ON_String s(*this);
00511   s.AppendToArray( ON_String::Length(s2), s2 );
00512         return s;
00513 }
00514 
00516 // operator+=()
00517 
00518 
00519 void ON_String::Append( const char* s , int count )
00520 {
00521   // append specified number of characters
00522   if ( s && count > 0 )
00523     AppendToArray(count,s);
00524 }
00525 
00526 void ON_String::Append( const unsigned char* s , int count )
00527 {
00528   // append specified number of characters
00529   if ( s && count > 0 )
00530     AppendToArray(count,s);
00531 }
00532 
00533 
00534 const ON_String& ON_String::operator+=(const ON_String& s)
00535 {
00536   AppendToArray(s);
00537         return *this;
00538 }
00539 
00540 const ON_String& ON_String::operator+=( char s )
00541 {
00542   AppendToArray(1,&s);
00543         return *this;
00544 }
00545 
00546 const ON_String& ON_String::operator+=( unsigned char s )
00547 {
00548   AppendToArray(1,&s);
00549         return *this;
00550 }
00551 
00552 const ON_String& ON_String::operator+=( const char* s )
00553 {
00554   AppendToArray(Length(s),s);
00555         return *this;
00556 }
00557 
00558 const ON_String& ON_String::operator+=( const unsigned char* s )
00559 {
00560   AppendToArray(Length(s),s);
00561         return *this;
00562 }
00563 
00564 void ON_String::SetLength(size_t string_length)
00565 {
00566   int length = (int)string_length; // for 64 bit compilers
00567   if ( length >= Header()->string_capacity ) {
00568     ReserveArray(length);
00569   }
00570   if ( length >= 0 && length <= Header()->string_capacity ) {
00571     CopyArray();
00572     Header()->string_length = length;
00573     m_s[length] = 0;
00574   }
00575 }
00576 
00577 char* ON_String::Array()
00578 {
00579   CopyArray();
00580   return ( Header()->string_capacity > 0 ) ? m_s : 0;
00581 }
00582 
00583 const char* ON_String::Array() const
00584 {
00585   return ( Header()->string_capacity > 0 ) ? m_s : 0;
00586 }
00587 
00588 /*
00589 Returns:
00590   Total number of bytes of memory used by this class.
00591   (For use in ON_Object::SizeOf() overrides.
00592 */
00593 unsigned int ON_String::SizeOf() const
00594 {
00595   size_t sz = sizeof(*this);
00596   if ( ((const void*)m_s) != ((const void*)pEmptyaString) )
00597     sz += (sizeof(ON_aStringHeader) + (Header()->string_capacity+1));
00598   return (unsigned int)sz;
00599 }
00600 
00601 ON__UINT32 ON_String::DataCRC(ON__UINT32 current_remainder) const
00602 {
00603   int string_length = Header()->string_length;
00604   if ( string_length > 0 )
00605   {
00606     current_remainder = ON_CRC32(current_remainder,string_length*sizeof(*m_s),m_s);
00607   }
00608   return current_remainder;
00609 }
00610 
00611 int ON_String::Compare( const char* s ) const
00612 {
00613   int rc = 0;
00614   if ( s && s[0] ) {
00615     if ( IsEmpty() ) {
00616       rc = -1;
00617     }
00618     else {
00619       rc = strcmp( m_s, s );
00620     }
00621   }
00622   else {
00623     rc = IsEmpty() ? 0 : 1;
00624   }
00625   return rc;
00626 }
00627 
00628 int ON_String::Compare( const unsigned char* s) const
00629 {
00630   return ON_String::Compare((const char*)s);
00631 }
00632 
00633 int ON_String::CompareNoCase( const char* s) const
00634 {
00635   int rc = 0;
00636   if ( s && s[0] ) {
00637     if ( IsEmpty() ) {
00638       rc = -1;
00639     }
00640     else {
00641       rc = on_stricmp( m_s, s );
00642     }
00643   }
00644   else {
00645     rc = IsEmpty() ? 0 : 1;
00646   }
00647   return rc;
00648 }
00649 
00650 int ON_String::CompareNoCase( const unsigned char* s) const
00651 {
00652   return ON_String::CompareNoCase((const char*)s);
00653 }
00654 
00655 ON_String::operator const char*() const
00656 {
00657   return ( m_s == pEmptyaString ) ? NULL : m_s;
00658 }
00659 
00660 
00661 bool ON_WildCardMatch(const char* s, const char* pattern)
00662 {
00663   if ( !pattern || !pattern[0] ) {
00664     return ( !s || !s[0] ) ? true : false;
00665   }
00666 
00667   if ( *pattern == '*' ) {
00668     pattern++;
00669     while ( *pattern == '*' )
00670       pattern++;
00671     
00672     if ( !pattern[0] )
00673       return true;
00674 
00675     while (*s) {
00676       if ( ON_WildCardMatch(s,pattern) )
00677         return true;
00678       s++;
00679     }
00680 
00681     return false;
00682   }
00683 
00684   while ( *pattern != '*' )
00685   {
00686     if ( *pattern == '?' ) {
00687       if ( *s) {
00688         pattern++;
00689         s++;
00690         continue;
00691       }
00692       return false;
00693     }
00694     
00695     if ( *pattern == '\\' ) {
00696       switch( pattern[1] )
00697       {
00698       case '*':
00699       case '?':
00700         pattern++;
00701         break;
00702       }
00703     }
00704     if ( *pattern != *s ) {
00705       return false;
00706     }
00707 
00708     if ( *s == 0 )
00709       return true;
00710 
00711     pattern++;
00712     s++;
00713   }
00714   
00715   return ON_WildCardMatch(s,pattern);
00716 }
00717 
00718 
00719 bool ON_WildCardMatchNoCase(const char* s, const char* pattern)
00720 {
00721   if ( !pattern || !pattern[0] ) {
00722     return ( !s || !s[0] ) ? true : false;
00723   }
00724 
00725   if ( *pattern == '*' ) 
00726   {
00727     pattern++;
00728     while ( *pattern == '*' )
00729       pattern++;
00730     
00731     if ( !pattern[0] )
00732       return true;
00733 
00734     while (*s) {
00735       if ( ON_WildCardMatchNoCase(s,pattern) )
00736         return true;
00737       s++;
00738     }
00739 
00740     return false;
00741   }
00742 
00743   while ( *pattern != '*' )
00744   {
00745     if ( *pattern == '?' ) {
00746       if ( *s) {
00747         pattern++;
00748         s++;
00749         continue;
00750       }
00751       return false;
00752     }
00753     
00754     if ( *pattern == '\\' ) {
00755       switch( pattern[1] )
00756       {
00757       case '*':
00758       case '?':
00759         pattern++;
00760         break;
00761       }
00762     }
00763     if ( toupper(*pattern) != toupper(*s) ) {
00764       return false;
00765     }
00766 
00767     if ( *s == 0 )
00768       return true;
00769 
00770     pattern++;
00771     s++;
00772   }
00773   
00774   return ON_WildCardMatchNoCase(s,pattern);
00775 }
00776 
00777 bool ON_String::WildCardMatch( const char* pattern) const
00778 {
00779   return ON_WildCardMatch(m_s,pattern);
00780 }
00781 
00782 bool ON_String::WildCardMatch( const unsigned char* pattern ) const
00783 {
00784   return ON_WildCardMatch(m_s,(const char*)pattern);
00785 }
00786 
00787 bool ON_String::WildCardMatchNoCase( const char* pattern) const
00788 {
00789   return ON_WildCardMatchNoCase(m_s,pattern);
00790 }
00791 
00792 bool ON_String::WildCardMatchNoCase( const unsigned char* pattern ) const
00793 {
00794   return ON_WildCardMatchNoCase(m_s,(const char*)pattern);
00795 }
00796 
00797 int ON_String::Replace( const char* token1, const char* token2 )
00798 {
00799   int count = 0;
00800 
00801   if ( 0 != token1 && 0 != token1[0] )
00802   {
00803     if ( 0 == token2 )
00804       token2 = "";
00805     const int len1 = (int)strlen(token1);
00806     if ( len1 > 0 )
00807     {
00808       const int len2 = (int)strlen(token2);
00809       int len = Length();
00810       if ( len >= len1 )
00811       {
00812         // in-place
00813         ON_SimpleArray<int> n(32);
00814         const char* s = m_s;
00815         int i;
00816         for ( i = 0; i <= len-len1; /*empty*/ )
00817         {
00818           if ( strncmp(s,token1,len1) )
00819           {
00820             s++;
00821             i++;
00822           }
00823           else
00824           {
00825             n.Append(i);
00826             i += len1;
00827             s += len1;
00828           }
00829         }
00830 
00831         count = n.Count();
00832 
00833         // reserve array space - must be done even when len2 <= len1
00834         // so that shared arrays are not corrupted.
00835         const int newlen = len + (count*(len2-len1));
00836         if ( 0 == newlen )
00837         {
00838           Destroy();
00839           return count;
00840         }
00841 
00842         CopyArray();
00843 
00844         // 24 August 2006 Dale Lear
00845         //    This used to say
00846         //       ReserveArray(newlen);
00847         //    but when newlen < len and the string had multiple
00848         //    references, the ReserveArray(newlen) call truncated
00849         //    the input array.  
00850         ReserveArray( ((newlen<len) ? len : newlen) );
00851 
00852         int i0, i1, ni, j;
00853 
00854         if ( len2 > len1 )
00855         {
00856           // copy from back to front
00857           i1 = newlen;
00858           i0 = len;
00859           for ( ni =0; ni < count; ni++ )
00860             n[ni] = n[ni] + len1;
00861           for ( ni = count-1; ni >= 0; ni-- )
00862           {
00863             j = n[ni];
00864             while ( i0 > j )
00865             {
00866               i0--;
00867               i1--;
00868               m_s[i1] = m_s[i0];
00869             }
00870             i1 -= len2;
00871             i0 -= len1;
00872             memcpy(&m_s[i1],token2,len2*sizeof(m_s[0]));
00873           }
00874         }
00875         else
00876         {
00877           // copy from front to back
00878           i0 = i1 = n[0];
00879           n.Append(len);
00880           for ( ni = 0; ni < count; ni++ )
00881           {
00882             if ( len2 > 0 )
00883             {
00884               memcpy(&m_s[i1],token2,len2*sizeof(m_s[0]));
00885               i1 += len2;
00886             }
00887             i0 += len1;
00888             j = n[ni+1];
00889             while ( i0 < j )
00890             {
00891               m_s[i1++] = m_s[i0++];
00892             }
00893           }
00894         }
00895         Header()->string_length = newlen;
00896         m_s[newlen] = 0;
00897       }
00898     }
00899   }
00900 
00901   return count;
00902 }
00903 
00904 int ON_String::Replace( const unsigned char* token1, const unsigned char* token2 )
00905 {
00906   return Replace((const char*)token1, (const char*)token2);
00907 }
00908 
00909 int ON_String::Replace( char token1, char token2 )
00910 {
00911   int count = 0;
00912   int i = Length();
00913   while (i--)
00914   {
00915     if ( token1 == m_s[i] )
00916     {
00917       if ( 0 == count )
00918         CopyArray();
00919       m_s[i] = token2;
00920       count++;
00921     }
00922   }
00923   return count;
00924 }
00925 
00926 int ON_String::Replace( unsigned char token1, unsigned char token2 )
00927 {
00928   return Replace((const char)token1, (const char)token2);
00929 }
00930 
00931 
00933 
00934 int ON_String::Find( char c ) const
00935 {
00936         // find first single character
00937   char s[2];
00938   s[0] = c;
00939   s[1] = 0;
00940   return Find( s );
00941 }
00942 
00943 int ON_String::Find( unsigned char c ) const
00944 {
00945   return Find( (char)c );
00946 }
00947 
00948 int ON_String::ReverseFind( char c ) const
00949 {
00950         // find first single character
00951   if ( IsEmpty() )
00952     return -1;
00953   int i;
00954   const int length = Length();
00955   for ( i = length-1; i >= 0; i-- ) {
00956     if ( c == m_s[i] )
00957       return i;
00958   }
00959   return -1;
00960 }
00961 
00962 int ON_String::ReverseFind( unsigned char c ) const
00963 {
00964   return ReverseFind( (char)c );
00965 }
00966 
00967 int ON_String::Find( const char* s ) const
00968 {
00969   int rc = -1;
00970   if ( s && s[0] && !IsEmpty() ) {
00971     const char* p;
00972     p = strstr( m_s, s );
00973     if ( p )
00974     {
00975       rc = ((int)(p-m_s)); // the (int) is for 64 bit size_t conversion
00976     }
00977   }
00978   return rc;
00979 }
00980 
00981 int ON_String::Find( const unsigned char* s ) const
00982 {
00983   return Find( (const char*)s );
00984 }
00985 
00986 void ON_String::MakeUpper()
00987 {
00988   if ( !IsEmpty() ) {
00989         CopyArray();
00990     on_strupr(m_s);
00991   }
00992 }
00993 
00994 void ON_String::MakeLower()
00995 {
00996   if ( !IsEmpty() ) {
00997         CopyArray();
00998     on_strlwr(m_s);
00999   }
01000 }
01001 
01002 void ON_String::MakeReverse()
01003 {
01004   if ( !IsEmpty() ) {
01005         CopyArray();
01006     on_strrev(m_s);
01007   }
01008 }
01009 
01010 void ON_String::TrimLeft(const char* s)
01011 {
01012   char c;
01013   const char* sc;
01014   char* dc;
01015   int i;
01016   if ( !IsEmpty() ) {
01017     if ( !s )
01018       s = " \t\n";
01019     for ( i = 0; 0 != (c=m_s[i]); i++ )
01020     {
01021       for (sc = s;*sc;sc++) {
01022         if ( *sc == c )
01023           break;
01024       }
01025       if (!(*sc))
01026         break;
01027     }
01028     if ( i > 0 ) {
01029       if ( m_s[i] ) {
01030         CopyArray();
01031         dc = m_s;
01032         sc = m_s+i;
01033         while( 0 != (*dc++ = *sc++) );
01034         Header()->string_length -= i;
01035       }
01036       else
01037         Destroy();
01038     }
01039   }
01040 }
01041 
01042 void ON_String::TrimRight(const char* s)
01043 {
01044   char c;
01045   const char* sc;
01046   int i = Header()->string_length;
01047   if ( i > 0 ) {
01048     if ( !s )
01049       s = " \t\n";
01050     for (i--; i >= 0 && 0 != (c=m_s[i]); i-- )
01051     {
01052       for (sc = s;*sc;sc++) {
01053         if ( *sc == c )
01054           break;
01055       }
01056       if (!(*sc))
01057         break;
01058     }
01059     if ( i < 0 )
01060       Destroy();
01061     else if ( m_s[i+1] ) {
01062       CopyArray();
01063       m_s[i+1] = 0;
01064       Header()->string_length = i+1;
01065     }
01066   }
01067 }
01068 
01069 void ON_String::TrimLeftAndRight(const char* s)
01070 {
01071   TrimRight(s);
01072   TrimLeft(s);
01073 }
01074 
01075 int ON_String::Remove( const char chRemove)
01076 {
01077   CopyArray();
01078 
01079   char* pstrSource = m_s;
01080   char* pstrDest = m_s;
01081   char* pstrEnd = m_s + Length();
01082 
01083   while( pstrSource && pstrSource  < pstrEnd)
01084   {
01085     if (*pstrSource != chRemove)
01086     {
01087       *pstrDest = *pstrSource;
01088       pstrDest++;
01089     }
01090     pstrSource++;
01091   }
01092 
01093   *pstrDest = 0;
01094   int nCount = (int)(pstrSource - pstrDest); // the (int) is for 64 bit size_t conversion
01095 
01096   Header()->string_length -= nCount;
01097 
01098   return nCount;
01099 }
01100 
01101 char ON_String::GetAt( int i ) const
01102 {
01103   // no error checking
01104   return m_s[i];
01105 }
01106 
01107 void ON_String::SetAt( int i, char c )
01108 {
01109   if ( i >= 0 && i < Header()->string_length ) {
01110           CopyArray();
01111           m_s[i] = c;
01112   }
01113 }
01114 
01115 void ON_String::SetAt( int i, unsigned char c )
01116 {
01117   SetAt( i, (char)c );
01118 }
01119 
01120 ON_String ON_String::Mid(int i, int count) const
01121 {
01122   ON_String(s);
01123   if ( i >= 0 && i < Length() && count > 0 ) {
01124     if ( count > Length() - i )
01125       count = Length() - i;
01126     s.CopyToArray( count, &m_s[i] );
01127   }
01128   return s;
01129 }
01130 
01131 ON_String ON_String::Mid(int i) const
01132 {
01133   return Mid( i, Length() - i );
01134 }
01135 
01136 ON_String ON_String::Left(int count) const
01137 {
01138   ON_String s;
01139   if ( count > Length() )
01140     count = Length();
01141   if ( count > 0 ) {
01142     s.CopyToArray( count, m_s );
01143   }
01144   return s;
01145 }
01146 
01147 ON_String ON_String::Right(int count) const
01148 {
01149   ON_String s;
01150   if ( count > Length() )
01151     count = Length();
01152   if ( count > 0 ) {
01153     s.CopyToArray( count, &m_s[Length()-count] );
01154   }
01155   return s;
01156 }
01157 
01158 void ON_MSC_CDECL ON_String::Format( const char* sFormat, ...)
01159 {
01160 #define MAX_MSG_LENGTH 2048
01161   char sMessage[MAX_MSG_LENGTH];
01162   va_list args;
01163 
01164   /* put formatted message in sMessage */
01165   memset(sMessage,0,sizeof(sMessage));
01166   if (sFormat) {
01167     va_start(args, sFormat);
01168     on_vsnprintf(sMessage, MAX_MSG_LENGTH-1, sFormat, args);
01169     sMessage[MAX_MSG_LENGTH-1] = 0;
01170     va_end(args);
01171   }
01172   const int len = Length(sMessage);
01173   if ( len < 1 ) {
01174     Destroy();
01175     Create();
01176   }
01177   else {
01178     ReserveArray( len );
01179     CopyToArray( len, sMessage );
01180   }
01181 }
01182 
01183 void ON_MSC_CDECL ON_String::Format( const unsigned char* sFormat, ...)
01184 {
01185 #define MAX_MSG_LENGTH 2048
01186   char sMessage[MAX_MSG_LENGTH];
01187   va_list args;
01188 
01189   /* put formatted message in sMessage */
01190   memset(sMessage,0,sizeof(sMessage));
01191   if (sFormat) {
01192     va_start(args, sFormat);
01193     on_vsnprintf(sMessage, MAX_MSG_LENGTH-1, (const char*)sFormat, args);
01194     sMessage[MAX_MSG_LENGTH-1] = 0;
01195     va_end(args);
01196   }
01197   const int len = Length(sMessage);
01198   if ( len < 1 ) {
01199     Destroy();
01200     Create();
01201   }
01202   else {
01203     ReserveArray( len );
01204     CopyToArray( len, sMessage );
01205   }
01206 }
01207 
01209 
01210 bool ON_String::operator==(const ON_String& s2) const
01211 {
01212   return (Compare(s2) == 0) ? true : false;
01213 }
01214 
01215 bool ON_String::operator==(const char* s2) const
01216 {
01217   return (Compare(s2) == 0) ? true : false;
01218 }
01219 
01220 bool ON_String::operator!=(const ON_String& s2) const
01221 {
01222   return (Compare(s2) != 0) ? true : false;
01223 }
01224 
01225 bool ON_String::operator!=(const char* s2) const
01226 {
01227   return (Compare(s2) != 0) ? true : false;
01228 }
01229 
01230 bool ON_String::operator<(const ON_String& s2) const
01231 {
01232   return (Compare(s2) < 0) ? true : false;
01233 }
01234 
01235 bool ON_String::operator<(const char* s2) const
01236 {
01237   return (Compare(s2) < 0) ? true : false;
01238 }
01239 
01240 bool ON_String::operator>(const ON_String& s2) const
01241 {
01242   return (Compare(s2) > 0) ? true : false;
01243 }
01244 
01245 bool ON_String::operator>(const char* s2) const
01246 {
01247   return (Compare(s2) > 0) ? true : false;
01248 }
01249 
01250 bool ON_String::operator<=(const ON_String& s2) const
01251 {
01252   return (Compare(s2) <= 0) ? true : false;
01253 }
01254 
01255 bool ON_String::operator<=(const char* s2) const
01256 {
01257   return (Compare(s2) <= 0) ? true : false;
01258 }
01259 
01260 bool ON_String::operator>=(const ON_String& s2) const
01261 {
01262   return (Compare(s2) >= 0) ? true : false;
01263 }
01264 
01265 bool ON_String::operator>=(const char* s2) const
01266 {
01267   return (Compare(s2) >= 0) ? true : false;
01268 }
01269 
01270 
01271 ON_CheckSum::ON_CheckSum()
01272 {
01273   Zero();
01274 }
01275 
01276 ON_CheckSum::~ON_CheckSum()
01277 {
01278   Zero();
01279 }
01280 
01281 void ON_CheckSum::Zero()
01282 {
01283   m_size = 0;
01284   m_time = 0;
01285   for ( int i = 0; i < 8; i++ ) 
01286     m_crc[i] = 0;
01287 }
01288 
01289 const ON_CheckSum ON_CheckSum::UnsetCheckSum;
01290 
01291 bool ON_CheckSum::IsSet() const
01292 {
01293   return ( 0 != m_size 
01294            || 0 != m_time 
01295            || 0 != m_crc[0]
01296            || 0 != m_crc[1]
01297            || 0 != m_crc[2]
01298            || 0 != m_crc[3]
01299            || 0 != m_crc[4]
01300            || 0 != m_crc[5]
01301            || 0 != m_crc[6]
01302            || 0 != m_crc[7]
01303            );           
01304 }
01305 
01306 bool ON_CheckSum::SetBufferCheckSum( 
01307                 size_t size, 
01308                 const void* buffer,
01309                 time_t time
01310                )
01311 {
01312   bool rc = false;
01313   Zero();
01314   if ( size != 0 && buffer != 0 )
01315   {
01316     m_size = (unsigned int)size;
01317 
01318     ON__INT32 crc = 0;
01319     size_t sz, maxsize = 0x40000;
01320     const unsigned char* p = (const unsigned char*)buffer;
01321     for ( int i = 0; i < 7; i++ )
01322     {
01323       if ( size > 0 )
01324       {
01325         sz = (size > maxsize) ? maxsize : size;
01326         crc = ON_CRC32(crc,sz,p);
01327         p += sz;
01328         size -= sz;
01329         maxsize *= 2;
01330       }
01331       m_crc[i] = crc;
01332     }
01333     if ( size > 0 )
01334     {
01335       crc = ON_CRC32(crc,size,p);
01336     }
01337     m_crc[7] = crc;
01338     rc = true;
01339   }
01340   else if ( 0 == size )
01341   {
01342     rc = true;
01343   }
01344   m_time = time;
01345   return rc;
01346 }
01347 
01348 bool ON::GetFileStats( const wchar_t* filename,
01349                        size_t* filesize,
01350                        time_t* create_time,
01351                        time_t* lastmodify_time
01352                       )
01353 {
01354   bool rc = false;
01355 
01356   if (filesize)
01357     *filesize = 0;
01358   if (create_time)
01359     *create_time = 0;
01360   if (lastmodify_time)
01361     *lastmodify_time = 0;
01362 
01363   if ( filename && filename[0] )
01364   {
01365     FILE* fp = ON::OpenFile(filename,L"rb");
01366     if ( fp )
01367     {
01368       rc = ON::GetFileStats(fp,filesize,create_time,lastmodify_time);
01369       ON::CloseFile(fp);
01370     }
01371   }
01372 
01373   return rc;
01374 }
01375 
01376 bool ON::GetFileStats( FILE* fp,
01377                        size_t* filesize,
01378                        time_t* create_time,
01379                        time_t* lastmodify_time
01380                       )
01381 {
01382   bool rc = false;
01383 
01384   if (filesize)
01385     *filesize = 0;
01386   if (create_time)
01387     *create_time = 0;
01388   if (lastmodify_time)
01389     *lastmodify_time = 0;
01390 
01391   if ( fp )
01392   {
01393 
01394 #if defined(ON_COMPILER_MSC)
01395 
01396     // Microsoft compilers
01397     int fd = _fileno(fp);    
01398 #if (_MSC_VER >= 1400)
01399     // VC 8 (2005) 
01400     // works for file sizes > 4GB 
01401     // when size_t is a 64 bit integer
01402     struct _stat64 sb;
01403     memset(&sb,0,sizeof(sb));
01404     int fstat_rc = _fstat64(fd, &sb);
01405 #else
01406     // VC6 compiler
01407     // works on most compilers
01408     struct _stat sb;
01409     memset(&sb,0,sizeof(sb));
01410     int fstat_rc = _fstat(fd, &sb);
01411 #endif
01412 
01413 #else
01414     // works on most compilers
01415     int fd = fileno(fp);
01416     struct stat sb;
01417     memset(&sb,0,sizeof(sb));
01418     int fstat_rc = fstat(fd, &sb);
01419 #endif
01420 
01421 
01422     if (0 == fstat_rc)
01423     {
01424       if (filesize)
01425         *filesize = (size_t)sb.st_size;
01426       if (create_time)
01427         *create_time = (time_t)sb.st_ctime;
01428       if (lastmodify_time)
01429         *lastmodify_time = (time_t)sb.st_mtime;
01430       rc = true;
01431     }
01432   }
01433 
01434   return rc;
01435 }
01436 
01437 bool ON::IsDirectory( const wchar_t* pathname )
01438 {
01439   bool rc = false;
01440 
01441   if ( 0 != pathname && 0 != pathname[0] )
01442   {
01443     ON_wString buffer;
01444     const wchar_t* stail = pathname;
01445     while ( 0 != *stail )
01446       stail++;
01447     stail--;
01448     if ( '\\' == *stail || '/' == *stail ) 
01449     {
01450       const wchar_t trim[2] = {*stail,0};
01451       buffer = pathname;
01452       buffer.TrimRight(trim);
01453       if ( buffer.Length() > 0 )
01454         pathname = buffer;
01455     }
01456 #if defined(ON_COMPILER_MSC)
01457     // this works on Windows
01458     struct _stat64 buf;
01459     memset(&buf,0,sizeof(buf));
01460     int stat_errno = _wstat64( pathname, &buf );
01461     if ( 0 == stat_errno && 0 != (_S_IFDIR & buf.st_mode) )
01462     {
01463       rc = true;
01464     }
01465 #else
01466     ON_String s = pathname;
01467     const char* utf8pathname = s;
01468     rc = ON::IsDirectory(utf8pathname);
01469 #endif
01470   }
01471 
01472   return rc;
01473 }
01474 
01475 bool ON::IsDirectory( const char* utf8pathname )
01476 {
01477   bool rc = false;
01478 
01479   if ( 0 != utf8pathname && 0 != utf8pathname[0] )
01480   {
01481     ON_String buffer;
01482     const char* stail = utf8pathname;
01483     while ( 0 != *stail )
01484       stail++;
01485     stail--;
01486     if ( '\\' == *stail || '/' == *stail ) 
01487     {
01488       const char trim[2] = {*stail,0};
01489       buffer = utf8pathname;
01490       buffer.TrimRight(trim);
01491       if ( buffer.Length() > 0 )
01492         utf8pathname = buffer;
01493     }
01494 #if defined(ON_COMPILER_MSC)
01495     // this works on Windows
01496     struct _stat64 buf;
01497     memset(&buf,0,sizeof(buf));
01498     int stat_errno = _stat64( utf8pathname, &buf );
01499     if ( 0 == stat_errno && 0 != (_S_IFDIR & buf.st_mode) )
01500     {
01501       rc = true;
01502     }
01503 #else
01504     // this works on Apple and gcc implentations.
01505     struct stat buf;
01506     memset(&buf,0,sizeof(buf));
01507     int stat_errno = stat( utf8pathname, &buf );
01508     if ( 0 == stat_errno && S_ISDIR(buf.st_mode) )
01509     {
01510       rc = true;
01511     }
01512 #endif
01513   }
01514 
01515   return rc;
01516 }
01517 
01518 
01519 int ON::IsOpenNURBSFile( FILE* fp )
01520 {
01521   ON_String sStartSectionComment;
01522   int version = 0;
01523   if ( 0 != fp )
01524   {
01525     ON_BinaryFile archive(ON::read3dm,fp);
01526     if ( !archive.Read3dmStartSection(&version,sStartSectionComment) )
01527       version = 0;
01528   }
01529   return version;
01530 }
01531 
01532 int ON::IsOpenNURBSFile( const wchar_t* pathname )
01533 {
01534   int version = 0;
01535   if ( 0 != pathname && 0 != pathname[0] )
01536   {
01537     FILE* fp = ON::OpenFile(pathname,L"rb");
01538     if ( 0 != fp )
01539     {
01540       version = ON::IsOpenNURBSFile(fp);
01541       ON::CloseFile(fp);
01542     }
01543   }
01544   return version;
01545 }
01546 
01547 int ON::IsOpenNURBSFile( const char* utf8pathname )
01548 {
01549   int version = 0;
01550   if ( 0 != utf8pathname && 0 != utf8pathname[0] )
01551   {
01552     FILE* fp = ON::OpenFile(utf8pathname,"rb");
01553     if ( 0 != fp )
01554     {
01555       version = ON::IsOpenNURBSFile(fp);
01556       ON::CloseFile(fp);
01557     }
01558   }
01559   return version;
01560 }
01561 
01562 bool ON_CheckSum::SetFileCheckSum( FILE* fp )
01563 {
01564   bool rc = false;
01565   Zero();
01566   if ( fp )
01567   {
01568     size_t filesize = 0;
01569     time_t filetime = 0;
01570     if ( ON::GetFileStats(fp,&filesize,NULL,&filetime) )
01571     {
01572       m_time = filetime;
01573     }
01574 
01575     unsigned char buffer[1024];
01576     int count=1024;
01577     ON__INT32 crc = 0;
01578     size_t sz0 = 0, maxsize = 0x40000;
01579 
01580     for( int i = 0; i < 7; i++ )
01581     {
01582       sz0 += maxsize;
01583       while(1024 == count && m_size < sz0)
01584       {
01585         count = (int)fread( buffer, 1, 1024, fp ); // the (int) is for 64 bit size_t conversion
01586         if ( count > 0 )
01587         {
01588           m_size += count;
01589           crc = ON_CRC32( crc, count, buffer );
01590         }
01591       }
01592       maxsize *= 2;
01593       m_crc[i] = crc;
01594     }
01595 
01596     while(1024 == count)
01597     {
01598       count = (int)fread( buffer, 1, 1024, fp ); // the (int) is for 64 bit size_t conversion
01599       if ( count > 0 )
01600       {
01601         m_size += count;
01602         crc = ON_CRC32( crc, count, buffer );
01603       }
01604     }
01605     m_crc[7] = crc;
01606 
01607     rc = (filesize == m_size);
01608   }
01609   return rc;
01610 }
01611 
01612 bool ON_CheckSum::Write(ON_BinaryArchive& archive) const
01613 {
01614   bool rc = false;
01615   if ( archive.Archive3dmVersion() < 4 )
01616   {
01617     // V3 files had other information
01618     // 48 bytes of zeros will work ok
01619     unsigned char b[48];
01620     memset(b,0,sizeof(b));
01621     rc = archive.WriteByte(48,b);
01622   }
01623   else
01624   {
01625     rc = archive.WriteBigSize(m_size);
01626     if (rc)
01627       rc = archive.WriteBigTime(m_time);
01628     if (rc)
01629       rc = archive.WriteInt(8,&m_crc[0]);
01630   }
01631   return rc;
01632 }
01633 
01634 bool ON_CheckSum::Read(ON_BinaryArchive& archive)
01635 {
01636   bool rc;
01637 
01638   Zero();
01639 
01640   rc  = archive.ReadBigSize(&m_size);
01641   if (rc)
01642     rc = archive.ReadBigTime(&m_time);
01643   if (rc)
01644     rc = archive.ReadInt(8,&m_crc[0]);
01645 
01646   if (    archive.ArchiveOpenNURBSVersion() < 200603100 
01647        || archive.Archive3dmVersion() < 4 
01648        )
01649   {
01650     // ON_CheckSums in V3 archives and V4 archives with
01651     // version < 200603100 have the same size but an 
01652     // incompatible format.  These were not used.
01653     Zero();
01654   }
01655 
01656   return rc;
01657 }
01658 
01659 
01660 bool ON_CheckSum::SetFileCheckSum( const wchar_t* filename )
01661 {
01662   bool rc = false;
01663   Zero();
01664   if ( 0 == filename || 0 == filename[0] )
01665   {
01666     rc = true;
01667   }
01668   else
01669   {
01670     FILE* fp = ON::OpenFile(filename,L"rb");
01671     if ( fp )
01672     {
01673       rc = SetFileCheckSum(fp);
01674       ON::CloseFile(fp);
01675     }
01676   }
01677   return rc;
01678 }
01679 
01680 bool ON_CheckSum::CheckBuffer( 
01681   size_t size, 
01682   const void* buffer
01683   ) const
01684 {
01685   if ( m_size != size )
01686     return false;
01687   if ( 0 == size )
01688     return true;
01689   if ( 0 == buffer )
01690     return false;
01691 
01692   ON__UINT32 crc = 0;
01693   size_t sz, maxsize = 0x40000;
01694   const unsigned char* p = (const unsigned char*)buffer;
01695   for ( int i = 0; i < 7; i++ )
01696   {
01697     if ( size > 0 )
01698     {
01699       sz = (size > maxsize) ? maxsize : size;
01700       crc = ON_CRC32(crc,sz,p);
01701       p += sz;
01702       size -= sz;
01703       maxsize *= 2;
01704     }
01705     if ( m_crc[i] != crc )
01706       return false;
01707   }
01708   if ( size > 0 )
01709   {
01710     crc = ON_CRC32(crc,size,p);
01711   }
01712   if ( m_crc[7] != crc )
01713     return false;
01714 
01715   return true;
01716 }
01717 
01718 bool ON_CheckSum::CheckFile( 
01719   FILE* fp,
01720   bool bSkipTimeCheck
01721   ) const
01722 {
01723   if ( !fp )
01724     return false;
01725 
01726   size_t filesize=0;
01727   time_t filetime=0;
01728   if ( ON::GetFileStats( fp, &filesize, NULL, &filetime ) )
01729   {
01730     if ( m_size != filesize )
01731     {
01732       return false;
01733     }
01734 
01735     if ( !bSkipTimeCheck && m_time != filetime)
01736     {
01737       return false;
01738     }
01739   }
01740 
01741   unsigned char buffer[1024];
01742   int count=1024;
01743   ON__UINT32 crc = 0;
01744   size_t sz0 = 0, maxsize = 0x40000;
01745   size_t sz = 0;
01746 
01747   for( int i = 0; i < 7; i++ )
01748   {
01749     sz0 += maxsize;
01750     while(1024 == count && sz < sz0)
01751     {
01752       count = (int)fread( buffer, 1, 1024, fp ); // the (int) is for 64 bit size_t conversion
01753       if ( count > 0 )
01754       {
01755         sz += count;
01756         crc = ON_CRC32( crc, count, buffer );
01757       }
01758     }
01759     maxsize *= 2;
01760     if ( m_crc[i] != crc )
01761       return false;
01762   }
01763 
01764   while(1024 == count)
01765   {
01766     count = (int)fread( buffer, 1, 1024, fp ); // the (int) is for 64 bit size_t conversion
01767     if ( count > 0 )
01768     {
01769       sz += count;
01770       crc = ON_CRC32( crc, count, buffer );
01771     }
01772   }
01773   if (m_crc[7] != crc)
01774     return false;
01775 
01776   if ( sz != m_size )
01777     return false;
01778 
01779   return true;
01780 }
01781 
01782 bool ON_CheckSum::CheckFile( 
01783   const wchar_t* filename,
01784   bool bSkipTimeCheck
01785   ) const
01786 {
01787   bool rc = false;
01788   if ( filename && filename[0] )
01789   {
01790     FILE* fp = ON::OpenFile(filename,L"rb");
01791     if ( fp )
01792     {
01793       rc = CheckFile(fp,bSkipTimeCheck);
01794       ON::CloseFile(fp);
01795     }
01796   }
01797   return rc;
01798 }
01799 
01800 void ON_CheckSum::Dump(ON_TextLog& text_log) const
01801 {
01802   // Using %llu so this code is portable for both 32 and 64 bit
01803   // builds on a wide range of compilers.
01804 
01805   unsigned long long u; // 8 bytes in windows and gcc - should be at least as big
01806                         // as a size_t or time_t.
01807 
01808   text_log.Print("Checksum:");
01809   if ( !IsSet() )
01810     text_log.Print("zero (not set)\n");
01811   else
01812   {
01813     text_log.PushIndent();
01814     text_log.Print("\n");
01815     u = (unsigned long long)m_size;
01816     text_log.Print("Size: %llu bytes\n",u);
01817     u = (unsigned long long)m_time;
01818     text_log.Print("Last Modified Time: %u (seconds since January 1, 1970, UCT)\n",u);
01819     text_log.Print("CRC List: %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x\n",
01820                    m_crc[0],m_crc[1],m_crc[2],m_crc[3],m_crc[4],m_crc[5],m_crc[6],m_crc[7]
01821                    );
01822     text_log.PopIndent();
01823   }
01824 }


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