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