1 /* $NoKeywords: $ */
2 /*
3 //
4 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
5 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
6 // McNeel & Associates.
7 //
8 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
9 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
10 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
11 //
12 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
13 //
14 ////////////////////////////////////////////////////////////////
15 */
16 
17 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
18 
19 /////////////////////////////////////////////////////////////////////////////
20 // Empty strings point at empty_astring
21 
22 
23 struct ON_aStringHeader
24 {
25 	int   ref_count;       // reference count (>=0 or -1 for empty string)
26 	int   string_length;   // does not include NULL terminator
27 	int   string_capacity; // does not include NULL terminator
string_arrayON_aStringHeader28   char* string_array() {return (char*)(this+1);}
29 };
30 
31 static struct {
32   ON_aStringHeader header;
33   char           s;
34 } empty_astring = { {-1, 0, 0}, 0 }; // ref_count=-1, length=0, capacity=0, s=0
35 static ON_aStringHeader* pEmptyStringHeader = &empty_astring.header;
36 static const char* pEmptyaString = &empty_astring.s;
37 
38 //////////////////////////////////////////////////////////////////////////////
39 // protected helpers
40 
Create()41 void ON_String::Create()
42 {
43   m_s = (char*)pEmptyaString;
44 }
45 
Destroy()46 void ON_String::Destroy()
47 {
48   ON_aStringHeader* p = Header();
49   if ( p != pEmptyStringHeader && p->ref_count > 0 ) {
50     p->ref_count--;
51 		if ( p->ref_count == 0 )
52 			onfree(p);
53   }
54 	Create();
55 }
56 
Empty()57 void ON_String::Empty()
58 {
59   ON_aStringHeader* p = Header();
60   if ( p != pEmptyStringHeader ) {
61     if ( p->ref_count > 1 ) {
62       // string memory is shared
63       p->ref_count--;
64 	    Create();
65     }
66     else if ( p->ref_count == 1 ) {
67       // string memory is not shared - reuse it
68       if (m_s && p->string_capacity>0)
69         *m_s = 0;
70       p->string_length = 0;
71     }
72     else {
73       // should not happen
74       ON_ERROR("ON_String::Empty() encountered invalid header - fixed.");
75       Create();
76     }
77   }
78   else {
79     // initialized again
80 	  Create();
81   }
82 }
83 
EmergencyDestroy()84 void ON_String::EmergencyDestroy()
85 {
86 	Create();
87 }
88 
EnableReferenceCounting(bool)89 void ON_String::EnableReferenceCounting( bool )
90 {
91   // TODO fill this in;
92 }
93 
IsReferenceCounted() const94 bool ON_String::IsReferenceCounted() const
95 {
96   return true;
97 }
98 
99 
Header() const100 ON_aStringHeader* ON_String::Header() const
101 {
102   ON_aStringHeader* p = (ON_aStringHeader*)m_s;
103   if (p)
104     p--;
105   else
106     p = pEmptyStringHeader;
107   return p;
108 }
109 
CreateArray(int capacity)110 void ON_String::CreateArray( int capacity )
111 {
112   Destroy();
113   if ( capacity > 0 ) {
114 		ON_aStringHeader* p =
115 			(ON_aStringHeader*)onmalloc( sizeof(ON_aStringHeader) + (capacity+1)*sizeof(*m_s) );
116 		p->ref_count = 1;
117 		p->string_length = 0;
118 		p->string_capacity = capacity;
119 		m_s = p->string_array();
120     memset( m_s, 0, (capacity+1)*sizeof(*m_s) );
121   }
122 }
123 
CopyArray()124 void ON_String::CopyArray()
125 {
126   // If 2 or more strings are using the array, it is duplicated.
127   // Call CopyArray() before modifying array contents.
128   ON_aStringHeader* p = Header();
129   if ( p != pEmptyStringHeader && p && p->ref_count > 1 )
130   {
131     const char* s = m_s;
132     // p and s remain valid after Destroy() because
133     // will simply be decremented and no deallocation
134     // will happen.
135     Destroy();
136     CopyToArray( p->string_capacity, s );
137     if ( p->string_length < p->string_capacity )
138     {
139       Header()->string_length = p->string_length;
140     }
141   }
142 }
143 
ReserveArray(std::size_t array_capacity)144 void ON_String::ReserveArray( std::size_t array_capacity )
145 {
146   ON_aStringHeader* p = Header();
147   const int capacity = (int) array_capacity;
148   if ( p == pEmptyStringHeader )
149   {
150 		CreateArray(capacity);
151   }
152   else if ( p->ref_count > 1 )
153   {
154 		CreateArray(capacity);
155     ON_aStringHeader* p1 = Header();
156     const int size = (capacity < p->string_length) ? capacity : p->string_length;
157     if ( size > 0 )
158     {
159       memcpy( p1->string_array(), p->string_array(), size*sizeof(*m_s) );
160       p1->string_length = size;
161     }
162   }
163 	else if ( capacity > p->string_capacity )
164   {
165 		p = (ON_aStringHeader*)onrealloc( p, sizeof(ON_aStringHeader) + (capacity+1)*sizeof(*m_s) );
166     m_s = p->string_array();
167     memset( &m_s[p->string_capacity], 0, (1+capacity-p->string_capacity)*sizeof(*m_s) );
168     p->string_capacity = capacity;
169 	}
170 }
171 
ShrinkArray()172 void ON_String::ShrinkArray()
173 {
174   ON_aStringHeader* p = Header();
175   if ( p != pEmptyStringHeader ) {
176     if ( p->string_length < 1 ) {
177       Destroy();
178     }
179     else if ( p->ref_count > 1 ) {
180       // shared string
181       CreateArray(p->string_length);
182 		  ON_aStringHeader* p1 = Header();
183       memcpy( m_s, p->string_array(), p->string_length*sizeof(*m_s));
184       p1->string_length = p->string_length;
185       m_s[p1->string_length] = 0;
186     }
187 	  else if ( p->string_length < p->string_capacity ) {
188       // onrealloc string
189 		  p = (ON_aStringHeader*)onrealloc( p, sizeof(ON_aStringHeader) + (p->string_length+1)*sizeof(*m_s) );
190       p->string_capacity = p->string_length;
191       m_s = p->string_array();
192       m_s[p->string_length] = 0;
193 	  }
194   }
195 }
196 
CopyToArray(const ON_String & s)197 void ON_String::CopyToArray( const ON_String& s )
198 {
199   CopyToArray( s.Length(), s.Array() );
200 }
201 
CopyToArray(int size,const char * s)202 void ON_String::CopyToArray( int size, const char* s )
203 {
204   if ( size > 0 && s && s[0] ) {
205 	  ReserveArray(size);
206 	  memcpy(m_s, s, size*sizeof(*m_s));
207 	  Header()->string_length = size;
208     m_s[Header()->string_length] = 0;
209   }
210   else {
211     if ( Header()->ref_count > 1 )
212       Destroy();
213     else {
214       Header()->string_length = 0;
215       m_s[0] = 0;
216     }
217   }
218 }
219 
CopyToArray(int size,const unsigned char * s)220 void ON_String::CopyToArray( int size, const unsigned char* s )
221 {
222   CopyToArray( size, ((char*)s) );
223 }
224 
AppendToArray(const ON_String & s)225 void ON_String::AppendToArray( const ON_String& s )
226 {
227   AppendToArray( s.Length(), s.Array() );
228 }
229 
AppendToArray(int size,const char * s)230 void ON_String::AppendToArray( int size, const char* s )
231 {
232   if ( size > 0 && s && s[0] ) {
233 	  ReserveArray(size + Header()->string_length );
234     // m_s = char array
235 	  memcpy(&m_s[Header()->string_length], s, size*sizeof(*m_s));
236 	  Header()->string_length += size;
237     m_s[Header()->string_length] = 0;
238   }
239 }
240 
AppendToArray(int size,const unsigned char * s)241 void ON_String::AppendToArray( int size, const unsigned char* s )
242 {
243   AppendToArray( size, ((char*)s) );
244 }
245 
Length(const char * s)246 int ON_String::Length( const char* s )
247 {
248   std::size_t slen = s ? strlen(s) : 0;
249   int n = ((0 < slen && slen <= 2147483645) ?((int)slen) : 0); // the (int) cast is for 64 bit std::size_t conversion
250   return n;
251 }
252 
Length(const unsigned char * s)253 int ON_String::Length( const unsigned char* s )
254 {
255   return ON_String::Length((const char*)s);
256 }
257 
258 //////////////////////////////////////////////////////////////////////////////
259 // Construction/Destruction
260 
ON_String()261 ON_String::ON_String()
262 {
263 	Create();
264 }
265 
~ON_String()266 ON_String::~ON_String()
267 {
268   Destroy();
269 }
270 
ON_String(const ON_String & src)271 ON_String::ON_String(const ON_String& src)
272 {
273 	if (    src.Header()->ref_count > 0
274        && 0 == ON_WorkerMemoryPool()
275      )
276   {
277 		m_s = src.m_s;
278     src.Header()->ref_count++;
279 	}
280 	else
281   {
282 		Create();
283 		*this = src.m_s; // use operator=(const char*) to copy
284 	}
285 }
286 
ON_String(const char * s)287 ON_String::ON_String( const char* s )
288 {
289 	Create();
290   if ( s && s[0] ) {
291     CopyToArray( (int)strlen(s), s ); // the (int) is for 64 bit std::size_t conversion
292   }
293 }
294 
ON_String(const char * s,int length)295 ON_String::ON_String( const char* s, int length )
296 {
297 	Create();
298   if ( s && length > 0 ) {
299     CopyToArray(length,s);
300 	}
301 }
302 
ON_String(char c,int repeat_count)303 ON_String::ON_String( char c, int repeat_count )
304 {
305   Create();
306   if ( repeat_count > 0 ) {
307     ReserveArray(repeat_count);
308     memset( m_s, c, repeat_count*sizeof(*m_s) );
309     m_s[repeat_count] = 0;
310     Header()->string_length = repeat_count;
311   }
312 }
313 
ON_String(const unsigned char * s)314 ON_String::ON_String( const unsigned char* s )
315 {
316 	Create();
317   if ( s && s[0] )
318   {
319     CopyToArray( (int)strlen((const char*)s), (const char*)s ); // the (int) is for 64 bit std::size_t conversion
320   }
321 }
322 
ON_String(const unsigned char * s,int length)323 ON_String::ON_String( const unsigned char* s, int length )
324 {
325 	Create();
326   if ( s && length > 0 ) {
327     CopyToArray(length,s);
328 	}
329 }
330 
ON_String(unsigned char c,int repeat_count)331 ON_String::ON_String( unsigned char c, int repeat_count )
332 {
333   Create();
334   if ( repeat_count > 0 ) {
335     ReserveArray(repeat_count);
336     memset( m_s, c, repeat_count*sizeof(*m_s) );
337     m_s[repeat_count] = 0;
338     Header()->string_length = repeat_count;
339   }
340 }
341 
342 
ON_String(const wchar_t * w)343 ON_String::ON_String( const wchar_t* w)
344 {
345   Create();
346   if ( w && w[0] ) {
347     *this = w;
348   }
349 }
350 
ON_String(const wchar_t * w,int w_length)351 ON_String::ON_String( const wchar_t* w, int w_length )
352 {
353   // from substring
354   Create();
355   if ( w && w[0] ) {
356     CopyToArray( w_length, w );
357   }
358 }
359 
360 
ON_String(const ON_wString & w)361 ON_String::ON_String( const ON_wString& w )
362 {
363   Create();
364   *this = w;
365 }
366 
367 
368 
369 #if defined (ON_OS_WINDOWS)
LoadResourceString(HINSTANCE instance,UINT id)370 bool ON_String::LoadResourceString( HINSTANCE instance, UINT id )
371 {
372   char s[2048]; // room for 2047 characters
373   int length;
374 
375   Destroy();
376   length = ::LoadStringA( instance, id, s, 2047 );
377   if ( length > 0 && length < 2048 ) {
378     CopyToArray( length, s );
379   }
380   return (length > 0 );
381 }
382 #endif
383 
Length() const384 int ON_String::Length() const
385 {
386   return Header()->string_length;
387 }
388 
389 // 25 October 2007 Dale Lear - remove bogus decl and defn
390 //void Destroy();
391 //void EmergencyDestroy()
392 //{
393 //}
394 
operator [](int i)395 char& ON_String::operator[](int i)
396 {
397   CopyArray();
398   return m_s[i];
399 }
400 
operator [](int i) const401 char ON_String::operator[](int i) const
402 {
403   return m_s[i];
404 }
405 
IsEmpty() const406 bool ON_String::IsEmpty() const
407 {
408   return (Header()->string_length <= 0 ) ? true : false;
409 }
410 
operator =(const ON_String & src)411 ON_String& ON_String::operator=(const ON_String& src)
412 {
413 	if (m_s != src.m_s)
414   {
415     if ( src.IsEmpty() )
416     {
417       Destroy();
418       Create();
419     }
420     else if (    src.Header()->ref_count > 0
421               && 0 == ON_WorkerMemoryPool()
422             )
423     {
424       Destroy();
425       src.Header()->ref_count++;
426       m_s = src.m_s;
427     }
428     else
429     {
430       ReserveArray(src.Length());
431       memcpy( m_s, src.Array(), src.Length()*sizeof(*m_s));
432       Header()->string_length = src.Length();
433     }
434   }
435 	return *this;
436 }
437 
operator =(char c)438 ON_String& ON_String::operator=( char c )
439 {
440 	CopyToArray( 1, &c );
441 	return *this;
442 }
443 
operator =(const char * s)444 ON_String& ON_String::operator=( const char* s )
445 {
446   if ( (void*)s != (void*)m_s )
447 	  CopyToArray( Length(s), s);
448 	return *this;
449 }
450 
operator =(unsigned char c)451 ON_String& ON_String::operator=( unsigned char c )
452 {
453 	CopyToArray( 1, &c );
454 	return *this;
455 }
456 
operator =(const unsigned char * s)457 ON_String& ON_String::operator=( const unsigned char* s )
458 {
459   if ( (void*)s != (void*)m_s )
460 	  CopyToArray( Length(s), s);
461 	return *this;
462 }
463 
operator =(const wchar_t * w)464 ON_String& ON_String::operator=( const wchar_t* w )
465 {
466   // converts wide string to byt string
467   int w_length = 0;
468   if ( w ) while ( w[w_length] ) w_length++;
469   CopyToArray( w_length, w);
470 	return *this;
471 }
472 
operator =(const ON_wString & w)473 ON_String& ON_String::operator=( const ON_wString& w )
474 {
475   *this = w.Array();
476   return *this;
477 }
478 
479 
operator +(const ON_String & s2) const480 ON_String ON_String::operator+(const ON_String& s2) const
481 {
482 	ON_String s(*this);
483   s.AppendToArray( s2 );
484 	return s;
485 }
486 
operator +(char s2) const487 ON_String ON_String::operator+( char s2 ) const
488 {
489 	ON_String s(*this);
490   s.AppendToArray( 1, &s2 );
491 	return s;
492 }
493 
operator +(unsigned char s2) const494 ON_String ON_String::operator+( unsigned char s2 ) const
495 {
496 	ON_String s(*this);
497   s.AppendToArray( 1, &s2 );
498 	return s;
499 }
500 
operator +(const char * s2) const501 ON_String ON_String::operator+(const char* s2) const
502 {
503 	ON_String s(*this);
504   s.AppendToArray( ON_String::Length(s2), s2 );
505 	return s;
506 }
507 
operator +(const unsigned char * s2) const508 ON_String ON_String::operator+( const unsigned char* s2) const
509 {
510 	ON_String s(*this);
511   s.AppendToArray( ON_String::Length(s2), s2 );
512 	return s;
513 }
514 
515 //////////////////////////////////////////////////////////////////////////////
516 // operator+=()
517 
518 
Append(const char * s,int count)519 void ON_String::Append( const char* s , int count )
520 {
521   // append specified number of characters
522   if ( s && count > 0 )
523     AppendToArray(count,s);
524 }
525 
Append(const unsigned char * s,int count)526 void ON_String::Append( const unsigned char* s , int count )
527 {
528   // append specified number of characters
529   if ( s && count > 0 )
530     AppendToArray(count,s);
531 }
532 
533 
operator +=(const ON_String & s)534 const ON_String& ON_String::operator+=(const ON_String& s)
535 {
536   AppendToArray(s);
537 	return *this;
538 }
539 
operator +=(char s)540 const ON_String& ON_String::operator+=( char s )
541 {
542   AppendToArray(1,&s);
543 	return *this;
544 }
545 
operator +=(unsigned char s)546 const ON_String& ON_String::operator+=( unsigned char s )
547 {
548   AppendToArray(1,&s);
549 	return *this;
550 }
551 
operator +=(const char * s)552 const ON_String& ON_String::operator+=( const char* s )
553 {
554   AppendToArray(Length(s),s);
555 	return *this;
556 }
557 
operator +=(const unsigned char * s)558 const ON_String& ON_String::operator+=( const unsigned char* s )
559 {
560   AppendToArray(Length(s),s);
561 	return *this;
562 }
563 
SetLength(std::size_t string_length)564 void ON_String::SetLength(std::size_t string_length)
565 {
566   int length = (int)string_length; // for 64 bit compilers
567   if ( length >= Header()->string_capacity ) {
568     ReserveArray(length);
569   }
570   if ( length >= 0 && length <= Header()->string_capacity ) {
571     CopyArray();
572     Header()->string_length = length;
573     m_s[length] = 0;
574   }
575 }
576 
Array()577 char* ON_String::Array()
578 {
579   CopyArray();
580   return ( Header()->string_capacity > 0 ) ? m_s : 0;
581 }
582 
Array() const583 const char* ON_String::Array() const
584 {
585   return ( Header()->string_capacity > 0 ) ? m_s : 0;
586 }
587 
588 /*
589 Returns:
590   Total number of bytes of memory used by this class.
591   (For use in ON_Object::SizeOf() overrides.
592 */
SizeOf() const593 unsigned int ON_String::SizeOf() const
594 {
595   std::size_t sz = sizeof(*this);
596   if ( ((const void*)m_s) != ((const void*)pEmptyaString) )
597     sz += (sizeof(ON_aStringHeader) + (Header()->string_capacity+1));
598   return (unsigned int)sz;
599 }
600 
DataCRC(ON__UINT32 current_remainder) const601 ON__UINT32 ON_String::DataCRC(ON__UINT32 current_remainder) const
602 {
603   int string_length = Header()->string_length;
604   if ( string_length > 0 )
605   {
606     current_remainder = ON_CRC32(current_remainder,string_length*sizeof(*m_s),m_s);
607   }
608   return current_remainder;
609 }
610 
Compare(const char * s) const611 int ON_String::Compare( const char* s ) const
612 {
613   int rc = 0;
614   if ( s && s[0] ) {
615     if ( IsEmpty() ) {
616       rc = -1;
617     }
618     else {
619       rc = strcmp( m_s, s );
620     }
621   }
622   else {
623     rc = IsEmpty() ? 0 : 1;
624   }
625   return rc;
626 }
627 
Compare(const unsigned char * s) const628 int ON_String::Compare( const unsigned char* s) const
629 {
630   return ON_String::Compare((const char*)s);
631 }
632 
CompareNoCase(const char * s) const633 int ON_String::CompareNoCase( const char* s) const
634 {
635   int rc = 0;
636   if ( s && s[0] ) {
637     if ( IsEmpty() ) {
638       rc = -1;
639     }
640     else {
641       rc = on_stricmp( m_s, s );
642     }
643   }
644   else {
645     rc = IsEmpty() ? 0 : 1;
646   }
647   return rc;
648 }
649 
CompareNoCase(const unsigned char * s) const650 int ON_String::CompareNoCase( const unsigned char* s) const
651 {
652   return ON_String::CompareNoCase((const char*)s);
653 }
654 
operator const char*() const655 ON_String::operator const char*() const
656 {
657   return ( m_s == pEmptyaString ) ? NULL : m_s;
658 }
659 
660 
ON_WildCardMatch(const char * s,const char * pattern)661 bool ON_WildCardMatch(const char* s, const char* pattern)
662 {
663   if ( !pattern || !pattern[0] ) {
664     return ( !s || !s[0] ) ? true : false;
665   }
666 
667   if ( *pattern == '*' ) {
668     pattern++;
669     while ( *pattern == '*' )
670       pattern++;
671 
672     if ( !pattern[0] )
673       return true;
674 
675     while (*s) {
676       if ( ON_WildCardMatch(s,pattern) )
677         return true;
678       s++;
679     }
680 
681     return false;
682   }
683 
684   while ( *pattern != '*' )
685   {
686     if ( *pattern == '?' ) {
687       if ( *s) {
688         pattern++;
689         s++;
690         continue;
691       }
692       return false;
693     }
694 
695     if ( *pattern == '\\' ) {
696       switch( pattern[1] )
697       {
698       case '*':
699       case '?':
700         pattern++;
701         break;
702       }
703     }
704     if ( *pattern != *s ) {
705       return false;
706     }
707 
708     if ( *s == 0 )
709       return true;
710 
711     pattern++;
712     s++;
713   }
714 
715   return ON_WildCardMatch(s,pattern);
716 }
717 
718 
ON_WildCardMatchNoCase(const char * s,const char * pattern)719 bool ON_WildCardMatchNoCase(const char* s, const char* pattern)
720 {
721   if ( !pattern || !pattern[0] ) {
722     return ( !s || !s[0] ) ? true : false;
723   }
724 
725   if ( *pattern == '*' )
726   {
727     pattern++;
728     while ( *pattern == '*' )
729       pattern++;
730 
731     if ( !pattern[0] )
732       return true;
733 
734     while (*s) {
735       if ( ON_WildCardMatchNoCase(s,pattern) )
736         return true;
737       s++;
738     }
739 
740     return false;
741   }
742 
743   while ( *pattern != '*' )
744   {
745     if ( *pattern == '?' ) {
746       if ( *s) {
747         pattern++;
748         s++;
749         continue;
750       }
751       return false;
752     }
753 
754     if ( *pattern == '\\' ) {
755       switch( pattern[1] )
756       {
757       case '*':
758       case '?':
759         pattern++;
760         break;
761       }
762     }
763     if ( toupper(*pattern) != toupper(*s) ) {
764       return false;
765     }
766 
767     if ( *s == 0 )
768       return true;
769 
770     pattern++;
771     s++;
772   }
773 
774   return ON_WildCardMatchNoCase(s,pattern);
775 }
776 
WildCardMatch(const char * pattern) const777 bool ON_String::WildCardMatch( const char* pattern) const
778 {
779   return ON_WildCardMatch(m_s,pattern);
780 }
781 
WildCardMatch(const unsigned char * pattern) const782 bool ON_String::WildCardMatch( const unsigned char* pattern ) const
783 {
784   return ON_WildCardMatch(m_s,(const char*)pattern);
785 }
786 
WildCardMatchNoCase(const char * pattern) const787 bool ON_String::WildCardMatchNoCase( const char* pattern) const
788 {
789   return ON_WildCardMatchNoCase(m_s,pattern);
790 }
791 
WildCardMatchNoCase(const unsigned char * pattern) const792 bool ON_String::WildCardMatchNoCase( const unsigned char* pattern ) const
793 {
794   return ON_WildCardMatchNoCase(m_s,(const char*)pattern);
795 }
796 
Replace(const char * token1,const char * token2)797 int ON_String::Replace( const char* token1, const char* token2 )
798 {
799   int count = 0;
800 
801   if ( 0 != token1 && 0 != token1[0] )
802   {
803     if ( 0 == token2 )
804       token2 = "";
805     const int len1 = (int)strlen(token1);
806     if ( len1 > 0 )
807     {
808       const int len2 = (int)strlen(token2);
809       int len = Length();
810       if ( len >= len1 )
811       {
812         // in-place
813         ON_SimpleArray<int> n(32);
814         const char* s = m_s;
815         int i;
816         for ( i = 0; i <= len-len1; /*empty*/ )
817         {
818           if ( strncmp(s,token1,len1) )
819           {
820             s++;
821             i++;
822           }
823           else
824           {
825             n.Append(i);
826             i += len1;
827             s += len1;
828           }
829         }
830 
831         count = n.Count();
832 
833         // reserve array space - must be done even when len2 <= len1
834         // so that shared arrays are not corrupted.
835         const int newlen = len + (count*(len2-len1));
836         if ( 0 == newlen )
837         {
838           Destroy();
839           return count;
840         }
841 
842         CopyArray();
843 
844         // 24 August 2006 Dale Lear
845         //    This used to say
846         //       ReserveArray(newlen);
847         //    but when newlen < len and the string had multiple
848         //    references, the ReserveArray(newlen) call truncated
849         //    the input array.
850         ReserveArray( ((newlen<len) ? len : newlen) );
851 
852         int i0, i1, ni, j;
853 
854         if ( len2 > len1 )
855         {
856           // copy from back to front
857           i1 = newlen;
858           i0 = len;
859           for ( ni =0; ni < count; ni++ )
860             n[ni] = n[ni] + len1;
861           for ( ni = count-1; ni >= 0; ni-- )
862           {
863             j = n[ni];
864             while ( i0 > j )
865             {
866               i0--;
867               i1--;
868               m_s[i1] = m_s[i0];
869             }
870             i1 -= len2;
871             i0 -= len1;
872             memcpy(&m_s[i1],token2,len2*sizeof(m_s[0]));
873           }
874         }
875         else
876         {
877           // copy from front to back
878           i0 = i1 = n[0];
879           n.Append(len);
880           for ( ni = 0; ni < count; ni++ )
881           {
882             if ( len2 > 0 )
883             {
884               memcpy(&m_s[i1],token2,len2*sizeof(m_s[0]));
885               i1 += len2;
886             }
887             i0 += len1;
888             j = n[ni+1];
889             while ( i0 < j )
890             {
891               m_s[i1++] = m_s[i0++];
892             }
893           }
894         }
895         Header()->string_length = newlen;
896         m_s[newlen] = 0;
897       }
898     }
899   }
900 
901   return count;
902 }
903 
Replace(const unsigned char * token1,const unsigned char * token2)904 int ON_String::Replace( const unsigned char* token1, const unsigned char* token2 )
905 {
906   return Replace((const char*)token1, (const char*)token2);
907 }
908 
Replace(char token1,char token2)909 int ON_String::Replace( char token1, char token2 )
910 {
911   int count = 0;
912   int i = Length();
913   while (i--)
914   {
915     if ( token1 == m_s[i] )
916     {
917       if ( 0 == count )
918         CopyArray();
919       m_s[i] = token2;
920       count++;
921     }
922   }
923   return count;
924 }
925 
Replace(unsigned char token1,unsigned char token2)926 int ON_String::Replace( unsigned char token1, unsigned char token2 )
927 {
928   return Replace((char)token1, (char)token2);
929 }
930 
931 
932 ///////////////////////////////////////////////////////////////////////////////
933 
Find(char c) const934 int ON_String::Find( char c ) const
935 {
936 	// find first single character
937   char s[2];
938   s[0] = c;
939   s[1] = 0;
940   return Find( s );
941 }
942 
Find(unsigned char c) const943 int ON_String::Find( unsigned char c ) const
944 {
945   return Find( (char)c );
946 }
947 
ReverseFind(char c) const948 int ON_String::ReverseFind( char c ) const
949 {
950 	// find first single character
951   if ( IsEmpty() )
952     return -1;
953   int i;
954   const int length = Length();
955   for ( i = length-1; i >= 0; i-- ) {
956     if ( c == m_s[i] )
957       return i;
958   }
959   return -1;
960 }
961 
ReverseFind(unsigned char c) const962 int ON_String::ReverseFind( unsigned char c ) const
963 {
964   return ReverseFind( (char)c );
965 }
966 
Find(const char * s) const967 int ON_String::Find( const char* s ) const
968 {
969   int rc = -1;
970   if ( s && s[0] && !IsEmpty() ) {
971     const char* p;
972     p = strstr( m_s, s );
973     if ( p )
974     {
975       rc = ((int)(p-m_s)); // the (int) is for 64 bit std::size_t conversion
976     }
977   }
978   return rc;
979 }
980 
Find(const unsigned char * s) const981 int ON_String::Find( const unsigned char* s ) const
982 {
983   return Find( (const char*)s );
984 }
985 
MakeUpper()986 void ON_String::MakeUpper()
987 {
988   if ( !IsEmpty() ) {
989   	CopyArray();
990     on_strupr(m_s);
991   }
992 }
993 
MakeLower()994 void ON_String::MakeLower()
995 {
996   if ( !IsEmpty() ) {
997   	CopyArray();
998     on_strlwr(m_s);
999   }
1000 }
1001 
MakeReverse()1002 void ON_String::MakeReverse()
1003 {
1004   if ( !IsEmpty() ) {
1005   	CopyArray();
1006     on_strrev(m_s);
1007   }
1008 }
1009 
TrimLeft(const char * s)1010 void ON_String::TrimLeft(const char* s)
1011 {
1012   char c;
1013   const char* sc;
1014   char* dc;
1015   int i;
1016   if ( !IsEmpty() ) {
1017     if ( !s )
1018       s = " \t\n";
1019     for ( i = 0; 0 != (c=m_s[i]); i++ )
1020     {
1021       for (sc = s;*sc;sc++) {
1022         if ( *sc == c )
1023           break;
1024       }
1025       if (!(*sc))
1026         break;
1027     }
1028     if ( i > 0 ) {
1029       if ( m_s[i] ) {
1030         CopyArray();
1031         dc = m_s;
1032         sc = m_s+i;
1033         while( 0 != (*dc++ = *sc++) );
1034         Header()->string_length -= i;
1035       }
1036       else
1037         Destroy();
1038     }
1039   }
1040 }
1041 
TrimRight(const char * s)1042 void ON_String::TrimRight(const char* s)
1043 {
1044   char c;
1045   const char* sc;
1046   int i = Header()->string_length;
1047   if ( i > 0 ) {
1048     if ( !s )
1049       s = " \t\n";
1050     for (i--; i >= 0 && 0 != (c=m_s[i]); i-- )
1051     {
1052       for (sc = s;*sc;sc++) {
1053         if ( *sc == c )
1054           break;
1055       }
1056       if (!(*sc))
1057         break;
1058     }
1059     if ( i < 0 )
1060       Destroy();
1061     else if ( m_s[i+1] ) {
1062       CopyArray();
1063       m_s[i+1] = 0;
1064       Header()->string_length = i+1;
1065     }
1066   }
1067 }
1068 
TrimLeftAndRight(const char * s)1069 void ON_String::TrimLeftAndRight(const char* s)
1070 {
1071   TrimRight(s);
1072   TrimLeft(s);
1073 }
1074 
Remove(const char chRemove)1075 int ON_String::Remove( const char chRemove)
1076 {
1077   CopyArray();
1078 
1079   char* pstrSource = m_s;
1080   char* pstrDest = m_s;
1081   char* pstrEnd = m_s + Length();
1082 
1083   while( pstrSource && pstrSource  < pstrEnd)
1084   {
1085     if (*pstrSource != chRemove)
1086     {
1087       *pstrDest = *pstrSource;
1088       pstrDest++;
1089     }
1090     pstrSource++;
1091   }
1092 
1093   *pstrDest = 0;
1094   int nCount = (int)(pstrSource - pstrDest); // the (int) is for 64 bit std::size_t conversion
1095 
1096   Header()->string_length -= nCount;
1097 
1098   return nCount;
1099 }
1100 
GetAt(int i) const1101 char ON_String::GetAt( int i ) const
1102 {
1103   // no error checking
1104   return m_s[i];
1105 }
1106 
SetAt(int i,char c)1107 void ON_String::SetAt( int i, char c )
1108 {
1109   if ( i >= 0 && i < Header()->string_length ) {
1110 	  CopyArray();
1111 	  m_s[i] = c;
1112   }
1113 }
1114 
SetAt(int i,unsigned char c)1115 void ON_String::SetAt( int i, unsigned char c )
1116 {
1117   SetAt( i, (char)c );
1118 }
1119 
Mid(int i,int count) const1120 ON_String ON_String::Mid(int i, int count) const
1121 {
1122   ON_String(s);
1123   if ( i >= 0 && i < Length() && count > 0 ) {
1124     if ( count > Length() - i )
1125       count = Length() - i;
1126     s.CopyToArray( count, &m_s[i] );
1127   }
1128   return s;
1129 }
1130 
Mid(int i) const1131 ON_String ON_String::Mid(int i) const
1132 {
1133   return Mid( i, Length() - i );
1134 }
1135 
Left(int count) const1136 ON_String ON_String::Left(int count) const
1137 {
1138   ON_String s;
1139   if ( count > Length() )
1140     count = Length();
1141   if ( count > 0 ) {
1142     s.CopyToArray( count, m_s );
1143   }
1144   return s;
1145 }
1146 
Right(int count) const1147 ON_String ON_String::Right(int count) const
1148 {
1149   ON_String s;
1150   if ( count > Length() )
1151     count = Length();
1152   if ( count > 0 ) {
1153     s.CopyToArray( count, &m_s[Length()-count] );
1154   }
1155   return s;
1156 }
1157 
Format(const char * sFormat,...)1158 void ON_MSC_CDECL ON_String::Format( const char* sFormat, ...)
1159 {
1160 #define MAX_MSG_LENGTH 2048
1161   char sMessage[MAX_MSG_LENGTH];
1162   va_list args;
1163 
1164   /* put formatted message in sMessage */
1165   memset(sMessage,0,sizeof(sMessage));
1166   if (sFormat) {
1167     va_start(args, sFormat);
1168     on_vsnprintf(sMessage, MAX_MSG_LENGTH-1, sFormat, args);
1169     sMessage[MAX_MSG_LENGTH-1] = 0;
1170     va_end(args);
1171   }
1172   const int len = Length(sMessage);
1173   if ( len < 1 ) {
1174     Destroy();
1175     Create();
1176   }
1177   else {
1178     ReserveArray( len );
1179     CopyToArray( len, sMessage );
1180   }
1181 }
1182 
Format(const unsigned char * sFormat,...)1183 void ON_MSC_CDECL ON_String::Format( const unsigned char* sFormat, ...)
1184 {
1185 #define MAX_MSG_LENGTH 2048
1186   char sMessage[MAX_MSG_LENGTH];
1187   va_list args;
1188 
1189   /* put formatted message in sMessage */
1190   memset(sMessage,0,sizeof(sMessage));
1191   if (sFormat) {
1192     va_start(args, sFormat);
1193     on_vsnprintf(sMessage, MAX_MSG_LENGTH-1, (const char*)sFormat, args);
1194     sMessage[MAX_MSG_LENGTH-1] = 0;
1195     va_end(args);
1196   }
1197   const int len = Length(sMessage);
1198   if ( len < 1 ) {
1199     Destroy();
1200     Create();
1201   }
1202   else {
1203     ReserveArray( len );
1204     CopyToArray( len, sMessage );
1205   }
1206 }
1207 
1208 ///////////////////////////////////////////////////////////////////////////////
1209 
operator ==(const ON_String & s2) const1210 bool ON_String::operator==(const ON_String& s2) const
1211 {
1212   return (Compare(s2) == 0) ? true : false;
1213 }
1214 
operator ==(const char * s2) const1215 bool ON_String::operator==(const char* s2) const
1216 {
1217   return (Compare(s2) == 0) ? true : false;
1218 }
1219 
operator !=(const ON_String & s2) const1220 bool ON_String::operator!=(const ON_String& s2) const
1221 {
1222   return (Compare(s2) != 0) ? true : false;
1223 }
1224 
operator !=(const char * s2) const1225 bool ON_String::operator!=(const char* s2) const
1226 {
1227   return (Compare(s2) != 0) ? true : false;
1228 }
1229 
operator <(const ON_String & s2) const1230 bool ON_String::operator<(const ON_String& s2) const
1231 {
1232   return (Compare(s2) < 0) ? true : false;
1233 }
1234 
operator <(const char * s2) const1235 bool ON_String::operator<(const char* s2) const
1236 {
1237   return (Compare(s2) < 0) ? true : false;
1238 }
1239 
operator >(const ON_String & s2) const1240 bool ON_String::operator>(const ON_String& s2) const
1241 {
1242   return (Compare(s2) > 0) ? true : false;
1243 }
1244 
operator >(const char * s2) const1245 bool ON_String::operator>(const char* s2) const
1246 {
1247   return (Compare(s2) > 0) ? true : false;
1248 }
1249 
operator <=(const ON_String & s2) const1250 bool ON_String::operator<=(const ON_String& s2) const
1251 {
1252   return (Compare(s2) <= 0) ? true : false;
1253 }
1254 
operator <=(const char * s2) const1255 bool ON_String::operator<=(const char* s2) const
1256 {
1257   return (Compare(s2) <= 0) ? true : false;
1258 }
1259 
operator >=(const ON_String & s2) const1260 bool ON_String::operator>=(const ON_String& s2) const
1261 {
1262   return (Compare(s2) >= 0) ? true : false;
1263 }
1264 
operator >=(const char * s2) const1265 bool ON_String::operator>=(const char* s2) const
1266 {
1267   return (Compare(s2) >= 0) ? true : false;
1268 }
1269 
1270 
ON_CheckSum()1271 ON_CheckSum::ON_CheckSum()
1272 {
1273   Zero();
1274 }
1275 
~ON_CheckSum()1276 ON_CheckSum::~ON_CheckSum()
1277 {
1278   Zero();
1279 }
1280 
Zero()1281 void ON_CheckSum::Zero()
1282 {
1283   m_size = 0;
1284   m_time = 0;
1285   for ( int i = 0; i < 8; i++ )
1286     m_crc[i] = 0;
1287 }
1288 
1289 const ON_CheckSum ON_CheckSum::UnsetCheckSum;
1290 
IsSet() const1291 bool ON_CheckSum::IsSet() const
1292 {
1293   return ( 0 != m_size
1294            || 0 != m_time
1295            || 0 != m_crc[0]
1296            || 0 != m_crc[1]
1297            || 0 != m_crc[2]
1298            || 0 != m_crc[3]
1299            || 0 != m_crc[4]
1300            || 0 != m_crc[5]
1301            || 0 != m_crc[6]
1302            || 0 != m_crc[7]
1303            );
1304 }
1305 
SetBufferCheckSum(std::size_t size,const void * buffer,time_t time)1306 bool ON_CheckSum::SetBufferCheckSum(
1307                 std::size_t size,
1308                 const void* buffer,
1309                 time_t time
1310                )
1311 {
1312   bool rc = false;
1313   Zero();
1314   if ( size != 0 && buffer != 0 )
1315   {
1316     m_size = (unsigned int)size;
1317 
1318     ON__INT32 crc = 0;
1319     std::size_t sz, maxsize = 0x40000;
1320     const unsigned char* p = (const unsigned char*)buffer;
1321     for ( int i = 0; i < 7; i++ )
1322     {
1323       if ( size > 0 )
1324       {
1325         sz = (size > maxsize) ? maxsize : size;
1326         crc = ON_CRC32(crc,sz,p);
1327         p += sz;
1328         size -= sz;
1329         maxsize *= 2;
1330       }
1331       m_crc[i] = crc;
1332     }
1333     if ( size > 0 )
1334     {
1335       crc = ON_CRC32(crc,size,p);
1336     }
1337     m_crc[7] = crc;
1338     rc = true;
1339   }
1340   else if ( 0 == size )
1341   {
1342     rc = true;
1343   }
1344   m_time = time;
1345   return rc;
1346 }
1347 
GetFileStats(const wchar_t * filename,std::size_t * filesize,time_t * create_time,time_t * lastmodify_time)1348 bool ON::GetFileStats( const wchar_t* filename,
1349                        std::size_t* filesize,
1350                        time_t* create_time,
1351                        time_t* lastmodify_time
1352                       )
1353 {
1354   bool rc = false;
1355 
1356   if (filesize)
1357     *filesize = 0;
1358   if (create_time)
1359     *create_time = 0;
1360   if (lastmodify_time)
1361     *lastmodify_time = 0;
1362 
1363   if ( filename && filename[0] )
1364   {
1365     FILE* fp = ON::OpenFile(filename,L"rb");
1366     if ( fp )
1367     {
1368       rc = ON::GetFileStats(fp,filesize,create_time,lastmodify_time);
1369       ON::CloseFile(fp);
1370     }
1371   }
1372 
1373   return rc;
1374 }
1375 
GetFileStats(FILE * fp,std::size_t * filesize,time_t * create_time,time_t * lastmodify_time)1376 bool ON::GetFileStats( FILE* fp,
1377                        std::size_t* filesize,
1378                        time_t* create_time,
1379                        time_t* lastmodify_time
1380                       )
1381 {
1382   bool rc = false;
1383 
1384   if (filesize)
1385     *filesize = 0;
1386   if (create_time)
1387     *create_time = 0;
1388   if (lastmodify_time)
1389     *lastmodify_time = 0;
1390 
1391   if ( fp )
1392   {
1393 
1394 #if defined(ON_COMPILER_MSC)
1395 
1396     // Microsoft compilers
1397     int fd = _fileno(fp);
1398 #if (_MSC_VER >= 1400)
1399     // VC 8 (2005)
1400     // works for file sizes > 4GB
1401     // when std::size_t is a 64 bit integer
1402     struct _stat64 sb;
1403     memset(&sb,0,sizeof(sb));
1404     int fstat_rc = _fstat64(fd, &sb);
1405 #else
1406     // VC6 compiler
1407     // works on most compilers
1408     struct _stat sb;
1409     memset(&sb,0,sizeof(sb));
1410     int fstat_rc = _fstat(fd, &sb);
1411 #endif
1412 
1413 #else
1414     // works on most compilers
1415     int fd = fileno(fp);
1416     struct stat sb;
1417     memset(&sb,0,sizeof(sb));
1418     int fstat_rc = fstat(fd, &sb);
1419 #endif
1420 
1421 
1422     if (0 == fstat_rc)
1423     {
1424       if (filesize)
1425         *filesize = (std::size_t)sb.st_size;
1426       if (create_time)
1427         *create_time = (time_t)sb.st_ctime;
1428       if (lastmodify_time)
1429         *lastmodify_time = (time_t)sb.st_mtime;
1430       rc = true;
1431     }
1432   }
1433 
1434   return rc;
1435 }
1436 
IsDirectory(const wchar_t * pathname)1437 bool ON::IsDirectory( const wchar_t* pathname )
1438 {
1439   bool rc = false;
1440 
1441   if ( 0 != pathname && 0 != pathname[0] )
1442   {
1443     ON_wString buffer;
1444     const wchar_t* stail = pathname;
1445     while ( 0 != *stail )
1446       stail++;
1447     stail--;
1448     if ( '\\' == *stail || '/' == *stail )
1449     {
1450       const wchar_t trim[2] = {*stail,0};
1451       buffer = pathname;
1452       buffer.TrimRight(trim);
1453       if ( buffer.Length() > 0 )
1454         pathname = buffer;
1455     }
1456 #if defined(ON_COMPILER_MSC)
1457     // this works on Windows
1458     struct _stat64 buf;
1459     memset(&buf,0,sizeof(buf));
1460     int stat_errno = _wstat64( pathname, &buf );
1461     if ( 0 == stat_errno && 0 != (_S_IFDIR & buf.st_mode) )
1462     {
1463       rc = true;
1464     }
1465 #else
1466     ON_String s = pathname;
1467     const char* utf8pathname = s;
1468     rc = ON::IsDirectory(utf8pathname);
1469 #endif
1470   }
1471 
1472   return rc;
1473 }
1474 
IsDirectory(const char * utf8pathname)1475 bool ON::IsDirectory( const char* utf8pathname )
1476 {
1477   bool rc = false;
1478 
1479   if ( 0 != utf8pathname && 0 != utf8pathname[0] )
1480   {
1481     ON_String buffer;
1482     const char* stail = utf8pathname;
1483     while ( 0 != *stail )
1484       stail++;
1485     stail--;
1486     if ( '\\' == *stail || '/' == *stail )
1487     {
1488       const char trim[2] = {*stail,0};
1489       buffer = utf8pathname;
1490       buffer.TrimRight(trim);
1491       if ( buffer.Length() > 0 )
1492         utf8pathname = buffer;
1493     }
1494 #if defined(ON_COMPILER_MSC)
1495     // this works on Windows
1496     struct _stat64 buf;
1497     memset(&buf,0,sizeof(buf));
1498     int stat_errno = _stat64( utf8pathname, &buf );
1499     if ( 0 == stat_errno && 0 != (_S_IFDIR & buf.st_mode) )
1500     {
1501       rc = true;
1502     }
1503 #else
1504     // this works on Apple and gcc implentations.
1505     struct stat buf;
1506     memset(&buf,0,sizeof(buf));
1507     int stat_errno = stat( utf8pathname, &buf );
1508     if ( 0 == stat_errno && S_ISDIR(buf.st_mode) )
1509     {
1510       rc = true;
1511     }
1512 #endif
1513   }
1514 
1515   return rc;
1516 }
1517 
1518 
IsOpenNURBSFile(FILE * fp)1519 int ON::IsOpenNURBSFile( FILE* fp )
1520 {
1521   ON_String sStartSectionComment;
1522   int version = 0;
1523   if ( 0 != fp )
1524   {
1525     ON_BinaryFile archive(ON::read3dm,fp);
1526     if ( !archive.Read3dmStartSection(&version,sStartSectionComment) )
1527       version = 0;
1528   }
1529   return version;
1530 }
1531 
IsOpenNURBSFile(const wchar_t * pathname)1532 int ON::IsOpenNURBSFile( const wchar_t* pathname )
1533 {
1534   int version = 0;
1535   if ( 0 != pathname && 0 != pathname[0] )
1536   {
1537     FILE* fp = ON::OpenFile(pathname,L"rb");
1538     if ( 0 != fp )
1539     {
1540       version = ON::IsOpenNURBSFile(fp);
1541       ON::CloseFile(fp);
1542     }
1543   }
1544   return version;
1545 }
1546 
IsOpenNURBSFile(const char * utf8pathname)1547 int ON::IsOpenNURBSFile( const char* utf8pathname )
1548 {
1549   int version = 0;
1550   if ( 0 != utf8pathname && 0 != utf8pathname[0] )
1551   {
1552     FILE* fp = ON::OpenFile(utf8pathname,"rb");
1553     if ( 0 != fp )
1554     {
1555       version = ON::IsOpenNURBSFile(fp);
1556       ON::CloseFile(fp);
1557     }
1558   }
1559   return version;
1560 }
1561 
SetFileCheckSum(FILE * fp)1562 bool ON_CheckSum::SetFileCheckSum( FILE* fp )
1563 {
1564   bool rc = false;
1565   Zero();
1566   if ( fp )
1567   {
1568     std::size_t filesize = 0;
1569     time_t filetime = 0;
1570     if ( ON::GetFileStats(fp,&filesize,NULL,&filetime) )
1571     {
1572       m_time = filetime;
1573     }
1574 
1575     unsigned char buffer[1024];
1576     int count=1024;
1577     ON__INT32 crc = 0;
1578     std::size_t sz0 = 0, maxsize = 0x40000;
1579 
1580     for( int i = 0; i < 7; i++ )
1581     {
1582       sz0 += maxsize;
1583       while(1024 == count && m_size < sz0)
1584       {
1585         count = (int)fread( buffer, 1, 1024, fp ); // the (int) is for 64 bit std::size_t conversion
1586         if ( count > 0 )
1587         {
1588           m_size += count;
1589           crc = ON_CRC32( crc, count, buffer );
1590         }
1591       }
1592       maxsize *= 2;
1593       m_crc[i] = crc;
1594     }
1595 
1596     while(1024 == count)
1597     {
1598       count = (int)fread( buffer, 1, 1024, fp ); // the (int) is for 64 bit std::size_t conversion
1599       if ( count > 0 )
1600       {
1601         m_size += count;
1602         crc = ON_CRC32( crc, count, buffer );
1603       }
1604     }
1605     m_crc[7] = crc;
1606 
1607     rc = (filesize == m_size);
1608   }
1609   return rc;
1610 }
1611 
Write(ON_BinaryArchive & archive) const1612 bool ON_CheckSum::Write(ON_BinaryArchive& archive) const
1613 {
1614   bool rc = false;
1615   if ( archive.Archive3dmVersion() < 4 )
1616   {
1617     // V3 files had other information
1618     // 48 bytes of zeros will work ok
1619     unsigned char b[48];
1620     memset(b,0,sizeof(b));
1621     rc = archive.WriteByte(48,b);
1622   }
1623   else
1624   {
1625     rc = archive.WriteBigSize(m_size);
1626     if (rc)
1627       rc = archive.WriteBigTime(m_time);
1628     if (rc)
1629       rc = archive.WriteInt(8,&m_crc[0]);
1630   }
1631   return rc;
1632 }
1633 
Read(ON_BinaryArchive & archive)1634 bool ON_CheckSum::Read(ON_BinaryArchive& archive)
1635 {
1636   bool rc;
1637 
1638   Zero();
1639 
1640   rc  = archive.ReadBigSize(&m_size);
1641   if (rc)
1642     rc = archive.ReadBigTime(&m_time);
1643   if (rc)
1644     rc = archive.ReadInt(8,&m_crc[0]);
1645 
1646   if (    archive.ArchiveOpenNURBSVersion() < 200603100
1647        || archive.Archive3dmVersion() < 4
1648        )
1649   {
1650     // ON_CheckSums in V3 archives and V4 archives with
1651     // version < 200603100 have the same size but an
1652     // incompatible format.  These were not used.
1653     Zero();
1654   }
1655 
1656   return rc;
1657 }
1658 
1659 
SetFileCheckSum(const wchar_t * filename)1660 bool ON_CheckSum::SetFileCheckSum( const wchar_t* filename )
1661 {
1662   bool rc = false;
1663   Zero();
1664   if ( 0 == filename || 0 == filename[0] )
1665   {
1666     rc = true;
1667   }
1668   else
1669   {
1670     FILE* fp = ON::OpenFile(filename,L"rb");
1671     if ( fp )
1672     {
1673       rc = SetFileCheckSum(fp);
1674       ON::CloseFile(fp);
1675     }
1676   }
1677   return rc;
1678 }
1679 
CheckBuffer(std::size_t size,const void * buffer) const1680 bool ON_CheckSum::CheckBuffer(
1681   std::size_t size,
1682   const void* buffer
1683   ) const
1684 {
1685   if ( m_size != size )
1686     return false;
1687   if ( 0 == size )
1688     return true;
1689   if ( 0 == buffer )
1690     return false;
1691 
1692   ON__UINT32 crc = 0;
1693   std::size_t sz, maxsize = 0x40000;
1694   const unsigned char* p = (const unsigned char*)buffer;
1695   for ( int i = 0; i < 7; i++ )
1696   {
1697     if ( size > 0 )
1698     {
1699       sz = (size > maxsize) ? maxsize : size;
1700       crc = ON_CRC32(crc,sz,p);
1701       p += sz;
1702       size -= sz;
1703       maxsize *= 2;
1704     }
1705     if ( m_crc[i] != crc )
1706       return false;
1707   }
1708   if ( size > 0 )
1709   {
1710     crc = ON_CRC32(crc,size,p);
1711   }
1712   if ( m_crc[7] != crc )
1713     return false;
1714 
1715   return true;
1716 }
1717 
CheckFile(FILE * fp,bool bSkipTimeCheck) const1718 bool ON_CheckSum::CheckFile(
1719   FILE* fp,
1720   bool bSkipTimeCheck
1721   ) const
1722 {
1723   if ( !fp )
1724     return false;
1725 
1726   std::size_t filesize=0;
1727   time_t filetime=0;
1728   if ( ON::GetFileStats( fp, &filesize, NULL, &filetime ) )
1729   {
1730     if ( m_size != filesize )
1731     {
1732       return false;
1733     }
1734 
1735     if ( !bSkipTimeCheck && m_time != filetime)
1736     {
1737       return false;
1738     }
1739   }
1740 
1741   unsigned char buffer[1024];
1742   int count=1024;
1743   ON__UINT32 crc = 0;
1744   std::size_t sz0 = 0, maxsize = 0x40000;
1745   std::size_t sz = 0;
1746 
1747   for( int i = 0; i < 7; i++ )
1748   {
1749     sz0 += maxsize;
1750     while(1024 == count && sz < sz0)
1751     {
1752       count = (int)fread( buffer, 1, 1024, fp ); // the (int) is for 64 bit std::size_t conversion
1753       if ( count > 0 )
1754       {
1755         sz += count;
1756         crc = ON_CRC32( crc, count, buffer );
1757       }
1758     }
1759     maxsize *= 2;
1760     if ( m_crc[i] != crc )
1761       return false;
1762   }
1763 
1764   while(1024 == count)
1765   {
1766     count = (int)fread( buffer, 1, 1024, fp ); // the (int) is for 64 bit std::size_t conversion
1767     if ( count > 0 )
1768     {
1769       sz += count;
1770       crc = ON_CRC32( crc, count, buffer );
1771     }
1772   }
1773   if (m_crc[7] != crc)
1774     return false;
1775 
1776   if ( sz != m_size )
1777     return false;
1778 
1779   return true;
1780 }
1781 
CheckFile(const wchar_t * filename,bool bSkipTimeCheck) const1782 bool ON_CheckSum::CheckFile(
1783   const wchar_t* filename,
1784   bool bSkipTimeCheck
1785   ) const
1786 {
1787   bool rc = false;
1788   if ( filename && filename[0] )
1789   {
1790     FILE* fp = ON::OpenFile(filename,L"rb");
1791     if ( fp )
1792     {
1793       rc = CheckFile(fp,bSkipTimeCheck);
1794       ON::CloseFile(fp);
1795     }
1796   }
1797   return rc;
1798 }
1799 
Dump(ON_TextLog & text_log) const1800 void ON_CheckSum::Dump(ON_TextLog& text_log) const
1801 {
1802   // Using %llu so this code is portable for both 32 and 64 bit
1803   // builds on a wide range of compilers.
1804 
1805   unsigned long long u; // 8 bytes in windows and gcc - should be at least as big
1806                         // as a std::size_t or time_t.
1807 
1808   text_log.Print("Checksum:");
1809   if ( !IsSet() )
1810     text_log.Print("zero (not set)\n");
1811   else
1812   {
1813     text_log.PushIndent();
1814     text_log.Print("\n");
1815     u = (unsigned long long)m_size;
1816     text_log.Print("Size: %llu bytes\n",u);
1817     u = (unsigned long long)m_time;
1818     text_log.Print("Last Modified Time: %u (seconds since January 1, 1970, UCT)\n",u);
1819     text_log.Print("CRC List: %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x\n",
1820                    m_crc[0],m_crc[1],m_crc[2],m_crc[3],m_crc[4],m_crc[5],m_crc[6],m_crc[7]
1821                    );
1822     text_log.PopIndent();
1823   }
1824 }
1825