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 "opennurbs.h"
18
Open(const wchar_t * filename,const wchar_t * mode)19 FILE* ON_FileStream::Open( const wchar_t* filename, const wchar_t* mode )
20 {
21 FILE* fp = 0;
22
23 if ( 0 == filename || 0 == filename[0] || 0 == mode || 0 == mode[0] )
24 return fp;
25
26 #if defined(ON_OS_WINDOWS)
27 errno_t e = _wfopen_s(&fp,filename,mode);
28 if ( 0 != e && 0 == fp )
29 fp = 0; // reference e to keep lint quiet.
30 #else
31 // I can't find an wfopen() or _wfopen() in
32 // gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)
33 ON_String fnameUTF8(filename);
34 ON_String modeUTF8(mode);
35 fp = fopen(fnameUTF8,modeUTF8);
36 #endif
37
38 return fp;
39 }
40
Open(const char * filename,const char * mode)41 FILE* ON_FileStream::Open( const char* filename, const char* mode )
42 {
43 FILE* fp = 0;
44
45 if ( 0 == filename || 0 == filename[0] || 0 == mode || 0 == mode[0] )
46 return fp;
47
48 #if defined(ON_OS_WINDOWS)
49 errno_t e = fopen_s(&fp,filename,mode);
50 if ( 0 != e && 0 == fp )
51 fp = 0; // reference e to keep lint quiet.
52 #else
53 fp = fopen(filename,mode);
54 #endif
55
56 return fp;
57 }
58
Close(FILE * fp)59 int ON_FileStream::Close( FILE* fp )
60 {
61 return ( ( 0 != fp ) ? fclose(fp) : -1 );
62 }
63
CurrentPosition(FILE * fp)64 ON__INT64 ON_FileStream::CurrentPosition( FILE* fp )
65 {
66 if ( 0 == fp )
67 return -1;
68 #if defined(ON_OS_WINDOWS)
69 return _ftelli64(fp);
70 #else
71 return ftell(fp);
72 #endif
73 }
74
SeekFromCurrentPosition(FILE * fp,ON__INT64 offset)75 bool ON_FileStream::SeekFromCurrentPosition( FILE* fp, ON__INT64 offset )
76 {
77 return ON_FileStream::Seek(fp,offset,SEEK_CUR);
78 }
79
SeekFromStart(FILE * fp,ON__INT64 offset)80 bool ON_FileStream::SeekFromStart( FILE* fp, ON__INT64 offset )
81 {
82 return ON_FileStream::Seek(fp,offset,SEEK_SET);
83 }
84
SeekFromEnd(FILE * fp,ON__INT64 offset)85 bool ON_FileStream::SeekFromEnd( FILE* fp, ON__INT64 offset )
86 {
87 return ON_FileStream::Seek(fp,offset,SEEK_END);
88 }
89
Seek(FILE * fp,ON__INT64 offset,int origin)90 bool ON_FileStream::Seek( FILE* fp, ON__INT64 offset, int origin )
91 {
92 if ( 0 == fp )
93 return false;
94
95 if ( origin < 0 || origin > 2 )
96 return false;
97
98 if ( 0 == offset )
99 return true;
100
101 #if defined(ON_OS_WINDOWS)
102
103 if ( 0 != _fseeki64(fp,offset,origin) )
104 return false;
105
106 #else
107
108 const int i = 2147483646;
109 const ON__INT64 i64 = i;
110 while ( offset > i64 )
111 {
112 if ( 0 != fseek( fp, i, origin ) )
113 return false;
114 offset -= i64;
115 }
116 while ( offset < -i64 )
117 {
118 if ( 0 != fseek( fp, -i, origin ) )
119 return false;
120 offset += i64;
121 }
122 if ( 0 != offset )
123 {
124 int ioffset = (int)offset;
125 if ( 0 != fseek( fp, ioffset, origin ) )
126 return false;
127 }
128
129 #endif
130
131 return true;
132 }
133
Read(FILE * fp,ON__UINT64 count,void * buffer)134 ON__UINT64 ON_FileStream::Read( FILE* fp, ON__UINT64 count, void* buffer )
135 {
136 ON__UINT64 rc = 0;
137 if ( 0 == fp || count <= 0 || 0 == buffer )
138 return rc;
139
140 if ( count <= ON_MAX_SIZE_T )
141 {
142 rc = (ON__UINT64)fread(buffer,1,(size_t)count,fp);
143 }
144 else
145 {
146 size_t sz, szread;
147 while ( count > 0 )
148 {
149 sz = ( count > ON_MAX_SIZE_T ) ? ON_MAX_SIZE_T : ((size_t)count);
150 szread = fread(buffer,1,sz,fp);
151 rc += szread;
152 if ( szread != sz )
153 break;
154 count -= sz;
155 buffer = ((unsigned char*)buffer) + sz;
156 }
157 }
158
159 return rc;
160 }
161
Write(FILE * fp,ON__UINT64 count,const void * buffer)162 ON__UINT64 ON_FileStream::Write( FILE* fp, ON__UINT64 count, const void* buffer )
163 {
164 ON__UINT64 rc = 0;
165 if ( 0 == fp || count <= 0 || 0 == buffer )
166 return rc;
167
168 if ( count <= ON_MAX_SIZE_T )
169 {
170 rc = fwrite(buffer,1,(size_t)count,fp);
171 }
172 else
173 {
174 size_t sz, szwrite;
175 while ( count > 0 )
176 {
177 sz = ( count > ON_MAX_SIZE_T ) ? ON_MAX_SIZE_T : ((size_t)count);
178 szwrite = fwrite(buffer,1,sz,fp);
179 rc += szwrite;
180 if ( szwrite != sz )
181 break;
182 count -= sz;
183 buffer = ((unsigned char*)buffer) + sz;
184 }
185 }
186
187 return rc;
188 }
189
Flush(FILE * fp)190 bool ON_FileStream::Flush( FILE* fp )
191 {
192 if ( 0 == fp )
193 return false;
194 if ( 0 != fflush(fp) )
195 return false;
196 return true;
197 }
198
199
GetFileInformation(FILE * fp,ON__UINT64 * file_size,ON__UINT64 * file_create_time,ON__UINT64 * file_last_modified_time)200 bool ON_FileStream::GetFileInformation(
201 FILE* fp,
202 ON__UINT64* file_size,
203 ON__UINT64* file_create_time,
204 ON__UINT64* file_last_modified_time
205 )
206 {
207 bool rc = false;
208
209 if (file_size)
210 *file_size = 0;
211 if (file_create_time)
212 *file_create_time = 0;
213 if (file_last_modified_time)
214 *file_last_modified_time = 0;
215
216 if ( fp )
217 {
218
219 #if defined(ON_COMPILER_MSC)
220
221 // Microsoft compilers
222 int fd = _fileno(fp);
223 #if (_MSC_VER >= 1400)
224 // VC 8 (2005)
225 // works for file sizes > 4GB
226 // when size_t is a 64 bit integer
227 struct _stat64 sb;
228 memset(&sb,0,sizeof(sb));
229 int fstat_rc = _fstat64(fd, &sb);
230 #else
231 // VC6 compiler
232 // works on most compilers
233 struct _stat sb;
234 memset(&sb,0,sizeof(sb));
235 int fstat_rc = _fstat(fd, &sb);
236 #endif
237
238 #else
239 // works on most compilers
240 int fd = fileno(fp);
241 struct stat sb;
242 memset(&sb,0,sizeof(sb));
243 int fstat_rc = fstat(fd, &sb);
244 #endif
245
246
247 if (0 == fstat_rc)
248 {
249 if (file_size)
250 *file_size = (ON__UINT64)sb.st_size;
251 if (file_create_time)
252 *file_create_time = (ON__UINT64)sb.st_ctime;
253 if (file_last_modified_time)
254 *file_last_modified_time = (ON__UINT64)sb.st_mtime;
255 rc = true;
256 }
257 }
258
259 return rc;
260 }
261
262
263 class ON_ReadChunkHelper
264 {
265 public:
266 ON_ReadChunkHelper(ON_BinaryArchive&);
267 ~ON_ReadChunkHelper();
268
269 ON_BinaryArchive& m_binary_archive;
270 bool m_bReadSuccess;
271 ON__UINT32 m_chunk_tcode;
272 ON__INT64 m_chunk_value;
273
274 private:
275 bool m_bCallEndRead3dmChunk;
276 // prohibit use - no implementation
277 ON_ReadChunkHelper();
278 ON_ReadChunkHelper(const ON_ReadChunkHelper&);
279 ON_ReadChunkHelper& operator=(const ON_ReadChunkHelper&);
280 };
281
ON_ReadChunkHelper(ON_BinaryArchive & binary_archive)282 ON_ReadChunkHelper::ON_ReadChunkHelper(ON_BinaryArchive& binary_archive)
283 : m_binary_archive(binary_archive)
284 , m_bReadSuccess(0)
285 , m_chunk_tcode(0)
286 , m_chunk_value(0)
287 , m_bCallEndRead3dmChunk(0)
288 {
289 m_bReadSuccess = m_binary_archive.BeginRead3dmBigChunk(&m_chunk_tcode,&m_chunk_value);
290 if ( m_bReadSuccess )
291 m_bCallEndRead3dmChunk = true;
292 }
293
~ON_ReadChunkHelper()294 ON_ReadChunkHelper::~ON_ReadChunkHelper()
295 {
296 if ( m_bReadSuccess && !m_binary_archive.EndRead3dmChunk() )
297 m_bReadSuccess = false;
298 }
299
ON_IsUnsignedChunkTypecode(ON__UINT32 typecode)300 bool ON_IsUnsignedChunkTypecode( ON__UINT32 typecode )
301 {
302 // returns tru if the chunk value should be treated as an unsigned int.
303 return ( 0 == (TCODE_SHORT & typecode)
304 || TCODE_RGB == typecode
305 || TCODE_RGBDISPLAY == typecode
306 || TCODE_PROPERTIES_OPENNURBS_VERSION == typecode
307 || TCODE_OBJECT_RECORD_TYPE == typecode
308 );
309 }
310
ON_IsLongChunkTypecode(ON__UINT32 typecode)311 bool ON_IsLongChunkTypecode(ON__UINT32 typecode)
312 {
313 // NOTE: RenderXXXX plug-in used zero as a typecode in material userdata, sigh ...
314 //return (0 != typecode && 0 == (TCODE_SHORT & typecode));
315 return (0 == (TCODE_SHORT & typecode));
316 }
317
ON_IsShorChunkTypecode(ON__UINT32 typecode)318 bool ON_IsShorChunkTypecode(ON__UINT32 typecode)
319 {
320 return (0 != (TCODE_SHORT & typecode));
321 }
322
323 static
DownSizeINT(ON__INT64 i64,ON__INT32 * i32)324 bool DownSizeINT( ON__INT64 i64, ON__INT32* i32 )
325 {
326 const static ON__INT64 i32max = 2147483647;
327 if ( i64 <= i32max && i64 >= (-i32max - 1) )
328 {
329 *i32 = (ON__INT32)i64;
330 return true;
331 }
332
333 ON_ERROR("i64 too big to convert to 4 byte signed int");
334 *i32 = 0;
335 return false;
336 }
337
338 static
DownSizeUINT(ON__UINT64 u64,ON__UINT32 * u32)339 bool DownSizeUINT( ON__UINT64 u64, ON__UINT32* u32 )
340 {
341 if ( u64 <= 0xFFFFFFFF )
342 {
343 *u32 = (ON__UINT32)u64;
344 return true;
345 }
346
347 ON_ERROR("u64 too big to convert to 4 byte unsigned int");
348 *u32 = 0;
349 return false;
350 }
351
352 static
DownSizeChunkValue(ON__UINT32 typecode,ON__INT64 v64,ON__INT32 * v32)353 bool DownSizeChunkValue( ON__UINT32 typecode, ON__INT64 v64, ON__INT32* v32 )
354 {
355 if ( 0 == v32 )
356 return true;
357 return ( ON_IsLongChunkTypecode(typecode) )
358 ? DownSizeUINT( (ON__UINT64)v64, (ON__UINT32*)v32 )
359 : DownSizeINT( v64, v32 );
360 }
361
362
363
364 struct ON__3dmV1LayerIndex
365 {
366 int m_layer_index;
367 int m_layer_name_length;
368 char* m_layer_name;
369 struct ON__3dmV1LayerIndex* m_next;
370 };
371
ON_BinaryArchive(ON::archive_mode mode)372 ON_BinaryArchive::ON_BinaryArchive( ON::archive_mode mode )
373 : m_3dm_version(0),
374 m_3dm_v1_layer_index(0), m_3dm_v1_material_index(0),
375 m_error_message_mask(0),
376 m_3dm_opennurbs_version(0),
377 m_3dm_start_section_offset(0),
378 m_active_table(ON_BinaryArchive::no_active_table),
379 m_bDoChunkCRC(0), m_bad_CRC_count(0),
380 m_endian(ON::Endian()),
381 m_mode(mode)
382 {
383 // Sparc, MIPS, ... CPUs have big endian byte order
384 // ON_BinaryArchives use little endian byte order
385
386 m_bSaveUserData = true; // true to save user data (increases file size)
387 m_bSavePreviewImage = false; // true to save 200x200 preview bitmap (increases file size)
388 m_bEmbedTextureBitmaps = false; // true to embed texture, bump, trace, and wallpaper bitmaps (increases file size)
389 m_bSaveRenderMeshes = false; // true to save meshes used to render B-rep objects (increases file size)
390 m_bSaveAnalysisMeshes = false; // true to save meshes used in surface analysis (increases file size)
391
392 m_zlib.mode = ON::unknown_archive_mode;
393 memset( &m_zlib.strm, 0, sizeof(m_zlib.strm) );
394
395 m_V1_layer_list = 0;
396 }
397
~ON_BinaryArchive()398 ON_BinaryArchive::~ON_BinaryArchive()
399 {
400 if ( 0 != m_V1_layer_list )
401 {
402 struct ON__3dmV1LayerIndex* next = m_V1_layer_list;
403 m_V1_layer_list = 0;
404 for ( int i = 0; 0 != next && i < 1000; i++ )
405 {
406 struct ON__3dmV1LayerIndex* p = next;
407 next = p->m_next;
408 onfree(p);
409 }
410 }
411
412 CompressionEnd();
413 }
414
415
ToggleByteOrder(int count,int sizeof_element,const void * src,void * dst)416 bool ON_BinaryArchive::ToggleByteOrder(
417 int count, // number of elements
418 int sizeof_element, // size of element (2,4, or 8)
419 const void* src, // source buffer
420 void* dst // destination buffer (can be same as source buffer)
421 )
422 {
423 unsigned char c[32];
424 const unsigned char* a = (const unsigned char*)src;
425 unsigned char* b = (unsigned char*)dst;
426
427 bool rc = (count==0 || (count>0&&src&&dst));
428 if ( rc )
429 {
430 // loops are unrolled and a switch is used
431 // to speed things up a bit.
432 switch(sizeof_element)
433 {
434 case 2:
435 while(count--)
436 {
437 c[0] = *a++;
438 c[1] = *a++;
439 *b++ = c[1];
440 *b++ = c[0];
441 }
442 break;
443
444 case 4:
445 while(count--)
446 {
447 c[0] = *a++;
448 c[1] = *a++;
449 c[2] = *a++;
450 c[3] = *a++;
451 *b++ = c[3];
452 *b++ = c[2];
453 *b++ = c[1];
454 *b++ = c[0];
455 }
456 break;
457
458 case 8:
459 while(count--)
460 {
461 c[0] = *a++;
462 c[1] = *a++;
463 c[2] = *a++;
464 c[3] = *a++;
465 c[4] = *a++;
466 c[5] = *a++;
467 c[6] = *a++;
468 c[7] = *a++;
469 *b++ = c[7];
470 *b++ = c[6];
471 *b++ = c[5];
472 *b++ = c[4];
473 *b++ = c[3];
474 *b++ = c[2];
475 *b++ = c[1];
476 *b++ = c[0];
477 }
478 break;
479
480 default:
481 if ( sizeof_element > 0 && sizeof_element < 32 )
482 {
483 // As of 2 May 2003, this case is never used
484 // by core opennurbs objects.
485 //
486 // This is here so that future code will work
487 // if and when 128 bit "ints"/"doubles" become common
488 // enough that they can be stored in 3dm files.
489 // It may also happen that third party applications
490 // on specialized CPUs need to toggle byte order
491 // for 128 bit ints/doubles stored as user data.
492 int i;
493 while(count--)
494 {
495 for (i = 0; i < sizeof_element; i++)
496 c[i] = *a++;
497 while(i--)
498 *b++ = c[i];
499 }
500 }
501 else
502 {
503 rc = false;
504 }
505 break;
506 }
507 }
508 return rc;
509 }
510
BigSeekFromStart(ON__UINT64 offset)511 bool ON_BinaryArchive::BigSeekFromStart( ON__UINT64 offset )
512 {
513 // SeekFromStart() is a virutal function that
514 // any developer can implement. Some implementations
515 // may use signed 4 byte int in critical places.
516 // BigSeekFromStart() will work correctly in
517 // this worst case situation.
518 return ( offset > 2147483632 )
519 ? ( SeekFromStart(2147483632) && BigSeekForward(offset - 2147483632) )
520 : SeekFromStart((size_t)offset);
521 }
522
523
524
BigSeekForward(ON__UINT64 offset)525 bool ON_BinaryArchive::BigSeekForward( ON__UINT64 offset )
526 {
527 // SeekFromCurrentPosition() is a virutal function that
528 // uses a signed 4 byte int in critical places.
529 // BigSeekForward() will work correctly when
530 // offset is larger than the maximum value of a signed
531 // 4 byte int.
532 while ( offset > 2147483632 )
533 {
534 if ( !SeekFromCurrentPosition(2147483632) )
535 return false;
536 offset -= 2147483632;
537 }
538 if ( offset > 0 )
539 {
540 int ioffset32 = (int)((ON__INT64)offset);
541 return SeekFromCurrentPosition(ioffset32);
542 }
543 return true;
544 }
545
546
BigSeekBackward(ON__UINT64 offset)547 bool ON_BinaryArchive::BigSeekBackward( ON__UINT64 offset )
548 {
549 // SeekFromCurrentPosition() is a virutal function that
550 // uses a signed 4 byte int in critical places.
551 // BigSeekBackward() will work correctly when
552 // offset is larger than the maximum value of a signed
553 // 4 byte int.
554 while ( offset > 2147483632 )
555 {
556 if ( !SeekFromCurrentPosition(-2147483632) )
557 return false;
558 offset -= 2147483632;
559 }
560 if ( offset > 0 )
561 {
562 int ioffset32 = (int)((ON__INT64)offset);
563 return SeekFromCurrentPosition(-ioffset32);
564 }
565 return true;
566 }
567
568
BigSeekFromCurrentPosition(ON__INT64 offset)569 bool ON_BinaryArchive::BigSeekFromCurrentPosition( ON__INT64 offset )
570 {
571 // SeekFromCurrentPosition() is a virutal function that
572 // uses a signed 4 byte int in critical places.
573 // BigSeekFromCurrentPosition() will work correctly when
574 // offset is smaller than the minimum value of a signed
575 // 4 byte int or the maximum value of a signed 4 byte int.
576 return ( offset >= 0 )
577 ? BigSeekForward((ON__UINT64)offset)
578 : BigSeekBackward((ON__UINT64)(-offset));
579 }
580
581 bool
ReadMode() const582 ON_BinaryArchive::ReadMode() const
583 {
584 return (m_mode & ON::read) ? true : false;
585 }
586
587 bool
WriteMode() const588 ON_BinaryArchive::WriteMode() const
589 {
590 return (m_mode & ON::write) ? true : false;
591 }
592
593 bool
ReadChar(size_t count,char * p)594 ON_BinaryArchive::ReadChar( // Read an array of 8 bit chars
595 size_t count, // number of chars to read
596 char* p
597 )
598 {
599 return ReadByte( count, p );
600 }
601
602 bool
ReadChar(size_t count,unsigned char * p)603 ON_BinaryArchive::ReadChar( // Read an array of 8 bit unsigned chars
604 size_t count, // number of unsigned chars to read
605 unsigned char* p
606 )
607 {
608 return ReadByte( count, p );
609 }
610
611 bool
ReadChar(char * p)612 ON_BinaryArchive::ReadChar( // Read a single 8 bit char
613 char* p
614 )
615 {
616 return ReadByte( 1, p );
617 }
618
619 bool
ReadChar(unsigned char * p)620 ON_BinaryArchive::ReadChar( // Read a single 8 bit unsigned char
621 unsigned char* p
622 )
623 {
624 return ReadByte( 1, p );
625 }
626
627 bool
ReadInt16(size_t count,ON__INT16 * p)628 ON_BinaryArchive::ReadInt16( // Read an array of 16 bit integers
629 size_t count, // number of unsigned integers to read
630 ON__INT16* p
631 )
632 {
633 bool rc = ReadByte( count<<1, p );
634 if ( rc && m_endian == ON::big_endian )
635 {
636 // reverse byte order
637 unsigned char* b= (unsigned char*) (p);
638 unsigned char c;
639 while(count--) {
640 c = b[0]; b[0] = b[1]; b[1] = c;
641 b += 2;
642 }
643 }
644 return rc;
645 }
646
647 bool
ReadShort(size_t count,short * p)648 ON_BinaryArchive::ReadShort( // Read an array of 16 bit shorts
649 size_t count, // number of unsigned chars to read
650 short* p
651 )
652 {
653 #if defined(ON_COMPILER_MSC)
654 #pragma warning( push )
655 // Disable the MSC /W4 "conditional expression is constant" warning
656 // about 2 == sizeof(*p). Since this code has to run on machines
657 // where sizeof(*p) can be 2, 4, or 8 bytes, the test is necessary.
658 #pragma warning( disable : 4127 )
659 #endif
660
661 bool rc = true;
662
663 if ( 2 == sizeof(*p) )
664 {
665 rc = ReadInt16( count, (ON__INT16*)p );
666 }
667 else
668 {
669 size_t j;
670 ON__INT16 i16;
671 for ( j = 0; j < count && rc; j++ )
672 {
673 rc = ReadInt16( 1, &i16 );
674 *p++ = (short)i16;
675 }
676 }
677 return rc;
678
679 #if defined(ON_COMPILER_MSC)
680 #pragma warning( pop )
681 #endif
682 }
683
684 bool
ReadShort(size_t count,unsigned short * p)685 ON_BinaryArchive::ReadShort( // Read an array of 16 bit unsigned shorts
686 size_t count, // number of unsigned chars to read
687 unsigned short* p
688 )
689 {
690 return ReadShort( count, (short*)p );
691 }
692
693 bool
ReadShort(short * p)694 ON_BinaryArchive::ReadShort( // Read a single 16 bit short
695 short* p
696 )
697 {
698 return ReadShort( 1, p );
699 }
700
701 bool
ReadShort(unsigned short * p)702 ON_BinaryArchive::ReadShort( // Read a single 16 bit unsigned short
703 unsigned short* p
704 )
705 {
706 return ReadShort( 1, p );
707 }
708
709 bool
ReadInt32(size_t count,ON__INT32 * p)710 ON_BinaryArchive::ReadInt32( // Read an array of 32 bit integers
711 size_t count, // number of 32 bit integers to read
712 ON__INT32* p
713 )
714 {
715 bool rc = ReadByte( count<<2, p );
716 if ( rc && m_endian == ON::big_endian )
717 {
718 unsigned char* b= (unsigned char*)p;
719 unsigned char c;
720 while(count--) {
721 c = b[0]; b[0] = b[3]; b[3] = c;
722 c = b[1]; b[1] = b[2]; b[2] = c;
723 b += 4;
724 }
725 }
726 return rc;
727 }
728
729 bool
ReadInt(size_t count,int * p)730 ON_BinaryArchive::ReadInt( // Read an array of integers
731 size_t count, // number of unsigned chars to read
732 int* p
733 )
734 {
735 #if defined(ON_COMPILER_MSC)
736 #pragma warning( push )
737 // Disable the MSC /W4 "conditional expression is constant" warning
738 // about 4 == sizeof(*p). Since this code has to run on machines
739 // where sizeof(*p) can be 2, 4, or 8 bytes, the test is necessary.
740 #pragma warning( disable : 4127 )
741 #endif
742
743 bool rc;
744 if ( 4 == sizeof(*p) )
745 {
746 rc = ReadInt32( count, (ON__INT32*)p );
747 }
748 else
749 {
750 rc = true;
751 ON__INT32 i32;
752 size_t j;
753 for ( j = 0; j < count && rc; j++ )
754 {
755 rc = ReadInt32(1,&i32);
756 if (rc)
757 *p++ = (int)i32;
758 }
759 }
760 return rc;
761
762 #if defined(ON_COMPILER_MSC)
763 #pragma warning( pop )
764 #endif
765 }
766
767 bool
ReadInt(size_t count,unsigned int * p)768 ON_BinaryArchive::ReadInt( // Read an array of 32 bit integers
769 size_t count, // number of unsigned chars to read
770 unsigned int* p
771 )
772 {
773 return ReadInt( count, (int*)p );
774 }
775
776 bool
ReadInt(int * p)777 ON_BinaryArchive::ReadInt( // Read a single 32 bit integer
778 int* p
779 )
780 {
781 return ReadInt( 1, p );
782 }
783
784 bool
ReadInt(unsigned int * p)785 ON_BinaryArchive::ReadInt( // Read a single 32 bit unsigned integer
786 unsigned int* p
787 )
788 {
789 return ReadInt( 1, p );
790 }
791
ReadBigInt(size_t count,ON__INT64 * p)792 bool ON_BinaryArchive::ReadBigInt( // Read an array of 64 bit integers
793 size_t count,
794 ON__INT64* p
795 )
796 {
797 return ReadInt64(1,p);
798 }
799
ReadBigInt(size_t count,ON__UINT64 * p)800 bool ON_BinaryArchive::ReadBigInt( // Read an array of 64 bit integers
801 size_t count,
802 ON__UINT64* p
803 )
804 {
805 return ReadInt64(1,(ON__INT64*)p);
806 }
807
ReadBigInt(ON__INT64 * p)808 bool ON_BinaryArchive::ReadBigInt( // Read a single 64 bit integer
809 ON__INT64* p
810 )
811 {
812 return ReadInt64(1,p);
813 }
814
ReadBigInt(ON__UINT64 * p)815 bool ON_BinaryArchive::ReadBigInt( // Read a single 64 bit unsigned integer
816 ON__UINT64* p
817 )
818 {
819 return ReadInt64(1,(ON__INT64*)p);
820 }
821
822
823
824 bool
ReadLong(size_t count,long * p)825 ON_BinaryArchive::ReadLong( // Read an array of 32 bit integers
826 size_t count, // number of unsigned chars to read
827 long* p
828 )
829 {
830 #if defined(ON_COMPILER_MSC)
831 #pragma warning( push )
832 // Disable the MSC /W4 "conditional expression is constant" warning
833 // about 4 == sizeof(*p). Since this code has to run on machines
834 // where sizeof(*p) can be 2, 4, or 8 bytes, the test is necessary.
835 #pragma warning( disable : 4127 )
836 #endif
837
838 bool rc;
839 if ( 4 == sizeof(*p) )
840 {
841 rc = ReadInt32( count, (ON__INT32*)p );
842 }
843 else
844 {
845 rc = true;
846 ON__INT32 i32;
847 size_t j;
848 for ( j = 0; j < count && rc; j++ )
849 {
850 rc = ReadInt32(1,&i32);
851 if (rc)
852 *p++ = (long)i32;
853 }
854 }
855 return rc;
856
857 #if defined(ON_COMPILER_MSC)
858 #pragma warning( pop )
859 #endif
860 }
861
862 bool
ReadLong(size_t count,unsigned long * p)863 ON_BinaryArchive::ReadLong( // Read an array of 32 bit integers
864 size_t count, // number of unsigned chars to read
865 unsigned long* p
866 )
867 {
868 return ReadLong( count, (long*)p );
869 }
870
871 bool
ReadLong(long * p)872 ON_BinaryArchive::ReadLong( // Read a single 32 bit integer
873 long* p
874 )
875 {
876 return ReadLong( 1, (long*)p );
877 }
878
879 bool
ReadLong(unsigned long * p)880 ON_BinaryArchive::ReadLong( // Read a single 32 bit unsigned integer
881 unsigned long* p
882 )
883 {
884 return ReadLong( 1, (long*)p );
885 }
886
887 bool
ReadFloat(size_t count,float * p)888 ON_BinaryArchive::ReadFloat( // Read an array of floats
889 size_t count, // number of unsigned chars to read
890 float* p
891 )
892 {
893 // 32 bit floats and 32 bit integers have same size and endian issues
894 return ReadInt32( count, (ON__INT32*)p );
895 }
896
897 bool
ReadFloat(float * p)898 ON_BinaryArchive::ReadFloat( // Read a single float
899 float* p
900 )
901 {
902 return ReadFloat( 1, p );
903 }
904
905 bool
ReadDouble(size_t count,double * p)906 ON_BinaryArchive::ReadDouble( // Read an array of IEEE 64 bit doubles
907 size_t count, // number of unsigned chars to read
908 double* p
909 )
910 {
911 bool rc = ReadByte( count<<3, p );
912 if ( rc && m_endian == ON::big_endian )
913 {
914 unsigned char* b=(unsigned char*)p;
915 unsigned char c;
916 while(count--) {
917 c = b[0]; b[0] = b[7]; b[7] = c;
918 c = b[1]; b[1] = b[6]; b[6] = c;
919 c = b[2]; b[2] = b[5]; b[5] = c;
920 c = b[3]; b[3] = b[4]; b[4] = c;
921 b += 8;
922 }
923 }
924 return rc;
925 }
926
927 bool
ReadDouble(double * p)928 ON_BinaryArchive::ReadDouble( // Read a single double
929 double* p
930 )
931 {
932 return ReadDouble( 1, p );
933 }
934
935 bool
ReadColor(ON_Color & color)936 ON_BinaryArchive::ReadColor( ON_Color& color )
937 {
938 unsigned int colorref = 0;
939 bool rc = ReadInt( &colorref );
940 color = colorref;
941 return rc;
942 }
943
944 bool
ReadPoint(ON_2dPoint & p)945 ON_BinaryArchive::ReadPoint (
946 ON_2dPoint& p
947 )
948 {
949 return ReadDouble( 2, &p.x );
950 }
951
952 bool
ReadPoint(ON_3dPoint & p)953 ON_BinaryArchive::ReadPoint (
954 ON_3dPoint& p
955 )
956 {
957 return ReadDouble( 3, &p.x );
958 }
959
960 bool
ReadPoint(ON_4dPoint & p)961 ON_BinaryArchive::ReadPoint (
962 ON_4dPoint& p
963 )
964 {
965 return ReadDouble( 4, &p.x );
966 }
967
968 bool
ReadVector(ON_2dVector & v)969 ON_BinaryArchive::ReadVector (
970 ON_2dVector& v
971 )
972 {
973 return ReadDouble( 2, &v.x );
974 }
975
976 bool
ReadVector(ON_3dVector & v)977 ON_BinaryArchive::ReadVector (
978 ON_3dVector& v
979 )
980 {
981 return ReadDouble( 3, &v.x );
982 }
983
WriteBoundingBox(const ON_BoundingBox & bbox)984 bool ON_BinaryArchive::WriteBoundingBox(const ON_BoundingBox& bbox)
985 {
986 bool rc = WritePoint( bbox.m_min );
987 if (rc) rc = WritePoint( bbox.m_max );
988 return rc;
989 }
990
ReadBoundingBox(ON_BoundingBox & bbox)991 bool ON_BinaryArchive::ReadBoundingBox(ON_BoundingBox& bbox)
992 {
993 bool rc = ReadPoint( bbox.m_min );
994 if (rc) rc = ReadPoint( bbox.m_max );
995 return rc;
996 }
997
998 bool
WriteXform(const ON_Xform & x)999 ON_BinaryArchive::WriteXform( const ON_Xform& x )
1000 {
1001 return WriteDouble( 16, &x.m_xform[0][0] );
1002 }
1003
1004 bool
ReadXform(ON_Xform & x)1005 ON_BinaryArchive::ReadXform( ON_Xform& x )
1006 {
1007 return ReadDouble( 16, &x.m_xform[0][0] );
1008 }
1009 bool
WritePlaneEquation(const ON_PlaneEquation & plane_equation)1010 ON_BinaryArchive::WritePlaneEquation( const ON_PlaneEquation& plane_equation )
1011 {
1012 bool rc = WriteDouble( 4, &plane_equation.x );
1013 return rc;
1014 }
1015
1016 bool
ReadPlaneEquation(ON_PlaneEquation & plane_equation)1017 ON_BinaryArchive::ReadPlaneEquation( ON_PlaneEquation& plane_equation )
1018 {
1019 bool rc = ReadDouble( 4, &plane_equation.x );
1020 return rc;
1021 }
1022
1023 bool
WritePlane(const ON_Plane & plane)1024 ON_BinaryArchive::WritePlane( const ON_Plane& plane )
1025 {
1026 bool rc = WritePoint( plane.origin );
1027 if (rc) rc = WriteVector( plane.xaxis );
1028 if (rc) rc = WriteVector( plane.yaxis );
1029 if (rc) rc = WriteVector( plane.zaxis );
1030 if (rc) rc = WriteDouble( 4, &plane.plane_equation.x );
1031 return rc;
1032 }
1033
1034 bool
ReadPlane(ON_Plane & plane)1035 ON_BinaryArchive::ReadPlane( ON_Plane& plane )
1036 {
1037 bool rc = ReadPoint( plane.origin );
1038 if (rc) rc = ReadVector( plane.xaxis );
1039 if (rc) rc = ReadVector( plane.yaxis );
1040 if (rc) rc = ReadVector( plane.zaxis );
1041 if (rc) rc = ReadDouble( 4, &plane.plane_equation.x );
1042 return rc;
1043 }
1044
1045 bool
WriteLine(const ON_Line & line)1046 ON_BinaryArchive::WriteLine( const ON_Line& line )
1047 {
1048 bool rc = WritePoint( line.from );
1049 if (rc) rc = WritePoint( line.to );
1050 return rc;
1051 }
1052
1053 bool
ReadLine(ON_Line & line)1054 ON_BinaryArchive::ReadLine( ON_Line& line )
1055 {
1056 bool rc = ReadPoint( line.from );
1057 if (rc) rc = ReadPoint( line.to );
1058 return rc;
1059 }
1060
1061 bool
WriteArc(const ON_Arc & arc)1062 ON_BinaryArchive::WriteArc(const ON_Arc& arc )
1063 {
1064 bool rc = WriteCircle(arc);
1065 if (rc)
1066 rc = WriteInterval(arc.m_angle);
1067 return rc;
1068 }
1069
1070 bool
ReadArc(ON_Arc & arc)1071 ON_BinaryArchive::ReadArc( ON_Arc& arc )
1072 {
1073 bool rc = ReadCircle(arc);
1074 if (rc)
1075 rc = ReadInterval(arc.m_angle);
1076 return rc;
1077 }
1078
1079 bool
WriteCircle(const ON_Circle & circle)1080 ON_BinaryArchive::WriteCircle(const ON_Circle& circle)
1081 {
1082 bool rc = WritePlane( circle.plane );
1083 if (rc)
1084 rc = WriteDouble( circle.radius );
1085 // m_point[] removed 2001, November, 7
1086 if (rc)
1087 rc = WritePoint( circle.PointAt(0.0) );
1088 if (rc)
1089 rc = WritePoint( circle.PointAt(0.5*ON_PI) );
1090 if (rc)
1091 rc = WritePoint( circle.PointAt(ON_PI) );
1092 /*
1093 if (rc)
1094 rc = WritePoint( circle.m_point[0] );
1095 if (rc)
1096 rc = WritePoint( circle.m_point[1] );
1097 if (rc)
1098 rc = WritePoint( circle.m_point[2] );
1099 */
1100 return rc;
1101 }
1102
1103 bool
ReadCircle(ON_Circle & circle)1104 ON_BinaryArchive::ReadCircle(ON_Circle& circle)
1105 {
1106 ON_3dPoint scratch;
1107 bool rc = ReadPlane( circle.plane );
1108 if (rc)
1109 rc = ReadDouble( &circle.radius );
1110 // m_point[] removed 2001, November, 7
1111 if (rc)
1112 rc = ReadPoint( scratch );
1113 if (rc)
1114 rc = ReadPoint( scratch );
1115 if (rc)
1116 rc = ReadPoint( scratch );
1117 /*
1118 if (rc)
1119 rc = ReadPoint( circle.m_point[0] );
1120 if (rc)
1121 rc = ReadPoint( circle.m_point[1] );
1122 if (rc)
1123 rc = ReadPoint( circle.m_point[2] );
1124 */
1125 return rc;
1126 }
1127
1128
1129 bool
WriteInterval(const ON_Interval & t)1130 ON_BinaryArchive::WriteInterval( const ON_Interval& t )
1131 {
1132 return WriteDouble( 2, t.m_t );
1133 }
1134
1135 bool
ReadInterval(ON_Interval & t)1136 ON_BinaryArchive::ReadInterval( ON_Interval& t )
1137 {
1138 return ReadDouble( 2, t.m_t );
1139 }
1140
1141 bool
ReadUuid(ON_UUID & uuid)1142 ON_BinaryArchive::ReadUuid( ON_UUID& uuid )
1143 {
1144 bool rc = ReadInt32( 1, (ON__INT32*)(&uuid.Data1) );
1145 if (rc) rc = ReadInt16( 1, (ON__INT16*)(&uuid.Data2) );
1146 if (rc) rc = ReadInt16( 1, (ON__INT16*)(&uuid.Data3) );
1147 if (rc) rc = ReadByte( 8, uuid.Data4 );
1148 return rc;
1149 }
1150
ReadDisplayMaterialRef(ON_DisplayMaterialRef & dmr)1151 bool ON_BinaryArchive::ReadDisplayMaterialRef( ON_DisplayMaterialRef& dmr )
1152 {
1153 bool rc = ReadUuid( dmr.m_viewport_id );
1154 if (rc)
1155 rc = ReadUuid( dmr.m_display_material_id );
1156 return rc;
1157 }
1158
1159 bool
ReadTime(struct tm & utc)1160 ON_BinaryArchive::ReadTime( struct tm& utc )
1161 {
1162 // utc = coordinated universal time ( a.k.a GMT, UTC )
1163 // (From ANSI C time() and gmtime().)
1164 bool rc = ReadInt( &utc.tm_sec );
1165 if ( rc )
1166 rc = ReadInt( &utc.tm_min );
1167 if ( rc )
1168 rc = ReadInt( &utc.tm_hour );
1169 if ( rc )
1170 rc = ReadInt( &utc.tm_mday );
1171 if ( rc )
1172 rc = ReadInt( &utc.tm_mon );
1173 if ( rc )
1174 rc = ReadInt( &utc.tm_year );
1175 if ( rc )
1176 rc = ReadInt( &utc.tm_wday );
1177 if ( rc )
1178 rc = ReadInt( &utc.tm_yday );
1179 if ( rc ) {
1180 if ( utc.tm_sec < 0 || utc.tm_sec > 60 )
1181 rc = false;
1182 if ( utc.tm_min < 0 || utc.tm_min > 60 )
1183 rc = false;
1184 if ( utc.tm_hour < 0 || utc.tm_hour > 24 )
1185 rc = false;
1186 if ( utc.tm_mday < 0 || utc.tm_mday > 31 )
1187 rc = false;
1188 if ( utc.tm_mon < 0 || utc.tm_mon > 12 )
1189 rc = false;
1190 // no year restrictions because dates are used in archeological userdata
1191 if ( utc.tm_wday < 0 || utc.tm_wday > 7 )
1192 rc = false;
1193 if ( utc.tm_yday < 0 || utc.tm_yday > 366 )
1194 rc = false;
1195 if ( !rc ) {
1196 ON_ERROR("ON_BinaryArchive::ReadTime() - bad time in archive");
1197 }
1198 }
1199 return rc;
1200 }
1201
1202 bool
ReadStringSize(size_t * sizeof_string)1203 ON_BinaryArchive::ReadStringSize( // Read size of NULL terminated string
1204 size_t* sizeof_string // (returned size includes NULL terminator)
1205 )
1206 {
1207 ON__UINT32 ui32 = 0;
1208 bool rc = ReadInt32(1,(ON__INT32*)&ui32);
1209 // Note that ui32 = number of elements in the string array, including
1210 // the null terminator. So ui32 should either be 0 or be >= 2.
1211 // The string array elements can be chars or unsigned shorts;
1212 // therefore the number of bytes in the string cannot be determined
1213 // at this point because we don't know what type of string is
1214 // being read.
1215 if (rc)
1216 {
1217 // 8 October 2004 Dale Lear
1218 // Added the sanity checks on string size to avoid attempts
1219 // to allocate huge amounts of memory when the value
1220 // comes from a damaged file.
1221 if ( 0 != (0xF000000 & ui32) )
1222 {
1223 // 268 million chars oughta be plenty
1224 ON_ERROR("string element count is impossibly large");
1225 rc = false;
1226 }
1227 else if ( ui32 > 0 )
1228 {
1229 // make sure this is possible
1230 const ON_3DM_BIG_CHUNK* curchunk = m_chunk.Last();
1231 if ( 0 != curchunk && 0 == (TCODE_SHORT & curchunk->m_typecode) )
1232 {
1233 if ( curchunk->m_big_value < 0
1234 || ((ON__INT64)ui32) > curchunk->m_big_value
1235 )
1236 {
1237 ON_ERROR("string element count exceeds current chunk size");
1238 rc = false;
1239 }
1240 }
1241 }
1242
1243 if (rc)
1244 {
1245 *sizeof_string = (size_t)ui32;
1246 }
1247 }
1248 return rc;
1249 }
1250
1251
1252 bool
ReadStringUTF8ElementCount(size_t * string_utf8_element_count)1253 ON_BinaryArchive::ReadStringUTF8ElementCount(
1254 size_t* string_utf8_element_count
1255 )
1256 {
1257 ON__UINT32 ui32 = 0;
1258 bool rc = ReadInt32(1,(ON__INT32*)&ui32);
1259 // Note that ui32 = number of elements in the string array, including
1260 // the null terminator. So ui32 should either be 0 or be >= 2.
1261 // The string array elements can be chars or unsigned shorts;
1262 // therefore the number of bytes in the string cannot be determined
1263 // at this point because we don't know what type of string is
1264 // being read.
1265 if (rc)
1266 {
1267 // 8 October 2004 Dale Lear
1268 // Added the sanity checks on string size to avoid attempts
1269 // to allocate huge amounts of memory when the value
1270 // comes from a damaged file.
1271 if ( 0 != (0xF000000 & ui32) )
1272 {
1273 // 268 million chars oughta be plenty
1274 ON_ERROR("string element count is impossibly large");
1275 rc = false;
1276 }
1277 else if ( ui32 > 0 )
1278 {
1279 // make sure this is possible
1280 const ON_3DM_BIG_CHUNK* curchunk = m_chunk.Last();
1281 if ( 0 != curchunk && 0 == (TCODE_SHORT & curchunk->m_typecode) )
1282 {
1283 if ( curchunk->m_big_value < 0
1284 || ((ON__INT64)ui32) > curchunk->m_big_value
1285 )
1286 {
1287 ON_ERROR("string byte count exceeds current chunk size");
1288 rc = false;
1289 }
1290 }
1291 }
1292 }
1293 if (!rc)
1294 ui32 = 0;
1295 if ( string_utf8_element_count )
1296 *string_utf8_element_count = (size_t)ui32;
1297 return rc;
1298 }
1299
1300
1301 bool
ReadStringUTF16ElementCount(size_t * string_utf16_element_count)1302 ON_BinaryArchive::ReadStringUTF16ElementCount(
1303 size_t* string_utf16_element_count
1304 )
1305 {
1306 ON__UINT32 ui32 = 0;
1307 bool rc = ReadInt32(1,(ON__INT32*)&ui32);
1308 // Note that ui32 = number of elements in the string array, including
1309 // the null terminator. So ui32 should either be 0 or be >= 2.
1310 // The string array elements can be chars or unsigned shorts;
1311 // therefore the number of bytes in the string cannot be determined
1312 // at this point because we don't know what type of string is
1313 // being read.
1314 if (rc)
1315 {
1316 if ( 0 != (0xF000000 & ui32) )
1317 {
1318 // 268 million chars oughta be plenty
1319 ON_ERROR("string element count is impossibly large");
1320 rc = false;
1321 }
1322 else if ( ui32 > 0 )
1323 {
1324 // make sure this is possible
1325 const ON_3DM_BIG_CHUNK* curchunk = m_chunk.Last();
1326 if ( 0 != curchunk && 0 == (TCODE_SHORT & curchunk->m_typecode) )
1327 {
1328 // 2*ui32 is used because opennurbs writes all wide character
1329 // strings as UTF-16 encoded strings.
1330 if ( curchunk->m_big_value < 0
1331 || ((ON__INT64)2*ui32) > curchunk->m_big_value
1332 )
1333 {
1334 ON_ERROR("string byte count exceeds current chunk size");
1335 rc = false;
1336 }
1337 }
1338 }
1339 }
1340
1341 if (!rc)
1342 ui32 = 0;
1343 if ( string_utf16_element_count )
1344 *string_utf16_element_count = (size_t)ui32;
1345 return rc;
1346 }
1347
1348 bool
ReadString(size_t string_utf8_element_count,char * p)1349 ON_BinaryArchive::ReadString( // Read NULL terminated string
1350 size_t string_utf8_element_count, // = value from ReadStringUTF8ElementCount()
1351 char* p // array[string_utf8_element_count]
1352 )
1353 {
1354 return ReadByte( string_utf8_element_count, p );
1355 }
1356
1357 bool
ReadString(size_t string_utf8_element_count,unsigned char * p)1358 ON_BinaryArchive::ReadString( // Read NULL terminated string
1359 size_t string_utf8_element_count, // = value from ReadStringUTF8ElementCount()
1360 unsigned char* p // array[string_utf8_element_count]
1361 )
1362 {
1363 return ReadByte( string_utf8_element_count, p );
1364 }
1365
1366 bool
ReadString(size_t string_utf16_element_count,unsigned short * p)1367 ON_BinaryArchive::ReadString( // Read NULL terminated unicode string
1368 size_t string_utf16_element_count, // length = value ReadStringUTF16ElementCount ReadStringSize()
1369 unsigned short* p // array[string_utf16_element_count]
1370 )
1371 {
1372 return ReadShort( string_utf16_element_count, p );
1373 }
1374
1375 bool
ReadString(ON_String & s)1376 ON_BinaryArchive::ReadString( ON_String& s )
1377 {
1378 s.Destroy();
1379 size_t string_utf8_element_count = 0;
1380 bool rc = ReadStringUTF8ElementCount( &string_utf8_element_count );
1381 if ( rc && string_utf8_element_count > 0 )
1382 {
1383 const int istring_utf8_element_count = (int)string_utf8_element_count; // (int) converts 64 bits size_t
1384 s.ReserveArray(istring_utf8_element_count);
1385 ReadString( string_utf8_element_count, s.Array() );
1386 s.SetLength( istring_utf8_element_count-1 );
1387 }
1388 return rc;
1389 }
1390
1391 bool
ReadString(ON_wString & s)1392 ON_BinaryArchive::ReadString( ON_wString& s )
1393 {
1394 #if defined(ON_COMPILER_MSC)
1395 #pragma warning( push )
1396 // Disable the MSC /W4 "conditional expression is constant" warning
1397 // about 2 == sizeof(wchar_t). Since this code has to run on machines
1398 // where sizeof(wchar_t) can be 2, 4, or 8 bytes, the test is necessary.
1399 #pragma warning( disable : 4127 )
1400 #endif
1401
1402 s.Destroy();
1403 size_t string_utf16_element_count = 0;
1404 bool rc = ReadStringUTF16ElementCount( &string_utf16_element_count );
1405 if ( rc && string_utf16_element_count > 0 )
1406 {
1407 // string_utf16_element_count = number of ON__INT16 elements in
1408 // the string. This is almost always the same as the
1409 // number of unicode code points. However, if one of
1410 // the code points happens to require two ON__INT16
1411 // values to encode, then string_utf16_element_count will be
1412 // larger than the number of unicode code points in
1413 // the array.
1414 const int istring_utf16_element_count = (int)string_utf16_element_count;
1415 if ( 2 == sizeof(wchar_t) )
1416 {
1417 // When sizeof(wchar_t) is 2 bytes, assume wchar_t strings are
1418 // UTF-16 encoded unicode strings.
1419 s.ReserveArray( istring_utf16_element_count );
1420 rc = ReadInt16( string_utf16_element_count, (ON__INT16*)s.Array() );
1421 if (rc)
1422 s.SetLength( istring_utf16_element_count-1 );
1423 }
1424 else if ( 4 == sizeof(wchar_t) )
1425 {
1426 // When sizeof(wchar_t) is 4 bytes, assume wchar_t strings are
1427 // UTF-32 encoded unicode strings. (some gcc implementations do this.)
1428
1429 // Read the UTF-16 encode string from the file into
1430 // utf16_buffer[].
1431 const int istring_utf16_element_count = (int)string_utf16_element_count;
1432 ON_SimpleArray<ON__UINT16> utf16_buffer(istring_utf16_element_count);
1433 rc = ReadInt16(string_utf16_element_count,(ON__INT16*)utf16_buffer.Array());
1434 if(rc)
1435 {
1436 // convert to a UTF-32 encoded unicode string.
1437 utf16_buffer.SetCount(istring_utf16_element_count);
1438 utf16_buffer[istring_utf16_element_count-1] = 0;
1439 rc = false;
1440 const ON__UINT16* sUTF16 = utf16_buffer.Array();
1441 const int bTestByteOrder = false;
1442 const int sUTF16_count = istring_utf16_element_count-1;
1443 const ON__UINT32 error_code_point = 0xFFFD;
1444 const unsigned int error_mask = 0xFFFFFFFF;
1445 unsigned int error_status = 0;
1446
1447 const int utf32_array_count = ON_ConvertUTF16ToUTF32(
1448 bTestByteOrder,
1449 sUTF16,
1450 sUTF16_count,
1451 0, // unsigned int* sUTF32
1452 0, // int sUTF32_count
1453 &error_status,
1454 error_mask,
1455 error_code_point,
1456 0 // const ON__UINT16** sNextUTF16
1457 );
1458
1459 if ( 0 == utf32_array_count )
1460 {
1461 rc = true;
1462 }
1463 else if ( utf32_array_count > 0 )
1464 {
1465 error_status = 0;
1466 s.ReserveArray(utf32_array_count+1);
1467 const int utf32_array_count1 = ON_ConvertUTF16ToUTF32(
1468 bTestByteOrder,
1469 sUTF16,
1470 sUTF16_count,
1471 (unsigned int*)s.Array(), // unsigned int* sUTF32
1472 utf32_array_count, // sUTF32_count
1473 &error_status,
1474 error_mask,
1475 error_code_point,
1476 0 // const ON__UINT16** sNextUTF16
1477 );
1478 if ( utf32_array_count1 == utf32_array_count )
1479 {
1480 s.SetLength( utf32_array_count );
1481 rc = true;
1482 }
1483 }
1484 }
1485 }
1486 // G+Smo
1487 //if (!rc)
1488 s.Destroy();
1489 }
1490 return rc;
1491
1492 #if defined(ON_COMPILER_MSC)
1493 #pragma warning( pop )
1494 #endif
1495 }
1496
1497
WriteArray(const ON_SimpleArray<ON_MappingChannel> & a)1498 bool ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_MappingChannel>& a)
1499 {
1500 int i, count = a.Count();
1501 if ( count < 0 )
1502 count = 0;
1503 bool rc = WriteInt( count );
1504 for ( i = 0; i < count && rc; i++ )
1505 {
1506 // ON_MappingChannel::Write() puts the element in a chunk
1507 rc = a[i].Write(*this);
1508 }
1509 return rc;
1510 }
1511
WriteArray(const ON_ClassArray<ON_MaterialRef> & a)1512 bool ON_BinaryArchive::WriteArray( const ON_ClassArray<ON_MaterialRef>& a)
1513 {
1514 int i, count = a.Count();
1515 if ( count < 0 )
1516 count = 0;
1517 bool rc = WriteInt( count );
1518 for ( i = 0; i < count && rc; i++ )
1519 {
1520 // ON_MaterialRef::Write() puts the element in a chunk
1521 rc = a[i].Write(*this);
1522 }
1523 return rc;
1524 }
1525
1526
WriteArray(int count,const ON_Layer * a)1527 bool ON_BinaryArchive::WriteArray( int count, const ON_Layer* a)
1528 {
1529 int i;
1530 if ( count < 0 || 0 == a )
1531 count = 0;
1532 bool rc = WriteInt( count );
1533 for ( i = 0; i < count && rc; i++ )
1534 {
1535 rc = WriteObject(a[i]);
1536 }
1537 return rc;
1538 }
1539
WriteArray(int count,const ON_Layer * const * a)1540 bool ON_BinaryArchive::WriteArray( int count, const ON_Layer*const* a)
1541 {
1542 int i;
1543 if ( count < 0 || 0 == a )
1544 count = 0;
1545 bool rc = WriteInt( count );
1546 for ( i = 0; i < count && rc; i++ )
1547 {
1548 rc = WriteObject(a[i]);
1549 }
1550 return rc;
1551 }
1552
WriteArray(const ON_ClassArray<ON_MappingRef> & a)1553 bool ON_BinaryArchive::WriteArray( const ON_ClassArray<ON_MappingRef>& a )
1554 {
1555 int i, count = a.Count();
1556 if ( count < 0 )
1557 count = 0;
1558 bool rc = WriteInt( count );
1559 for ( i = 0; i < count && rc; i++ )
1560 {
1561 // ON_MappingRef::Write() puts the element in a chunk
1562 rc = a[i].Write(*this);
1563 }
1564 return rc;
1565 }
1566
1567
WriteArray(const ON_ClassArray<ON_ObjRef> & a)1568 bool ON_BinaryArchive::WriteArray( const ON_ClassArray<ON_ObjRef>& a)
1569 {
1570 int i, count = a.Count();
1571 if ( count < 0 )
1572 count = 0;
1573 bool rc = WriteInt( count );
1574 for ( i = 0; i < count && rc; i++ )
1575 {
1576 // ON_ObjRef::Write() puts the element in a chunk
1577 rc = a[i].Write(*this);
1578 }
1579 return rc;
1580 }
1581
WriteArray(const ON_SimpleArray<ON_ObjRef_IRefID> & a)1582 bool ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_ObjRef_IRefID>& a)
1583 {
1584 int i, count = a.Count();
1585 if ( count < 0 )
1586 count = 0;
1587 bool rc = WriteInt( count );
1588 for ( i = 0; i < count && rc; i++ )
1589 {
1590 // ON_ObjRef_IRefID::Write() puts the element in a chunk
1591 rc = a[i].Write(*this);
1592 }
1593 return rc;
1594 }
1595
ReadArray(ON_SimpleArray<ON_MappingChannel> & a)1596 bool ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_MappingChannel>& a )
1597 {
1598 a.Empty();
1599 int i, count;
1600 bool rc = ReadInt( &count );
1601 if (rc)
1602 {
1603 a.SetCapacity(count);
1604 for ( i = 0; i < count && rc; i++ )
1605 {
1606 rc = a.AppendNew().Read(*this);
1607 }
1608 }
1609 return rc;
1610 }
1611
ReadArray(ON_ClassArray<ON_MaterialRef> & a)1612 bool ON_BinaryArchive::ReadArray( ON_ClassArray<ON_MaterialRef>& a)
1613 {
1614 a.Empty();
1615 int i, count;
1616 bool rc = ReadInt( &count );
1617 if (rc)
1618 {
1619 a.SetCapacity(count);
1620 for ( i = 0; i < count && rc; i++ )
1621 {
1622 rc = a.AppendNew().Read(*this);
1623 }
1624 }
1625 return rc;
1626 }
1627
ReadArray(ON_ObjectArray<class ON_Layer> & a)1628 bool ON_BinaryArchive::ReadArray( ON_ObjectArray<class ON_Layer>& a)
1629 {
1630 a.Empty();
1631 int i, count;
1632 bool rc = ReadInt( &count );
1633 if (rc)
1634 {
1635 a.SetCapacity(count);
1636 for ( i = 0; i < count && rc; i++ )
1637 {
1638 rc = (1 == ReadObject(a.AppendNew()));
1639 if (!rc)
1640 {
1641 a.Remove();
1642 break;
1643 }
1644 }
1645 }
1646 return rc;
1647 }
1648
1649
ReadArray(ON_SimpleArray<class ON_Layer * > & a)1650 bool ON_BinaryArchive::ReadArray( ON_SimpleArray<class ON_Layer*>& a)
1651 {
1652 a.Empty();
1653 ON_Layer* layer;
1654 int i, count;
1655 bool rc = ReadInt( &count );
1656 if (rc)
1657 {
1658 a.SetCapacity(count);
1659 for ( i = 0; i < count && rc; i++ )
1660 {
1661 layer = 0;
1662 ON_Object* p = 0;
1663 rc = (1==ReadObject(&p));
1664 if (rc)
1665 {
1666 layer = ON_Layer::Cast(p);
1667 }
1668 if (!rc || 0 == layer)
1669 {
1670 if ( p )
1671 delete p;
1672 rc = false;
1673 break;
1674 }
1675 a.Append(layer);
1676 }
1677 }
1678 return rc;
1679 }
1680
ReadArray(ON_ClassArray<ON_MappingRef> & a)1681 bool ON_BinaryArchive::ReadArray( ON_ClassArray<ON_MappingRef>& a)
1682 {
1683 a.Empty();
1684 int i, count;
1685 bool rc = ReadInt( &count );
1686 if (rc)
1687 {
1688 a.SetCapacity(count);
1689 for ( i = 0; i < count && rc; i++ )
1690 {
1691 rc = a.AppendNew().Read(*this);
1692 }
1693 }
1694 return rc;
1695 }
1696
ReadArray(ON_ClassArray<ON_ObjRef> & a)1697 bool ON_BinaryArchive::ReadArray( ON_ClassArray<ON_ObjRef>& a)
1698 {
1699 a.Empty();
1700 int i, count;
1701 bool rc = ReadInt( &count );
1702 if (rc)
1703 {
1704 a.SetCapacity(count);
1705 for ( i = 0; i < count && rc; i++ )
1706 {
1707 rc = a.AppendNew().Read(*this);
1708 }
1709 }
1710 return rc;
1711 }
1712
ReadArray(ON_SimpleArray<ON_ObjRef_IRefID> & a)1713 bool ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_ObjRef_IRefID>& a)
1714 {
1715 a.Empty();
1716 int i, count;
1717 bool rc = ReadInt( &count );
1718 if (rc)
1719 {
1720 a.SetCapacity(count);
1721 for ( i = 0; i < count && rc; i++ )
1722 {
1723 rc = a.AppendNew().Read(*this);
1724 }
1725 }
1726 return rc;
1727 }
1728
1729
ReadArray(ON_SimpleArray<ON_DisplayMaterialRef> & a)1730 bool ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_DisplayMaterialRef>& a )
1731 {
1732 a.Empty();
1733 int count = 0;
1734 bool rc = ReadInt( &count );
1735 if ( rc && count > 0 )
1736 {
1737 a.SetCapacity( count );
1738 int i;
1739 for ( i = 0; i < count && rc; i++ )
1740 {
1741 rc = ReadDisplayMaterialRef(a.AppendNew());
1742 }
1743 }
1744 return rc;
1745 }
1746
1747 bool
ReadArray(ON_ClassArray<ON_String> & a)1748 ON_BinaryArchive::ReadArray( ON_ClassArray<ON_String>& a)
1749 {
1750 a.Empty();
1751 int count = 0;
1752 bool rc = ReadInt( &count );
1753 if ( rc && count > 0 )
1754 {
1755 a.SetCapacity( count );
1756 int i;
1757 for ( i = 0; i < count && rc; i++ )
1758 {
1759 rc = ReadString( a.AppendNew() );
1760 }
1761 }
1762 return rc;
1763 }
1764
1765 bool
ReadArray(ON_ClassArray<ON_wString> & a)1766 ON_BinaryArchive::ReadArray( ON_ClassArray<ON_wString>& a)
1767 {
1768 a.Empty();
1769 int count = 0;
1770 bool rc = ReadInt( &count );
1771 if ( rc && count > 0 )
1772 {
1773 a.SetCapacity( count );
1774 int i;
1775 for ( i = 0; i < count && rc; i++ )
1776 {
1777 rc = ReadString( a.AppendNew() );
1778 }
1779 }
1780 return rc;
1781 }
1782
1783 bool
WriteArray(const ON_SimpleArray<ON_DisplayMaterialRef> & a)1784 ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_DisplayMaterialRef>& a )
1785 {
1786 int i, count = a.Count();
1787 if ( count < 0 )
1788 count = 0;
1789 bool rc = WriteInt( count );
1790 for ( i = 0; i < count && rc; i++ )
1791 {
1792 rc = WriteDisplayMaterialRef( a[i] );
1793 }
1794 return rc;
1795 }
1796
1797 bool
WriteArray(const ON_ClassArray<ON_String> & a)1798 ON_BinaryArchive::WriteArray( const ON_ClassArray<ON_String>& a )
1799 {
1800 int i, count = a.Count();
1801 if ( count < 0 )
1802 count = 0;
1803 bool rc = WriteInt( count );
1804 for ( i = 0; i < count && rc; i++ )
1805 {
1806 rc = WriteString( a[i] );
1807 }
1808 return rc;
1809 }
1810
1811 bool
WriteArray(const ON_ClassArray<ON_wString> & a)1812 ON_BinaryArchive::WriteArray( const ON_ClassArray<ON_wString>& a )
1813 {
1814 int i, count = a.Count();
1815 if ( count < 0 )
1816 count = 0;
1817 bool rc = WriteInt( count );
1818 for ( i = 0; i < count && rc; i++ )
1819 {
1820 rc = WriteString( a[i] );
1821 }
1822 return rc;
1823 }
1824
1825 bool
ReadArray(ON_SimpleArray<bool> & a)1826 ON_BinaryArchive::ReadArray( ON_SimpleArray<bool>& a )
1827 {
1828 #if defined(ON_COMPILER_MSC)
1829 // Disable the MSC /W4 "conditional expression is constant" warning
1830 // about sizeof(*c) == sizeof(*b). Since this code has to run on machines
1831 // where sizeof(bool) can be 1, 2, 4, or 8 bytes, the test is necessary.
1832 #pragma warning( push )
1833 #pragma warning( disable : 4127 )
1834 #endif
1835
1836 a.Empty();
1837 int count = 0;
1838 bool rc = ReadInt( &count );
1839 if ( rc && count > 0 )
1840 {
1841 a.SetCapacity( count );
1842 char* c = 0;
1843 bool* b = a.Array();
1844 if ( sizeof(*c) == sizeof(*b) )
1845 {
1846 // 8 bit "bool" on this compiler
1847 c = (char*)b;
1848 }
1849 else if ( b )
1850 {
1851 // bigger "bool" on this compiler
1852 c = (char*)onmalloc(count*sizeof(*c));
1853 }
1854 rc = ReadChar( count, c );
1855 if ( rc )
1856 {
1857 if ( c == (char*)b )
1858 {
1859 a.SetCount(count);
1860 }
1861 else if ( c )
1862 {
1863 int i;
1864 for ( i = 0; i < count; i++ )
1865 {
1866 a.Append(c[i]?true:false);
1867 }
1868 onfree(c);
1869 }
1870 }
1871 }
1872 return rc;
1873
1874 #if defined(ON_COMPILER_MSC)
1875 #pragma warning( pop )
1876 #endif
1877
1878 }
1879
1880 bool
ReadArray(ON_SimpleArray<char> & a)1881 ON_BinaryArchive::ReadArray( ON_SimpleArray<char>& a )
1882 {
1883 a.Empty();
1884 int count = 0;
1885 bool rc = ReadInt( &count );
1886 if ( rc && count > 0 ) {
1887 a.SetCapacity( count );
1888 rc = ReadChar( count, a.Array() );
1889 if ( rc )
1890 a.SetCount(count);
1891 }
1892 return rc;
1893 }
1894
1895 bool
ReadArray(ON_SimpleArray<short> & a)1896 ON_BinaryArchive::ReadArray( ON_SimpleArray<short>& a )
1897 {
1898 a.Empty();
1899 int count = 0;
1900 bool rc = ReadInt( &count );
1901 if ( rc && count > 0 ) {
1902 a.SetCapacity( count );
1903 rc = ReadShort( count, a.Array() );
1904 if ( rc )
1905 a.SetCount(count);
1906 }
1907 return rc;
1908 }
1909
1910 bool
ReadArray(ON_SimpleArray<int> & a)1911 ON_BinaryArchive::ReadArray( ON_SimpleArray<int>& a )
1912 {
1913 a.Empty();
1914 int count = 0;
1915 bool rc = ReadInt( &count );
1916 if ( rc && count > 0 ) {
1917 a.SetCapacity( count );
1918 rc = ReadInt( count, a.Array() );
1919 if ( rc )
1920 a.SetCount(count);
1921 }
1922 return rc;
1923 }
1924
1925 bool
ReadArray(ON_SimpleArray<float> & a)1926 ON_BinaryArchive::ReadArray( ON_SimpleArray<float>& a )
1927 {
1928 a.Empty();
1929 int count = 0;
1930 bool rc = ReadInt( &count );
1931 if ( rc && count > 0 ) {
1932 a.SetCapacity( count );
1933 rc = ReadFloat( count, a.Array() );
1934 if ( rc )
1935 a.SetCount(count);
1936 }
1937 return rc;
1938 }
1939
1940 bool
ReadArray(ON_SimpleArray<double> & a)1941 ON_BinaryArchive::ReadArray( ON_SimpleArray<double>& a )
1942 {
1943 a.Empty();
1944 int count = 0;
1945 bool rc = ReadInt( &count );
1946 if ( rc && count > 0 ) {
1947 a.SetCapacity( count );
1948 rc = ReadDouble( count, a.Array() );
1949 if ( rc )
1950 a.SetCount(count);
1951 }
1952 return rc;
1953 }
1954
1955 bool
ReadArray(ON_SimpleArray<ON_Color> & a)1956 ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_Color>& a )
1957 {
1958 a.Empty();
1959 int count = 0;
1960 bool rc = ReadInt( &count );
1961 if ( rc && count > 0 ) {
1962 a.SetCapacity( count );
1963 rc = ReadInt( count, (int*)a.Array() );
1964 if ( rc )
1965 a.SetCount(count);
1966 }
1967 return rc;
1968 }
1969
1970
1971 bool
ReadArray(ON_SimpleArray<ON_2dPoint> & a)1972 ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_2dPoint>& a )
1973 {
1974 a.Empty();
1975 int count = 0;
1976 bool rc = ReadInt( &count );
1977 if ( rc && count > 0 ) {
1978 a.SetCapacity( count );
1979 rc = ReadDouble( 2*count, &a.Array()->x );
1980 if ( rc )
1981 a.SetCount(count);
1982 }
1983 return rc;
1984 }
1985
1986 bool
ReadArray(ON_SimpleArray<ON_3dPoint> & a)1987 ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_3dPoint>& a )
1988 {
1989 a.Empty();
1990 int count = 0;
1991 bool rc = ReadInt( &count );
1992 if ( rc && count > 0 ) {
1993 a.SetCapacity( count );
1994 rc = ReadDouble( 3*count, &a.Array()->x );
1995 if ( rc )
1996 a.SetCount(count);
1997 }
1998 return rc;
1999 }
2000
2001 bool
ReadArray(ON_SimpleArray<ON_4dPoint> & a)2002 ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_4dPoint>& a )
2003 {
2004 a.Empty();
2005 int count = 0;
2006 bool rc = ReadInt( &count );
2007 if ( rc && count > 0 ) {
2008 a.SetCapacity( count );
2009 rc = ReadDouble( 4*count, &a.Array()->x );
2010 if ( rc )
2011 a.SetCount(count);
2012 }
2013 return rc;
2014 }
2015
2016 bool
ReadArray(ON_SimpleArray<ON_2dVector> & a)2017 ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_2dVector>& a )
2018 {
2019 a.Empty();
2020 int count = 0;
2021 bool rc = ReadInt( &count );
2022 if ( rc && count > 0 ) {
2023 a.SetCapacity( count );
2024 rc = ReadDouble( 2*count, &a.Array()->x );
2025 if ( rc )
2026 a.SetCount(count);
2027 }
2028 return rc;
2029 }
2030
2031 bool
ReadArray(ON_SimpleArray<ON_3dVector> & a)2032 ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_3dVector>& a )
2033 {
2034 a.Empty();
2035 int count = 0;
2036 bool rc = ReadInt( &count );
2037 if ( rc && count > 0 ) {
2038 a.SetCapacity( count );
2039 rc = ReadDouble( 3*count, &a.Array()->x );
2040 if ( rc )
2041 a.SetCount(count);
2042 }
2043 return rc;
2044 }
2045
2046 bool
ReadArray(ON_SimpleArray<ON_Xform> & a)2047 ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_Xform>& a )
2048 {
2049 a.Empty();
2050 int count = 0;
2051 bool rc = ReadInt( &count );
2052 if ( rc && count > 0 )
2053 {
2054 a.SetCapacity( count );
2055 int i;
2056 for ( i = 0; i < count && rc; i++ )
2057 {
2058 rc = ReadXform(a.AppendNew());
2059 }
2060 }
2061 return rc;
2062 }
2063
2064 bool
ReadArray(ON_SimpleArray<ON_2fPoint> & a)2065 ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_2fPoint>& a )
2066 {
2067 a.Empty();
2068 int count = 0;
2069 bool rc = ReadInt( &count );
2070 if ( rc && count > 0 ) {
2071 a.SetCapacity( count );
2072 rc = ReadFloat( 2*count, &a.Array()->x );
2073 if ( rc )
2074 a.SetCount(count);
2075 }
2076 return rc;
2077 }
2078
2079 bool
ReadArray(ON_SimpleArray<ON_3fPoint> & a)2080 ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_3fPoint>& a )
2081 {
2082 a.Empty();
2083 int count = 0;
2084 bool rc = ReadInt( &count );
2085 if ( rc && count > 0 ) {
2086 a.SetCapacity( count );
2087 rc = ReadFloat( 3*count, &a.Array()->x );
2088 if ( rc )
2089 a.SetCount(count);
2090 }
2091 return rc;
2092 }
2093
2094 bool
ReadArray(ON_SimpleArray<ON_4fPoint> & a)2095 ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_4fPoint>& a )
2096 {
2097 a.Empty();
2098 int count = 0;
2099 bool rc = ReadInt( &count );
2100 if ( rc && count > 0 ) {
2101 a.SetCapacity( count );
2102 rc = ReadFloat( 4*count, &a.Array()->x );
2103 if ( rc )
2104 a.SetCount(count);
2105 }
2106 return rc;
2107 }
2108
2109 bool
ReadArray(ON_SimpleArray<ON_2fVector> & a)2110 ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_2fVector>& a )
2111 {
2112 a.Empty();
2113 int count = 0;
2114 bool rc = ReadInt( &count );
2115 if ( rc && count > 0 ) {
2116 a.SetCapacity( count );
2117 rc = ReadFloat( 2*count, &a.Array()->x );
2118 if ( rc )
2119 a.SetCount(count);
2120 }
2121 return rc;
2122 }
2123
2124 bool
ReadArray(ON_SimpleArray<ON_3fVector> & a)2125 ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_3fVector>& a )
2126 {
2127 a.Empty();
2128 int count = 0;
2129 bool rc = ReadInt( &count );
2130 if ( rc && count > 0 ) {
2131 a.SetCapacity( count );
2132 rc = ReadFloat( 3*count, &a.Array()->x );
2133 if ( rc )
2134 a.SetCount(count);
2135 }
2136 return rc;
2137 }
2138
2139 bool
ReadArray(ON_SimpleArray<ON_UUID> & a)2140 ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_UUID>& a )
2141 {
2142 a.Empty();
2143 ON_UUID uuid;
2144 int i, count = 0;
2145 bool rc = ReadInt( &count );
2146 if ( rc && count > 0 )
2147 {
2148 a.SetCapacity( count );
2149 for ( i = 0; i < count && rc; i++ )
2150 {
2151 rc = ReadUuid( uuid );
2152 if ( rc )
2153 a.Append(uuid);
2154 }
2155 }
2156 return rc;
2157 }
2158
2159
2160
2161
2162 bool
ReadArray(ON_SimpleArray<ON_UuidIndex> & a)2163 ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_UuidIndex>& a )
2164 {
2165 a.Empty();
2166 ON_UuidIndex idi;
2167 int i, count = 0;
2168 bool rc = ReadInt( &count );
2169 if ( rc && count > 0 )
2170 {
2171 a.SetCapacity( count );
2172 for ( i = 0; i < count && rc; i++ )
2173 {
2174 rc = ReadUuid( idi.m_id );
2175 if ( rc )
2176 {
2177 rc = ReadInt(&idi.m_i);
2178 if(rc)
2179 a.Append(idi);
2180 }
2181 }
2182 }
2183 return rc;
2184 }
2185
2186
2187 bool
WriteArray(const ON_SimpleArray<ON_UUID> & a)2188 ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_UUID>& a )
2189 {
2190 int i, count = a.Count();
2191 if ( count < 0 )
2192 count = 0;
2193 bool rc = WriteInt( count );
2194 for ( i = 0; i < count && rc; i++ )
2195 {
2196 rc = WriteUuid( a[i] );
2197 }
2198 return rc;
2199 }
2200
2201
2202 bool
WriteArray(const ON_SimpleArray<ON_UuidIndex> & a)2203 ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_UuidIndex>& a )
2204 {
2205 int i, count = a.Count();
2206 if ( count < 0 )
2207 count = 0;
2208 bool rc = WriteInt( count );
2209 for ( i = 0; i < count && rc; i++ )
2210 {
2211 rc = WriteUuid( a[i].m_id );
2212 if (rc)
2213 rc = WriteInt( a[i].m_i );
2214 }
2215 return rc;
2216 }
2217
2218
2219 bool
ReadArray(ON_SimpleArray<ON_LinetypeSegment> & a)2220 ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_LinetypeSegment>& a )
2221 {
2222 a.Empty();
2223 ON_LinetypeSegment seg;
2224 int i, count = 0;
2225 bool rc = ReadInt( &count );
2226 if ( rc && count > 0 )
2227 {
2228 a.SetCapacity( count );
2229 for ( i = 0; i < count && rc; i++ )
2230 {
2231 rc = ReadLinetypeSegment( seg );
2232 if ( rc )
2233 a.Append(seg);
2234 }
2235 }
2236 return rc;
2237 }
2238
2239 bool
WriteArray(const ON_SimpleArray<ON_LinetypeSegment> & a)2240 ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_LinetypeSegment>& a )
2241 {
2242 int i, count = a.Count();
2243 if ( count < 0 )
2244 count = 0;
2245 bool rc = WriteInt( count );
2246 for ( i = 0; i < count && rc; i++ )
2247 {
2248 rc = WriteLinetypeSegment( a[i] );
2249 }
2250 return rc;
2251 }
2252
ReadLinetypeSegment(ON_LinetypeSegment & seg)2253 bool ON_BinaryArchive::ReadLinetypeSegment(ON_LinetypeSegment& seg)
2254 {
2255 seg.m_length = 1.0;
2256 seg.m_seg_type = ON_LinetypeSegment::stLine;
2257 unsigned int i;
2258 bool rc = ReadDouble(&seg.m_length);
2259 if (rc)
2260 {
2261 rc = ReadInt(&i);
2262 if( ON_LinetypeSegment::stLine == i )
2263 seg.m_seg_type = ON_LinetypeSegment::stLine;
2264 else if ( ON_LinetypeSegment::stSpace == i )
2265 seg.m_seg_type = ON_LinetypeSegment::stSpace;
2266 }
2267 return rc;
2268 }
2269
2270
WriteLinetypeSegment(const ON_LinetypeSegment & seg)2271 bool ON_BinaryArchive::WriteLinetypeSegment( const ON_LinetypeSegment& seg)
2272 {
2273 // do not add chunk info here
2274 unsigned int i = seg.m_seg_type;
2275 bool rc = WriteDouble(seg.m_length);
2276 if (rc)
2277 rc = WriteInt(i);
2278 return rc;
2279 }
2280
2281
2282 bool
ReadArray(ON_SimpleArray<ON_SurfaceCurvature> & a)2283 ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_SurfaceCurvature>& a )
2284 {
2285 a.Empty();
2286 int count = 0;
2287 bool rc = ReadInt( &count );
2288 if ( rc && count > 0 ) {
2289 a.SetCapacity( count );
2290 rc = ReadDouble( 2*count, &a.Array()->k1 );
2291 if ( rc )
2292 a.SetCount(count);
2293 }
2294 return rc;
2295 }
2296
2297
2298 bool
ReadArray(ON_SimpleArray<ON_ClippingPlaneInfo> & a)2299 ON_BinaryArchive::ReadArray( ON_SimpleArray<ON_ClippingPlaneInfo>& a )
2300 {
2301 a.Empty();
2302 int count = 0;
2303 bool rc = ReadInt( &count );
2304 if ( rc && count > 0 )
2305 {
2306 a.SetCapacity(count);
2307 for ( int i = 0; i < count && rc ; i++ )
2308 {
2309 rc = a.AppendNew().Read(*this);
2310 if (!rc)
2311 a.Remove();
2312 }
2313 }
2314 return rc;
2315 }
2316
2317
WriteBool(bool b)2318 bool ON_BinaryArchive::WriteBool( bool b )
2319 {
2320 unsigned char c = (b?1:0);
2321 return WriteChar(c);
2322 }
2323
ReadBool(bool * b)2324 bool ON_BinaryArchive::ReadBool( bool *b )
2325 {
2326 unsigned char c;
2327 bool rc = ReadChar(&c);
2328 if (rc && b)
2329 {
2330 if ( c != 0 && c != 1 )
2331 {
2332 // WriteBool always writes a 0 or 1. So either your code
2333 // has a bug, the file is corrupt, the the file pointer
2334 // is where it should be.
2335 ON_ERROR("ON_BinaryArchive::ReadBool - bool value != 0 and != 1");
2336 rc = false;
2337 }
2338 *b = c?true:false;
2339 }
2340 return rc;
2341 }
2342
2343 bool
WriteChar(size_t count,const char * p)2344 ON_BinaryArchive::WriteChar( // Write an array of 8 bit chars
2345 size_t count, // number of chars to write
2346 const char* p
2347 )
2348 {
2349 return WriteByte( count, p );
2350 }
2351
2352 bool
WriteChar(size_t count,const unsigned char * p)2353 ON_BinaryArchive::WriteChar( // Write an array of 8 bit unsigned chars
2354 size_t count, // number of unsigned chars to write
2355 const unsigned char* p
2356 )
2357 {
2358 return WriteByte( count, p );
2359 }
2360
2361 bool
WriteChar(char c)2362 ON_BinaryArchive::WriteChar( // Write a single 8 bit char
2363 char c
2364 )
2365 {
2366 return WriteByte( 1, &c );
2367 }
2368
2369 bool
WriteChar(unsigned char c)2370 ON_BinaryArchive::WriteChar( // Write a single 8 bit unsigned char
2371 unsigned char c
2372 )
2373 {
2374 return WriteByte( 1, &c );
2375 }
2376
2377 bool
WriteInt16(size_t count,const ON__INT16 * p)2378 ON_BinaryArchive::WriteInt16( // Write an array of 16 bit shorts
2379 size_t count, // number of shorts to write
2380 const ON__INT16* p
2381 )
2382 {
2383 bool rc = true;
2384 if ( m_endian == ON::big_endian )
2385 {
2386 if ( count > 0 )
2387 {
2388 const char* b = (const char*)p;
2389 while ( rc && count-- )
2390 {
2391 rc = WriteByte( 1, b+1 );
2392 if (rc)
2393 rc = WriteByte( 1, b );
2394 b++;
2395 b++;
2396 }
2397 }
2398 }
2399 else
2400 {
2401 rc = WriteByte( count<<1, p );
2402 }
2403 return rc;
2404 }
2405
2406 bool
WriteShort(size_t count,const short * p)2407 ON_BinaryArchive::WriteShort( // Write an array of 16 bit shorts
2408 size_t count, // number of shorts to write
2409 const short* p
2410 )
2411 {
2412 #if defined(ON_COMPILER_MSC)
2413 #pragma warning( push )
2414 // Disable the MSC /W4 "conditional expression is constant" warning
2415 // about 2 == sizeof(*p). Since this code has to run on machines
2416 // where sizeof(*p) can be 2, 4, or 8 bytes, the test is necessary.
2417 #pragma warning( disable : 4127 )
2418 #endif
2419
2420 bool rc;
2421 if ( 2 == sizeof(*p) )
2422 {
2423 rc = WriteInt16( count, (const ON__INT16*)p );
2424 }
2425 else
2426 {
2427 rc = true;
2428 ON__INT16 i16;
2429 size_t j;
2430 for ( j = 0; j < count; j++ )
2431 {
2432 i16 = (ON__INT16)(*p++);
2433 rc = WriteInt16( 1, &i16);
2434 }
2435 }
2436 return rc;
2437
2438 #if defined(ON_COMPILER_MSC)
2439 #pragma warning( pop )
2440 #endif
2441 }
2442
2443 bool
WriteShort(size_t count,const unsigned short * p)2444 ON_BinaryArchive::WriteShort( // Write an array of 16 bit unsigned shorts
2445 size_t count, // number of shorts to write
2446 const unsigned short* p
2447 )
2448 {
2449 return WriteShort( count, (const short*)p );
2450 }
2451
2452 bool
WriteShort(short s)2453 ON_BinaryArchive::WriteShort( // Write a single 16 bit short
2454 short s
2455 )
2456 {
2457 return WriteShort( 1, &s );
2458 }
2459
2460 bool
WriteShort(unsigned short s)2461 ON_BinaryArchive::WriteShort( // Write a single 16 bit unsigned short
2462 unsigned short s
2463 )
2464 {
2465 return WriteShort( 1, &s );
2466 }
2467
2468 bool
WriteInt32(size_t count,const ON__INT32 * p)2469 ON_BinaryArchive::WriteInt32( // Write an array of 32 bit integers
2470 size_t count, // number of ints to write
2471 const ON__INT32* p
2472 )
2473 {
2474 bool rc = true;
2475 if ( m_endian == ON::big_endian )
2476 {
2477 if ( count > 0 )
2478 {
2479 const char* b = (const char*)p;
2480 while ( rc && count-- )
2481 {
2482 rc = WriteByte( 1, b+3 );
2483 if (rc) rc = WriteByte( 1, b+2 );
2484 if (rc) rc = WriteByte( 1, b+1 );
2485 if (rc) rc = WriteByte( 1, b );
2486 b += 4;
2487 }
2488 }
2489 }
2490 else
2491 {
2492 rc = WriteByte( count<<2, p );
2493 }
2494 return rc;
2495 }
2496
2497 bool
ReadInt64(size_t count,ON__INT64 * p)2498 ON_BinaryArchive::ReadInt64( // Read an array of 64 bit integers
2499 size_t count, // number of 64 bit integers to read
2500 ON__INT64* p
2501 )
2502 {
2503 bool rc = ReadByte( count<<3, p );
2504 if ( rc && m_endian == ON::big_endian )
2505 {
2506 unsigned char* b=(unsigned char*)p;
2507 unsigned char c;
2508 while(count--) {
2509 c = b[0]; b[0] = b[7]; b[7] = c;
2510 c = b[1]; b[1] = b[6]; b[6] = c;
2511 c = b[2]; b[2] = b[5]; b[5] = c;
2512 c = b[3]; b[3] = b[4]; b[4] = c;
2513 b += 8;
2514 }
2515 }
2516 return rc;
2517 }
2518
2519 bool
WriteInt64(size_t count,const ON__INT64 * p)2520 ON_BinaryArchive::WriteInt64( // Write an array of 64 bit integers
2521 size_t count, // number of ints to write
2522 const ON__INT64* p
2523 )
2524 {
2525 bool rc = true;
2526 if ( m_endian == ON::big_endian )
2527 {
2528 if ( count > 0 )
2529 {
2530 const char* b = (const char*)p;
2531 while ( rc && count-- )
2532 {
2533 rc = WriteByte( 1, b+7 );
2534 if (rc) rc = WriteByte( 1, b+6 );
2535 if (rc) rc = WriteByte( 1, b+5 );
2536 if (rc) rc = WriteByte( 1, b+4 );
2537 if (rc) rc = WriteByte( 1, b+3 );
2538 if (rc) rc = WriteByte( 1, b+2 );
2539 if (rc) rc = WriteByte( 1, b+1 );
2540 if (rc) rc = WriteByte( 1, b );
2541 b += 8;
2542 }
2543 }
2544 }
2545 else
2546 {
2547 rc = WriteByte( count<<3, p );
2548 }
2549 return rc;
2550 }
2551
2552 bool
WriteInt(size_t count,const int * p)2553 ON_BinaryArchive::WriteInt( // Write an array of integers
2554 size_t count, // number of ints to write
2555 const int* p
2556 )
2557 {
2558 #if defined(ON_COMPILER_MSC)
2559 #pragma warning( push )
2560 // Disable the MSC /W4 "conditional expression is constant" warning
2561 // about 4 == sizeof(*p). Since this code has to run on machines
2562 // where sizeof(*p) can be 2, 4, or 8 bytes, the test is necessary.
2563 #pragma warning( disable : 4127 )
2564 #endif
2565
2566 bool rc;
2567 if ( 4 == sizeof(*p) )
2568 {
2569 rc = WriteInt32( count, (const ON__INT32*)p );
2570 }
2571 else
2572 {
2573 ON__INT32 i32;
2574 size_t j;
2575 rc = true;
2576 for ( j = 0; j < count && rc; j++ )
2577 {
2578 i32 = (ON__INT32)(*p++);
2579 rc = WriteInt32( 1, &i32 );
2580 }
2581 }
2582 return rc;
2583
2584 #if defined(ON_COMPILER_MSC)
2585 #pragma warning( pop )
2586 #endif
2587 }
2588
2589 bool
WriteSize(size_t sz)2590 ON_BinaryArchive::WriteSize(size_t sz)
2591 {
2592 unsigned int u = (unsigned int)sz;
2593 return WriteInt(u);
2594 }
2595
2596 bool
ReadSize(size_t * sz)2597 ON_BinaryArchive::ReadSize(size_t* sz)
2598 {
2599 unsigned int u = 0;
2600 bool rc = ReadInt(&u);
2601 if (rc)
2602 *sz = u;
2603 return rc;
2604 }
2605
WriteBigSize(size_t sz)2606 bool ON_BinaryArchive::WriteBigSize(size_t sz)
2607 {
2608 ON__UINT64 u = (ON__UINT64)sz;
2609 return WriteInt64(1,(ON__INT64*)&u);;
2610 }
2611
ReadBigSize(size_t * sz)2612 bool ON_BinaryArchive::ReadBigSize( size_t* sz )
2613 {
2614 ON__UINT64 u;
2615 bool rc = ReadInt64(1,(ON__INT64*)&u);
2616 if (rc)
2617 *sz = (size_t)u;
2618 return rc;
2619 }
2620
WriteBigTime(time_t t)2621 bool ON_BinaryArchive::WriteBigTime(time_t t)
2622 {
2623 ON__UINT64 u = (ON__UINT64)t;
2624 return WriteInt64(1,(ON__INT64*)&u);
2625 }
2626
ReadBigTime(time_t * t)2627 bool ON_BinaryArchive::ReadBigTime( time_t* t )
2628 {
2629 ON__UINT64 u;
2630 bool rc = ReadInt64(1,(ON__INT64*)&u);
2631 if (rc)
2632 *t = (time_t)u;
2633 return rc;
2634 }
2635
2636
2637 bool
WriteInt(size_t count,const unsigned int * p)2638 ON_BinaryArchive::WriteInt( // Write an array of 32 bit integers
2639 size_t count, // number of ints to write
2640 const unsigned int* p
2641 )
2642 {
2643 return WriteInt( count, (const int*)p );
2644 }
2645
2646 bool
WriteInt(int i)2647 ON_BinaryArchive::WriteInt( // Write a single 32 bit integer
2648 int i
2649 )
2650 {
2651 return WriteInt( 1, &i );
2652 }
2653
2654 bool
WriteInt(unsigned int i)2655 ON_BinaryArchive::WriteInt( // Write a single 32 bit integer
2656 unsigned int i
2657 )
2658 {
2659 return WriteInt( 1, &i );
2660 }
2661
WriteBigInt(size_t count,const ON__INT64 * p)2662 bool ON_BinaryArchive::WriteBigInt( // Write an array of 64 bit integers
2663 size_t count,
2664 const ON__INT64* p
2665 )
2666 {
2667 return WriteInt64(count,p);
2668 }
2669
WriteBigInt(size_t count,const ON__UINT64 * p)2670 bool ON_BinaryArchive::WriteBigInt( // Write an array of 64 bit integers
2671 size_t count,
2672 const ON__UINT64* p
2673 )
2674 {
2675 return WriteInt64(count,(const ON__INT64*)p);
2676 }
2677
WriteBigInt(ON__INT64 i)2678 bool ON_BinaryArchive:: WriteBigInt( // Write a single 64 bit integer
2679 ON__INT64 i
2680 )
2681 {
2682 return WriteInt64(1,&i);
2683 }
2684
WriteBigInt(ON__UINT64 u)2685 bool ON_BinaryArchive::WriteBigInt( // Write a single 64 bit unsigned integer
2686 ON__UINT64 u
2687 )
2688 {
2689 return WriteInt64(1,(const ON__INT64*)&u);
2690 }
2691
2692
2693
2694 bool
WriteLong(size_t count,const long * p)2695 ON_BinaryArchive::WriteLong( // Write an array of longs
2696 size_t count, // number of longs to write
2697 const long* p
2698 )
2699 {
2700 #if defined(ON_COMPILER_MSC)
2701 #pragma warning( push )
2702 // Disable the MSC /W4 "conditional expression is constant" warning
2703 // about 4 == sizeof(*p). Since this code has to run on machines
2704 // where sizeof(*p) can be 2, 4, or 8 bytes, the test is necessary.
2705 #pragma warning( disable : 4127 )
2706 #endif
2707
2708 bool rc;
2709 if ( 4 == sizeof(*p) )
2710 {
2711 rc = WriteInt32( count, (const ON__INT32*)p );
2712 }
2713 else
2714 {
2715 ON__INT32 i32;
2716 size_t j;
2717 rc = true;
2718 for ( j = 0; j < count && rc; j++ )
2719 {
2720 i32 = (ON__INT32)(*p++);
2721 rc = WriteInt32( 1, &i32 );
2722 }
2723 }
2724 return rc;
2725
2726 #if defined(ON_COMPILER_MSC)
2727 #pragma warning( pop )
2728 #endif
2729 }
2730
2731 bool
WriteLong(size_t count,const unsigned long * p)2732 ON_BinaryArchive::WriteLong( // Write an array of longs
2733 size_t count, // number of longs to write
2734 const unsigned long* p
2735 )
2736 {
2737 return WriteLong( count, (const long*)p );
2738 }
2739
2740 bool
WriteLong(long i)2741 ON_BinaryArchive::WriteLong( // Write a single long
2742 long i
2743 )
2744 {
2745 return WriteLong( 1, &i );
2746 }
2747
2748 bool
WriteLong(unsigned long i)2749 ON_BinaryArchive::WriteLong( // Write a single unsigned long
2750 unsigned long i
2751 )
2752 {
2753 return WriteLong( 1, &i );
2754 }
2755
2756
2757 bool
WriteFloat(size_t count,const float * p)2758 ON_BinaryArchive::WriteFloat( // Write a number of IEEE floats
2759 size_t count, // number of doubles
2760 const float* p
2761 )
2762 {
2763 // floats and integers have same size and endian issues
2764 return WriteInt( count, (const int*)p );
2765 }
2766
2767 bool
WriteFloat(float f)2768 ON_BinaryArchive::WriteFloat( // Write a single float
2769 float f
2770 )
2771 {
2772 return WriteFloat( 1, &f );
2773 }
2774
2775 bool
WriteDouble(size_t count,const double * p)2776 ON_BinaryArchive::WriteDouble( // Write a single double
2777 size_t count, // number of doubles
2778 const double* p
2779 )
2780 {
2781 bool rc = true;
2782 if ( m_endian == ON::big_endian ) {
2783 if ( count > 0 ) {
2784 const char* b = (const char*)p;
2785 while ( rc && count-- ) {
2786 rc = WriteByte( 1, b+7 );
2787 if (rc) rc = WriteByte( 1, b+6 );
2788 if (rc) rc = WriteByte( 1, b+5 );
2789 if (rc) rc = WriteByte( 1, b+4 );
2790 if (rc) rc = WriteByte( 1, b+3 );
2791 if (rc) rc = WriteByte( 1, b+2 );
2792 if (rc) rc = WriteByte( 1, b+1 );
2793 if (rc) rc = WriteByte( 1, b );
2794 b += 8;
2795 }
2796 }
2797 }
2798 else {
2799 rc = WriteByte( count<<3, p );
2800 }
2801 return rc;
2802 }
2803
2804 bool
WriteComponentIndex(const ON_COMPONENT_INDEX & ci)2805 ON_BinaryArchive::WriteComponentIndex(
2806 const ON_COMPONENT_INDEX& ci
2807 )
2808 {
2809 bool rc = WriteInt( ci.m_type );
2810 if (rc)
2811 rc = WriteInt( ci.m_index );
2812 // do not add additional writes - you will break old file IO
2813 return rc;
2814 }
2815
2816 bool
ReadComponentIndex(ON_COMPONENT_INDEX & ci)2817 ON_BinaryArchive::ReadComponentIndex(
2818 ON_COMPONENT_INDEX& ci
2819 )
2820 {
2821 int t;
2822 ci.m_type = ON_COMPONENT_INDEX::invalid_type;
2823 ci.m_index = 0;
2824 bool rc = ReadInt( &t );
2825 if (rc)
2826 {
2827 rc = ReadInt( &ci.m_index );
2828 if (rc)
2829 {
2830 ci.m_type = ON_COMPONENT_INDEX::Type(t);
2831 }
2832 // do not add additional read - you will break old file IO
2833 }
2834 return rc;
2835 }
2836
2837 bool
WriteDouble(const double x)2838 ON_BinaryArchive::WriteDouble( // Write a single double
2839 const double x
2840 )
2841 {
2842 return WriteDouble( 1, &x );
2843 }
2844
2845 bool
WriteColor(const ON_Color & color)2846 ON_BinaryArchive::WriteColor( const ON_Color& color )
2847 {
2848 unsigned int colorref = color;
2849 return WriteInt( colorref );
2850 }
2851
2852 bool
WritePoint(const ON_2dPoint & p)2853 ON_BinaryArchive::WritePoint (
2854 const ON_2dPoint& p
2855 )
2856 {
2857 return WriteDouble( 2, &p.x );
2858 }
2859
2860 bool
WritePoint(const ON_3dPoint & p)2861 ON_BinaryArchive::WritePoint (
2862 const ON_3dPoint& p
2863 )
2864 {
2865 return WriteDouble( 3, &p.x );
2866 }
2867
2868 bool
WritePoint(const ON_4dPoint & p)2869 ON_BinaryArchive::WritePoint (
2870 const ON_4dPoint& p
2871 )
2872 {
2873 return WriteDouble( 4, &p.x );
2874 }
2875
2876 bool
WriteVector(const ON_2dVector & v)2877 ON_BinaryArchive::WriteVector (
2878 const ON_2dVector& v
2879 )
2880 {
2881 return WriteDouble( 2, &v.x );
2882 }
2883
2884 bool
WriteVector(const ON_3dVector & v)2885 ON_BinaryArchive::WriteVector (
2886 const ON_3dVector& v
2887 )
2888 {
2889 return WriteDouble( 3, &v.x );
2890 }
2891
WriteDisplayMaterialRef(const ON_DisplayMaterialRef & dmr)2892 bool ON_BinaryArchive::WriteDisplayMaterialRef( const ON_DisplayMaterialRef& dmr )
2893 {
2894 bool rc = WriteUuid( dmr.m_viewport_id );
2895 if (rc) rc = WriteUuid( dmr.m_display_material_id );
2896 return rc;
2897 }
2898
2899 bool
WriteUuid(const ON_UUID & uuid)2900 ON_BinaryArchive::WriteUuid( const ON_UUID& uuid )
2901 {
2902 bool rc = WriteInt32( 1, (const ON__INT32*)(&uuid.Data1) );
2903 if (rc) rc = WriteInt16( 1, (const ON__INT16*)(&uuid.Data2) );
2904 if (rc) rc = WriteInt16( 1, (const ON__INT16*)(&uuid.Data3) );
2905 if (rc) rc = WriteByte( 8, uuid.Data4 );
2906 return rc;
2907 }
2908
2909 bool
WriteTime(const struct tm & utc)2910 ON_BinaryArchive::WriteTime( const struct tm& utc )
2911 {
2912 // utc = coordinated universal time ( a.k.a GMT, UTC )
2913 // (From ANSI C time() and gmtime().)
2914 // The checks are here so we can insure files don't contain
2915 // garbage dates and ReadTime() can treat out of bounds
2916 // values as file corruption errors.
2917 int i;
2918 i = (int)utc.tm_sec; if ( i < 0 || i > 60 ) i = 0;
2919 bool rc = WriteInt( i );
2920 i = (int)utc.tm_min; if ( i < 0 || i > 60 ) i = 0;
2921 if ( rc )
2922 rc = WriteInt( i );
2923 i = (int)utc.tm_hour; if ( i < 0 || i > 24 ) i = 0;
2924 if ( rc )
2925 rc = WriteInt( i );
2926 i = (int)utc.tm_mday; if ( i < 0 || i > 31 ) i = 0;
2927 if ( rc )
2928 rc = WriteInt( i );
2929 i = (int)utc.tm_mon; if ( i < 0 || i > 12 ) i = 0;
2930 if ( rc )
2931 rc = WriteInt( i );
2932
2933 // no year restrictions because dates are used in archeological userdata
2934 i = (int)utc.tm_year;
2935 if ( rc )
2936 rc = WriteInt( i );
2937
2938 i = (int)utc.tm_wday; if ( i < 0 || i > 7 ) i = 0;
2939 if ( rc )
2940 rc = WriteInt( i );
2941 i = (int)utc.tm_yday; if ( i < 0 || i > 366 ) i = 0;
2942 if ( rc )
2943 rc = WriteInt( i );
2944 return rc;
2945 }
2946
2947 bool
WriteString(const char * sUTF8)2948 ON_BinaryArchive::WriteString( // Write NULL terminated UTF-8 encoded unicode string
2949 const char* sUTF8
2950 )
2951 {
2952 size_t string_utf8_element_count = 0;
2953 if ( sUTF8 )
2954 {
2955 while(sUTF8[string_utf8_element_count])
2956 string_utf8_element_count++;
2957 if ( string_utf8_element_count )
2958 string_utf8_element_count++;
2959 }
2960 ON__UINT32 ui32 = (ON__UINT32)string_utf8_element_count;
2961 bool rc = WriteInt32(1,(ON__INT32*)&ui32);
2962 if ( rc && string_utf8_element_count > 0 )
2963 rc = WriteByte( string_utf8_element_count, sUTF8 );
2964 return rc;
2965 }
2966
2967 bool
WriteString(const unsigned char * sUTF8)2968 ON_BinaryArchive::WriteString( // Write NULL terminated UTF-8 encoded unicode string
2969 const unsigned char* sUTF8
2970 )
2971 {
2972 return WriteString( (const char*)sUTF8 );
2973 }
2974
2975 bool
WriteString(const unsigned short * sUTF16)2976 ON_BinaryArchive::WriteString( // Write NULL terminated UTF-16 encoded unicode string
2977 const unsigned short* sUTF16
2978 )
2979 {
2980 size_t string_utf16_element_count = 0;
2981 if ( sUTF16 )
2982 {
2983 while(sUTF16[string_utf16_element_count])
2984 string_utf16_element_count++;
2985 if ( string_utf16_element_count )
2986 string_utf16_element_count++;
2987 }
2988 ON__UINT32 ui32 = (ON__UINT32)string_utf16_element_count;
2989 bool rc = WriteInt32(1,(ON__INT32*)&ui32);
2990 if ( rc && string_utf16_element_count > 0 )
2991 {
2992 rc = WriteShort( string_utf16_element_count, sUTF16 );
2993 }
2994 return rc;
2995 }
2996
2997 bool
WriteString(const ON_String & sUTF8)2998 ON_BinaryArchive::WriteString( const ON_String& sUTF8 )
2999 {
3000 size_t string_utf8_element_count = sUTF8.Length();
3001 if ( string_utf8_element_count )
3002 string_utf8_element_count++;
3003 ON__UINT32 ui32 = (ON__UINT32)string_utf8_element_count;
3004 bool rc = WriteInt32(1,(ON__INT32*)&ui32);
3005 if ( rc && string_utf8_element_count > 0 )
3006 rc = WriteByte( string_utf8_element_count, sUTF8.Array() );
3007 return rc;
3008 }
3009
3010 bool
WriteString(const ON_wString & s)3011 ON_BinaryArchive::WriteString( const ON_wString& s )
3012 {
3013 #if defined(ON_COMPILER_MSC)
3014 #pragma warning( push )
3015 // Disable the MSC /W4 "conditional expression is constant" warning
3016 // about 2 == sizeof(wchar_t). Since this code has to run on machines
3017 // where sizeof(wchar_t) can be 2, 4, or ... bytes, the test is necessary.
3018 #pragma warning( disable : 4127 )
3019 #endif
3020
3021 size_t string_element_count = s.Length();
3022 if ( string_element_count > 0)
3023 string_element_count++;
3024 bool rc = false;
3025 if ( string_element_count <= 1 )
3026 {
3027 ON__UINT32 ui32 = 0;
3028 rc = WriteInt32(1,(ON__INT32*)&ui32);
3029 }
3030 else if ( 2 == sizeof(wchar_t) && string_element_count > 0 )
3031 {
3032 ON__UINT32 ui32 = (ON__UINT32)string_element_count;
3033 rc = WriteInt32(1,(ON__INT32*)&ui32);
3034 if (rc)
3035 rc = WriteInt16( string_element_count, (const ON__INT16*)s.Array() );
3036 }
3037 else if ( 4 == sizeof(wchar_t) && string_element_count > 0 )
3038 {
3039 // Assume the string is UTF-32 encoded (this is the case for some gcc implementations).
3040 const int bTestByteOrder = false;
3041 const ON__UINT32* sUTF32 = (const ON__UINT32*)s.Array();
3042 const int sUTF32_count = (int)(string_element_count-1);
3043 const unsigned int error_mask = 0xFFFFFFFF;
3044 const ON__UINT32 error_code_point = 0xFFFD;
3045 unsigned int error_status = 0;
3046
3047 const int sUTF16_count = ON_ConvertUTF32ToUTF16(
3048 bTestByteOrder,
3049 sUTF32,
3050 sUTF32_count,
3051 0, // ON__UINT16* sUTF16,
3052 0, // int sUTF16_count,
3053 &error_status,
3054 error_mask,
3055 error_code_point,
3056 0 // const ON__UINT32** sNextUTF32
3057 );
3058
3059 if ( sUTF16_count > 0 )
3060 {
3061 error_status = 0;
3062 ON_SimpleArray<ON__UINT16> utf16_buffer(sUTF16_count+1);
3063 utf16_buffer.SetCount(sUTF16_count+1);
3064 const int sUTF16_count1 = ON_ConvertUTF32ToUTF16(
3065 bTestByteOrder,
3066 sUTF32,
3067 sUTF32_count,
3068 utf16_buffer.Array(),
3069 utf16_buffer.Count(),
3070 &error_status,
3071 error_mask,
3072 error_code_point,
3073 0 // const ON__UINT32** sNextUTF32
3074 );
3075 if ( sUTF16_count1 == sUTF16_count )
3076 {
3077 utf16_buffer[sUTF16_count] = 0;
3078 const ON__UINT32 ui32 = (ON__UINT32)(sUTF16_count+1);
3079 rc = WriteInt32(1,(const ON__INT32*)&ui32);
3080 if ( rc && ui32 > 0 )
3081 rc = WriteInt16( ui32, (const ON__INT16*)utf16_buffer.Array() );
3082 }
3083 }
3084 }
3085 return rc;
3086
3087 #if defined(ON_COMPILER_MSC)
3088 #pragma warning( pop )
3089 #endif
3090 }
3091
WriteArray(const ON_SimpleArray<bool> & a)3092 bool ON_BinaryArchive::WriteArray( const ON_SimpleArray<bool>& a )
3093 {
3094 #if defined(ON_COMPILER_MSC)
3095 #pragma warning( push )
3096 // Disable the MSC /W4 "conditional expression is constant" warning
3097 // about sizeof(*c) == sizeof(*b). Since this code has to run on machines
3098 // where sizeof(bool) can be 1, 2, 4, or 8 bytes, the test is necessary.
3099 #pragma warning( disable : 4127 )
3100 #endif
3101
3102 int count = a.Count();
3103 if ( count < 0 )
3104 count = 0;
3105 bool rc = WriteInt( count );
3106
3107 if ( rc && count > 0 )
3108 {
3109 char* p = 0;
3110 const char* c = 0;
3111 const bool* b = a.Array();
3112 if ( sizeof(*c) == sizeof(*b) )
3113 {
3114 // 8 bit "bool" on this compiler
3115 c = (char*)(b);
3116 }
3117 else if ( b )
3118 {
3119 // bigger "bool" on this compiler
3120 p = (char*)onmalloc(count*sizeof(*p));
3121 int i;
3122 for ( i = 0; i < count; i++ )
3123 p[i] = (b[i]?1:0);
3124 c = p;
3125 }
3126 rc = WriteChar( count, c );
3127 if ( p )
3128 onfree(p);
3129 }
3130
3131 return rc;
3132
3133 #if defined(ON_COMPILER_MSC)
3134 #pragma warning( pop )
3135 #endif
3136 }
3137
3138 bool
WriteArray(const ON_SimpleArray<char> & a)3139 ON_BinaryArchive::WriteArray( const ON_SimpleArray<char>& a )
3140 {
3141 int count = a.Count();
3142 if ( count < 0 )
3143 count = 0;
3144 bool rc = WriteInt( count );
3145 if ( rc && count > 0 ) {
3146 rc = WriteChar( count, a.Array() );
3147 }
3148 return rc;
3149 }
3150
3151 bool
WriteArray(const ON_SimpleArray<short> & a)3152 ON_BinaryArchive::WriteArray( const ON_SimpleArray<short>& a )
3153 {
3154 int count = a.Count();
3155 if ( count < 0 )
3156 count = 0;
3157 bool rc = WriteInt( count );
3158 if ( rc && count > 0 ) {
3159 rc = WriteShort( count, a.Array() );
3160 }
3161 return rc;
3162 }
3163
3164 bool
WriteArray(const ON_SimpleArray<int> & a)3165 ON_BinaryArchive::WriteArray( const ON_SimpleArray<int>& a )
3166 {
3167 int count = a.Count();
3168 if ( count < 0 )
3169 count = 0;
3170 bool rc = WriteInt( count );
3171 if ( rc && count > 0 ) {
3172 rc = WriteInt( count, a.Array() );
3173 }
3174 return rc;
3175 }
3176
3177 bool
WriteArray(const ON_SimpleArray<float> & a)3178 ON_BinaryArchive::WriteArray( const ON_SimpleArray<float>& a )
3179 {
3180 int count = a.Count();
3181 if ( count < 0 )
3182 count = 0;
3183 bool rc = WriteInt( count );
3184 if ( rc && count > 0 ) {
3185 rc = WriteFloat( count, a.Array() );
3186 }
3187 return rc;
3188 }
3189
3190 bool
WriteArray(const ON_SimpleArray<double> & a)3191 ON_BinaryArchive::WriteArray( const ON_SimpleArray<double>& a )
3192 {
3193 int count = a.Count();
3194 if ( count < 0 )
3195 count = 0;
3196 bool rc = WriteInt( count );
3197 if ( rc && count > 0 ) {
3198 rc = WriteDouble( count, a.Array() );
3199 }
3200 return rc;
3201 }
3202
3203 bool
WriteArray(const ON_SimpleArray<ON_Color> & a)3204 ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_Color>& a )
3205 {
3206 int count = a.Count();
3207 if ( count < 0 )
3208 count = 0;
3209 bool rc = WriteInt( count );
3210 if ( rc && count > 0 ) {
3211 rc = WriteInt( count, (int*)a.Array() );
3212 }
3213 return rc;
3214 }
3215
3216 bool
WriteArray(const ON_SimpleArray<ON_2dPoint> & a)3217 ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_2dPoint>& a )
3218 {
3219 int count = a.Count();
3220 if ( count < 0 )
3221 count = 0;
3222 bool rc = WriteInt( count );
3223 if ( rc && count > 0 ) {
3224 rc = WriteDouble( count*2, &a.Array()->x );
3225 }
3226 return rc;
3227 }
3228
3229 bool
WriteArray(const ON_SimpleArray<ON_3dPoint> & a)3230 ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_3dPoint>& a )
3231 {
3232 int count = a.Count();
3233 if ( count < 0 )
3234 count = 0;
3235 bool rc = WriteInt( count );
3236 if ( rc && count > 0 ) {
3237 rc = WriteDouble( count*3, &a.Array()->x );
3238 }
3239 return rc;
3240 }
3241
3242 bool
WriteArray(const ON_SimpleArray<ON_4dPoint> & a)3243 ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_4dPoint>& a )
3244 {
3245 int count = a.Count();
3246 if ( count < 0 )
3247 count = 0;
3248 bool rc = WriteInt( count );
3249 if ( rc && count > 0 ) {
3250 rc = WriteDouble( count*4, &a.Array()->x );
3251 }
3252 return rc;
3253 }
3254
3255 bool
WriteArray(const ON_SimpleArray<ON_2dVector> & a)3256 ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_2dVector>& a )
3257 {
3258 int count = a.Count();
3259 if ( count < 0 )
3260 count = 0;
3261 bool rc = WriteInt( count );
3262 if ( rc && count > 0 ) {
3263 rc = WriteDouble( count*2, &a.Array()->x );
3264 }
3265 return rc;
3266 }
3267
3268
3269 bool
WriteArray(const ON_SimpleArray<ON_3dVector> & a)3270 ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_3dVector>& a )
3271 {
3272 int count = a.Count();
3273 if ( count < 0 )
3274 count = 0;
3275 bool rc = WriteInt( count );
3276 if ( rc && count > 0 ) {
3277 rc = WriteDouble( count*3, &a.Array()->x );
3278 }
3279 return rc;
3280 }
3281
3282
3283 bool
WriteArray(const ON_SimpleArray<ON_Xform> & a)3284 ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_Xform>& a )
3285 {
3286 int count = a.Count();
3287 if ( count < 0 )
3288 count = 0;
3289 bool rc = WriteInt( count );
3290 if ( rc && count > 0 )
3291 {
3292 int i;
3293 for ( i = 0; i < count && rc; i++ )
3294 rc = WriteXform(a[i]);
3295 }
3296 return rc;
3297 }
3298
3299 bool
WriteArray(const ON_SimpleArray<ON_2fPoint> & a)3300 ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_2fPoint>& a )
3301 {
3302 int count = a.Count();
3303 if ( count < 0 )
3304 count = 0;
3305 bool rc = WriteInt( count );
3306 if ( rc && count > 0 ) {
3307 rc = WriteFloat( count*2, &a.Array()->x );
3308 }
3309 return rc;
3310 }
3311
3312 bool
WriteArray(const ON_SimpleArray<ON_3fPoint> & a)3313 ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_3fPoint>& a )
3314 {
3315 int count = a.Count();
3316 if ( count < 0 )
3317 count = 0;
3318 bool rc = WriteInt( count );
3319 if ( rc && count > 0 ) {
3320 rc = WriteFloat( count*3, &a.Array()->x );
3321 }
3322 return rc;
3323 }
3324
3325 bool
WriteArray(const ON_SimpleArray<ON_4fPoint> & a)3326 ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_4fPoint>& a )
3327 {
3328 int count = a.Count();
3329 if ( count < 0 )
3330 count = 0;
3331 bool rc = WriteInt( count );
3332 if ( rc && count > 0 ) {
3333 rc = WriteFloat( count*4, &a.Array()->x );
3334 }
3335 return rc;
3336 }
3337
3338 bool
WriteArray(const ON_SimpleArray<ON_2fVector> & a)3339 ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_2fVector>& a )
3340 {
3341 int count = a.Count();
3342 if ( count < 0 )
3343 count = 0;
3344 bool rc = WriteInt( count );
3345 if ( rc && count > 0 ) {
3346 rc = WriteFloat( count*2, &a.Array()->x );
3347 }
3348 return rc;
3349 }
3350
3351 bool
WriteArray(const ON_SimpleArray<ON_3fVector> & a)3352 ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_3fVector>& a )
3353 {
3354 int count = a.Count();
3355 if ( count < 0 )
3356 count = 0;
3357 bool rc = WriteInt( count );
3358 if ( rc && count > 0 ) {
3359 rc = WriteFloat( count*3, &a.Array()->x );
3360 }
3361 return rc;
3362 }
3363
3364
3365 bool
WriteArray(const ON_SimpleArray<ON_SurfaceCurvature> & a)3366 ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_SurfaceCurvature>& a )
3367 {
3368 int count = a.Count();
3369 if ( count < 0 )
3370 count = 0;
3371 bool rc = WriteInt( count );
3372 if ( rc && count > 0 ) {
3373 rc = WriteDouble( count*2, &a.Array()->k1 );
3374 }
3375 return rc;
3376 }
3377
3378 bool
WriteArray(const ON_SimpleArray<ON_ClippingPlaneInfo> & a)3379 ON_BinaryArchive::WriteArray( const ON_SimpleArray<ON_ClippingPlaneInfo>& a )
3380 {
3381 int count = a.Count();
3382 if ( count < 0 )
3383 count = 0;
3384 bool rc = WriteInt( count );
3385 for ( int i = 0; i < count && rc ; i++ )
3386 {
3387 rc = a[i].Write(*this);
3388 }
3389 return rc;
3390 }
3391
3392
3393 /////////////////////////////////////////////////////////////////////////
3394 /////////////////////////////////////////////////////////////////////////
3395 /////////////////////////////////////////////////////////////////////////
3396
3397 bool
WriteObject(const ON_Object * o)3398 ON_BinaryArchive::WriteObject( const ON_Object* o )
3399 {
3400 bool rc = false;
3401 if ( o )
3402 rc = WriteObject(*o);
3403 else {
3404 // NULL object has nil UUID and no date
3405 rc = BeginWrite3dmChunk( TCODE_OPENNURBS_CLASS, 0 );
3406 if (rc) {
3407 rc = BeginWrite3dmChunk( TCODE_OPENNURBS_CLASS_UUID, 0 );
3408 if ( rc ) {
3409 rc = WriteUuid( ON_nil_uuid );
3410 if ( !EndWrite3dmChunk() ) // end of TCODE_OPENNURBS_CLASS_UUID chunk
3411 rc = false;
3412 }
3413 if ( !EndWrite3dmChunk() )
3414 rc = false;
3415 }
3416 }
3417 return rc;
3418 }
3419
3420 static
IsCriticalUserData(const ON_BinaryArchive & ar,const ON_UserData * ud)3421 bool IsCriticalUserData( const ON_BinaryArchive& ar, const ON_UserData* ud )
3422 {
3423 // {31F55AA3-71FB-49f5-A975-757584D937FF}
3424 static const ON_UUID ON_MeshNgonUserData_ID =
3425 { 0x31F55AA3, 0x71FB, 0x49f5, { 0xA9, 0x75, 0x75, 0x75, 0x84, 0xD9, 0x37, 0xFF } };
3426
3427 // Userdata that must be saved even when userdata saving is "off".
3428 // Please discuss any changes with Dale Lear. In particular,
3429 // "critical" is used in a narrow sense and modifying this
3430 // function to save in form of plug-in's user data saved is
3431 // not appropriate. The definition of the user data class must
3432 // be in the opennurbs library and its purpose must be to extend
3433 // a core opennurbs data structure, usually because it was the
3434 // only way to add information to core opennurbs data structure
3435 // and not break the public C++ SDK.
3436 if ( 0 == ud )
3437 return false;
3438
3439 switch( ar.Archive3dmVersion() )
3440 {
3441 case 50:
3442 if ( ON_opennurbs5_id == ud->m_application_uuid )
3443 {
3444 // As of 30 August 2012, all the core opennurbs user data
3445 // classes with an application id of ON_opennurbs5_id are
3446 // deemed "critical".
3447 return true;
3448 }
3449
3450 if ( ON_opennurbs4_id == ud->m_application_uuid )
3451 {
3452 // ON_MeshNgonUserData is the only "critical" core
3453 // opennurbs user data with an application id of
3454 // ON_opennurbs4_id.
3455 if ( ON_MeshNgonUserData_ID == ud->m_userdata_uuid )
3456 return true;
3457 }
3458 break;
3459
3460 case 4:
3461 if ( ON_opennurbs4_id == ud->m_application_uuid )
3462 {
3463 // ON_MeshNgonUserData is the only "critical" core
3464 // opennurbs user data with an application id of
3465 // ON_opennurbs4_id.
3466 if ( ON_MeshNgonUserData_ID == ud->m_userdata_uuid )
3467 return true;
3468 }
3469 break;
3470 }
3471
3472 return false;
3473 }
3474
3475 static
HasCriticalUserData(const ON_BinaryArchive & ar,const ON_Object * obj)3476 bool HasCriticalUserData( const ON_BinaryArchive& ar, const ON_Object* obj )
3477 {
3478 if ( 0 == obj )
3479 return false;
3480
3481 for ( const ON_UserData* ud = obj->FirstUserData(); 0 != ud; ud = ud->Next() )
3482 {
3483 if ( IsCriticalUserData(ar,ud) )
3484 return true;
3485 }
3486
3487 return false;
3488 }
3489
3490 static
IsCoreUserData(const ON_UserData * ud)3491 bool IsCoreUserData( const ON_UserData* ud )
3492 {
3493 // Userdata with IO code we trust.
3494 if ( 0 == ud )
3495 return false;
3496 if ( ud->m_application_uuid == ON_rhino4_id
3497 || ud->m_application_uuid == ON_rhino5_id
3498 || ud->m_application_uuid == ON_rhino_id
3499 || ud->m_application_uuid == ON_opennurbs4_id
3500 || ud->m_application_uuid == ON_opennurbs5_id
3501 || ud->m_application_uuid == ON_opennurbs_id
3502 )
3503 {
3504 return true;
3505 }
3506 return false;
3507 }
3508
3509 bool
WriteObject(const ON_Object & o)3510 ON_BinaryArchive::WriteObject( const ON_Object& o )
3511 {
3512 // writes polymorphic object derived from ON_Object in a way that
3513 // it can be recreated from ON_BinaryArchive::ReadObject
3514 ON_UUID uuid;
3515 bool rc = false;
3516 const ON_ClassId* pID = o.ClassId();
3517 if ( !pID ) {
3518 ON_ERROR("ON_BinaryArchive::WriteObject() o.ClassId() returned NULL.");
3519 return false;
3520 }
3521 uuid = pID->Uuid();
3522
3523 if ( m_3dm_version <= 2 )
3524 {
3525 if ( ON_Curve::Cast(&o) && !ON_NurbsCurve::Cast(&o) )
3526 {
3527 ON_NurbsCurve nc;
3528 const ON_Curve* curve = static_cast<const ON_Curve*>(&o);
3529 if ( curve->GetNurbForm(nc) )
3530 return WriteObject( nc );
3531 }
3532 else if ( ON_Surface::Cast(&o) && !ON_NurbsSurface::Cast(&o) )
3533 {
3534 ON_NurbsSurface ns;
3535 const ON_Surface* surface = static_cast<const ON_Surface*>(&o);
3536 if ( surface->GetNurbForm(ns) )
3537 return WriteObject( ns );
3538 }
3539 else if( ON_Annotation2::Cast(&o))
3540 {
3541 // 6-23-03 lw added for writing annotation to v2 files
3542 ON_Annotation2* pA = (ON_Annotation2*)&o;
3543 switch( pA->Type())
3544 {
3545 case ON::dtNothing:
3546 break;
3547 case ON::dtDimLinear:
3548 case ON::dtDimAligned:
3549 {
3550 ON_LinearDimension dim;
3551 ((ON_LinearDimension2*)pA)->GetV2Form( dim);
3552 return WriteObject( dim);
3553 }
3554 case ON::dtDimAngular:
3555 {
3556 ON_AngularDimension dim;
3557 ((ON_AngularDimension2*)pA)->GetV2Form( dim);
3558 return WriteObject( dim);
3559 }
3560 case ON::dtDimDiameter:
3561 case ON::dtDimRadius:
3562 {
3563 ON_RadialDimension dim;
3564 ((ON_RadialDimension2*)pA)->GetV2Form( dim);
3565 return WriteObject( dim);
3566 }
3567 case ON::dtLeader:
3568 {
3569 ON_Leader leader;
3570 ((ON_Leader2*)pA)->GetV2Form( leader);
3571 return WriteObject( leader);
3572 }
3573 case ON::dtTextBlock:
3574 {
3575 ON_TextEntity text;
3576 ((ON_TextEntity2*)pA)->GetV2Form( text);
3577 return WriteObject( text);
3578 }
3579 case ON::dtDimOrdinate:
3580 // no V2 form of ordinate dimensions
3581 // Fall through and save it in v4 format.
3582 // It will be skipped by the v2 and v3 readers
3583 // but users won't loose the ordinate dimensions
3584 // when they encounter the situation described in
3585 // the next comment.
3586 break;
3587 }
3588
3589 // 7 August 2003 Dale Lear
3590 // I commented out the "return false;".
3591 // It is imporant to fall through to the working
3592 // code because people overwrite their "good" files
3593 // with a V2 version and loose everything when the
3594 // writing code returns false. By falling through,
3595 // V2 will still read what it can from the file and
3596 // V3 will read the entire file.
3597 //return false;
3598 }
3599 }
3600
3601 if ( m_3dm_version <= 4 && ON::extrusion_object == o.ObjectType() )
3602 {
3603 // 29 September 2010 Dale Lear
3604 // ON_Extrusion was added in V5. It must be translated
3605 // to a brep or surface to save it in a V4 file.
3606 const ON_Extrusion* extrusion = ON_Extrusion::Cast(&o);
3607 if ( 0 != extrusion )
3608 {
3609 ON_Object* v4object = 0;
3610 if ( extrusion->IsCapped() || extrusion->ProfileCount() >= 2 )
3611 v4object = extrusion->BrepForm(0);
3612 if ( 0 == v4object )
3613 v4object = extrusion->SumSurfaceForm(0);
3614 if ( 0 == v4object )
3615 v4object = extrusion->NurbsSurface(0);
3616 if ( 0 != v4object
3617 && ON::extrusion_object != v4object->ObjectType() // no infinte recursion!
3618 )
3619 {
3620 // Some plug-in userdata code is not robust enough to check
3621 // archive version numbers and correctly handle save as v4
3622 // changes. The upshot is that, extrusion user data
3623 // has to be lost when saving as V4.
3624 //v4object->MoveUserData(const_cast<ON_Object&>(o));
3625 rc = WriteObject( v4object );
3626 //const_cast<ON_Object&>(o).MoveUserData(*v4object);
3627 delete v4object;
3628 return rc;
3629 }
3630 if ( 0 != v4object )
3631 delete v4object;
3632 }
3633 }
3634
3635 rc = BeginWrite3dmChunk( TCODE_OPENNURBS_CLASS, 0 );
3636 if (rc) {
3637
3638 // TCODE_OPENNURBS_CLASS_UUID chunk contains class's UUID
3639 rc = BeginWrite3dmChunk( TCODE_OPENNURBS_CLASS_UUID, 0 );
3640 if ( rc ) {
3641 rc = WriteUuid( uuid );
3642 if ( !EndWrite3dmChunk() ) // end of TCODE_OPENNURBS_CLASS_UUID chunk
3643 rc = false;
3644 }
3645
3646 // TCODE_OPENNURBS_CLASS_DATA chunk contains definition of class
3647 if ( rc ) {
3648 rc = BeginWrite3dmChunk( TCODE_OPENNURBS_CLASS_DATA, 0 );
3649 if (rc)
3650 {
3651 rc = o.Write( *this )?true:false;
3652 if ( !rc ) {
3653 ON_ERROR("ON_BinaryArchive::WriteObject() o.Write() failed.");
3654 }
3655 if ( !EndWrite3dmChunk() ) // end of TCODE_OPENNURBS_CLASS_DATA chunk
3656 rc = false;
3657 }
3658 }
3659
3660 if (rc && (m_bSaveUserData || HasCriticalUserData(*this,&o) ) )
3661 {
3662 // write user data. Each piece of user data is in a
3663 // TCODE_OPENNURBS_CLASS_USERDATA chunk.
3664 rc = WriteObjectUserData(o);
3665 }
3666
3667 // TCODE_OPENNURBS_CLASS_END chunk marks end of class record
3668 if ( BeginWrite3dmChunk( TCODE_OPENNURBS_CLASS_END, 0 ) ) {
3669 if ( !EndWrite3dmChunk() )
3670 rc = false;
3671 }
3672 else
3673 rc = false;
3674
3675 if ( !EndWrite3dmChunk() ) // end of TCODE_OPENNURBS_CLASS chunk
3676 rc = false;
3677 }
3678
3679 return rc;
3680 }
3681
WriteObjectUserData(const ON_Object & object)3682 bool ON_BinaryArchive::WriteObjectUserData( const ON_Object& object )
3683 {
3684 if ( m_3dm_version < 3 )
3685 {
3686 // no user data is saved in V1 and V2 files.
3687 return true;
3688 }
3689
3690 // writes user data attached to object.
3691 bool rc = true;
3692 const ON_UserData* ud;
3693 ON_UUID userdata_classid;
3694
3695 for (ud = object.m_userdata_list; ud && rc; ud = ud->m_userdata_next)
3696 {
3697 if ( !ud->Archive() )
3698 {
3699 continue;
3700 }
3701
3702 if ( false == m_bSaveUserData )
3703 {
3704 // user data is not being saved unless it is functioning
3705 // as a critcial extension of a core opennurbs data
3706 // structure.
3707 if ( false == IsCriticalUserData(*this,ud) )
3708 continue;
3709 }
3710
3711
3712 // LOTS of tests to weed out bogus user data
3713 if ( 0 == ON_UuidCompare( ud->m_userdata_uuid, ON_nil_uuid ) )
3714 continue;
3715 if ( &object != ud->m_userdata_owner )
3716 continue;
3717 const ON_ClassId* cid = ud->ClassId();
3718 if ( 0 == cid )
3719 continue;
3720 if ( cid == &ON_UserData::m_ON_UserData_class_id )
3721 continue;
3722 if ( cid == &ON_UserData::m_ON_Object_class_id )
3723 continue;
3724
3725 // The UserDataClassUuid() function is used instead of
3726 // calling cid->Uuid() so we get the value of the
3727 // plug-in's class id when the plug-in is not loaded
3728 // and ud is ON_UnknownUserData.
3729 userdata_classid = ud->UserDataClassUuid();
3730 if ( 0 == ON_UuidCompare( userdata_classid, ON_nil_uuid ) )
3731 continue;
3732 if ( 0 == ON_UuidCompare( userdata_classid, ON_UserData::m_ON_UserData_class_id.Uuid() ) )
3733 continue;
3734 if ( 0 == ON_UuidCompare( userdata_classid, ON_Object::m_ON_Object_class_id.Uuid() ) )
3735 continue;
3736 if ( 0 == ON_UuidCompare( userdata_classid, ON_UnknownUserData::m_ON_Object_class_id.Uuid() ) )
3737 continue;
3738
3739 if ( 3 == m_3dm_version )
3740 {
3741 // When saving a V3 archive and the user data is not
3742 // native V3 data, make sure the plug-in supports
3743 // writing V3 user data.
3744 if ( m_V3_plugin_id_list.BinarySearch( &ud->m_application_uuid, ON_UuidCompare ) < 0 )
3745 continue;
3746 }
3747
3748 if ( ON_UuidIsNil( ud->m_application_uuid ) )
3749 {
3750 // As of version 200909190 - a non-nil application_uuid is
3751 // required in order for user data to be saved in a
3752 // 3dm archive.
3753 ON_Error(__FILE__,__LINE__,"Not saving %s userdata - m_application_uuid is nil.",cid->ClassName());
3754 continue;
3755 }
3756
3757 // See if we have unknown user data (goo) and make sure
3758 // IsUnknownUserData() agrees with ON_UnknownUserData::Cast().
3759 const ON_UnknownUserData* unknown_ud = ON_UnknownUserData::Cast(ud);
3760 if ( 0 == unknown_ud )
3761 {
3762 if ( ud->IsUnknownUserData() )
3763 {
3764 ON_ERROR("ON_UnknownUserData::Cast(ud) is null and ud->IsUnknownUserData() is true.");
3765 continue; // something's wrong
3766 }
3767 }
3768 else
3769 {
3770 if ( !ud->IsUnknownUserData() )
3771 {
3772 ON_ERROR("ON_UnknownUserData::Cast(ud) is not null and ud->IsUnknownUserData() is false.");
3773 continue; // something's wrong
3774 }
3775 }
3776
3777 if ( 0 != unknown_ud )
3778 {
3779 if ( false == m_bSaveUserData )
3780 continue; // "unknown" user data cannot be "critical"
3781
3782 if ( unknown_ud->m_3dm_version <= 3 )
3783 continue; // Unknown will not be resaved in V3 archives
3784
3785 if ( unknown_ud->m_3dm_version > 5 && unknown_ud->m_3dm_version < 50 )
3786 continue;
3787
3788 if ( unknown_ud->m_3dm_opennurbs_version < 200701010 )
3789 continue;
3790
3791 if ( unknown_ud->m_3dm_version >= 50 && m_3dm_version < 50 )
3792 {
3793 // Unknown userdata with 8 byte chunk lengths cannot be
3794 // saved into a V4 file with 4 byte chunk lengths because
3795 // the resulting chunk will be unreadable in V4.
3796 // This is not an error condition. It is a consequence
3797 // of V4 IO code not being robust enough to handle
3798 // 8 bytes chunk lengths.
3799 continue;
3800 }
3801 }
3802
3803 // Each piece of user data is inside of
3804 // a TCODE_OPENNURBS_CLASS_USERDATA chunk.
3805 rc = BeginWrite3dmChunk( TCODE_OPENNURBS_CLASS_USERDATA, 0 );
3806 if (rc) {
3807 rc = Write3dmChunkVersion(2,2);
3808 // wrap user data header info in an TCODE_OPENNURBS_CLASS_USERDATA_HEADER chunk
3809 rc = BeginWrite3dmChunk( TCODE_OPENNURBS_CLASS_USERDATA_HEADER, 0 );
3810 if (rc)
3811 {
3812 if ( rc ) rc = WriteUuid( userdata_classid );
3813 if ( rc ) rc = WriteUuid( ud->m_userdata_uuid );
3814 if ( rc ) rc = WriteInt( ud->m_userdata_copycount );
3815 if ( rc ) rc = WriteXform( ud->m_userdata_xform );
3816
3817 // added for version 2.1
3818 if ( rc ) rc = WriteUuid( ud->m_application_uuid );
3819
3820 // added for version 2.2 - 14, October 2009
3821 if ( rc )
3822 {
3823 rc = WriteBool( unknown_ud ? true : false );
3824 int ver = unknown_ud ? unknown_ud->m_3dm_version : m_3dm_version;
3825 rc = WriteInt( ver );
3826 ver = unknown_ud ? unknown_ud->m_3dm_opennurbs_version : m_3dm_opennurbs_version;
3827 if (rc) rc = WriteInt( ver );
3828 }
3829
3830 if ( !EndWrite3dmChunk() )
3831 rc = false;
3832 }
3833 if (rc)
3834 {
3835 // wrap user data in an anonymous chunk
3836 rc = BeginWrite3dmChunk( TCODE_ANONYMOUS_CHUNK, 0 );
3837 if ( rc )
3838 {
3839 if ( 0 != unknown_ud )
3840 {
3841 // 22 January 2004 Dale Lear
3842 // Disable crc checking when writing the
3843 // unknow user data block.
3844 // This has to be done so we don't get an extra
3845 // 32 bit CRC calculated on the block that
3846 // ON_UnknownUserData::Write() writes. The
3847 // original 32 bit crc is at the end of this
3848 // block and will be checked when the class
3849 // that wrote this user data is present.
3850 // The EndWrite3dmChunk() will reset the
3851 // CRC checking flags to the appropriate
3852 // values.
3853 m_chunk.Last()->m_do_crc16 = 0;
3854 m_chunk.Last()->m_do_crc32 = 0;
3855 m_bDoChunkCRC = false;
3856 }
3857 rc = ud->Write(*this)?true:false;
3858 if ( !EndWrite3dmChunk() )
3859 rc = false;
3860 }
3861 }
3862 if ( !EndWrite3dmChunk() )
3863 rc = false;
3864 }
3865 }
3866 return rc;
3867 }
3868
3869 int
LoadUserDataApplication(ON_UUID application_id)3870 ON_BinaryArchive::LoadUserDataApplication( ON_UUID application_id )
3871 {
3872 // This is a virtual function.
3873 // Rhino overrides this function to load plug-ins.
3874 return 0;
3875 }
3876
ReadObject(ON_Object ** ppObject)3877 int ON_BinaryArchive::ReadObject( ON_Object** ppObject )
3878 {
3879 if ( !ppObject )
3880 {
3881 ON_ERROR("ON_BinaryArchive::ReadObject() called with NULL ppObject.");
3882 return 0;
3883 }
3884 *ppObject = 0;
3885 return ReadObjectHelper(ppObject);
3886 }
3887
ReadObject(ON_Object & object)3888 int ON_BinaryArchive::ReadObject( ON_Object& object )
3889 {
3890 ON_Object* pObject = &object;
3891 return ReadObjectHelper(&pObject);
3892 }
3893
ReadObjectHelper(ON_Object ** ppObject)3894 int ON_BinaryArchive::ReadObjectHelper( ON_Object** ppObject )
3895 {
3896 // returns 0: failure - unable to read object because of file IO problems
3897 // 1: success
3898 // 3: unable to read object because it's UUID is not registered
3899 // this could happen in cases where old code is attempting to read
3900 // new objects.
3901 ON__UINT32 tcode;
3902 ON__INT64 length_TCODE_OPENNURBS_CLASS = 0;
3903 ON__INT64 length_TCODE_OPENNURBS_CLASS_UUID = 0;
3904 ON__INT64 length_TCODE_OPENNURBS_CLASS_DATA = 0;
3905 ON_UUID uuid;
3906 const ON_ClassId* pID = 0;
3907 ON_Object* pObject = *ppObject; // If not null, use input
3908 int rc = 0;
3909 const ON__INT64 sizeof_chunk_header = (ON__INT64)(4 + SizeofChunkLength());
3910 const ON__INT64 expected_length_TCODE_OPENNURBS_CLASS_UUID = 20;
3911
3912 //bool bBogusUserData = false;
3913
3914
3915 // all ON_Objects written by WriteObject are in a TCODE_OPENNURBS_CLASS chunk
3916 rc = BeginRead3dmBigChunk( &tcode, &length_TCODE_OPENNURBS_CLASS );
3917 if ( !rc )
3918 return 0;
3919
3920 // When a NULL ON_Object is written, the file has
3921 //
3922 // TCODE_OPENNURBS_CLASS, length = 20 + sizeof_chunk_header
3923 // TCODE_OPENNURBS_CLASS_UUID, length = 20
3924 // 16 byte nil uuid
3925 // 4 byte TCODE_OPENNURBS_CLASS_UUID crc
3926 //
3927 // When a non-NULL ON_Object is written, the file has
3928 //
3929 // TCODE_OPENNURBS_CLASS, length = 20 + 3*sizeof_chunk_header + length_DATA_chunk + length_USER_DATA_chunk(s)
3930 //
3931 // TCODE_OPENNURBS_CLASS_UUID, length = 20
3932 // 16 byte nil uuid
3933 // 4 byte TCODE_OPENNURBS_CLASS_UUID crc
3934 //
3935 // TCODE_OPENNURBS_CLASS_DATA, length_DATA >= 4
3936 // ...
3937 // 4 byte TCODE_OPENNURBS_CLASS_DATA crc
3938 //
3939 // Optional TCODE_OPENNURBS_CLASS_USERDATA chunks
3940 //
3941 // TCODE_OPENNURBS_CLASS_END, chunk value = 0
3942
3943 if ( tcode != TCODE_OPENNURBS_CLASS )
3944 {
3945 ON_ERROR("ON_BinaryArchive::ReadObject() didn't find TCODE_OPENNURBS_CLASS block.");
3946 rc = 0;
3947 }
3948 else if ( length_TCODE_OPENNURBS_CLASS < expected_length_TCODE_OPENNURBS_CLASS_UUID + sizeof_chunk_header)
3949 {
3950 ON_ERROR("ON_BinaryArchive::ReadObject() TCODE_OPENNURBS_CLASS chunk length too small.");
3951 rc = 0;
3952 }
3953 else
3954 {
3955 // we break out of this loop if something bad happens
3956 for (;;)
3957 {
3958 // read class's UUID ///////////////////////////////////////////////////////////
3959 rc = BeginRead3dmBigChunk( &tcode, &length_TCODE_OPENNURBS_CLASS_UUID );
3960 if ( !rc )
3961 break;
3962 if ( tcode != TCODE_OPENNURBS_CLASS_UUID )
3963 {
3964 ON_ERROR("ON_BinaryArchive::ReadObject() didn't find TCODE_OPENNURBS_CLASS_UUID block");
3965 rc = 0;
3966 }
3967 else if ( expected_length_TCODE_OPENNURBS_CLASS_UUID != length_TCODE_OPENNURBS_CLASS_UUID )
3968 {
3969 ON_ERROR("ON_BinaryArchive::ReadObject() TCODE_OPENNURBS_CLASS_UUID has invalid length");
3970 rc = 0;
3971 }
3972 else if ( !ReadUuid( uuid ) )
3973 {
3974 rc = 0;
3975 }
3976 if ( !EndRead3dmChunk() )
3977 {
3978 rc = 0;
3979 }
3980 if ( !rc ) {
3981 break;
3982 }
3983 ///////////////////////////////////////////////////////////////////////////////
3984
3985 if ( !ON_UuidCompare( &uuid, &ON_nil_uuid ) ) {
3986 // nil UUID written if NULL pointer is passed to WriteObject();
3987 rc = 1;
3988 break;
3989 }
3990
3991 // Use UUID to get ON_ClassId for this class //////////////////////////////////
3992 if ( pObject )
3993 {
3994 pID = pObject->ClassId();
3995 if ( uuid != pID->Uuid() )
3996 {
3997 ON_ERROR("ON_BinaryArchive::ReadObject() - uuid does not match intput pObject's class id.");
3998 pID = 0;
3999 rc = 2;
4000 break;
4001 }
4002 }
4003 else
4004 {
4005 pID = ON_ClassId::ClassId( uuid );
4006 }
4007 if ( !pID )
4008 {
4009 // If you get here and you are not calling ON::Begin() at some point in your
4010 // executable, then call ON::Begin() to force all class definition to be linked.
4011 // If you are callig ON::Begin(), then either the uuid is garbage or you are
4012 // attempting to read an object with old code.
4013 // Visit http://www.opennurbs.org to get the latest OpenNURBS code.
4014 ON_WARNING("ON_BinaryArchive::ReadObject() ON_ClassId::ClassId(uuid) returned NULL.");
4015 rc = 3;
4016 break;
4017 }
4018 ///////////////////////////////////////////////////////////////////////////////
4019
4020 // read class's definitions /////////////////////////////////////////////////
4021 rc = BeginRead3dmBigChunk( &tcode, &length_TCODE_OPENNURBS_CLASS_DATA );
4022 if ( !rc )
4023 break;
4024 if ( tcode != TCODE_OPENNURBS_CLASS_DATA )
4025 {
4026 ON_ERROR("ON_BinaryArchive::ReadObject() didn't find TCODE_OPENNURBS_CLASS_DATA block");
4027 rc = 0;
4028 }
4029 else if ( length_TCODE_OPENNURBS_CLASS_DATA <= 0 )
4030 {
4031 ON_ERROR("ON_BinaryArchive::ReadObject() TCODE_OPENNURBS_CLASS_DATA chunk length too small");
4032 rc = 0;
4033 }
4034 else
4035 {
4036 if ( !pObject )
4037 {
4038 pObject = pID->Create();
4039 }
4040
4041 if ( !pObject )
4042 {
4043 ON_ERROR("ON_BinaryArchive::ReadObject() pID->Create() returned NULL.");
4044 rc = 0;
4045 }
4046 else
4047 {
4048 rc = pObject->Read(*this);
4049 if ( !rc )
4050 {
4051 ON_ERROR("ON_BinaryArchive::ReadObject() pObject->Read() failed.");
4052 delete pObject;
4053 // don't break here - we still need to call end chunk.
4054 }
4055 else
4056 {
4057 *ppObject = pObject;
4058 }
4059 }
4060 }
4061 if ( !EndRead3dmChunk() )
4062 {
4063 rc = 0;
4064 }
4065
4066 if ( rc && 0 != pObject )
4067 {
4068 // read user data /////////////////////////////////////////////////
4069 // If TCODE_OPENNURBS_CLASS_USERDATA chunks exist, this reads them.
4070 // ReadObjectUserData() stops when it reads a TCODE_OPENNURBS_CLASS_END chunk.
4071 if (!ReadObjectUserData(*pObject))
4072 rc = 0;
4073 }
4074
4075 break;
4076 }
4077 }
4078 if ( !EndRead3dmChunk() ) // TCODE_OPENNURBS_CLASS
4079 rc = 0;
4080
4081 return rc;
4082 }
4083
ReadObjectUserDataAnonymousChunk(const ON__UINT64 length_TCODE_ANONYMOUS_CHUNK,const int archive_3dm_version,const int archive_opennurbs_version,ON_UserData * ud)4084 bool ON_BinaryArchive::ReadObjectUserDataAnonymousChunk(
4085 const ON__UINT64 length_TCODE_ANONYMOUS_CHUNK,
4086 const int archive_3dm_version,
4087 const int archive_opennurbs_version,
4088 ON_UserData* ud )
4089 {
4090 // Reads the portion of the file containing the userdata into a buffer
4091 // and lets the plug-in try to read from that. If the plug-in fails,
4092 // we press on because we cannot trust plug-ins to get IO code right.
4093 bool rc = false;
4094
4095 if ( 0 == ud )
4096 return false;
4097
4098 if ( ud->IsUnknownUserData()
4099 || (archive_3dm_version == Archive3dmVersion()
4100 && archive_opennurbs_version == ArchiveOpenNURBSVersion()
4101 && IsCoreUserData(ud))
4102 )
4103 {
4104 // assume this userdata's read function is robust.
4105 ON_ReadChunkHelper ch(*this);
4106 if ( !ch.m_bReadSuccess
4107 || TCODE_ANONYMOUS_CHUNK != ch.m_chunk_tcode
4108 || length_TCODE_ANONYMOUS_CHUNK != (ON__UINT64)ch.m_chunk_value
4109 )
4110 {
4111 return false;
4112 }
4113 if ( ud->IsUnknownUserData() )
4114 {
4115 // 22 January 2004 Dale Lear:
4116 // Disable CRC checking while reading this chunk.
4117 // (If the user data has nested chunks, the crc we get
4118 // by reading the thing as one large chunk will be wrong.)
4119 m_chunk.Last()->m_do_crc16 = false;
4120 m_chunk.Last()->m_do_crc32 = false;
4121 m_bDoChunkCRC = false;
4122 }
4123 rc = ud->Read(*this) ? true : false;
4124 }
4125 else
4126 {
4127 // Untrusted plug-in userdata.
4128 // Insulate file reading from possible bugs plug-in IO code by reading
4129 // entire anonymous chunk into memory and letting the plug-in use
4130 // the memory buffer archive.
4131 unsigned char stack_buffer[2048];
4132 const size_t sizeof_buffer = (size_t)(length_TCODE_ANONYMOUS_CHUNK + 4 + SizeofChunkLength());
4133 void* freeme = 0;
4134 void* buffer = (sizeof_buffer <= sizeof(stack_buffer))
4135 ? &stack_buffer[0]
4136 : (freeme = onmalloc(sizeof_buffer)); // generally, object userdata is small we almost never use heap
4137 if ( 0 != buffer
4138 && sizeof_buffer == ReadBuffer(sizeof_buffer,buffer)
4139 )
4140 {
4141 ON_Read3dmBufferArchive memory_archive(
4142 sizeof_buffer,
4143 buffer,
4144 false,
4145 archive_3dm_version,
4146 archive_opennurbs_version
4147 );
4148
4149 // The TCODE_ANONYMOUS_CHUNK wrapper has chunk lengths set
4150 // by whatever version wrote this file. The information
4151 // in the chunk has chunk lengths set by the plug-in that
4152 // originally wrote the user data. If the plug-in used
4153 // worte to a version <= 5 archive and the user data has
4154 // was read as goo and saved as goo in a version 50+
4155 // archive, then we need to tweak the archive version
4156 // when reading the chunk length of the TCODE_ANONYMOUS_CHUNK wrapper.
4157 bool bTweakArchiveVersion = (memory_archive.SizeofChunkLength() != SizeofChunkLength());
4158 if ( bTweakArchiveVersion )
4159 memory_archive.SetArchive3dmVersion(Archive3dmVersion());
4160 ON_ReadChunkHelper ch(memory_archive);
4161 if ( bTweakArchiveVersion )
4162 memory_archive.SetArchive3dmVersion(archive_3dm_version);
4163
4164 if ( !ch.m_bReadSuccess
4165 || TCODE_ANONYMOUS_CHUNK != ch.m_chunk_tcode
4166 || length_TCODE_ANONYMOUS_CHUNK != (ON__UINT64)ch.m_chunk_value
4167 )
4168 rc = false;
4169 else
4170 rc = ud->Read(memory_archive) ? true : false;
4171 }
4172 if ( freeme )
4173 onfree(freeme);
4174 }
4175 return rc;
4176 }
4177
4178
4179 class CUserDataHeaderInfo
4180 {
4181 public:
4182 CUserDataHeaderInfo();
4183
4184 void Initialize();
4185
4186 ON_UUID m_classid;
4187 ON_UUID m_itemid;
4188 ON_UUID m_appid;
4189 int m_3dm_version;
4190 int m_3dm_opennurbs_version;
4191 int m_copycount;
4192 bool m_bLastSavedAsGoo;
4193 ON_Xform m_xform;
4194 };
4195
CUserDataHeaderInfo()4196 CUserDataHeaderInfo::CUserDataHeaderInfo()
4197 {
4198 Initialize();
4199 }
4200
Initialize()4201 void CUserDataHeaderInfo::Initialize()
4202 {
4203 memset(this,0,sizeof(*this));
4204 }
4205
4206 static
ReadObjectUserDataHeaderHelper(ON_BinaryArchive & binary_archive,const int major_userdata_version,const int minor_userdata_version,CUserDataHeaderInfo & ud_header)4207 bool ReadObjectUserDataHeaderHelper(
4208 ON_BinaryArchive& binary_archive,
4209 const int major_userdata_version,
4210 const int minor_userdata_version,
4211 CUserDataHeaderInfo& ud_header
4212 )
4213 {
4214 bool rc = true;
4215 ON__UINT32 t = 0;
4216 ON__INT64 length_TCODE_OPENNURBS_CLASS_USERDATA_HEADER = 0;
4217
4218 ud_header.Initialize();
4219
4220 if ( major_userdata_version == 2 )
4221 {
4222 // major_userdata_version 2 started wrapping the userdata header info
4223 // in a TCODE_OPENNURBS_CLASS_USERDATA_HEADER chunk
4224 rc = binary_archive.BeginRead3dmBigChunk( &t, &length_TCODE_OPENNURBS_CLASS_USERDATA_HEADER );
4225 if (!rc)
4226 return false;
4227 if ( t != TCODE_OPENNURBS_CLASS_USERDATA_HEADER )
4228 {
4229 ON_ERROR("version 2.0 TCODE_OPENNURBS_CLASS_USERDATA chunk is missing TCODE_OPENNURBS_CLASS_USERDATA_HEADER chunk.");
4230 binary_archive.EndRead3dmChunk(); // end of mystery chunk
4231 return false;
4232 }
4233 }
4234
4235 if (rc) rc = binary_archive.ReadUuid( ud_header.m_classid );
4236 if (rc) rc = binary_archive.ReadUuid( ud_header.m_itemid );
4237 if (rc) rc = binary_archive.ReadInt( &ud_header.m_copycount );
4238 if (rc) rc = binary_archive.ReadXform( ud_header.m_xform );
4239 if ( major_userdata_version == 2 )
4240 {
4241 if ( minor_userdata_version >= 1 )
4242 {
4243 if (rc) rc = binary_archive.ReadUuid( ud_header.m_appid );
4244 if ( minor_userdata_version >= 2 )
4245 {
4246 // bLastSavedAsGoo is true if the user data was saved
4247 // into the file by ON_UnknownUserData.
4248 if (rc) rc = binary_archive.ReadBool( &ud_header.m_bLastSavedAsGoo );
4249 if (rc) rc = binary_archive.ReadInt( &ud_header.m_3dm_version );
4250 if (rc) rc = binary_archive.ReadInt( &ud_header.m_3dm_opennurbs_version );
4251 }
4252 }
4253 if ( !binary_archive.EndRead3dmChunk() ) // end of TCODE_OPENNURBS_CLASS_USERDATA_HEADER
4254 rc = 0;
4255 }
4256
4257 if (!rc)
4258 {
4259 ON_ERROR("Unable to read user data header information.");
4260 return false;
4261 }
4262
4263 if ( 0 == ud_header.m_3dm_version || 0 == ud_header.m_3dm_opennurbs_version )
4264 {
4265 // The userdata was saved in in an archive before
4266 // the 3dm_version and 3dm_opennurbs_version were saved in
4267 // userdata headers. This means it has to be userdata
4268 // with 4 byte chunk lengths. If the archive we are
4269 // reading was written with a newer version of opennurbs
4270 // that does save the 3dm version info, then this unknown
4271 // userdata was that has persisted through multiple read/write
4272 // cycles and we cannot tell it's original version. So we
4273 // will default to a maximum of 5 and 200910180 - the
4274 // 3dm versions just before we started saving 3dm
4275 // version info n userdata headers.
4276 if ( binary_archive.Archive3dmVersion() < 50 )
4277 {
4278 ud_header.m_3dm_version = binary_archive.Archive3dmVersion();
4279 }
4280 else
4281 {
4282 // All Archive3dmVersion() >= 50 have userdata_3dm_version info,
4283 // so this userdata had to be saved as goo from a version 5 or
4284 // earlier archive.
4285 ud_header.m_bLastSavedAsGoo = true;
4286 ud_header.m_3dm_version = 5;
4287 }
4288 ud_header.m_3dm_opennurbs_version = binary_archive.ArchiveOpenNURBSVersion();
4289 if ( ud_header.m_3dm_opennurbs_version >= 200910190 )
4290 {
4291 ud_header.m_3dm_opennurbs_version = 200910180;
4292 ud_header.m_bLastSavedAsGoo = true;
4293 }
4294 }
4295
4296 return rc;
4297 }
4298
ReadObjectUserData(ON_Object & object)4299 bool ON_BinaryArchive::ReadObjectUserData( ON_Object& object )
4300 {
4301 bool rc = true;
4302 while(rc)
4303 {
4304 ON_ReadChunkHelper ch(*this);
4305 if ( !ch.m_bReadSuccess )
4306 {
4307 rc = false;
4308 break;
4309 }
4310
4311 if ( TCODE_OPENNURBS_CLASS_END == ch.m_chunk_tcode )
4312 {
4313 // A short TCODE_OPENNURBS_CLASS_END chunk marks the end of the opennurbs class
4314 break; // done
4315 }
4316
4317 if ( TCODE_OPENNURBS_CLASS_USERDATA != ch.m_chunk_tcode )
4318 {
4319 // skip new chunk type added by later version
4320 continue;
4321 }
4322
4323 if ( ch.m_chunk_value < (ON__INT64)(8 + 4 * SizeofChunkLength()) )
4324 {
4325 ON_ERROR("TCODE_OPENNURBS_CLASS_USERDATA chunk is too short");
4326 continue;
4327 }
4328
4329 // Read userdata header information
4330 int major_userdata_version = 0;
4331 int minor_userdata_version = 0;
4332 rc = Read3dmChunkVersion( &major_userdata_version, &minor_userdata_version );
4333 if ( !rc )
4334 {
4335 ON_ERROR("Unable to read TCODE_OPENNURBS_CLASS_USERDATA chunk version numbers");
4336 break;
4337 }
4338
4339 if ( major_userdata_version < 1 || major_userdata_version > 2 )
4340 {
4341 // unsupported version - too old or added in new version
4342 continue;
4343 }
4344
4345 CUserDataHeaderInfo ud_header;
4346 rc = ReadObjectUserDataHeaderHelper(*this,major_userdata_version,minor_userdata_version,ud_header);
4347 if (!rc)
4348 {
4349 ON_ERROR("Unable to read user data header information.");
4350 break;
4351 }
4352
4353 // we should be ready to read a TCODE_ANONYMOUS_CHUNK containing userdata
4354 ON__INT64 length_TCODE_ANONYMOUS_CHUNK = 0;
4355 for(;;)
4356 {
4357 ON__UINT32 t = 0;
4358 rc = PeekAt3dmBigChunkType( &t, &length_TCODE_ANONYMOUS_CHUNK );
4359 if (!rc)
4360 break;
4361 if ( t != TCODE_ANONYMOUS_CHUNK )
4362 {
4363 ON_ERROR("Reading object user data - unable to find TCODE_ANONYMOUS_CHUNK");
4364 rc = false;
4365 break;
4366 }
4367 if ( length_TCODE_ANONYMOUS_CHUNK < 4 )
4368 {
4369 ON_ERROR("Reading object user data - length of TCODE_ANONYMOUS_CHUNK < 4");
4370 rc = false;
4371 break;
4372 }
4373 break;
4374 }
4375 if (!rc)
4376 {
4377 break;
4378 }
4379
4380 // attempt to get an instance of the userdata class that saved this information
4381 ON_UserData* ud = 0;
4382 for(;;)
4383 {
4384 const ON_ClassId* udId = ON_ClassId::ClassId( ud_header.m_classid );
4385 if ( 0 == udId )
4386 {
4387 // The application that created this userdata is not active
4388 if ( !ON_UuidIsNil(ud_header.m_appid) )
4389 {
4390 // see if we can load the application
4391 if ( 1 == LoadUserDataApplication(ud_header.m_appid) )
4392 {
4393 // try again
4394 udId = ON_ClassId::ClassId( ud_header.m_classid );
4395 }
4396 }
4397
4398 if ( 0 == udId )
4399 {
4400 // The application that created this user data is
4401 // not available. This information will be stored
4402 // in an ON_UnknownUserData class so that it can
4403 // persist.
4404 udId = &ON_UnknownUserData::m_ON_UnknownUserData_class_id;
4405 }
4406 }
4407
4408 ON_Object* tmp = udId->Create();
4409 ud = ON_UserData::Cast(tmp);
4410 if ( 0 == ud )
4411 {
4412 ON_ERROR("Reading object user data - unable to create userdata class");
4413 if ( tmp )
4414 delete tmp;
4415 tmp = 0;
4416 break;
4417 }
4418 tmp = 0;
4419
4420 break;
4421 }
4422
4423 if ( 0 == ud )
4424 {
4425 // no luck on this one
4426 // One reason can be that the plug-in userdata class has something wrong with
4427 // its ON_OBJECT_DECLARE/ON_OBJECT_IMPLEMENT stuff.
4428 ON_ERROR("Unable to create object user data class. Flawed class id information.");
4429 continue; // keep trying
4430 }
4431
4432 if ( ON_UuidIsNil(ud->m_application_uuid) )
4433 {
4434 if ( ON_UuidIsNil(ud_header.m_appid) )
4435 {
4436 switch( Archive3dmVersion())
4437 {
4438 case 2:
4439 // V2 archives do not contain app ids.
4440 // This id flags the userdata as being read from a V3 archive.
4441 ud_header.m_appid = ON_v2_userdata_id;
4442 break;
4443 case 3:
4444 // V3 archives do not contain app ids.
4445 // This id flags the userdata as being
4446 // read from a V3 archive.
4447 ud_header.m_appid = ON_v3_userdata_id;
4448 break;
4449 case 4:
4450 if ( ArchiveOpenNURBSVersion() < 200909190 )
4451 {
4452 // V4 archives before version 200909190
4453 // did not require user data application ids.
4454 ud_header.m_appid = ON_v4_userdata_id;
4455 }
4456 break;
4457 }
4458 }
4459 ud->m_application_uuid = ud_header.m_appid;
4460 }
4461 ud->m_userdata_uuid = ud_header.m_itemid;
4462 ud->m_userdata_copycount = ud_header.m_copycount;
4463 ud->m_userdata_xform = ud_header.m_xform;
4464 if ( ud->IsUnknownUserData() )
4465 {
4466 ON_UnknownUserData* uud = ON_UnknownUserData::Cast(ud);
4467 if ( uud )
4468 {
4469 uud->m_sizeof_buffer = (int)length_TCODE_ANONYMOUS_CHUNK;
4470 uud->m_unknownclass_uuid = ud_header.m_classid;
4471 uud->m_3dm_version = ud_header.m_3dm_version;
4472 uud->m_3dm_opennurbs_version = ud_header.m_3dm_opennurbs_version;
4473 }
4474 }
4475 ud->m_userdata_owner = &object; // so reading code can look at owner
4476 bool bReadUserData = ReadObjectUserDataAnonymousChunk(
4477 length_TCODE_ANONYMOUS_CHUNK,
4478 ud_header.m_3dm_version,
4479 ud_header.m_3dm_opennurbs_version,
4480 ud
4481 );
4482 ud->m_userdata_owner = 0;
4483 if (bReadUserData)
4484 {
4485 if ( !object.AttachUserData( ud ) )
4486 delete ud;
4487 }
4488 else
4489 {
4490 delete ud;
4491 }
4492 }
4493
4494 return rc;
4495 }
4496
Write3dmChunkVersion(int major_version,int minor_version)4497 bool ON_BinaryArchive::Write3dmChunkVersion(
4498 int major_version, // major // 0 to 15
4499 int minor_version // minor // 0 to 16
4500 )
4501 {
4502 const unsigned char v = (unsigned char)(major_version*16+minor_version);
4503 return WriteChar( v );
4504 }
4505
Read3dmChunkVersion(int * major_version,int * minor_version)4506 bool ON_BinaryArchive::Read3dmChunkVersion(
4507 int* major_version, // major // 0 to 15
4508 int* minor_version // minor // 0 to 16
4509 )
4510 {
4511 unsigned char v = 0;
4512 bool rc = ReadChar( &v );
4513 if ( minor_version) *minor_version = v%16;
4514 // The bit shift happens on the fly in the following
4515 // if statement. It was happening twice which always
4516 // set the major version to 0
4517 //v >>= 4;
4518 if ( major_version) *major_version = (v>>4);
4519 return rc;
4520 }
4521
Archive3dmVersion() const4522 int ON_BinaryArchive::Archive3dmVersion() const
4523 {
4524 return m_3dm_version;
4525 }
4526
ArchiveOpenNURBSVersion() const4527 int ON_BinaryArchive::ArchiveOpenNURBSVersion() const
4528 {
4529 return m_3dm_opennurbs_version;
4530 }
4531
ArchiveStartOffset() const4532 size_t ON_BinaryArchive::ArchiveStartOffset() const
4533 {
4534 return m_3dm_start_section_offset;
4535 }
4536
4537 /////////////////////////////////////////////////////////////////////////
4538 /////////////////////////////////////////////////////////////////////////
4539 /////////////////////////////////////////////////////////////////////////
4540
4541 bool
BeginWrite3dmChunk(unsigned int typecode,int value)4542 ON_BinaryArchive::BeginWrite3dmChunk( unsigned int typecode, int value )
4543 {
4544 /*// G+Smo
4545 ON__INT64 value64 = 0;
4546 if ( 0 != value )
4547 {
4548 if ( ON_IsUnsignedChunkTypecode(typecode) )
4549 {
4550 // treat value parameter as an unsigned int
4551 ON__UINT32 u32 = (ON__UINT32)value;
4552 ON__UINT64 u64 = u32;
4553 value64 = (ON__INT64)u64;
4554 }
4555 else
4556 {
4557 // treat value paramter is a signed int
4558 value64 = value;
4559 }
4560 }
4561 */
4562 return BeginWrite3dmBigChunk(typecode,value);
4563 }
4564
4565 bool
BeginWrite3dmBigChunk(ON__UINT32 typecode,ON__INT64 value64)4566 ON_BinaryArchive::BeginWrite3dmBigChunk( ON__UINT32 typecode, ON__INT64 value64 )
4567 {
4568 m_bDoChunkCRC = false; // no CRC on chunks because length is written twice.
4569 bool rc = WriteInt32( 1, (ON__INT32*)&typecode );
4570 if (rc)
4571 rc = WriteChunkValue( typecode, value64 );
4572 if (rc)
4573 rc = PushBigChunk( typecode, value64 );
4574 return rc;
4575 }
4576
4577 bool
BeginWrite3dmChunk(unsigned int tcode,int major_version,int minor_version)4578 ON_BinaryArchive::BeginWrite3dmChunk(
4579 unsigned int tcode,
4580 int major_version,
4581 int minor_version
4582 )
4583 {
4584 bool rc = false;
4585 if ( 0 == tcode )
4586 {
4587 ON_ERROR("ON_BinaryArchive::BeginWrite3dmChunk - input tcode = 0");
4588 }
4589 else if ( 0 != (tcode & TCODE_SHORT) )
4590 {
4591 ON_ERROR("ON_BinaryArchive::BeginWrite3dmChunk - input tcode has short flag set.");
4592 }
4593 else if ( major_version <= 0 )
4594 {
4595 ON_ERROR("ON_BinaryArchive::BeginWrite3dmChunk - input major_version <= 0.");
4596 }
4597 else if ( minor_version < 0 )
4598 {
4599 ON_ERROR("ON_BinaryArchive::BeginWrite3dmChunk - input minor_version < 0.");
4600 }
4601 else
4602 {
4603 rc = BeginWrite3dmChunk(tcode,0);
4604 if (rc)
4605 {
4606 rc = WriteInt(major_version);
4607 if (rc)
4608 rc = WriteInt(minor_version);
4609 if ( !rc)
4610 EndWrite3dmChunk();
4611 }
4612 }
4613 return rc;
4614 }
4615
4616 bool
EndWrite3dmChunk()4617 ON_BinaryArchive::EndWrite3dmChunk()
4618 {
4619 bool rc = false;
4620 ON_3DM_BIG_CHUNK* c = m_chunk.Last();
4621 if ( c ) {
4622 if ( c->m_bLongChunk )
4623 {
4624 if ( c->m_do_crc16 )
4625 {
4626 // write 16 bit CRC
4627 unsigned char two_zero_bytes[2] = {0,0};
4628 ON__UINT16 crc = ON_CRC16( c->m_crc16, 2, two_zero_bytes );
4629 rc = WriteInt16( 1, (ON__INT16*)&crc );
4630 if (c->m_crc16)
4631 {
4632 // should never happen unless ON_CRC16() code is damaged
4633 m_bad_CRC_count++;
4634 ON_ERROR("ON_BinaryArchive::EndWrite3dmChunk: CRC16 computation error.");
4635 }
4636 }
4637 else if ( c->m_do_crc32 )
4638 {
4639 // write 32 bit CRC
4640 const ON__UINT32 crc0 = c->m_crc32;
4641 rc = WriteInt32( 1, (ON__INT32*)&crc0 );
4642 }
4643 else {
4644 rc = true;
4645 }
4646
4647 // write length
4648 m_bDoChunkCRC = 0;
4649 const size_t offset = CurrentPosition();
4650 if ( offset < c->m_big_offset )
4651 {
4652 ON_ERROR("ON_BinaryArchive::EndWrite3dmChunk() - chunk length < 0");
4653 rc = false;
4654 }
4655 else
4656 {
4657 ON__UINT64 length = (offset - c->m_big_offset);
4658 if ( !BigSeekBackward( length + SizeofChunkLength() ) )
4659 {
4660 rc = false;
4661 }
4662 else
4663 {
4664 if ( !WriteChunkLength( length ) )
4665 {
4666 rc = false;
4667 }
4668 if ( !BigSeekForward( length ) )
4669 {
4670 rc = false;
4671 }
4672 }
4673 if ( CurrentPosition() != offset )
4674 {
4675 ON_ERROR("ON_BinaryArchive::EndWrite3dmChunk() - CurrentPosition() != offset");
4676 rc = false;
4677 }
4678 }
4679 }
4680 else
4681 {
4682 // "short" chunks are completely written by call to BeginWrite3dmChunk().
4683 rc = true;
4684 }
4685
4686 m_chunk.Remove();
4687 c = m_chunk.Last();
4688 if ( !c )
4689 {
4690 Flush();
4691 }
4692 m_bDoChunkCRC = c && (c->m_do_crc16 || c->m_do_crc32);
4693 }
4694 return rc;
4695 }
4696
Write3dmGoo(const ON_3dmGoo & goo)4697 bool ON_BinaryArchive::Write3dmGoo( const ON_3dmGoo& goo )
4698 {
4699 bool rc = false;
4700
4701 if ( goo.m_typecode ) {
4702 const bool savedDoCRC = m_bDoChunkCRC;
4703 m_bDoChunkCRC = false;
4704 if ( 0 != (goo.m_typecode & TCODE_SHORT) ) {
4705 if ( goo.m_value == 0 || (goo.m_value > 0 && goo.m_goo) ) {
4706 // write long chunk - do not use Begin/EndWrite3dmChunk() because
4707 // goo may contain subchunks and CRC would be
4708 // incorrectly computed.
4709 rc = WriteInt( goo.m_typecode );
4710 if (rc) rc = WriteInt( goo.m_value );
4711 if (rc && goo.m_value>0) rc = WriteByte( goo.m_value, goo.m_goo );
4712 }
4713 }
4714 else {
4715 // write short chunk
4716 rc = WriteInt( goo.m_typecode );
4717 if (rc) rc = WriteInt( goo.m_value );
4718 }
4719 m_bDoChunkCRC = savedDoCRC;
4720 }
4721
4722 return rc;
4723 }
4724
PeekAt3dmChunkType(unsigned int * typecode,int * value)4725 bool ON_BinaryArchive::PeekAt3dmChunkType( unsigned int* typecode, int* value )
4726 {
4727 // does not change file position
4728 bool rc;
4729 unsigned int tc = 0;
4730 ON__INT64 i64 = 0;
4731 rc = PeekAt3dmBigChunkType(&tc,&i64);
4732 if ( rc )
4733 {
4734 if ( 0 != typecode )
4735 *typecode = tc;
4736 if ( 0 != value )
4737 {
4738 ON__INT32 i32 = 0;
4739 if ( ON_IsUnsignedChunkTypecode(tc) )
4740 rc = DownSizeUINT((ON__UINT64)i64,(ON__UINT32*)&i32);
4741 else
4742 rc = DownSizeINT(i64,&i32);
4743 *value = i32;
4744 }
4745 }
4746 return rc;
4747 }
4748
PeekAt3dmBigChunkType(unsigned int * typecode,ON__INT64 * big_value)4749 bool ON_BinaryArchive::PeekAt3dmBigChunkType(
4750 unsigned int* typecode,
4751 ON__INT64* big_value
4752 )
4753 {
4754 // does not change file position
4755
4756 // 10 January 2005 Dale Lear
4757 // Do not let the "peeking" affect the CRC.
4758 bool bDoChunkCRC = m_bDoChunkCRC;
4759 m_bDoChunkCRC = false;
4760
4761 const ON__UINT64 pos0 = CurrentPosition();
4762 ON__UINT32 t = 0;
4763 ON__INT64 v = 0;
4764 bool rc = ReadChunkTypecode( &t );
4765 if (rc)
4766 {
4767 rc = ReadChunkValue( t, &v );
4768 }
4769 const ON__UINT64 pos1 = CurrentPosition();
4770 if ( pos1 > pos0 && !BigSeekBackward( pos1-pos0 ) )
4771 {
4772 rc = false;
4773 }
4774
4775 m_bDoChunkCRC = bDoChunkCRC;
4776
4777 if ( typecode )
4778 *typecode = t;
4779 if ( big_value )
4780 *big_value = v;
4781
4782 return rc;
4783 }
4784
4785
Seek3dmChunkFromStart(unsigned int typecode)4786 bool ON_BinaryArchive::Seek3dmChunkFromStart(
4787 // beginning at the start of the active chunk, search portion of
4788 // archive included in active chunk for the start of a subchunk
4789 // with the specified type.
4790 // if true is returned, then the position is set so the next call to
4791 // BeginRead3dmChunk() will read a chunk with the specified typecode
4792 unsigned int typecode // typecode from opennurbs_3dm.h
4793 )
4794 {
4795 bool rc = false;
4796 if ( ReadMode() )
4797 {
4798 const ON__UINT64 pos0 = CurrentPosition();
4799 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
4800 if ( c )
4801 {
4802 // set archive position to the beginning of this chunk
4803 if ( !ON_IsLongChunkTypecode(c->m_typecode) )
4804 {
4805 ON_ERROR("ON_BinaryArchive::Seek3dmChunkFromStart() - current chunk is not a long chunk");
4806 return false;
4807 }
4808 if ( c->m_big_value < 0 )
4809 {
4810 ON_ERROR("ON_BinaryArchive::Seek3dmChunkFromStart() called with an active chunk that has m_value < 0");
4811 return false;
4812 }
4813 if ( pos0 < c->m_big_offset || pos0 > c->m_big_offset + c->Length() )
4814 {
4815 ON_ERROR("ON_BinaryArchive::Seek3dmChunkFromStart() called with out of bounds current position");
4816 return false;
4817 }
4818 rc = BigSeekBackward( pos0 - c->m_big_offset ); // pos0 >= c->m_offset, so this size_t subtraction is ok
4819 }
4820 else
4821 {
4822 // set archive position to the beginning of archive chunks by skipping
4823 // 32 byte version info and any start section padding.
4824 size_t start_offset = ((m_3dm_start_section_offset > 0) ? m_3dm_start_section_offset : 0);
4825 rc = SeekFromStart( start_offset );
4826 if (!rc && start_offset > 0)
4827 {
4828 start_offset = 0;
4829 rc = SeekFromStart(start_offset);
4830 }
4831 char s3d[33];
4832 memset(s3d,0,sizeof(s3d));
4833 if (rc)
4834 rc = ReadByte(32,s3d);
4835
4836 if (rc)
4837 {
4838 rc = (0 == strncmp( s3d, "3D Geometry File Format ", 24));
4839 if ( !rc && start_offset > 0 )
4840 {
4841 start_offset = 0;
4842 rc = SeekFromStart(start_offset);
4843 if (rc) rc = ReadByte(32,s3d);
4844 rc = (0 == strncmp( s3d, "3D Geometry File Format ", 24));
4845 }
4846 }
4847
4848 if (rc)
4849 {
4850 if ( start_offset != m_3dm_start_section_offset )
4851 m_3dm_start_section_offset = start_offset;
4852 unsigned int t=0;
4853 ON__INT64 v=-1;
4854 rc = PeekAt3dmBigChunkType(&t,&v);
4855 if (rc && (t != 1 || v < 0) )
4856 rc = false;
4857 }
4858 }
4859
4860 if (rc)
4861 {
4862 rc = Seek3dmChunkFromCurrentPosition( typecode );
4863 }
4864
4865 if (!rc)
4866 {
4867 BigSeekFromStart(pos0);
4868 }
4869 }
4870 return rc;
4871 }
4872
Length() const4873 ON__UINT64 ON_3DM_BIG_CHUNK::Length() const
4874 {
4875 return (ON_IsLongChunkTypecode(m_typecode) && m_big_value >= 0 )
4876 ? ((ON__UINT64)m_big_value)
4877 : 0;
4878 }
4879
Seek3dmChunkFromCurrentPosition(unsigned int typecode)4880 bool ON_BinaryArchive::Seek3dmChunkFromCurrentPosition(
4881 // beginning at the current position, search portion of archive
4882 // included in active chunk for the start of a subchunk with the
4883 // specified type.
4884 // if true is returned, then the position is set so the next call to
4885 // BeginRead3dmChunk() will read a chunk with the specified typecode
4886 unsigned int typecode // typecode from opennurbs_3dm.h
4887 )
4888 {
4889 bool rc = false;
4890 if ( ReadMode() )
4891 {
4892 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
4893 const ON__UINT64 pos1 = c ? c->m_big_offset + c->Length() : 0;
4894 const size_t pos_start = CurrentPosition();
4895 size_t pos_prev = 0;
4896 size_t pos = 0;
4897 unsigned int t;
4898 ON__INT64 v64;
4899 bool bFirstTime = true;
4900 while(pos > pos_prev || bFirstTime)
4901 {
4902 bFirstTime = false;
4903 pos_prev = pos;
4904 pos = CurrentPosition();
4905 if ( pos1 && pos > pos1 )
4906 break;
4907 t = !typecode;
4908 if ( !PeekAt3dmBigChunkType( &t, 0 ) )
4909 break;
4910 if ( t == typecode )
4911 {
4912 rc = true;
4913 break;
4914 }
4915 if ( 0 == t )
4916 {
4917 // zero is not a valid typecode - file is corrupt at or before this position
4918 break;
4919 }
4920 if ( !BeginRead3dmBigChunk( &t, &v64 ) )
4921 break;
4922 if ( !EndRead3dmChunk() )
4923 break;
4924 if ( TCODE_ENDOFTABLE == t && 0 != v64 )
4925 {
4926 // TCODE_ENDOFTABLE chunks always have value = 0 - file is corrupt at or before this position
4927 break;
4928 }
4929 }
4930 if ( !rc )
4931 {
4932 SeekFromStart( pos_start );
4933 }
4934 }
4935 return rc;
4936 }
4937
BeginRead3dmChunk(unsigned int * typecode,int * value)4938 bool ON_BinaryArchive::BeginRead3dmChunk( unsigned int* typecode, int* value )
4939 {
4940 ON__UINT32 tc = 0;
4941 ON__INT64 v64 = 0;
4942 bool rc = BeginRead3dmBigChunk(&tc,&v64);
4943 if (rc)
4944 {
4945 if ( 0 != typecode )
4946 *typecode = tc;
4947 rc = DownSizeChunkValue(tc,v64,value);
4948 }
4949 return rc;
4950 }
4951
BeginRead3dmBigChunk(unsigned int * typecode,ON__INT64 * value)4952 bool ON_BinaryArchive::BeginRead3dmBigChunk( unsigned int* typecode, ON__INT64* value )
4953 {
4954 ON__UINT32 t = 0;
4955 ON__INT64 v = 0;
4956 m_bDoChunkCRC = false; // no CRC on chunk headers because length is written twice
4957 const unsigned int saved_error_message_mask = m_error_message_mask;
4958 m_error_message_mask |= 0x0001; // disable ReadByte() error message at EOF
4959 bool rc = ReadChunkTypecode( &t );
4960 m_error_message_mask = saved_error_message_mask;
4961 if (rc)
4962 {
4963 if ( t == TCODE_ENDOFFILE )
4964 {
4965 // Either this chunk is a bona fide end of file mark, or it's "goo"
4966 // that Rhino 1.0 or the pre-February 2000 Rhino 1.1 saved and wrote.
4967 ON__UINT64 sizeof_file = 0;
4968 if ( rc )
4969 rc = ReadChunkValue( t, &v );
4970 if ( rc && v >= 0 && ((ON__UINT64)v) >= SizeofChunkLength() )
4971 {
4972 ON__UINT64 EOF_chunk_length = (ON__UINT64)v;
4973 ON__UINT64 pos0 = CurrentPosition();
4974 rc = ReadEOFSizeOfFile( &sizeof_file );
4975 ON__UINT64 pos1 = CurrentPosition();
4976 if ( pos0 > 0 && pos1 > pos0 )
4977 {
4978 if ( !BigSeekBackward(pos1-pos0) )
4979 rc = false;
4980 }
4981 if ( rc )
4982 {
4983 if ( BigSeekForward( EOF_chunk_length ) )
4984 {
4985 ON__UINT64 pos2 = CurrentPosition();
4986 if ( m_3dm_version <= 1 )
4987 {
4988 if ( !AtEnd() )
4989 {
4990 // Rhino v1 reads chunks with unknown typecodes as a block of "goo"
4991 // and then saves them back into file. When this happens to an
4992 // eof marker, we get TCODE_ENDOFFILE chunks in the middle of a file.
4993 // This can only happen in m_3dm_version = 1 files.
4994 t = TCODE_ENDOFFILE_GOO;
4995 }
4996 }
4997 else
4998 {
4999 // check that current position matches saved file size
5000 if ( pos2 != sizeof_file ) {
5001 ON_ERROR("ON_BinaryArchive::BeginRead3dmChunk() - Rogue eof marker in v2 file.\n");
5002 }
5003 }
5004 rc = BigSeekBackward( EOF_chunk_length );
5005 }
5006 }
5007 if ( rc )
5008 rc = PushBigChunk( t, v );
5009 }
5010 else
5011 {
5012 ON_ERROR( "ON_BinaryArchive::BeginRead3dmChunk() - file is damaged." );
5013 rc = false;
5014 t = 0; // ?? file is trashed ??
5015 }
5016 }
5017 else
5018 {
5019 if ( rc )
5020 rc = ReadChunkValue( t, &v );
5021 if ( rc )
5022 rc = PushBigChunk( t, v );
5023 }
5024 }
5025 if ( typecode )
5026 *typecode = t;
5027 if ( value )
5028 *value = v;
5029 return rc;
5030 }
5031
5032 bool
BeginRead3dmChunk(unsigned int expected_tcode,int * major_version,int * minor_version)5033 ON_BinaryArchive::BeginRead3dmChunk(
5034 unsigned int expected_tcode,
5035 int* major_version,
5036 int* minor_version
5037 )
5038 {
5039 bool rc = false;
5040 if ( 0 == expected_tcode )
5041 {
5042 ON_ERROR("ON_BinaryArchive::BeginRead3dmChunk - input expected_tcode = 0");
5043 }
5044 else if ( 0 != (expected_tcode & TCODE_SHORT) )
5045 {
5046 ON_ERROR("ON_BinaryArchive::BeginRead3dmChunk - input expected_tcode has short flag set.");
5047 }
5048 else if ( 0 == major_version )
5049 {
5050 ON_ERROR("ON_BinaryArchive::BeginRead3dmChunk - input major_version NULL");
5051 }
5052 else if ( 0 == minor_version )
5053 {
5054 ON_ERROR("ON_BinaryArchive::BeginRead3dmChunk - input minor_version NULL");
5055 }
5056 else
5057 {
5058 *major_version = 0;
5059 *minor_version = 0;
5060 unsigned int tcode = 0;
5061 ON__INT64 value = 0;
5062 rc = PeekAt3dmBigChunkType(&tcode,&value);
5063 if ( expected_tcode != tcode )
5064 {
5065 ON_ERROR("ON_BinaryArchive::BeginRead3dmChunk - unexpected tcode");
5066 rc = false;
5067 }
5068 else if ( value < 8 )
5069 {
5070 ON_ERROR("ON_BinaryArchive::BeginRead3dmChunk - unexpected chunk length");
5071 rc = false;
5072 }
5073 else
5074 {
5075 tcode = 0;
5076 value = 0;
5077 rc = BeginRead3dmBigChunk(&tcode,&value);
5078 if (rc)
5079 {
5080 if ( expected_tcode != tcode || value < 8 )
5081 {
5082 // can happen when seek fails
5083 ON_ERROR("ON_BinaryArchive::BeginRead3dmChunk - unexpected tcode or chunk length - archive driver or device may be bad");
5084 rc = false;
5085 }
5086 else
5087 {
5088 rc = ReadInt(major_version);
5089 if ( rc && *major_version < 1 )
5090 {
5091 ON_ERROR("ON_BinaryArchive::BeginRead3dmChunk - major_version < 1");
5092 rc = false;
5093 }
5094 if (rc)
5095 {
5096 rc = ReadInt(minor_version);
5097 if ( rc && *minor_version < 0 )
5098 {
5099 ON_ERROR("ON_BinaryArchive::BeginRead3dmChunk - minor_version < 0");
5100 rc = false;
5101 }
5102 }
5103 }
5104
5105 if ( !rc )
5106 {
5107 // this is required to keep chunk accounting in synch
5108 EndRead3dmChunk();
5109 }
5110 }
5111 }
5112 }
5113 return rc;
5114 }
EndRead3dmChunk()5115 bool ON_BinaryArchive::EndRead3dmChunk()
5116 {
5117 return EndRead3dmChunk(false);
5118 }
5119
EndRead3dmChunk(bool bSupressPartiallyReadChunkWarning)5120 bool ON_BinaryArchive::EndRead3dmChunk(bool bSupressPartiallyReadChunkWarning)
5121 {
5122 //int length = 0;
5123 bool rc = false;
5124 ON_3DM_BIG_CHUNK* c = m_chunk.Last();
5125 if ( c )
5126 {
5127 ON__UINT64 file_offset = CurrentPosition();
5128 ON__UINT64 end_offset = c->m_big_offset;
5129 if ( c->m_bLongChunk )
5130 {
5131 if ( c->m_big_value < 0 )
5132 {
5133 ON_ERROR("ON_BinaryArchive::EndRead3dmChunk - negative chunk length");
5134 }
5135 else
5136 {
5137 end_offset += ((ON__UINT64)c->m_big_value);
5138 }
5139 }
5140
5141 if ( c->m_bLongChunk )
5142 {
5143 if ( c->m_do_crc16 )
5144 {
5145 if ( file_offset+2 == end_offset )
5146 {
5147 // read 16 bit CRC
5148 unsigned char two_crc_bytes[2] = {0,0};
5149 rc = ReadByte( 2, two_crc_bytes );
5150 if (rc)
5151 {
5152 file_offset+=2;
5153 if (c->m_crc16)
5154 {
5155 m_bad_CRC_count++;
5156 ON_ERROR("ON_BinaryArchive::EndRead3dmChunk: CRC16 error.");
5157 }
5158 }
5159 }
5160 else
5161 {
5162 // partially read chunk - crc check not possible.
5163 rc = true;
5164 }
5165 }
5166 else if ( c->m_do_crc32 )
5167 {
5168 if ( file_offset+4 == end_offset )
5169 {
5170 // read 32 bit CRC
5171 ON__UINT32 crc1 = c->m_crc32;
5172 ON__UINT32 crc0;
5173 rc = ReadInt32( 1, (ON__INT32*)&crc0 );
5174 if (rc)
5175 {
5176 file_offset+=4;
5177 if (crc0 != crc1)
5178 {
5179 m_bad_CRC_count++;
5180 ON_ERROR("ON_BinaryArchive::EndRead3dmChunk: CRC32 error.");
5181 }
5182 }
5183 }
5184 else
5185 {
5186 // partially read chunk - crc check not possible.
5187 rc = true;
5188 }
5189 }
5190 else
5191 {
5192 // no crc in this chunk
5193 rc = true;
5194 }
5195 }
5196 else
5197 {
5198 rc = true;
5199 }
5200
5201 // check length and seek to end of chunk if things are amiss
5202 if ( file_offset < c->m_big_offset )
5203 {
5204 ON_ERROR("ON_BinaryArchive::EndRead3dmChunk: current position before start of current chunk.");
5205 if ( !BigSeekFromStart( end_offset ) )
5206 rc = false;
5207 }
5208 else if ( file_offset > end_offset )
5209 {
5210 ON_ERROR("ON_BinaryArchive::EndRead3dmChunk: current position after end of current chunk.");
5211 if ( !BigSeekFromStart( end_offset ) )
5212 rc = false;
5213 }
5214 else if ( file_offset != end_offset )
5215 {
5216 // partially read chunk - happens when chunks are skipped or old code
5217 // reads a new minor version of a chunk whnich has added information.
5218 if ( file_offset != c->m_big_offset )
5219 {
5220 if ( m_3dm_version != 1 || (m_error_message_mask&0x02) == 0 )
5221 {
5222 // when reading v1 files, there are some situations where
5223 // it is reasonable to attempt to read 4 bytes at the end
5224 // of a file. The above test prevents making a call
5225 // to ON_WARNING() in these situations.
5226
5227 const int app_opennurbs_version = ON::Version();
5228 const int filev_date = m_3dm_opennurbs_version/10;
5229 const int appv_date = app_opennurbs_version/10;
5230 int file_v = m_3dm_opennurbs_version%10;
5231 int app_v = app_opennurbs_version%10;
5232 if ( 9 == file_v || 9 == app_v )
5233 {
5234 // 9 means DEBUG opennurbs was used to write the file.
5235 file_v = app_v = 0;
5236 }
5237 if ( file_v <= app_v && filev_date <= appv_date )
5238 {
5239 // We are reading a file written by this version or an
5240 // earlier version of opennurbs.
5241 // There should not be any partially read chunks.
5242 if (!bSupressPartiallyReadChunkWarning)
5243 {
5244 ON_WARNING("ON_BinaryArchive::EndRead3dmChunk: partially read chunk - skipping bytes at end of current chunk.");
5245 }
5246 }
5247 }
5248 }
5249 //int delta = (end_offset >= file_offset)
5250 // ? ((int)(end_offset-file_offset))
5251 // : -((int)(file_offset-end_offset));
5252 //if ( !SeekFromCurrentPosition( delta ) )
5253 // rc = false;
5254 if ( end_offset > file_offset )
5255 {
5256 if ( !BigSeekForward(end_offset - file_offset) )
5257 rc = false;
5258 }
5259 else if ( end_offset < file_offset )
5260 {
5261 if ( !BigSeekBackward(file_offset - end_offset) )
5262 rc = false;
5263 }
5264 }
5265
5266 m_chunk.Remove();
5267 c = m_chunk.Last();
5268 m_bDoChunkCRC = (c && (c->m_do_crc16 || c->m_do_crc32));
5269 }
5270 return rc;
5271 }
5272
BeginWriteDictionary(ON_UUID dictionary_id,unsigned int version,const wchar_t * dictionary_name)5273 bool ON_BinaryArchive::BeginWriteDictionary(
5274 ON_UUID dictionary_id,
5275 unsigned int version,
5276 const wchar_t* dictionary_name
5277 )
5278 {
5279 #if defined(ON_COMPILER_MSC)
5280 // Disable the MSC /W4 "conditional expression is constant" warning
5281 // about sizeof(unsigned short) == sizeof(*dictionary_name).
5282 // Since this code has to run on machines where sizeof(wchar_t)
5283 // can be 2, 4, or 8 bytes, the test is necessary.
5284 #pragma warning( push )
5285 #pragma warning( disable : 4127 )
5286 #endif
5287
5288 bool rc = BeginWrite3dmChunk(TCODE_DICTIONARY,1,0);
5289 if ( !rc )
5290 return rc;
5291
5292 // Write dictionary id chunk
5293 rc = BeginWrite3dmChunk(TCODE_DICTIONARY_ID,1,0);
5294 if ( rc )
5295 {
5296 for(;;)
5297 {
5298 rc = WriteUuid(dictionary_id);
5299 if (!rc) break;
5300 rc = WriteInt(version);
5301 if (!rc) break;
5302 if ( sizeof(unsigned short) == sizeof(*dictionary_name) )
5303 {
5304 rc = WriteString((const unsigned short*)dictionary_name);
5305 }
5306 else
5307 {
5308 ON_wString s(dictionary_name);
5309 rc = WriteString(s);
5310 }
5311 if (!rc) break;
5312 break;
5313 }
5314 if ( !EndWrite3dmChunk() ) // TCODE_DICTIONARY_ID end
5315 rc = false;
5316 }
5317
5318 if ( !rc )
5319 EndWrite3dmChunk(); // TCODE_DICTIONARY end
5320 return rc;
5321
5322 #if defined(ON_COMPILER_MSC)
5323 #pragma warning( pop )
5324 #endif
5325 }
5326
EndWriteDictionary()5327 bool ON_BinaryArchive::EndWriteDictionary()
5328 {
5329 int chunk_count = m_chunk.Count();
5330 bool rc = ( chunk_count > 0 && TCODE_DICTIONARY == m_chunk[chunk_count-1].m_typecode );
5331 if (rc)
5332 {
5333 rc = BeginWrite3dmChunk(TCODE_DICTIONARY_END,0);
5334 if (rc)
5335 rc = EndWrite3dmChunk(); // TCODE_DICTIONARY_END
5336
5337 if ( !EndWrite3dmChunk() ) // TCODE_DICTIONARY
5338 rc = false;
5339 }
5340 return rc;
5341 }
5342
BeginWriteDictionaryEntry(int de_type,const wchar_t * entry_name)5343 bool ON_BinaryArchive::BeginWriteDictionaryEntry(
5344 int de_type,
5345 const wchar_t* entry_name
5346 )
5347 {
5348 #if defined(ON_COMPILER_MSC)
5349 // Disable the MSC /W4 "conditional expression is constant" warning
5350 // about sizeof(unsigned short) == sizeof(*entry_name).
5351 // Since this code has to run on machines where sizeof(wchar_t)
5352 // can be 2, 4, or 8 bytes, the test is necessary.
5353 #pragma warning( push )
5354 #pragma warning( disable : 4127 )
5355 #endif
5356
5357 bool rc = BeginWrite3dmChunk(TCODE_DICTIONARY_ENTRY,0);
5358 if ( rc )
5359 {
5360 for(;;)
5361 {
5362 rc = WriteInt(de_type);
5363 if (!rc) break;
5364 if ( sizeof(unsigned short) == sizeof(*entry_name) )
5365 {
5366 rc = WriteString((const unsigned short*)entry_name);
5367 }
5368 else
5369 {
5370 ON_wString s(entry_name);
5371 rc = WriteString(s);
5372 }
5373 if (!rc) break;
5374 break;
5375 }
5376 if ( !rc )
5377 EndWrite3dmChunk(); // TCODE_DICTIONARY_ENTRY
5378 }
5379 return rc;
5380
5381 #if defined(ON_COMPILER_MSC)
5382 #pragma warning( pop )
5383 #endif
5384 }
5385
EndWriteDictionaryEntry()5386 bool ON_BinaryArchive::EndWriteDictionaryEntry()
5387 {
5388 int chunk_count = m_chunk.Count();
5389 bool rc = ( chunk_count > 0 && TCODE_DICTIONARY_ENTRY == m_chunk[chunk_count-1].m_typecode )
5390 ? EndWrite3dmChunk()
5391 : false;
5392 return rc;
5393 }
5394
BeginReadDictionary(ON_UUID * dictionary_id,unsigned int * version,ON_wString & dictionary_name)5395 bool ON_BinaryArchive::BeginReadDictionary(
5396 ON_UUID* dictionary_id,
5397 unsigned int* version,
5398 ON_wString& dictionary_name
5399 )
5400 {
5401 int major_version = 0;
5402 int minor_version = 0;
5403 bool rc = BeginRead3dmChunk(TCODE_DICTIONARY,&major_version,&minor_version);
5404 if ( rc )
5405 {
5406 for(;;)
5407 {
5408 rc = (1 == major_version);
5409 if (!rc) break;
5410
5411 // Read dictionary id chunk
5412 rc = BeginRead3dmChunk(TCODE_DICTIONARY_ID,&major_version,&minor_version);
5413 if ( !rc ) break;
5414 for(;;)
5415 {
5416 rc = (1==major_version);
5417 if (!rc) break;
5418 ON_UUID id;
5419 rc = ReadUuid(id);
5420 if (!rc) break;
5421 if ( dictionary_id )
5422 *dictionary_id = id;
5423 rc = ReadInt(version);
5424 if (!rc) break;
5425 rc = ReadString(dictionary_name);
5426 if (!rc) break;
5427 break;
5428 }
5429 if ( !EndRead3dmChunk() ) // TCODE_DICTIONARY_ID end
5430 rc = false;
5431 break;
5432 }
5433
5434 if ( !rc )
5435 EndRead3dmChunk(); // TCODE_DICTIONARY end
5436 }
5437 return rc;
5438 }
5439
EndReadDictionary()5440 bool ON_BinaryArchive::EndReadDictionary()
5441 {
5442 int chunk_count = m_chunk.Count();
5443 bool rc = ( chunk_count > 0 && TCODE_DICTIONARY == m_chunk[chunk_count-1].m_typecode )
5444 ? EndRead3dmChunk()
5445 : false;
5446 return rc;
5447 }
5448
BeginReadDictionaryEntry(int * de_type,ON_wString & entry_name)5449 int ON_BinaryArchive::BeginReadDictionaryEntry(
5450 int* de_type,
5451 ON_wString& entry_name
5452 )
5453 {
5454 unsigned int tcode = 0;
5455 ON__INT64 chunk_length = 0;
5456 int chunk_count = m_chunk.Count();
5457 int rc = ( chunk_count > 0 && TCODE_DICTIONARY == m_chunk[chunk_count-1].m_typecode )
5458 ? (BeginRead3dmBigChunk(&tcode,&chunk_length)?1:0)
5459 : 0;
5460 if ( de_type )
5461 *de_type = 0;
5462 if ( rc )
5463 {
5464 if ( TCODE_DICTIONARY_ENTRY == tcode )
5465 {
5466 for(;;)
5467 {
5468 rc = 0;
5469 if ( !ReadInt(de_type) )
5470 {
5471 entry_name.Empty();
5472 break;
5473 }
5474 if ( !ReadString(entry_name) )
5475 {
5476 entry_name.Empty();
5477 break;
5478 }
5479 rc = 1;
5480 break;
5481 }
5482 }
5483 else
5484 {
5485 rc = (TCODE_DICTIONARY_END == tcode) ? 2 : 0;
5486 }
5487 if ( 1 != rc )
5488 {
5489 if ( !EndRead3dmChunk() )
5490 rc = 0;
5491 }
5492 }
5493 return rc;
5494 }
5495
EndReadDictionaryEntry()5496 bool ON_BinaryArchive::EndReadDictionaryEntry()
5497 {
5498 int chunk_count = m_chunk.Count();
5499 bool rc = ( chunk_count > 0 && TCODE_DICTIONARY_ENTRY == m_chunk[chunk_count-1].m_typecode )
5500 ? EndRead3dmChunk()
5501 : false;
5502 return rc;
5503 }
5504
5505
5506
Read3dmGoo(ON_3dmGoo & goo)5507 bool ON_BinaryArchive::Read3dmGoo( ON_3dmGoo& goo )
5508 {
5509 // goo is an entire "chunk" that is not short.
5510 // A call to EndRead3dmChunk() must immediately follow
5511 // the call to Read3dmGoo().
5512 bool rc = false;
5513 if (goo.m_goo)
5514 {
5515 onfree(goo.m_goo);
5516 goo.m_goo = 0;
5517 }
5518 goo.m_typecode = 0;
5519 goo.m_value = 0;
5520 ON_3DM_BIG_CHUNK* c = m_chunk.Last();
5521 if (c)
5522 {
5523 goo.m_typecode = c->m_typecode;
5524 if ( c->m_bLongChunk )
5525 rc = DownSizeUINT(c->Length(),(ON__UINT32*)&goo.m_value);
5526 else
5527 rc = DownSizeINT(c->m_big_value,&goo.m_value);
5528 if ( rc && c->m_bLongChunk && c->m_big_value > 0 )
5529 {
5530 if ( CurrentPosition() == c->m_big_offset )
5531 {
5532 // read the rest of this chunk into the goo.m_goo buffer.
5533 // 23 January 2004 Dale Lear:
5534 // Have to turn of CRC checking because the goo may contiain
5535 // subchunks. If a CRC exixts, it is at the end of the
5536 // goo and will persist until the application that
5537 // wrote this chunk is available to parse the chunk.
5538 c->m_do_crc16 = 0;
5539 c->m_do_crc32 = 0;
5540 m_bDoChunkCRC = false;
5541 size_t sizeof_goo = (size_t)c->Length();
5542 goo.m_goo = (unsigned char*)onmalloc( sizeof_goo );
5543 rc = ReadByte( sizeof_goo, goo.m_goo );
5544 }
5545 }
5546 }
5547 return rc;
5548 }
5549
WriteChunkTypecode(ON__UINT32 typecode)5550 bool ON_BinaryArchive::WriteChunkTypecode( ON__UINT32 typecode )
5551 {
5552 return WriteInt32(1,(ON__INT32*)&typecode);
5553 }
5554
ReadChunkTypecode(ON__UINT32 * typecode)5555 bool ON_BinaryArchive::ReadChunkTypecode( ON__UINT32* typecode )
5556 {
5557 ON__UINT32 tc = 0;
5558 bool rc = ReadInt32(1,(ON__INT32*)&tc);
5559 if (rc && typecode )
5560 *typecode = tc;
5561 return rc;
5562 }
5563
WriteChunkValue(ON__UINT32 typecode,ON__INT64 big_value)5564 bool ON_BinaryArchive::WriteChunkValue( ON__UINT32 typecode, ON__INT64 big_value )
5565 {
5566 bool rc;
5567 if ( 8 == SizeofChunkLength() )
5568 {
5569 rc = WriteInt64(1,&big_value);
5570 }
5571 else if ( ON_IsUnsignedChunkTypecode(typecode) )
5572 {
5573 // treat big_value as an unsigned int
5574 ON__UINT32 u32 = 0;
5575 rc = DownSizeUINT((ON__UINT64)big_value,&u32);
5576 if ( !WriteInt32(1,(ON__INT32*)&u32) )
5577 rc = false;
5578 }
5579 else
5580 {
5581 // treat big_value as a signed int
5582 ON__INT32 v32 = 0;
5583 rc = DownSizeINT(big_value,&v32);
5584 if ( !WriteInt32(1,&v32) )
5585 rc = false;
5586 }
5587 return rc;
5588 }
5589
5590
WriteChunkLength(ON__UINT64 length)5591 bool ON_BinaryArchive::WriteChunkLength( ON__UINT64 length )
5592 {
5593 bool rc;
5594 if ( 8 == SizeofChunkLength() )
5595 {
5596 rc = WriteInt64(1,(ON__INT64*)&length);
5597 }
5598 else
5599 {
5600 ON__UINT32 u32 = 0;
5601 rc = DownSizeUINT(length,&u32);
5602 if ( !WriteInt32(1,(ON__INT32*)&u32) )
5603 rc = false;
5604 }
5605 return rc;
5606 }
5607
ReadEOFSizeOfFile(ON__UINT64 * sizeof_file)5608 bool ON_BinaryArchive::ReadEOFSizeOfFile( ON__UINT64* sizeof_file )
5609 {
5610 bool rc;
5611 ON__INT64 u64 = 0;
5612 if ( 8 == SizeofChunkLength() )
5613 {
5614 // file has a 8 byte file size
5615 rc = ReadInt64(1,(ON__INT64*)&u64);
5616 }
5617 else
5618 {
5619 // file has a 4 byte file size
5620 ON__UINT32 u32 = 0;
5621 rc = ReadInt32(1,(ON__INT32*)&u32);
5622 if ( rc )
5623 u64 = u32;
5624 }
5625 if ( rc && 0 != sizeof_file )
5626 *sizeof_file = u64;
5627 return rc;
5628 }
5629
WriteEOFSizeOfFile(ON__UINT64 sizeof_file)5630 bool ON_BinaryArchive::WriteEOFSizeOfFile( ON__UINT64 sizeof_file )
5631 {
5632 bool rc;
5633 if ( 8 == SizeofChunkLength() )
5634 {
5635 // file has a 8 byte file size
5636 rc = WriteInt64(1,(ON__INT64*)&sizeof_file);
5637 }
5638 else
5639 {
5640 // file has a 4 byte file size
5641 ON__UINT32 u32=0;
5642 DownSizeUINT(sizeof_file,&u32);
5643 rc = WriteInt32(1,(ON__INT32*)&u32);
5644 }
5645 return rc;
5646 }
5647
ReadChunkValue(ON__UINT32 typecode,ON__INT64 * value64)5648 bool ON_BinaryArchive::ReadChunkValue( ON__UINT32 typecode, ON__INT64* value64 )
5649 {
5650 bool rc;
5651 ON__INT64 i64 = 0;
5652 if ( 8 == SizeofChunkLength() )
5653 {
5654 // file has a 8 byte chunk value
5655 rc = ReadInt64(1,&i64);
5656 }
5657 else
5658 {
5659 // file has a 4 byte chunk value
5660 if ( ON_IsUnsignedChunkTypecode(typecode) )
5661 {
5662 // This Mickey Mouse is here to convince all compilers
5663 // that when we read a 4 byte value with the high bit set,
5664 // the resulting i64 value is positive. I.e.,
5665 // 0xFFFFFFFF is converted to 0x00000000FFFFFFFF
5666 ON__UINT32 u32 = 0;
5667 ON__UINT64 u64 = 0;
5668 rc = ReadInt32(1,(ON__INT32*)&u32);
5669 if ( rc )
5670 u64 = u32;
5671 i64 = (ON__INT64)u64;
5672 }
5673 else
5674 {
5675 // If we read a 4 byte value with the high bit set,
5676 // the resulting i64 value is negative. I.e.,
5677 // -1 is converted to -1 (0xFFFFFFFF to 0xFFFFFFFFFFFFFFFF)
5678 ON__INT32 i32 = 0;
5679 rc = ReadInt32(1,&i32);
5680 i64 = i32;
5681 }
5682 }
5683 if ( rc && 0 != value64 )
5684 *value64 = i64;
5685 return rc;
5686 }
5687
SizeofChunkLength() const5688 size_t ON_BinaryArchive::SizeofChunkLength() const
5689 {
5690 // Version 1 - 4 and early version 5 files had
5691 // 4 byte chunk lengths. In October of 2009,
5692 // 8 byte chunk lengths were phased in for V5
5693 // files.
5694 return (m_3dm_version < 50) ? 4 : 8;
5695 }
5696
PushBigChunk(ON__UINT32 typecode,ON__INT64 big_value)5697 bool ON_BinaryArchive::PushBigChunk( ON__UINT32 typecode, ON__INT64 big_value )
5698 {
5699 ON_3DM_BIG_CHUNK c;
5700 memset(&c,0,sizeof(c));
5701 c.m_typecode = typecode;
5702 c.m_big_value = big_value;
5703
5704 // | and & are BITOPS - do NOT change to || and &&
5705 //
5706 // Some v1 files have a short chunk with typecode = 0.
5707 if ( 0 == ( TCODE_SHORT & typecode ) && (0 != typecode || 1 != Archive3dmVersion()) )
5708 {
5709 if ( m_3dm_version == 1 && 0 != (TCODE_LEGACY_GEOMETRY & typecode) )
5710 {
5711 // these legacy typecodes have 16 bit CRCs
5712 c.m_do_crc16 = 1;
5713 c.m_crc16 = 1;
5714 }
5715 else
5716 {
5717 // some other legacy typecodes that have 16 bit CRCs
5718 switch(typecode)
5719 {
5720
5721 case TCODE_SUMMARY:
5722 if ( m_3dm_version == 1 )
5723 {
5724 c.m_do_crc16 = 1;
5725 c.m_crc16 = 1;
5726 }
5727 break;
5728
5729 case TCODE_OPENNURBS_OBJECT | TCODE_CRC | 0x7FFD:
5730 if ( m_3dm_version == 1 )
5731 {
5732 // 1.1 uuid has a 16 bit crc
5733 c.m_do_crc16 = 1;
5734 c.m_crc16 = 1;
5735 }
5736 else
5737 {
5738 // 2.0 uuid has a 32 bit crc
5739 c.m_do_crc32 = 1;
5740 c.m_crc32 = 0;
5741 }
5742 break;
5743
5744 default:
5745 if ( m_3dm_version != 1 && 0 != (TCODE_CRC & typecode) )
5746 {
5747 // 32 bit CRC
5748 c.m_do_crc32 = 1;
5749 c.m_crc32 = 0;
5750 }
5751 break;
5752
5753 }
5754 }
5755 c.m_bLongChunk = 1;
5756 }
5757 c.m_big_offset = CurrentPosition();
5758 m_bDoChunkCRC = c.m_do_crc16 || c.m_do_crc32;
5759
5760 if ( m_chunk.Capacity() == 0 )
5761 m_chunk.Reserve(128);
5762 m_chunk.Append( c );
5763
5764 return true;
5765 }
5766
EnableSave3dmRenderMeshes(ON_BOOL32 b)5767 bool ON_BinaryArchive::EnableSave3dmRenderMeshes( ON_BOOL32 b /* default = true */ )
5768 {
5769 bool oldb = m_bSaveRenderMeshes;
5770 m_bSaveRenderMeshes = b?true:false;
5771 return oldb;
5772 }
5773
Save3dmRenderMeshes() const5774 bool ON_BinaryArchive::Save3dmRenderMeshes() const
5775 {
5776 return m_bSaveRenderMeshes;
5777 }
5778
EnableSave3dmAnalysisMeshes(ON_BOOL32 b)5779 bool ON_BinaryArchive::EnableSave3dmAnalysisMeshes( ON_BOOL32 b /* default = true */ )
5780 {
5781 bool oldb = m_bSaveAnalysisMeshes;
5782 m_bSaveAnalysisMeshes = b?true:false;
5783 return oldb;
5784 }
5785
Save3dmAnalysisMeshes() const5786 bool ON_BinaryArchive::Save3dmAnalysisMeshes() const
5787 {
5788 return m_bSaveAnalysisMeshes;
5789 }
5790
EnableSaveUserData(ON_BOOL32 b)5791 bool ON_BinaryArchive::EnableSaveUserData( ON_BOOL32 b )
5792 {
5793 bool b0 = m_bSaveUserData;
5794 m_bSaveUserData = b?true:false;
5795 return b0;
5796 }
5797
SaveUserData() const5798 bool ON_BinaryArchive::SaveUserData() const
5799 {
5800 return m_bSaveUserData;
5801 }
5802
CurrentArchiveVersion()5803 int ON_BinaryArchive::CurrentArchiveVersion()
5804 {
5805 // Latest version of opennurbs binary archives supported by
5806 // this version of opennurbs.
5807 return 50; // Rhino 5.0 files with 8 byte chunk lengths.
5808 }
5809
Write3dmStartSection(int version,const char * sInformation)5810 bool ON_BinaryArchive::Write3dmStartSection( int version, const char* sInformation )
5811 {
5812 if ( 0 == version )
5813 version = ON_BinaryArchive::CurrentArchiveVersion();
5814
5815 // 2009 November 6
5816 // Default 3dm files now have 8 byte chunk lengths.
5817 // 3dm archive version numbers >= 50 indicate the file has 8 byte chunk lengths.
5818 // Rather than change the hundreds of places in Rhino that use 5, 6, 7 ...
5819 // the "version *= 10" line handles it.
5820 if ( version >= 5 && version < 50 )
5821 version *= 10;
5822
5823 if ( version > ON_BinaryArchive::CurrentArchiveVersion() )
5824 {
5825 ON_ERROR("3dm archive version must be <= ON_BinaryArchive::CurrentArchiveVersion() ");
5826 return false;
5827 }
5828
5829 if ( version < 2
5830 || (version >= 5 && version < 50)
5831 || (version >= 50 && 0 != (version % 10))
5832 )
5833 {
5834 ON_ERROR("3dm archive version must be 2, 3, 4 or 50");
5835 return false;
5836 }
5837
5838 m_bad_CRC_count = 0;
5839 m_3dm_version = 0;
5840 m_3dm_opennurbs_version = ON::Version();
5841 m_3dm_version = version;
5842
5843 char sVersion[64];
5844 memset( sVersion, 0, sizeof(sVersion) );
5845 if ( version < 1 )
5846 version = ON_BinaryArchive::CurrentArchiveVersion();
5847 sprintf(sVersion,"3D Geometry File Format %8d",version);
5848 bool rc = WriteByte( 32, sVersion );
5849 if ( rc )
5850 rc = BeginWrite3dmBigChunk( TCODE_COMMENTBLOCK, 0 );
5851 if ( rc ) {
5852 if ( sInformation && sInformation[0] ) {
5853 rc = WriteByte( strlen(sInformation), sInformation );
5854 }
5855 if ( rc ) {
5856 // write information that helps determine what code wrote the 3dm file
5857 char s[2048];
5858 size_t s_len = 0;
5859 memset( s, 0, sizeof(s) );
5860 sprintf(s," 3DM I/O processor: OpenNURBS toolkit version %d",ON::Version());
5861 strcat(s," (compiled on ");
5862 strcat(s,__DATE__);
5863 strcat(s,")\n");
5864 s_len = strlen(s);
5865 s[s_len++] = 26; // ^Z
5866 s[s_len++] = 0;
5867 rc = WriteByte( s_len, s );
5868 }
5869 if ( !EndWrite3dmChunk() ) // need to call EndWrite3dmChunk() even if a WriteByte() has failed
5870 rc = false;
5871 }
5872 return rc;
5873 }
5874
Read3dmStartSection(int * version,ON_String & s)5875 bool ON_BinaryArchive::Read3dmStartSection( int* version, ON_String& s )
5876 {
5877 // The first 24 bytes of a 3dm file must be "3D Geometry File Format "
5878 // The next 8 bytes must be a right justified ASCII integer >= 1. For
5879 // example, prior to March 2000, all 3DM files were version 1 files and
5880 // they began with "3D Geometry File Format 1". At the time of
5881 // this writing (May 2011) there are version 1,2,3,4,5 and 50 files.
5882 //
5883 // The next section must contain a long chunk with typecode 1.
5884 m_bad_CRC_count = 0;
5885 m_3dm_version = 0;
5886
5887 // In Read3dmProperties, m_3dm_opennurbs_version will be set to
5888 // the version of OpenNURBS that was used to write this archive.
5889 m_3dm_opennurbs_version = 0;
5890
5891 unsigned int typecode = 0;
5892 ON__INT64 length = -1;
5893 int ver = m_3dm_version;
5894 if ( version )
5895 *version = m_3dm_version;
5896 s.Destroy();
5897 char s3d[33];
5898 memset( s3d, 0, sizeof(s3d) );
5899 bool rc = ReadByte( 32, s3d );
5900 if ( rc )
5901 {
5902
5903 if ( strncmp( s3d, "3D Geometry File Format ", 24) )
5904 {
5905 // it's not a "pure" .3DM file
5906 // - see if we have a .3DM file with MS OLE-goo at the start
5907 // (generally, there is around 6kb of goo. I keep looking
5908 // for up to 32mb just in case.)
5909 rc = false;
5910 unsigned int n;
5911 int j;
5912 for ( n = 0; n < 33554432 && !rc; n++ )
5913 {
5914 for ( j = 0; j < 31; j++ )
5915 s3d[j] = s3d[j+1];
5916 if ( !ReadByte( 1, &s3d[31]) )
5917 break;
5918 if ( !strncmp( s3d, "3D Geometry File Format ", 24) )
5919 {
5920 m_3dm_start_section_offset = n+1;
5921 rc = true;
5922 break;
5923 }
5924 }
5925 }
5926
5927 if (rc) {
5928 // get version
5929 //char* sVersion = s3d+24;
5930 // skip leading spaces
5931 int i = 24;
5932 while (i < 32 && s3d[i] == ' ')
5933 i++;
5934 while (i < 32 && rc) {
5935 // TEMPORARY 2 = X
5936 if ( i == 31 && s3d[i] == 'X' ) {
5937 s3d[i] = '2';
5938 }
5939
5940 if ( s3d[i] < '0' || s3d[i] > '9' ) {
5941 rc = false; // it's not a valid .3DM file version
5942 break;
5943 }
5944 ver = ver*10 + ((int)(s3d[i]-'0'));
5945 i++;
5946 }
5947 if ( rc ) {
5948 m_3dm_version = ver;
5949 if ( version )
5950 *version = ver;
5951 }
5952 }
5953 if ( rc ) {
5954 rc = BeginRead3dmBigChunk( &typecode, &length );
5955 if ( rc ) {
5956 if ( typecode != 1 ) {
5957 rc = false; // it's not a .3DM file
5958 }
5959 else if ( length > 0 )
5960 {
5961 if ( length > 0x00FFFFFF )
5962 {
5963 ON_ERROR("ON_BinaryArchive::Read3dmStartSection - start section string is unreasonably long.");
5964 rc = false;
5965 }
5966 else
5967 {
5968 int slen = (int)length;
5969 s.ReserveArray( slen+1 );
5970 s.SetLength( slen );
5971 s[slen] = 0;
5972 ReadByte( slen, s.Array() );
5973 while ( slen > 0 && (0 == s[slen-1] || 26 == s[slen-1]) )
5974 {
5975 s[slen-1] = 0;
5976 slen--;
5977 }
5978 s.SetLength(slen);
5979 }
5980 }
5981 }
5982 if ( !EndRead3dmChunk() )
5983 rc = false;
5984 if ( rc && m_3dm_version == 1 ) {
5985 // In March 2001, we got reports of files with V1 headers and
5986 // a V2 bodies. We haven't been able to track down the application
5987 // that is creating these damaged files, but we can detect them
5988 // and read them because they all have a TCODE_PROPERTIES_TABLE
5989 // chunk right after the start comments chunk and no valid V1
5990 // file has a chunk with a TCODE_PROPERTIES_TABLE tcode.
5991 //
5992 // Rhino 1.1 version 31-May-2000 reads 2.0 files as goo. If a user
5993 // saves this file for some reason (no instances have been reported)
5994 // the resulting file has a V1 header, V1 fluff, and a V2 body.
5995 // This code will cause opennurbs to read the V2 body.
5996 // a file that is different from those describe This code
5997 // detects these files.
5998 {
5999
6000 const ON__UINT64 pos1 = CurrentPosition();
6001 //int v1_fluff_chunk_count = 0;
6002 bool bCheckChunks = true;
6003
6004 //////////
6005 while(bCheckChunks) {
6006 if ( !PeekAt3dmBigChunkType(&typecode,&length) )
6007 break;
6008 switch(typecode)
6009 {
6010 case TCODE_SUMMARY:
6011 case TCODE_BITMAPPREVIEW:
6012 case TCODE_UNIT_AND_TOLERANCES:
6013 case TCODE_VIEWPORT:
6014 case TCODE_LAYER:
6015 case TCODE_RENDERMESHPARAMS:
6016 case TCODE_CURRENTLAYER:
6017 case TCODE_ANNOTATION_SETTINGS:
6018 case TCODE_NOTES:
6019 case TCODE_NAMED_CPLANE:
6020 case TCODE_NAMED_VIEW:
6021 // skip potential v1 fluff
6022 bCheckChunks = BeginRead3dmBigChunk( &typecode, &length );
6023 if ( bCheckChunks )
6024 bCheckChunks = EndRead3dmChunk();
6025 break;
6026
6027 //case TCODE_PROPERTIES_TABLE:
6028 //case TCODE_SETTINGS_TABLE:
6029 //case TCODE_OBJECT_TABLE:
6030 //case TCODE_BITMAP_TABLE:
6031 //case TCODE_LAYER_TABLE:
6032 //case TCODE_GROUP_TABLE:
6033 //case TCODE_LIGHT_TABLE:
6034 //case TCODE_MATERIAL_TABLE:
6035 //case TCODE_USER_TABLE:
6036 default:
6037 if ( TCODE_TABLE == (typecode & 0xFFFF0000) ) {
6038 // Found a V2 table which has to be V1 goo
6039 ON_WARNING("ON_BinaryArchive::Read3dmStartSection(): Archive has V1 header and V2 body. Continuing to read V2 body.");
6040 m_3dm_version = 2;
6041 if ( version )
6042 *version = 2;
6043 }
6044 bCheckChunks = false;
6045 break;
6046 }
6047 }
6048
6049 if ( m_3dm_version == 1 ) {
6050 // move archive pointer back to
6051 ON__UINT64 pos2 = CurrentPosition();
6052 if ( pos2 > pos1 )
6053 {
6054 BigSeekBackward(pos2 - pos1);
6055 }
6056 }
6057 }
6058 }
6059 }
6060 }
6061 return rc;
6062 }
6063
Write3dmProperties(const ON_3dmProperties & prop)6064 bool ON_BinaryArchive::Write3dmProperties(
6065 const ON_3dmProperties& prop
6066 )
6067 {
6068 bool rc = false;
6069 if ( m_3dm_version == 1 )
6070 {
6071 ON_String s;
6072
6073 rc = true;
6074
6075 if ( rc && prop.m_RevisionHistory.IsValid() )
6076 {
6077 rc = BeginWrite3dmChunk(TCODE_SUMMARY,0);
6078 if (rc)
6079 {
6080 // version 1 revision history chunk
6081 s = prop.m_RevisionHistory.m_sCreatedBy;
6082 if (rc) rc = WriteString(s);
6083 if (rc) rc = WriteTime( prop.m_RevisionHistory.m_create_time );
6084 if (rc) rc = WriteInt(0);
6085 s = prop.m_RevisionHistory.m_sLastEditedBy;
6086 if (rc) rc = WriteString(s);
6087 if (rc) rc = WriteTime( prop.m_RevisionHistory.m_last_edit_time );
6088 if (rc) rc = WriteInt(0);
6089 if (rc) rc = WriteInt( prop.m_RevisionHistory.m_revision_count );
6090 if ( !EndWrite3dmChunk() ) // writes 16 bit crc
6091 rc = false;
6092 }
6093 }
6094
6095 if ( rc && prop.m_Notes.IsValid() )
6096 {
6097 rc = BeginWrite3dmChunk(TCODE_NOTES,0);
6098 // version 1 notes chunk
6099 if ( rc )
6100 {
6101 if ( rc ) rc = WriteInt( prop.m_Notes.m_bVisible );
6102 if ( rc ) rc = WriteInt( prop.m_Notes.m_window_left );
6103 if ( rc ) rc = WriteInt( prop.m_Notes.m_window_top );
6104 if ( rc ) rc = WriteInt( prop.m_Notes.m_window_right );
6105 if ( rc ) rc = WriteInt( prop.m_Notes.m_window_bottom );
6106 s = prop.m_Notes.m_notes;
6107 if ( rc ) rc = WriteString( s );
6108 if ( !EndWrite3dmChunk() )
6109 rc = false;
6110 }
6111 }
6112
6113 if ( rc && prop.m_PreviewImage.IsValid() )
6114 {
6115 rc = BeginWrite3dmChunk(TCODE_BITMAPPREVIEW,0);
6116 if (rc)
6117 {
6118 // version 1 preview image chunk
6119 prop.m_PreviewImage.Write(*this);
6120 if ( !EndWrite3dmChunk() )
6121 rc = false;
6122 }
6123 }
6124 }
6125 else
6126 {
6127 // version 2+ file properties chunk
6128 rc = BeginWrite3dmChunk(TCODE_PROPERTIES_TABLE,0);
6129 if ( rc ) {
6130 rc = prop.Write( *this )?true:false;
6131 if ( !EndWrite3dmChunk() )
6132 rc = false;
6133 }
6134 }
6135 return rc;
6136 }
6137
on_strnicmp(const char * s1,const char * s2,int n)6138 int on_strnicmp(const char * s1, const char * s2, int n)
6139 {
6140 #if defined(ON_OS_WINDOWS)
6141 //return stricmp(s1,s2,n);
6142 return _strnicmp(s1,s2,n);
6143 #else
6144 return strncasecmp(s1,s2,n);
6145 #endif
6146 }
6147
Read3dmProperties(ON_3dmProperties & prop)6148 bool ON_BinaryArchive::Read3dmProperties( ON_3dmProperties& prop )
6149 {
6150 // In ON_3dmProperties::Read(), m_3dm_opennurbs_version will be
6151 // set to the version of OpenNURBS that was used to write this archive.
6152 // If the file was written with by a pre 200012210 version of OpenNURBS,
6153 // then m_3dm_opennurbs_version will be zero.
6154 m_3dm_opennurbs_version = 0;
6155
6156 prop.Default();
6157
6158 bool rc = true;
6159
6160 // we need these when reading version 1 files
6161 const size_t pos0 = CurrentPosition();
6162 bool bHaveRevisionHistory = false;
6163 bool bHaveNotes = false;
6164 bool bHavePreviewImage = false;
6165 bool bDone = false;
6166 bool bRewindFilePointer = false;
6167
6168 ON__UINT32 tcode;
6169 ON__INT64 big_value;
6170 //int version = 0;
6171
6172 if ( m_3dm_version != 1 ) {
6173 for(;;)
6174 {
6175 tcode = 0;
6176 big_value = 0;
6177 rc = BeginRead3dmBigChunk( &tcode, &big_value );
6178 if ( !rc ) {
6179 bRewindFilePointer = true;
6180 break;
6181 }
6182
6183 if ( tcode == TCODE_PROPERTIES_TABLE ) {
6184 rc = prop.Read(*this)?true:false;
6185 }
6186 else {
6187 bRewindFilePointer = true;
6188 }
6189
6190 if ( !EndRead3dmChunk() ) {
6191 rc = false;
6192 bRewindFilePointer = true;
6193 }
6194 if ( tcode == TCODE_PROPERTIES_TABLE || !rc )
6195 break;
6196 }
6197 }
6198 else {
6199 // version 1 file
6200 rc = SeekFromStart(32)?true:false;
6201 bRewindFilePointer = true;
6202 for(;;)
6203 {
6204 tcode = 0;
6205 big_value = 0;
6206 rc = BeginRead3dmBigChunk( &tcode, &big_value );
6207 if ( !rc ) {
6208 rc = true; // assume we are at the end of the file
6209 bRewindFilePointer = true;
6210 break;
6211 }
6212
6213 switch ( tcode ) {
6214
6215 case 1: // comments section has application name
6216 if ( big_value > 1000000 )
6217 {
6218 ON_ERROR("Comment length > 1000000");
6219 }
6220 else if ( big_value > 1 )
6221 {
6222 int slen = (int)big_value;
6223 int i;
6224 char* name = 0;
6225 ON_String s;
6226 s.ReserveArray( slen+1 );
6227 s.SetLength( slen );
6228 s[slen] = 0;
6229 ReadByte( slen, s.Array() );
6230 while ( slen > 0 && (0 == s[slen-1] || 26 == s[slen-1]) )
6231 {
6232 s[slen-1] = 0;
6233 slen--;
6234 }
6235 s.SetLength(slen);
6236 name = s.Array();
6237 if ( name ) {
6238 while(*name) {
6239 if ( !on_strnicmp(name,"Interface:",10) ) {
6240 name += 10;
6241 break;
6242 }
6243 name++;
6244 }
6245 while(*name && *name <= 32 )
6246 name++;
6247 for ( i = 0; name[i] ; i++ ) {
6248 if ( name[i] == '(' ) {
6249 name[i] = 0;
6250 while ( i > 0 && (name[i] <= 32 || name[i] == '-') ) {
6251 name[i] = 0;
6252 i--;
6253 }
6254 break;
6255 }
6256 }
6257 if ( *name )
6258 {
6259 char* details = 0;
6260 if ( !on_strnicmp(name,"Rhinoceros",10) ) {
6261 prop.m_Application.m_application_URL = "http://www.rhino3d.com";
6262 details = name+10;
6263 while ( *details && *details <= 32 )
6264 details++;
6265 while ( (*details >= '0' && *details <= '9') || *details == '.' )
6266 details++;
6267 if ( *details && *details <= 32 ) {
6268 *details = 0;
6269 details++;
6270 while ( *details && (*details <= 32 ||*details == '-')) {
6271 details++;
6272 }
6273 }
6274 }
6275 if (*name)
6276 prop.m_Application.m_application_name = name;
6277 if (details && *details)
6278 prop.m_Application.m_application_details = details;
6279 }
6280 }
6281 }
6282 break;
6283
6284 case TCODE_SUMMARY:
6285 // version 1 revision history chunk (has 16 bit CRC)
6286 //version = 1;
6287 bHaveRevisionHistory = true;
6288 {
6289 int slength = 0;
6290 char* s = 0;
6291 if (rc) rc = ReadInt(&slength);
6292 if (rc && slength > 0 ) {
6293 s = (char*)onmalloc((slength+1)*sizeof(*s));
6294 memset( s, 0, (slength+1)*sizeof(*s) );
6295 if (rc) rc = ReadChar( slength, s );
6296 if ( rc )
6297 prop.m_RevisionHistory.m_sCreatedBy = s;
6298 onfree(s);
6299 slength = 0;
6300 s = 0;
6301 }
6302 if (rc) rc = ReadTime( prop.m_RevisionHistory.m_create_time );
6303 int i32 = 0;
6304 if (rc) rc = ReadInt(&i32); // 0 in 1.x files
6305 if (rc) rc = ReadInt(&slength);
6306 if ( rc && slength > 0 )
6307 {
6308 s = (char*)onmalloc((slength+1)*sizeof(*s));
6309 memset( s, 0, (slength+1)*sizeof(*s) );
6310 if (rc) rc = ReadChar( slength, s );
6311 if ( rc )
6312 prop.m_RevisionHistory.m_sLastEditedBy = s;
6313 onfree(s);
6314 slength = 0;
6315 s = 0;
6316 }
6317 if (rc) rc = ReadTime( prop.m_RevisionHistory.m_last_edit_time );
6318 if (rc) rc = ReadInt(&i32); // 0 in 1.x files
6319 if (rc) rc = ReadInt( &prop.m_RevisionHistory.m_revision_count );
6320 }
6321 break;
6322
6323 case TCODE_NOTES:
6324 // version 1 notes chunk
6325 //version = 1;
6326 bHaveNotes = true;
6327 for(;;)
6328 {
6329 int slength;
6330 char* s = 0;
6331 rc = ReadInt( &prop.m_Notes.m_bVisible );
6332 if(!rc) break;
6333 rc = ReadInt( &prop.m_Notes.m_window_left );
6334 if(!rc) break;
6335 rc = ReadInt( &prop.m_Notes.m_window_top );
6336 if(!rc) break;
6337 rc = ReadInt( &prop.m_Notes.m_window_right );
6338 if(!rc) break;
6339 rc = ReadInt( &prop.m_Notes.m_window_bottom );
6340 if(!rc) break;
6341 rc = ReadInt( &slength );
6342 if(!rc) break;
6343 if ( slength > 0 )
6344 {
6345 s = (char*)onmalloc( (slength+1)*sizeof(*s) );
6346 memset( s, 0, (slength+1)*sizeof(*s) );
6347 if ( rc ) rc = ReadChar( slength, s );
6348 if ( rc )
6349 {
6350 prop.m_Notes.m_notes = s;
6351 }
6352 onfree(s);
6353 slength = 0;
6354 s = 0;
6355 }
6356 break;
6357 }
6358 break;
6359
6360 case TCODE_BITMAPPREVIEW:
6361 // version 1 preview image chunk
6362 //version = 1;
6363 rc = prop.m_PreviewImage.Read(*this)?true:false;
6364 bHavePreviewImage = rc;
6365 break;
6366
6367 case TCODE_CURRENTLAYER:
6368 case TCODE_LAYER:
6369 // version 1 layer and current layer chunks always came after notes/bitmap/summary
6370 bDone = true;
6371 bRewindFilePointer = true;
6372 break;
6373
6374 default:
6375 // the call to EndRead3dmChunk() will skip over this chunk
6376 bRewindFilePointer = true;
6377 break;
6378 }
6379
6380 // this call to EndRead3dmChunk() skips any unread portions of the chunk
6381 if ( !EndRead3dmChunk() ) {
6382 rc = false;
6383 bRewindFilePointer = true;
6384 }
6385
6386 if ( bHaveRevisionHistory && bHaveNotes && bHavePreviewImage )
6387 bDone = true;
6388
6389 if ( bDone || !rc )
6390 break;
6391 }
6392 }
6393
6394 if ( bRewindFilePointer ) {
6395 // reposition file pointer to pos0
6396 const ON__UINT64 pos1 = CurrentPosition();
6397 if ( pos0 != pos1 )
6398 {
6399 if (pos1 > pos0)
6400 BigSeekBackward(pos1-pos0);
6401 else if ( pos1 < pos0 )
6402 BigSeekForward(pos0-pos1);
6403 }
6404 }
6405
6406 return rc;
6407 }
6408
Write3dmSettings(const ON_3dmSettings & settings)6409 bool ON_BinaryArchive::Write3dmSettings(
6410 const ON_3dmSettings& settings
6411 )
6412 {
6413 bool rc = false;
6414 if ( m_3dm_version == 1 ) {
6415 // legacy v1 settings info is a bunch of unreleated top level chunks
6416 rc = settings.Write(*this)?true:false;
6417 }
6418 else
6419 {
6420 // version 2+ file settings chunk
6421 rc = BeginWrite3dmChunk(TCODE_SETTINGS_TABLE,0);
6422 if ( rc ) {
6423 rc = settings.Write( *this );
6424 if ( !EndWrite3dmChunk() )
6425 rc = false;
6426 }
6427
6428 if ( rc && 3 == Archive3dmVersion() )
6429 {
6430 // Build a list of ids of plug-ins that support saving
6431 // V3 user data. If a plug-in id is not in this list,
6432 // the user data will not be saved in the V3 archive.
6433 int i, count = settings.m_plugin_list.Count();
6434 m_V3_plugin_id_list.SetCount(0);
6435 m_V3_plugin_id_list.SetCapacity( count+5 );
6436 for ( i = 0; i < count; i++ )
6437 {
6438 const ON_UUID& pid = settings.m_plugin_list[i].m_plugin_id;
6439 if ( !ON_UuidIsNil(pid) )
6440 m_V3_plugin_id_list.Append(pid);
6441 }
6442
6443 // These ids insure V3, V4 and V5 core user data will round trip
6444 // through SaveAs V3 and SaveAs V4
6445 m_V3_plugin_id_list.Append( ON_v3_userdata_id );
6446 m_V3_plugin_id_list.Append( ON_v4_userdata_id );
6447 m_V3_plugin_id_list.Append( ON_opennurbs4_id );
6448 m_V3_plugin_id_list.Append( ON_opennurbs5_id );
6449 m_V3_plugin_id_list.Append( ON_rhino3_id );
6450 m_V3_plugin_id_list.Append( ON_rhino4_id );
6451 m_V3_plugin_id_list.Append( ON_rhino5_id );
6452 m_V3_plugin_id_list.QuickSort( ON_UuidCompare );
6453 }
6454 }
6455 return rc;
6456 }
6457
Read3dmSettings(ON_3dmSettings & settings)6458 bool ON_BinaryArchive::Read3dmSettings( ON_3dmSettings& settings )
6459 {
6460 bool rc = false;
6461 ON__UINT32 tcode;
6462 ON__INT64 big_value;
6463
6464 if ( m_3dm_version == 1 ) {
6465 // read legacy v 1 info that is scattered around the file
6466 rc = settings.Read(*this);
6467 }
6468 else {
6469 rc = true;
6470 while(rc)
6471 {
6472 tcode = 0;
6473 big_value = 0;
6474 rc = BeginRead3dmBigChunk( &tcode, &big_value );
6475 if ( !rc )
6476 break;
6477 if ( tcode == TCODE_SETTINGS_TABLE ) {
6478 // version 2 model properties
6479 rc = settings.Read(*this);
6480 }
6481 if ( !EndRead3dmChunk() ) {
6482 rc = false;
6483 break;
6484 }
6485 if ( TCODE_SETTINGS_TABLE == tcode )
6486 break;
6487 }
6488 }
6489
6490 return rc;
6491 }
6492
TableTypeFromTypecode(unsigned int typecode)6493 ON_BinaryArchive::table_type ON_BinaryArchive::TableTypeFromTypecode( unsigned int typecode )
6494 {
6495 table_type tt = no_active_table;
6496 switch(typecode)
6497 {
6498 case TCODE_PROPERTIES_TABLE: tt = properties_table; break;
6499 case TCODE_SETTINGS_TABLE: tt = settings_table; break;
6500 case TCODE_BITMAP_TABLE: tt = bitmap_table; break;
6501 case TCODE_TEXTURE_MAPPING_TABLE: tt = texture_mapping_table; break;
6502 case TCODE_MATERIAL_TABLE: tt = material_table; break;
6503 case TCODE_LINETYPE_TABLE: tt = linetype_table; break;
6504 case TCODE_LAYER_TABLE: tt = layer_table; break;
6505 case TCODE_LIGHT_TABLE: tt = light_table; break;
6506 case TCODE_OBJECT_TABLE: tt = object_table; break;
6507 case TCODE_GROUP_TABLE: tt = group_table; break;
6508 case TCODE_FONT_TABLE: tt = font_table; break;
6509 case TCODE_DIMSTYLE_TABLE: tt = dimstyle_table; break;
6510 case TCODE_HATCHPATTERN_TABLE: tt = hatchpattern_table; break;
6511 case TCODE_INSTANCE_DEFINITION_TABLE: tt = instance_definition_table; break;
6512 case TCODE_HISTORYRECORD_TABLE: tt = historyrecord_table; break;
6513 case TCODE_USER_TABLE: tt = user_table; break;
6514 }
6515 return tt;
6516 }
6517
BeginWrite3dmTable(unsigned int typecode)6518 bool ON_BinaryArchive::BeginWrite3dmTable( unsigned int typecode )
6519 {
6520 const table_type tt = TableTypeFromTypecode(typecode);
6521 if (tt == no_active_table) {
6522 ON_ERROR("ON_BinaryArchive::BeginWrite3dmTable() bad typecode");
6523 return false;
6524 }
6525 if ( m_active_table != no_active_table ) {
6526 ON_ERROR("ON_BinaryArchive::BeginWrite3dmTable() m_active_table != no_active_table");
6527 return false;
6528 }
6529 if ( m_chunk.Count() ) {
6530 ON_ERROR("ON_BinaryArchive::BeginWrite3dmTable() m_chunk.Count() > 0");
6531 return false;
6532 }
6533 bool rc = BeginWrite3dmChunk(typecode,0);
6534 if (rc)
6535 m_active_table = tt;
6536 return rc;
6537 }
6538
EndWrite3dmTable(unsigned int typecode)6539 bool ON_BinaryArchive::EndWrite3dmTable( unsigned int typecode )
6540 {
6541 const table_type tt = TableTypeFromTypecode(typecode);
6542 if (tt == no_active_table) {
6543 ON_ERROR("ON_BinaryArchive::EndWrite3dmTable() bad typecode");
6544 return false;
6545 }
6546 if ( m_active_table != tt ) {
6547 ON_ERROR("ON_BinaryArchive::EndWrite3dmTable() m_active_table != t");
6548 return false;
6549 }
6550 if ( m_chunk.Count() != 1 ) {
6551 ON_ERROR("ON_BinaryArchive::EndWrite3dmTable() m_chunk.Count() != 1");
6552 return false;
6553 }
6554 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
6555 if ( 0 == c || c->m_typecode != typecode ) {
6556 ON_ERROR("ON_BinaryArchive::EndWrite3dmTable() m_chunk.Last()->typecode != typecode");
6557 return false;
6558 }
6559 bool rc = BeginWrite3dmChunk( TCODE_ENDOFTABLE, 0 );
6560 if (rc) {
6561 if (!EndWrite3dmChunk())
6562 rc = false;
6563 }
6564 if (!EndWrite3dmChunk())
6565 rc = false;
6566 Flush();
6567 m_active_table = no_active_table;
6568 return rc;
6569 }
6570
BeginRead3dmTable(unsigned int typecode)6571 bool ON_BinaryArchive::BeginRead3dmTable( unsigned int typecode )
6572 {
6573 bool rc = false;
6574 const table_type tt = TableTypeFromTypecode(typecode);
6575 if (tt == no_active_table) {
6576 ON_ERROR("ON_BinaryArchive::BeginRead3dmTable() bad typecode");
6577 return false;
6578 }
6579 if ( m_active_table != no_active_table ) {
6580 ON_ERROR("ON_BinaryArchive::BeginRead3dmTable() m_active_table != no_active_table");
6581 return false;
6582 }
6583 if ( m_chunk.Count() ) {
6584 ON_ERROR("ON_BinaryArchive::BeginRead3dmTable() m_chunk.Count() > 0");
6585 return false;
6586 }
6587
6588 if ( m_3dm_version <= 1 )
6589 {
6590 if ( TCODE_USER_TABLE == typecode )
6591 return false; // no user tables in V1 files
6592
6593 // version 1 files had can have chunks in any order. To read a "table",
6594 // you have to go through the entire list of chunks looking for those
6595 // that belong to a particular table.
6596 rc = SeekFromStart(32)?true:false;
6597 m_active_table = tt;
6598 }
6599 else
6600 {
6601 if ( TCODE_USER_TABLE == typecode && m_3dm_version <= 2 )
6602 return false; // no user tables in V2 files
6603
6604 bool bReadTable = true;
6605 ON__UINT32 tcode = !typecode;
6606 ON__INT64 big_value = 0;
6607 rc = PeekAt3dmBigChunkType( &tcode, &big_value );
6608 if ( rc ) {
6609 if ( tcode != typecode )
6610 {
6611 if ( typecode == TCODE_USER_TABLE )
6612 {
6613 // it's ok to not have user tables
6614 rc = false;
6615 bReadTable = false;
6616 }
6617 else if ( typecode == TCODE_GROUP_TABLE && m_3dm_opennurbs_version < 200012210 )
6618 {
6619 // 3DM archives written before version 200012210 and before do not have group tables
6620 rc = true;
6621 m_active_table = tt;
6622 bReadTable = false;
6623 }
6624 else if ( typecode == TCODE_FONT_TABLE && m_3dm_opennurbs_version < 200109180 )
6625 {
6626 // 3DM archives written before version 200109180 and before do not have font tables
6627 rc = true;
6628 m_active_table = tt;
6629 bReadTable = false;
6630 }
6631 else if ( typecode == TCODE_DIMSTYLE_TABLE && m_3dm_opennurbs_version < 200109260 )
6632 {
6633 // 3DM archives written before version 200109260 and before do not have dimstyle tables
6634 rc = true;
6635 m_active_table = tt;
6636 bReadTable = false;
6637 }
6638 else if ( typecode == TCODE_INSTANCE_DEFINITION_TABLE && m_3dm_opennurbs_version < 200205110 )
6639 {
6640 // 3DM archives written before version 200205110 and before do not have instance definition tables
6641 rc = true;
6642 m_active_table = tt;
6643 bReadTable = false;
6644 }
6645 else if ( typecode == TCODE_HATCHPATTERN_TABLE && m_3dm_opennurbs_version < 200405030 )
6646 {
6647 // 3DM archives written before version 200405030 and before do not have hatch pattern tables
6648 rc = true;
6649 m_active_table = tt;
6650 bReadTable = false;
6651 }
6652 else if ( typecode == TCODE_LINETYPE_TABLE && m_3dm_opennurbs_version < 200503170 )
6653 {
6654 // 3DM archives written before version 200503170 and before do not have linetype tables
6655 rc = true;
6656 m_active_table = tt;
6657 bReadTable = false;
6658 }
6659 else if ( typecode == TCODE_TEXTURE_MAPPING_TABLE && m_3dm_opennurbs_version < 200511110 )
6660 {
6661 // 3DM archives written before version 200511110 and before do not have texture mapping tables
6662 rc = true;
6663 m_active_table = tt;
6664 bReadTable = false;
6665 }
6666 else if ( typecode == TCODE_HISTORYRECORD_TABLE && m_3dm_opennurbs_version < 200601180 )
6667 {
6668 // 3DM archives written before version 200601180 and before do not have history record tables
6669 rc = true;
6670 m_active_table = tt;
6671 bReadTable = false;
6672 }
6673 else
6674 {
6675 // A required table is not at the current position in the archive
6676 // see if we can find it someplace else in the archive. This can
6677 // happen when old code encounters a table that was added later.
6678
6679 bool bSeekFromStart = true;
6680
6681 if ( TCODE_HATCHPATTERN_TABLE == tcode
6682 && TCODE_INSTANCE_DEFINITION_TABLE == typecode
6683 && 3 == m_3dm_version
6684 && 200405190 <= m_3dm_opennurbs_version )
6685 {
6686 // Dale Lear
6687 // V3 files from 19 may 2004 on contained bogus hatch pattern tables
6688 // where the instance definition table was supposed to be.
6689 //
6690 // Do not set rc in this code. The goal of this code is to
6691 // avoid seeking from the start of the file and posting
6692 // an ON_ERROR alert about something we can work around
6693 // and has been fixed in V4.
6694 tcode = 0;
6695 big_value = 0;
6696 if ( BeginRead3dmBigChunk( &tcode, &big_value ) )
6697 {
6698 if ( TCODE_HATCHPATTERN_TABLE == tcode )
6699 {
6700 bSeekFromStart = false;
6701 }
6702
6703 if ( !EndRead3dmChunk() )
6704 {
6705 bSeekFromStart = true;
6706 }
6707 else if ( !bSeekFromStart )
6708 {
6709 tcode = 0;
6710 big_value = 0;
6711 PeekAt3dmBigChunkType( &tcode, &big_value );
6712 if ( tcode != typecode )
6713 bSeekFromStart = true;
6714 }
6715 }
6716 }
6717
6718 if ( bSeekFromStart )
6719 {
6720 ON_ERROR("ON_BinaryArchive::BeginRead3dmTable() - current file position not at start of table - searching");
6721 rc = Seek3dmChunkFromStart( typecode );
6722 }
6723 }
6724 }
6725 if ( rc && bReadTable ) {
6726 tcode = !typecode;
6727 big_value = 0;
6728 rc = BeginRead3dmBigChunk( &tcode, &big_value );
6729 if ( rc && tcode != typecode ) {
6730 ON_ERROR("ON_BinaryArchive::BeginRead3dmTable() - corrupt table - skipping");
6731 rc = false;
6732 EndRead3dmChunk();
6733 }
6734 else if (rc) {
6735 m_active_table = tt;
6736 }
6737 }
6738 }
6739 }
6740
6741 return rc;
6742 }
6743
6744
GetCurrentChunk(ON_3DM_CHUNK & chunk) const6745 int ON_BinaryArchive::GetCurrentChunk(ON_3DM_CHUNK& chunk) const
6746 {
6747 ON_3DM_BIG_CHUNK big_chunk;
6748 memset(&chunk,0,sizeof(ON_3DM_CHUNK));
6749 memset(&big_chunk,0,sizeof(big_chunk));
6750 int rc = GetCurrentChunk(big_chunk);
6751 if ( rc > 0 )
6752 {
6753 chunk.m_offset = (size_t)big_chunk.m_big_offset;
6754 chunk.m_typecode = big_chunk.m_typecode;
6755
6756 ON__INT32 i32 = 0;
6757 if ( ON_IsLongChunkTypecode( big_chunk.m_typecode ) )
6758 DownSizeUINT( (ON__UINT64)big_chunk.m_big_value, (ON__UINT32*)&i32 );
6759 else
6760 DownSizeINT( big_chunk.m_big_value, &i32 );
6761 chunk.m_value = i32;
6762
6763 chunk.m_do_length = big_chunk.m_bLongChunk ? 1 : 0;
6764 chunk.m_do_crc16 = big_chunk.m_do_crc16 ? 1 : 0;
6765 chunk.m_do_crc32 = big_chunk.m_do_crc32 ? 1 : 0;
6766 chunk.m_crc16 = big_chunk.m_crc16;
6767 chunk.m_crc32 = big_chunk.m_crc32;
6768 }
6769 return rc;
6770 }
6771
6772
GetCurrentChunk(ON_3DM_BIG_CHUNK & chunk) const6773 int ON_BinaryArchive::GetCurrentChunk(ON_3DM_BIG_CHUNK& chunk) const
6774 {
6775 int rc = m_chunk.Count();
6776 if ( rc > 0 )
6777 {
6778 chunk = m_chunk[rc-1];
6779 }
6780 else
6781 {
6782 memset(&chunk,0,sizeof(ON_3DM_BIG_CHUNK));
6783 }
6784 return rc;
6785 }
6786
6787 static
BufferToUINT16(bool bReverseByteOrder,const unsigned char * buffer,const unsigned char * buffer_max,ON__UINT16 * u16)6788 const unsigned char* BufferToUINT16(
6789 bool bReverseByteOrder,
6790 const unsigned char* buffer,
6791 const unsigned char* buffer_max,
6792 ON__UINT16* u16 )
6793 {
6794 if ( buffer >= buffer_max || buffer_max - buffer < 2 )
6795 return 0;
6796 if ( u16 )
6797 {
6798 unsigned char* dst = (unsigned char*)u16;
6799 if ( bReverseByteOrder )
6800 {
6801 dst[0] = buffer[1];
6802 dst[1] = buffer[0];
6803 }
6804 else
6805 {
6806 dst[0] = buffer[0];
6807 dst[1] = buffer[1];
6808 }
6809 }
6810 return buffer+2;
6811 }
6812
6813 static
BufferToUINT32(bool bReverseByteOrder,const unsigned char * buffer,const unsigned char * buffer_end,ON__UINT32 * u32)6814 const unsigned char* BufferToUINT32(
6815 bool bReverseByteOrder,
6816 const unsigned char* buffer,
6817 const unsigned char* buffer_end,
6818 ON__UINT32* u32 )
6819 {
6820 if ( buffer >= buffer_end || buffer_end - buffer < 4 )
6821 return 0;
6822 if ( u32 )
6823 {
6824 unsigned char* dst = (unsigned char*)u32;
6825 if ( bReverseByteOrder )
6826 {
6827 dst[0] = buffer[3];
6828 dst[1] = buffer[2];
6829 dst[2] = buffer[1];
6830 dst[3] = buffer[0];
6831 }
6832 else
6833 {
6834 dst[0] = buffer[0];
6835 dst[1] = buffer[1];
6836 dst[2] = buffer[2];
6837 dst[3] = buffer[3];
6838 }
6839 }
6840 return buffer+4;
6841 }
6842
6843 static
BufferToINT64(bool bReverseByteOrder,const unsigned char * buffer,const unsigned char * buffer_end,ON__INT64 * i64)6844 const unsigned char* BufferToINT64(
6845 bool bReverseByteOrder,
6846 const unsigned char* buffer,
6847 const unsigned char* buffer_end,
6848 ON__INT64* i64 )
6849 {
6850 if ( buffer >= buffer_end || buffer_end - buffer < 8 )
6851 return 0;
6852 if ( i64 )
6853 {
6854 unsigned char* dst = (unsigned char*)i64;
6855 if ( bReverseByteOrder )
6856 {
6857 dst[0] = buffer[7];
6858 dst[1] = buffer[6];
6859 dst[2] = buffer[5];
6860 dst[3] = buffer[4];
6861 dst[4] = buffer[3];
6862 dst[5] = buffer[2];
6863 dst[6] = buffer[1];
6864 dst[7] = buffer[0];
6865 }
6866 else
6867 {
6868 dst[0] = buffer[0];
6869 dst[1] = buffer[1];
6870 dst[2] = buffer[2];
6871 dst[3] = buffer[3];
6872 dst[4] = buffer[4];
6873 dst[5] = buffer[5];
6874 dst[6] = buffer[6];
6875 dst[7] = buffer[7];
6876 }
6877 }
6878 return buffer+8;
6879 }
6880
6881 static
BufferValidateTcode(bool bReverseByteOrder,const unsigned char * buffer,const unsigned char * buffer_end,ON__UINT32 expected_tcode)6882 const unsigned char* BufferValidateTcode(
6883 bool bReverseByteOrder,
6884 const unsigned char* buffer,
6885 const unsigned char* buffer_end,
6886 ON__UINT32 expected_tcode )
6887 {
6888 ON__UINT32 tc = expected_tcode ? 0 : 1;
6889 buffer = BufferToUINT32(bReverseByteOrder,buffer,buffer_end,&tc);
6890 return ( 0 != buffer && tc == expected_tcode ) ? buffer : 0;
6891 }
6892
6893 static
BufferToChunkValue(bool bReverseByteOrder,size_t sizeof_chunk_value,const unsigned char * buffer,const unsigned char * buffer_end,ON__INT64 * chunk_value)6894 const unsigned char* BufferToChunkValue(
6895 bool bReverseByteOrder,
6896 size_t sizeof_chunk_value,
6897 const unsigned char* buffer,
6898 const unsigned char* buffer_end,
6899 ON__INT64* chunk_value )
6900 {
6901 if ( 8 == sizeof_chunk_value )
6902 {
6903 buffer = BufferToINT64(bReverseByteOrder,buffer,buffer_end,chunk_value);
6904 }
6905 else
6906 {
6907 ON__UINT32 u32;
6908 ON__UINT64 u64;
6909 buffer = BufferToUINT32(bReverseByteOrder,buffer,buffer_end,&u32);
6910 if ( buffer && chunk_value )
6911 {
6912 // this u64 = u32 is here so 4 byte unsigned ints with the high
6913 // bit set are converted to positive 8 bytes ints.
6914 u64 = u32;
6915 *chunk_value = (ON__INT64)u64;
6916 }
6917 }
6918 return buffer;
6919 }
6920
6921 static
BufferToUuid(bool bReverseByteOrder,const unsigned char * buffer,const unsigned char * buffer_end,ON_UUID & uuid)6922 const unsigned char* BufferToUuid(
6923 bool bReverseByteOrder,
6924 const unsigned char* buffer,
6925 const unsigned char* buffer_end,
6926 ON_UUID& uuid )
6927 {
6928 ON__UINT32 data1=0;
6929 ON__UINT16 data2=0, data3=0;
6930 if ( buffer >= buffer_end || buffer_end - buffer < 16 )
6931 return 0;
6932 buffer = BufferToUINT32(bReverseByteOrder,buffer,buffer_end,&data1);
6933 if (buffer)
6934 buffer = BufferToUINT16(bReverseByteOrder,buffer,buffer_end,&data2);
6935 if (buffer)
6936 buffer = BufferToUINT16(bReverseByteOrder,buffer,buffer_end,&data3);
6937 if (buffer)
6938 {
6939 if ( buffer >= buffer_end || buffer_end - buffer < 8 )
6940 buffer = 0;
6941 else
6942 {
6943 uuid.Data1 = data1;
6944 uuid.Data2 = data2;
6945 uuid.Data3 = data3;
6946 memcpy(&uuid.Data4,buffer,8);
6947 buffer += 8;
6948 }
6949 }
6950 return buffer;
6951 }
6952
6953 static
EmergencyFindTable_UuidHelper(bool bReverseByteOrder,size_t sizeof_chunk_value,const unsigned char * buffer,const unsigned char * buffer_end,const ON__UINT32 expected_tcode,const ON_UUID * expected_uuid)6954 const unsigned char* EmergencyFindTable_UuidHelper(
6955 bool bReverseByteOrder,
6956 size_t sizeof_chunk_value,
6957 const unsigned char* buffer,
6958 const unsigned char* buffer_end,
6959 const ON__UINT32 expected_tcode,
6960 const ON_UUID* expected_uuid
6961 )
6962 {
6963 ON__INT64 chunk_value;
6964 ON__UINT32 c, cc;
6965 ON_UUID uuid;
6966
6967 // make sure the value at the start of the buffer = expected_tcode.
6968 buffer = BufferValidateTcode(bReverseByteOrder,buffer,buffer_end,expected_tcode);
6969 if ( 0 == buffer )
6970 return 0;
6971
6972 // get length of this chunk containing the uuid
6973 chunk_value = -1;
6974 buffer = BufferToChunkValue( bReverseByteOrder,sizeof_chunk_value,buffer,buffer_end,&chunk_value );
6975 if ( 0 == buffer || chunk_value < 0 )
6976 return 0;
6977
6978 // determine how long the chunk is supposed to be and validate the length.
6979 //
6980 // The "16+4+sizeof_chunk_value+21+4+4" in the bLookForUserTableRecordHeader
6981 // breaks down as:
6982 // 16 sizeof(uuid)
6983 // +4 + sizeof(TCODE_USER_TABLE_RECORD_HEADER chunk typecode)
6984 // +sizeof_chunk_value + sizeof(TCODE_USER_TABLE_RECORD_HEADER chunk length)
6985 // +21 + major ver, minor ver, bool, archive ver, 3dm ver
6986 // +4 + sizeof(TCODE_USER_TABLE_RECORD_HEADER chunk crc)
6987 // +4 + sizeof(TCODE_USER_TABLE_UUID chunk crc)
6988 const bool bLookForUserTableRecordHeader = (TCODE_USER_TABLE_UUID == expected_tcode
6989 && ((ON__UINT64)chunk_value) >= (16+4+sizeof_chunk_value+21+4+4)
6990 );
6991 if ( !bLookForUserTableRecordHeader && 20 != chunk_value )
6992 return 0;
6993 buffer = BufferToUuid(bReverseByteOrder,buffer,buffer_end,uuid);
6994 if ( 0 == buffer )
6995 return 0;
6996 if( 0 != expected_uuid && uuid != *expected_uuid )
6997 return 0;
6998
6999 if ( bLookForUserTableRecordHeader )
7000 {
7001 // make sure there is a TCODE_USER_TABLE_RECORD_HEADER chunk and skip over it.
7002 buffer = BufferValidateTcode(bReverseByteOrder,buffer,buffer_end,TCODE_USER_TABLE_RECORD_HEADER);
7003 if ( 0 == buffer )
7004 return 0;
7005 // get length of the TCODE_USER_TABLE_RECORD_HEADER chunk
7006 ON__INT64 header_length = -1;
7007 buffer = BufferToChunkValue( bReverseByteOrder,sizeof_chunk_value,buffer,buffer_end,&header_length );
7008 if ( 0 == buffer )
7009 return 0;
7010 if ( header_length < 25 )
7011 return 0;
7012 if ( buffer >= buffer_end || buffer_end - buffer < header_length )
7013 return 0;
7014 buffer += header_length;
7015 }
7016
7017 buffer = BufferToUINT32(bReverseByteOrder,buffer,buffer_end,&c);
7018 if ( 0 == buffer )
7019 return 0;
7020 cc = ON_CRC32(0,4,&uuid.Data1);
7021 cc = ON_CRC32(cc,2,&uuid.Data2);
7022 cc = ON_CRC32(cc,2,&uuid.Data3);
7023 cc = ON_CRC32(cc,8,&uuid.Data4[0]);
7024 if ( c != cc )
7025 return 0;
7026
7027 return buffer;
7028 }
7029
7030
FindMisplacedTable(ON__UINT64 filelength,const ON__UINT32 table_tcode,const ON__UINT32 table_record_tcode,const ON_UUID class_uuid,const ON__UINT64 min_length_data)7031 bool ON_BinaryArchive::FindMisplacedTable(
7032 ON__UINT64 filelength,
7033 const ON__UINT32 table_tcode,
7034 const ON__UINT32 table_record_tcode,
7035 const ON_UUID class_uuid,
7036 const ON__UINT64 min_length_data
7037 )
7038 {
7039 bool rc = false;
7040 unsigned char buffer2048[2048];
7041 const ON__UINT64 pos0 = CurrentPosition();
7042 if ( filelength > 0 && pos0 >= filelength )
7043 return false;
7044
7045 ON__UINT32 tcode;
7046 ON__INT64 i64;
7047
7048 const bool bReverseByteOrder = (ON::big_endian == Endian());
7049 const size_t sizeof_chunk_typecode = 4;
7050 const size_t sizeof_chunk_value = SizeofChunkLength();
7051 const size_t sizeof_chunk_header = sizeof_chunk_typecode + sizeof_chunk_value;
7052 size_t length_of_user_uuid_and_header = 0;
7053 const bool bFindObjectTable = ( TCODE_OBJECT_TABLE == table_tcode
7054 && TCODE_OBJECT_RECORD == table_record_tcode );
7055 const bool bFindUserTable = ( TCODE_USER_TABLE == table_tcode
7056 && TCODE_USER_RECORD == table_record_tcode );
7057
7058 if ( TCODE_USER_TABLE == table_tcode && !bFindUserTable )
7059 return false;
7060 if ( TCODE_OBJECT_TABLE == table_tcode && !bFindObjectTable )
7061 return false;
7062 if ( bFindUserTable && ON_UuidIsNil(class_uuid) )
7063 {
7064 // must provide plug-in id when searching for user tables
7065 ON_ERROR("ON_BinaryArchive::FindMisplacedTable - must provide plug-in id when searching for user tables");
7066 return false;
7067 }
7068
7069 if ( !SeekFromStart(0) )
7070 return false;
7071
7072 ON__UINT64 pos1 = CurrentPosition();
7073 ON__UINT64 pos;
7074 ON__UINT64 empty_table_pos = 0; // position of first empty table candidate
7075 int empty_table_status = 0; // 1 = found a candidate for an empty table
7076 // 2 = found 2 or more candidates
7077
7078 const size_t sizeof_buffer2048 = sizeof(buffer2048);
7079 bool bAtEOF = false;
7080
7081 while(!bAtEOF)
7082 {
7083 pos = CurrentPosition();
7084 if ( pos < pos1 )
7085 {
7086 break;
7087 }
7088 else if ( pos > pos1 )
7089 {
7090 if ( !BigSeekBackward(pos - pos1) )
7091 break;
7092 if ( pos1 != CurrentPosition() )
7093 break;
7094 }
7095
7096 memset(buffer2048,0,sizeof_buffer2048);
7097 // Depending on the table and the version of the file, less than
7098 // sizeof_buffer128 bytes may be read. Setting bit 0x04 of
7099 // m_error_message_mask disables calls to ON_Error when we
7100 // attempt to read beyond the end of file.
7101 const unsigned int saved_error_message_mask = m_error_message_mask;
7102 m_error_message_mask |= 0x04;
7103 const size_t sizeof_read = Read(sizeof_buffer2048,buffer2048);
7104 m_error_message_mask = saved_error_message_mask;
7105 if ( sizeof_read < sizeof_buffer2048 )
7106 {
7107 // we need to parse what was read, but there's nothing after this.
7108 bAtEOF = true;
7109 }
7110 if ( sizeof_read < 2*sizeof_chunk_header || sizeof_read > sizeof_buffer2048 )
7111 break;
7112 const unsigned char* buffer_end = (&buffer2048[0]) + sizeof_read;
7113 const unsigned char* buffer = buffer2048;
7114
7115 pos1++;
7116
7117 // "read" 4 byte tcode
7118 tcode = !table_tcode;
7119 buffer = BufferToUINT32(bReverseByteOrder,buffer,buffer_end,&tcode);
7120 if ( 0 == buffer )
7121 break;
7122
7123 if ( table_tcode != tcode )
7124 {
7125 // This for loop looks through the buffer we just
7126 // read to reduce the amount of times we seek backwards
7127 // and re-read.
7128 for ( size_t i = 1; i <= sizeof_read - sizeof_chunk_typecode; i++ )
7129 {
7130 tcode = !table_tcode;
7131 buffer = BufferToUINT32(bReverseByteOrder,&buffer2048[i],buffer_end,&tcode);
7132 if ( 0 == buffer || table_tcode == tcode )
7133 {
7134 if ( bAtEOF && sizeof_read > 0 && 0 != buffer && table_tcode == tcode )
7135 {
7136 // this table starts within sizeof_buffer2048 bytes of the eof.
7137 bAtEOF = false;
7138 }
7139 break;
7140 }
7141 pos1++;
7142 }
7143 continue; // start again with archive positioned at the tcode we want
7144 }
7145
7146 // "read" 4 or 8 byte chunk value
7147 i64 = -1;
7148 buffer = BufferToChunkValue(bReverseByteOrder,sizeof_chunk_value,buffer,buffer_end,&i64);
7149 if ( 0 == buffer || i64 <= 0 )
7150 continue;
7151 const ON__UINT64 length_of_table = (ON__UINT64)i64;
7152
7153 if ( length_of_table < 2*sizeof_chunk_header + 4 + min_length_data )
7154 {
7155 if ( sizeof_chunk_header == length_of_table && 2 != empty_table_status )
7156 {
7157 // see if we are at a TCODE_ENDOFTABLE chunk
7158 buffer = BufferValidateTcode(bReverseByteOrder,buffer,buffer_end,TCODE_ENDOFTABLE);
7159 if ( 0 != buffer )
7160 {
7161 i64 = -1;
7162 buffer = BufferToChunkValue(bReverseByteOrder,sizeof_chunk_value,buffer,buffer_end,&i64);
7163 if ( 0 == i64 )
7164 {
7165 if ( 0 == empty_table_status )
7166 {
7167 empty_table_pos = pos1-1;
7168 empty_table_status = 1;
7169 }
7170 else
7171 {
7172 // found 2 or more candidates for the end of table chunk
7173 empty_table_status = 2;
7174 }
7175 }
7176 }
7177 }
7178 continue;
7179 }
7180
7181 if ( bFindUserTable )
7182 {
7183 // We found TCODE_USER_TABLE + chunk length. If it is a user table,
7184 // there should be a TCODE_USER_TABLE_UUID chunk with a crc.
7185 const unsigned char* buffer0 = buffer;
7186 buffer = EmergencyFindTable_UuidHelper(bReverseByteOrder,sizeof_chunk_value,buffer,buffer_end,TCODE_USER_TABLE_UUID,&class_uuid);
7187 if ( 0 == buffer || buffer <= buffer0 )
7188 continue;
7189
7190 length_of_user_uuid_and_header = buffer - buffer0;
7191 // At this point we should be postioned at the table_record_tcode = TCODE_USER_RECORD chunk
7192 }
7193
7194 // see if the start of the buffer contains the 4 byte typecode value = table_record_tcode.
7195 buffer = BufferValidateTcode(bReverseByteOrder,buffer,buffer_end,table_record_tcode);
7196 if ( 0 == buffer )
7197 continue;
7198 i64 = -1;
7199 buffer = BufferToChunkValue( bReverseByteOrder, sizeof_chunk_value,buffer,buffer_end,&i64);
7200 if ( 0 == buffer || i64 <= 0 )
7201 continue;
7202 const ON__UINT64 length_of_record = (ON__UINT64)i64;
7203
7204
7205 if ( bFindUserTable )
7206 {
7207 ON__UINT64 expected_length_of_table = length_of_user_uuid_and_header
7208 + sizeof_chunk_header
7209 + length_of_record;
7210 if ( expected_length_of_table != length_of_table )
7211 continue;
7212 }
7213 else
7214 {
7215 if ( length_of_record < 4*sizeof_chunk_header + 20 + min_length_data )
7216 continue;
7217 if ( length_of_record + 2*sizeof_chunk_header > length_of_table)
7218 continue;
7219
7220 if (bFindObjectTable)
7221 {
7222 buffer = BufferValidateTcode(bReverseByteOrder,buffer,buffer_end,TCODE_OBJECT_RECORD_TYPE);
7223 if ( 0 == buffer )
7224 continue;
7225 // The TCODE_OBJECT_RECORD_TYPE is a shot chunk whose value is a bitfield
7226 // used to filter reading of objects. Checking the value will not help
7227 // validate the record, but we need to skip over it.
7228 buffer = BufferToChunkValue(bReverseByteOrder,sizeof_chunk_value,buffer,buffer_end,0);
7229 if ( 0 == buffer )
7230 continue;
7231 }
7232
7233 buffer = BufferValidateTcode(bReverseByteOrder,buffer,buffer_end,TCODE_OPENNURBS_CLASS);
7234 if ( 0 == buffer )
7235 continue;
7236
7237 i64 = -1;
7238 buffer = BufferToChunkValue( bReverseByteOrder,sizeof_chunk_value,buffer,buffer_end,&i64);
7239 if ( 0 == buffer || i64 <= 0 )
7240 continue;
7241 const ON__UINT64 length_of_on_class = (ON__UINT64)i64;
7242
7243 if ( length_of_on_class < 3*sizeof_chunk_header + 20 + min_length_data )
7244 continue;
7245
7246 if ( length_of_on_class + sizeof_chunk_header + 4 > length_of_record)
7247 continue;
7248
7249 const unsigned char* buffer0 = buffer;
7250 buffer = EmergencyFindTable_UuidHelper(bReverseByteOrder,sizeof_chunk_value,buffer,buffer_end,TCODE_OPENNURBS_CLASS_UUID,(ON_UuidIsNil(class_uuid) ? NULL : &class_uuid));
7251 if ( 0 == buffer || buffer <= buffer0)
7252 continue;
7253 const size_t length_of_uuid_chunk = buffer-buffer0;
7254
7255 buffer = BufferValidateTcode(bReverseByteOrder,buffer,buffer_end,TCODE_OPENNURBS_CLASS_DATA);
7256 if ( 0 == buffer )
7257 continue;
7258
7259 i64 = -1;
7260 buffer = BufferToChunkValue( bReverseByteOrder,sizeof_chunk_value,buffer,buffer_end,&i64);
7261 if ( 0 == buffer || i64 < 0 )
7262 continue;
7263 const ON__UINT64 length_of_data = (ON__UINT64)i64;
7264
7265 if ( length_of_data < min_length_data )
7266 continue;
7267 if ( length_of_data + length_of_uuid_chunk + 2*sizeof_chunk_header > length_of_on_class)
7268 continue;
7269 }
7270
7271 // position archive at point where the table tcode was read
7272 if ( !BigSeekBackward(sizeof_read) )
7273 break;
7274 pos = CurrentPosition();
7275 if ( pos+1 == pos1)
7276 rc = true;
7277 break;
7278 }
7279
7280 if ( !rc )
7281 {
7282 // we didn't fing a table containing anything
7283 if ( 1 == empty_table_status )
7284 {
7285 // we found one candidate for an empty table.
7286 // This is reasonable for materials, bitmaps, and the like.
7287 rc = BigSeekFromStart(empty_table_pos);
7288 }
7289 else
7290 {
7291 // nothing in this file.
7292 BigSeekFromStart(pos0);
7293 }
7294 }
7295 return rc;
7296 }
7297
FindTableInDamagedArchive(const unsigned int tcode_table,const unsigned int tcode_record,const ON_UUID class_uuid,const int min_length_data)7298 bool ON_BinaryArchive::FindTableInDamagedArchive(
7299 const unsigned int tcode_table,
7300 const unsigned int tcode_record,
7301 const ON_UUID class_uuid,
7302 const int min_length_data
7303 )
7304 {
7305 bool rc = FindMisplacedTable(
7306 0,
7307 tcode_table,
7308 tcode_record,
7309 class_uuid,
7310 min_length_data
7311 );
7312 return rc;
7313 }
7314
7315 /*
7316 static
7317 bool FindMaterialTable( ON_BinaryArchive& binary_archive, size_t filelength )
7318 {
7319 bool rc = EmergencyFindTable(
7320 binary_archive, filelength,
7321 TCODE_MATERIAL_TABLE, TCODE_MATERIAL_RECORD,
7322 ON_Material::m_ON_Material_class_id.Uuid(),
7323 114
7324 );
7325 return rc;
7326 }
7327 */
7328
EndRead3dmTable(unsigned int typecode)7329 bool ON_BinaryArchive::EndRead3dmTable( unsigned int typecode )
7330 {
7331 bool rc = false;
7332 const table_type tt = TableTypeFromTypecode(typecode);
7333 if (tt == no_active_table) {
7334 ON_ERROR("ON_BinaryArchive::EndRead3dmTable() bad typecode");
7335 return false;
7336 }
7337 if ( m_active_table != tt ) {
7338 ON_ERROR("ON_BinaryArchive::EndRead3dmTable() m_active_table != t");
7339 return false;
7340 }
7341 if ( m_3dm_version == 1 ) {
7342 if ( m_chunk.Count() != 0 ) {
7343 ON_ERROR("ON_BinaryArchive::EndRead3dmTable() v1 file m_chunk.Count() != 0");
7344 return false;
7345 }
7346 rc = true;
7347 }
7348 else {
7349 if ( m_active_table == group_table && m_3dm_opennurbs_version < 200012210 )
7350 {
7351 // 3DM archives written before version 200012210 and before do not have group tables
7352 rc = true;
7353 }
7354 else if ( m_active_table == font_table && m_3dm_opennurbs_version < 200109180 )
7355 {
7356 // 3DM archives written before version 200109180 and before do not have font tables
7357 rc = true;
7358 }
7359 else if ( m_active_table == dimstyle_table && m_3dm_opennurbs_version < 200109260 )
7360 {
7361 // 3DM archives written before version 200109260 and before do not have dimstyle tables
7362 rc = true;
7363 }
7364 else if ( m_active_table == instance_definition_table && m_3dm_opennurbs_version < 200205110 )
7365 {
7366 // 3DM archives written before version 200205110 and before do not have instance definition tables
7367 rc = true;
7368 }
7369 else if ( m_active_table == hatchpattern_table && m_3dm_opennurbs_version < 200405030 )
7370 {
7371 // 3DM archives written before version 200405030 and before do not have hatch pattern tables
7372 rc = true;
7373 }
7374 else if ( m_active_table == linetype_table && m_3dm_opennurbs_version < 200503170 )
7375 {
7376 // 3DM archives written before version 200503170 and before do not have linetype tables
7377 rc = true;
7378 }
7379 else if ( m_active_table == texture_mapping_table && m_3dm_opennurbs_version < 200511110 )
7380 {
7381 // 3DM archives written before version 200511110 and before do not have texture mapping tables
7382 rc = true;
7383 }
7384 else if ( m_active_table == historyrecord_table && m_3dm_opennurbs_version < 200601180 )
7385 {
7386 // 3DM archives written before version 200601180 and before do not have history record tables
7387 rc = true;
7388 }
7389 else
7390 {
7391 if ( m_chunk.Count() != 1 )
7392 {
7393 ON_ERROR("ON_BinaryArchive::EndRead3dmTable() v2 file m_chunk.Count() != 1");
7394 return false;
7395 }
7396 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
7397 if ( 0 == c || c->m_typecode != typecode )
7398 {
7399 ON_ERROR("ON_BinaryArchive::EndRead3dmTable() m_chunk.Last()->typecode != typecode");
7400 return false;
7401 }
7402 rc = EndRead3dmChunk();
7403 }
7404 }
7405 m_active_table = no_active_table;
7406 return rc;
7407 }
7408
BeginWrite3dmBitmapTable()7409 bool ON_BinaryArchive::BeginWrite3dmBitmapTable()
7410 {
7411 return BeginWrite3dmTable( TCODE_BITMAP_TABLE );
7412 }
7413
EndWrite3dmBitmapTable()7414 bool ON_BinaryArchive::EndWrite3dmBitmapTable()
7415 {
7416 return EndWrite3dmTable( TCODE_BITMAP_TABLE );
7417 }
7418
Write3dmBitmap(const ON_Bitmap & bitmap)7419 bool ON_BinaryArchive::Write3dmBitmap( const ON_Bitmap& bitmap )
7420 {
7421 bool rc = false;
7422 if ( m_3dm_version != 1 )
7423 {
7424 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
7425 if ( c && c->m_typecode == TCODE_BITMAP_TABLE )
7426 {
7427 rc = BeginWrite3dmChunk( TCODE_BITMAP_RECORD, 0 );
7428 if ( rc )
7429 {
7430 rc = WriteObject( bitmap );
7431 if ( !EndWrite3dmChunk() )
7432 rc = false;
7433 }
7434 }
7435 else
7436 {
7437 ON_ERROR("ON_BinaryArchive::Write3dmBitmap() must be called in BeginWrite3dmBitmapTable() block");
7438 rc = false;
7439 }
7440 }
7441 return rc;
7442 }
7443
BeginRead3dmBitmapTable()7444 bool ON_BinaryArchive::BeginRead3dmBitmapTable()
7445 {
7446 bool rc = BeginRead3dmTable( TCODE_BITMAP_TABLE );
7447 if ( !rc )
7448 {
7449 // 1 November 2005 Dale Lear
7450 // This fall back is slow but it has been finding
7451 // layer and object tables in damaged files. I'm
7452 // adding it to the other BeginRead3dm...Table()
7453 // functions when it makes sense.
7454 rc = FindMisplacedTable(
7455 0,
7456 TCODE_BITMAP_TABLE, TCODE_BITMAP_RECORD,
7457 ON_nil_uuid, // multiple types of opennurbs objects in bitmap tables
7458 40
7459 );
7460 if ( rc )
7461 {
7462 rc = BeginRead3dmTable( TCODE_BITMAP_TABLE );
7463 }
7464 }
7465 return rc;
7466 }
7467
EndRead3dmBitmapTable()7468 bool ON_BinaryArchive::EndRead3dmBitmapTable()
7469 {
7470 return EndRead3dmTable( TCODE_BITMAP_TABLE );
7471 }
7472
Read3dmBitmap(ON_Bitmap ** ppBitmap)7473 int ON_BinaryArchive::Read3dmBitmap( // returns 0 at end of bitmap table
7474 // 1 bitmap successfully read
7475 ON_Bitmap** ppBitmap // bitmap returned here
7476 )
7477 {
7478 if ( ppBitmap )
7479 *ppBitmap = 0;
7480 ON_Bitmap* bitmap = 0;
7481 int rc = 0;
7482 if ( m_3dm_version != 1 ) {
7483 ON__UINT32 tcode = 0;
7484 ON__INT64 big_value = 0;
7485 if ( BeginRead3dmBigChunk( &tcode, &big_value ) )
7486 {
7487 if ( tcode == TCODE_BITMAP_RECORD )
7488 {
7489 ON_Object* p = 0;
7490 if ( ReadObject( &p ) )
7491 {
7492 bitmap = ON_Bitmap::Cast(p);
7493 if ( !bitmap )
7494 delete p;
7495 else
7496 rc = 1;
7497 }
7498 if (!bitmap)
7499 {
7500 ON_ERROR("ON_BinaryArchive::Read3dmBitmap() - corrupt bitmap table");
7501 }
7502 if ( ppBitmap )
7503 *ppBitmap = bitmap;
7504 else if ( bitmap )
7505 delete bitmap;
7506 }
7507 else if ( tcode != TCODE_ENDOFTABLE )
7508 {
7509 ON_ERROR("ON_BinaryArchive::Read3dmBitmap() - corrupt bitmap table");
7510 }
7511 EndRead3dmChunk();
7512 }
7513 }
7514
7515 return rc;
7516 }
7517
7518
BeginWrite3dmLayerTable()7519 bool ON_BinaryArchive::BeginWrite3dmLayerTable()
7520 {
7521 bool rc = false;
7522 if ( m_3dm_version != 1 ) {
7523 rc = BeginWrite3dmTable( TCODE_LAYER_TABLE );
7524 }
7525 else {
7526 if ( m_chunk.Count() ) {
7527 ON_ERROR("ON_BinaryArchive::BeginWrite3dmLayerTable() - chunk stack should be empty");
7528 return false;
7529 }
7530 if ( m_active_table != no_active_table ) {
7531 ON_ERROR("ON_BinaryArchive::BeginWrite3dmLayerTable() - m_active_table != no_active_table");
7532 }
7533 m_active_table = layer_table;
7534 rc = true;
7535 }
7536
7537 return rc;
7538 }
7539
Write3dmLayer(const ON_Layer & layer)7540 bool ON_BinaryArchive::Write3dmLayer( const ON_Layer& layer )
7541 {
7542 bool rc = false;
7543 if ( m_active_table != layer_table ) {
7544 ON_ERROR("ON_BinaryArchive::Write3dmLayer() - m_active_table != layer_table");
7545 }
7546
7547 if ( m_3dm_version == 1 ) {
7548 // legacy version 1 layer information is in a top level TCODE_LAYER chunk
7549 if ( m_chunk.Count() ) {
7550 ON_ERROR("ON_BinaryArchive::Write3dmLayer() - version 1 - chunk stack should be empty");
7551 return false;
7552 }
7553 ON_String s = layer.LayerName();
7554 if ( !s.IsEmpty() ) {
7555 rc = BeginWrite3dmChunk( TCODE_LAYER, 0 );
7556
7557 // layer name
7558 if (rc) {
7559 rc = BeginWrite3dmChunk( TCODE_LAYERNAME, 0 );
7560 if(rc) rc = WriteString(s);
7561 if (!EndWrite3dmChunk())
7562 rc = false;
7563 }
7564
7565 // layer color
7566 if (rc) {
7567 rc = BeginWrite3dmChunk( TCODE_RGB, layer.Color() );
7568 if (!EndWrite3dmChunk())
7569 rc = false;
7570 }
7571
7572 // layer mode normal=0/hidden=1/locked=2
7573 if (rc)
7574 {
7575 int mode;
7576 if ( layer.IsLocked() )
7577 mode = 2; // "locked"
7578 else if ( layer.IsVisible() )
7579 mode = 0; // "normal"
7580 else
7581 mode = 1; // "hidden"
7582 rc = BeginWrite3dmChunk( TCODE_LAYERSTATE, mode );
7583 if (!EndWrite3dmChunk())
7584 rc = false;
7585 }
7586
7587 if ( !BeginWrite3dmChunk( TCODE_ENDOFTABLE, 0 ) )
7588 rc = false;
7589 if ( !EndWrite3dmChunk() )
7590 rc = false;
7591
7592 if (!EndWrite3dmChunk()) // end of TCODE_LAYER chunk
7593 rc = false;
7594 }
7595 }
7596 else {
7597 // version 2+
7598 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
7599 if ( c && c->m_typecode == TCODE_LAYER_TABLE ) {
7600 rc = BeginWrite3dmChunk( TCODE_LAYER_RECORD, 0 );
7601 if ( rc ) {
7602 rc = WriteObject( layer );
7603 if ( !EndWrite3dmChunk() )
7604 rc = false;
7605 }
7606 }
7607 else {
7608 ON_ERROR("ON_BinaryArchive::Write3dmLayer() must be called in BeginWrite3dmLayerTable(2) block");
7609 rc = false;
7610 }
7611 }
7612
7613 return rc;
7614 }
7615
EndWrite3dmLayerTable()7616 bool ON_BinaryArchive::EndWrite3dmLayerTable()
7617 {
7618 bool rc = false;
7619 if ( m_3dm_version == 1 ) {
7620 if ( m_active_table != layer_table ) {
7621 ON_ERROR("ON_BinaryArchive::EndWrite3dmLayerTable() - m_active_table != layer_table");
7622 }
7623 rc = true;
7624 m_active_table = no_active_table;
7625 }
7626 else {
7627 rc = EndWrite3dmTable( TCODE_LAYER_TABLE );
7628 }
7629 return rc;
7630 }
7631
BeginRead3dmLayerTable()7632 bool ON_BinaryArchive::BeginRead3dmLayerTable()
7633 {
7634 bool rc = false;
7635 m_3dm_v1_layer_index = 0;
7636 rc = BeginRead3dmTable( TCODE_LAYER_TABLE );
7637 if ( !rc )
7638 {
7639 // 8 October 2004 Dale Lear
7640 // This fall back is slow but it will find
7641 // layer tables in files that have been damaged.
7642 rc = FindMisplacedTable(
7643 0,
7644 TCODE_LAYER_TABLE, TCODE_LAYER_RECORD,
7645 ON_Layer::m_ON_Layer_class_id.Uuid(),
7646 30
7647 );
7648 if ( rc )
7649 {
7650 rc = BeginRead3dmTable( TCODE_LAYER_TABLE );
7651 }
7652
7653 }
7654 else if ( rc && m_3dm_version == 1 ) {
7655 rc = Seek3dmChunkFromStart( TCODE_LAYER );
7656 rc = true; // there are 1.0 files written by the old IO toolkit that have no layers
7657 }
7658 return rc;
7659 }
7660
Read3dmV1LayerIndex(const char * sV1LayerName) const7661 int ON_BinaryArchive::Read3dmV1LayerIndex(const char* sV1LayerName) const
7662 {
7663 // returns V1 layer index
7664
7665 int layer_index = -1;
7666
7667 if ( ON::read3dm == m_mode
7668 && 0 == m_3dm_opennurbs_version
7669 && 1 == m_3dm_version
7670 && 0 != m_V1_layer_list
7671 && 0 != sV1LayerName
7672 && 0 != sV1LayerName[0]
7673 )
7674 {
7675 struct ON__3dmV1LayerIndex* p = m_V1_layer_list;
7676 int i;
7677 for ( i = 0; 0 != p && i < 1000; i++ )
7678 {
7679 if ( p->m_layer_index < 0 )
7680 break;
7681 if ( p->m_layer_name_length < 1 || p->m_layer_name_length>256)
7682 break;
7683 if ( 0 == p->m_layer_name )
7684 break;
7685 if ( 0 == p->m_layer_name[0] )
7686 break;
7687 if ( 0 != p->m_layer_name[p->m_layer_name_length] )
7688 break;
7689 if ( !on_stricmp(p->m_layer_name,sV1LayerName) )
7690 {
7691 layer_index = p->m_layer_index;
7692 break;
7693 }
7694 p = p->m_next;
7695 }
7696 }
7697
7698 return layer_index;
7699 }
7700
Read3dmV1Layer(ON_Layer * & layer)7701 bool ON_BinaryArchive::Read3dmV1Layer( ON_Layer*& layer )
7702 {
7703 ON_String s;
7704 bool rc = 0;
7705 ON__UINT32 tcode;
7706 ON__INT64 big_value;
7707 for (;;)
7708 {
7709 tcode = 0;
7710 big_value = 0;
7711 if (!BeginRead3dmBigChunk(&tcode,&big_value))
7712 break; // assume we are at the end of the file
7713 if ( tcode == TCODE_LAYER ) {
7714 layer = new ON_Layer();
7715 layer->SetLayerIndex(m_3dm_v1_layer_index++);
7716 rc = 1;
7717 break;
7718 }
7719 if (!EndRead3dmChunk())
7720 break;
7721 }
7722 if ( layer ) {
7723 rc = false;
7724 for (;;)
7725 {
7726 tcode = 0;
7727 big_value = 0;
7728 if (!BeginRead3dmBigChunk(&tcode,&big_value))
7729 break;
7730 switch(tcode)
7731 {
7732 case TCODE_LAYERNAME:
7733 {
7734 int slen = 0;
7735 ReadInt(&slen);
7736 if ( slen < 0 || slen > 10000 )
7737 {
7738 ON_ERROR("ON_BinaryArchive::Read3dmV1Layer() - invalid layer name length");
7739 }
7740 else
7741 {
7742 s.SetLength(slen);
7743 if ( ReadByte( s.Length(), s.Array() ) )
7744 {
7745 layer->SetLayerName(s);
7746 }
7747 }
7748 }
7749 break;
7750 case TCODE_RGB:
7751 {
7752 ON__UINT64 rgb64 = (ON__UINT64)big_value;
7753 ON__UINT32 rgb32 = (ON__UINT32)rgb64;
7754 layer->SetColor( ON_Color((ON__UINT32)rgb32) );
7755 }
7756 break;
7757 case TCODE_LAYERSTATE:
7758 switch (big_value)
7759 {
7760 case 1: // hidden
7761 layer->SetVisible(false);
7762 layer->SetLocked(false);
7763 break;
7764 case 2: // locked
7765 layer->SetVisible(true);
7766 layer->SetLocked(true);
7767 break;
7768 default: // normal
7769 layer->SetVisible(true);
7770 layer->SetLocked(false);
7771 break;
7772 }
7773 break;
7774 }
7775 if (!EndRead3dmChunk())
7776 break;
7777 if ( TCODE_ENDOFTABLE == tcode ) {
7778 rc = true;
7779 break;
7780 }
7781 }
7782 if ( !EndRead3dmChunk() ) // end of TCODE_LAYER chunk
7783 rc = false;
7784 }
7785 if ( !rc && layer )
7786 {
7787 delete layer;
7788 layer = 0;
7789 }
7790 else if (rc && layer)
7791 {
7792 if ( ON::read3dm == m_mode
7793 && 0 == m_3dm_opennurbs_version
7794 && 1 == m_3dm_version
7795 )
7796 {
7797 // save layer index and name in a linked list.
7798 int s_length = s.Length();
7799 const char* s_name = s.Array();
7800 if ( layer->LayerIndex() >= 0
7801 && s_length > 0
7802 && s_length < 256
7803 && 0 != s_name
7804 && 0 != s_name[0]
7805 )
7806 {
7807 struct ON__3dmV1LayerIndex* p = (struct ON__3dmV1LayerIndex*)oncalloc(1, sizeof(*p) + (s_length+1)*sizeof(*p->m_layer_name) );
7808 p->m_layer_name = (char*)(p+1);
7809 p->m_layer_index = layer->LayerIndex();
7810 p->m_layer_name_length = s_length;
7811 memcpy(p->m_layer_name,s_name,s_length*sizeof(*p->m_layer_name));
7812 p->m_layer_name[s_length] = 0;
7813 p->m_next = m_V1_layer_list;
7814 m_V1_layer_list = p;
7815 }
7816 }
7817 }
7818 return rc;
7819 }
7820
Read3dmLayer(ON_Layer ** ppLayer)7821 int ON_BinaryArchive::Read3dmLayer( ON_Layer** ppLayer )
7822 {
7823 if ( !ppLayer )
7824 return 0;
7825 *ppLayer = 0;
7826 if ( m_active_table != layer_table ) {
7827 ON_ERROR("ON_BinaryArchive::BeginRead3dmLayerTable() - m_active_table != no_active_table");
7828 }
7829 ON__UINT32 tcode;
7830 ON__INT64 big_value;
7831 ON_Layer* layer = NULL;
7832 // returns 0 at end of layer table
7833 if ( m_3dm_version == 1 ) {
7834 Read3dmV1Layer(layer);
7835 }
7836 else {
7837 // version 2+
7838 tcode = 0;
7839 big_value = 0;
7840 if ( BeginRead3dmBigChunk( &tcode, &big_value ) ) {
7841 if ( tcode == TCODE_LAYER_RECORD ) {
7842 ON_Object* p = 0;
7843 if ( ReadObject( &p ) ) {
7844 layer = ON_Layer::Cast(p);
7845 if ( !layer )
7846 delete p;
7847 }
7848 if (!layer) {
7849 ON_ERROR("ON_BinaryArchive::Read3dmLayer() - corrupt layer table");
7850 }
7851 }
7852 else if ( tcode != TCODE_ENDOFTABLE ) {
7853 ON_ERROR("ON_BinaryArchive::Read3dmLayer() - corrupt layer table");
7854 }
7855 EndRead3dmChunk();
7856 }
7857 }
7858 if ( layer )
7859 layer->HasPerViewportSettings(ON_nil_uuid); // this call sets ON_Layer::m__runtime_flags
7860 *ppLayer = layer;
7861 return (layer) ? 1 : 0;
7862 }
7863
EndRead3dmLayerTable()7864 bool ON_BinaryArchive::EndRead3dmLayerTable()
7865 {
7866 bool rc = false;
7867 if ( m_3dm_version == 1 ) {
7868 if ( m_active_table != layer_table ) {
7869 ON_ERROR("ON_BinaryArchive::EndRead3dmLayerTable() - m_active_table != no_active_table");
7870 rc = false;
7871 }
7872 else if ( m_chunk.Count() ) {
7873 ON_ERROR("ON_BinaryArchive::EndRead3dmLayerTable() - m_chunk.Count() > 0");
7874 rc = false;
7875 }
7876 else {
7877 // rewind to start of chunks
7878 rc = SeekFromStart(32)?true:false;
7879 }
7880 m_active_table = no_active_table;
7881 }
7882 else {
7883 rc = EndRead3dmTable( TCODE_LAYER_TABLE );
7884 }
7885 return rc;
7886 }
7887
7888
7889 ///////////////////////////////////////////////////////////
7890 ///////////////////////////////////////////////////////////
7891 ///////////////////////////////////////////////////////////
7892 ///////////////////////////////////////////////////////////
7893
BeginWrite3dmGroupTable()7894 bool ON_BinaryArchive::BeginWrite3dmGroupTable()
7895 {
7896 bool rc = false;
7897 rc = BeginWrite3dmTable( TCODE_GROUP_TABLE );
7898 return rc;
7899 }
7900
Write3dmGroup(const ON_Group & group)7901 bool ON_BinaryArchive::Write3dmGroup( const ON_Group& group )
7902 {
7903 bool rc = false;
7904 if ( m_active_table != group_table ) {
7905 ON_ERROR("ON_BinaryArchive::Write3dmGroup() - m_active_table != group_table");
7906 }
7907
7908 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
7909 if ( c && c->m_typecode == TCODE_GROUP_TABLE ) {
7910 rc = BeginWrite3dmChunk( TCODE_GROUP_RECORD, 0 );
7911 if ( rc ) {
7912 rc = WriteObject( group );
7913 if ( !EndWrite3dmChunk() )
7914 rc = false;
7915 }
7916 }
7917 else {
7918 ON_ERROR("ON_BinaryArchive::Write3dmGroup() must be called in BeginWrite3dmGroupTable() block");
7919 rc = false;
7920 }
7921
7922 return rc;
7923 }
7924
EndWrite3dmGroupTable()7925 bool ON_BinaryArchive::EndWrite3dmGroupTable()
7926 {
7927 bool rc = false;
7928 rc = EndWrite3dmTable( TCODE_GROUP_TABLE );
7929 return rc;
7930 }
7931
BeginRead3dmGroupTable()7932 bool ON_BinaryArchive::BeginRead3dmGroupTable()
7933 {
7934 if ( m_3dm_version == 1 ) {
7935 return true;
7936 }
7937 bool rc = false;
7938 rc = BeginRead3dmTable( TCODE_GROUP_TABLE );
7939
7940 if ( !rc )
7941 {
7942 // 1 November 2005 Dale Lear
7943 // This fall back is slow but it has been finding
7944 // layer and object tables in damaged files. I'm
7945 // adding it to the other BeginRead3dm...Table()
7946 // functions when it makes sense.
7947 rc = FindMisplacedTable(
7948 0,
7949 TCODE_GROUP_TABLE, TCODE_GROUP_RECORD,
7950 ON_Group::m_ON_Group_class_id.Uuid(),
7951 20
7952 );
7953 if ( rc )
7954 {
7955 rc = BeginRead3dmTable( TCODE_GROUP_TABLE );
7956 }
7957 }
7958
7959 return rc;
7960 }
7961
Read3dmGroup(ON_Group ** ppGroup)7962 int ON_BinaryArchive::Read3dmGroup( ON_Group** ppGroup )
7963 {
7964 if ( !ppGroup )
7965 return 0;
7966 *ppGroup = 0;
7967 if ( m_3dm_version == 1 ) {
7968 return 0;
7969 }
7970 if ( m_active_table != group_table ) {
7971 ON_ERROR("ON_BinaryArchive::BeginRead3dmGroupTable() - m_active_table != no_active_table");
7972 }
7973 if ( m_3dm_opennurbs_version < 200012210 ) {
7974 // 3DM archives written before version 200012210 and before do not have group tables
7975 return 0;
7976 }
7977
7978 ON__UINT32 tcode = 0;
7979 ON__INT64 big_value = 0;
7980 ON_Group* group = NULL;
7981 if ( BeginRead3dmBigChunk( &tcode, &big_value ) )
7982 {
7983 if ( tcode == TCODE_GROUP_RECORD ) {
7984 ON_Object* p = 0;
7985 if ( ReadObject( &p ) ) {
7986 group = ON_Group::Cast(p);
7987 if ( !group )
7988 delete p;
7989 }
7990 if (!group) {
7991 ON_ERROR("ON_BinaryArchive::Read3dmGroup() - corrupt group table");
7992 }
7993 }
7994 else if ( tcode != TCODE_ENDOFTABLE ) {
7995 ON_ERROR("ON_BinaryArchive::Read3dmGroup() - corrupt group table");
7996 }
7997 EndRead3dmChunk();
7998 }
7999 *ppGroup = group;
8000 return (group) ? 1 : 0;
8001 }
8002
EndRead3dmGroupTable()8003 bool ON_BinaryArchive::EndRead3dmGroupTable()
8004 {
8005 bool rc = false;
8006 if ( m_3dm_version == 1 ) {
8007 return true;
8008 }
8009 else {
8010 rc = EndRead3dmTable( TCODE_GROUP_TABLE );
8011 }
8012 return rc;
8013 }
8014
8015 ///////////////////////////////////////////////////////////
8016 ///////////////////////////////////////////////////////////
8017 ///////////////////////////////////////////////////////////
8018 ///////////////////////////////////////////////////////////
8019
BeginWrite3dmFontTable()8020 bool ON_BinaryArchive::BeginWrite3dmFontTable()
8021 {
8022 bool rc = false;
8023 rc = BeginWrite3dmTable( TCODE_FONT_TABLE );
8024 return rc;
8025 }
8026
Write3dmFont(const ON_Font & font)8027 bool ON_BinaryArchive::Write3dmFont( const ON_Font& font )
8028 {
8029 bool rc = false;
8030 if ( m_active_table != font_table ) {
8031 ON_ERROR("ON_BinaryArchive::Write3dmFont() - m_active_table != font_table");
8032 }
8033
8034 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
8035 if ( c && c->m_typecode == TCODE_FONT_TABLE ) {
8036 rc = BeginWrite3dmChunk( TCODE_FONT_RECORD, 0 );
8037 if ( rc ) {
8038 rc = WriteObject( font );
8039 if ( !EndWrite3dmChunk() )
8040 rc = false;
8041 }
8042 }
8043 else {
8044 ON_ERROR("ON_BinaryArchive::Write3dmFont() must be called in BeginWrite3dmFontTable() block");
8045 rc = false;
8046 }
8047
8048 return rc;
8049 }
8050
EndWrite3dmFontTable()8051 bool ON_BinaryArchive::EndWrite3dmFontTable()
8052 {
8053 bool rc = false;
8054 rc = EndWrite3dmTable( TCODE_FONT_TABLE );
8055 return rc;
8056 }
8057
BeginRead3dmFontTable()8058 bool ON_BinaryArchive::BeginRead3dmFontTable()
8059 {
8060 if ( m_3dm_version <= 2 ) {
8061 return true;
8062 }
8063 bool rc = false;
8064 rc = BeginRead3dmTable( TCODE_FONT_TABLE );
8065
8066 if ( !rc )
8067 {
8068 // 1 November 2005 Dale Lear
8069 // This fall back is slow but it has been finding
8070 // layer and object tables in damaged files. I'm
8071 // adding it to the other BeginRead3dm...Table()
8072 // functions FindMisplacedTable it makes sense.
8073 rc = FindMisplacedTable(
8074 0,
8075 TCODE_FONT_TABLE, TCODE_FONT_RECORD,
8076 ON_Font::m_ON_Font_class_id.Uuid(),
8077 30
8078 );
8079 if ( rc )
8080 {
8081 rc = BeginRead3dmTable( TCODE_FONT_TABLE );
8082 }
8083 }
8084
8085 return rc;
8086 }
8087
Read3dmFont(ON_Font ** ppFont)8088 int ON_BinaryArchive::Read3dmFont( ON_Font** ppFont )
8089 {
8090 if ( !ppFont )
8091 return 0;
8092 *ppFont = 0;
8093 if ( m_3dm_version <= 2 ) {
8094 return 0;
8095 }
8096 if ( m_active_table != font_table ) {
8097 ON_ERROR("ON_BinaryArchive::BeginRead3dmFontTable() - m_active_table != no_active_table");
8098 }
8099 if ( m_3dm_opennurbs_version < 200109180 ) {
8100 // 3DM archives written before version 200109180 and before do not have font tables
8101 return 0;
8102 }
8103
8104 ON__UINT32 tcode = 0;
8105 ON__INT64 big_value = 0;
8106 ON_Font* font = NULL;
8107 if ( BeginRead3dmBigChunk( &tcode, &big_value ) )
8108 {
8109 if ( tcode == TCODE_FONT_RECORD ) {
8110 ON_Object* p = 0;
8111 if ( ReadObject( &p ) ) {
8112 font = ON_Font::Cast(p);
8113 if ( !font )
8114 delete p;
8115 }
8116 if (!font) {
8117 ON_ERROR("ON_BinaryArchive::Read3dmFont() - corrupt font table");
8118 }
8119 }
8120 else if ( tcode != TCODE_ENDOFTABLE ) {
8121 ON_ERROR("ON_BinaryArchive::Read3dmFont() - corrupt font table");
8122 }
8123 EndRead3dmChunk();
8124 }
8125 *ppFont = font;
8126 return (font) ? 1 : 0;
8127 }
8128
EndRead3dmFontTable()8129 bool ON_BinaryArchive::EndRead3dmFontTable()
8130 {
8131 bool rc = false;
8132 if ( m_3dm_version <= 2 ) {
8133 return true;
8134 }
8135 else {
8136 rc = EndRead3dmTable( TCODE_FONT_TABLE );
8137 }
8138 return rc;
8139 }
8140
8141 ///////////////////////////////////////////////////////////
8142 ///////////////////////////////////////////////////////////
8143 ///////////////////////////////////////////////////////////
8144 ///////////////////////////////////////////////////////////
8145
BeginWrite3dmDimStyleTable()8146 bool ON_BinaryArchive::BeginWrite3dmDimStyleTable()
8147 {
8148 bool rc = false;
8149 rc = BeginWrite3dmTable( TCODE_DIMSTYLE_TABLE );
8150 return rc;
8151 }
8152
Write3dmDimStyle(const ON_DimStyle & dimstyle)8153 bool ON_BinaryArchive::Write3dmDimStyle( const ON_DimStyle& dimstyle )
8154 {
8155 bool rc = false;
8156 if ( m_active_table != dimstyle_table ) {
8157 ON_ERROR("ON_BinaryArchive::Write3dmDimStyle() - m_active_table != dimstyle_table");
8158 }
8159
8160 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
8161 if ( c && c->m_typecode == TCODE_DIMSTYLE_TABLE ) {
8162 rc = BeginWrite3dmChunk( TCODE_DIMSTYLE_RECORD, 0 );
8163 if ( rc ) {
8164 rc = WriteObject( dimstyle );
8165 if ( !EndWrite3dmChunk() )
8166 rc = false;
8167 }
8168 }
8169 else {
8170 ON_ERROR("ON_BinaryArchive::Write3dmDimStyle() must be called in BeginWrite3dmDimStyleTable() block");
8171 rc = false;
8172 }
8173
8174 return rc;
8175 }
8176
EndWrite3dmDimStyleTable()8177 bool ON_BinaryArchive::EndWrite3dmDimStyleTable()
8178 {
8179 bool rc = false;
8180 rc = EndWrite3dmTable( TCODE_DIMSTYLE_TABLE );
8181 return rc;
8182 }
8183
BeginRead3dmDimStyleTable()8184 bool ON_BinaryArchive::BeginRead3dmDimStyleTable()
8185 {
8186 if ( m_3dm_version <= 2 ) {
8187 return true;
8188 }
8189 bool rc = false;
8190 rc = BeginRead3dmTable( TCODE_DIMSTYLE_TABLE );
8191
8192 if ( !rc )
8193 {
8194 // 1 November 2005 Dale Lear
8195 // This fall back is slow but it has been finding
8196 // layer and object tables in damaged files. I'm
8197 // adding it to the other BeginRead3dm...Table()
8198 // functions when it makes sense.
8199 rc = FindMisplacedTable(
8200 0,
8201 TCODE_DIMSTYLE_TABLE, TCODE_DIMSTYLE_RECORD,
8202 ON_DimStyle::m_ON_DimStyle_class_id.Uuid(),
8203 30
8204 );
8205 if ( rc )
8206 {
8207 rc = BeginRead3dmTable( TCODE_DIMSTYLE_TABLE );
8208 }
8209 }
8210
8211 return rc;
8212 }
8213
Read3dmDimStyle(ON_DimStyle ** ppDimStyle)8214 int ON_BinaryArchive::Read3dmDimStyle( ON_DimStyle** ppDimStyle )
8215 {
8216 if ( !ppDimStyle )
8217 return 0;
8218 *ppDimStyle = 0;
8219 if ( m_3dm_version <= 2 ) {
8220 return 0;
8221 }
8222 if ( m_active_table != dimstyle_table ) {
8223 ON_ERROR("ON_BinaryArchive::BeginRead3dmDimStyleTable() - m_active_table != no_active_table");
8224 }
8225 if ( m_3dm_opennurbs_version < 200109260 ) {
8226 // 3DM archives written before version 200109260 and before do not have dimstyle tables
8227 return 0;
8228 }
8229
8230 ON__UINT32 tcode = 0;
8231 ON__INT64 big_value = 0;
8232 ON_DimStyle* dimstyle = NULL;
8233 tcode = 0;
8234 if ( BeginRead3dmBigChunk( &tcode, &big_value ) )
8235 {
8236 if ( tcode == TCODE_DIMSTYLE_RECORD ) {
8237 ON_Object* p = 0;
8238 if ( ReadObject( &p ) ) {
8239 dimstyle = ON_DimStyle::Cast(p);
8240 if ( !dimstyle )
8241 delete p;
8242 }
8243 if (!dimstyle) {
8244 ON_ERROR("ON_BinaryArchive::Read3dmDimStyle() - corrupt dimstyle table");
8245 }
8246 }
8247 else if ( tcode != TCODE_ENDOFTABLE ) {
8248 ON_ERROR("ON_BinaryArchive::Read3dmDimStyle() - corrupt dimstyle table");
8249 }
8250 EndRead3dmChunk();
8251 }
8252 *ppDimStyle = dimstyle;
8253 return (dimstyle) ? 1 : 0;
8254 }
8255
EndRead3dmDimStyleTable()8256 bool ON_BinaryArchive::EndRead3dmDimStyleTable()
8257 {
8258 bool rc = false;
8259 if ( m_3dm_version <= 2 ) {
8260 return true;
8261 }
8262 else {
8263 rc = EndRead3dmTable( TCODE_DIMSTYLE_TABLE );
8264 }
8265 return rc;
8266 }
8267
8268 ///////////////////////////////////////////////////////////
8269 ///////////////////////////////////////////////////////////
8270 ///////////////////////////////////////////////////////////
8271 ///////////////////////////////////////////////////////////
8272
BeginWrite3dmHatchPatternTable()8273 bool ON_BinaryArchive::BeginWrite3dmHatchPatternTable()
8274 {
8275 bool rc = false;
8276 rc = BeginWrite3dmTable( TCODE_HATCHPATTERN_TABLE );
8277 return rc;
8278 }
8279
Write3dmHatchPattern(const ON_HatchPattern & pattern)8280 bool ON_BinaryArchive::Write3dmHatchPattern( const ON_HatchPattern& pattern )
8281 {
8282 bool rc = false;
8283 if ( m_active_table != hatchpattern_table ) {
8284 ON_ERROR("ON_BinaryArchive::Write3dmHatchPattern() - m_active_table != hatchpattern_table");
8285 }
8286
8287 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
8288 if ( c && c->m_typecode == TCODE_HATCHPATTERN_TABLE )
8289 {
8290 rc = BeginWrite3dmChunk( TCODE_HATCHPATTERN_RECORD, 0 );
8291 if (rc)
8292 {
8293 rc = WriteObject( pattern );
8294 if ( !EndWrite3dmChunk() )
8295 rc = false;
8296 }
8297
8298 // 1 Nov 2005 Dale Lear:
8299 //
8300 // This code was used before version 200511010. The reader can
8301 // still read the old files, but old versions of Rhino cannot read
8302 // files written with version 200511010 or later. This happened in
8303 // the early beta cycile of V4. V3 did not have hatch patterns.
8304 // Please leave this comment here until Nov 2006 so I can remember
8305 // what happened if I have to debug file IO. By May 2006, all
8306 // the betas that could write the bogus hatch tables should have
8307 // expired.
8308 //
8309 //if ( rc ) {
8310 // rc = pattern.Write( *this)?true:false;
8311 // if ( !EndWrite3dmChunk())
8312 // rc = false;
8313 //}
8314 }
8315 else
8316 {
8317 ON_ERROR("ON_BinaryArchive::Write3dmHatchPattern() must be called in BeginWrite3dmHatchPatternTable() block");
8318 rc = false;
8319 }
8320
8321 return rc;
8322 }
8323
EndWrite3dmHatchPatternTable()8324 bool ON_BinaryArchive::EndWrite3dmHatchPatternTable()
8325 {
8326 bool rc = false;
8327 rc = EndWrite3dmTable( TCODE_HATCHPATTERN_TABLE );
8328 return rc;
8329 }
8330
BeginRead3dmHatchPatternTable()8331 bool ON_BinaryArchive::BeginRead3dmHatchPatternTable()
8332 {
8333 if ( m_3dm_version <= 3)
8334 {
8335 return true;
8336 }
8337 bool rc = BeginRead3dmTable( TCODE_HATCHPATTERN_TABLE );
8338
8339 if ( !rc && m_3dm_opennurbs_version >= 200511010 )
8340 {
8341 // 1 November 2005 Dale Lear
8342 // This fall back is slow but it has been finding
8343 // layer and object tables in damaged files. I'm
8344 // adding it to the other BeginRead3dm...Table()
8345 // functions when it makes sense.
8346 // It only works on files with ver
8347 rc = FindMisplacedTable(
8348 0,
8349 TCODE_HATCHPATTERN_TABLE, TCODE_HATCHPATTERN_RECORD,
8350 ON_HatchPattern::m_ON_HatchPattern_class_id.Uuid(),
8351 30
8352 );
8353 if ( rc )
8354 {
8355 rc = BeginRead3dmTable( TCODE_HATCHPATTERN_TABLE );
8356 }
8357 }
8358
8359 return rc;
8360 }
8361
Read3dmHatchPattern(ON_HatchPattern ** ppPattern)8362 int ON_BinaryArchive::Read3dmHatchPattern( ON_HatchPattern** ppPattern )
8363 {
8364 if( !ppPattern )
8365 return 0;
8366
8367 *ppPattern = 0;
8368 if( m_3dm_version <= 3) // 1 Nov 2005 Dale lear: change < to <=
8369 return 0; // because v3 files don't have hatch patterns.
8370
8371 if ( m_active_table != hatchpattern_table )
8372 {
8373 ON_ERROR("ON_BinaryArchive::BeginRead3dmHatchPatternTable() - m_active_table != hatchpattern_table");
8374 }
8375 if ( m_3dm_opennurbs_version < 200405030 )
8376 {
8377 // 3DM archives written before version 200405030 do not have hatchpattern tables
8378 return 0;
8379 }
8380
8381 ON__UINT32 tcode = 0;
8382 ON__INT64 big_value = 0;
8383 ON_HatchPattern* pPat = NULL;
8384 if( BeginRead3dmBigChunk( &tcode, &big_value))
8385 {
8386 if ( tcode == TCODE_HATCHPATTERN_RECORD )
8387 {
8388 if ( m_3dm_opennurbs_version < 200511010 )
8389 {
8390 // There was a bug in Write3dmHatchPattern and files written
8391 // before version 200511010 didn't use ON_Object IO.
8392 pPat = new ON_HatchPattern;
8393 if( !pPat->Read( *this))
8394 {
8395 delete pPat;
8396 pPat = NULL;
8397 ON_ERROR("ON_BinaryArchive::Read3dmHatchPattern() - corrupt hatch pattern table");
8398 }
8399 }
8400 else
8401 {
8402 ON_Object* p = 0;
8403 if ( ReadObject( &p ) )
8404 {
8405 pPat = ON_HatchPattern::Cast(p);
8406 if ( !pPat )
8407 delete p;
8408 }
8409 if (!pPat)
8410 {
8411 ON_ERROR("ON_BinaryArchive::Read3dmLayer() - corrupt layer table");
8412 }
8413 }
8414 }
8415 else if ( tcode != TCODE_ENDOFTABLE )
8416 {
8417 ON_ERROR("ON_BinaryArchive::Read3dmHatchPattern() - corrupt hatch pattern table");
8418 }
8419
8420 EndRead3dmChunk();
8421 }
8422 *ppPattern = pPat;
8423 return( pPat) ? 1 : 0;
8424 }
8425
EndRead3dmHatchPatternTable()8426 bool ON_BinaryArchive::EndRead3dmHatchPatternTable()
8427 {
8428 bool rc = false;
8429 if( m_3dm_version <= 3)
8430 {
8431 return true;
8432 }
8433 else
8434 {
8435 rc = EndRead3dmTable( TCODE_HATCHPATTERN_TABLE);
8436 }
8437 return rc;
8438 }
8439
8440
8441
8442 ///////////////////////////////////////////////////////////
8443 ///////////////////////////////////////////////////////////
8444 ///////////////////////////////////////////////////////////
8445 ///////////////////////////////////////////////////////////
8446
BeginWrite3dmLinetypeTable()8447 bool ON_BinaryArchive::BeginWrite3dmLinetypeTable()
8448 {
8449 bool rc = BeginWrite3dmTable( TCODE_LINETYPE_TABLE );
8450 return rc;
8451 }
8452
Write3dmLinetype(const ON_Linetype & linetype)8453 bool ON_BinaryArchive::Write3dmLinetype( const ON_Linetype& linetype )
8454 {
8455 bool rc = false;
8456
8457 if( m_active_table != linetype_table )
8458 {
8459 ON_ERROR("ON_BinaryArchive::Write3dmLinetype() - m_active_table != linetype_table");
8460 }
8461
8462 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
8463 if ( c && c->m_typecode == TCODE_LINETYPE_TABLE )
8464 {
8465 rc = BeginWrite3dmChunk( TCODE_LINETYPE_RECORD, 0 );
8466 if ( rc )
8467 {
8468 rc = WriteObject( linetype );
8469 if ( !EndWrite3dmChunk())
8470 rc = false;
8471 }
8472 }
8473 else
8474 {
8475 ON_ERROR("ON_BinaryArchive::Write3dmLinetype() must be called in BeginWrite3dmLinetypeTable() block");
8476 rc = false;
8477 }
8478
8479 return rc;
8480 }
8481
EndWrite3dmLinetypeTable()8482 bool ON_BinaryArchive::EndWrite3dmLinetypeTable()
8483 {
8484 bool rc = EndWrite3dmTable( TCODE_LINETYPE_TABLE );
8485 return rc;
8486 }
8487
BeginRead3dmLinetypeTable()8488 bool ON_BinaryArchive::BeginRead3dmLinetypeTable()
8489 {
8490 bool rc = false;
8491
8492 if ( m_3dm_version < 4 || m_3dm_opennurbs_version < 200503170 )
8493 {
8494 rc = true;
8495 }
8496 else
8497 {
8498 rc = BeginRead3dmTable( TCODE_LINETYPE_TABLE );
8499 if ( !rc )
8500 {
8501 // 1 November 2005 Dale Lear
8502 // This fall back is slow but it has been finding
8503 // layer and object tables in damaged files. I'm
8504 // adding it to the other BeginRead3dm...Table()
8505 // functions when it makes sense.
8506 rc = FindMisplacedTable(
8507 0,
8508 TCODE_LINETYPE_TABLE, TCODE_LINETYPE_RECORD,
8509 ON_Linetype::m_ON_Linetype_class_id.Uuid(),
8510 20
8511 );
8512 if ( rc )
8513 {
8514 rc = BeginRead3dmTable( TCODE_LINETYPE_TABLE );
8515 }
8516 }
8517 }
8518
8519 return rc;
8520 }
8521
Read3dmLinetype(ON_Linetype ** ppLinetype)8522 int ON_BinaryArchive::Read3dmLinetype( ON_Linetype** ppLinetype )
8523 {
8524 if( !ppLinetype)
8525 return 0;
8526
8527 *ppLinetype = 0;
8528
8529 if( m_3dm_version < 4 || m_3dm_opennurbs_version < 200503170)
8530 return 0;
8531
8532 if ( m_active_table != linetype_table )
8533 {
8534 ON_ERROR("ON_BinaryArchive::BeginRead3dmLinetypeTable() - m_active_table != linetype_table");
8535 }
8536
8537 ON__UINT32 tcode = 0;
8538 ON__INT64 big_value = 0;
8539 ON_Linetype* linetype = NULL;
8540 int rc = -1;
8541 if( BeginRead3dmBigChunk( &tcode, &big_value))
8542 {
8543 if ( tcode == TCODE_LINETYPE_RECORD )
8544 {
8545 ON_Object* p = 0;
8546 if ( ReadObject( &p ) )
8547 {
8548 linetype = ON_Linetype::Cast(p);
8549 if (!linetype )
8550 delete p;
8551 else
8552 {
8553 if (ppLinetype)
8554 *ppLinetype = linetype;
8555 rc = 1;
8556 }
8557 }
8558 if (!linetype)
8559 {
8560 ON_ERROR("ON_BinaryArchive::Read3dmLinetype() - corrupt linetype table");
8561 }
8562 }
8563 else if ( tcode == TCODE_ENDOFTABLE )
8564 {
8565 // end of linetype table
8566 rc = 0;
8567 }
8568 else
8569 {
8570 ON_ERROR("ON_BinaryArchive::Read3dmLinetype() - corrupt linetype table");
8571 }
8572 if (!EndRead3dmChunk())
8573 rc = -1;
8574 }
8575
8576 return rc;
8577 }
8578
EndRead3dmLinetypeTable()8579 bool ON_BinaryArchive::EndRead3dmLinetypeTable()
8580 {
8581 bool rc = false;
8582 if( m_3dm_version < 4 || m_3dm_opennurbs_version < 200503170)
8583 {
8584 rc = true;
8585 }
8586 else
8587 {
8588 rc = EndRead3dmTable( TCODE_LINETYPE_TABLE);
8589 }
8590 return rc;
8591 }
8592
8593
8594 ///////////////////////////////////////////////////////////
8595 ///////////////////////////////////////////////////////////
8596 ///////////////////////////////////////////////////////////
8597 ///////////////////////////////////////////////////////////
8598 ///////////////////////////////////////////////////////////
8599
BeginWrite3dmInstanceDefinitionTable()8600 bool ON_BinaryArchive::BeginWrite3dmInstanceDefinitionTable()
8601 {
8602 bool rc = false;
8603 rc = BeginWrite3dmTable( TCODE_INSTANCE_DEFINITION_TABLE );
8604 return rc;
8605 }
8606
Write3dmInstanceDefinition(const ON_InstanceDefinition & idef)8607 bool ON_BinaryArchive::Write3dmInstanceDefinition( const ON_InstanceDefinition& idef )
8608 {
8609 bool rc = false;
8610 if ( m_active_table != instance_definition_table ) {
8611 ON_ERROR("ON_BinaryArchive::Write3dmInstanceDefinition() - m_active_table != instance_definition_table");
8612 }
8613
8614 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
8615 if ( c && c->m_typecode == TCODE_INSTANCE_DEFINITION_TABLE ) {
8616 rc = BeginWrite3dmChunk( TCODE_INSTANCE_DEFINITION_RECORD, 0 );
8617 if ( rc ) {
8618 rc = WriteObject( idef );
8619 if ( !EndWrite3dmChunk() )
8620 rc = false;
8621 }
8622 }
8623 else {
8624 ON_ERROR("ON_BinaryArchive::Write3dmInstanceDefinition() must be called in BeginWrite3dmInstanceDefinitionTable() block");
8625 rc = false;
8626 }
8627
8628 return rc;
8629 }
8630
EndWrite3dmInstanceDefinitionTable()8631 bool ON_BinaryArchive::EndWrite3dmInstanceDefinitionTable()
8632 {
8633 bool rc = false;
8634 rc = EndWrite3dmTable( TCODE_INSTANCE_DEFINITION_TABLE );
8635 return rc;
8636 }
8637
BeginRead3dmInstanceDefinitionTable()8638 bool ON_BinaryArchive::BeginRead3dmInstanceDefinitionTable()
8639 {
8640 if ( m_3dm_version <= 2 ) {
8641 return true;
8642 }
8643 bool rc = false;
8644 rc = BeginRead3dmTable( TCODE_INSTANCE_DEFINITION_TABLE );
8645
8646 if ( !rc )
8647 {
8648 // 1 November 2005 Dale Lear
8649 // This fall back is slow but it has been finding
8650 // layer and object tables in damaged files. I'm
8651 // adding it to the other BeginRead3dm...Table()
8652 // functions when it makes sense.
8653 rc = FindMisplacedTable(
8654 0,
8655 TCODE_INSTANCE_DEFINITION_TABLE, TCODE_INSTANCE_DEFINITION_RECORD,
8656 ON_InstanceDefinition::m_ON_InstanceDefinition_class_id.Uuid(),
8657 30
8658 );
8659 if ( rc )
8660 {
8661 rc = BeginRead3dmTable( TCODE_INSTANCE_DEFINITION_TABLE );
8662 }
8663 }
8664
8665 return rc;
8666 }
8667
Read3dmInstanceDefinition(ON_InstanceDefinition ** ppInstanceDefinition)8668 int ON_BinaryArchive::Read3dmInstanceDefinition( ON_InstanceDefinition** ppInstanceDefinition )
8669 {
8670 if ( !ppInstanceDefinition )
8671 return 0;
8672 *ppInstanceDefinition = 0;
8673 if ( m_3dm_version <= 2 ) {
8674 return 0;
8675 }
8676 if ( m_active_table != instance_definition_table )
8677 {
8678 ON_ERROR("ON_BinaryArchive::BeginRead3dmInstanceDefinitionTable() - m_active_table != no_active_table");
8679 }
8680 if ( m_3dm_opennurbs_version < 200205110 )
8681 {
8682 // 3DM archives written before version 200205110 and before do not have instance definition tables
8683 return 0;
8684 }
8685
8686 ON__UINT32 tcode = 0;
8687 ON__INT64 big_value = 0;
8688 ON_InstanceDefinition* idef = NULL;
8689 if ( BeginRead3dmBigChunk( &tcode, &big_value ) )
8690 {
8691 if ( tcode == TCODE_INSTANCE_DEFINITION_RECORD ) {
8692 ON_Object* p = 0;
8693 if ( ReadObject( &p ) ) {
8694 idef = ON_InstanceDefinition::Cast(p);
8695 if ( !idef )
8696 delete p;
8697 }
8698 if (!idef) {
8699 ON_ERROR("ON_BinaryArchive::Read3dmInstanceDefinition() - corrupt instance definition table");
8700 }
8701 }
8702 else if ( tcode != TCODE_ENDOFTABLE ) {
8703 ON_ERROR("ON_BinaryArchive::Read3dmInstanceDefinition() - corrupt instance definition table");
8704 }
8705 EndRead3dmChunk();
8706 }
8707 *ppInstanceDefinition = idef;
8708 return (idef) ? 1 : 0;
8709 }
8710
EndRead3dmInstanceDefinitionTable()8711 bool ON_BinaryArchive::EndRead3dmInstanceDefinitionTable()
8712 {
8713 bool rc = false;
8714 if ( m_3dm_version <= 2 ) {
8715 return true;
8716 }
8717 else {
8718 rc = EndRead3dmTable( TCODE_INSTANCE_DEFINITION_TABLE );
8719 }
8720 return rc;
8721 }
8722
8723 ///////////////////////////////////////////////////////////
8724 ///////////////////////////////////////////////////////////
8725 ///////////////////////////////////////////////////////////
8726 ///////////////////////////////////////////////////////////
8727 ///////////////////////////////////////////////////////////
8728
BeginWrite3dmTextureMappingTable()8729 bool ON_BinaryArchive::BeginWrite3dmTextureMappingTable()
8730 {
8731 return BeginWrite3dmTable( TCODE_TEXTURE_MAPPING_TABLE );
8732 }
8733
Write3dmTextureMapping(const ON_TextureMapping & texture_mapping)8734 bool ON_BinaryArchive::Write3dmTextureMapping( const ON_TextureMapping& texture_mapping )
8735 {
8736 bool rc = false;
8737
8738 if ( m_active_table != texture_mapping_table )
8739 {
8740 ON_ERROR("ON_BinaryArchive::Write3dmTextureMapping() - m_active_table != texture_mapping_table");
8741 }
8742
8743 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
8744 if ( !c || c->m_typecode != TCODE_TEXTURE_MAPPING_TABLE )
8745 {
8746 ON_ERROR("ON_BinaryArchive::Write3dmTextureMapping() - active chunk typecode != TCODE_TEXTURE_MAPPING_TABLE");
8747 }
8748 else
8749 {
8750 rc = BeginWrite3dmChunk( TCODE_TEXTURE_MAPPING_RECORD, 0 );
8751 if (rc)
8752 {
8753 rc = WriteObject( texture_mapping );
8754 if ( !EndWrite3dmChunk() )
8755 rc = false;
8756 }
8757 }
8758 return rc;
8759 }
8760
EndWrite3dmTextureMappingTable()8761 bool ON_BinaryArchive::EndWrite3dmTextureMappingTable()
8762 {
8763 return EndWrite3dmTable( TCODE_TEXTURE_MAPPING_TABLE );
8764 }
8765
BeginRead3dmTextureMappingTable()8766 bool ON_BinaryArchive::BeginRead3dmTextureMappingTable()
8767 {
8768 if ( m_3dm_version < 4 || m_3dm_opennurbs_version < 200511110 )
8769 {
8770 return true;
8771 }
8772
8773 bool rc = BeginRead3dmTable( TCODE_TEXTURE_MAPPING_TABLE );
8774 if ( !rc )
8775 {
8776 // 31 October 2005 Dale Lear
8777 // This fall back is slow but it will find
8778 // texture_mapping tables in files that have been damaged.
8779 //
8780 // This approach has been tested with layer tables
8781 // for over a year and has successfully made files
8782 // with garbled starts read correctly after the
8783 // call to EmergencyFindTable was able to detect
8784 // the start of the layer table. I'm adding it
8785 // to texture_mapping tables now because I have a good
8786 // test file.
8787 rc = FindMisplacedTable(
8788 0,
8789 TCODE_TEXTURE_MAPPING_TABLE, TCODE_TEXTURE_MAPPING_RECORD,
8790 ON_TextureMapping::m_ON_TextureMapping_class_id.Uuid(),
8791 sizeof(ON_TextureMapping)
8792 );
8793 if ( rc )
8794 {
8795 rc = BeginRead3dmTable( TCODE_TEXTURE_MAPPING_TABLE );
8796 }
8797 }
8798 return rc;
8799 }
8800
Read3dmTextureMapping(ON_TextureMapping ** ppTextureMapping)8801 int ON_BinaryArchive::Read3dmTextureMapping( ON_TextureMapping** ppTextureMapping )
8802 {
8803 int rc = 0;
8804 if ( !ppTextureMapping )
8805 return 0;
8806 *ppTextureMapping = 0;
8807 ON_TextureMapping* texture_mapping = NULL;
8808 ON__UINT32 tcode = 0;
8809 ON__INT64 big_value = 0;
8810 if ( m_3dm_version < 4 || m_3dm_opennurbs_version < 200511110 )
8811 {
8812 // no texture mapping table until version 200511110 of v4 files
8813 return 0;
8814 }
8815
8816 rc = -1;
8817 if ( BeginRead3dmBigChunk( &tcode, &big_value ) )
8818 {
8819 if ( tcode == TCODE_TEXTURE_MAPPING_RECORD )
8820 {
8821 ON_Object* p = 0;
8822 if ( ReadObject( &p ) )
8823 {
8824 texture_mapping = ON_TextureMapping::Cast(p);
8825 if ( !texture_mapping )
8826 delete p;
8827 else
8828 {
8829 if ( ppTextureMapping )
8830 *ppTextureMapping = texture_mapping;
8831 rc = 1;
8832 }
8833 }
8834 if (!texture_mapping)
8835 {
8836 ON_ERROR("ON_BinaryArchive::Read3dmTextureMapping() - corrupt texture_mapping table");
8837 }
8838 }
8839 else if ( tcode == TCODE_ENDOFTABLE )
8840 {
8841 // end of texture_mapping table
8842 rc = 0;
8843 }
8844 else
8845 {
8846 ON_ERROR("ON_BinaryArchive::Read3dmTextureMapping() - corrupt texture_mapping table");
8847 }
8848 if ( !EndRead3dmChunk() )
8849 rc = -1;
8850 }
8851
8852 return rc;
8853 }
8854
EndRead3dmTextureMappingTable()8855 bool ON_BinaryArchive::EndRead3dmTextureMappingTable()
8856 {
8857 bool rc = false;
8858 if ( m_3dm_version < 4 || m_3dm_opennurbs_version < 200511110 )
8859 {
8860 rc = true;
8861 }
8862 else
8863 {
8864 rc = EndRead3dmTable( TCODE_TEXTURE_MAPPING_TABLE );
8865 }
8866 return rc;
8867 }
8868
8869 ///////////////////////////////////////////////////////////
8870 ///////////////////////////////////////////////////////////
8871 ///////////////////////////////////////////////////////////
8872 ///////////////////////////////////////////////////////////
8873 ///////////////////////////////////////////////////////////
8874
BeginWrite3dmHistoryRecordTable()8875 bool ON_BinaryArchive::BeginWrite3dmHistoryRecordTable()
8876 {
8877 return BeginWrite3dmTable( TCODE_HISTORYRECORD_TABLE );
8878 }
8879
Write3dmHistoryRecord(const ON_HistoryRecord & history_record)8880 bool ON_BinaryArchive::Write3dmHistoryRecord( const ON_HistoryRecord& history_record )
8881 {
8882 bool rc = false;
8883
8884 if ( m_active_table != historyrecord_table )
8885 {
8886 ON_ERROR("ON_BinaryArchive::Write3dmHistoryRecord() - m_active_table != history_record_table");
8887 }
8888
8889 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
8890 if ( !c || c->m_typecode != TCODE_HISTORYRECORD_TABLE )
8891 {
8892 ON_ERROR("ON_BinaryArchive::Write3dmHistoryRecord() - active chunk typecode != TCODE_HISTORYRECORD_TABLE");
8893 }
8894 else
8895 {
8896 rc = BeginWrite3dmChunk( TCODE_HISTORYRECORD_RECORD, 0 );
8897 if (rc)
8898 {
8899 rc = WriteObject( history_record );
8900 if ( !EndWrite3dmChunk() )
8901 rc = false;
8902 }
8903 }
8904 return rc;
8905 }
8906
EndWrite3dmHistoryRecordTable()8907 bool ON_BinaryArchive::EndWrite3dmHistoryRecordTable()
8908 {
8909 return EndWrite3dmTable( TCODE_HISTORYRECORD_TABLE );
8910 }
8911
BeginRead3dmHistoryRecordTable()8912 bool ON_BinaryArchive::BeginRead3dmHistoryRecordTable()
8913 {
8914 if ( m_3dm_version < 4 || m_3dm_opennurbs_version < 200601180 )
8915 {
8916 return true;
8917 }
8918
8919 bool rc = BeginRead3dmTable( TCODE_HISTORYRECORD_TABLE );
8920 if ( !rc )
8921 {
8922 // 31 October 2005 Dale Lear
8923 // This fall back is slow but it will find
8924 // history_record tables in files that have been damaged.
8925 //
8926 // This approach has been tested with layer tables
8927 // for over a year and has successfully made files
8928 // with garbled starts read correctly after the
8929 // call to EmergencyFindTable was able to detect
8930 // the start of the layer table. I'm adding it
8931 // to history_record tables now because I have a good
8932 // test file.
8933 rc = FindMisplacedTable(
8934 0,
8935 TCODE_HISTORYRECORD_TABLE, TCODE_HISTORYRECORD_RECORD,
8936 ON_HistoryRecord::m_ON_HistoryRecord_class_id.Uuid(),
8937 sizeof(ON_HistoryRecord)
8938 );
8939 if ( rc )
8940 {
8941 rc = BeginRead3dmTable( TCODE_HISTORYRECORD_TABLE );
8942 }
8943 }
8944 return rc;
8945 }
8946
Read3dmHistoryRecord(ON_HistoryRecord * & history_record)8947 int ON_BinaryArchive::Read3dmHistoryRecord( ON_HistoryRecord*& history_record )
8948 {
8949 int rc = 0;
8950 history_record = 0;
8951 ON__UINT32 tcode = 0;
8952 ON__INT64 big_value = 0;
8953 if ( m_3dm_version < 4 || m_3dm_opennurbs_version < 200601180 )
8954 {
8955 // no history record table until version 200601180 of v4 files
8956 return 0;
8957 }
8958
8959 rc = -1;
8960 if ( BeginRead3dmBigChunk( &tcode, &big_value ) )
8961 {
8962 if ( tcode == TCODE_HISTORYRECORD_RECORD )
8963 {
8964 ON_Object* p = 0;
8965 if ( ReadObject( &p ) )
8966 {
8967 history_record = ON_HistoryRecord::Cast(p);
8968 if ( !history_record )
8969 {
8970 delete p;
8971 }
8972 else
8973 {
8974 rc = 1;
8975 }
8976 }
8977 if (!history_record)
8978 {
8979 ON_ERROR("ON_BinaryArchive::Read3dmHistoryRecord() - corrupt history_record table");
8980 }
8981 }
8982 else if ( tcode == TCODE_ENDOFTABLE )
8983 {
8984 // end of history_record table
8985 rc = 0;
8986 }
8987 else
8988 {
8989 ON_ERROR("ON_BinaryArchive::Read3dmHistoryRecord() - corrupt history_record table");
8990 }
8991 if ( !EndRead3dmChunk() )
8992 rc = -1;
8993 }
8994
8995 return rc;
8996 }
8997
EndRead3dmHistoryRecordTable()8998 bool ON_BinaryArchive::EndRead3dmHistoryRecordTable()
8999 {
9000 bool rc = false;
9001 if ( m_3dm_version < 4 || m_3dm_opennurbs_version < 200601180 )
9002 {
9003 rc = true;
9004 }
9005 else
9006 {
9007 rc = EndRead3dmTable( TCODE_HISTORYRECORD_TABLE );
9008 }
9009 return rc;
9010 }
9011
9012 ///////////////////////////////////////////////////////////
9013 ///////////////////////////////////////////////////////////
9014 ///////////////////////////////////////////////////////////
9015 ///////////////////////////////////////////////////////////
9016 ///////////////////////////////////////////////////////////
9017
BeginWrite3dmMaterialTable()9018 bool ON_BinaryArchive::BeginWrite3dmMaterialTable()
9019 {
9020 return BeginWrite3dmTable( TCODE_MATERIAL_TABLE );
9021 }
9022
Write3dmMaterial(const ON_Material & material)9023 bool ON_BinaryArchive::Write3dmMaterial( const ON_Material& material )
9024 {
9025 bool rc = false;
9026
9027 if ( m_active_table != material_table )
9028 {
9029 ON_ERROR("ON_BinaryArchive::Write3dmMaterial() - m_active_table != material_table");
9030 }
9031
9032 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
9033 if ( !c || c->m_typecode != TCODE_MATERIAL_TABLE )
9034 {
9035 ON_ERROR("ON_BinaryArchive::Write3dmMaterial() - active chunk typecode != TCODE_MATERIAL_TABLE");
9036 }
9037 else
9038 {
9039 rc = BeginWrite3dmChunk( TCODE_MATERIAL_RECORD, 0 );
9040 if (rc)
9041 {
9042 rc = WriteObject( material );
9043 if ( !EndWrite3dmChunk() )
9044 rc = false;
9045 }
9046 }
9047 return rc;
9048 }
9049
EndWrite3dmMaterialTable()9050 bool ON_BinaryArchive::EndWrite3dmMaterialTable()
9051 {
9052 return EndWrite3dmTable( TCODE_MATERIAL_TABLE );
9053 }
9054
BeginRead3dmMaterialTable()9055 bool ON_BinaryArchive::BeginRead3dmMaterialTable()
9056 {
9057 m_3dm_v1_material_index = 0;
9058 bool rc = BeginRead3dmTable( TCODE_MATERIAL_TABLE );
9059 if ( !rc )
9060 {
9061 // 31 October 2005 Dale Lear
9062 // This fall back is slow but it will find
9063 // material tables in files that have been damaged.
9064 //
9065 // This approach has been tested with layer tables
9066 // for over a year and has successfully made files
9067 // with garbled starts read correctly after the
9068 // call to EmergencyFindTable was able to detect
9069 // the start of the layer table. I'm adding it
9070 // to material tables now because I have a good
9071 // test file.
9072 rc = FindMisplacedTable(
9073 0,
9074 TCODE_MATERIAL_TABLE, TCODE_MATERIAL_RECORD,
9075 ON_Material::m_ON_Material_class_id.Uuid(),
9076 114
9077 );
9078 if ( rc )
9079 {
9080 rc = BeginRead3dmTable( TCODE_MATERIAL_TABLE );
9081 }
9082 }
9083 return rc;
9084 }
9085
Read3dmV1String(ON_String & s)9086 bool ON_BinaryArchive::Read3dmV1String( ON_String& s )
9087 {
9088 int string_length = 0;
9089 s.Empty();
9090 bool rc = ReadInt( &string_length );
9091 if (rc) {
9092 s.ReserveArray(string_length+1);
9093 rc = ReadChar( string_length, s.Array() );
9094 if (rc)
9095 s.SetLength(string_length);
9096 }
9097 return rc;
9098 }
9099
9100
9101 class ON__3dmV1_XDATA
9102 {
9103 // helper class to get V1 "xdata" out of attributes block.
9104 public:
9105 enum
9106 {
9107 unknown_xdata = 0,
9108 hidden_object_layer_name, // m_string = actual layer name
9109 locked_object_layer_name, // m_string = actual layer name
9110 arrow_direction, // m_vector = arrow head location
9111 dot_text // m_string = dot text
9112 }
9113 m_type;
9114 ON_String m_string;
9115 ON_3dVector m_vector;
9116 };
9117
Read3dmV1AttributesOrMaterial(ON_3dmObjectAttributes * attributes,ON_Material * material,ON_BOOL32 & bHaveMat,unsigned int end_mark_tcode,ON__3dmV1_XDATA * xdata)9118 bool ON_BinaryArchive::Read3dmV1AttributesOrMaterial(
9119 ON_3dmObjectAttributes* attributes,
9120 ON_Material* material,
9121 ON_BOOL32& bHaveMat,
9122 unsigned int end_mark_tcode,
9123 ON__3dmV1_XDATA* xdata
9124 )
9125 {
9126 // Check ReadV1Material() if you fix any bugs in the mateial related items
9127
9128 if ( 0 != xdata )
9129 {
9130 xdata->m_type = ON__3dmV1_XDATA::unknown_xdata;
9131 }
9132
9133 bool rc = false;
9134 unsigned int u;
9135 ON__UINT32 tcode = 0;
9136 ON__INT64 big_value = 0;
9137 ON_Color c;
9138 bHaveMat = false;
9139 bool bEndRead3dmChunk_rc;
9140
9141 const unsigned int saved_error_message_mask = m_error_message_mask;
9142
9143 int xdata_layer_index = -1;
9144
9145 if ( attributes )
9146 {
9147 attributes->Default();
9148 }
9149
9150 if ( material )
9151 {
9152 material->Default();
9153 material->m_diffuse.SetRGB(255,255,255);
9154 material->m_specular.SetRGB(255,255,255);
9155 material->m_ambient.SetRGB(0,0,0);
9156 }
9157
9158 for (;;)
9159 {
9160 m_error_message_mask = saved_error_message_mask;
9161
9162 if ( end_mark_tcode != TCODE_ENDOFTABLE ) {
9163 tcode = 0;
9164 big_value = 0;
9165 if ( !PeekAt3dmBigChunkType(&tcode,&big_value) ) {
9166 break; // should not happen
9167 }
9168 if ( tcode == end_mark_tcode ) {
9169 rc = true;
9170 break; // done reading attributes
9171 }
9172 }
9173 tcode = 0;
9174 big_value = 0;
9175 if ( !BeginRead3dmBigChunk(&tcode,&big_value) )
9176 break;
9177 if ( tcode == end_mark_tcode ) {
9178 rc = EndRead3dmChunk();
9179 break;
9180 }
9181
9182 switch( tcode )
9183 {
9184 case (TCODE_OPENNURBS_OBJECT | TCODE_CRC | 0x7FFD):
9185 // 1.1 object 16 byte UUID + 2 byte crc
9186 if ( attributes )
9187 ReadUuid( attributes->m_uuid );
9188 break;
9189
9190 case TCODE_LAYERREF:
9191 if ( attributes
9192 && (-1 == xdata_layer_index || attributes->m_layer_index != xdata_layer_index)
9193 && (big_value >= 0 && big_value < 0x7FFFFFFF)
9194 )
9195 {
9196 attributes->m_layer_index = (int)big_value;
9197 }
9198 break;
9199
9200 case TCODE_RGB:
9201 if ( big_value != 0xFFFFFF )
9202 {
9203 if ( material )
9204 {
9205 ON__UINT64 rgb64 = (ON__UINT64)big_value;
9206 ON__UINT32 rgb32 = (ON__UINT32)rgb64;
9207 u = rgb32;
9208 c.SetRGB( u%256,(u>>8)%256,(u>>16)%256 );
9209 material->SetDiffuse(c);
9210 material->SetShine((u >> 24)/100.0*ON_Material::MaxShine());
9211 }
9212 bHaveMat = true;
9213 }
9214 break;
9215
9216 case TCODE_RGBDISPLAY:
9217 if ( attributes )
9218 {
9219 ON__UINT64 rgb64 = (ON__UINT64)big_value;
9220 ON__UINT32 rgb32 = (ON__UINT32)rgb64;
9221 u = rgb32;
9222 attributes->m_color.SetRGB( u%256,(u>>8)%256,(u>>16)%256 );
9223 }
9224 break;
9225
9226 case TCODE_TRANSPARENCY:
9227 if ( big_value > 0 && big_value <= 255 )
9228 {
9229 if ( material )
9230 material->SetTransparency(big_value/255.0);
9231 bHaveMat = true;
9232 }
9233 break;
9234
9235 case TCODE_NAME:
9236 if ( attributes ) {
9237 ON_String s;
9238 Read3dmV1String(s);
9239 if( s.Length() > 0 )
9240 attributes->m_name = s;
9241 }
9242 break;
9243
9244 case TCODE_TEXTUREMAP:
9245 {
9246 ON_String s;
9247 Read3dmV1String(s);
9248 if ( s.Length() > 0 )
9249 {
9250 if ( material )
9251 {
9252 ON_Texture& tx = material->m_textures.AppendNew();
9253 tx.m_filename = s;
9254 tx.m_type = ON_Texture::bitmap_texture;
9255 }
9256 bHaveMat = true;
9257 }
9258 }
9259 break;
9260
9261 case TCODE_BUMPMAP:
9262 if ( material ) {
9263 ON_String s;
9264 Read3dmV1String(s);
9265 if ( s.Length() )
9266 {
9267 if ( material )
9268 {
9269 ON_Texture& tx = material->m_textures.AppendNew();
9270 tx.m_filename = s;
9271 tx.m_type = ON_Texture::bump_texture;
9272 }
9273 bHaveMat = true;
9274 }
9275 }
9276 break;
9277
9278 case TCODE_XDATA:
9279 // v1 "xdata"
9280 if ( attributes )
9281 {
9282 ON_String layer_name;
9283 ON_String xid;
9284 int sizeof_xid = 0;
9285 int sizeof_data = 0;
9286 ReadInt(&sizeof_xid);
9287 ReadInt(&sizeof_data);
9288 xid.SetLength(sizeof_xid);
9289 ReadByte(sizeof_xid,xid.Array());
9290 if ( !on_stricmp("RhHidePrevLayer",xid) )
9291 {
9292 if ( sizeof_data > 0 )
9293 {
9294 // v1 object is hidden - real layer name is in xdata
9295 char* buffer = (char*)onmalloc((sizeof_data+1)*sizeof(buffer[0]));
9296 buffer[0] = 0;
9297 buffer[sizeof_data] = 0;
9298 if ( ReadByte(sizeof_data,buffer) )
9299 {
9300 if ( -1 == xdata_layer_index )
9301 {
9302 xdata_layer_index = Read3dmV1LayerIndex(buffer);
9303 if ( xdata_layer_index >= 0 )
9304 {
9305 attributes->m_layer_index = xdata_layer_index;
9306 attributes->SetVisible(false);
9307 }
9308 }
9309 else
9310 {
9311 xdata_layer_index = -2;
9312 }
9313 //if ( 0 != xdata )
9314 //{
9315 // xdata->m_type = ON__3dmV1_XDATA::hidden_object_layer_name;
9316 // xdata->m_string = buffer;
9317 //}
9318 }
9319 onfree(buffer);
9320 }
9321 }
9322 else if ( !on_stricmp("RhFreezePrevLayer",xid) )
9323 {
9324 // v1 object is locked - real layer name is in xdata
9325 if ( sizeof_data > 0 )
9326 {
9327 char* buffer = (char*)onmalloc((sizeof_data+1)*sizeof(buffer[0]));
9328 buffer[0] = 0;
9329 buffer[sizeof_data] = 0;
9330 if ( ReadByte(sizeof_data,buffer) )
9331 {
9332 if ( -1 == xdata_layer_index )
9333 {
9334 xdata_layer_index = Read3dmV1LayerIndex(buffer);
9335 if ( xdata_layer_index >= 0 )
9336 {
9337 attributes->m_layer_index = xdata_layer_index;
9338 attributes->SetMode(ON::locked_object);
9339 }
9340 }
9341 else
9342 {
9343 xdata_layer_index = -2;
9344 }
9345 //if ( 0 != xdata )
9346 //{
9347 // xdata->m_type = ON__3dmV1_XDATA::locked_object_layer_name;
9348 // xdata->m_string = buffer;
9349 //}
9350 }
9351 onfree(buffer);
9352 }
9353 }
9354 else if ( !on_stricmp("RhAnnotateArrow",xid) && 24 == sizeof_data )
9355 {
9356 // v1 annotation arrow objects were saved
9357 // as TCODE_RH_POINT objects with the
9358 // arrow tail location = point location and the
9359 // arrow head location saved in 24 bytes of "xdata".
9360 ON_3dVector arrow_direction;
9361 if ( ReadVector( arrow_direction ) && 0 != xdata )
9362 {
9363 xdata->m_type = ON__3dmV1_XDATA::arrow_direction;
9364 xdata->m_vector = arrow_direction;
9365 }
9366 }
9367 else if ( !on_stricmp("RhAnnotateDot",xid) )
9368 {
9369 if ( sizeof_data > 0 )
9370 {
9371 // v1 annotation dot objects were saved
9372 // as TCODE_RH_POINT objects with the
9373 // dot text saved in "xdata".
9374 char* buffer = (char*)onmalloc((sizeof_data+1)*sizeof(buffer[0]));
9375 buffer[0] = 0;
9376 buffer[sizeof_data] = 0;
9377 if ( ReadByte(sizeof_data,buffer) && 0 != xdata )
9378 {
9379 xdata->m_type = ON__3dmV1_XDATA::dot_text;
9380 xdata->m_string = buffer;
9381 }
9382 onfree(buffer);
9383 }
9384 }
9385 else
9386 {
9387 m_error_message_mask |= 0x0002; // disable v1 EndRead3dmChunk() partially read chunk warning
9388 }
9389 // call to EndRead3dmChunk() will skip unread junk
9390 }
9391 break;
9392
9393 case TCODE_DISP_CPLINES:
9394 if ( big_value > 0 && big_value <= 0x7FFFFFFF && attributes )
9395 attributes->m_wire_density = (int)big_value;
9396 break;
9397
9398 case TCODE_RENDER_MATERIAL_ID:
9399 {
9400 int flag;
9401 ON_String s;
9402 ReadInt(&flag);
9403 if ( flag == 1 ) {
9404 Read3dmV1String(s);
9405 if ( s.Length() > 0 )
9406 {
9407 if ( material )
9408 material->m_material_name = s;
9409 bHaveMat = true;
9410 }
9411 }
9412 }
9413 break;
9414
9415 default:
9416 // obsolete attributes from v1
9417 m_error_message_mask |= 0x02; // disable v1 EndRead3dmChunk() partially read chunk warning
9418 break;
9419 }
9420
9421 bEndRead3dmChunk_rc = EndRead3dmChunk();
9422 if ( !bEndRead3dmChunk_rc )
9423 break;
9424 }
9425
9426 m_error_message_mask = saved_error_message_mask;
9427
9428 if ( bHaveMat ) {
9429 if ( attributes )
9430 attributes->m_material_index = m_3dm_v1_material_index;
9431 if ( material )
9432 material->SetMaterialIndex(m_3dm_v1_material_index);
9433 m_3dm_v1_material_index++;
9434 }
9435
9436 return rc;
9437 }
9438
9439
9440
Read3dmV1Material(ON_Material ** ppMaterial)9441 int ON_BinaryArchive::Read3dmV1Material( ON_Material** ppMaterial )
9442 {
9443 int rc = 0;
9444 // returns -1: failure
9445 // 0: end of material table
9446 // 1: success
9447
9448 ON_Material material;
9449 ON__UINT32 tcode = 0;
9450 ON__INT64 big_value = 0;
9451 ON_BOOL32 bHaveMat;
9452 bool bEndReadChunk_rc;
9453 // reads NURBS, point, and mesh objects
9454
9455 while( 0 == rc )
9456 {
9457 bHaveMat = false;
9458 rc = 0;
9459 tcode = 0;
9460 big_value = 0;
9461 if ( !BeginRead3dmBigChunk(&tcode,&big_value) )
9462 {
9463 // assume we are at the end of the file
9464 break;
9465 }
9466
9467 switch(tcode)
9468 {
9469 case TCODE_RH_POINT:
9470 // v1 3d point
9471 {
9472 ON_3DM_BIG_CHUNK* point_chunk = m_chunk.Last();
9473 ON__UINT64 pos0 = 0;
9474 if ( 0 != point_chunk
9475 && TCODE_RH_POINT == point_chunk->m_typecode
9476 && 0 == point_chunk->m_big_value )
9477 {
9478 // Some V1 files have TCODE_RH_POINT chunks with length=0.
9479 // (It appears that points with arrow xdata have this problem.)
9480 // For these chunks we need to set the chunk length so EndRead3dmChunk()
9481 // will keep going.
9482 pos0 = CurrentPosition();
9483 }
9484 else
9485 point_chunk = 0;
9486
9487 ON_3dPoint pt; // need to read point to get to material defn
9488 bool bOK = ReadPoint( pt );
9489
9490 if ( bOK )
9491 bOK = Read3dmV1AttributesOrMaterial( NULL, &material, bHaveMat, TCODE_ENDOFTABLE );
9492
9493 if ( !bOK )
9494 rc = -1;
9495 // else if appropriate, rc will get set to +1 below.
9496
9497 if ( bOK
9498 && 0 != point_chunk
9499 && point_chunk == m_chunk.Last()
9500 && TCODE_RH_POINT == point_chunk->m_typecode
9501 && 0 == point_chunk->m_big_value )
9502 {
9503 // set the chunk length so that reading can continue.
9504 ON__UINT64 pos1 = CurrentPosition();
9505 ON__UINT64 chunk_length = (pos1 > pos0) ? (pos1 - pos0) : 0;
9506 if ( chunk_length >= 32 && chunk_length < 0x0FFFFFFF )
9507 point_chunk->m_big_value = (ON__INT64)chunk_length;
9508 }
9509 }
9510 break;
9511
9512 case TCODE_MESH_OBJECT:
9513 // v1 mesh
9514 {
9515 ON__UINT32 tc = 0;
9516 ON__INT64 i64 = 0;
9517 if ( !PeekAt3dmBigChunkType( &tc, &i64 ) )
9518 break;
9519 if ( tc != TCODE_COMPRESSED_MESH_GEOMETRY )
9520 break;
9521 // skip over the TCODE_COMPRESSED_MESH_GEOMETRY chunk
9522 if ( !BeginRead3dmBigChunk(&tc,&i64) )
9523 break;
9524 if ( !EndRead3dmChunk() )
9525 break;
9526 // attributes and material informtion follow the TCODE_COMPRESSED_MESH_GEOMETRY chunk
9527 if ( !Read3dmV1AttributesOrMaterial( NULL, &material, bHaveMat, TCODE_ENDOFTABLE ) )
9528 rc = -1;
9529 // if appropriate, rc will get set to +1 below
9530 }
9531 break;
9532
9533 case TCODE_LEGACY_SHL:
9534 // v1 polysurface
9535 if ( !Read3dmV1AttributesOrMaterial( NULL, &material, bHaveMat, TCODE_LEGACY_SHLSTUFF ) )
9536 rc = -1;
9537 // if appropriate, rc will get set to +1 below
9538 break;
9539 case TCODE_LEGACY_FAC:
9540 // v1 trimmed surface
9541 if ( !Read3dmV1AttributesOrMaterial( NULL, &material, bHaveMat, TCODE_LEGACY_FACSTUFF ) )
9542 rc = -1;
9543 // if appropriate, rc will get set to +1 below
9544 break;
9545 case TCODE_LEGACY_CRV:
9546 // v1 curve
9547 if ( !Read3dmV1AttributesOrMaterial( NULL, &material, bHaveMat, TCODE_LEGACY_CRVSTUFF ) )
9548 rc = -1;
9549 // if appropriate, rc will get set to +1 below
9550 break;
9551
9552 case TCODE_RHINOIO_OBJECT_NURBS_CURVE:
9553 case TCODE_RHINOIO_OBJECT_NURBS_SURFACE:
9554 case TCODE_RHINOIO_OBJECT_BREP:
9555 // old Rhino I/O toolkit nurbs curve, surface, and breps
9556 {
9557 ON__UINT32 tc = 0;
9558 ON__INT64 i64 = 0;
9559 if ( !PeekAt3dmBigChunkType( &tc, &i64 ) )
9560 break;
9561 if ( tc != TCODE_RHINOIO_OBJECT_DATA )
9562 break;
9563 // skip over the TCODE_RHINOIO_OBJECT_DATA chunk
9564 if ( !BeginRead3dmBigChunk(&tc,&i64) )
9565 break;
9566 if ( !EndRead3dmChunk() )
9567 break;
9568 if ( !Read3dmV1AttributesOrMaterial( NULL, &material, bHaveMat, TCODE_RHINOIO_OBJECT_END ) )
9569 rc = -1;
9570 // if appropriate, rc will get set to +1 below
9571 }
9572 break;
9573 }
9574
9575 const unsigned int saved_error_message_mask = m_error_message_mask;
9576 m_error_message_mask |= 0x02; // disable v1 EndRead3dmChunk() partially read chunk warning
9577 bEndReadChunk_rc = EndRead3dmChunk();
9578 m_error_message_mask = saved_error_message_mask; // enable v1 EndRead3dmChunk() partially read chunk warning
9579 if (!bEndReadChunk_rc )
9580 {
9581 rc = -1;
9582 break;
9583 }
9584 if ( bHaveMat && ppMaterial)
9585 {
9586 // found a valid non-default material
9587 *ppMaterial = new ON_Material(material);
9588 rc = 1;
9589 break;
9590 }
9591 }
9592
9593 return rc;
9594 }
9595
9596
Read3dmMaterial(ON_Material ** ppMaterial)9597 int ON_BinaryArchive::Read3dmMaterial( ON_Material** ppMaterial )
9598 {
9599 int rc = 0;
9600 if ( !ppMaterial )
9601 return 0;
9602 *ppMaterial = 0;
9603 ON_Material* material = NULL;
9604 ON__UINT32 tcode = 0;
9605 ON__INT64 big_value = 0;
9606 if ( m_3dm_version == 1 )
9607 {
9608 rc = ON_BinaryArchive::Read3dmV1Material( ppMaterial );
9609 }
9610 else
9611 {
9612 // version 2+
9613 rc = -1;
9614 if ( BeginRead3dmBigChunk( &tcode, &big_value ) )
9615 {
9616 if ( tcode == TCODE_MATERIAL_RECORD )
9617 {
9618 ON_Object* p = 0;
9619 if ( ReadObject( &p ) )
9620 {
9621 material = ON_Material::Cast(p);
9622 if ( !material )
9623 delete p;
9624 else
9625 {
9626 if ( ppMaterial )
9627 *ppMaterial = material;
9628 rc = 1;
9629 }
9630 }
9631 if (!material)
9632 {
9633 ON_ERROR("ON_BinaryArchive::Read3dmMaterial() - corrupt material table");
9634 }
9635 }
9636 else if ( tcode == TCODE_ENDOFTABLE )
9637 {
9638 // end of material table
9639 rc = 0;
9640 }
9641 else
9642 {
9643 ON_ERROR("ON_BinaryArchive::Read3dmMaterial() - corrupt material table");
9644 }
9645 if ( !EndRead3dmChunk() )
9646 rc = -1;
9647 }
9648 }
9649 return rc;
9650 }
9651
EndRead3dmMaterialTable()9652 bool ON_BinaryArchive::EndRead3dmMaterialTable()
9653 {
9654 return EndRead3dmTable( TCODE_MATERIAL_TABLE );
9655 }
9656
9657
BeginWrite3dmLightTable()9658 bool ON_BinaryArchive::BeginWrite3dmLightTable()
9659 {
9660 return BeginWrite3dmTable( TCODE_LIGHT_TABLE );
9661 }
9662
Write3dmLight(const ON_Light & light,const ON_3dmObjectAttributes * attributes)9663 bool ON_BinaryArchive::Write3dmLight( const ON_Light& light, const ON_3dmObjectAttributes* attributes )
9664 {
9665 bool rc = false;
9666 if ( m_active_table != light_table ) {
9667 ON_ERROR("ON_BinaryArchive::Write3dmLight() - m_active_table != light_table");
9668 }
9669 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
9670 if ( c && c->m_typecode == TCODE_LIGHT_TABLE ) {
9671 rc = BeginWrite3dmChunk( TCODE_LIGHT_RECORD, 0 );
9672 if (rc) {
9673 // WriteObject writes TCODE_OPENNURBS_CLASS chunk that contains light definition
9674 rc = WriteObject( light );
9675
9676 // optional TCODE_LIGHT_RECORD_ATTRIBUTES chunk
9677 if ( rc && attributes )
9678 {
9679 rc = BeginWrite3dmChunk( TCODE_LIGHT_RECORD_ATTRIBUTES, 0 );
9680 if (rc)
9681 {
9682 rc = attributes->Write( *this )?true:false;
9683 if (!EndWrite3dmChunk())
9684 rc = false;
9685 if( rc
9686 && (m_bSaveUserData || HasCriticalUserData(*this,attributes))
9687 && Archive3dmVersion() >= 4
9688 && 0 != attributes->FirstUserData()
9689 )
9690 {
9691 // 14 May 2008 Dale Lear
9692 // Added support for saving light attribute userdata
9693 rc = BeginWrite3dmChunk( TCODE_LIGHT_RECORD_ATTRIBUTES_USERDATA, 0 );
9694 if (rc)
9695 {
9696 // write user data
9697 rc = WriteObjectUserData(*attributes);
9698 if (rc)
9699 {
9700 // Because I'm not using Write3dmObject() to write
9701 // the attributes, the user data must be immediately
9702 // followed by a short TCODE_OPENNURBS_CLASS_END chunk
9703 // in order for ReadObjectUserData() to work correctly.
9704 //
9705 // The reason that this is hacked in is that V3 files did
9706 // not support attribute user data and doing it this way
9707 // means that V3 can still read V4 files.
9708 rc = BeginWrite3dmChunk(TCODE_OPENNURBS_CLASS_END,0);
9709 if (rc)
9710 {
9711 if (!EndWrite3dmChunk())
9712 rc = false;
9713 }
9714 }
9715 if (!EndWrite3dmChunk())
9716 rc = false;
9717 }
9718 }
9719 }
9720 }
9721
9722 // TCODE_LIGHT_RECORD_END chunk marks end of light record
9723 if ( BeginWrite3dmChunk( TCODE_LIGHT_RECORD_END, 0 ) ) {
9724 if (!EndWrite3dmChunk())
9725 rc = false;
9726 }
9727 else {
9728 rc = false;
9729 }
9730
9731 if ( !EndWrite3dmChunk() ) // end of TCODE_LIGHT_RECORD
9732 rc = false;
9733 }
9734 }
9735 else {
9736 ON_ERROR("ON_BinaryArchive::Write3dmMaterial() - active chunk typecode != TCODE_LIGHT_TABLE");
9737 }
9738 return rc;
9739 }
9740
EndWrite3dmLightTable()9741 bool ON_BinaryArchive::EndWrite3dmLightTable()
9742 {
9743 return EndWrite3dmTable( TCODE_LIGHT_TABLE );
9744 }
9745
BeginRead3dmLightTable()9746 bool ON_BinaryArchive::BeginRead3dmLightTable()
9747 {
9748 bool rc = BeginRead3dmTable( TCODE_LIGHT_TABLE );
9749
9750 if ( !rc )
9751 {
9752 // 1 November 2005 Dale Lear
9753 // This fall back is slow but it has been finding
9754 // layer and object tables in damaged files. I'm
9755 // adding it to the other BeginRead3dm...Table()
9756 // functions when it makes sense.
9757 rc = FindMisplacedTable(
9758 0,
9759 TCODE_LIGHT_TABLE, TCODE_LIGHT_RECORD,
9760 ON_Light::m_ON_Light_class_id.Uuid(),
9761 30
9762 );
9763 if ( rc )
9764 {
9765 rc = BeginRead3dmTable( TCODE_LIGHT_TABLE );
9766 }
9767 }
9768
9769 return rc;
9770 }
9771
Read3dmV1Light(ON_Light ** ppLight,ON_3dmObjectAttributes * pAttributes)9772 int ON_BinaryArchive::Read3dmV1Light( // returns 0 at end of light table
9773 // 1 light successfully read
9774 // -1 if file is corrupt
9775 ON_Light** ppLight, // light returned here
9776 ON_3dmObjectAttributes* pAttributes// optional - if NOT NULL, object attributes are
9777 // returned here
9778 )
9779 {
9780 ON_BOOL32 bHaveMat;
9781 ON_Material material;
9782 // TODO - read v1 lights
9783 if ( m_chunk.Count() != 0 ) {
9784 ON_ERROR("ON_BinaryArchive::Read3dmV1Light() m_chunk.Count() != 0");
9785 return false;
9786 }
9787 ON_BOOL32 rc = false;
9788 ON__UINT32 tcode = 0;
9789 ON__INT64 big_value = 0;
9790
9791 // find TCODE_RH_SPOTLIGHT chunk
9792 for(;;)
9793 {
9794 if ( !BeginRead3dmBigChunk(&tcode,&big_value) )
9795 break; // assume we are at the end of the file
9796 if ( tcode == TCODE_RH_SPOTLIGHT ) {
9797 rc = 1;
9798 break;
9799 }
9800 if ( !EndRead3dmChunk() )
9801 break;
9802 }
9803 if (rc) {
9804 ON_3dPoint origin;
9805 ON_3dVector xaxis, yaxis;
9806 double radius;
9807 double height;
9808 double hotspot;
9809
9810 for(;;)
9811 {
9812 rc = ReadPoint( origin );
9813 if (!rc) break;
9814 rc = ReadVector( xaxis );
9815 if (!rc) break;
9816 rc = ReadVector( yaxis );
9817 if (!rc) break;
9818 rc = ReadDouble( &radius );
9819 if (!rc) break;
9820 rc = ReadDouble( &height );
9821 if (!rc) break;
9822 rc = ReadDouble( &hotspot );
9823 if (!rc) break;
9824 if (ppLight )
9825 {
9826 ON_3dVector Z = ON_CrossProduct( xaxis, yaxis );
9827 ON_3dPoint location = height*Z + origin;
9828 ON_3dVector direction = -Z;
9829
9830 if( height > 0.0)
9831 direction *= height;
9832 ON_Light* light = new ON_Light;
9833 light->SetStyle( ON::world_spot_light );
9834 light->SetLocation(location);
9835 light->SetDirection(direction);
9836 light->SetSpotExponent( 64.0);
9837 if( radius > 0.0 && height > 0.0 )
9838 light->SetSpotAngleRadians( atan( radius/height));
9839 *ppLight = light;
9840 }
9841 break;
9842 }
9843
9844 if (rc && ppLight && *ppLight) {
9845 bHaveMat = false;
9846 Read3dmV1AttributesOrMaterial(pAttributes,&material,bHaveMat,TCODE_ENDOFTABLE);
9847 if ( pAttributes )
9848 pAttributes->m_material_index = -1;
9849 if (bHaveMat)
9850 (*ppLight)->SetDiffuse(material.Diffuse());
9851 }
9852
9853 if ( !EndRead3dmChunk() ) // end of TCODE_RH_SPOTLIGHT chunk
9854 rc = false;
9855 }
9856
9857 return rc;
9858 }
9859
Read3dmLight(ON_Light ** ppLight,ON_3dmObjectAttributes * attributes)9860 int ON_BinaryArchive::Read3dmLight( ON_Light** ppLight, ON_3dmObjectAttributes* attributes )
9861 {
9862 if ( attributes )
9863 attributes->Default();
9864 int rc = -1;
9865 if ( !ppLight )
9866 return 0;
9867 *ppLight = 0;
9868 if ( m_active_table != light_table ) {
9869 ON_ERROR("ON_BinaryArchive::Read3dmLight() - m_active_table != light_table");
9870 }
9871 else if ( m_3dm_version == 1 ) {
9872 rc = Read3dmV1Light( ppLight, attributes );
9873 }
9874 else {
9875 ON_Light* light = NULL;
9876 ON__UINT32 tcode = 0;
9877 ON__INT64 big_value = 0;
9878 if ( BeginRead3dmBigChunk( &tcode, &big_value ) ) {
9879 if ( tcode == TCODE_LIGHT_RECORD ) {
9880 ON_Object* p = 0;
9881 if ( ReadObject( &p ) ) {
9882 light = ON_Light::Cast(p);
9883 if ( !light )
9884 delete p;
9885 }
9886 if (!light) {
9887 ON_ERROR("ON_BinaryArchive::Read3dmLight() - corrupt light table");
9888 }
9889 else {
9890 *ppLight = light;
9891 rc = 1;
9892 }
9893 }
9894 else if ( tcode != TCODE_ENDOFTABLE )
9895 {
9896 ON_ERROR("ON_BinaryArchive::Read3dmLight() - corrupt light table");
9897 }
9898 else
9899 rc = 0;
9900
9901 while(rc==1)
9902 {
9903 tcode = 0;
9904 big_value = 0;
9905 if (!BeginRead3dmBigChunk( &tcode, &big_value ))
9906 {
9907 rc = -1;
9908 break;
9909 }
9910 if ( tcode == TCODE_LIGHT_RECORD_ATTRIBUTES && attributes )
9911 {
9912 if ( !attributes->Read( *this ) )
9913 rc = -1;
9914 }
9915 else if ( tcode == TCODE_LIGHT_RECORD_ATTRIBUTES_USERDATA )
9916 {
9917 if ( 0 != attributes )
9918 {
9919 // 14 May 2008
9920 // Added support for reading user data on light attributes
9921 if ( !ReadObjectUserData(*attributes))
9922 rc = -1;
9923 }
9924 }
9925 if ( !EndRead3dmChunk() )
9926 {
9927 rc = -1;
9928 break;
9929 }
9930 if ( tcode == TCODE_LIGHT_RECORD_END )
9931 break;
9932 }
9933
9934 EndRead3dmChunk();
9935 }
9936 }
9937 return rc;
9938 }
9939
EndRead3dmLightTable()9940 bool ON_BinaryArchive::EndRead3dmLightTable()
9941 {
9942 return EndRead3dmTable( TCODE_LIGHT_TABLE );
9943 }
9944
BeginWrite3dmObjectTable()9945 bool ON_BinaryArchive::BeginWrite3dmObjectTable()
9946 {
9947 return BeginWrite3dmTable( TCODE_OBJECT_TABLE );
9948 }
9949
Write3dmObject(const ON_Object & object,const ON_3dmObjectAttributes * attributes)9950 bool ON_BinaryArchive::Write3dmObject(
9951 const ON_Object& object,
9952 const ON_3dmObjectAttributes* attributes
9953 )
9954 {
9955 bool rc = false;
9956 if ( m_active_table != object_table ) {
9957 ON_ERROR("ON_BinaryArchive::Write3dmObject() - m_active_table != object_table");
9958 }
9959
9960 if ( Archive3dmVersion() <= 2 && object.ObjectType() == ON::pointset_object )
9961 {
9962 // There were no point clouds in V1 and V2 files and we cannot handle
9963 // this problem inside of ON_PointCloud::Write() because we have to
9964 // write multiple point objects. (c.f. ON_Brep::Write()).
9965 const ON_PointCloud* pc = ON_PointCloud::Cast(&object);
9966 if ( 0 != pc )
9967 {
9968 int i, count = pc->PointCount();
9969 rc = true;
9970 for ( i = 0; i < count && rc ; i++ )
9971 {
9972 ON_Point pt( pc->m_P[i] );
9973 rc = Write3dmObject( pt, attributes );
9974 }
9975 return rc;
9976 }
9977 }
9978
9979 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
9980 if ( c && c->m_typecode == TCODE_OBJECT_TABLE )
9981 {
9982 Flush();
9983 rc = BeginWrite3dmChunk( TCODE_OBJECT_RECORD, 0 );
9984 if (rc) {
9985 // TCODE_OBJECT_RECORD_TYPE chunk integer value that can be used
9986 // for skipping unwanted types of objects
9987 rc = BeginWrite3dmChunk( TCODE_OBJECT_RECORD_TYPE, object.ObjectType() );
9988 if (rc) {
9989 if (!EndWrite3dmChunk())
9990 rc = false;
9991 }
9992
9993 // WriteObject writes TCODE_OPENNURBS_CLASS chunk that contains object definition
9994 rc = WriteObject( object );
9995
9996 // optional TCODE_OBJECT_RECORD_ATTRIBUTES chunk
9997 if ( rc && attributes ) {
9998 rc = BeginWrite3dmChunk( TCODE_OBJECT_RECORD_ATTRIBUTES, 0 );
9999 if (rc) {
10000 rc = attributes->Write( *this )?true:false;
10001 if (!EndWrite3dmChunk())
10002 rc = false;
10003
10004 if( rc
10005 && (m_bSaveUserData || HasCriticalUserData(*this,attributes))
10006 && Archive3dmVersion() >= 4
10007 && 0 != attributes->FirstUserData()
10008 )
10009 {
10010 // 19 October 2004
10011 // Added support for saving user data on object attributes
10012 rc = BeginWrite3dmChunk( TCODE_OBJECT_RECORD_ATTRIBUTES_USERDATA, 0 );
10013 if (rc)
10014 {
10015 // write user data
10016 rc = WriteObjectUserData(*attributes);
10017 if (rc)
10018 {
10019 // Because I'm not using Write3dmObject() to write
10020 // the attributes, the user data must be immediately
10021 // followed by a short TCODE_OPENNURBS_CLASS_END chunk
10022 // in order for ReadObjectUserData() to work correctly.
10023 //
10024 // The reason that this is hacked in is that V3 files did
10025 // not support attribute user data and doing it this way
10026 // means that V3 can still read V4 files.
10027 rc = BeginWrite3dmChunk(TCODE_OPENNURBS_CLASS_END,0);
10028 if (rc)
10029 {
10030 if (!EndWrite3dmChunk())
10031 rc = false;
10032 }
10033 }
10034 if (!EndWrite3dmChunk())
10035 rc = false;
10036 }
10037 }
10038 }
10039 }
10040
10041 // TCODE_OBJECT_RECORD_END chunk marks end of object record
10042 if ( BeginWrite3dmChunk( TCODE_OBJECT_RECORD_END, 0 ) ) {
10043 if (!EndWrite3dmChunk())
10044 rc = false;
10045 }
10046 else {
10047 rc = false;
10048 }
10049
10050 if (!EndWrite3dmChunk()) // end of TCODE_OBJECT_RECORD
10051 {
10052 rc = false;
10053 }
10054 if (!Flush())
10055 rc = false;
10056 }
10057 else {
10058 ON_ERROR("ON_BinaryArchive::Write3dmObject() - active chunk typecode != TCODE_OBJECT_TABLE");
10059 }
10060 }
10061 return rc;
10062 }
10063
EndWrite3dmObjectTable()10064 bool ON_BinaryArchive::EndWrite3dmObjectTable()
10065 {
10066 return EndWrite3dmTable( TCODE_OBJECT_TABLE );
10067 }
10068
BeginRead3dmObjectTable()10069 bool ON_BinaryArchive::BeginRead3dmObjectTable()
10070 {
10071 m_3dm_v1_material_index = 0;
10072 bool rc = BeginRead3dmTable( TCODE_OBJECT_TABLE );
10073 if ( !rc )
10074 {
10075 // 8 October 2004 Dale Lear
10076 // This fall back is slow but it will find
10077 // object tables in files that have been damaged.
10078 rc = FindMisplacedTable(
10079 0,
10080 TCODE_OBJECT_TABLE, TCODE_OBJECT_RECORD,
10081 ON_nil_uuid,
10082 26 // ON_Point data is 3 doubles + 2 byte version number
10083 );
10084 if ( rc )
10085 {
10086 rc = BeginRead3dmTable( TCODE_OBJECT_TABLE );
10087 }
10088
10089 }
10090 return rc;
10091 }
10092
ReadV1_TCODE_RH_POINT(ON_Object ** ppObject,ON_3dmObjectAttributes * pAttributes)10093 bool ON_BinaryArchive::ReadV1_TCODE_RH_POINT(
10094 ON_Object** ppObject,
10095 ON_3dmObjectAttributes* pAttributes
10096 )
10097 {
10098 ON__UINT64 pos0 = 0;
10099 ON_3DM_BIG_CHUNK* point_chunk = m_chunk.Last();
10100
10101 if ( 0 != point_chunk
10102 && TCODE_RH_POINT == point_chunk->m_typecode
10103 && 0 == point_chunk->m_big_value )
10104 {
10105 // Some early V1 files have TCODE_RH_POINT chunks with arrow xdata
10106 // attached have a length set to zero.
10107 // For these chunks we need to set the chunk length so EndRead3dmChunk()
10108 // will keep going.
10109 pos0 = CurrentPosition();
10110 }
10111 else
10112 point_chunk = 0;
10113
10114 // read v1 point
10115 bool rc = false;
10116 ON_BOOL32 bHaveMat = false;
10117 ON_3dPoint pt;
10118 ON__3dmV1_XDATA xdata;
10119 rc = ReadPoint(pt);
10120 if (rc)
10121 {
10122 rc = Read3dmV1AttributesOrMaterial(pAttributes,NULL,bHaveMat,TCODE_ENDOFTABLE,&xdata);
10123 // do switch even if Read3dmV1AttributesOrMaterial() fails
10124 switch ( xdata.m_type )
10125 {
10126 case ON__3dmV1_XDATA::arrow_direction:
10127 if ( xdata.m_vector.Length() > ON_ZERO_TOLERANCE )
10128 {
10129 ON_AnnotationArrow* arrow = new ON_AnnotationArrow();
10130 arrow->m_tail = pt;
10131 arrow->m_head = pt + xdata.m_vector;
10132 *ppObject = arrow;
10133 }
10134 else
10135 {
10136 *ppObject = new ON_Point(pt);
10137 }
10138 break;
10139
10140 case ON__3dmV1_XDATA::dot_text:
10141 {
10142 ON_AnnotationTextDot* dot = new ON_AnnotationTextDot();
10143 dot->point = pt;
10144 dot->m_text = xdata.m_string;
10145 if ( dot->m_text.IsEmpty() )
10146 dot->m_text = " "; // a single blank
10147 *ppObject = dot;
10148 }
10149 break;
10150
10151 default:
10152 *ppObject = new ON_Point(pt);
10153 break;
10154 }
10155 }
10156
10157 // carefully test for the V1 zero length chunk bug
10158 if ( rc && pos0 > 0 && 0 != point_chunk && point_chunk == m_chunk.Last() )
10159 {
10160 if ( TCODE_RH_POINT == point_chunk->m_typecode && 0 == point_chunk->m_big_value )
10161 {
10162 // This TCODE_RH_POINT chunk has the zero length chunk bug
10163 // that was in some V1 files.
10164 // Fill in the correct chunk length so that reading can continue.
10165 ON__UINT64 pos1 = CurrentPosition();
10166 ON__UINT64 chunk_length = (pos1 > pos0) ? (pos1 - pos0) : 0;
10167 if ( chunk_length >= 32 && chunk_length < 0x0FFFFFFF )
10168 point_chunk->m_big_value = (ON__INT64)chunk_length;
10169 }
10170 }
10171
10172 return rc;
10173 }
10174
10175 static
TweakAnnotationPlane(ON_Plane & plane)10176 void TweakAnnotationPlane( ON_Plane& plane )
10177 {
10178 // 10 November 2003 Dale Lear
10179 // Fixed lots of bugs in annotation plane tweaking.
10180 // Before the fix this block of code was cut-n-pasted
10181 // in three places. The fabs() calls were wrong. In addition
10182 // and the
10183 // .x values where tested and then the .y/.z values were set.
10184
10185 // if( fabs( plane.origin.x > 1e10 ))
10186 // plane.origin.x = 0.0;
10187 // if( fabs( plane.origin.y > 1e10 ))
10188 // plane.origin.y = 0.0;
10189 // if( fabs( plane.origin.z > 1e10 ))
10190 // plane.origin.z = 0.0;
10191 //
10192 // if( fabs( plane.xaxis.x > 1e10 ))
10193 // plane.xaxis.x = 1.0;
10194 // if( fabs( plane.xaxis.x > 1e10 ))
10195 // plane.xaxis.y = 0.0;
10196 // if( fabs( plane.xaxis.x > 1e10 ))
10197 // plane.xaxis.z = 0.0;
10198 //
10199 // if( fabs( plane.yaxis.x > 1e10 ))
10200 // plane.yaxis.x = 0.0;
10201 // if( fabs( plane.yaxis.x > 1e10 ))
10202 // plane.yaxis.y = 1.0;
10203 // if( fabs( plane.yaxis.x > 1e10 ))
10204 // plane.yaxis.z = 0.0;
10205
10206 // Lowell has decided that annotation plane
10207 // coordinates bigger than "too_big" should be
10208 // set to zero.
10209 const double too_big = 1.0e10;
10210
10211 if( fabs( plane.origin.x ) > too_big )
10212 plane.origin.x = 0.0;
10213 if( fabs( plane.origin.y ) > too_big )
10214 plane.origin.y = 0.0;
10215 if( fabs( plane.origin.z ) > too_big )
10216 plane.origin.z = 0.0;
10217
10218 if( fabs( plane.xaxis.x ) > too_big )
10219 plane.xaxis.x = 1.0;
10220 if( fabs( plane.xaxis.y ) > too_big )
10221 plane.xaxis.y = 0.0;
10222 if( fabs( plane.xaxis.z ) > too_big )
10223 plane.xaxis.z = 0.0;
10224
10225 if( fabs( plane.yaxis.x ) > too_big )
10226 plane.yaxis.x = 0.0;
10227 if( fabs( plane.yaxis.y ) > too_big )
10228 plane.yaxis.y = 1.0;
10229 if( fabs( plane.yaxis.z ) > too_big )
10230 plane.yaxis.z = 0.0;
10231
10232 plane.xaxis.Unitize();
10233 plane.yaxis.Unitize();
10234 plane.zaxis = ON_CrossProduct(plane.xaxis,plane.yaxis);
10235 plane.zaxis.Unitize();
10236 plane.UpdateEquation();
10237 }
10238
10239
10240 #define RHINO_ANNOTATION_SETTINGS_VERSION_1 1
10241 #define RHINO_LINEAR_DIMENSION_VERSION_1 1
10242 #define RHINO_RADIAL_DIMENSION_VERSION_1 1
10243 #define RHINO_ANGULAR_DIMENSION_VERSION_1 1
10244 #define RHINO_TEXT_BLOCK_VERSION_1 1
10245 #define RHINO_TEXT_BLOCK_VERSION_2 2
10246 #define RHINO_ANNOTATION_LEADER_VERSION_1 1
10247
10248 #define BUFLEN 128
10249
ReadV1_TCODE_ANNOTATION_Helper(ON_BinaryArchive & archive,char * buffer,ON_wString & tc)10250 static bool ReadV1_TCODE_ANNOTATION_Helper( ON_BinaryArchive& archive, char* buffer, ON_wString& tc )
10251 {
10252 char* cp = 0;
10253 int j = 0;
10254 if( !archive.ReadInt( &j))
10255 return false;
10256 size_t sz = (j+1)*sizeof(cp[0]);
10257 if( j > BUFLEN - 1 || !buffer )
10258 {
10259 cp = (char*)onmalloc( sz );
10260 if( !cp)
10261 return false;
10262 }
10263 else
10264 {
10265 cp = buffer;
10266 }
10267
10268 memset( cp, 0, sz );
10269 if( !archive.ReadChar( j, cp))
10270 {
10271 if ( cp != buffer )
10272 onfree(cp);
10273 return false;
10274 }
10275
10276 cp[j] = 0;
10277 tc = cp;
10278 if ( cp != buffer )
10279 onfree( cp );
10280 return true;
10281 }
10282
ReadV1_TCODE_ANNOTATION(unsigned int tcode,ON_Object ** ppObject,ON_3dmObjectAttributes * pAttributes)10283 bool ON_BinaryArchive::ReadV1_TCODE_ANNOTATION(
10284 unsigned int tcode,
10285 ON_Object** ppObject,
10286 ON_3dmObjectAttributes* pAttributes
10287 )
10288 {
10289 enum RhAnnotationType
10290 {
10291 Nothing = 0,
10292 TextBlock = 1,
10293 DimHorizontal = 2,
10294 DimVertical = 3,
10295 DimAligned = 4,
10296 DimRotated = 5,
10297 DimAngular = 6,
10298 DimDiameter = 7 ,
10299 DimRadius = 8,
10300 Leader = 9,
10301 DimLinear = 10,
10302 };
10303
10304 bool rc = false;
10305 *ppObject = NULL;
10306 ON_wString tc;
10307 char buffer[BUFLEN];
10308 int i, j, k, byobject, version;
10309 //char* cp;
10310 double d, d4[4];
10311 //ON_3dPoint pt;
10312
10313 switch( tcode)
10314 {
10315 case TCODE_TEXT_BLOCK:
10316 {
10317 // read the version id
10318 rc = ReadInt( &version);
10319 if ( rc &&
10320 (version == RHINO_TEXT_BLOCK_VERSION_1 ||
10321 version == RHINO_TEXT_BLOCK_VERSION_2)
10322 )
10323 {
10324 //this is a version we can read....
10325 // this is a type flag that we throw away
10326 rc = ReadInt( &i);
10327 if( !rc)
10328 return rc;
10329
10330 ON_TextEntity* text = new ON_TextEntity;
10331 text->SetType( ON::dtTextBlock);
10332
10333 ON_Plane plane;
10334
10335 // the entity plane
10336 if( !ReadDouble( 3, &plane.origin.x))
10337 return false;
10338 if( !ReadDouble( 3, &plane.xaxis.x))
10339 return false;
10340 if( !ReadDouble( 3, &plane.yaxis.x))
10341 return false;
10342
10343 // 11 November 2003 Dale Lear - see comments in TweakAnnotationPlane()
10344 TweakAnnotationPlane( plane );
10345
10346 text->SetPlane( plane);
10347
10348 // read string to display
10349 if ( !ReadV1_TCODE_ANNOTATION_Helper( *this, buffer, tc ) )
10350 return false;
10351 text->SetUserText( tc.Array());
10352
10353 // flags ( future )
10354 if( !ReadInt( 1, &j))
10355 return false;
10356
10357 // settings byobject flag
10358 if( !ReadInt( 1, &byobject))
10359 return false;
10360
10361 // depending on the value of byobject, more fields might be read here
10362
10363 // facename
10364 if ( !ReadV1_TCODE_ANNOTATION_Helper( *this, buffer, tc ) )
10365 return false;
10366 text->SetFaceName(tc);
10367
10368 // face weight
10369 if( !ReadInt( 1, &j))
10370 return false;
10371 text->SetFontWeight( j);
10372
10373 if( !ReadDouble( 1, &d))
10374 return false;
10375 text->SetHeight( d);
10376
10377 // 2 extra doubles were written into the file by mistake in version 1
10378 if( version == RHINO_TEXT_BLOCK_VERSION_1 )
10379 {
10380 if( !ReadDouble( 1, &d))
10381 return false;
10382 if( !ReadDouble( 1, &d))
10383 return false;
10384 }
10385
10386 if( text->UserText().Length() < 1 )
10387 {
10388 *ppObject = 0;
10389 return true;
10390 }
10391 *ppObject = text;
10392 rc = true;
10393 }
10394 }
10395 break;
10396
10397 case TCODE_ANNOTATION_LEADER:
10398 {
10399 // read the version id
10400 if( !ReadInt( &i))
10401 return false;
10402
10403 if( i == RHINO_ANNOTATION_LEADER_VERSION_1)
10404 {
10405 // redundant type code to throw away
10406 if( !ReadInt( &i))
10407 return false;
10408
10409 ON_Leader* ldr = new ON_Leader;
10410 ldr->SetType( ON::dtLeader);
10411
10412 ON_Plane plane;
10413
10414 // the entity plane
10415 if( !ReadDouble( 3, &plane.origin.x))
10416 return false;
10417 if( !ReadDouble( 3, &plane.xaxis.x))
10418 return false;
10419 if( !ReadDouble( 3, &plane.yaxis.x))
10420 return false;
10421
10422 // 11 November 2003 Dale Lear - see comments in TweakAnnotationPlane()
10423 TweakAnnotationPlane( plane );
10424
10425 ldr->SetPlane( plane);
10426
10427 // flags ( future )
10428 if( !ReadInt( 1, &j))
10429 return false;
10430
10431 // settings byobject flag
10432 if( !ReadInt( 1, &byobject))
10433 return false;
10434
10435 // number of points to read
10436 if( !ReadInt( &k))
10437 return false;
10438
10439 if( k < 2)
10440 return true;
10441
10442 ON_SimpleArray<ON_2dPoint> points;
10443 for( j = 0; j < k; j++ )
10444 {
10445 double pt[3];
10446 if( !ReadDouble( 3, pt))
10447 return false;
10448 points.Append( ON_2dPoint( pt));
10449 }
10450 ldr->SetPoints( points);
10451
10452 *ppObject = ldr;
10453 rc = true;
10454 break;
10455 }
10456 }
10457 break;
10458 case TCODE_LINEAR_DIMENSION:
10459 {
10460 // read the version id
10461 if( !ReadInt( &i))
10462 return false;
10463
10464 if( i == RHINO_LINEAR_DIMENSION_VERSION_1)
10465 {
10466 if( !ReadInt( &i))
10467 return false;
10468
10469 ON_LinearDimension* dim = new ON_LinearDimension;
10470 switch( i )
10471 {
10472 case DimHorizontal:
10473 case DimVertical:
10474 case DimRotated:
10475 case DimLinear:
10476 dim->SetType( ON::dtDimLinear);
10477 break;
10478 default:
10479 dim->SetType( ON::dtDimAligned);
10480 break;
10481 }
10482
10483 ON_Plane plane;
10484
10485 // the entity plane
10486 if( !ReadDouble( 3, &plane.origin.x))
10487 return false;
10488 if( !ReadDouble( 3, &plane.xaxis.x))
10489 return false;
10490 if( !ReadDouble( 3, &plane.yaxis.x))
10491 return false;
10492
10493 // 11 November 2003 Dale Lear - see comments in TweakAnnotationPlane()
10494 TweakAnnotationPlane( plane );
10495
10496 dim->SetPlane( plane);
10497
10498 // definition points in coordinates of entity plane
10499 ON_SimpleArray<ON_2dPoint> points;
10500 for( j = 0; j < 11; j++ )
10501 {
10502 double pt[3];
10503 if( !ReadDouble( 3, pt))
10504 return false;
10505 points.Append( ON_2dPoint( pt));
10506 }
10507 dim->SetPoints( points);
10508
10509 // read user text string
10510 if ( !ReadV1_TCODE_ANNOTATION_Helper( *this, buffer, tc ) )
10511 return false;
10512 dim->SetUserText( tc.Array());
10513
10514 // Set the symbols used in dimension strings to the selected options
10515 // SetStringSymbols();
10516
10517 // read string to display
10518 if ( !ReadV1_TCODE_ANNOTATION_Helper( *this, buffer, tc ) )
10519 return false;
10520 dim->SetDefaultText( tc.Array());
10521
10522 // user positioned text flag
10523 if( !ReadInt( &j))
10524 return false;
10525 dim->SetUserPositionedText( j);
10526
10527 // flags ( future )
10528 if( !ReadInt( 1, &j))
10529 return false;
10530
10531 // settings byobject flag
10532 if( !ReadInt( 1, &byobject))
10533 return false;
10534
10535 *ppObject = dim;
10536 rc = true;
10537 break;
10538 }
10539 }
10540 break;
10541
10542 case TCODE_ANGULAR_DIMENSION:
10543 {
10544 // read the version id
10545 if( !ReadInt( &i))
10546 return false;
10547
10548 if( i == RHINO_ANGULAR_DIMENSION_VERSION_1)
10549 {
10550 if( !ReadInt( &i))
10551 return false;
10552
10553 ON_AngularDimension* dim = new ON_AngularDimension;
10554 dim->SetType( ON::dtDimAngular);
10555
10556 ON_Plane plane;
10557
10558 // the entity plane
10559 if( !ReadDouble( 3, &plane.origin.x))
10560 return false;
10561 if( !ReadDouble( 3, &plane.xaxis.x))
10562 return false;
10563 if( !ReadDouble( 3, &plane.yaxis.x))
10564 return false;
10565
10566 // 11 November 2003 Dale Lear - see comments in TweakAnnotationPlane()
10567 TweakAnnotationPlane( plane );
10568
10569 dim->SetPlane( plane);
10570
10571 if( !ReadDouble( &d))
10572 return false;
10573 dim->SetAngle( d);
10574
10575 if( !ReadDouble( &d))
10576 return false;
10577 dim->SetRadius( d);
10578
10579 // distances from apes to start and end of dimensioned lines - not used
10580 if( !ReadDouble( 4, d4))
10581 return false;
10582
10583 // definition points in coordinates of entity plane
10584 ON_SimpleArray<ON_2dPoint> points;
10585 for( j = 0; j < 5; j++ )
10586 {
10587 double pt[3];
10588 if( !ReadDouble( 3, pt))
10589 return false;
10590 points.Append( ON_2dPoint( pt));
10591 }
10592 dim->SetPoints( points);
10593
10594 // read user text string
10595 if ( !ReadV1_TCODE_ANNOTATION_Helper( *this, buffer, tc ) )
10596 return false;
10597 dim->SetUserText( tc.Array());
10598
10599 // Set the symbols used in dimension strings to the selected options
10600 // SetStringSymbols();
10601
10602 // read string to display
10603 if ( !ReadV1_TCODE_ANNOTATION_Helper( *this, buffer, tc ) )
10604 return false;
10605 dim->SetDefaultText( tc.Array());
10606
10607 // user positioned text flag
10608 if( !ReadInt( &j))
10609 return false;
10610 dim->SetUserPositionedText( j);
10611
10612
10613 // flags ( future )
10614 if( !ReadInt( 1, &j))
10615 return false;
10616
10617 // settings byobject flag
10618 if( !ReadInt( 1, &byobject))
10619 return false;
10620
10621
10622 *ppObject = dim;
10623 rc = true;
10624 break;
10625 }
10626 }
10627 break;
10628
10629 case TCODE_RADIAL_DIMENSION:
10630 {
10631 // read the version id
10632 if( !ReadInt( &i))
10633 return false;
10634
10635 if( i == RHINO_RADIAL_DIMENSION_VERSION_1)
10636 {
10637 if( !ReadInt( &i))
10638 return false;
10639
10640 ON_RadialDimension* dim = new ON_RadialDimension;
10641
10642 switch( i)
10643 {
10644 case DimDiameter:
10645 dim->SetType( ON::dtDimDiameter);
10646 break;
10647 case DimRadius:
10648 dim->SetType( ON::dtDimRadius);
10649 break;
10650 }
10651
10652 ON_Plane plane;
10653
10654 // the entity plane
10655 if( !ReadDouble( 3, &plane.origin.x))
10656 return false;
10657 if( !ReadDouble( 3, &plane.xaxis.x))
10658 return false;
10659 if( !ReadDouble( 3, &plane.yaxis.x))
10660 return false;
10661
10662 // 11 November 2003 Dale Lear - see comments in TweakAnnotationPlane()
10663 TweakAnnotationPlane( plane );
10664
10665 dim->SetPlane( plane);
10666
10667 // definition points in coordinates of entity plane
10668 ON_SimpleArray<ON_2dPoint> points;
10669 for( j = 0; j < 5; j++ )
10670 {
10671 double pt[3];
10672 if( !ReadDouble( 3, pt))
10673 return false;
10674 points.Append( ON_2dPoint( pt));
10675 }
10676 dim->SetPoints( points);
10677
10678 // read user text string
10679 if ( !ReadV1_TCODE_ANNOTATION_Helper( *this, buffer, tc ) )
10680 return false;
10681 dim->SetUserText( tc.Array());
10682
10683 // Set the symbols used in dimension strings to the selected options
10684 // SetStringSymbols();
10685
10686 // read string to display
10687 if ( !ReadV1_TCODE_ANNOTATION_Helper( *this, buffer, tc ) )
10688 return false;
10689 dim->SetDefaultText( tc.Array());
10690
10691 // user positioned text flag
10692 if( !ReadInt( &j))
10693 return false;
10694 dim->SetUserPositionedText( j);
10695
10696 // flags ( future )
10697 if( !ReadInt( 1, &j))
10698 return false;
10699
10700 // settings byobject flag
10701 if( !ReadInt( 1, &byobject))
10702 return false;
10703
10704
10705 *ppObject = dim;
10706 rc = true;
10707 break;
10708 }
10709
10710 }
10711 break;
10712
10713 default: // some unknown type to skip over
10714 return true;
10715 } //switch
10716
10717 if( rc)
10718 {
10719 ON_BOOL32 bHaveMat = false;
10720 Read3dmV1AttributesOrMaterial(pAttributes,NULL,bHaveMat,TCODE_ENDOFTABLE);
10721 }
10722
10723 return rc;
10724
10725 // TODO: fill in this function
10726
10727 // input tcode returned *ppObject points to
10728 // TCODE_TEXT_BLOCK: ON_TextEntity
10729 // TCODE_ANNOTATION_LEADER: ON_Leader
10730 // TCODE_LINEAR_DIMENSION: ON_LinearDimension
10731 // TCODE_ANGULAR_DIMENSION: ON_AngularDimension
10732 // TCODE_RADIAL_DIMENSION: ON_RadialDimension
10733 //return true if successful and false for failure.
10734 }
10735
10736
ReadV1_TCODE_MESH_OBJECT(ON_Object ** ppObject,ON_3dmObjectAttributes * pAttributes)10737 bool ON_BinaryArchive::ReadV1_TCODE_MESH_OBJECT(
10738 ON_Object** ppObject,
10739 ON_3dmObjectAttributes* pAttributes
10740 )
10741 {
10742 ON_Mesh* mesh = 0;
10743 bool rc = false;
10744 // read v1 mesh
10745 ON__UINT32 tcode = 0;
10746 ON__INT64 big_value = 0;
10747 int i;
10748 if ( !BeginRead3dmBigChunk(&tcode,&big_value) )
10749 return false;
10750
10751 if ( tcode == TCODE_COMPRESSED_MESH_GEOMETRY ) for(;;)
10752 {
10753
10754 int point_count = 0;
10755 int face_count = 0;
10756 ON_BOOL32 bHasVertexNormals = false;
10757 ON_BOOL32 bHasTexCoords = false;
10758 ON_BoundingBox bbox;
10759
10760 if (!ReadInt(&point_count) )
10761 break;
10762 if ( point_count <= 0 )
10763 break;
10764 if (!ReadInt(&face_count) )
10765 break;
10766 if ( face_count <= 0 )
10767 break;
10768 if (!ReadInt(&bHasVertexNormals) )
10769 break;
10770 if (!ReadInt(&bHasTexCoords) )
10771 break;
10772 if ( !ReadPoint(bbox.m_min) )
10773 break;
10774 if ( !ReadPoint(bbox.m_max) )
10775 break;
10776
10777 mesh = new ON_Mesh(face_count,
10778 point_count,
10779 bHasVertexNormals?true:false,
10780 bHasTexCoords?true:false
10781 );
10782
10783 // read 3d vertex locations
10784 {
10785 ON_3dVector d = bbox.Diagonal();
10786 double dx = d.x / 65535.0;
10787 double dy = d.y / 65535.0;
10788 double dz = d.z / 65535.0;
10789 unsigned short xyz[3];
10790 ON_3fPoint pt;
10791 for ( i = 0; i < point_count; i++ ) {
10792 if ( !ReadShort(3,xyz) )
10793 break;
10794 pt.x = (float)(dx*xyz[0] + bbox.m_min.x);
10795 pt.y = (float)(dy*xyz[1] + bbox.m_min.y);
10796 pt.z = (float)(dz*xyz[2] + bbox.m_min.z);
10797 mesh->m_V.Append(pt);
10798 }
10799 }
10800 if ( mesh->m_V.Count() != point_count )
10801 break;
10802
10803 // read triangle/quadrangle faces
10804 if ( point_count < 65535 ) {
10805 unsigned short abcd[4];
10806 for ( i = 0; i < face_count; i++ ) {
10807 if ( !ReadShort(4,abcd) )
10808 break;
10809 ON_MeshFace& f = mesh->m_F.AppendNew();
10810 f.vi[0] = abcd[0];
10811 f.vi[1] = abcd[1];
10812 f.vi[2] = abcd[2];
10813 f.vi[3] = abcd[3];
10814 }
10815 }
10816 else {
10817 int abcd[4];
10818 for ( i = 0; i < face_count; i++ ) {
10819 if ( !ReadInt(4,abcd) )
10820 break;
10821 ON_MeshFace& f = mesh->m_F.AppendNew();
10822 f.vi[0] = abcd[0];
10823 f.vi[1] = abcd[1];
10824 f.vi[2] = abcd[2];
10825 f.vi[3] = abcd[3];
10826 }
10827 }
10828 if ( mesh->m_F.Count() != face_count )
10829 break;
10830
10831 if ( bHasVertexNormals ) {
10832 char xyz[3];
10833 ON_3fVector normal;
10834 for ( i = 0; i < point_count; i++ ) {
10835 if ( !ReadChar(3,xyz) )
10836 break;
10837 normal.x = (float)(((signed char)xyz[0])/127.0);
10838 normal.y = (float)(((signed char)xyz[1])/127.0);
10839 normal.z = (float)(((signed char)xyz[2])/127.0);
10840 mesh->m_N.Append(normal);
10841 }
10842 if ( mesh->m_N.Count() != mesh->m_V.Count() )
10843 break;
10844 }
10845
10846 if ( bHasTexCoords ) {
10847 unsigned short uv[2];
10848 ON_2fPoint t;
10849 for ( i = 0; i < point_count; i++ ) {
10850 if ( !ReadShort(2,uv) )
10851 break;
10852 t.x = (float)(uv[0]/65535.0);
10853 t.y = (float)(uv[1]/65535.0);
10854 mesh->m_T.Append(t);
10855 }
10856 if ( mesh->m_T.Count() != mesh->m_V.Count() )
10857 break;
10858 }
10859
10860 rc = true;
10861
10862 break;
10863 }
10864
10865 if ( !EndRead3dmChunk() )
10866 rc = false;
10867
10868 if ( rc && mesh ) {
10869 *ppObject = mesh;
10870 }
10871 else {
10872 if ( mesh )
10873 delete mesh;
10874 rc = false;
10875 }
10876
10877 if ( rc && mesh ) {
10878 // attributes and material information follows the TCODE_COMPRESSED_MESH_GEOMETRY chunk;
10879 ON_BOOL32 bHaveMat = false;
10880 Read3dmV1AttributesOrMaterial(pAttributes,NULL,bHaveMat,TCODE_ENDOFTABLE);
10881 }
10882
10883 return rc;
10884 }
10885
BeginRead3dmLEGACYSTUFF(ON_BinaryArchive & file,unsigned int stuff_tcode)10886 static bool BeginRead3dmLEGACYSTUFF( ON_BinaryArchive& file, unsigned int stuff_tcode )
10887 {
10888 // begins reading stuff chunk
10889 bool rc = false;
10890 ON__UINT32 tcode = !stuff_tcode;
10891 ON__INT64 big_value = 0;
10892 for (;;)
10893 {
10894 if ( !file.BeginRead3dmBigChunk(&tcode,&big_value) )
10895 break;
10896 if ( tcode == stuff_tcode ) {
10897 rc = true;
10898 break;
10899 }
10900 if ( !file.EndRead3dmChunk() )
10901 break;
10902 }
10903 return rc;
10904 }
10905
ReadV1_TCODE_LEGACY_SPLSTUFF(ON_BinaryArchive & file)10906 static ON_NurbsCurve* ReadV1_TCODE_LEGACY_SPLSTUFF( ON_BinaryArchive& file )
10907 {
10908 // reads contents of a v1 TCODE_LEGACY_SPLSTUFF chunk
10909 ON_NurbsCurve* pNurbsCurve = 0;
10910 int i, dim, is_rat, order, cv_count; // , is_closed, form;
10911 ON_BoundingBox bbox;
10912 char c;
10913
10914 // read v1 agspline chunk
10915 if ( !file.ReadChar(1,&c) )
10916 return NULL;
10917 if ( c != 2 && c != 3 )
10918 return NULL;
10919 dim = c;
10920 if ( !file.ReadChar(1,&c) )
10921 return NULL;
10922 if ( c != 0 && c != 1 && c != 2 )
10923 return NULL;
10924 is_rat = c; // 0 = no, 1 = euclidean, 2 = homogeneous
10925 if ( !file.ReadChar(1,&c) )
10926 return NULL;
10927 if ( c < 2 )
10928 return NULL;
10929 order = c;
10930
10931 {
10932 // 5 February 2003 - An single case of a V1 file
10933 // with a spline that had cv_count = 54467 (>32767)
10934 // exists. Changing from a signed short to
10935 // an unsigned short fixed the problem.
10936 // The ui casting stuff is here to keep all
10937 // the various compilers/lints happy and to
10938 // make sure the short with the high bit set
10939 // gets properly converted to a positive cv_count.
10940 unsigned short s;
10941 if ( !file.ReadShort(1,&s) )
10942 return NULL;
10943 unsigned int ui = s;
10944 cv_count = (int)ui;
10945 if ( cv_count < order )
10946 return NULL;
10947 }
10948
10949 // The "is_closed" and "form" flags are here to recording
10950 // the values of legacy data found in the Rhino file. These
10951 // values are not used in the toolkit code.
10952 if ( !file.ReadByte(1,&c) )
10953 return NULL;
10954 if (c != 0 && c != 1 && c != 2)
10955 return NULL;
10956 // is_closed = c; // 0 = open, 1 = closed, 2 = periodic
10957 if ( !file.ReadByte(1,&c) )
10958 return NULL;
10959 // form = c;
10960
10961 // read bounding box
10962 if ( !file.ReadDouble( dim, bbox.m_min ) )
10963 return NULL;
10964 if ( !file.ReadDouble( dim, bbox.m_max ) )
10965 return NULL;
10966
10967 pNurbsCurve = new ON_NurbsCurve( dim, is_rat?true:false, order, cv_count );
10968
10969 ON_BOOL32 rc = false;
10970 for(;;) {
10971
10972 // read legacy v1 knot vector
10973 const int knot_count = order+cv_count-2;
10974 int knot_index = 0;
10975 double knot;
10976
10977 // clamped_end_knot_flag: 0 = none, 1 = left, 2 = right, 3 = both
10978 char clamped_end_knot_flag = 0;
10979 if ( order > 2 )
10980 file.ReadChar(1,&clamped_end_knot_flag);
10981
10982 // first knot(s)
10983 if ( !file.ReadDouble(&knot) )
10984 break;
10985 pNurbsCurve->m_knot[knot_index++] = knot;
10986 if (clamped_end_knot_flag % 2) {
10987 // clamped_start_knot
10988 while ( knot_index <= order-2 )
10989 pNurbsCurve->m_knot[knot_index++] = knot;
10990 }
10991
10992 // middle knots
10993 while ( knot_index <= cv_count-1 ) {
10994 if ( !file.ReadDouble(&knot) )
10995 break;
10996 pNurbsCurve->m_knot[knot_index++] = knot;
10997 }
10998 if ( knot_index <= cv_count-1 )
10999 break;
11000
11001 // end knot(s)
11002 if ( clamped_end_knot_flag >= 2 ) {
11003 while ( knot_index < knot_count )
11004 pNurbsCurve->m_knot[knot_index++] = knot;
11005 }
11006 else {
11007 while ( knot_index < knot_count ) {
11008 if ( !file.ReadDouble(&knot) )
11009 break;
11010 pNurbsCurve->m_knot[knot_index++] = knot;
11011 }
11012 if ( knot_index < knot_count )
11013 break;
11014 }
11015
11016 // read legacy v1 control points
11017 const int cvdim = ( is_rat ) ? dim+1 : dim;
11018 for ( i = 0; i < cv_count; i++ ) {
11019 if ( !file.ReadDouble( cvdim, pNurbsCurve->CV(i) ) )
11020 break;
11021 }
11022 if ( i < cv_count )
11023 break;
11024 if ( is_rat ) {
11025 // is_rat == 1 check fails because invalid is_rat flags in old files
11026 // convert rational CVs from euclidean to homogeneous
11027 double w, *cv;
11028 int cv_index;
11029 for ( cv_index = 0; cv_index < cv_count; cv_index++ ) {
11030 cv = pNurbsCurve->CV(cv_index);
11031 w = cv[dim];
11032 for ( i = 0; i < dim; i++ )
11033 cv[i] *= w;
11034 }
11035 }
11036 if ( order == 2 && cv_count == 2 && pNurbsCurve->m_knot[0] > pNurbsCurve->m_knot[1] ) {
11037 // a few isolated old v1 3DM file created by Rhino 1.0 files have lines with reversed knots.
11038 pNurbsCurve->m_knot[0] = -pNurbsCurve->m_knot[0];
11039 pNurbsCurve->m_knot[1] = -pNurbsCurve->m_knot[1];
11040 }
11041 rc = true;
11042
11043 break;
11044 }
11045 if ( !rc && pNurbsCurve ) {
11046 delete pNurbsCurve;
11047 pNurbsCurve = 0;
11048 }
11049 return pNurbsCurve;
11050 }
11051
ReadV1_TCODE_LEGACY_SPL(ON_BinaryArchive & file,ON_NurbsCurve * & pNurbsCurve)11052 static ON_BOOL32 ReadV1_TCODE_LEGACY_SPL( ON_BinaryArchive& file,
11053 ON_NurbsCurve*& pNurbsCurve
11054 )
11055 {
11056 // reads contents of TCODE_LEGACY_SPL chunk
11057 pNurbsCurve = 0;
11058 ON_BOOL32 rc = BeginRead3dmLEGACYSTUFF(file, TCODE_LEGACY_SPLSTUFF );
11059 if ( !rc )
11060 return false;
11061 pNurbsCurve = ReadV1_TCODE_LEGACY_SPLSTUFF(file);
11062 if ( !file.EndRead3dmChunk() ) // end of TCODE_LEGACY_SPLSTUFF chunk
11063 rc = false;
11064 if ( !pNurbsCurve )
11065 rc = false;
11066 return rc;
11067 }
11068
ReadV1_TCODE_LEGACY_SRFSTUFF(ON_BinaryArchive & file)11069 static ON_NurbsSurface* ReadV1_TCODE_LEGACY_SRFSTUFF( ON_BinaryArchive& file )
11070 {
11071 // reads contents of TCODE_LEGACY_SRFSTUFF chunk
11072 ON_NurbsSurface* pNurbsSurface = 0;
11073 int i, j, dim=0, is_rat=0, order[2], cv_count[2]; //, is_closed[2], is_singular[2], form;
11074 ON_BoundingBox bbox;
11075 char c;
11076
11077 // read contents of v1 TCODE_LEGACY_SRFSTUFF chunk
11078 if ( !file.ReadChar(1,&c) )
11079 return NULL;
11080 if ( c != 2 && c != 3 )
11081 return NULL;
11082 dim = c;
11083 if ( !file.ReadByte(1,&c) )
11084 return NULL;
11085 // form = c;
11086 if ( !file.ReadChar(1,&c) )
11087 return NULL;
11088 if ( c < 1 )
11089 return NULL;
11090 order[0] = c+1;
11091 if ( !file.ReadChar(1,&c) )
11092 return NULL;
11093 if ( c < 1 )
11094 return NULL;
11095 order[1] = c+1;
11096
11097 {
11098 // 5 February 2003 - An single case of a V1 files
11099 // See the comment above in ReadV1_TCODE_LEGACY_SPLSTUFF
11100 // concerning the spline with cv_count >= 0x8000.
11101 // The analogous fix is here for the surface case.
11102 unsigned short s;
11103 if ( !file.ReadShort(1,&s) )
11104 return NULL;
11105 if ( s < 1 )
11106 return NULL;
11107 unsigned int ui = s;
11108 cv_count[0] = order[0]-1+((int)ui);
11109 if ( !file.ReadShort(1,&s) )
11110 return NULL;
11111 if ( s < 1 )
11112 return NULL;
11113 ui = s;
11114 cv_count[1] = order[1]-1+((int)ui);
11115 }
11116
11117 // "ratu" 0 = no, 1 = euclidean, 2 = homogeneous
11118 if ( !file.ReadChar(1,&c) )
11119 return NULL;
11120 if ( c == 1 ) is_rat = 1; else if ( c == 2 ) is_rat = 2;
11121
11122 // "ratv" 0 = no, 1 = euclidean, 2 = homogeneous
11123 if ( !file.ReadChar(1,&c) )
11124 return NULL;
11125 if ( c == 1 ) is_rat = 1; else if ( c == 2 ) is_rat = 2;
11126
11127 // The "is_closed" and "is_singular" flags are here to recording
11128 // the values of legacy data found in the Rhino file. These
11129 // values are not used in the toolkit code.
11130 if ( !file.ReadByte(1,&c) )
11131 return NULL;
11132 if (c != 0 && c != 1 && c != 2)
11133 return NULL;
11134 // is_closed[0] = c; // 0 = open, 1 = closed, 2 = periodic
11135 if ( !file.ReadByte(1,&c) )
11136 return NULL;
11137 if (c != 0 && c != 1 && c != 2)
11138 return NULL;
11139 // is_closed[1] = c; // 0 = open, 1 = closed, 2 = periodic
11140
11141 if ( !file.ReadByte(1,&c) )
11142 return NULL;
11143 if (c != 0 && c != 1 && c != 2 && c != 3)
11144 return NULL;
11145 // is_singular[0] = c;
11146 if ( !file.ReadByte(1,&c) )
11147 return NULL;
11148 if (c != 0 && c != 1 && c != 2 && c != 3)
11149 return NULL;
11150 // is_singular[1] = c;
11151
11152 // read bounding box
11153 if ( !file.ReadDouble( dim, bbox.m_min ) )
11154 return NULL;
11155 if ( !file.ReadDouble( dim, bbox.m_max ) )
11156 return NULL;
11157
11158 pNurbsSurface = new ON_NurbsSurface( dim, is_rat?true:false,
11159 order[0], order[1],
11160 cv_count[0], cv_count[1] );
11161
11162 ON_BOOL32 rc = false;
11163 for (;;) {
11164
11165 // read legacy v1 knot vectors
11166 if ( !file.ReadDouble( order[0]+cv_count[0]-2, pNurbsSurface->m_knot[0] ) )
11167 break;
11168 if ( !file.ReadDouble( order[1]+cv_count[1]-2, pNurbsSurface->m_knot[1] ) )
11169 break;
11170
11171 // read legacy v1 control points
11172 const int cvdim = ( is_rat ) ? dim+1 : dim;
11173 for ( i = 0; i < cv_count[0]; i++ ) {
11174 for ( j = 0; j < cv_count[1]; j++ ) {
11175 if ( !file.ReadDouble( cvdim, pNurbsSurface->CV(i,j) ) )
11176 break;
11177 }
11178 if ( j < cv_count[1] )
11179 break;
11180 }
11181 if ( i < cv_count[0] )
11182 break;
11183 if ( is_rat == 1 ) {
11184 double w, *cv;
11185 int k;
11186 for ( i = 0; i < cv_count[0]; i++ ) for ( j = 0; j < cv_count[1]; j++ ) {
11187 cv = pNurbsSurface->CV(i,j);
11188 w = cv[dim];
11189 for ( k = 0; k < dim; k++ )
11190 cv[k] *= w;
11191 }
11192 }
11193 rc = true;
11194
11195 break;
11196 }
11197 if ( !rc ) {
11198 delete pNurbsSurface;
11199 pNurbsSurface = 0;
11200 }
11201
11202 return pNurbsSurface;
11203 }
11204
ReadV1_TCODE_LEGACY_SRF(ON_BinaryArchive & file,ON_NurbsSurface * & pNurbsSurface)11205 static ON_BOOL32 ReadV1_TCODE_LEGACY_SRF( ON_BinaryArchive& file,
11206 ON_NurbsSurface*& pNurbsSurface
11207 )
11208 {
11209 pNurbsSurface = 0;
11210 ON_BOOL32 rc = BeginRead3dmLEGACYSTUFF( file, TCODE_LEGACY_SRF );
11211 if ( rc ) {
11212 rc = BeginRead3dmLEGACYSTUFF( file, TCODE_LEGACY_SRFSTUFF );
11213 if ( rc ) {
11214 pNurbsSurface = ReadV1_TCODE_LEGACY_SRFSTUFF( file );
11215 if ( !file.EndRead3dmChunk() ) // end of TCODE_LEGACY_SRFSTUFF chunk
11216 rc = false;
11217 }
11218 if ( !file.EndRead3dmChunk() )
11219 rc = false; // end of TCODE_LEGACY_SRF chunk
11220 }
11221 if ( !rc && pNurbsSurface ) {
11222 delete pNurbsSurface;
11223 pNurbsSurface = 0;
11224 }
11225 return rc;
11226 }
11227
ReadV1_TCODE_LEGACY_CRVSTUFF(ON_BinaryArchive & file)11228 ON_Curve* ReadV1_TCODE_LEGACY_CRVSTUFF( ON_BinaryArchive& file )
11229 {
11230 // reads contents of a v1 TCODE_LEGACY_CRVSTUFF chunk
11231 ON_Curve* curve = 0;
11232 ON_PolyCurve* polycurve = 0;
11233 ON_NurbsCurve* segment = 0;
11234 ON_BOOL32 rc = false;
11235 ON__UINT32 tcode = 0;
11236 ON__INT64 big_value = 0;
11237 int i;
11238 ON_BOOL32 bIsPolyline = false;
11239 ON_BoundingBox bbox;
11240
11241 for (;;) {
11242 char c;
11243 short s;
11244 int segment_count = 0;
11245 file.ReadChar(1,&c);
11246 if ( c != 2 && c != 3 )
11247 break;
11248 int dim = c;
11249 file.ReadChar(1,&c);
11250 if ( c != -1 && c != 0 && c != 1 && c != 2 )
11251 break;
11252 //int is_closed = (c) ? 1 : 0;
11253 file.ReadShort(&s);
11254 if ( s < 1 )
11255 break;
11256 file.ReadDouble( dim, bbox.m_min);
11257 file.ReadDouble( dim, bbox.m_max);
11258 segment_count = s;
11259 for ( i = 0; i < segment_count; i++ ) {
11260 segment = 0;
11261 tcode = 0;
11262 big_value = 0;
11263 if ( !file.BeginRead3dmBigChunk( &tcode, &big_value ) )
11264 break;
11265 if ( tcode == TCODE_LEGACY_SPL && big_value > 0 ) {
11266 ReadV1_TCODE_LEGACY_SPL(file,segment);
11267 }
11268 if ( !file.EndRead3dmChunk() ) {
11269 if ( segment ) {
11270 delete segment;
11271 segment = 0;
11272 }
11273 break;
11274 }
11275 if ( !segment )
11276 break;
11277 if ( i == 0 )
11278 polycurve = new ON_PolyCurve(segment_count);
11279 if ( segment->CVCount() > 2 || segment->Order() != 2 || segment->IsRational() )
11280 {
11281 if ( segment->Order() != 2 || segment->IsRational() )
11282 bIsPolyline = false;
11283 polycurve->Append(segment);
11284 }
11285 else
11286 {
11287 ON_LineCurve* line = new ON_LineCurve();
11288 line->m_t.Set( segment->m_knot[0], segment->m_knot[1] );
11289 segment->GetCV( 0, line->m_line.from );
11290 segment->GetCV( 1, line->m_line.to );
11291 line->m_dim = segment->m_dim;
11292 delete segment;
11293 segment = 0;
11294 polycurve->Append(line);
11295 }
11296 }
11297
11298 // 5 February 2003
11299 // The check for a NULL polycurve was added to avoid
11300 // crashes in files when the first NURBS curve in the
11301 // polycurve could not be read.
11302 if ( 0 == polycurve )
11303 break;
11304 if ( polycurve->Count() != segment_count )
11305 break;
11306 rc = true;
11307 break;
11308 }
11309
11310 if ( rc && polycurve )
11311 {
11312 if ( polycurve->Count() == 1 )
11313 {
11314 curve = polycurve->HarvestSegment(0);
11315 delete polycurve;
11316 }
11317 else if ( bIsPolyline )
11318 {
11319 ON_PolylineCurve* pline = new ON_PolylineCurve();
11320 pline->m_dim = polycurve->Dimension();
11321 pline->m_t.Reserve(polycurve->Count()+1);
11322 pline->m_t.SetCount(polycurve->Count()+1);
11323 polycurve->GetSpanVector( pline->m_t.Array() );
11324 pline->m_pline.Reserve(polycurve->Count()+1);
11325 for ( i = 0; i < polycurve->Count(); i++ ) {
11326 pline->m_pline.Append(polycurve->SegmentCurve(i)->PointAtStart());
11327 }
11328 pline->m_pline.Append(polycurve->SegmentCurve(polycurve->Count()-1)->PointAtEnd());
11329 curve = pline;
11330 delete polycurve;
11331 }
11332 else
11333 {
11334 curve = polycurve;
11335 }
11336 }
11337 else
11338 {
11339 if ( polycurve )
11340 delete polycurve;
11341 rc = false;
11342 }
11343
11344 return curve;
11345 }
11346
ReadV1_LegacyTrimStuff(ON_BinaryArchive & file,ON_BrepFace &,ON_BrepLoop & loop)11347 bool ON_Brep::ReadV1_LegacyTrimStuff( ON_BinaryArchive& file,
11348 ON_BrepFace&, // face - formal parameter intentionally ignored
11349 ON_BrepLoop& loop )
11350 {
11351 // read contents of TCODE_LEGACY_TRMSTUFF chunk
11352 bool rc = false;
11353 int revedge, gcon, mono;
11354 int curve2d_index = -1, curve3d_index = -1, trim_index = -1;
11355 double tol_3d, tol_2d;
11356 ON_Curve* curve2d = NULL;
11357 ON_Curve* curve3d = NULL;
11358
11359 char c;
11360 file.ReadChar( &c );
11361
11362 ON_BOOL32 bHasEdge = (c % 2 ); // bit 0 = 1 if "tedge" has non NULL "->edge"
11363 ON_BOOL32 bHasMate = (c & 6 ); // bit 1 or 2 = 1 if "tedge" has non NULL "->twin"
11364 ON_BOOL32 bIsSeam = (c & 2 ); // bit 1 = 1 if "tedge->twin" belongs to same face
11365
11366 if ( !file.ReadInt(&revedge) )
11367 return false;
11368 if ( !file.ReadInt(&gcon) )
11369 return false;
11370 if ( !file.ReadInt(&mono) )
11371 return false;
11372 if ( !file.ReadDouble( &tol_3d ) )
11373 return false;
11374 if ( !file.ReadDouble( &tol_2d ) )
11375 return false;
11376
11377 // 2d trim curve
11378 if ( !BeginRead3dmLEGACYSTUFF( file, TCODE_LEGACY_CRV ) )
11379 return false;
11380 if ( BeginRead3dmLEGACYSTUFF( file, TCODE_LEGACY_CRVSTUFF ) ) {
11381 curve2d = ReadV1_TCODE_LEGACY_CRVSTUFF(file);
11382 if ( !file.EndRead3dmChunk() ) // end of TCODE_LEGACY_CRVSTUFF chunk
11383 rc = false;
11384 }
11385 if ( !file.EndRead3dmChunk() ) // end of TCODE_LEGACY_CRV chunk
11386 rc = false;
11387 if ( !curve2d )
11388 return false;
11389 curve2d_index = AddTrimCurve(curve2d);
11390 if ( curve2d_index < 0 ) {
11391 delete curve2d;
11392 return false;
11393 }
11394
11395 // 3d curve
11396 if ( bHasEdge ) {
11397 if ( !BeginRead3dmLEGACYSTUFF( file, TCODE_LEGACY_CRV ) )
11398 return false;
11399 if ( BeginRead3dmLEGACYSTUFF( file, TCODE_LEGACY_CRVSTUFF ) ) {
11400 curve3d = ReadV1_TCODE_LEGACY_CRVSTUFF(file);
11401 if ( !file.EndRead3dmChunk() ) // end of TCODE_LEGACY_CRVSTUFF chunk
11402 rc = false;
11403 }
11404 if ( !file.EndRead3dmChunk() ) // end of TCODE_LEGACY_CRV chunk
11405 rc = false;
11406 if ( !curve3d )
11407 return false;
11408 curve3d_index = AddEdgeCurve(curve3d);
11409 if ( curve3d_index < 0 ) {
11410 delete curve3d;
11411 return false;
11412 }
11413 ON_BrepEdge& edge = NewEdge(curve3d_index);
11414 ON_BrepTrim& trim = NewTrim( edge,
11415 revedge ? true : false,
11416 loop,
11417 curve2d_index
11418 );
11419 trim_index = trim.m_trim_index;
11420 }
11421 else {
11422 ON_BrepTrim& trim = NewTrim( revedge ? true : false,
11423 loop,
11424 curve2d_index
11425 );
11426 trim_index = trim.m_trim_index;
11427 }
11428 if ( trim_index >= 0 ) {
11429 ON_BrepTrim& trim = m_T[trim_index];
11430 trim.m__legacy_2d_tol = tol_2d;
11431 trim.m__legacy_3d_tol = tol_3d;
11432 trim.m__legacy_flags_Set(gcon,mono);
11433 if ( bIsSeam ) {
11434 trim.m_type = ON_BrepTrim::seam;
11435 }
11436 else if ( bHasMate ) {
11437 trim.m_type = ON_BrepTrim::mated;
11438 }
11439 else if ( bHasEdge ) {
11440 trim.m_type = ON_BrepTrim::boundary;
11441 }
11442 else {
11443 trim.m_type = ON_BrepTrim::singular;
11444 }
11445 }
11446
11447 (void)rc;//G+Smo
11448 return (trim_index>=0) ? true : false;
11449 }
11450
ReadV1_LegacyTrim(ON_BinaryArchive & file,ON_BrepFace & face,ON_BrepLoop & loop)11451 bool ON_Brep::ReadV1_LegacyTrim( ON_BinaryArchive& file,
11452 ON_BrepFace& face,
11453 ON_BrepLoop& loop )
11454 {
11455 bool rc = false;
11456 if ( !BeginRead3dmLEGACYSTUFF( file, TCODE_LEGACY_TRM ) )
11457 return false;
11458 rc = BeginRead3dmLEGACYSTUFF( file, TCODE_LEGACY_TRMSTUFF );
11459 if ( rc ) {
11460 rc = ReadV1_LegacyTrimStuff( file, face, loop );
11461 if ( !file.EndRead3dmChunk() ) // end of TCODE_LEGACY_TRMSTUFF
11462 rc = false;
11463 }
11464 if ( !file.EndRead3dmChunk() ) // end of TCODE_LEGACY_TRM chunk
11465 rc = false;
11466 return rc;
11467 }
11468
11469
ReadV1_LegacyLoopStuff(ON_BinaryArchive & file,ON_BrepFace & face)11470 bool ON_Brep::ReadV1_LegacyLoopStuff( ON_BinaryArchive& file,
11471 ON_BrepFace& face )
11472 {
11473 // reads contents of TCODE_LEGACY_BNDSTUFF chunk
11474 // read boundary
11475 ON_BrepLoop::TYPE loop_type = ON_BrepLoop::unknown;
11476 int tedge_count, btype, lti;
11477 double pspace_box[2][2]; // parameter space bounding box
11478
11479 if ( !file.ReadInt( &tedge_count ) )
11480 return false;
11481 if ( tedge_count < 1 ) {
11482 return false;
11483 }
11484 if ( !file.ReadInt( &btype ) )
11485 return false;
11486 if ( btype < -1 || btype > 1 ) {
11487 return false;
11488 }
11489 if ( !file.ReadDouble( 4, &pspace_box[0][0] ) )
11490 return false;
11491 switch( btype ) {
11492 case -1:
11493 loop_type = ON_BrepLoop::slit;
11494 break;
11495 case 0:
11496 loop_type = ON_BrepLoop::outer;
11497 break;
11498 case 1:
11499 loop_type = ON_BrepLoop::inner;
11500 break;
11501 }
11502 ON_BrepLoop& loop = NewLoop( loop_type, face );
11503
11504 for ( lti = 0; lti < tedge_count; lti++ ) {
11505 if ( !ReadV1_LegacyTrim( file, face, loop ) )
11506 return false;
11507 }
11508
11509 return true;
11510 }
11511
ReadV1_LegacyLoop(ON_BinaryArchive & file,ON_BrepFace & face)11512 bool ON_Brep::ReadV1_LegacyLoop( ON_BinaryArchive& file,
11513 ON_BrepFace& face )
11514 {
11515 bool rc = false;
11516 if ( !BeginRead3dmLEGACYSTUFF( file, TCODE_LEGACY_BND ) )
11517 return false;
11518 rc = BeginRead3dmLEGACYSTUFF( file, TCODE_LEGACY_BNDSTUFF );
11519 if ( rc ) {
11520 rc = ReadV1_LegacyLoopStuff( file, face );
11521 if ( !file.EndRead3dmChunk() ) // end of TCODE_LEGACY_BNDSTUFF
11522 rc = false;
11523 }
11524 if ( !file.EndRead3dmChunk() ) // end of TCODE_LEGACY_BND chunk
11525 rc = false;
11526 return rc;
11527 }
11528
ReadV1_LegacyFaceStuff(ON_BinaryArchive & file)11529 bool ON_Brep::ReadV1_LegacyFaceStuff( ON_BinaryArchive& file )
11530 {
11531 // reads contents of TCODE_LEGACY_FACSTUFF chunk
11532 ON_NurbsSurface* surface = 0;
11533 ON_Workspace ws;
11534 int flipnorm = 0;
11535 int ftype = 0;
11536 int bndcnt = 0;
11537 int twincnt = 0;
11538 ON_BOOL32 bHasOuter = false;
11539 ON_BoundingBox face_bbox;
11540
11541 int ti0 = m_T.Count();
11542
11543 bool rc = false;
11544
11545 // read flags
11546 if ( !file.ReadInt(&flipnorm) )
11547 return false;
11548 if ( flipnorm < 0 || flipnorm > 1 )
11549 return false;
11550 if ( !file.ReadInt(&ftype) )
11551 return false;
11552 if ( !file.ReadInt(&bndcnt) )
11553 return false;
11554 bHasOuter = (bndcnt%2); // always true in v1 files
11555 bndcnt /= 2;
11556
11557 // read bounding box
11558 if ( !file.ReadDouble( 3, face_bbox.m_min ) )
11559 return false;
11560 if ( !file.ReadDouble( 3, face_bbox.m_max ) )
11561 return false;
11562
11563 // B-rep edge gluing info
11564 if ( !file.ReadInt(&twincnt) )
11565 return false;
11566 short* glue = (twincnt > 0 ) ? (short*)ws.GetMemory(twincnt*sizeof(*glue)) : NULL;
11567 if (twincnt > 0) {
11568 if ( !file.ReadShort(twincnt,glue) )
11569 return false;
11570 }
11571
11572 // read surface
11573 if ( !ReadV1_TCODE_LEGACY_SRF( file, surface ) )
11574 return false;
11575 if ( !surface )
11576 return false;
11577 const int srf_index = AddSurface(surface);
11578
11579 // create face
11580 ON_BrepFace& face = NewFace(srf_index);
11581 face.m_bRev = (flipnorm) ? true : false;
11582 face.m_li.Reserve(bndcnt);
11583
11584 // read boundary loops
11585 int loop_index = -1;
11586 if ( !bHasOuter ) {
11587 // TODO: cook up outer boundary loop (never happes with v1 files)
11588 face.m_li.Append(loop_index);
11589 }
11590 int bi;
11591 rc = true;
11592 for ( bi = 0; rc && bi < bndcnt; bi++ ) {
11593 rc = ReadV1_LegacyLoop( file, face );
11594 }
11595
11596 if ( twincnt > 0 ) {
11597 // twincnt = number of seams edges in face
11598 // glue[] = order 2 permutation of {0,....,twincnt-1}
11599
11600 // set seam_i[] = m_T[] indices of seam trims
11601 int si, ti;
11602 const int ti1 = m_T.Count();
11603 int* seam_i = (int*)ws.GetMemory(twincnt*sizeof(*seam_i));
11604 for ( ti = ti0, si = 0; ti < ti1 && si < twincnt; ti++ ) {
11605 if (m_T[ti].m_type != ON_BrepTrim::seam )
11606 continue;
11607 seam_i[si++] = ti;
11608 }
11609
11610 if ( si == twincnt ) {
11611 // glue seams
11612 for ( si = 0; si < twincnt; si++ ) {
11613 if ( glue[si] >= 0 && glue[si] < twincnt ) {
11614 const int i0 = seam_i[si];
11615 const int i1 = seam_i[glue[si]];
11616 // m_T[i0] and m_T[i1] use the same edge;
11617 const int ei0 = m_T[i0].m_ei;
11618 const int ei1 = m_T[i1].m_ei;
11619 if ( ei0 == -1 && ei1 >= 0 ) {
11620 m_T[i0].m_ei = ei1;
11621 m_E[ei1].m_ti.Append(i0);
11622 }
11623 else if ( ei1 == -1 && ei0 >= 0 ) {
11624 m_T[i1].m_ei = ei0;
11625 m_E[ei0].m_ti.Append(i1);
11626 }
11627 }
11628 }
11629 }
11630 }
11631
11632 return rc;
11633 }
11634
ReadV1_LegacyShellStuff(ON_BinaryArchive & file)11635 bool ON_Brep::ReadV1_LegacyShellStuff( ON_BinaryArchive& file )
11636 {
11637 // read contents of TCODE_LEGACY_SHLSTUFF chunk
11638 ON_Workspace ws;
11639 int outer = 0;
11640 int facecnt = 0;
11641 int twincnt = 0;
11642 ON_BoundingBox shell_bbox;
11643 const int ti0 = m_T.Count();
11644
11645 /* read flags */
11646 file.ReadInt(&outer);
11647 file.ReadInt(&facecnt);
11648
11649 // read bounding box
11650 file.ReadPoint( shell_bbox.m_min );
11651 file.ReadPoint( shell_bbox.m_max );
11652
11653 /* B-rep edge gluing info */
11654 file.ReadInt(&twincnt);
11655 short* glue = (twincnt > 0 ) ? (short*)ws.GetMemory(twincnt*sizeof(*glue)) : NULL;
11656 if (twincnt > 0)
11657 file.ReadShort(twincnt,glue);
11658
11659 bool rc = true;
11660 int fi;
11661 for ( fi = 0; rc && fi < facecnt; fi++ ) {
11662 rc = BeginRead3dmLEGACYSTUFF( file, TCODE_LEGACY_FAC );
11663 if ( rc ) {
11664 rc = BeginRead3dmLEGACYSTUFF( file, TCODE_LEGACY_FACSTUFF );
11665 if ( rc ) {
11666 rc = ReadV1_LegacyFaceStuff( file );
11667 if ( !file.EndRead3dmChunk() ) // end of TCODE_LEGACY_FACSTUFF chunk
11668 rc = false;
11669 }
11670 if ( !file.EndRead3dmChunk() ) // end of TCODE_LEGACY_FAC chunk
11671 rc = false;
11672 }
11673 }
11674
11675 if ( twincnt > 0 ) {
11676 // twincnt = number of shared (inter-face) edges
11677 // glue[] = order 2 permutation of {0,....,twincnt-1}
11678
11679 // set share_i[] = m_T[] indices of shared trims
11680 int si, ti;
11681 const int ti1 = m_T.Count();
11682 int* share_i = (int*)ws.GetMemory(twincnt*sizeof(*share_i));
11683 for ( ti = ti0, si = 0; ti < ti1 && si < twincnt; ti++ ) {
11684 if (m_T[ti].m_type != ON_BrepTrim::mated )
11685 continue;
11686 share_i[si++] = ti;
11687 }
11688
11689 if ( si == twincnt ) {
11690 // glue seams
11691 for ( si = 0; si < twincnt; si++ ) {
11692 if ( glue[si] >= 0 && glue[si] < twincnt ) {
11693 const int i0 = share_i[si];
11694 const int i1 = share_i[glue[si]];
11695 // m_T[i0] and m_T[i1] use the same edge;
11696 const int ei0 = m_T[i0].m_ei;
11697 const int ei1 = m_T[i1].m_ei;
11698 if ( ei0 == -1 && ei1 >= 0 ) {
11699 m_T[i0].m_ei = ei1;
11700 m_E[ei1].m_ti.Append(i0);
11701 }
11702 else if ( ei1 == -1 && ei0 >= 0 ) {
11703 m_T[i1].m_ei = ei0;
11704 m_E[ei0].m_ti.Append(i1);
11705 }
11706 }
11707 }
11708 }
11709 }
11710
11711 return rc;
11712 }
11713
ReadV1_TCODE_LEGACY_CRV(ON_Object ** ppObject,ON_3dmObjectAttributes * pAttributes)11714 bool ON_BinaryArchive::ReadV1_TCODE_LEGACY_CRV(
11715 ON_Object** ppObject,
11716 ON_3dmObjectAttributes* pAttributes
11717 )
11718 {
11719 ON_Curve* curve = NULL;
11720 bool rc = false;
11721 ON__UINT32 tcode = 0;
11722 ON__INT64 big_value = 0;
11723 ON_BOOL32 bHaveMat = false;
11724
11725 Read3dmV1AttributesOrMaterial(pAttributes,NULL,bHaveMat,TCODE_LEGACY_CRVSTUFF);
11726
11727 if ( !BeginRead3dmBigChunk( &tcode, &big_value ) )
11728 return false;
11729 if ( tcode == TCODE_LEGACY_CRVSTUFF )
11730 curve = ReadV1_TCODE_LEGACY_CRVSTUFF(*this);
11731 rc = EndRead3dmChunk();
11732 if ( !curve )
11733 rc = false;
11734 else
11735 *ppObject = curve;
11736 return rc;
11737 }
11738
11739
ReadV1_TCODE_LEGACY_FAC(ON_Object ** ppObject,ON_3dmObjectAttributes * pAttributes)11740 bool ON_BinaryArchive::ReadV1_TCODE_LEGACY_FAC(
11741 ON_Object** ppObject,
11742 ON_3dmObjectAttributes* pAttributes
11743 )
11744 {
11745 // read V1 TCODE_LEGACY_FAC chunk
11746 ON_BOOL32 bHaveMat = false;
11747 if ( !Read3dmV1AttributesOrMaterial(pAttributes,NULL,bHaveMat,TCODE_LEGACY_FACSTUFF) )
11748 return false;
11749 if ( !BeginRead3dmLEGACYSTUFF( *this, TCODE_LEGACY_FACSTUFF ) )
11750 return false;
11751 ON_Brep* brep = new ON_Brep();
11752 bool rc = brep->ReadV1_LegacyFaceStuff( *this );
11753 if ( !EndRead3dmChunk() ) // end of TCODE_LEGACY_FACSTUFF chunk
11754 rc = false;
11755
11756 if ( !rc ) {
11757 delete brep;
11758 }
11759 else {
11760 brep->SetVertices();
11761 brep->SetTrimIsoFlags();
11762 brep->SetTolsFromLegacyValues();
11763 *ppObject = brep;
11764 }
11765
11766 return rc;
11767 }
11768
ReadV1_TCODE_LEGACY_SHL(ON_Object ** ppObject,ON_3dmObjectAttributes * pAttributes)11769 bool ON_BinaryArchive::ReadV1_TCODE_LEGACY_SHL(
11770 ON_Object** ppObject,
11771 ON_3dmObjectAttributes* pAttributes
11772 )
11773 {
11774 // read v1 TCODE_LEGACY_SHL chunk
11775 ON_BOOL32 bHaveMat = false;
11776 if ( !Read3dmV1AttributesOrMaterial(pAttributes,NULL,bHaveMat,TCODE_LEGACY_SHLSTUFF) )
11777 return false;
11778 if ( !BeginRead3dmLEGACYSTUFF( *this, TCODE_LEGACY_SHLSTUFF ) )
11779 return false;
11780 ON_Brep* brep = new ON_Brep();
11781 bool rc = brep->ReadV1_LegacyShellStuff( *this );
11782 if ( !EndRead3dmChunk() ) // end of TCODE_LEGACY_SHLSTUFF chunk
11783 rc = false;
11784
11785 if ( !rc ) {
11786 delete brep;
11787 }
11788 else {
11789 brep->SetVertices();
11790 brep->SetTrimIsoFlags();
11791 brep->SetTolsFromLegacyValues();
11792 *ppObject = brep;
11793 }
11794
11795 return rc;
11796 }
11797
11798
11799 static
ReadV1_RHINOIO_NURBS_CURVE_OBJECT_DATA(ON_BinaryArchive & file)11800 ON_NurbsCurve* ReadV1_RHINOIO_NURBS_CURVE_OBJECT_DATA( ON_BinaryArchive& file )
11801 {
11802 // read TCODE_RHINOIO_OBJECT_DATA chunk that is contained in a
11803 // TCODE_RHINOIO_OBJECT_NURBS_CURVE chunk. The TCODE_RHINOIO_OBJECT_DATA
11804 // chunk contains the definition of NURBS curves written by the
11805 // old RhinoIO toolkit.
11806 ON_NurbsCurve* curve = 0;
11807 ON_BOOL32 rc = false;
11808 ON__UINT32 tcode = 0;
11809 ON__INT64 big_value = 0;
11810 int version, dim, is_rat, order, cv_count, flag, i;
11811 if ( !file.BeginRead3dmBigChunk( &tcode, &big_value ) )
11812 return NULL;
11813 if ( tcode == TCODE_RHINOIO_OBJECT_DATA ) for (;;) {
11814 if ( !file.ReadInt(&version) )
11815 break;
11816 // int bReverse = version & 0x100;
11817 version &= 0xFFFFFEFF;
11818 if ( version != 100 && version != 101 )
11819 break;
11820 file.ReadInt(&dim);
11821 if ( dim < 1 )
11822 break;
11823 file.ReadInt(&is_rat);
11824 if ( is_rat < 0 || is_rat > 1 )
11825 break;
11826 file.ReadInt(&order);
11827 if ( order < 2 )
11828 break;
11829 file.ReadInt(&cv_count);
11830 if ( cv_count < order )
11831 break;
11832 file.ReadInt(&flag);
11833 if ( flag != 0 )
11834 break;
11835
11836 curve = new ON_NurbsCurve(dim,is_rat,order,cv_count);
11837 if ( !file.ReadDouble( order+cv_count-2, curve->m_knot ) )
11838 break;
11839 int cvdim = is_rat ? dim+1 : dim;
11840 for ( i = 0; i < cv_count; i++ ) {
11841 if ( !file.ReadDouble( cvdim, curve->CV(i) ) )
11842 break;
11843 }
11844 if ( i < cv_count )
11845 break;
11846 rc = true;
11847 break;
11848 }
11849 if ( !file.EndRead3dmChunk() ) // end of TCODE_RHINOIO_OBJECT_DATA chunk
11850 rc = false;
11851 if ( !rc && curve ) {
11852 delete curve;
11853 curve = 0;
11854 }
11855
11856 return curve;
11857 }
11858
11859 static
ReadV1_RHINOIO_NURBS_SURFACE_OBJECT_DATA(ON_BinaryArchive & file)11860 ON_NurbsSurface* ReadV1_RHINOIO_NURBS_SURFACE_OBJECT_DATA( ON_BinaryArchive& file )
11861 {
11862 // read TCODE_RHINOIO_OBJECT_DATA chunk that is contained in a
11863 // TCODE_RHINOIO_OBJECT_NURBS_SURFACE chunk. The TCODE_RHINOIO_OBJECT_DATA
11864 // chunk contains the definition of NURBS surfaces written by the
11865 // old RhinoIO toolkit.
11866 bool rc = false;
11867 ON_NurbsSurface* surface = 0;
11868 ON__UINT32 tcode = 0;
11869 ON__INT64 big_value = 0;
11870 int version, dim, is_rat, order[2], cv_count[2], flag, i, j;
11871
11872 if ( !file.BeginRead3dmBigChunk( &tcode, &big_value ) )
11873 return NULL;
11874 if ( tcode == TCODE_RHINOIO_OBJECT_DATA ) for (;;) {
11875 if ( !file.ReadInt(&version) )
11876 break;
11877 // int bReverse = version & 0x100;
11878 version &= 0xFFFFFEFF;
11879 if ( version != 100 && version != 101 )
11880 break;
11881 file.ReadInt(&dim);
11882 if ( dim < 1 )
11883 break;
11884 file.ReadInt(&is_rat);
11885 if ( is_rat < 0 || is_rat > 1 )
11886 break;
11887 file.ReadInt(&order[0]);
11888 if ( order[0] < 2 )
11889 break;
11890 file.ReadInt(&order[1]);
11891 if ( order[1] < 2 )
11892 break;
11893 file.ReadInt(&cv_count[0]);
11894 if ( cv_count[0] < order[0] )
11895 break;
11896 file.ReadInt(&cv_count[1]);
11897 if ( cv_count[1] < order[1] )
11898 break;
11899 file.ReadInt(&flag);
11900 if ( flag != 0 )
11901 break;
11902
11903 surface = new ON_NurbsSurface(dim,is_rat,order[0],order[1],cv_count[0],cv_count[1]);
11904 if ( !file.ReadDouble( order[0]+cv_count[0]-2, surface->m_knot[0] ) )
11905 break;
11906 if ( !file.ReadDouble( order[1]+cv_count[1]-2, surface->m_knot[1] ) )
11907 break;
11908 int cvdim = is_rat ? dim+1 : dim;
11909 for ( i = 0; i < cv_count[0]; i++ ) {
11910 for ( j = 0; j < cv_count[1]; j++ ) {
11911 if ( !file.ReadDouble( cvdim, surface->CV(i,j) ) )
11912 break;
11913 }
11914 if ( j < cv_count[1] )
11915 break;
11916 }
11917 if ( i < cv_count[0] )
11918 break;
11919 rc = true;
11920 break;
11921 }
11922 if ( !file.EndRead3dmChunk() ) // end of TCODE_RHINOIO_OBJECT_DATA
11923 rc = false;
11924 if ( !rc && surface ) {
11925 delete surface;
11926 surface = 0;
11927 }
11928 return surface;
11929 }
11930
ReadV1_TCODE_RHINOIO_OBJECT_NURBS_CURVE(ON_Object ** ppObject,ON_3dmObjectAttributes * pAttributes)11931 bool ON_BinaryArchive::ReadV1_TCODE_RHINOIO_OBJECT_NURBS_CURVE(
11932 ON_Object** ppObject,
11933 ON_3dmObjectAttributes* pAttributes
11934 )
11935 {
11936 // read contents of ReadV1_TCODE_RHINOIO_OBJECT_NURBS_CURVE chunk
11937 // written by v1 RhinoIO toolkit
11938 ON_NurbsCurve* curve = 0;
11939 bool rc = false;
11940 ON_BOOL32 bHaveMat = false;
11941
11942 // reads TCODE_RHINOIO_OBJECT_DATA header and nurbs curve definition
11943 curve = ReadV1_RHINOIO_NURBS_CURVE_OBJECT_DATA(*this);
11944
11945 if ( curve ) {
11946 *ppObject = curve;
11947 rc = true;
11948 Read3dmV1AttributesOrMaterial(pAttributes,NULL,bHaveMat,TCODE_RHINOIO_OBJECT_END);
11949 }
11950
11951 return rc;
11952 }
11953
ReadV1_TCODE_RHINOIO_OBJECT_NURBS_SURFACE(ON_Object ** ppObject,ON_3dmObjectAttributes * pAttributes)11954 bool ON_BinaryArchive::ReadV1_TCODE_RHINOIO_OBJECT_NURBS_SURFACE(
11955 ON_Object** ppObject,
11956 ON_3dmObjectAttributes* pAttributes
11957 )
11958 {
11959 // read contents of TCODE_RHINOIO_OBJECT_NURBS_SURFACE chunk
11960 // written by v1 RhinoIO toolkit
11961 ON_BOOL32 bHaveMat = false;
11962 bool rc = false;
11963 ON_NurbsSurface* surface = 0;
11964
11965 surface = ReadV1_RHINOIO_NURBS_SURFACE_OBJECT_DATA( *this );
11966
11967 if ( surface ) {
11968 *ppObject = surface;
11969 rc = true;
11970 Read3dmV1AttributesOrMaterial(pAttributes,NULL,bHaveMat,TCODE_RHINOIO_OBJECT_END);
11971 }
11972
11973 return rc;
11974 }
11975
11976 static
ReadV1_RHINOIO_BREP_CURVE(ON_BinaryArchive & file)11977 ON_Curve* ReadV1_RHINOIO_BREP_CURVE( ON_BinaryArchive& file )
11978 {
11979 ON_Curve* curve = NULL;
11980 ON_PolyCurve* pcurve = NULL;
11981 ON_NurbsCurve* nurbs_curve = NULL;
11982 int segment_index, segment_count = 0;
11983 ON__UINT32 tcode = 0;
11984 ON__INT64 big_value = 0;
11985
11986 if ( !file.ReadInt(&segment_count) )
11987 return NULL;
11988 if ( segment_count < 1 )
11989 return NULL;
11990
11991 for ( segment_index = 0; segment_index < segment_count; segment_index++ ) {
11992 if ( !file.BeginRead3dmBigChunk(&tcode,&big_value) )
11993 break;
11994 if ( tcode == TCODE_RHINOIO_OBJECT_NURBS_CURVE ) {
11995 nurbs_curve = ReadV1_RHINOIO_NURBS_CURVE_OBJECT_DATA( file );
11996 }
11997 if ( !file.EndRead3dmChunk() )
11998 break;
11999 if ( !nurbs_curve )
12000 break;
12001 if ( segment_index == 0 ) {
12002 curve = nurbs_curve;
12003 nurbs_curve = 0;
12004 }
12005 else {
12006 if ( segment_index == 1 ) {
12007 pcurve = new ON_PolyCurve();
12008 pcurve->Append(curve);
12009 curve = pcurve;
12010 }
12011 pcurve->Append(nurbs_curve);
12012 nurbs_curve = NULL;
12013 }
12014 }
12015
12016 if ( segment_index < segment_count ) {
12017 if ( nurbs_curve ) {
12018 delete nurbs_curve;
12019 nurbs_curve = 0;
12020 }
12021 if ( curve ) {
12022 delete curve;
12023 curve = 0;
12024 }
12025 }
12026 return curve;
12027 }
12028
ReadV1_TCODE_RHINOIO_OBJECT_BREP(ON_Object ** ppObject,ON_3dmObjectAttributes * pAttributes)12029 bool ON_BinaryArchive::ReadV1_TCODE_RHINOIO_OBJECT_BREP(
12030 ON_Object** ppObject,
12031 ON_3dmObjectAttributes* pAttributes
12032 )
12033 {
12034 ON_3dPoint m_oldTrim_mP[2];
12035 ON_BOOL32 bHaveMat = false;
12036 bool rc = false;
12037 ON_Brep* brep = 0;
12038 ON__UINT32 tcode = 0;
12039 ON__INT64 big_value = 0;
12040 if ( !BeginRead3dmBigChunk( &tcode, &big_value ) )
12041 return false;
12042 if ( tcode == TCODE_RHINOIO_OBJECT_DATA ) for (;;) {
12043 int version = -1;
12044 int sz, i, j;
12045 double tol2d, tol3d;
12046 if ( !ReadInt( &version ) )
12047 break; // serialization version
12048 // version = 100 means the b-rep was written by the RhinoIO toolkit
12049 // version = 101 means the b-rep was written by Rhino 1.0
12050 if ( version != 100 && version != 101 ) {
12051 return false;
12052 }
12053
12054 brep = new ON_Brep();
12055
12056 // 2d trimming curves
12057 if ( !ReadInt( &sz ) )
12058 break;
12059 if ( sz < 1 ) {
12060 break;
12061 }
12062 brep->m_C2.Reserve(sz);
12063 for ( i = 0; i < sz; i++ ) {
12064 ON_Curve* curve = ReadV1_RHINOIO_BREP_CURVE( *this );
12065 if ( !curve )
12066 break;
12067 brep->m_C2.Append(curve);
12068 }
12069 if ( i < sz )
12070 break;
12071
12072 // 3d trimming curves
12073 if ( !ReadInt( &sz ) )
12074 break;
12075 if ( sz < 1 ) {
12076 break;
12077 }
12078 brep->m_C3.Reserve(sz);
12079 for ( i = 0; i < sz; i++ ) {
12080 ON_Curve* curve = ReadV1_RHINOIO_BREP_CURVE( *this );
12081 if ( !curve )
12082 break;
12083 brep->m_C3.Append(curve);
12084 }
12085 if ( i < sz )
12086 break;
12087
12088 // 3d untrimmed surfaces
12089 if ( !ReadInt( &sz ) )
12090 break;
12091 if ( sz < 1 ) {
12092 break;
12093 }
12094 brep->m_S.Reserve(sz);
12095 for ( i = 0; i < sz; i++ ) {
12096 ON_NurbsSurface* surface = 0;
12097 tcode = 0;
12098 big_value = 0;
12099 if ( !BeginRead3dmBigChunk(&tcode,&big_value) )
12100 break;
12101 if ( tcode == TCODE_RHINOIO_OBJECT_NURBS_SURFACE ) {
12102 surface = ReadV1_RHINOIO_NURBS_SURFACE_OBJECT_DATA( *this );
12103 }
12104 if ( !EndRead3dmChunk() )
12105 break;
12106 if ( !surface )
12107 break;
12108 brep->m_S.Append(surface);
12109 }
12110 if ( i < sz )
12111 break;
12112
12113 // vertices
12114 ReadInt( &sz );
12115 brep->m_V.Reserve(sz);
12116 for ( i = 0; i < sz; i++ ) {
12117 ON_BrepVertex& vertex = brep->NewVertex();
12118 if ( !ReadInt( &vertex.m_vertex_index ) ) break;
12119 if ( !ReadPoint( vertex.point ) ) break;
12120 if ( !ReadArray( vertex.m_ei ) ) break;
12121 if ( !ReadDouble( &vertex.m_tolerance ) ) break;
12122 }
12123 if ( i < sz )
12124 break;
12125
12126 // edges
12127 ReadInt( &sz );
12128 brep->m_E.Reserve(sz);
12129 for ( i = 0; i < sz; i++ )
12130 {
12131 ON_Interval proxy_domain;
12132 ON_BrepEdge& edge = brep->NewEdge();
12133 if ( !ReadInt( &edge.m_edge_index ) ) break;
12134 if ( !ReadInt( &edge.m_c3i ) ) break;
12135 if ( !ReadInterval( proxy_domain ) ) break;
12136 edge.SetProxyCurveDomain(proxy_domain);
12137 if ( !ReadInt( 2, edge.m_vi ) ) break;
12138 if ( !ReadArray( edge.m_ti ) ) break;
12139 if ( !ReadDouble( &edge.m_tolerance ) ) break;
12140 }
12141 if ( i < sz )
12142 break;
12143
12144 // trims
12145 ReadInt( &sz );
12146 brep->m_T.Reserve(sz);
12147 for ( i = 0; i < sz; i++ ) {
12148 ON_BrepTrim& trim = brep->NewTrim();
12149 if ( !ReadInt( &trim.m_trim_index ) ) break;
12150 if ( !ReadInt( &trim.m_c2i ) ) break;
12151 ON_Interval d;
12152 if ( !ReadInterval( d ) )
12153 break;
12154 trim.SetProxyCurve(NULL,d);
12155 if ( !ReadInt( &trim.m_ei ) ) break;
12156 if ( !ReadInt( 2, trim.m_vi ) ) break;
12157 j = trim.m_bRev3d;
12158 if ( !ReadInt( &j ) ) break;
12159 trim.m_bRev3d = (j!=0);
12160 if ( !ReadInt( &j ) ) break;
12161 switch(j) {
12162 case 1: trim.m_type = ON_BrepTrim::boundary; break;
12163 case 2: trim.m_type = ON_BrepTrim::mated; break;
12164 case 3: trim.m_type = ON_BrepTrim::seam; break;
12165 case 4: trim.m_type = ON_BrepTrim::singular; break;
12166 }
12167 if ( !ReadInt( &j ) ) break; // legacy iso flag - ignore and recaluate
12168 if ( !ReadInt( &trim.m_li ) ) break;
12169 if ( !ReadDouble( 2, trim.m_tolerance ) ) break;
12170 if ( !ReadPoint( m_oldTrim_mP[0] ) ) break;
12171 if ( !ReadPoint( m_oldTrim_mP[1] ) ) break;
12172 if ( !ReadDouble( &tol2d ) ) break;
12173 if ( !ReadDouble( &tol3d ) ) break;
12174 }
12175 if ( i < sz )
12176 break;
12177
12178 // loops
12179 ReadInt( &sz );
12180 brep->m_L.Reserve(sz);
12181 for ( i = 0; i < sz; i++ ) {
12182 ON_BrepLoop& loop = brep->NewLoop(ON_BrepLoop::unknown);
12183 if ( !ReadInt( &loop.m_loop_index ) ) break;
12184 if ( !ReadArray( loop.m_ti ) ) break;
12185 if ( !ReadInt( &j ) ) break;
12186 switch (j) {
12187 case 1: loop.m_type = ON_BrepLoop::outer; break;
12188 case 2: loop.m_type = ON_BrepLoop::inner; break;
12189 case 3: loop.m_type = ON_BrepLoop::slit; break;
12190 }
12191 if ( !ReadInt( &loop.m_fi ) ) break;
12192 }
12193 if ( i < sz )
12194 break;
12195
12196 // faces
12197 ReadInt( &sz );
12198 brep->m_F.Reserve(sz);
12199 for ( i = 0; i < sz; i++ ) {
12200 ON_BrepFace& face = brep->NewFace();
12201 if ( !ReadInt( &face.m_face_index ) ) break;
12202 if ( !ReadArray( face.m_li ) ) break;
12203 if ( !ReadInt( &face.m_si ) ) break;
12204 int k = face.m_bRev;
12205 if ( !ReadInt( &k ) ) break;
12206 face.m_bRev = (k!=0);
12207 }
12208 if ( i < sz )
12209 break;
12210
12211 // bounding box
12212 {
12213 ON_BoundingBox bbox;
12214 if ( !ReadPoint( bbox.m_min ) ) break;
12215 if ( !ReadPoint( bbox.m_max ) ) break;
12216 }
12217
12218 rc = true;
12219 break;
12220 }
12221 if ( !EndRead3dmChunk() )
12222 rc = false;
12223 if ( rc && brep ) {
12224 brep->SetTrimIsoFlags();
12225 *ppObject = brep;
12226 }
12227 else {
12228 if ( brep )
12229 delete brep;
12230 rc = false;
12231 }
12232
12233 if ( rc && brep ) {
12234 Read3dmV1AttributesOrMaterial(pAttributes,NULL,bHaveMat,TCODE_RHINOIO_OBJECT_END);
12235 }
12236
12237 return rc;
12238 }
12239
12240 int
Read3dmV1Object(ON_Object ** ppObject,ON_3dmObjectAttributes * pAttributes,unsigned int object_filter)12241 ON_BinaryArchive::Read3dmV1Object(
12242 ON_Object** ppObject, // object is returned here
12243 ON_3dmObjectAttributes* pAttributes, // optional - object attributes
12244 unsigned int object_filter // optional filter made by or-ing object_type bits
12245 )
12246 {
12247 int rc = 0;
12248 // returns -1: failure
12249 // 0: end of geometry table
12250 // 1: success
12251 // 2: skipped filtered objects
12252
12253 ON__UINT32 tcode = 0;
12254 ON__INT64 big_value = 0;
12255 // reads NURBS, point, and mesh objects
12256 for(;;)
12257 {
12258 tcode = 0;
12259 big_value = 0;
12260 if ( !BeginRead3dmBigChunk(&tcode,&big_value) ) {
12261 rc = 0; // at the end of the file
12262 break;
12263 }
12264 switch(tcode)
12265 {
12266
12267 case TCODE_TEXT_BLOCK:
12268 case TCODE_ANNOTATION_LEADER:
12269 case TCODE_LINEAR_DIMENSION:
12270 case TCODE_ANGULAR_DIMENSION:
12271 case TCODE_RADIAL_DIMENSION:
12272 if ( 0 != (ON::annotation_object & object_filter) )
12273 {
12274 if ( ReadV1_TCODE_ANNOTATION( tcode, ppObject, pAttributes ) )
12275 rc = 1;
12276 else
12277 rc = -1;
12278 }
12279 else
12280 {
12281 rc = 2;
12282 }
12283 break;
12284
12285 case TCODE_RH_POINT:
12286 // v1 3d point
12287 if ( 0 != (ON::point_object & object_filter) ) {
12288 if (ReadV1_TCODE_RH_POINT( ppObject, pAttributes ))
12289 rc = 1;
12290 else
12291 rc = -1;
12292 }
12293 else {
12294 rc = 2;
12295 }
12296 break;
12297
12298 case TCODE_MESH_OBJECT:
12299 // v1 mesh
12300 if ( 0 != (ON::mesh_object & object_filter) ) {
12301 if ( ReadV1_TCODE_MESH_OBJECT( ppObject, pAttributes ) )
12302 rc = 1;
12303 else
12304 rc = -1;
12305 }
12306 else {
12307 rc = 2;
12308 }
12309 break;
12310
12311 case TCODE_LEGACY_SHL:
12312 // v1 polysurface
12313 if ( 0 != (ON::mesh_object & object_filter) ) {
12314 if ( ReadV1_TCODE_LEGACY_SHL( ppObject, pAttributes ) )
12315 rc = 1;
12316 else
12317 rc = -1;
12318 }
12319 else {
12320 rc = 2;
12321 }
12322 break;
12323
12324 case TCODE_LEGACY_FAC:
12325 // v1 trimmed surface
12326 if ( 0 != (ON::mesh_object & object_filter) ) {
12327 if ( ReadV1_TCODE_LEGACY_FAC( ppObject, pAttributes ) )
12328 rc = 1;
12329 else
12330 rc = -1;
12331 }
12332 else {
12333 rc = 2;
12334 }
12335 break;
12336
12337 case TCODE_LEGACY_CRV:
12338 // v1 curve
12339 if ( 0 != (ON::mesh_object & object_filter) ) {
12340 if ( ReadV1_TCODE_LEGACY_CRV( ppObject, pAttributes ) )
12341 rc = 1;
12342 else
12343 rc = -1;
12344 }
12345 else {
12346 rc = 2;
12347 }
12348 break;
12349
12350 case TCODE_RHINOIO_OBJECT_NURBS_CURVE:
12351 // old Rhino I/O toolkit nurbs curve
12352 if ( 0 != (ON::mesh_object & object_filter) ) {
12353 if ( ReadV1_TCODE_RHINOIO_OBJECT_NURBS_CURVE( ppObject, pAttributes ) )
12354 rc = 1;
12355 else
12356 rc = -1;
12357 }
12358 else {
12359 rc = 2;
12360 }
12361 break;
12362
12363 case TCODE_RHINOIO_OBJECT_NURBS_SURFACE:
12364 // old Rhino I/O toolkit nurbs surface
12365 if ( 0 != (ON::mesh_object & object_filter) ) {
12366 if ( ReadV1_TCODE_RHINOIO_OBJECT_NURBS_SURFACE( ppObject, pAttributes ) )
12367 rc = 1;
12368 else
12369 rc = -1;
12370 }
12371 else {
12372 rc = 2;
12373 }
12374 break;
12375
12376 case TCODE_RHINOIO_OBJECT_BREP:
12377 // old Rhino I/O toolkit nurbs brep
12378 if ( 0 != (ON::mesh_object & object_filter) ) {
12379 if ( ReadV1_TCODE_RHINOIO_OBJECT_BREP( ppObject, pAttributes ) )
12380 rc = 1;
12381 else
12382 rc = -1;
12383 }
12384 else {
12385 rc = 2;
12386 }
12387 break;
12388 }
12389
12390 if (!EndRead3dmChunk() )
12391 break;
12392 if ( rc == 1 || rc == -1 )
12393 break;
12394 }
12395
12396 return rc;
12397 }
12398
12399 #if 1
12400 class ON_OBSOLETE_CCustomMeshUserData : public ON_UserData
12401 {
12402 public:
12403 ON_OBJECT_DECLARE(ON_OBSOLETE_CCustomMeshUserData);
12404 ON_OBSOLETE_CCustomMeshUserData();
12405 ~ON_OBSOLETE_CCustomMeshUserData();
12406 ON_BOOL32 GetDescription( ON_wString& );
12407 ON_BOOL32 Read(ON_BinaryArchive& binary_archive);
12408 bool m_bInUse;
12409 ON_MeshParameters m_mp;
12410 };
12411
12412 ON_OBJECT_IMPLEMENT(ON_OBSOLETE_CCustomMeshUserData, ON_UserData, "69F27695-3011-4FBA-82C1-E529F25B5FD9");
12413
ON_OBSOLETE_CCustomMeshUserData()12414 ON_OBSOLETE_CCustomMeshUserData::ON_OBSOLETE_CCustomMeshUserData()
12415 {
12416 m_userdata_copycount = 0;
12417 m_userdata_uuid = ON_OBSOLETE_CCustomMeshUserData::m_ON_OBSOLETE_CCustomMeshUserData_class_id.Uuid();
12418 m_application_uuid = ON_nil_uuid;
12419 m_bInUse = false;
12420 }
12421
~ON_OBSOLETE_CCustomMeshUserData()12422 ON_OBSOLETE_CCustomMeshUserData::~ON_OBSOLETE_CCustomMeshUserData()
12423 {
12424 }
12425
Read(ON_BinaryArchive & ba)12426 ON_BOOL32 ON_OBSOLETE_CCustomMeshUserData::Read(ON_BinaryArchive& ba)
12427 {
12428 int i = 0;
12429 if ( !ba.ReadInt( &i ) )
12430 return false;
12431 if( !ba.ReadBool( &m_bInUse ) )
12432 return false;
12433 return m_mp.Read( ba );
12434 }
12435
GetDescription(ON_wString & s)12436 ON_BOOL32 ON_OBSOLETE_CCustomMeshUserData::GetDescription( ON_wString& s )
12437 {
12438 s = "OBSOLETE CustomMeshUserData";
12439 return true;
12440 }
12441 #endif
12442
12443
12444 int
Read3dmObject(ON_Object ** ppObject,ON_3dmObjectAttributes * pAttributes,unsigned int object_filter)12445 ON_BinaryArchive::Read3dmObject(
12446 ON_Object** ppObject, // object is returned here
12447 ON_3dmObjectAttributes* pAttributes, // optional - object attributes
12448 unsigned int object_filter // optional filter made by or-ing object_type bits
12449 )
12450 {
12451 // returns -1: failure
12452 // 0: end of geometry table
12453 // 1: success
12454 // 2: skipped filtered objects
12455 // 3: skipped new object (object's class UUID wasn't found in class list)
12456 ON_BOOL32 rc = -1;
12457 if ( pAttributes )
12458 pAttributes->Default();
12459 if ( !ppObject )
12460 return 0;
12461 *ppObject = 0;
12462 if ( !object_filter ) // default filter (0) reads every object
12463 object_filter = 0xFFFFFFFF;
12464
12465 if ( m_3dm_version == 1 ) {
12466 rc = Read3dmV1Object(ppObject,pAttributes,object_filter);
12467 }
12468 else
12469 {
12470 ON__UINT32 tcode = 0;
12471 ON__INT64 length_TCODE_OBJECT_RECORD = 0;
12472 ON__INT64 value_TCODE_OBJECT_RECORD_TYPE = 0;
12473 ON__INT64 length_TCODE_OBJECT_RECORD_ATTRIBUTES = 0;
12474 if ( BeginRead3dmBigChunk( &tcode, &length_TCODE_OBJECT_RECORD ) )
12475 {
12476 if ( tcode == TCODE_OBJECT_RECORD )
12477 {
12478 if (BeginRead3dmBigChunk( &tcode, &value_TCODE_OBJECT_RECORD_TYPE ))
12479 {
12480 if ( tcode != TCODE_OBJECT_RECORD_TYPE ) {
12481 rc = -1;
12482 ON_ERROR("ON_BinaryArchive::Read3dmObject() - missing TCODE_OBJECT_RECORD_TYPE chunk.");
12483 }
12484 else if ( 0 != value_TCODE_OBJECT_RECORD_TYPE && 0 == (value_TCODE_OBJECT_RECORD_TYPE | object_filter) )
12485 rc = 2; // skip reading this object
12486 else
12487 rc = 1; // need to read this object
12488
12489 if ( !EndRead3dmChunk() )
12490 rc = -1;
12491
12492 switch(ReadObject(ppObject))
12493 {
12494 case 1:
12495 rc = 1; // successfully read this object
12496 break;
12497 case 3:
12498 rc = 3; // skipped object - assume it's just a newer object than this code reads
12499 break;
12500 default:
12501 rc = -1; // serious failure
12502 break;
12503 }
12504 }
12505 else
12506 rc = -1;
12507 }
12508 else if ( tcode != TCODE_ENDOFTABLE ) {
12509 ON_ERROR("ON_BinaryArchive::Read3dmObject() - corrupt object table");
12510 rc = -1;
12511 }
12512 else
12513 rc = 0;
12514
12515 while(rc==1)
12516 {
12517 tcode = 0;
12518 if (!BeginRead3dmBigChunk( &tcode, &length_TCODE_OBJECT_RECORD_ATTRIBUTES )) {
12519 rc = -1;
12520 break;
12521 }
12522 if ( tcode == TCODE_OBJECT_RECORD_ATTRIBUTES )
12523 {
12524 if ( 0 != pAttributes )
12525 {
12526 if ( !pAttributes->Read( *this ) )
12527 rc = -1;
12528 }
12529 }
12530 else if ( tcode == TCODE_OBJECT_RECORD_ATTRIBUTES_USERDATA )
12531 {
12532 if ( 0 != pAttributes )
12533 {
12534 // 19 October 2004
12535 // Added support for saving user data on object attributes
12536 if ( !ReadObjectUserData(*pAttributes))
12537 rc = -1;
12538 else
12539 {
12540 #if 1
12541 // 3 March 2011 - convert obsolete user data
12542 ON_OBSOLETE_CCustomMeshUserData* ud = ON_OBSOLETE_CCustomMeshUserData::Cast(pAttributes->GetUserData(ON_OBSOLETE_CCustomMeshUserData::m_ON_OBSOLETE_CCustomMeshUserData_class_id.Uuid()));
12543 if ( ud )
12544 {
12545 ud->m_mp.m_bCustomSettingsEnabled = ud->m_bInUse ? true : false;
12546 pAttributes->SetCustomRenderMeshParameters(ud->m_mp);
12547 delete ud;
12548 }
12549 #endif
12550 }
12551 }
12552 }
12553
12554 if ( !EndRead3dmChunk() )
12555 {
12556 rc = -1;
12557 }
12558 if ( tcode == TCODE_OBJECT_RECORD_END )
12559 break;
12560 }
12561
12562 if ( !EndRead3dmChunk() )
12563 rc = -1;
12564 }
12565 }
12566
12567 return rc;
12568 }
12569
EndRead3dmObjectTable()12570 bool ON_BinaryArchive::EndRead3dmObjectTable()
12571 {
12572 bool rc = EndRead3dmTable( TCODE_OBJECT_TABLE );
12573
12574 if ( 0 != m_V1_layer_list )
12575 {
12576 struct ON__3dmV1LayerIndex* next = m_V1_layer_list;
12577 m_V1_layer_list = 0;
12578 for ( int i = 0; 0 != next && i < 1000; i++ )
12579 {
12580 struct ON__3dmV1LayerIndex* p = next;
12581 next = p->m_next;
12582 onfree(p);
12583 }
12584 }
12585
12586 return rc;
12587 }
12588
BeginWrite3dmUserTable(const ON_UUID & usertable_uuid)12589 bool ON_BinaryArchive::BeginWrite3dmUserTable( const ON_UUID& usertable_uuid )
12590 {
12591 return BeginWrite3dmUserTable(usertable_uuid, false, 0, 0 );
12592 }
12593
BeginWrite3dmUserTable(const ON_UUID & plugin_id,bool bSavingGoo,int goo_3dm_version,int goo_opennurbs_version)12594 bool ON_BinaryArchive::BeginWrite3dmUserTable(
12595 const ON_UUID& plugin_id,
12596 bool bSavingGoo,
12597 int goo_3dm_version,
12598 int goo_opennurbs_version
12599 )
12600 {
12601 if ( m_active_table != no_active_table ) {
12602 ON_ERROR("ON_BinaryArchive::BeginWrite3dmUserTable() - m_active_table != no_active_table");
12603 }
12604 if ( !ON_UuidCompare( &ON_nil_uuid, &plugin_id ) ) {
12605 ON_ERROR("ON_BinaryArchive::BeginWrite3dmUserTable() - nil usertable_uuid not permitted.");
12606 return false;
12607 }
12608 if ( bSavingGoo )
12609 {
12610 if ( goo_3dm_version <= 3 )
12611 return false;
12612 if ( goo_opennurbs_version < 200601010 )
12613 return false;
12614 if ( goo_3dm_version >= 50 && Archive3dmVersion() < 50 )
12615 {
12616 // goo with 8 byte chunk lengths cannot be saved
12617 // in files expecting 4 byte chunk lengths.
12618 return false;
12619 }
12620 }
12621 else
12622 {
12623 goo_3dm_version = Archive3dmVersion();
12624 goo_opennurbs_version = ArchiveOpenNURBSVersion();
12625 }
12626
12627 bool rc = BeginWrite3dmTable( TCODE_USER_TABLE);
12628 if (rc) {
12629 rc = BeginWrite3dmChunk( TCODE_USER_TABLE_UUID, 0 );
12630 if (rc)
12631 {
12632 rc = WriteUuid( plugin_id );
12633 if (rc)
12634 {
12635 // The TCODE_USER_TABLE_RECORD_HEADER chunk was added in
12636 // version 200910190 to contain the archive and opennurbs
12637 // version the plug-in used when writing the file.
12638 // This information is needed so "goo" can be correctly
12639 // read.
12640 rc = BeginWrite3dmChunk( TCODE_USER_TABLE_RECORD_HEADER, 1, 0 );
12641 if ( rc )
12642 {
12643 if (rc) rc = WriteBool(bSavingGoo);
12644 if (rc) rc = WriteInt(goo_3dm_version);
12645 if (rc) rc = WriteInt(goo_opennurbs_version);
12646 if ( !EndWrite3dmChunk() )
12647 rc = false;
12648 }
12649 }
12650 if ( !EndWrite3dmChunk() )
12651 rc = false;
12652 }
12653 if (rc) {
12654 rc = BeginWrite3dmChunk( TCODE_USER_RECORD, 0 );
12655 }
12656 if ( !rc ) {
12657 EndWrite3dmTable( TCODE_USER_TABLE);
12658 }
12659 }
12660 return rc;
12661 }
12662
Write3dmAnonymousUserTableRecord(const ON_UUID & plugin_id,int goo_3dm_version,int goo_opennurbs_version,const ON_3dmGoo & goo)12663 bool ON_BinaryArchive::Write3dmAnonymousUserTableRecord(
12664 const ON_UUID& plugin_id,
12665 int goo_3dm_version,
12666 int goo_opennurbs_version,
12667 const ON_3dmGoo& goo
12668 )
12669 {
12670 if ( ON_UuidIsNil(plugin_id) )
12671 return false;
12672 if ( goo_3dm_version <= 3 )
12673 return false;
12674 if (goo_opennurbs_version < 200000000 )
12675 return false;
12676 if ( goo.m_typecode != TCODE_USER_RECORD )
12677 return false;
12678 if ( 0 == goo.m_value )
12679 return false;
12680 if ( 0 == goo.m_goo )
12681 return false;
12682 bool bSavingGoo = true;
12683 if ( !BeginWrite3dmUserTable( plugin_id, bSavingGoo, goo_3dm_version, goo_opennurbs_version ) )
12684 return false;
12685 bool rc = WriteByte( goo.m_value, goo.m_goo );
12686 if ( !EndWrite3dmUserTable() )
12687 rc = false;
12688 return rc;
12689 }
12690
12691
Write3dmAnonymousUserTable(const ON_3dmGoo & goo)12692 bool ON_BinaryArchive::Write3dmAnonymousUserTable( const ON_3dmGoo& goo )
12693 {
12694 bool rc = false;
12695 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
12696 if ( !c || c->m_typecode != TCODE_USER_RECORD ) {
12697 ON_ERROR("ON_BinaryArchive::Write3dmAnonymousUserTable() - active chunk not a TCODE_USER_RECORD.");
12698 rc = false;
12699 }
12700 else if ( goo.m_typecode != TCODE_USER_RECORD ) {
12701 ON_ERROR("ON_BinaryArchive::Write3dmAnonymousUserTable() - goo chunk not a TCODE_USER_RECORD.");
12702 rc = false;
12703 }
12704 else {
12705 rc = ( goo.m_value > 0 ) ? WriteByte( goo.m_value, goo.m_goo ) : true;
12706 }
12707 return rc;
12708 }
12709
12710
EndWrite3dmUserTable()12711 bool ON_BinaryArchive::EndWrite3dmUserTable()
12712 {
12713 bool rc = false;
12714 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
12715 if ( c && c->m_typecode == TCODE_USER_RECORD ) {
12716 rc = EndWrite3dmChunk();
12717 }
12718 else {
12719 ON_ERROR("ON_BinaryArchive::EndWrite3dmUserTable() - not in a TCODE_USER_RECORD chunk.");
12720 rc = false;
12721 }
12722 if ( !EndWrite3dmTable(TCODE_USER_TABLE) )
12723 rc = false;
12724 return rc;
12725 }
12726
BeginRead3dmUserTable(ON_UUID & usertable_uuid)12727 bool ON_BinaryArchive::BeginRead3dmUserTable( ON_UUID& usertable_uuid )
12728 {
12729 // OBSOLETE - use the BeginRead3dmUserTable() with more arguments
12730 bool bGoo = false;
12731 int archive_3dm_version = 0;
12732 int archive_opennurbs_version = 0;
12733 bool rc = BeginRead3dmUserTable( usertable_uuid, &bGoo, &archive_3dm_version, &archive_opennurbs_version );
12734 return rc;
12735 }
12736
BeginRead3dmUserTable(ON_UUID & plugin_id,bool * bLastSavedAsGoo,int * archive_3dm_version,int * archive_opennurbs_version)12737 bool ON_BinaryArchive::BeginRead3dmUserTable(
12738 ON_UUID& plugin_id,
12739 bool* bLastSavedAsGoo,
12740 int* archive_3dm_version,
12741 int* archive_opennurbs_version
12742 )
12743 {
12744 bool bReadArchiveInfo = false;
12745 if ( bLastSavedAsGoo )
12746 *bLastSavedAsGoo = false;
12747 if ( archive_3dm_version )
12748 *archive_3dm_version = 0;
12749 if ( archive_opennurbs_version )
12750 *archive_opennurbs_version = 0;
12751
12752 if ( m_3dm_version == 1 )
12753 return false;
12754
12755 bool rc = BeginRead3dmTable( TCODE_USER_TABLE );
12756
12757 // Do not add calls to EmergencyFindTable() here.
12758 // BeginRead3dmTable( TCODE_USER_TABLE ) returns
12759 // false when there are no user tables and that
12760 // is a common situation.
12761
12762 if ( rc )
12763 {
12764 // read table id
12765 ON__UINT32 tcode = 0;
12766 ON__INT64 big_value = 0;
12767 if (rc) rc = BeginRead3dmBigChunk( &tcode, &big_value );
12768 if (rc)
12769 {
12770 if ( tcode != TCODE_USER_TABLE_UUID )
12771 {
12772 ON_ERROR("ON_BinaryArchive::BeginRead3dmUserTable() - missing user table UUID");
12773 rc = false;
12774 }
12775 else
12776 {
12777 rc = ReadUuid( plugin_id );
12778
12779 // Version 200910190 of OpenNURBS began writing a TCODE_USER_TABLE_RECORD_HEADER
12780 // section immediately after the uuid. This was possible because the uuid
12781 // was wrapped in a TCODE_USER_TABLE_UUID chunk. The TCODE_USER_TABLE_RECORD_HEADER
12782 // contains information that let's us determine what version of Rhino and
12783 // opennurbs wrote the user table. We need to know this because "goo"
12784 // can have chunks with 4 byte lengths embedded in a file with 8 byte
12785 // chunk lengths. If this information is missing, then we know the "goo"
12786 // must have 4 byte chunk lengths and we assume it is from a V4 file.
12787 //
12788 // 37 + SizeofChunkLength() =
12789 // 16 bytes of uuid
12790 // + 4 bytes of TCODE_USER_TABLE_RECORD_HEADER typecode
12791 // + SizeofChunkLength() TCODE_USER_TABLE_RECORD_HEADER chunk length
12792 // + 1 byte of bSlastSavedAsGoo bool
12793 // + 4 bytes of archive_3dm_version
12794 // + 4 bytes of archive_opennurbs_version
12795 // + 4 bytes of TCODE_USER_TABLE_RECORD_HEADER chunk crc
12796 // + 4 bytes of TCODE_USER_TABLE_UUID chunk crc
12797 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
12798 if ( rc
12799 && ArchiveOpenNURBSVersion() >= 200910190
12800 && 0 != c
12801 && TCODE_USER_TABLE_UUID == c->m_typecode
12802 && c->Length() >= 45 + SizeofChunkLength()
12803 )
12804 {
12805 int major_chunk_version = 0;
12806 int minor_chunk_version = 0;
12807 rc = BeginRead3dmChunk(TCODE_USER_TABLE_RECORD_HEADER,&major_chunk_version,&minor_chunk_version);
12808 if (rc)
12809 {
12810 bReadArchiveInfo = true;
12811 bool b = true;
12812 int arch_ver = 0;
12813 int on_ver = 0;
12814 rc = ReadBool(&b);
12815 if ( rc && bLastSavedAsGoo )
12816 *bLastSavedAsGoo = b;
12817 if (rc)
12818 rc = ReadInt(&arch_ver);
12819 if (rc && archive_3dm_version)
12820 *archive_3dm_version = arch_ver;
12821 if (rc)
12822 rc = ReadInt(&on_ver);
12823 if (rc && archive_opennurbs_version)
12824 *archive_opennurbs_version = on_ver;
12825 if ( !EndRead3dmChunk() )
12826 rc = false;
12827 }
12828 }
12829 }
12830 if ( !EndRead3dmChunk() )
12831 rc = false;
12832 }
12833
12834 tcode = 0;
12835 big_value = 0;
12836 if (rc) rc = BeginRead3dmBigChunk( &tcode, &big_value );
12837 if (rc) {
12838 if ( tcode != TCODE_USER_RECORD ) {
12839 ON_ERROR("ON_BinaryArchive::BeginRead3dmUserTable() - missing user table TCODE_USER_RECORD chunk.");
12840 EndRead3dmChunk();
12841 rc = false;
12842 }
12843 }
12844
12845 if (!rc)
12846 EndRead3dmTable(TCODE_USER_TABLE);
12847
12848 if ( rc && !bReadArchiveInfo )
12849 {
12850 // If the file we are reading is V4 or an early V5 file, then use the
12851 // version numbers from the file. Otherwise, assume the goo is from
12852 // an early V5 file. All we know for sure is that the chunk lengths
12853 // in the user table are 4 bytes.
12854 if ( Archive3dmVersion() < 50 )
12855 {
12856 if (archive_3dm_version)
12857 *archive_3dm_version = Archive3dmVersion();
12858 if (archive_opennurbs_version)
12859 *archive_opennurbs_version = ArchiveOpenNURBSVersion();
12860 }
12861 else
12862 {
12863 if (archive_3dm_version)
12864 *archive_3dm_version = 5;
12865 if (archive_opennurbs_version)
12866 *archive_opennurbs_version = 200910180;
12867 }
12868 }
12869 }
12870
12871
12872 return rc;
12873 }
12874
Read3dmAnonymousUserTable(ON_3dmGoo & goo)12875 bool ON_BinaryArchive::Read3dmAnonymousUserTable( ON_3dmGoo& goo )
12876 {
12877 return Read3dmAnonymousUserTable(0,0,goo);
12878 }
12879
Read3dmAnonymousUserTable(int archive_3dm_version,int archive_opennurbs_version,ON_3dmGoo & goo)12880 bool ON_BinaryArchive::Read3dmAnonymousUserTable(
12881 int archive_3dm_version,
12882 int archive_opennurbs_version,
12883 ON_3dmGoo& goo
12884 )
12885 {
12886 if ( 0 == archive_3dm_version )
12887 {
12888 if ( Archive3dmVersion() < 50 )
12889 {
12890 archive_3dm_version = Archive3dmVersion();
12891 archive_opennurbs_version = ArchiveOpenNURBSVersion();
12892 }
12893 else
12894 {
12895 // recent version with 4 byte chunk lengths.
12896 archive_3dm_version = 5;
12897 archive_opennurbs_version = 200910190;
12898 }
12899 }
12900 bool rc = Read3dmGoo( goo );
12901 if (rc && goo.m_typecode != TCODE_USER_RECORD ) {
12902 ON_ERROR("ON_BinaryArchive::Read3dmAnonymousUserTable() do not read a TCODE_USER_RECORD chunk.");
12903 rc = false;
12904 }
12905 return rc;
12906 }
12907
EndRead3dmUserTable()12908 bool ON_BinaryArchive::EndRead3dmUserTable()
12909 {
12910 if ( m_chunk.Count() != 2 ) {
12911 ON_ERROR("ON_BinaryArchive::EndRead3dmUserTable() m_chunk.Count() != 2");
12912 return false;
12913 }
12914 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
12915 if ( 0 == c || c->m_typecode != TCODE_USER_RECORD ) {
12916 ON_ERROR("ON_BinaryArchive::EndRead3dmTable() m_chunk.Last()->typecode != TCODE_USER_RECORD");
12917 return false;
12918 }
12919
12920
12921 // end of TCODE_USER_RECORD chunk
12922 // Suppress the partially read chunk warning because plug-in IO
12923 // is too upredictable for this warning to be helpful.
12924 bool rc = EndRead3dmChunk(true);
12925
12926 if (rc) {
12927 // end of table chunk
12928 unsigned int tcode = 0;
12929 ON__INT64 big_value = -1;
12930 rc = BeginRead3dmBigChunk( &tcode, &big_value );
12931 if ( rc ) {
12932 if ( tcode != TCODE_ENDOFTABLE ) {
12933 ON_ERROR("ON_BinaryArchive::EndRead3dmTable() missing TCODE_ENDOFTABLE marker.");
12934 }
12935 if ( !EndRead3dmChunk() )
12936 rc = false;
12937 }
12938 }
12939
12940 if ( !EndRead3dmTable(TCODE_USER_TABLE) )
12941 rc = false;
12942 return rc;
12943 }
12944
Write3dmEndMark()12945 bool ON_BinaryArchive::Write3dmEndMark()
12946 {
12947 Flush();
12948 if ( m_chunk.Count() != 0 ) {
12949 ON_ERROR( "ON_BinaryArchive::WriteEndMark() called with unfinished chunks.\n" );
12950 return false;
12951 }
12952 ON__UINT64 length = CurrentPosition(); // since no chunks are unfinished, everything
12953 // has been committed to disk in either
12954 // write mode.
12955 bool rc = BeginWrite3dmChunk( TCODE_ENDOFFILE, 0 );
12956 if ( rc )
12957 {
12958 size_t sizeof_chunk_length = SizeofChunkLength();
12959 size_t sizeoffile_length = (8==SizeofChunkLength()) ? 8 : 4;
12960 length += (4 + sizeof_chunk_length + sizeoffile_length );
12961 rc = WriteEOFSizeOfFile(length);
12962 if ( !EndWrite3dmChunk() )
12963 rc = false;
12964 }
12965 Flush();
12966
12967 return rc;
12968 }
12969
Read3dmEndMark(size_t * file_length)12970 bool ON_BinaryArchive::Read3dmEndMark( size_t* file_length )
12971 {
12972 unsigned int tcode=0;
12973 ON__INT64 value=0;
12974 if ( file_length )
12975 *file_length = 0;
12976
12977 const unsigned int saved_error_message_mask = m_error_message_mask;
12978 m_error_message_mask |= 0x0001; // disable v1 ReadByte() error message at EOF
12979 bool rc = PeekAt3dmBigChunkType(&tcode,&value);
12980 m_error_message_mask = saved_error_message_mask;
12981
12982 if (rc)
12983 {
12984 if ( tcode == TCODE_ENDOFFILE )
12985 {
12986 rc = BeginRead3dmBigChunk(&tcode,&value);
12987 if ( rc && value > 0 && ((ON__UINT64)value) >= SizeofChunkLength() )
12988 {
12989 ON__UINT64 u64 = 0;
12990 rc = ReadEOFSizeOfFile( &u64 );
12991 if ( rc && file_length )
12992 *file_length = (size_t)u64;
12993 if ( !EndRead3dmChunk() )
12994 rc = false;
12995 }
12996 }
12997 }
12998 return rc;
12999 }
13000
13001 ///////////////////////////////////////////////////////////////////////////////
13002 ///////////////////////////////////////////////////////////////////////////////
13003 ///////////////////////////////////////////////////////////////////////////////
13004
13005 ON::endian
Endian() const13006 ON_BinaryArchive::Endian() const // endian-ness of cpu
13007 {
13008 return m_endian;
13009 }
13010
13011 ON::archive_mode
Mode() const13012 ON_BinaryArchive::Mode() const
13013 {
13014 return m_mode;
13015 }
13016
UpdateCRC(size_t count,const void * p)13017 void ON_BinaryArchive::UpdateCRC( size_t count, const void* p )
13018 {
13019 if ( m_bDoChunkCRC ) {
13020 ON_3DM_BIG_CHUNK* c = m_chunk.Last();
13021 if (c) {
13022 if ( c->m_do_crc16 )
13023 c->m_crc16 = ON_CRC16( c->m_crc16, count, p ); // version 1 files had 16 bit CRC
13024 if ( c->m_do_crc32 )
13025 c->m_crc32 = ON_CRC32( c->m_crc32, count, p ); // version 2 files have 32 bit CRC
13026 }
13027 }
13028 }
13029
BadCRCCount() const13030 int ON_BinaryArchive::BadCRCCount() const
13031 {
13032 return m_bad_CRC_count;
13033 }
13034
ErrorMessageMask() const13035 unsigned int ON_BinaryArchive::ErrorMessageMask() const
13036 {
13037 return m_error_message_mask;
13038 }
13039
MaskReadError(ON__UINT64 sizeof_request,ON__UINT64 sizeof_read) const13040 bool ON_BinaryArchive::MaskReadError( ON__UINT64 sizeof_request, ON__UINT64 sizeof_read ) const
13041 {
13042 if ( sizeof_request == sizeof_read )
13043 return true; // no error
13044 if ( sizeof_request > sizeof_read )
13045 return false; // something is seriously wrong
13046 if ( 0 != (0x04 & m_error_message_mask) )
13047 return true;
13048 if ( 0 != (0x01 & m_error_message_mask) && 4 == sizeof_request && 0 == sizeof_read )
13049 return true;
13050 return false; // parial read not permitted at this time.
13051 }
13052
ReadBuffer(ON__UINT64 sizeof_buffer,void * buffer)13053 ON__UINT64 ON_BinaryArchive::ReadBuffer( ON__UINT64 sizeof_buffer, void* buffer )
13054 {
13055 // Expert user function to load a buffer with up to sizeof_buffer
13056 // bytes but tolerate encountering the end of the file.
13057 if ( 0 == buffer )
13058 return 0;
13059 unsigned int saved_error_mask = m_error_message_mask;
13060 m_error_message_mask |= 0x04; // tell Read to tolerate hitting the end of the file
13061 ON__UINT64 sizeof_read = Read((size_t)sizeof_buffer,buffer);
13062 m_error_message_mask = saved_error_mask;
13063 return sizeof_read;
13064 }
13065
13066
13067 ///////////////////////////////////////////////////////////////////////////////
13068 ///////////////////////////////////////////////////////////////////////////////
13069 ///////////////////////////////////////////////////////////////////////////////
13070
ON_BinaryFile(ON::archive_mode mode)13071 ON_BinaryFile::ON_BinaryFile( ON::archive_mode mode )
13072 : ON_BinaryArchive( mode ),
13073 m_fp(0),
13074 m_memory_buffer_capacity(0),
13075 m_memory_buffer_size(0),
13076 m_memory_buffer_ptr(0),
13077 m_memory_buffer(0)
13078 {}
13079
ON_BinaryFile(ON::archive_mode mode,FILE * fp)13080 ON_BinaryFile::ON_BinaryFile( ON::archive_mode mode, FILE* fp )
13081 : ON_BinaryArchive( mode ),
13082 m_fp(fp),
13083 m_memory_buffer_capacity(0),
13084 m_memory_buffer_size(0),
13085 m_memory_buffer_ptr(0),
13086 m_memory_buffer(0)
13087 {}
13088
~ON_BinaryFile()13089 ON_BinaryFile::~ON_BinaryFile()
13090 {
13091 EnableMemoryBuffer(0);
13092 }
13093
13094 bool
ReadByte(size_t count,void * p)13095 ON_BinaryArchive::ReadByte( size_t count, void* p )
13096 {
13097 bool rc = false;
13098 if ( count > 0 ) {
13099 if ( !ReadMode() ) {
13100 ON_ERROR("ON_BinaryArchive::ReadByte() ReadMode() is false.");
13101 }
13102 else if ( p )
13103 {
13104
13105 #if defined(ON_DEBUG)
13106 {
13107 // this is slow (becuase of the call to CurrentPosition(), but it really helps find bugs in IO code
13108 const ON_3DM_BIG_CHUNK* c = m_chunk.Last();
13109 if ( c )
13110 {
13111 ON__UINT64 file_offset = CurrentPosition();
13112 if ( file_offset < c->m_big_offset )
13113 {
13114 ON_ERROR("ON_BinaryArchive::ReadByte will read before the start of the chunk.");
13115 }
13116 else if (c->m_big_offset + c->Length() < file_offset + count )
13117 {
13118 ON_ERROR("ON_BinaryArchive::ReadByte will read past end of the chunk");
13119 }
13120 }
13121 }
13122 #endif
13123
13124 size_t readcount = Read( count, p );
13125 if ( readcount == count )
13126 {
13127 UpdateCRC( count, p );
13128 rc = true;
13129 }
13130 else
13131 {
13132 // see if this is an error condition
13133 for(;;)
13134 {
13135 if ( 0 != (m_error_message_mask&0x01)
13136 && 0 == readcount && 4 == count
13137 )
13138 {
13139 // when reading v1 files, there are some situations where
13140 // it is reasonable to attempt to read 4 bytes at the end
13141 // of a file.
13142 break;
13143 }
13144 if ( 0 == m_3dm_version
13145 && 0 == m_3dm_opennurbs_version
13146 && 0 == m_3dm_start_section_offset
13147 && ON_BinaryArchive::no_active_table == m_active_table
13148 && 0 == m_chunk
13149 && ON::read3dm == m_mode
13150 )
13151 {
13152 // In Read3dmStartSection(), we search for the string
13153 // "3D Geometry File Format ...". When a non-.3dm file
13154 // is searched, we eventually reach the end of the file.
13155 // This error condition is reported by the returning
13156 // false from ON_BinaryArchive::Read3dmStartSection().
13157 // ON_ERROR is not called to prevent annoying everyone
13158 // when the open file dialog is digging around looking
13159 // for files.
13160 break;
13161 }
13162 ON_ERROR("ON_BinaryArchive::ReadByte() Read() failed.");
13163 break;
13164 }
13165 }
13166 }
13167 else
13168 {
13169 ON_ERROR("ON_BinaryArchive::ReadByte() NULL file or buffer.");
13170 }
13171 }
13172 else
13173 {
13174 rc = true;
13175 }
13176 return rc;
13177 }
13178
13179 bool
WriteByte(size_t count,const void * p)13180 ON_BinaryArchive::WriteByte( size_t count, const void* p )
13181 {
13182 bool rc = false;
13183 if ( count > 0 ) {
13184 if ( !WriteMode() ) {
13185 ON_ERROR("ON_BinaryArchive::WriteByte() WriteMode() is false.");
13186 }
13187 else if ( p ) {
13188 size_t writecount = (size_t)Write( count, p );
13189 if ( writecount == count ) {
13190 UpdateCRC( count, p );
13191 rc = true;
13192 }
13193 else {
13194 ON_ERROR("ON_BinaryArchive::WriteByte() fwrite() failed.");
13195 }
13196 }
13197 else {
13198 ON_ERROR("ON_BinaryArchive::WriteByte() NULL file or buffer.");
13199 }
13200 }
13201 else {
13202 rc = true;
13203 }
13204 return rc;
13205 }
13206
EnableCRCCalculation(bool bEnable)13207 bool ON_BinaryArchive::EnableCRCCalculation( bool bEnable )
13208 {
13209 bool rc = m_bDoChunkCRC;
13210 m_bDoChunkCRC = bEnable ? true : false;
13211 return rc;
13212 }
13213
13214 bool
SetArchive3dmVersion(int v)13215 ON_BinaryArchive::SetArchive3dmVersion(int v)
13216 {
13217 bool rc = false;
13218 // valid versions are 1,2,3,4,5,50,60,70,...
13219 // 1 - 4 correspond to Rhino V1 - V4.
13220 // 5 was used for early V5 betas with 4 byte chunk lengths
13221 // 50 is used for V5 files with 8 bytes chunk lengths.
13222 // 60, 70, ... will be used for Rhino V6, V7, etc.
13223 if ( (v >= 1 && v <= 5) || ( v >= 50 && 0 == (v % 10) ) )
13224 {
13225 m_3dm_version = v;
13226 rc = true;
13227 }
13228 else
13229 {
13230 m_3dm_version = 0;
13231 ON_ERROR("ON_BinaryArchive::SetArchive3dmVersion - invalid version");
13232 }
13233 return rc;
13234 }
13235
13236 void
EnableMemoryBuffer(int buffer_capacity)13237 ON_BinaryFile::EnableMemoryBuffer(
13238 int buffer_capacity
13239 )
13240 {
13241 if ( buffer_capacity > 0 && !m_memory_buffer) {
13242 m_memory_buffer = (unsigned char*)onmalloc(buffer_capacity);
13243 if ( m_memory_buffer ) {
13244 m_memory_buffer_capacity = buffer_capacity;
13245 m_memory_buffer_size = 0;
13246 m_memory_buffer_ptr = 0;
13247 }
13248 }
13249 else {
13250 if ( buffer_capacity == 0 && m_memory_buffer ) {
13251 Flush();
13252 onfree(m_memory_buffer);
13253 }
13254 m_memory_buffer = 0;
13255 m_memory_buffer_capacity = 0;
13256 m_memory_buffer_size = 0;
13257 m_memory_buffer_ptr = 0;
13258 }
13259 }
13260
13261
Read(size_t count,void * p)13262 size_t ON_BinaryFile::Read( size_t count, void* p )
13263 {
13264 return (m_fp) ? fread( p, 1, count, m_fp ) : 0;
13265 }
13266
Write(size_t count,const void * p)13267 size_t ON_BinaryFile::Write( size_t count, const void* p )
13268 {
13269 size_t rc = 0;
13270 if ( m_fp )
13271 {
13272 if ( m_memory_buffer )
13273 {
13274 if ( count+m_memory_buffer_ptr >= m_memory_buffer_capacity ) {
13275 if ( !Flush() ) // flush existing memory buffer to disk
13276 return 0;
13277 rc = fwrite( p, 1, count, m_fp ); // write directly to disk
13278 }
13279 else
13280 {
13281 // copy to the memory buffer
13282 memcpy( m_memory_buffer+m_memory_buffer_ptr, p, count );
13283 m_memory_buffer_ptr += count;
13284 if ( m_memory_buffer_ptr > m_memory_buffer_size )
13285 m_memory_buffer_size = m_memory_buffer_ptr;
13286 rc = count;
13287 }
13288 }
13289 else
13290 {
13291 rc = fwrite( p, 1, count, m_fp );
13292 }
13293 }
13294 return rc;
13295 }
13296
Flush()13297 bool ON_BinaryFile::Flush()
13298 {
13299 bool rc = true;
13300 if ( m_fp )
13301 {
13302 if ( m_memory_buffer && m_memory_buffer_size > 0 )
13303 {
13304 rc = ( m_memory_buffer_size == fwrite( m_memory_buffer, 1, m_memory_buffer_size, m_fp ));
13305 if ( rc && m_memory_buffer_ptr != m_memory_buffer_size )
13306 {
13307 //if ( !fseek( m_fp, m_memory_buffer_size-m_memory_buffer_ptr, SEEK_CUR ) )
13308 int delta = (m_memory_buffer_ptr >= m_memory_buffer_size)
13309 ? ((int)(m_memory_buffer_ptr - m_memory_buffer_size))
13310 : -((int)(m_memory_buffer_size - m_memory_buffer_ptr));
13311 if ( !fseek( m_fp, delta, SEEK_CUR ) )
13312 {
13313 rc = false;
13314 }
13315 }
13316 m_memory_buffer_size = 0;
13317 m_memory_buffer_ptr = 0;
13318 }
13319 }
13320 return rc;
13321 }
13322
CurrentPosition() const13323 size_t ON_BinaryFile::CurrentPosition() const
13324 {
13325 size_t offset = 0;
13326
13327 if ( 0 != m_fp )
13328 {
13329
13330 #if defined(ON_COMPILER_MSC)
13331 // use an ftell() that supports file offsets > 2GB
13332 ON__INT64 offset64 = _ftelli64(m_fp);
13333 if ( offset64 < 0 )
13334 {
13335 ON_ERROR("ON_BinaryFile::CurrentPosition() - _ftelli64() failed");
13336 }
13337 else
13338 {
13339 offset = (size_t)((ON__UINT64)offset64);
13340 }
13341 #else
13342 offset = ftell(m_fp);
13343 #endif
13344
13345 if ( m_memory_buffer && m_memory_buffer_size > 0 )
13346 {
13347 offset += m_memory_buffer_ptr;
13348 }
13349 }
13350 else
13351 {
13352 ON_ERROR("ON_BinaryFile::CurrentPosition() NULL file.");
13353 }
13354
13355 return offset;
13356 }
13357
13358 #if defined(__GNUC__) && (!defined( __INTEL_COMPILER)) //G+Smo silence warning
13359 #pragma GCC diagnostic ignored "-Wunused-result"
13360 # endif
13361
AtEnd() const13362 bool ON_BinaryFile::AtEnd() const
13363 {
13364 bool rc = true;
13365 if ( m_fp ) {
13366 rc = false;
13367 if ( ReadMode() ) {
13368 if ( feof( m_fp ) ) {
13369 rc = true;
13370 }
13371 else
13372 {
13373 int buffer;
13374 fread( &buffer, 1, 1, m_fp );
13375 if ( feof( m_fp ) )
13376 {
13377 rc = true;
13378 }
13379 else
13380 {
13381 // back up to the byte we just read
13382 fseek( m_fp, -1, SEEK_CUR );
13383 }
13384 }
13385 }
13386 }
13387 return rc;
13388 }
13389
SeekFromCurrentPosition(int offset)13390 bool ON_BinaryFile::SeekFromCurrentPosition( int offset )
13391 {
13392 // it appears that the calls to SeekFromCurrentPosition(),
13393 // and consequent call to fseek(), in ON_BinaryArchive::EndWrite3DMChunk()
13394 // really slow down 3DM file writing on some networks. There are
13395 // reports of a 100x difference in local vs network saves.
13396 // I could not reproduce these 100x slow saves in testing on McNeel's
13397 // network but we have a good quality network and a server that's
13398 // properly tuned. My guess is that the slow saves are happening
13399 // on servers that do a poor job of cacheing because they are starved
13400 // for memory and/or heavily used at the time of the save.
13401 //
13402 // To speed up network saves, ON_BinaryFile can optionally use
13403 // it's own buffer for buffered I/O instead of relying on fwrite()
13404 // and the OS to handle this.
13405 bool rc = false;
13406 if ( m_fp )
13407 {
13408 if ( m_memory_buffer &&
13409 ((ON__INT_PTR)m_memory_buffer_ptr)+((ON__INT_PTR)offset) >= 0 &&
13410 m_memory_buffer_ptr+offset <= m_memory_buffer_size ) {
13411 m_memory_buffer_ptr += offset;
13412 rc = true;
13413 }
13414 else
13415 {
13416 // don't deal with memory buffer I/O if seek lands outside of
13417 // our current memory buffer.
13418 Flush();
13419 if ( !fseek(m_fp,offset,SEEK_CUR) )
13420 {
13421 rc = true;
13422 }
13423 else
13424 {
13425 ON_ERROR("ON_BinaryFile::Seek() fseek(,SEEK_CUR) failed.");
13426 }
13427 }
13428 }
13429 return rc;
13430 }
13431
SeekFromEnd(int offset)13432 bool ON_BinaryFile::SeekFromEnd( int offset )
13433 {
13434 bool rc = false;
13435 if ( m_fp )
13436 {
13437 Flush(); // don't deal with memory buffer I/O in rare seek from end
13438 if ( !fseek(m_fp,offset,SEEK_END) )
13439 {
13440 rc = true;
13441 }
13442 else
13443 {
13444 ON_ERROR("ON_BinaryFile::SeekFromEnd() fseek(,SEEK_END) failed.");
13445 }
13446 }
13447 return rc;
13448 }
13449
SeekFromStart(size_t offset)13450 bool ON_BinaryFile::SeekFromStart( size_t offset )
13451 {
13452 bool rc = false;
13453 if ( m_fp )
13454 {
13455 Flush(); // don't deal with memory buffer I/O in rare seek from start
13456 long loffset = (long)offset;
13457 if ( !fseek(m_fp,loffset,SEEK_SET) )
13458 {
13459 rc = true;
13460 }
13461 else
13462 {
13463 ON_ERROR("ON_BinaryFile::SeekFromStart() fseek(,SEEK_SET) failed.");
13464 }
13465 }
13466 return rc;
13467 }
13468
ON_3dmGoo()13469 ON_3dmGoo::ON_3dmGoo()
13470 : m_typecode(0),
13471 m_value(0),
13472 m_goo(0),
13473 m_next_goo(0),
13474 m_prev_goo(0)
13475 {}
13476
~ON_3dmGoo()13477 ON_3dmGoo::~ON_3dmGoo()
13478 {
13479 if ( m_prev_goo )
13480 m_prev_goo->m_next_goo = m_next_goo;
13481 if ( m_next_goo )
13482 m_next_goo->m_prev_goo = m_prev_goo;
13483 if ( m_goo ) {
13484 onfree(m_goo);
13485 m_goo = 0;
13486 }
13487 }
13488
ON_3dmGoo(const ON_3dmGoo & src)13489 ON_3dmGoo::ON_3dmGoo( const ON_3dmGoo& src )
13490 : m_typecode(0),
13491 m_value(0),
13492 m_goo(0),
13493 m_next_goo(0),
13494 m_prev_goo(0)
13495 {
13496 *this = src;
13497 }
13498
operator =(const ON_3dmGoo & src)13499 ON_3dmGoo& ON_3dmGoo::operator=( const ON_3dmGoo& src )
13500 {
13501 if ( this != &src ) {
13502 if ( m_goo ) {
13503 onfree(m_goo);
13504 }
13505 m_typecode = src.m_typecode;
13506 m_value = src.m_value;
13507 m_goo = (m_value > 0 && src.m_goo) ? (unsigned char*)onmemdup( src.m_goo, m_value ) : 0;
13508 }
13509 return *this;
13510 }
13511
Dump(ON_TextLog & dump) const13512 void ON_3dmGoo::Dump(ON_TextLog& dump) const
13513 {
13514 dump.Print("typecode = %08x value = %d\n",m_typecode,m_value);
13515 }
13516
ON_WriteOneObjectArchive(ON_BinaryArchive & archive,int version,const ON_Object & object)13517 bool ON_WriteOneObjectArchive(
13518 ON_BinaryArchive& archive,
13519 int version,
13520 const ON_Object& object
13521 )
13522 {
13523 bool rc = false;
13524
13525 const ON_Object* pObject = &object;
13526 {
13527 if ( ON_BrepEdge::Cast(pObject) )
13528 {
13529 // write parent brep
13530 pObject = static_cast<const ON_BrepEdge*>(pObject)->Brep();
13531 }
13532 else if ( ON_BrepTrim::Cast(pObject) )
13533 {
13534 pObject = NULL;
13535 }
13536 else if ( ON_BrepLoop::Cast(pObject) )
13537 {
13538 pObject = static_cast<const ON_BrepLoop*>(pObject)->Brep();
13539 }
13540 else if ( ON_BrepFace::Cast(pObject) )
13541 {
13542 // write parent brep
13543 pObject = static_cast<const ON_BrepFace*>(pObject)->Brep();
13544 }
13545 else if ( ON_CurveProxy::Cast(pObject) )
13546 {
13547 // write actual curve
13548 pObject = static_cast<const ON_CurveProxy*>(pObject)->ProxyCurve();
13549 }
13550 else if ( ON_SurfaceProxy::Cast(pObject) )
13551 {
13552 // write actual surface
13553 pObject = static_cast<const ON_SurfaceProxy*>(pObject)->ProxySurface();
13554 }
13555 }
13556
13557 ON_3dmProperties props;
13558 props.m_RevisionHistory.NewRevision();
13559
13560 ON_3dmSettings settings;
13561 // 1 Feb 2012 Dale Lear
13562 // http://dev.mcneel.com/bugtrack/?q=98543
13563 // Single object archives have no unit system so they
13564 // can be read into a file with no scaling. Prior to
13565 // today the unit system was always millimeters.
13566 settings.m_ModelUnitsAndTolerances.m_unit_system.m_unit_system = ON::no_unit_system;
13567
13568 ON_Layer layer;
13569 ON_3dmObjectAttributes attributes;
13570
13571 // layer table will have one layer
13572 layer.SetLayerIndex(0);
13573 layer.SetLayerName(L"Default");
13574 ON_CreateUuid(layer.m_layer_id);
13575
13576 // object attributes
13577 attributes.m_layer_index = 0;
13578 ON_CreateUuid(attributes.m_uuid);
13579
13580 while(pObject)
13581 {
13582 rc = archive.Write3dmStartSection( version, "Archive created by ON_WriteOneObjectArchive " __DATE__ " " __TIME__ );
13583 if ( !rc )
13584 break;
13585
13586 version = archive.Archive3dmVersion();
13587
13588 rc = archive.Write3dmProperties( props );
13589 if ( !rc )
13590 break;
13591
13592 rc = archive.Write3dmSettings( settings );
13593 if ( !rc )
13594 break;
13595
13596 rc = archive.BeginWrite3dmBitmapTable();
13597 if ( !rc )
13598 break;
13599 rc = archive.EndWrite3dmBitmapTable();
13600 if ( !rc )
13601 break;
13602
13603 if ( version >= 4 )
13604 {
13605 rc = archive.BeginWrite3dmTextureMappingTable();
13606 if ( !rc )
13607 break;
13608 rc = archive.EndWrite3dmTextureMappingTable();
13609 if ( !rc )
13610 break;
13611 }
13612
13613 rc = archive.BeginWrite3dmMaterialTable();
13614 if ( !rc )
13615 break;
13616 rc = archive.EndWrite3dmMaterialTable();
13617 if ( !rc )
13618 break;
13619
13620 if ( version >= 4 )
13621 {
13622 rc = archive.BeginWrite3dmLinetypeTable();
13623 if ( !rc )
13624 break;
13625 rc = archive.EndWrite3dmLinetypeTable();
13626 if ( !rc )
13627 break;
13628 }
13629
13630 rc = archive.BeginWrite3dmLayerTable();
13631 if ( !rc )
13632 break;
13633 {
13634 rc = archive.Write3dmLayer(layer);
13635 }
13636 if (!archive.EndWrite3dmLayerTable())
13637 rc = false;
13638 if ( !rc )
13639 break;
13640
13641 rc = archive.BeginWrite3dmGroupTable();
13642 if ( !rc )
13643 break;
13644 rc = archive.EndWrite3dmGroupTable();
13645 if ( !rc )
13646 break;
13647
13648 if ( version >= 3 )
13649 {
13650 rc = archive.BeginWrite3dmFontTable();
13651 if ( !rc )
13652 break;
13653 rc = archive.EndWrite3dmFontTable();
13654 if ( !rc )
13655 break;
13656 }
13657
13658 if ( version >= 3 )
13659 {
13660 rc = archive.BeginWrite3dmDimStyleTable();
13661 if ( !rc )
13662 break;
13663 rc = archive.EndWrite3dmDimStyleTable();
13664 if ( !rc )
13665 break;
13666 }
13667
13668 rc = archive.BeginWrite3dmLightTable();
13669 if ( !rc )
13670 break;
13671 rc = archive.EndWrite3dmLightTable();
13672 if ( !rc )
13673 break;
13674
13675 if ( version >= 4 )
13676 {
13677 rc = archive.BeginWrite3dmHatchPatternTable();
13678 if ( !rc )
13679 break;
13680 rc = archive.EndWrite3dmHatchPatternTable();
13681 if ( !rc )
13682 break;
13683 }
13684
13685 if ( version >= 3 )
13686 {
13687 rc = archive.BeginWrite3dmInstanceDefinitionTable();
13688 if ( !rc )
13689 break;
13690 rc = archive.EndWrite3dmInstanceDefinitionTable();
13691 if ( !rc )
13692 break;
13693 }
13694
13695 rc = archive.BeginWrite3dmObjectTable();
13696 if ( !rc )
13697 break;
13698 {
13699 rc = archive.Write3dmObject( *pObject, &attributes );
13700 }
13701 if ( !archive.EndWrite3dmObjectTable() )
13702 rc = false;
13703 if ( !rc )
13704 break;
13705
13706 if ( version >= 4 )
13707 {
13708 rc = archive.BeginWrite3dmHistoryRecordTable();
13709 if ( !rc )
13710 break;
13711 rc = archive.EndWrite3dmHistoryRecordTable();
13712 if ( !rc )
13713 break;
13714 }
13715
13716 rc = archive.Write3dmEndMark();
13717
13718 break;
13719 }
13720
13721 return rc;
13722 }
13723
13724 static
Dump3dmChunk_ErrorReportHelper(size_t offset,const char * msg,ON_TextLog & dump)13725 void Dump3dmChunk_ErrorReportHelper( size_t offset, const char* msg, ON_TextLog& dump )
13726 {
13727 int ioffset = (int)offset;
13728 dump.Print("** ERROR near offset %d ** %s\n",ioffset,msg);
13729 }
13730 static
DumpChunk_PrintHeaderInfo(size_t offset0,ON__UINT32 typecode,ON__INT64 big_value,const char * typecode_name,ON_TextLog & dump)13731 bool DumpChunk_PrintHeaderInfo( size_t offset0, ON__UINT32 typecode, ON__INT64 big_value, const char* typecode_name, ON_TextLog& dump)
13732 {
13733 bool bShortChunk = (0 != (typecode & TCODE_SHORT));
13734 if ( 0 == typecode_name )
13735 typecode_name = ON_BinaryArchive::TypecodeName(typecode);
13736 if ( 0 == typecode_name )
13737 typecode_name = "unknown tcode";
13738 if ( bShortChunk )
13739 {
13740 dump.Print("%6d: %08X %s: value = %lld (%016llX)\n", offset0, typecode, typecode_name, big_value, big_value );
13741 }
13742 else
13743 {
13744 // long chunk value = length of chunk data
13745 if ( big_value < 0 )
13746 {
13747 Dump3dmChunk_ErrorReportHelper(offset0,"BeginRead3dmChunk() returned length < 0.",dump);
13748 return false;
13749 }
13750 dump.Print("%6d: %08X %s: length = %lld bytes\n", offset0, typecode, typecode_name, big_value );
13751 }
13752 return true;
13753 }
13754
13755 #define CASEtcode2string(tc) case tc: s = #tc ; break
13756
TypecodeName(unsigned int tcode)13757 const char* ON_BinaryArchive::TypecodeName( unsigned int tcode )
13758 {
13759
13760 const char* s;
13761 switch( tcode )
13762 {
13763 CASEtcode2string(TCODE_FONT_TABLE);
13764 CASEtcode2string(TCODE_FONT_RECORD);
13765 CASEtcode2string(TCODE_DIMSTYLE_TABLE);
13766 CASEtcode2string(TCODE_DIMSTYLE_RECORD);
13767 CASEtcode2string(TCODE_INSTANCE_DEFINITION_RECORD);
13768 CASEtcode2string(TCODE_COMMENTBLOCK);
13769 CASEtcode2string(TCODE_ENDOFFILE);
13770 CASEtcode2string(TCODE_ENDOFFILE_GOO);
13771 CASEtcode2string(TCODE_LEGACY_GEOMETRY);
13772 CASEtcode2string(TCODE_OPENNURBS_OBJECT);
13773 CASEtcode2string(TCODE_GEOMETRY);
13774 CASEtcode2string(TCODE_ANNOTATION);
13775 CASEtcode2string(TCODE_DISPLAY);
13776 CASEtcode2string(TCODE_RENDER);
13777 CASEtcode2string(TCODE_INTERFACE);
13778 CASEtcode2string(TCODE_TOLERANCE);
13779 CASEtcode2string(TCODE_TABLE);
13780 CASEtcode2string(TCODE_TABLEREC);
13781 CASEtcode2string(TCODE_USER);
13782 CASEtcode2string(TCODE_SHORT);
13783 CASEtcode2string(TCODE_CRC);
13784 CASEtcode2string(TCODE_ANONYMOUS_CHUNK);
13785 CASEtcode2string(TCODE_MATERIAL_TABLE);
13786 CASEtcode2string(TCODE_LAYER_TABLE);
13787 CASEtcode2string(TCODE_LIGHT_TABLE);
13788 CASEtcode2string(TCODE_OBJECT_TABLE);
13789 CASEtcode2string(TCODE_PROPERTIES_TABLE);
13790 CASEtcode2string(TCODE_SETTINGS_TABLE);
13791 CASEtcode2string(TCODE_BITMAP_TABLE);
13792 CASEtcode2string(TCODE_USER_TABLE);
13793 CASEtcode2string(TCODE_INSTANCE_DEFINITION_TABLE);
13794 CASEtcode2string(TCODE_HATCHPATTERN_TABLE);
13795 CASEtcode2string(TCODE_HATCHPATTERN_RECORD);
13796 CASEtcode2string(TCODE_LINETYPE_TABLE);
13797 CASEtcode2string(TCODE_LINETYPE_RECORD);
13798 CASEtcode2string(TCODE_OBSOLETE_LAYERSET_TABLE);
13799 CASEtcode2string(TCODE_OBSOLETE_LAYERSET_RECORD);
13800 CASEtcode2string(TCODE_TEXTURE_MAPPING_TABLE);
13801 CASEtcode2string(TCODE_TEXTURE_MAPPING_RECORD);
13802 CASEtcode2string(TCODE_HISTORYRECORD_TABLE);
13803 CASEtcode2string(TCODE_HISTORYRECORD_RECORD);
13804 CASEtcode2string(TCODE_ENDOFTABLE);
13805 CASEtcode2string(TCODE_PROPERTIES_REVISIONHISTORY);
13806 CASEtcode2string(TCODE_PROPERTIES_NOTES);
13807 CASEtcode2string(TCODE_PROPERTIES_PREVIEWIMAGE);
13808 CASEtcode2string(TCODE_PROPERTIES_COMPRESSED_PREVIEWIMAGE);
13809 CASEtcode2string(TCODE_PROPERTIES_APPLICATION);
13810 CASEtcode2string(TCODE_PROPERTIES_OPENNURBS_VERSION);
13811 CASEtcode2string(TCODE_SETTINGS_PLUGINLIST);
13812 CASEtcode2string(TCODE_SETTINGS_UNITSANDTOLS);
13813 CASEtcode2string(TCODE_SETTINGS_RENDERMESH);
13814 CASEtcode2string(TCODE_SETTINGS_ANALYSISMESH);
13815 CASEtcode2string(TCODE_SETTINGS_ANNOTATION);
13816 CASEtcode2string(TCODE_SETTINGS_NAMED_CPLANE_LIST);
13817 CASEtcode2string(TCODE_SETTINGS_NAMED_VIEW_LIST);
13818 CASEtcode2string(TCODE_SETTINGS_VIEW_LIST);
13819 CASEtcode2string(TCODE_SETTINGS_CURRENT_LAYER_INDEX);
13820 CASEtcode2string(TCODE_SETTINGS_CURRENT_MATERIAL_INDEX);
13821 CASEtcode2string(TCODE_SETTINGS_CURRENT_COLOR);
13822 CASEtcode2string(TCODE_SETTINGS__NEVER__USE__THIS);
13823 CASEtcode2string(TCODE_SETTINGS_CURRENT_WIRE_DENSITY);
13824 CASEtcode2string(TCODE_SETTINGS_RENDER);
13825 CASEtcode2string(TCODE_SETTINGS_GRID_DEFAULTS);
13826 CASEtcode2string(TCODE_SETTINGS_MODEL_URL);
13827 CASEtcode2string(TCODE_SETTINGS_CURRENT_FONT_INDEX);
13828 CASEtcode2string(TCODE_SETTINGS_CURRENT_DIMSTYLE_INDEX);
13829 CASEtcode2string(TCODE_SETTINGS_ATTRIBUTES);
13830 CASEtcode2string(TCODE_VIEW_RECORD);
13831 CASEtcode2string(TCODE_VIEW_CPLANE);
13832 CASEtcode2string(TCODE_VIEW_VIEWPORT);
13833 CASEtcode2string(TCODE_VIEW_VIEWPORT_USERDATA);
13834 CASEtcode2string(TCODE_VIEW_SHOWCONGRID);
13835 CASEtcode2string(TCODE_VIEW_SHOWCONAXES);
13836 CASEtcode2string(TCODE_VIEW_SHOWWORLDAXES);
13837 CASEtcode2string(TCODE_VIEW_TRACEIMAGE);
13838 CASEtcode2string(TCODE_VIEW_WALLPAPER);
13839 CASEtcode2string(TCODE_VIEW_WALLPAPER_V3);
13840 CASEtcode2string(TCODE_VIEW_TARGET);
13841 CASEtcode2string(TCODE_VIEW_DISPLAYMODE);
13842 CASEtcode2string(TCODE_VIEW_NAME);
13843 CASEtcode2string(TCODE_VIEW_POSITION);
13844 CASEtcode2string(TCODE_VIEW_ATTRIBUTES);
13845 CASEtcode2string(TCODE_BITMAP_RECORD);
13846 CASEtcode2string(TCODE_MATERIAL_RECORD);
13847 CASEtcode2string(TCODE_LAYER_RECORD);
13848 CASEtcode2string(TCODE_LIGHT_RECORD);
13849 CASEtcode2string(TCODE_LIGHT_RECORD_ATTRIBUTES);
13850 CASEtcode2string(TCODE_OBJECT_RECORD_ATTRIBUTES_USERDATA);
13851 CASEtcode2string(TCODE_OBJECT_RECORD_HISTORY);
13852 CASEtcode2string(TCODE_OBJECT_RECORD_HISTORY_HEADER);
13853 CASEtcode2string(TCODE_OBJECT_RECORD_HISTORY_DATA);
13854 CASEtcode2string(TCODE_LIGHT_RECORD_END);
13855 CASEtcode2string(TCODE_USER_TABLE_UUID);
13856 CASEtcode2string(TCODE_USER_TABLE_RECORD_HEADER);
13857 CASEtcode2string(TCODE_USER_RECORD);
13858 CASEtcode2string(TCODE_GROUP_TABLE);
13859 CASEtcode2string(TCODE_GROUP_RECORD);
13860 CASEtcode2string(TCODE_OBJECT_RECORD);
13861 CASEtcode2string(TCODE_OBJECT_RECORD_TYPE);
13862 CASEtcode2string(TCODE_OBJECT_RECORD_ATTRIBUTES);
13863 CASEtcode2string(TCODE_OBJECT_RECORD_END);
13864 CASEtcode2string(TCODE_OPENNURBS_CLASS);
13865 CASEtcode2string(TCODE_OPENNURBS_CLASS_UUID);
13866 CASEtcode2string(TCODE_OPENNURBS_CLASS_DATA);
13867 CASEtcode2string(TCODE_OPENNURBS_CLASS_USERDATA);
13868 CASEtcode2string(TCODE_OPENNURBS_CLASS_USERDATA_HEADER);
13869 CASEtcode2string(TCODE_OPENNURBS_CLASS_END);
13870 CASEtcode2string(TCODE_OPENNURBS_BUFFER);
13871 CASEtcode2string(TCODE_ANNOTATION_SETTINGS);
13872 CASEtcode2string(TCODE_TEXT_BLOCK);
13873 CASEtcode2string(TCODE_ANNOTATION_LEADER);
13874 CASEtcode2string(TCODE_LINEAR_DIMENSION);
13875 CASEtcode2string(TCODE_ANGULAR_DIMENSION);
13876 CASEtcode2string(TCODE_RADIAL_DIMENSION);
13877 CASEtcode2string(TCODE_RHINOIO_OBJECT_NURBS_CURVE);
13878 CASEtcode2string(TCODE_RHINOIO_OBJECT_NURBS_SURFACE);
13879 CASEtcode2string(TCODE_RHINOIO_OBJECT_BREP);
13880 CASEtcode2string(TCODE_RHINOIO_OBJECT_DATA);
13881 CASEtcode2string(TCODE_RHINOIO_OBJECT_END);
13882 CASEtcode2string(TCODE_LEGACY_ASM);
13883 CASEtcode2string(TCODE_LEGACY_PRT);
13884 CASEtcode2string(TCODE_LEGACY_SHL);
13885 CASEtcode2string(TCODE_LEGACY_FAC);
13886 CASEtcode2string(TCODE_LEGACY_BND);
13887 CASEtcode2string(TCODE_LEGACY_TRM);
13888 CASEtcode2string(TCODE_LEGACY_SRF);
13889 CASEtcode2string(TCODE_LEGACY_CRV);
13890 CASEtcode2string(TCODE_LEGACY_SPL);
13891 CASEtcode2string(TCODE_LEGACY_PNT);
13892 CASEtcode2string(TCODE_STUFF);
13893 CASEtcode2string(TCODE_LEGACY_ASMSTUFF);
13894 CASEtcode2string(TCODE_LEGACY_PRTSTUFF);
13895 CASEtcode2string(TCODE_LEGACY_SHLSTUFF);
13896 CASEtcode2string(TCODE_LEGACY_FACSTUFF);
13897 CASEtcode2string(TCODE_LEGACY_BNDSTUFF);
13898 CASEtcode2string(TCODE_LEGACY_TRMSTUFF);
13899 CASEtcode2string(TCODE_LEGACY_SRFSTUFF);
13900 CASEtcode2string(TCODE_LEGACY_CRVSTUFF);
13901 CASEtcode2string(TCODE_LEGACY_SPLSTUFF);
13902 CASEtcode2string(TCODE_LEGACY_PNTSTUFF);
13903 CASEtcode2string(TCODE_RH_POINT);
13904 CASEtcode2string(TCODE_RH_SPOTLIGHT);
13905 CASEtcode2string(TCODE_OLD_RH_TRIMESH);
13906 CASEtcode2string(TCODE_OLD_MESH_VERTEX_NORMALS);
13907 CASEtcode2string(TCODE_OLD_MESH_UV);
13908 CASEtcode2string(TCODE_OLD_FULLMESH);
13909 CASEtcode2string(TCODE_MESH_OBJECT);
13910 CASEtcode2string(TCODE_COMPRESSED_MESH_GEOMETRY);
13911 CASEtcode2string(TCODE_ANALYSIS_MESH);
13912 CASEtcode2string(TCODE_NAME);
13913 CASEtcode2string(TCODE_VIEW);
13914 CASEtcode2string(TCODE_CPLANE);
13915 CASEtcode2string(TCODE_NAMED_CPLANE);
13916 CASEtcode2string(TCODE_NAMED_VIEW);
13917 CASEtcode2string(TCODE_VIEWPORT);
13918 CASEtcode2string(TCODE_SHOWGRID);
13919 CASEtcode2string(TCODE_SHOWGRIDAXES);
13920 CASEtcode2string(TCODE_SHOWWORLDAXES);
13921 CASEtcode2string(TCODE_VIEWPORT_POSITION);
13922 CASEtcode2string(TCODE_VIEWPORT_TRACEINFO);
13923 CASEtcode2string(TCODE_SNAPSIZE);
13924 CASEtcode2string(TCODE_NEAR_CLIP_PLANE);
13925 CASEtcode2string(TCODE_HIDE_TRACE);
13926 CASEtcode2string(TCODE_NOTES);
13927 CASEtcode2string(TCODE_UNIT_AND_TOLERANCES);
13928 CASEtcode2string(TCODE_MAXIMIZED_VIEWPORT);
13929 CASEtcode2string(TCODE_VIEWPORT_WALLPAPER);
13930 CASEtcode2string(TCODE_SUMMARY);
13931 CASEtcode2string(TCODE_BITMAPPREVIEW);
13932 CASEtcode2string(TCODE_VIEWPORT_DISPLAY_MODE);
13933 CASEtcode2string(TCODE_LAYERTABLE);
13934 CASEtcode2string(TCODE_LAYERREF);
13935 CASEtcode2string(TCODE_XDATA);
13936 CASEtcode2string(TCODE_RGB);
13937 CASEtcode2string(TCODE_TEXTUREMAP);
13938 CASEtcode2string(TCODE_BUMPMAP);
13939 CASEtcode2string(TCODE_TRANSPARENCY);
13940 CASEtcode2string(TCODE_DISP_AM_RESOLUTION);
13941 CASEtcode2string(TCODE_RGBDISPLAY);
13942 CASEtcode2string(TCODE_RENDER_MATERIAL_ID);
13943 CASEtcode2string(TCODE_LAYER);
13944 CASEtcode2string(TCODE_LAYER_OBSELETE_1);
13945 CASEtcode2string(TCODE_LAYER_OBSELETE_2);
13946 CASEtcode2string(TCODE_LAYER_OBSELETE_3);
13947 CASEtcode2string(TCODE_LAYERON);
13948 CASEtcode2string(TCODE_LAYERTHAWED);
13949 CASEtcode2string(TCODE_LAYERLOCKED);
13950 CASEtcode2string(TCODE_LAYERVISIBLE);
13951 CASEtcode2string(TCODE_LAYERPICKABLE);
13952 CASEtcode2string(TCODE_LAYERSNAPABLE);
13953 CASEtcode2string(TCODE_LAYERRENDERABLE);
13954 CASEtcode2string(TCODE_LAYERSTATE);
13955 CASEtcode2string(TCODE_LAYERINDEX);
13956 CASEtcode2string(TCODE_LAYERMATERIALINDEX);
13957 CASEtcode2string(TCODE_RENDERMESHPARAMS);
13958 CASEtcode2string(TCODE_DISP_CPLINES);
13959 CASEtcode2string(TCODE_DISP_MAXLENGTH);
13960 CASEtcode2string(TCODE_CURRENTLAYER);
13961 CASEtcode2string(TCODE_LAYERNAME);
13962 CASEtcode2string(TCODE_LEGACY_TOL_FIT);
13963 CASEtcode2string(TCODE_LEGACY_TOL_ANGLE);
13964 CASEtcode2string(TCODE_DICTIONARY);
13965 CASEtcode2string(TCODE_DICTIONARY_ID);
13966 CASEtcode2string(TCODE_DICTIONARY_ENTRY);
13967 CASEtcode2string(TCODE_DICTIONARY_END);
13968 default:
13969 // unknown typecode.
13970 s = 0;
13971 break;
13972 }
13973 return s;
13974 }
13975
13976 #undef CASEtcode2string
13977
ON_TypecodeParse(unsigned int tcode,char * typecode_name,size_t max_length)13978 char* ON_BinaryArchive::ON_TypecodeParse( unsigned int tcode, char* typecode_name, size_t max_length )
13979 {
13980 char* s;
13981 const char* sub_name;
13982 const char* h = "0123456789ABCDEF";
13983 char c, c0;
13984 size_t slen;
13985
13986 if ( !typecode_name || max_length <= 0 )
13987 return 0;
13988 memset(typecode_name,0,max_length*sizeof(typecode_name[0]));
13989 slen = max_length-1; // the -1 insures the there is a null terminator
13990 if ( slen <= 0 )
13991 return 0;
13992
13993 sub_name = ON_BinaryArchive::TypecodeName(tcode);
13994 if ( 0 != sub_name && 0 != sub_name[0] )
13995 {
13996 c0 = *sub_name++;
13997 s = typecode_name+1;
13998 slen--;
13999 while ( *sub_name )
14000 {
14001 if ( slen <= 0 )
14002 return 0;
14003 *s++ = *sub_name++;
14004 slen--;
14005 }
14006 typecode_name[0] = c0;
14007 return typecode_name;
14008 }
14009
14010 sub_name = ON_BinaryArchive::TypecodeName( tcode & 0x7FFF0000 );
14011 if ( !sub_name || 0 == sub_name[0] )
14012 return 0;
14013
14014 c0 = *sub_name++;
14015 s = typecode_name+1;
14016 slen--;
14017
14018 while ( *sub_name )
14019 {
14020 if ( slen <= 0 )
14021 return 0;
14022 *s++ = *sub_name++;
14023 slen--;
14024 }
14025
14026 sub_name = ON_BinaryArchive::TypecodeName( tcode & TCODE_SHORT );
14027 if ( sub_name )
14028 {
14029 if ( slen <= 0 ) {return 0;} *s++ = ' '; slen--;
14030 if ( slen <= 0 ) {return 0;} *s++ = '|'; slen--;
14031 if ( slen <= 0 ) {return 0;} *s++ = ' '; slen--;
14032 while ( *sub_name )
14033 {
14034 if ( slen <= 0 )
14035 return 0;
14036 *s++ = *sub_name++;
14037 slen--;
14038 }
14039 }
14040
14041 sub_name = ON_BinaryArchive::TypecodeName( tcode & TCODE_CRC );
14042 if ( sub_name )
14043 {
14044 if ( slen <= 0 ) {return 0;} *s++ = ' '; slen--;
14045 if ( slen <= 0 ) {return 0;} *s++ = '|'; slen--;
14046 if ( slen <= 0 ) {return 0;} *s++ = ' '; slen--;
14047 while ( *sub_name )
14048 {
14049 if ( slen <= 0 )
14050 return 0;
14051 *s++ = *sub_name++;
14052 slen--;
14053 }
14054 }
14055
14056 sub_name = ON_BinaryArchive::TypecodeName( tcode & 0x7FFF );
14057 if ( sub_name )
14058 {
14059 if ( slen <= 0 ) {return 0;} *s++ = ' '; slen--;
14060 if ( slen <= 0 ) {return 0;} *s++ = '|'; slen--;
14061 if ( slen <= 0 ) {return 0;} *s++ = ' '; slen--;
14062 while ( *sub_name )
14063 {
14064 if ( slen <= 0 )
14065 return 0;
14066 *s++ = *sub_name++;
14067 slen--;
14068 }
14069 }
14070 else
14071 {
14072 if ( slen <= 0 ) {return 0;} *s++ = ' '; slen--;
14073 if ( slen <= 0 ) {return 0;} *s++ = '|'; slen--;
14074 if ( slen <= 0 ) {return 0;} *s++ = ' '; slen--;
14075 if ( slen <= 0 ) {return 0;} *s++ = '0'; slen--;
14076 if ( slen <= 0 ) {return 0;} *s++ = 'x'; slen--;
14077 c = h[((tcode & 0x7000) / 0x1000) & 0xF];
14078 if ( slen > 0 ) {*s++ = c; slen--;}
14079 c = h[((tcode & 0xF00) / 0x100) & 0xF];
14080 if ( slen > 0 ) {*s++ = c; slen--;}
14081 c = h[((tcode & 0xF0) / 0x10) & 0xF];
14082 if ( slen > 0 ) {*s++ = c; slen--;}
14083 c = h[tcode & 0xF];
14084 if ( slen > 0 ) {*s++ = c; slen--;}
14085 }
14086
14087 *typecode_name = c0;
14088
14089 return typecode_name;
14090 }
14091
14092 static
Dump3dmChunk_EndReadChunkHelper(ON_BinaryArchive & file,size_t offset0,ON__UINT32 tcode,ON__INT64 big_value,ON_TextLog & dump)14093 bool Dump3dmChunk_EndReadChunkHelper( ON_BinaryArchive& file, size_t offset0, ON__UINT32 tcode, ON__INT64 big_value, ON_TextLog& dump )
14094 {
14095 const bool bShortChunk = (0 != (tcode & TCODE_SHORT));
14096 const size_t offset1 = file.CurrentPosition();
14097 bool rc = file.EndRead3dmChunk();
14098 if ( !rc )
14099 {
14100 Dump3dmChunk_ErrorReportHelper(offset1,"EndRead3dmChunk() failed.",dump);
14101 }
14102 else if (!bShortChunk)
14103 {
14104 // The crc is read or skipped by the EndRead3dmChunk() call.
14105 // "extra" is the number of bytes we did not parse in the dump.
14106 ON__INT64 sizeof_crc = (0 != (TCODE_CRC & tcode)) ? 4 : 0;
14107 ON__INT64 sizeof_chunk_header = 4+file.SizeofChunkLength();
14108 ON__INT64 delta = (offset1 > offset0)
14109 ? ((ON__INT64)(offset1 - offset0))
14110 : -((ON__INT64)(offset0 - offset1));
14111 const ON__INT64 extra = big_value - (delta+sizeof_crc-sizeof_chunk_header);
14112 if ( extra < 0 )
14113 {
14114 Dump3dmChunk_ErrorReportHelper(offset0,"Read beyond end of chunk.",dump);
14115 rc = false;
14116 }
14117 }
14118 return rc;
14119 }
14120
14121 static
Dump3dmChunk_UserDataHeaderHelper(size_t offset,ON_BinaryArchive & file,int major_userdata_version,int minor_userdata_version,ON_TextLog & dump)14122 bool Dump3dmChunk_UserDataHeaderHelper( size_t offset, ON_BinaryArchive& file,
14123 int major_userdata_version, int minor_userdata_version,
14124 ON_TextLog& dump )
14125 {
14126 // TCODE_OPENNURBS_CLASS_USERDATA chunks have 2 uuids
14127 // the first identifies the type of ON_Object class
14128 // the second identifies that kind of user data
14129 ON_UUID userdata_classid = ON_nil_uuid;
14130 ON_UUID userdata_itemid = ON_nil_uuid;
14131 ON_UUID userdata_appid = ON_nil_uuid; // id of plug-in that owns the user data
14132 int userdata_copycount = -1;
14133 ON_Xform userdata_xform;
14134 bool bLastSavedAsGoo = false;
14135 int ud_archive_3dm_version = 0;
14136 int ud_archive_opennurbs_version = 0;
14137
14138 bool rc = false;
14139 bool bCallEndRead3dmChunk = false;
14140
14141 ON__UINT32 tcode = 0;
14142 ON__INT64 big_value = 0;
14143 const size_t offset0 = file.CurrentPosition();
14144
14145 for(;;)
14146 {
14147 if ( 2 == major_userdata_version )
14148 {
14149 rc = file.PeekAt3dmBigChunkType(&tcode,&big_value);
14150 if ( !rc )
14151 {
14152 Dump3dmChunk_ErrorReportHelper(offset,"Unable to find the TCODE_OPENNURBS_CLASS_USERDATA_HEADER chunk header in a TCODE_OPENNURBS_CLASS_USERDATA chunk.",dump);
14153 break;
14154 }
14155 if ( TCODE_OPENNURBS_CLASS_USERDATA_HEADER != tcode )
14156 {
14157 Dump3dmChunk_ErrorReportHelper(offset,"Unable to find the TCODE_OPENNURBS_CLASS_USERDATA_HEADER chunk header in a TCODE_OPENNURBS_CLASS_USERDATA chunk.",dump);
14158 rc = false;
14159 break;
14160 }
14161 rc = file.BeginRead3dmBigChunk(&tcode,&big_value);
14162 if ( !rc )
14163 {
14164 Dump3dmChunk_ErrorReportHelper(offset,"Unable to read the TCODE_OPENNURBS_CLASS_USERDATA_HEADER chunk header in a TCODE_OPENNURBS_CLASS_USERDATA chunk.",dump);
14165 break;
14166 }
14167 if ( TCODE_OPENNURBS_CLASS_USERDATA_HEADER != tcode )
14168 {
14169 Dump3dmChunk_ErrorReportHelper(offset,"Missing TCODE_OPENNURBS_CLASS_USERDATA_HEADER chunk header in a TCODE_OPENNURBS_CLASS_USERDATA chunk.",dump);
14170 Dump3dmChunk_EndReadChunkHelper(file,offset0,tcode,big_value,dump);
14171 rc = false;
14172 break;
14173 }
14174 bCallEndRead3dmChunk = true;
14175 }
14176
14177 rc = file.ReadUuid( userdata_classid );
14178 if ( !rc )
14179 {
14180 Dump3dmChunk_ErrorReportHelper(offset,"ReadUuid() failed to read the user data class id.",dump);
14181 break;
14182 }
14183
14184 dump.Print("UserData class id = ");
14185 dump.Print( userdata_classid );
14186 const ON_ClassId* pUserDataClassId = ON_ClassId::ClassId(userdata_classid);
14187 if ( pUserDataClassId )
14188 {
14189 const char* sClassName = pUserDataClassId->ClassName();
14190 if ( sClassName )
14191 {
14192 dump.Print(" (%s)",sClassName);
14193 }
14194 }
14195 dump.Print("\n");
14196
14197 rc = file.ReadUuid( userdata_itemid );
14198 if ( !rc )
14199 {
14200 Dump3dmChunk_ErrorReportHelper(offset,"ReadUuid() failed to read the user data item id.",dump);
14201 break;
14202 }
14203 dump.Print("UserData item id = ");
14204 dump.Print( userdata_itemid );
14205 dump.Print("\n");
14206
14207 rc = file.ReadInt( &userdata_copycount );
14208 if ( !rc )
14209 {
14210 Dump3dmChunk_ErrorReportHelper(offset,"ReadInt() failed to read the user data copy count.",dump);
14211 break;
14212 }
14213 dump.Print("UserData copy count = %d\n",userdata_copycount);
14214
14215 rc = file.ReadXform( userdata_xform );
14216 if ( !rc )
14217 {
14218 Dump3dmChunk_ErrorReportHelper(offset,"ReadXform() failed to read the user data xform.",dump);
14219 break;
14220 }
14221
14222 if ( 2 != major_userdata_version )
14223 break;
14224 if ( minor_userdata_version < 1 )
14225 break;
14226 rc = file.ReadUuid( userdata_appid );
14227 if ( !rc)
14228 {
14229 Dump3dmChunk_ErrorReportHelper(offset,"ReadUuid() failed to read the user data app plug-in id.",dump);
14230 break;
14231 }
14232 dump.Print("UserData app plug-in id = ");
14233 dump.Print( userdata_appid );
14234 dump.Print("\n");
14235 if ( minor_userdata_version < 2 )
14236 break;
14237 rc = file.ReadBool(&bLastSavedAsGoo);
14238 if (!rc)
14239 {
14240 Dump3dmChunk_ErrorReportHelper(offset,"ReadBool() failed to read the user data header bSavedAsGoo value.",dump);
14241 break;
14242 }
14243 rc = file.ReadInt( &ud_archive_3dm_version );
14244 if (!rc)
14245 {
14246 Dump3dmChunk_ErrorReportHelper(offset,"ReadBool() failed to read the user data header bSavedAsGoo value.",dump);
14247 break;
14248 }
14249 rc = file.ReadInt( &ud_archive_opennurbs_version );
14250 if (!rc)
14251 {
14252 Dump3dmChunk_ErrorReportHelper(offset,"ReadBool() failed to read the user data header bSavedAsGoo value.",dump);
14253 break;
14254 }
14255 if ( bLastSavedAsGoo )
14256 dump.Print("Userdata originally written by opennurbs %d in 3dm version %d and saved as goo in this file.\n",ud_archive_opennurbs_version,ud_archive_3dm_version);
14257 else
14258 dump.Print("Userdata written by opennurbs %d in 3dm version %d.\n",ud_archive_opennurbs_version,ud_archive_3dm_version);
14259
14260 break;
14261 }
14262
14263 if ( bCallEndRead3dmChunk )
14264 {
14265 if (!Dump3dmChunk_EndReadChunkHelper(file,offset0,tcode,big_value,dump))
14266 {
14267 if (rc)
14268 {
14269 Dump3dmChunk_ErrorReportHelper(offset,"EndRead3dmChunk() failed to close the TCODE_OPENNURBS_CLASS_USERDATA_HEADER chunk.",dump);
14270 }
14271 rc = false;
14272 }
14273 }
14274
14275 return rc;
14276 }
14277
14278
14279 unsigned int
Dump3dmChunk(ON_TextLog & dump,int recursion_depth)14280 ON_BinaryArchive::Dump3dmChunk( ON_TextLog& dump, int recursion_depth )
14281 {
14282 //ON_BinaryArchive& file = *this;
14283 const char* typecode_name = 0;
14284 bool bShortChunk = false;
14285 const size_t offset0 = CurrentPosition();
14286 unsigned int typecode = 0;
14287 ON__INT64 big_value;
14288 bool rc = BeginRead3dmBigChunk( &typecode, &big_value );
14289 if (!rc)
14290 {
14291 Dump3dmChunk_ErrorReportHelper(offset0,"BeginRead3dmChunk() failed.",dump);
14292 }
14293 else
14294 {
14295 if ( 0 == typecode )
14296 {
14297 Dump3dmChunk_ErrorReportHelper(offset0,"BeginRead3dmChunk() returned typecode = 0.",dump);
14298 EndRead3dmChunk();
14299 return 0;
14300 }
14301 else {
14302 if ( 0 == recursion_depth )
14303 {
14304 dump.Print("\n");
14305 }
14306
14307 ////bShortChunk = (0 != (typecode & TCODE_SHORT));
14308 typecode_name = ON_BinaryArchive::TypecodeName(typecode);
14309 bShortChunk = (0 != (typecode & TCODE_SHORT));
14310 if ( !DumpChunk_PrintHeaderInfo(offset0,typecode,big_value,typecode_name,dump) )
14311 {
14312 EndRead3dmChunk();
14313 return 0;
14314 }
14315
14316 int major_userdata_version = -1;
14317 int minor_userdata_version = -1;
14318
14319 switch( typecode )
14320 {
14321 case TCODE_PROPERTIES_TABLE:
14322 case TCODE_SETTINGS_TABLE:
14323 case TCODE_BITMAP_TABLE:
14324 case TCODE_MATERIAL_TABLE:
14325 case TCODE_LAYER_TABLE:
14326 case TCODE_GROUP_TABLE:
14327 case TCODE_LIGHT_TABLE:
14328 case TCODE_FONT_TABLE:
14329 case TCODE_DIMSTYLE_TABLE:
14330 case TCODE_HATCHPATTERN_TABLE:
14331 case TCODE_LINETYPE_TABLE:
14332 case TCODE_TEXTURE_MAPPING_TABLE:
14333 case TCODE_HISTORYRECORD_TABLE:
14334 case TCODE_USER_TABLE:
14335 case TCODE_INSTANCE_DEFINITION_TABLE:
14336 case TCODE_OBJECT_TABLE:
14337 // start of a table
14338 {
14339 dump.PushIndent();
14340 unsigned int record_typecode = 0;
14341 for (;;) {
14342 record_typecode = Dump3dmChunk( dump, recursion_depth+1 );
14343 if ( !record_typecode ) {
14344 break;
14345 }
14346 if ( TCODE_ENDOFTABLE == record_typecode ) {
14347 break;
14348 }
14349 }
14350 dump.PopIndent();
14351 }
14352 break;
14353
14354 case TCODE_PROPERTIES_OPENNURBS_VERSION:
14355 {
14356 dump.PushIndent();
14357 dump.Print("Version of opennurbs that wrote this file: %lld\n",big_value);
14358 dump.PopIndent();
14359 if ( 0 == m_3dm_opennurbs_version && big_value > 0 && big_value <= 299999999 )
14360 ON_SetBinaryArchiveOpenNURBSVersion(*this,(ON__INT32)big_value);
14361 }
14362 break;
14363
14364 case TCODE_BITMAP_RECORD:
14365 {
14366 dump.PushIndent();
14367 unsigned int bitmap_chunk_typecode = Dump3dmChunk( dump, recursion_depth+1 );
14368 if ( 0 == typecode )
14369 typecode = bitmap_chunk_typecode;
14370 dump.PopIndent();
14371 }
14372 break;
14373
14374 case TCODE_MATERIAL_RECORD:
14375 {
14376 dump.PushIndent();
14377 unsigned int material_chunk_typecode = Dump3dmChunk( dump, recursion_depth+1 );
14378 if ( 0 == typecode )
14379 typecode = material_chunk_typecode;
14380 dump.PopIndent();
14381 }
14382 break;
14383
14384 case TCODE_LAYER_RECORD:
14385 {
14386 dump.PushIndent();
14387 unsigned int material_chunk_typecode = Dump3dmChunk( dump, recursion_depth+1 );
14388 if ( 0 == typecode )
14389 typecode = material_chunk_typecode;
14390 dump.PopIndent();
14391 }
14392 break;
14393
14394 case TCODE_GROUP_RECORD:
14395 {
14396 dump.PushIndent();
14397 unsigned int group_chunk_typecode = Dump3dmChunk( dump, recursion_depth+1 );
14398 if ( 0 == typecode )
14399 typecode = group_chunk_typecode;
14400 dump.PopIndent();
14401 }
14402 break;
14403
14404 case TCODE_FONT_RECORD:
14405 {
14406 dump.PushIndent();
14407 unsigned int font_chunk_typecode = Dump3dmChunk( dump, recursion_depth+1 );
14408 if ( 0 == typecode )
14409 typecode = font_chunk_typecode;
14410 dump.PopIndent();
14411 }
14412 break;
14413
14414 case TCODE_DIMSTYLE_RECORD:
14415 {
14416 dump.PushIndent();
14417 unsigned int dimstyle_chunk_typecode = Dump3dmChunk( dump, recursion_depth+1 );
14418 if ( 0 == typecode )
14419 typecode = dimstyle_chunk_typecode;
14420 dump.PopIndent();
14421 }
14422 break;
14423
14424 case TCODE_LIGHT_RECORD:
14425 {
14426 dump.PushIndent();
14427 unsigned int light_chunk_typecode = 0;
14428 for (;;) {
14429 light_chunk_typecode = Dump3dmChunk( dump, recursion_depth+1 );
14430 if ( !light_chunk_typecode ) {
14431 break;
14432 }
14433 if ( TCODE_LIGHT_RECORD_END == light_chunk_typecode ) {
14434 break;
14435 }
14436 switch( light_chunk_typecode ) {
14437 //case TCODE_OBJECT_RECORD_TYPE:
14438 case TCODE_LIGHT_RECORD_ATTRIBUTES:
14439 case TCODE_LIGHT_RECORD_ATTRIBUTES_USERDATA:
14440 case TCODE_OPENNURBS_CLASS:
14441 break;
14442 default:
14443 {
14444 Dump3dmChunk_ErrorReportHelper(offset0,"Rogue chunk in light record.",dump);
14445 }
14446 }
14447 }
14448 dump.PopIndent();
14449 }
14450 break;
14451
14452 case TCODE_TEXTURE_MAPPING_RECORD:
14453 {
14454 dump.PushIndent();
14455 unsigned int mapping_chunk_typecode = Dump3dmChunk( dump, recursion_depth+1 );
14456 if ( !typecode )
14457 typecode = mapping_chunk_typecode;
14458 dump.PopIndent();
14459 }
14460 break;
14461
14462 case TCODE_HISTORYRECORD_RECORD:
14463 {
14464 dump.PushIndent();
14465 unsigned int history_chunk_typecode = Dump3dmChunk( dump, recursion_depth+1 );
14466 if ( !typecode )
14467 typecode = history_chunk_typecode;
14468 dump.PopIndent();
14469 }
14470 break;
14471
14472 case TCODE_HATCHPATTERN_RECORD:
14473 {
14474 dump.PushIndent();
14475 unsigned int hatch_chunk_typecode = Dump3dmChunk( dump, recursion_depth+1 );
14476 if ( !typecode )
14477 typecode = hatch_chunk_typecode;
14478 dump.PopIndent();
14479 }
14480 break;
14481
14482 case TCODE_INSTANCE_DEFINITION_RECORD:
14483 {
14484 dump.PushIndent();
14485 unsigned int idef_chunk_typecode = Dump3dmChunk( dump, recursion_depth+1 );
14486 if ( 0 == typecode )
14487 typecode = idef_chunk_typecode;
14488 dump.PopIndent();
14489 }
14490 break;
14491
14492 case TCODE_OBJECT_RECORD:
14493 {
14494 dump.PushIndent();
14495 unsigned int object_chunk_typecode = 0;
14496 for (;;) {
14497 object_chunk_typecode = Dump3dmChunk( dump, recursion_depth+1 );
14498 if ( !object_chunk_typecode ) {
14499 break;
14500 }
14501 if ( TCODE_OBJECT_RECORD_END == object_chunk_typecode ) {
14502 break;
14503 }
14504 switch( object_chunk_typecode ) {
14505 case TCODE_OBJECT_RECORD_TYPE:
14506 case TCODE_OBJECT_RECORD_ATTRIBUTES:
14507 case TCODE_OBJECT_RECORD_ATTRIBUTES_USERDATA:
14508 case TCODE_OPENNURBS_CLASS:
14509 break;
14510 default:
14511 {
14512 Dump3dmChunk_ErrorReportHelper(offset0,"Rogue chunk in object record.",dump);
14513 }
14514 }
14515 }
14516 dump.PopIndent();
14517 }
14518 break;
14519
14520 case TCODE_OBJECT_RECORD_ATTRIBUTES:
14521 {
14522 dump.PushIndent();
14523 if ( big_value < 14 )
14524 {
14525 Dump3dmChunk_ErrorReportHelper(offset0,"Length of chunk is too small. Should be >= 14.",dump);
14526 }
14527 else
14528 {
14529 ON_UUID uuid = ON_nil_uuid;
14530 int layer_index = -99;
14531 int mj = -1;
14532 int mn = -1;
14533 if ( !Read3dmChunkVersion(&mj,&mn))
14534 {
14535 Dump3dmChunk_ErrorReportHelper(offset0,"Read3dmChunkVersion() failed.",dump);
14536 }
14537 else if (!ReadUuid(uuid))
14538 {
14539 Dump3dmChunk_ErrorReportHelper(offset0,"ReadUuid() failed.",dump);
14540 }
14541 else if ( !ReadInt(&layer_index) )
14542 {
14543 Dump3dmChunk_ErrorReportHelper(offset0,"ReadInt() failed to read layer index.",dump);
14544 }
14545 else
14546 {
14547 dump.Print("Rhino object uuid: ");
14548 dump.Print(uuid);
14549 dump.Print("\n");
14550 dump.Print("layer index: %d\n",layer_index);
14551 }
14552 }
14553 dump.PopIndent();
14554 }
14555 break;
14556
14557 case TCODE_OPENNURBS_CLASS:
14558 {
14559 dump.PushIndent();
14560 unsigned int opennurbs_object_chunk_typecode = 0;
14561 for (;;) {
14562 opennurbs_object_chunk_typecode = Dump3dmChunk( dump, recursion_depth+1 );
14563 if ( !opennurbs_object_chunk_typecode ) {
14564 break;
14565 }
14566 if ( TCODE_OPENNURBS_CLASS_END == opennurbs_object_chunk_typecode ) {
14567 break;
14568 }
14569 switch( opennurbs_object_chunk_typecode )
14570 {
14571 case TCODE_OPENNURBS_CLASS_UUID:
14572 break;
14573 case TCODE_OPENNURBS_CLASS_DATA:
14574 break;
14575 case TCODE_OPENNURBS_CLASS_USERDATA:
14576 break;
14577 default:
14578 {
14579 Dump3dmChunk_ErrorReportHelper(offset0,"Rogue chunk in OpenNURBS class record.",dump);
14580 }
14581 }
14582 }
14583 dump.PopIndent();
14584 }
14585 break;
14586
14587 case TCODE_OPENNURBS_CLASS_USERDATA:
14588 {
14589 if ( !Read3dmChunkVersion(&major_userdata_version, &minor_userdata_version ) )
14590 {
14591 Dump3dmChunk_ErrorReportHelper(offset0,"Read3dmChunkVersion() failed to read TCODE_OPENNURBS_CLASS_USERDATA chunk version.",dump);
14592 }
14593 else
14594 {
14595 dump.PushIndent();
14596 dump.Print("UserData chunk version: %d.%d\n",
14597 major_userdata_version,
14598 minor_userdata_version
14599 );
14600 if ( 1 == major_userdata_version || 2 == major_userdata_version )
14601 {
14602 const size_t userdata_header_offset = CurrentPosition();
14603 switch ( major_userdata_version )
14604 {
14605 case 1:
14606 case 2:
14607 {
14608 // version 1 user data header information was not wrapped
14609 // in a chunk.
14610 //
14611 // version 2 user data header information is wrapped
14612 // in a TCODE_OPENNURBS_CLASS_USERDATA_HEADER chunk.
14613 if ( Dump3dmChunk_UserDataHeaderHelper(
14614 userdata_header_offset, *this,
14615 major_userdata_version, minor_userdata_version,
14616 dump )
14617 )
14618 {
14619 // a TCODE_ANONYMOUS_CHUNK contains user data goo
14620 int anon_typecode = Dump3dmChunk( dump, recursion_depth+1 );
14621 if ( TCODE_ANONYMOUS_CHUNK != anon_typecode )
14622 {
14623 Dump3dmChunk_ErrorReportHelper( offset0,"Userdata Expected a TCODE_ANONYMOUS_CHUNK chunk.",dump);
14624 }
14625 }
14626 }
14627 break;
14628 default:
14629 if ( major_userdata_version < 3 )
14630 {
14631 }
14632 else
14633 {
14634 dump.Print("New user data format created after this diagnostic tool was written.\n");
14635 }
14636 break;
14637 }
14638 }
14639
14640 dump.PopIndent();
14641 }
14642 }
14643 break;
14644
14645 case TCODE_OPENNURBS_CLASS_UUID:
14646 case TCODE_USER_TABLE_UUID:
14647 {
14648 dump.PushIndent();
14649 ON_UUID uuid = ON_nil_uuid;
14650 const ON_ClassId* pClassId = 0;
14651 if ( !ReadUuid( uuid ) ) {
14652 Dump3dmChunk_ErrorReportHelper(offset0,"ReadUuid() failed.",dump);
14653 }
14654 else
14655 {
14656 if ( typecode == TCODE_OPENNURBS_CLASS_UUID )
14657 {
14658 dump.Print("OpenNURBS class id = ");
14659 pClassId = ON_ClassId::ClassId(uuid);
14660 }
14661 else if ( typecode == TCODE_USER_TABLE_UUID )
14662 {
14663 dump.Print("User table id = ");
14664 }
14665 else {
14666 dump.Print("UUID = ");
14667 }
14668 dump.Print( uuid );
14669 if ( pClassId )
14670 {
14671 const char* sClassName = pClassId->ClassName();
14672 if ( sClassName )
14673 {
14674 dump.Print(" (%s)",sClassName);
14675 }
14676 }
14677 dump.Print("\n");
14678 }
14679
14680 dump.PopIndent();
14681 }
14682 break;
14683
14684 case TCODE_OPENNURBS_CLASS_USERDATA_HEADER:
14685 {
14686 // we should never get here because this chunk is parsed in the TCODE_OPENNURBS_CLASS_USERDATA case above.
14687 Dump3dmChunk_ErrorReportHelper(offset0,"Encountered TCODE_OPENNURBS_CLASS_USERDATA_HEADER chunk outside a TCODE_OPENNURBS_CLASS_USERDATA chunk.",dump);
14688 }
14689 break;
14690
14691 case TCODE_ENDOFFILE:
14692 case TCODE_ENDOFFILE_GOO:
14693 {
14694 dump.PushIndent();
14695 if ( big_value < 4 ) {
14696 Dump3dmChunk_ErrorReportHelper(offset0,"TCODE_ENDOFFILE chunk withlength < 4.",dump);
14697 }
14698 else {
14699 ON__UINT64 sizeof_file = 0;
14700 ReadEOFSizeOfFile(&sizeof_file);
14701 dump.Print("current position = %d stored size = %llu\n",
14702 CurrentPosition(),
14703 sizeof_file
14704 );
14705 }
14706 dump.PopIndent();
14707 }
14708 break;
14709
14710 }
14711 }
14712
14713 const size_t offset1 = CurrentPosition();
14714 if ( !EndRead3dmChunk(true) )
14715 {
14716 Dump3dmChunk_ErrorReportHelper(offset1,"EndRead3dmChunk() failed.",dump);
14717 rc = false;
14718 }
14719 else if (!bShortChunk)
14720 {
14721 ON__INT64 delta = (offset1 > offset0)
14722 ? ((ON__INT64)(offset1 - offset0))
14723 : -((ON__INT64)(offset0 - offset1));
14724 const ON__INT64 extra = big_value - (delta-4-SizeofChunkLength());
14725 if ( extra < 0 )
14726 {
14727 Dump3dmChunk_ErrorReportHelper(offset0,"Read beyond end of chunk.",dump);
14728 }
14729 }
14730 }
14731 return typecode;
14732 }
14733
14734
14735
ON_Read3dmBufferArchive(size_t sizeof_buffer,const void * buffer,bool bCopyBuffer,int archive_3dm_version,int archive_opennurbs_version)14736 ON_Read3dmBufferArchive::ON_Read3dmBufferArchive(
14737 size_t sizeof_buffer,
14738 const void* buffer,
14739 bool bCopyBuffer,
14740 int archive_3dm_version,
14741 int archive_opennurbs_version
14742 )
14743 : ON_BinaryArchive(ON::read3dm)
14744 , m_p(0)
14745 , m_buffer(0)
14746 , m_sizeof_buffer(0)
14747 , m_buffer_position(0)
14748 , m_reserved1(0)
14749 , m_reserved2(0)
14750 , m_reserved3(0)
14751 , m_reserved4(0)
14752 {
14753 if ( sizeof_buffer > 0 && 0 != buffer )
14754 {
14755 if ( bCopyBuffer )
14756 {
14757 m_p = onmalloc(sizeof_buffer);
14758 if ( 0 != m_p )
14759 memcpy(m_p,buffer,sizeof_buffer);
14760 m_buffer = (const unsigned char*)m_p;
14761 }
14762 else
14763 {
14764 m_buffer = (const unsigned char*)buffer;
14765 }
14766 if ( m_buffer )
14767 {
14768 m_sizeof_buffer = sizeof_buffer;
14769 SetArchive3dmVersion(archive_3dm_version);
14770 ON_SetBinaryArchiveOpenNURBSVersion(*this,archive_opennurbs_version);
14771 }
14772 }
14773 }
14774
~ON_Read3dmBufferArchive()14775 ON_Read3dmBufferArchive::~ON_Read3dmBufferArchive()
14776 {
14777 if ( m_p )
14778 onfree(m_p);
14779 }
14780
14781 // ON_BinaryArchive overrides
CurrentPosition() const14782 size_t ON_Read3dmBufferArchive::CurrentPosition() const
14783 {
14784 return m_buffer_position;
14785 }
14786
SeekFromCurrentPosition(int offset)14787 bool ON_Read3dmBufferArchive::SeekFromCurrentPosition( int offset )
14788 {
14789 bool rc = false;
14790 if ( m_buffer )
14791 {
14792 if (offset >= 0 )
14793 {
14794 m_buffer_position += offset;
14795 rc = true;
14796 }
14797 else if ( size_t(-offset) <= m_buffer_position )
14798 {
14799 m_buffer_position -= (size_t(-offset));
14800 rc = true;
14801 }
14802 }
14803 return rc;
14804 }
14805
SeekFromStart(size_t offset)14806 bool ON_Read3dmBufferArchive::SeekFromStart( size_t offset )
14807 {
14808 bool rc = false;
14809 if ( m_buffer )
14810 {
14811 if ( offset > 0 )
14812 m_buffer_position = offset;
14813 else
14814 m_buffer_position = 0;
14815 rc = true;
14816 }
14817 return rc;
14818 }
14819
AtEnd() const14820 bool ON_Read3dmBufferArchive::AtEnd() const
14821 {
14822 return (m_buffer_position >= m_sizeof_buffer) ? true : false;
14823 }
14824
Read(size_t count,void * buffer)14825 size_t ON_Read3dmBufferArchive::Read( size_t count, void* buffer )
14826 {
14827 if ( count <= 0 || 0 == buffer )
14828 return 0;
14829
14830 size_t maxcount = ( m_sizeof_buffer > m_buffer_position )
14831 ? (m_sizeof_buffer - m_buffer_position)
14832 : 0;
14833 if ( count > maxcount )
14834 count = maxcount;
14835
14836 if ( count > 0 )
14837 {
14838 memcpy( buffer, m_buffer+m_buffer_position, count );
14839 m_buffer_position += count;
14840 }
14841
14842 return count;
14843 }
14844
Write(size_t,const void *)14845 size_t ON_Read3dmBufferArchive::Write( size_t, const void* )
14846 {
14847 // ON_Read3dmBufferArchive does not support Write() and Flush()
14848 return 0;
14849 }
14850
Flush()14851 bool ON_Read3dmBufferArchive::Flush()
14852 {
14853 // ON_Read3dmBufferArchive does not support Write() and Flush()
14854 return false;
14855 }
14856
14857
SizeOfBuffer() const14858 size_t ON_Read3dmBufferArchive::SizeOfBuffer() const
14859 {
14860 return m_sizeof_buffer;
14861 }
14862
Buffer() const14863 const void* ON_Read3dmBufferArchive::Buffer() const
14864 {
14865 return (const void*)m_buffer;
14866 }
14867
14868
14869
14870
14871
ON_Write3dmBufferArchive(size_t initial_sizeof_buffer,size_t max_sizeof_buffer,int archive_3dm_version,int archive_opennurbs_version)14872 ON_Write3dmBufferArchive::ON_Write3dmBufferArchive(
14873 size_t initial_sizeof_buffer,
14874 size_t max_sizeof_buffer,
14875 int archive_3dm_version,
14876 int archive_opennurbs_version
14877 )
14878 : ON_BinaryArchive(ON::write3dm)
14879 , m_p(0)
14880 , m_buffer(0)
14881 , m_sizeof_buffer(0)
14882 , m_max_sizeof_buffer(max_sizeof_buffer)
14883 , m_sizeof_archive(0)
14884 , m_buffer_position(0)
14885 , m_reserved1(0)
14886 , m_reserved2(0)
14887 , m_reserved3(0)
14888 , m_reserved4(0)
14889 {
14890 if ( initial_sizeof_buffer > 0 )
14891 AllocBuffer(initial_sizeof_buffer);
14892 if ( archive_3dm_version < 2 )
14893 archive_3dm_version = ON_BinaryArchive::CurrentArchiveVersion();
14894 SetArchive3dmVersion(archive_3dm_version);
14895 ON_SetBinaryArchiveOpenNURBSVersion(*this,archive_opennurbs_version);
14896 }
14897
~ON_Write3dmBufferArchive()14898 ON_Write3dmBufferArchive::~ON_Write3dmBufferArchive()
14899 {
14900 if ( m_p )
14901 onfree(m_p);
14902 }
14903
AllocBuffer(size_t sz)14904 void ON_Write3dmBufferArchive::AllocBuffer( size_t sz )
14905 {
14906 if ( sz > m_sizeof_buffer
14907 && (m_max_sizeof_buffer <= 0 || sz <= m_max_sizeof_buffer)
14908 )
14909 {
14910 if ( sz < 2*m_sizeof_buffer )
14911 {
14912 sz = 2*m_sizeof_buffer;
14913 if ( sz > m_max_sizeof_buffer )
14914 sz = m_max_sizeof_buffer;
14915 }
14916
14917 m_p = onrealloc(m_p,sz);
14918 m_buffer = (unsigned char*)m_p;
14919
14920 if ( 0 != m_buffer )
14921 {
14922 memset( m_buffer + m_sizeof_buffer, 0, sz - m_sizeof_buffer );
14923 m_sizeof_buffer = sz;
14924 }
14925 else
14926 {
14927 m_sizeof_buffer = 0;
14928 }
14929
14930 }
14931 }
14932
14933 // ON_BinaryArchive overrides
CurrentPosition() const14934 size_t ON_Write3dmBufferArchive::CurrentPosition() const
14935 {
14936 return m_buffer_position;
14937 }
14938
SeekFromCurrentPosition(int offset)14939 bool ON_Write3dmBufferArchive::SeekFromCurrentPosition( int offset )
14940 {
14941 bool rc = false;
14942 if ( m_buffer )
14943 {
14944 if (offset >= 0 )
14945 {
14946 m_buffer_position += offset;
14947 rc = true;
14948 }
14949 else if ( size_t(-offset) <= m_buffer_position )
14950 {
14951 m_buffer_position -= (size_t(-offset));
14952 rc = true;
14953 }
14954 }
14955 return rc;
14956 }
14957
SeekFromStart(size_t offset)14958 bool ON_Write3dmBufferArchive::SeekFromStart( size_t offset )
14959 {
14960 bool rc = false;
14961 if ( m_buffer )
14962 {
14963 if ( offset > 0 )
14964 m_buffer_position = offset;
14965 else
14966 m_buffer_position = 0;
14967 rc = true;
14968 }
14969 return rc;
14970 }
14971
AtEnd() const14972 bool ON_Write3dmBufferArchive::AtEnd() const
14973 {
14974 return (m_buffer_position >= m_sizeof_buffer) ? true : false;
14975 }
14976
Read(size_t count,void * buffer)14977 size_t ON_Write3dmBufferArchive::Read( size_t count, void* buffer )
14978 {
14979 if ( count <= 0 || 0 == buffer )
14980 return 0;
14981
14982 size_t maxcount = ( m_sizeof_buffer > m_buffer_position )
14983 ? (m_sizeof_buffer - m_buffer_position)
14984 : 0;
14985 if ( count > maxcount )
14986 count = maxcount;
14987
14988 if ( count > 0 )
14989 {
14990 memcpy( buffer, m_buffer+m_buffer_position, count );
14991 m_buffer_position += count;
14992 }
14993
14994 return count;
14995 }
14996
Write(size_t sz,const void * buffer)14997 size_t ON_Write3dmBufferArchive::Write( size_t sz, const void* buffer )
14998 {
14999 if ( sz <= 0 || 0 == buffer )
15000 return 0;
15001
15002 if ( m_buffer_position + sz > m_sizeof_buffer )
15003 {
15004 AllocBuffer(m_buffer_position + sz);
15005 }
15006
15007 if ( m_buffer_position + sz > m_sizeof_buffer )
15008 return 0;
15009
15010 memcpy( m_buffer + m_buffer_position, buffer, sz );
15011 m_buffer_position += sz;
15012 if ( m_buffer_position > m_sizeof_archive )
15013 m_sizeof_archive = m_buffer_position;
15014
15015 return sz;
15016 }
15017
Flush()15018 bool ON_Write3dmBufferArchive::Flush()
15019 {
15020 // Nothing to flush
15021 return true;
15022 }
15023
15024
SizeOfBuffer() const15025 size_t ON_Write3dmBufferArchive::SizeOfBuffer() const
15026 {
15027 return m_sizeof_buffer;
15028 }
15029
Buffer() const15030 const void* ON_Write3dmBufferArchive::Buffer() const
15031 {
15032 return (const void*)m_buffer;
15033 }
15034
HarvestBuffer()15035 void* ON_Write3dmBufferArchive::HarvestBuffer()
15036 {
15037 void* buffer = m_buffer;
15038
15039 m_p = 0;
15040 m_buffer = 0;
15041 m_sizeof_buffer = 0;
15042 m_sizeof_archive = 0;
15043 m_buffer_position = 0;
15044
15045 return buffer;
15046 }
15047
SizeOfArchive() const15048 size_t ON_Write3dmBufferArchive::SizeOfArchive() const
15049 {
15050 return m_sizeof_archive;
15051 }
15052
15053
15054
15055
ON_BinaryArchiveBuffer(ON::archive_mode mode,ON_Buffer * buffer)15056 ON_BinaryArchiveBuffer::ON_BinaryArchiveBuffer( ON::archive_mode mode, ON_Buffer* buffer )
15057 : ON_BinaryArchive(mode)
15058 , m_buffer(buffer)
15059 {
15060 }
15061
~ON_BinaryArchiveBuffer()15062 ON_BinaryArchiveBuffer::~ON_BinaryArchiveBuffer()
15063 {
15064 m_buffer = 0;
15065 }
15066
SetBuffer(ON_Buffer * buffer)15067 bool ON_BinaryArchiveBuffer::SetBuffer( ON_Buffer* buffer )
15068 {
15069 if ( 0 == m_buffer )
15070 {
15071 m_buffer = buffer;
15072 return true;
15073 }
15074
15075 return false;
15076 }
15077
Buffer() const15078 ON_Buffer* ON_BinaryArchiveBuffer::Buffer() const
15079 {
15080 return m_buffer;
15081 }
15082
CurrentPosition() const15083 size_t ON_BinaryArchiveBuffer::CurrentPosition() const
15084 {
15085 if ( 0 != m_buffer )
15086 return (size_t)m_buffer->CurrentPosition();
15087
15088 return 0;
15089 }
15090
SeekFromCurrentPosition(int offset)15091 bool ON_BinaryArchiveBuffer::SeekFromCurrentPosition(int offset)
15092 {
15093 if ( 0 != m_buffer )
15094 return m_buffer->SeekFromCurrentPosition(offset);
15095
15096 return false;
15097 }
15098
SeekFromStart(size_t offset)15099 bool ON_BinaryArchiveBuffer::SeekFromStart(size_t offset)
15100 {
15101 if ( 0 != m_buffer )
15102 return m_buffer->SeekFromStart((ON__INT64)offset);
15103
15104 return false;
15105 }
15106
AtEnd() const15107 bool ON_BinaryArchiveBuffer::AtEnd() const
15108 {
15109 if ( 0 != m_buffer )
15110 return m_buffer->AtEnd();
15111
15112 return false;
15113 }
15114
SeekFromEnd(ON__INT64 offset)15115 bool ON_BinaryArchiveBuffer::SeekFromEnd( ON__INT64 offset )
15116 {
15117 if ( 0 != m_buffer )
15118 return m_buffer->SeekFromEnd(offset);
15119
15120 return false;
15121 }
15122
Read(size_t count,void * a)15123 size_t ON_BinaryArchiveBuffer::Read( size_t count, void* a )
15124 {
15125 if ( 0 != m_buffer )
15126 return (size_t)m_buffer->Read(count,a);
15127
15128 return 0;
15129 }
15130
Write(size_t count,const void * a)15131 size_t ON_BinaryArchiveBuffer::Write( size_t count, const void* a )
15132 {
15133 if ( 0 != m_buffer )
15134 return (size_t)m_buffer->Write(count,a);
15135
15136 return 0;
15137 }
15138
Flush()15139 bool ON_BinaryArchiveBuffer::Flush()
15140 {
15141 if ( 0 != m_buffer )
15142 return true;
15143
15144 return false;
15145 }
15146
ON_FileIterator()15147 ON_FileIterator::ON_FileIterator()
15148 : m_count(0)
15149 #if defined(ON_COMPILER_MSC)
15150 , m_file_attributes_mask(0)
15151 , m_h(0)
15152 #else
15153 , m_dir(0)
15154 , m_current_file_attributes(0)
15155 , m_current_file_size(0)
15156 , m_current_file_create_time(0)
15157 , m_current_last_modified_time(0)
15158 , m_current_last_access_time(0)
15159 #endif
15160 {
15161 Destroy();
15162 #if defined(ON_COMPILER_MSC)
15163 memset(&m_fd,0,sizeof(m_fd));
15164 #else
15165 memset(&m_dirent,0,sizeof(m_dirent));
15166 m_dirent.d_name[0] = 0;
15167 memset(&m_dirent_name_buffer[0],0,sizeof(m_dirent_name_buffer));
15168 memset(&m_current_name[0],0,sizeof(m_current_name));
15169 #endif
15170 }
15171
~ON_FileIterator()15172 ON_FileIterator::~ON_FileIterator()
15173 {
15174 Destroy();
15175 }
15176
Destroy()15177 void ON_FileIterator::Destroy()
15178 {
15179 #if defined(ON_COMPILER_MSC)
15180 if ( 0 != m_h )
15181 {
15182 ::FindClose(m_h);
15183 m_h = 0;
15184 }
15185 m_file_attributes_mask = 0;
15186 memset(&m_fd,0,sizeof(m_fd));
15187 #else
15188 if ( 0 != m_dir )
15189 {
15190 closedir(m_dir);
15191 m_dir = 0;
15192 }
15193 memset(&m_dirent,0,sizeof(m_dirent));
15194 m_dirent.d_name[0] = 0;
15195 memset(&m_dirent_name_buffer[0],0,sizeof(m_dirent_name_buffer));
15196 m_ws_file_name_filter.Destroy();
15197 m_utf8_file_name_filter.Destroy();
15198 memset(&m_current_name[0],0,sizeof(m_current_name));
15199 m_current_file_attributes = 0;
15200 m_current_file_size = 0;
15201 m_current_file_create_time = 0;
15202 m_current_last_modified_time = 0;
15203 m_current_last_access_time = 0;
15204 #endif
15205 m_count = 0;
15206 m_directory.Empty();
15207 }
15208
Count() const15209 ON__UINT64 ON_FileIterator::Count() const
15210 {
15211 return m_count;
15212 }
15213
15214 #if defined(ON_COMPILER_MSC)
IsDotOrDotDotDir(const wchar_t * s)15215 static bool IsDotOrDotDotDir( const wchar_t* s )
15216 #else
15217 static bool IsDotOrDotDotDir( const char* s )
15218 #endif
15219 {
15220 bool rc = false;
15221 for (;;)
15222 {
15223 if ( 0 == s )
15224 break;
15225 if ( '.' != s[0] )
15226 break;
15227 if ( 0 != s[1] )
15228 {
15229 if ( '.' != s[1] )
15230 break;
15231 if ( 0 != s[2] )
15232 break;
15233 }
15234 rc = true; // s = "." or s = ".."
15235 break;
15236 }
15237 return rc;
15238 }
15239
FirstFile(const char * directory_name,const char * file_name_filter)15240 const wchar_t* ON_FileIterator::FirstFile(
15241 const char* directory_name,
15242 const char* file_name_filter
15243 )
15244 {
15245 // assume directory_name and file_name_filter are UTF-8 encoded
15246 // strings, convert them to wchar_t strings and call the
15247 // wchar_t version of this function.
15248 ON_wString ws_directory_name = directory_name;
15249 ON_wString ws_file_name_filter = file_name_filter;
15250 const wchar_t* wchar_directory_name = ws_directory_name;
15251 const wchar_t* wchar_file_name_filter = ws_file_name_filter;
15252 return FirstFile(wchar_directory_name,wchar_file_name_filter);
15253 }
15254
FirstFile(const wchar_t * directory_name,const wchar_t * file_name_filter)15255 const wchar_t* ON_FileIterator::FirstFile(
15256 const wchar_t* directory_name,
15257 const wchar_t* file_name_filter
15258 )
15259 {
15260 ON_wString buffer(directory_name);
15261 {
15262 const wchar_t* dir_seps = L"/\\";
15263 buffer.TrimRight(dir_seps);
15264 if ( buffer.Length() <= 0 || buffer.IsEmpty() )
15265 buffer = directory_name;
15266 else
15267 directory_name = buffer;
15268 }
15269
15270 #if defined(ON_COMPILER_MSC)
15271 const ON__UINT32 saved_mask = m_file_attributes_mask;
15272 Destroy();
15273 m_file_attributes_mask = saved_mask;
15274
15275 ON_wString s(directory_name);
15276
15277
15278 if ( 0 == file_name_filter )
15279 {
15280 // A null file file_name_filter means iterate
15281 // through all items in the directory. To do
15282 // this using Windows' ::FindFirstFile, set the
15283 // filter to "*.*", even though some items will
15284 // not contain a "dot".
15285 file_name_filter = L"*.*";
15286 }
15287
15288 if ( 0 != file_name_filter[0] )
15289 {
15290 s += L"\\";
15291 s += file_name_filter;
15292 }
15293
15294 m_h = ::FindFirstFile(s, &m_fd);
15295 if ( 0 == m_h || INVALID_HANDLE_VALUE == m_h || 0 == m_fd.cFileName[0] )
15296 {
15297 // Happens on "fake" directories like "My Music" and "My Videos"
15298 m_h = 0;
15299 Destroy();
15300 m_file_attributes_mask = saved_mask;
15301 return 0;
15302 }
15303
15304 m_directory = directory_name;
15305
15306 if ( IsDotOrDotDotDir(m_fd.cFileName) || 0 != (m_file_attributes_mask & m_fd.dwFileAttributes) )
15307 {
15308 return NextFile();
15309 }
15310
15311 m_count++;
15312 m_fd.cFileName[(sizeof(m_fd.cFileName)/sizeof(m_fd.cFileName[0]))-1] = 0;
15313 return m_fd.cFileName;
15314
15315 #else
15316
15317 // gcc code
15318 Destroy();
15319 m_directory = directory_name;
15320 m_ws_file_name_filter = file_name_filter;
15321 m_utf8_file_name_filter = file_name_filter;
15322 const ON_String utf8_str(m_directory); // convert wchar_t to utf8 string
15323 const char* s = utf8_str;
15324 m_dir = (0 != s && 0 != s[0]) ? opendir(s) : 0;
15325 if ( 0 != m_dir )
15326 return NextFile();
15327 Destroy();
15328 return 0;
15329
15330 #endif
15331 }
15332
NextFile()15333 const wchar_t* ON_FileIterator::NextFile()
15334 {
15335 #if defined(ON_COMPILER_MSC)
15336 const ON__UINT32 saved_mask = m_file_attributes_mask;
15337 if ( 0 == m_h || INVALID_HANDLE_VALUE == m_h || 0 == m_fd.cFileName[0] )
15338 {
15339 Destroy();
15340 m_file_attributes_mask = saved_mask;
15341 return 0;
15342 }
15343
15344 for (;;)
15345 {
15346 if ( !::FindNextFile( m_h, &m_fd) || 0 == m_fd.cFileName[0] )
15347 {
15348 Destroy();
15349 m_file_attributes_mask = saved_mask;
15350 return 0;
15351 }
15352
15353 if ( IsDotOrDotDotDir(m_fd.cFileName) || 0 != (m_file_attributes_mask & m_fd.dwFileAttributes) )
15354 {
15355 continue;
15356 }
15357
15358 break;
15359 }
15360
15361 m_count++;
15362 m_fd.cFileName[(sizeof(m_fd.cFileName)/sizeof(m_fd.cFileName[0]))-1] = 0;
15363 return m_fd.cFileName;
15364 #else
15365
15366 // gcc code
15367 ON__UINT64 current_file_attributes = 0;
15368 wchar_t current_name[ sizeof(m_current_name)/sizeof(m_current_name[0]) ];
15369 for(;;)
15370 {
15371 current_file_attributes = 0;
15372 struct dirent* dp = 0;
15373 //G+Smo
15374 # ifndef __MINGW32__
15375 dp = readdir(m_dir);
15376 //int readdir_errno = readdir_r(m_dir, &m_dirent, &dp);
15377 //if ( 0 != readdir_errno )
15378 // break;
15379 # endif
15380 if ( 0 != dp )
15381 m_dirent = *dp;
15382 else
15383 break;
15384
15385 if ( 0 == m_dirent.d_name[0] )
15386 break;
15387
15388 if ( IsDotOrDotDotDir(m_dirent.d_name) )
15389 continue;
15390
15391 memset( current_name, 0, sizeof(current_name) );
15392 ON_ConvertUTF8ToWideChar(
15393 false, // no BOM in input file name as utf8 string
15394 &m_dirent.d_name[0],
15395 -1, // null terminated utf8 string
15396 ¤t_name[0], ((int)(sizeof(current_name)/sizeof(current_name[0]))) - 1, // output wchar_t string
15397 0, // null output error status
15398 (4|8|16), // mask common conversion errors
15399 0, // error_code_point = null terminator inserted at point of conversion error
15400 0 // null ouput end-of-string pointer
15401 );
15402 // TODO
15403 // Test m_dirent.d_name to make sure it passes m_ws/utf8_file_name_filter
15404
15405 ON_wString wpath = m_directory;
15406 wpath += '/';
15407 wpath += current_name;
15408
15409 // get a utf8 version of the full path to pass to stat
15410 const ON_String utf8buffer(wpath);
15411 const char* utf8path = utf8buffer;
15412 if ( 0 == utf8path )
15413 continue;
15414
15415 struct stat buf;
15416 memset(&buf,0,sizeof(buf));
15417 int stat_errno = stat( utf8path, &buf);
15418 if ( 0 != stat_errno )
15419 continue;
15420
15421 if ( S_ISDIR(buf.st_mode) )
15422 {
15423 current_file_attributes = 2;
15424 }
15425 else if ( S_ISREG(buf.st_mode) )
15426 {
15427 // Only *.ext filters work at this time for non-windows
15428 const wchar_t* file_name_filter = m_ws_file_name_filter;
15429 if ( 0 != file_name_filter
15430 && '*' == file_name_filter[0]
15431 && '.' == file_name_filter[1]
15432 && 0 != file_name_filter[2]
15433 && '*' != file_name_filter[2] )
15434 {
15435 // assume this is a *.extension filter
15436 const wchar_t* current_name_ext = 0;
15437 on_wsplitpath(current_name,0,0,0,¤t_name_ext);
15438 if ( 0 == current_name_ext
15439 || 0 != wcscmp(file_name_filter+1,current_name_ext)
15440 )
15441 {
15442 // current_name does pass match file_name_filter
15443 continue;
15444 }
15445 }
15446 current_file_attributes = 1;
15447 }
15448 else
15449 continue;
15450
15451 // save current item information
15452 memcpy( m_current_name, current_name, sizeof(m_current_name) );
15453 m_current_file_attributes = current_file_attributes;
15454 m_current_file_size = buf.st_size;
15455 m_current_file_create_time = buf.st_mtime; // create time is not available on struct stat
15456 m_current_last_modified_time = buf.st_mtime;
15457 m_current_last_access_time = buf.st_atime;
15458
15459 return m_current_name;
15460 }
15461
15462 Destroy();
15463 return 0;
15464 #endif
15465 }
15466
15467
CurrentFileName() const15468 const wchar_t* ON_FileIterator::CurrentFileName() const
15469 {
15470 #if defined(ON_COMPILER_MSC)
15471 return ( 0 != m_h && 0 != m_fd.cFileName[0] ) ? m_fd.cFileName : 0;
15472 #else
15473 return ( 0 != m_current_name[0] ) ? m_current_name : 0;
15474 #endif
15475 }
15476
CurrentFileSize() const15477 ON__UINT64 ON_FileIterator::CurrentFileSize() const
15478 {
15479 ON__UINT64 file_size = 0;
15480
15481 #if defined(ON_COMPILER_MSC)
15482 if ( 0 != CurrentFileName() )
15483 {
15484 file_size = m_fd.nFileSizeHigh;
15485 file_size *= ((ON__UINT64)0xFFFFFFFF);
15486 file_size += m_fd.nFileSizeLow;
15487 }
15488 #else
15489 file_size = m_current_file_size;
15490 #endif
15491
15492 return file_size;
15493 }
15494
CurrentFileIsDirectory() const15495 bool ON_FileIterator::CurrentFileIsDirectory() const
15496 {
15497 bool rc = false;
15498 const wchar_t* current_file_name = CurrentFileName();
15499 if ( 0 != current_file_name && 0 != current_file_name[0] )
15500 {
15501 #if defined(ON_COMPILER_MSC)
15502 if ( 0 != (FILE_ATTRIBUTE_DIRECTORY & m_fd.dwFileAttributes) )
15503 {
15504 rc = true;
15505 }
15506 #else
15507 if ( 2 == m_current_file_attributes)
15508 {
15509 rc = true;
15510 }
15511 #endif
15512 }
15513 return rc;
15514 }
15515
CurrentFileIsHidden() const15516 bool ON_FileIterator::CurrentFileIsHidden() const
15517 {
15518 bool rc = false;
15519 const wchar_t* current_file_name = CurrentFileName();
15520 if ( 0 != current_file_name && 0 != current_file_name[0] )
15521 {
15522 if ( '.' == current_file_name[0] )
15523 {
15524 rc = true;
15525 }
15526 #if defined(ON_COMPILER_MSC)
15527 else if ( 0 != (FILE_ATTRIBUTE_HIDDEN & m_fd.dwFileAttributes) )
15528 {
15529 rc = true;
15530 }
15531 #endif
15532 }
15533 return rc;
15534 }
15535
15536
GetCurrentFullPathFileName(ON_wString & filename) const15537 bool ON_FileIterator::GetCurrentFullPathFileName( ON_wString& filename ) const
15538 {
15539 bool rc = false;
15540
15541 #if defined(ON_COMPILER_MSC)
15542 if ( 0 == m_h || 0 == m_fd.cFileName )
15543 {
15544 filename.Empty();
15545 }
15546 else
15547 {
15548 filename = m_directory;
15549 filename += L"\\";
15550 filename += m_fd.cFileName;
15551 rc = true;
15552 }
15553 #else
15554
15555 // gcc implementation
15556 if ( 0 == m_current_name[0] )
15557 {
15558 filename.Empty();
15559 }
15560 else
15561 {
15562 filename = m_directory;
15563 filename += L"/";
15564 filename += m_current_name;
15565 rc = true;
15566 }
15567
15568 #endif
15569
15570 return rc;
15571 }
15572
15573
15574 #if defined(ON_COMPILER_MSC)
SecondsSinceJanOne1970(FILETIME ft)15575 static ON__UINT64 SecondsSinceJanOne1970( FILETIME ft )
15576 {
15577 // The FILETIME is in 100-nanosecond intervals since January 1, 1601 UCT.
15578 //
15579 // Between midnight January 1, 1601 and midnight January 1, 1970 there
15580 // were 134774 days = 11644473600 seconds. Each second has 10^7 intervals
15581 // that are one hundred nanoseconds long. So, if N = number of one hundred
15582 // nanosecond intervals since midnight January 1, 1601, then
15583 // (N / 10000000) - 11644473600 = number of seconds since midnight
15584 // January 1, 1970.
15585 //
15586 // January 1, 1601 was the start of a Gregorian calendary 400 year cycle
15587 // and "the internet" sometimes cites that as the reason that date is
15588 // the "beginning of time" for Windows' FILETIME values. This convention
15589 // would slightly simplify the formulae used to account for leap years,
15590 // so it is plausable this might might even be true.
15591
15592 ON__UINT64 ft_since_jan_1_1601 = ft.dwHighDateTime;
15593 ft_since_jan_1_1601 *= 0xFFFFFFFF;
15594 ft_since_jan_1_1601 += ft.dwLowDateTime;
15595
15596 ON__UINT64 hundrednanoseconds_per_second = 10000000;
15597
15598 ON__UINT64 seconds_since_jan_1_1601 = ft_since_jan_1_1601 / hundrednanoseconds_per_second;
15599
15600 ON__UINT64 seconds_since_jan_1_1970 = seconds_since_jan_1_1601 - 11644473600;
15601
15602 return seconds_since_jan_1_1970;
15603 }
15604 #endif
15605
CurrentFileCreateTime() const15606 ON__UINT64 ON_FileIterator::CurrentFileCreateTime() const
15607 {
15608 #if defined(ON_COMPILER_MSC)
15609 return SecondsSinceJanOne1970(m_fd.ftCreationTime);
15610 #else
15611 return m_current_file_create_time;
15612 #endif
15613 }
15614
CurrentFileLastModifiedTime() const15615 ON__UINT64 ON_FileIterator::CurrentFileLastModifiedTime() const
15616 {
15617 #if defined(ON_COMPILER_MSC)
15618 return SecondsSinceJanOne1970(m_fd.ftLastWriteTime);
15619 #else
15620 return m_current_last_modified_time;
15621 #endif
15622 }
15623
CurrentFileLastAccessTime() const15624 ON__UINT64 ON_FileIterator::CurrentFileLastAccessTime() const
15625 {
15626 #if defined(ON_COMPILER_MSC)
15627 return SecondsSinceJanOne1970(m_fd.ftLastAccessTime);
15628 #else
15629 return m_current_last_access_time;
15630 #endif
15631 }
15632
15633