opennurbs_embedded_file.cpp
Go to the documentation of this file.
00001 /* $NoKeywords: $ */
00002 /*
00003 //
00004 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
00005 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
00006 // McNeel & Associates.
00007 //
00008 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
00009 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
00010 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
00011 //                              
00012 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
00013 //
00015 */
00016 
00017 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
00018 
00019 
00020 ON_Buffer::ON_Buffer()
00021 : m_buffer_size(0)
00022 , m_current_position(0)
00023 , m_first_segment(0)
00024 , m_last_segment(0)
00025 , m_current_segment(0)
00026 , m_heap(0)
00027 , m_error_handler(0)
00028 , m_last_error(0)
00029 {
00030   memset(m_reserved,0,sizeof(m_reserved));
00031 }
00032 
00033 
00034 void ON_Buffer::Destroy()
00035 {
00036   ChangeSize(0);
00037 }
00038 
00039 void ON_Buffer::EmergencyDestroy()
00040 {
00041   m_buffer_size = 0;
00042   m_current_position = 0;
00043   m_first_segment = 0;
00044   m_last_segment = 0;
00045   m_current_segment = 0;
00046   m_heap = 0;
00047   m_error_handler = 0;
00048   m_last_error = 0;
00049 }
00050 
00051 struct ON_BUFFER_SEGMENT
00052 {
00053   struct ON_BUFFER_SEGMENT* m_prev_segment;
00054   struct ON_BUFFER_SEGMENT* m_next_segment;
00055   ON__UINT64 m_segment_position0; // postion of first byte in this segment
00056   ON__UINT64 m_segment_position1; // position of the first byte in the next segment
00057                                   // When a segment is the last one in an ON_Buffer,
00058                                   // is is common for m_segment_position1 > m_buffer_size.
00059   unsigned char* m_segment_buffer; // null or an array of length (m_segment_position1 - m_segment_position0)
00060   void* m_reserved;
00061 };
00062 
00063 int ON_Buffer::Compare( const ON_Buffer& a, const ON_Buffer& b )
00064 {
00065   if ( &a == &b )
00066     return 0;
00067   if ( a.m_buffer_size < b.m_buffer_size )
00068     return -1;
00069   if ( a.m_buffer_size > b.m_buffer_size )
00070     return 1;
00071 
00072   struct ON_BUFFER_SEGMENT* aseg = a.m_first_segment;
00073   struct ON_BUFFER_SEGMENT* bseg = b.m_first_segment;
00074   const ON__UINT64 buffer_size = a.m_buffer_size;
00075   ON__UINT64 size = 0;
00076   size_t aoffset = 0;
00077   size_t boffset = 0;
00078   size_t asegsize = 0;
00079   size_t bsegsize = 0;  
00080   size_t asize = 0;
00081   size_t bsize = 0;  
00082   size_t sz;
00083   int rc = 0;
00084 
00085   while ( 0 != aseg && 0 != bseg && size < buffer_size )
00086   {
00087     if ( 0 == asegsize )
00088     {
00089       if ( aseg->m_segment_position0 >= aseg->m_segment_position1 )
00090       {
00091         aseg = aseg->m_next_segment;
00092         continue;
00093       }
00094       asegsize = (size_t)(aseg->m_segment_position1 - aseg->m_segment_position0);
00095       aoffset = 0;
00096     }
00097 
00098     if ( 0 == bsegsize )
00099     {
00100       if ( bseg->m_segment_position0 >= bseg->m_segment_position1 )
00101       {
00102         bseg = bseg->m_next_segment;
00103         continue;
00104       }
00105       bsegsize = (size_t)(bseg->m_segment_position1 - bseg->m_segment_position0);
00106       boffset = 0;
00107     }
00108     
00109     if ( aoffset >= asegsize )
00110     {
00111       asegsize = 0;
00112       aseg = aseg->m_next_segment;
00113       continue;
00114     }
00115 
00116     if ( boffset >= bsegsize )
00117     {
00118       bsegsize = 0;
00119       bseg = bseg->m_next_segment;
00120       continue;
00121     }
00122 
00123     if ( 0 == aseg->m_segment_buffer )
00124     {
00125       return (0 == bseg->m_segment_buffer) ? 0 : -1;
00126     }
00127 
00128     if ( 0 == bseg->m_segment_buffer )
00129     {
00130       return 1;
00131     }
00132 
00133     asize = asegsize - aoffset;
00134     bsize = bsegsize - boffset;
00135     sz = (asize <= bsize) ? asize : bsize;
00136     if ( size + sz > buffer_size )
00137       sz = (size_t)(buffer_size - size);
00138     rc = memcmp( aseg->m_segment_buffer + aoffset, bseg->m_segment_buffer + boffset, (size_t)sz );
00139     if ( 0 != rc )
00140       return ((rc<0)?-1:1);
00141     aoffset += sz;
00142     boffset += sz;
00143     size += sz;
00144   }
00145 
00146   return 0;
00147 }
00148 
00149 
00150 ON_Buffer::~ON_Buffer()
00151 {
00152   ChangeSize(0); // frees all heap and zeros everything but m_current_position.
00153   m_current_position = 0;
00154 }
00155 
00156 ON_Buffer::ON_Buffer( const ON_Buffer& src )
00157 : m_buffer_size(0)
00158 , m_current_position(0)
00159 , m_first_segment(0)
00160 , m_last_segment(0)
00161 , m_current_segment(0)
00162 , m_heap(src.m_heap)
00163 , m_error_handler(0)
00164 , m_last_error(0)
00165 {
00166   memset(m_reserved,0,sizeof(m_reserved));
00167   Copy(src);
00168 }
00169 
00170 ON_Buffer& ON_Buffer::operator=( const ON_Buffer& src )
00171 {
00172   if ( this != &src )
00173   {
00174     ChangeSize(0); // frees all heap and zeros everything but m_current_position.
00175     m_current_position = 0;
00176     Copy(src);
00177   }
00178   return *this;
00179 }
00180 
00181 bool ON_Buffer::Seek( ON__INT64 offset, int origin )
00182 {
00183   ON__UINT64 pos0, pos1;
00184 
00185   switch(origin)
00186   {
00187   case 0: // Seek from beginning of start.
00188     pos0 = 0;
00189     break;
00190 
00191   case 1: // Seek from current position.
00192     pos0 = m_current_position;
00193     break;
00194 
00195   case 2: // Seek from end.
00196     pos0 = m_buffer_size;
00197     break;
00198 
00199   default:
00200     {
00201       ON_ERROR("Invalid origin parameter");
00202       return false;
00203     }
00204     break;
00205   }
00206 
00207   if ( offset < 0 )
00208   {
00209     if ( pos0 < (ON__UINT64)(-offset) )
00210     {
00211       // current position cannot be negative
00212       ON_ERROR("Attempt to seek before start of buffer.");
00213       return false; 
00214     }    
00215     pos1 = pos0 - (ON__UINT64)(-offset); // overflow cannot happen in this operation
00216   }
00217   else if ( offset > 0 )
00218   {
00219     // current position can be >= m_buffer_size
00220     pos1 = pos0 + (ON__UINT64)(offset); // overflow is possible in this operation
00221     if ( pos1 <= pos0 )
00222     {
00223       // overflow
00224       ON_ERROR("Attempt to seek to a position that is too large for 64-bit unsigned int storage.");
00225       return false; 
00226     }
00227   }
00228   else
00229   {
00230     pos1 = pos0;
00231   }
00232 
00233   if ( pos1 != m_current_position )
00234   {
00235     m_current_position = pos1;
00236     m_current_segment = 0;
00237   }
00238 
00239   return true;
00240 }
00241 
00242 bool ON_Buffer::SeekFromStart( ON__INT64 offset )
00243 {
00244   return Seek(offset,0);
00245 }
00246 
00247 bool ON_Buffer::SeekFromCurrentPosition( ON__INT64 offset )
00248 {
00249   return Seek(offset,1);
00250 }
00251 
00252 bool ON_Buffer::SeekFromEnd( ON__INT64 offset )
00253 {
00254   return Seek(offset,2);
00255 }
00256 
00257 bool ON_Buffer::Compact()
00258 {
00259   bool rc = false;
00260   if ( 0 == m_buffer_size )
00261   {
00262     rc = ChangeSize(0); // frees all heap and zeros everything but m_current_position.
00263     m_current_segment = 0;
00264   }
00265   else if ( 0 != m_last_segment 
00266             && m_buffer_size > m_last_segment->m_segment_position0
00267             && m_buffer_size <= m_last_segment->m_segment_position1
00268             )
00269   {
00270     if ( m_buffer_size == m_last_segment->m_segment_position1 )
00271       rc = true;
00272     else
00273     {
00274       ON__UINT64 sizeof_segment_buffer = m_buffer_size - m_last_segment->m_segment_position0;
00275       struct ON_BUFFER_SEGMENT* prev_segment = m_last_segment->m_prev_segment;
00276       void* last_buffer = ( 0 != m_last_segment->m_segment_buffer && m_last_segment->m_segment_buffer != (unsigned char*)(m_last_segment+1) )
00277                         ? m_last_segment->m_segment_buffer
00278                         : 0;
00279       struct ON_BUFFER_SEGMENT* new_last_segment = (struct ON_BUFFER_SEGMENT*)onrealloc(m_last_segment,sizeof(*m_last_segment) + ((size_t)sizeof_segment_buffer)); // sizeof_segment_buffer always < 0xFFFFFFFF
00280       if ( 0 != new_last_segment )
00281       {
00282         if ( new_last_segment != m_last_segment || 0 != last_buffer )
00283         {
00284           new_last_segment->m_segment_buffer = (unsigned char*)(new_last_segment+1);
00285           if ( 0 != last_buffer )
00286           {
00287             memcpy(new_last_segment->m_segment_buffer,last_buffer,(size_t)sizeof_segment_buffer);
00288             onfree(last_buffer);
00289             last_buffer = 0;
00290           }
00291           new_last_segment->m_prev_segment = prev_segment;
00292           new_last_segment->m_next_segment = 0;
00293           if ( m_first_segment == m_last_segment )
00294             m_first_segment = new_last_segment;
00295           if ( m_current_segment == m_last_segment )
00296             m_current_segment = new_last_segment;
00297           m_last_segment = new_last_segment;
00298           if ( 0 != prev_segment )
00299           {
00300             prev_segment->m_next_segment = m_last_segment;
00301           }
00302         }
00303         m_last_segment->m_segment_position1 = m_buffer_size;
00304         rc = true;
00305       }
00306     }
00307   }
00308   return true;
00309 }
00310 
00311 bool ON_Buffer::ChangeSize(ON__UINT64 buffer_size)
00312 {
00313   if ( buffer_size <= 0 )
00314   {
00315     struct ON_BUFFER_SEGMENT* p0 = m_last_segment;
00316     struct ON_BUFFER_SEGMENT* p1 = 0;
00317     m_buffer_size = 0;
00318     m_first_segment = 0;
00319     m_last_segment = 0;
00320     m_current_segment = 0;
00321 
00322     // free in reverse order of allocation
00323     while ( 0 != p0 )
00324     {
00325       p1 = p0->m_prev_segment;
00326       if ( 0 != p0->m_segment_buffer && (void*)(p0->m_segment_buffer) != (void*)(p0+1) )
00327         onfree(p0->m_segment_buffer);
00328       onfree(p0);
00329       p0 = p1;
00330     }
00331   }
00332   else if ( buffer_size < m_buffer_size )
00333   {
00334     m_current_segment = 0;
00335 
00336     if ( 0 == m_first_segment || 0 == m_last_segment )
00337     {
00338       ON_ERROR("Corrupt ON_Buffer");
00339       return false;
00340     }
00341 
00342     while ( 0 != m_last_segment )
00343     {
00344       if ( m_last_segment->m_segment_position0 < buffer_size )
00345       {
00346         if ( buffer_size > m_last_segment->m_segment_position1 )
00347         {
00348           ON_ERROR("Corrupt ON_Buffer.");
00349           // Set m_buffer_size and m_last_segment to valid values
00350           // to prevent possible crashes if the return code is
00351           // ignored.
00352           if ( m_buffer_size > m_last_segment->m_segment_position1 )
00353             m_buffer_size = m_last_segment->m_segment_position1;
00354           m_last_segment->m_next_segment = 0;
00355           if ( m_current_position > m_buffer_size )
00356             m_current_position = m_buffer_size;
00357           return false;
00358         }
00359         if ( 0 != m_last_segment->m_segment_buffer && m_last_segment->m_segment_position1 > buffer_size )
00360         {
00361           memset(m_last_segment->m_segment_buffer + (buffer_size - m_last_segment->m_segment_position0),
00362                  0,
00363                  (size_t)(m_last_segment->m_segment_position1 - buffer_size)
00364                  );
00365         }
00366         m_buffer_size = buffer_size;
00367         break;
00368       }
00369       struct ON_BUFFER_SEGMENT* p = m_last_segment->m_prev_segment;
00370       if ( 0 != p )
00371         p->m_next_segment = 0;
00372       if ( 0 != m_last_segment->m_segment_buffer && (void*)(m_last_segment->m_segment_buffer) != (void*)(m_last_segment+1) )
00373         onfree(m_last_segment->m_segment_buffer);
00374       onfree(m_last_segment);
00375       m_last_segment = p;
00376     }
00377   }
00378   else if ( buffer_size > m_buffer_size )
00379   {
00380     // save current position;
00381     const ON__UINT64 saved_pos = CurrentPosition();
00382     if ( SeekFromStart(buffer_size-1) )
00383     {
00384       // calling Write with the current position at buffer_size-1
00385       // will pad with zeros from offset m_buffer_size to 
00386       // offset buffer_size-2, write a zero at offset buffer_size-1,
00387       // and set m_buffer_size to buffer size.
00388       const unsigned char zero_byte = 0;
00389       Write(1,&zero_byte);
00390     }
00391     // restore current position.
00392     SeekFromStart(saved_pos);
00393   }
00394 
00395   return (buffer_size == m_buffer_size);
00396 }
00397 
00398 void ON_Buffer::Copy( const ON_Buffer& src )
00399 {
00400   const struct ON_BUFFER_SEGMENT* src_seg;
00401   struct ON_BUFFER_SEGMENT* dst_seg;
00402   for ( src_seg = src.m_first_segment; 0 != src_seg; src_seg = src_seg->m_next_segment )
00403   {
00404     if (    m_buffer_size != src_seg->m_segment_position0 
00405          || src_seg->m_segment_position0 >= src.m_buffer_size
00406         )
00407     {
00408       ON_ERROR("Attempt to copy corrupt source.");
00409       break;
00410     }
00411     if ( src_seg->m_segment_position0 >= src_seg->m_segment_position1 
00412         )
00413     {
00414       ON_ERROR("Attempt to copy corrupt source.");
00415       continue;
00416     }
00417     ON__UINT64 segment_buffer_size = ( 0 != src_seg->m_segment_buffer)
00418                                ? src_seg->m_segment_position1 - src_seg->m_segment_position0
00419                                : 0;
00420     dst_seg = (struct ON_BUFFER_SEGMENT*)onmalloc(sizeof(*dst_seg) + ((size_t)segment_buffer_size) );
00421     memset(dst_seg,0,sizeof(*dst_seg));
00422 
00423     if ( segment_buffer_size > 0 )
00424     {
00425       dst_seg->m_segment_buffer = (unsigned char*)(dst_seg+1);
00426       memcpy( dst_seg->m_segment_buffer, src_seg->m_segment_buffer, (size_t)segment_buffer_size ); // segment_buffer_size always < 0xFFFFFFFF
00427     }
00428 
00429     if ( 0 == m_first_segment )
00430       m_first_segment = dst_seg;
00431     dst_seg->m_prev_segment = m_last_segment;
00432     if ( 0 != m_last_segment )
00433       m_last_segment->m_next_segment = dst_seg;
00434     m_last_segment = dst_seg;
00435     dst_seg->m_segment_position0 = src_seg->m_segment_position0;
00436     dst_seg->m_segment_position1 = src_seg->m_segment_position1;
00437     m_buffer_size = (src.m_buffer_size < dst_seg->m_segment_position1)
00438                   ? src.m_buffer_size
00439                   : dst_seg->m_segment_position1;
00440   }
00441   if ( src.m_current_position <= m_buffer_size )
00442     m_current_position = src.m_current_position;
00443   // 27 June, 2001 Dale Lear: Should this copy m_last_error and m_error_handler? Not sure.
00444 }
00445 
00446 static bool ON_Buffer_IsNotValid()
00447 {
00448   return false;
00449 }
00450 
00451 bool ON_Buffer::IsValid( const ON_TextLog* text_log ) const
00452 {
00453   // This function is primarily used to discover bugs
00454   // in the ON_Buffer member function code.
00455 
00456   if ( 0 == m_buffer_size )
00457   {
00458 
00459     if ( 0 != m_first_segment )
00460       return ON_Buffer_IsNotValid();
00461     if ( 0 != m_last_segment )
00462       return ON_Buffer_IsNotValid();
00463     if ( 0 != m_current_segment )
00464       return ON_Buffer_IsNotValid();
00465 
00466     return true;
00467   }
00468 
00469 
00470   if ( 0 == m_first_segment )
00471     return ON_Buffer_IsNotValid();
00472   if ( 0 != m_first_segment->m_prev_segment )
00473     return ON_Buffer_IsNotValid();
00474   if ( 0 == m_last_segment )
00475     return ON_Buffer_IsNotValid();
00476   if ( 0 != m_last_segment->m_next_segment )
00477     return ON_Buffer_IsNotValid();
00478 
00479   bool bCurrentSegInList = (0 == m_current_segment);
00480   ON__UINT64 pos = 0;
00481   ON__UINT64 u;
00482   const struct ON_BUFFER_SEGMENT* prev_seg = 0;
00483   const struct ON_BUFFER_SEGMENT* seg;
00484   for ( seg = m_first_segment; seg != 0; seg = seg->m_next_segment )
00485   {
00486     if ( prev_seg != seg->m_prev_segment )
00487       return ON_Buffer_IsNotValid();
00488     if ( 0 != prev_seg && prev_seg->m_segment_position1 != seg->m_segment_position0 )
00489       return ON_Buffer_IsNotValid();
00490     if ( seg->m_segment_position1 <= seg->m_segment_position0 )
00491       return ON_Buffer_IsNotValid();
00492     if ( pos != seg->m_segment_position0 )
00493       return ON_Buffer_IsNotValid();
00494 
00495     if ( m_current_segment == seg )
00496       bCurrentSegInList = true;
00497 
00498     // pos checks prevent infinite loop when the linked list has a cycle;
00499     u = pos + (seg->m_segment_position1 - seg->m_segment_position0);
00500     if ( pos >= u )
00501       return ON_Buffer_IsNotValid(); // addition wrapped value
00502     pos = u;
00503     prev_seg = seg;
00504   }
00505 
00506   if ( m_last_segment != prev_seg )
00507     return ON_Buffer_IsNotValid();
00508 
00509   if ( pos < m_buffer_size )
00510     return ON_Buffer_IsNotValid();
00511 
00512   if (    m_buffer_size <= m_last_segment->m_segment_position0 
00513        || m_buffer_size > m_last_segment->m_segment_position1 
00514      )
00515     return ON_Buffer_IsNotValid();
00516 
00517   return true;
00518 }
00519 
00520 bool ON_Buffer::AtEnd() const
00521 {
00522   return (m_current_position == m_buffer_size);
00523 }
00524 
00525 ON__UINT64 ON_Buffer::Size() const
00526 {
00527   return m_buffer_size;
00528 }
00529 
00530 ON__UINT32 ON_Buffer::CRC32( ON__UINT32 current_remainder ) const
00531 {
00532   ON__UINT64 size, seg_size;
00533   const struct ON_BUFFER_SEGMENT* prev_seg;
00534   const struct ON_BUFFER_SEGMENT* seg;
00535   const struct ON_BUFFER_SEGMENT* seg0 = 0;
00536 
00537   size = 0;
00538   for ( seg = m_first_segment; 0 != seg; seg = seg->m_next_segment )
00539   {
00540     // prev_seg is set this way so that the error handling
00541     // code can use continue statments for non-fatal errors.
00542     prev_seg = seg0;
00543     seg0 = seg;
00544 
00545     if ( seg->m_segment_position0 > seg->m_segment_position1 )
00546     {
00547       // This is really bad!  If you can determine how the corruption occurs,
00548       // plase make a bug report and tell Dale Lear as soon as possible.
00549       ON_ERROR("corrupt buffer - segment's position values are invalid.");
00550       continue;
00551     }
00552 
00553     if ( 0 == prev_seg )
00554     {
00555       if ( 0 != seg->m_segment_position0 )
00556       {
00557         // The first segment should have seg->m_segment_position0 = 0.
00558         // We'll keep going after the call to ON_ERROR.
00559         //
00560         // If you can determine how the corruption occured, please
00561         // make a bug report and assign it to Dale Lear.
00562         ON_ERROR("corrupt buffer - first segment has non-zero value for position0.");
00563       }
00564     }
00565     else if ( prev_seg->m_segment_position1 != seg->m_segment_position0 )
00566     {
00567       // Every segment after the first should have 
00568       // seg->m_segment_position0 = previous_segment->m_segment_position1.
00569       // We'll keep going after the call to ON_ERROR.
00570       //
00571       // If you can determine how the corruption occured, please
00572       // make a bug report and assign it to Dale Lear.
00573       ON_ERROR("corrupt buffer - previous segment's position1 !- segment's position0.");
00574     }
00575 
00576     seg_size = seg->m_segment_position1 - seg->m_segment_position0;
00577 
00578     if ( 0 == seg_size )
00579     {
00580       // If you can determine how the corruption occured, please
00581       // make a bug report and assign it to Dale Lear.
00582       ON_ERROR("corrupt buffer - empty segment buffer.");
00583       continue;
00584     }
00585     
00586     if ( seg_size + size > m_buffer_size )
00587     {
00588       if ( seg != m_last_segment || seg->m_next_segment )
00589       {
00590         // If you can determine how the corruption occured, please
00591         // make a bug report and assign it to Dale Lear.
00592         ON_ERROR("corrupt buffer - segments contain more bytes than m_buffer_size.");
00593       }
00594       seg_size = m_buffer_size - size;
00595     }
00596 
00597     current_remainder = ON_CRC32(current_remainder,(size_t)seg_size,seg->m_segment_buffer);
00598     size += seg_size;
00599     if ( size >= m_buffer_size )
00600     {
00601       if ( seg != m_last_segment || 0 != seg->m_next_segment || size > m_buffer_size )
00602       {
00603         // If you can determine how the corruption occured, please
00604         // make a bug report and assign it to Dale Lear.
00605         ON_ERROR("corrupt buffer - list of segments is too long.");
00606       }
00607       break;
00608     }
00609   }
00610 
00611   return current_remainder;
00612 }
00613 
00614 
00615 ON__UINT64 ON_Buffer::CurrentPosition() const
00616 {
00617   return m_current_position;
00618 }
00619 
00620 bool ON_Buffer::SetCurrentSegment( bool bWritePending )
00621 {
00622   // When ON_Buffer::Write() needs to write at least on byted, it 
00623   // calls ON_Buffer::SetCurrentSegment(true).
00624   //   In this case true is returned in all cases unless the information
00625   //   in the ON_Buffer class is corrupt.
00626   // When ON_Buffer::Read() needs to read a at least one byte, it
00627   // calls ON_Buffer::SetCurrentSegment(false).  
00628   //   In this case, true is returned when m_current_position < m_buffer_size
00629   //   and false is returned in all other cases.
00630   //
00631   // If seeks have occured since the last read or write, m_current_segment
00632   // and m_current_segment_offset may need to be updated.
00633   //
00634 
00635   if ( 0 == m_current_segment )
00636     m_current_segment = (m_current_position <= m_buffer_size/2) ? m_first_segment : m_last_segment;
00637 
00638   if ( !bWritePending && m_current_position >= m_buffer_size )
00639   {
00640     m_current_segment = 0;
00641     return false; // cannot read past end of buffer
00642   }
00643 
00644   if ( 0 != m_current_segment 
00645        && m_current_segment->m_segment_position0 <= m_current_position 
00646        && m_current_position < m_current_segment->m_segment_position1 
00647      )
00648   {
00649     // The current position is inside of m_current_segment.
00650     // This happens most of the time which is why this code is at the top
00651     // of this function.
00652     return true;
00653   }
00654 
00655   if ( 0 == m_first_segment )
00656   {
00657     // m_current_position can be > 0 if we are writing
00658     m_current_segment = 0;
00659     return bWritePending;
00660   }
00661 
00662   if ( 0 == m_last_segment )
00663   {
00664     m_current_segment = 0;
00665     ON_ERROR("Corrupt ON_Buffer");
00666     return false;
00667   }
00668 
00669   if ( m_current_position >= m_last_segment->m_segment_position1 )
00670   {
00671     m_current_segment = 0;
00672     return bWritePending;
00673   }
00674 
00675   while ( m_current_position < m_current_segment->m_segment_position0 )
00676   {
00677     m_current_segment = m_current_segment->m_prev_segment;
00678     if ( 0 == m_current_segment )
00679     {
00680       ON_ERROR("Corrupt ON_Buffer");
00681       return false;
00682     }
00683   }
00684 
00685   while ( m_current_position >= m_current_segment->m_segment_position1 )
00686   {
00687     m_current_segment = m_current_segment->m_next_segment;
00688     if ( 0 == m_current_segment )
00689       return bWritePending;
00690   }
00691 
00692   return true;
00693 }
00694 
00695 ON__UINT64 ON_Buffer::Write( ON__UINT64 size, const void* buffer )
00696 {
00697   if ( 0 == size )
00698     return 0; // not an error condition
00699 
00700   if ( 0 == buffer )
00701   {
00702     ON_ERROR("size parameter > 0 and buffer parameter is null.");
00703     return 0;
00704   }
00705 
00706   if ( !SetCurrentSegment(true) )
00707   {
00708     ON_ERROR("Corrupt ON_Buffer");
00709     return 0;
00710   }
00711 
00712   // m_current_position >= m_buffer_size is ok - it is not an error condition.
00713 
00714   ON__UINT64 rc = 0;
00715   while ( size > 0 )
00716   {
00717     if ( 0 == m_current_segment )
00718     {
00719       // allocate a new segment
00720       const ON__UINT64 padding_size = 4*sizeof(void*); // room for os heap info
00721       const ON__UINT64 header_size = sizeof(*m_current_segment);
00722       ON__UINT64 page_size = ON_MemoryPageSize();
00723       if ( page_size <= 4096 )
00724         page_size = 4096;
00725       const ON__UINT64 max_malloc_size = 16*page_size;  // largest request we want to make
00726 
00727       ON__UINT64 malloc_size = ( 0 != m_last_segment && m_last_segment->m_segment_position1 > m_last_segment->m_segment_position0 )
00728                           ? padding_size + header_size + (m_last_segment->m_segment_position1 - m_last_segment->m_segment_position0)
00729                           : 0;
00730       if ( malloc_size < page_size/2 )
00731         malloc_size = page_size/2;      
00732       if ( malloc_size < max_malloc_size )
00733         malloc_size *= 2;
00734       while ( malloc_size < max_malloc_size && size > malloc_size - header_size - padding_size )
00735         malloc_size *= 2;
00736 
00737       malloc_size -= padding_size;
00738       // (size_t) cast is safe because malloc_size is always <= max_malloc_size = 16*page_size <  0xFFFFFFFF
00739       m_current_segment = (struct ON_BUFFER_SEGMENT*)onmalloc((size_t)malloc_size); 
00740       memset(m_current_segment,0,(size_t)malloc_size);
00741       m_current_segment->m_prev_segment = m_last_segment;
00742       m_current_segment->m_segment_buffer = (unsigned char*)(m_current_segment + 1);
00743       if ( 0 != m_last_segment )
00744       {
00745         m_last_segment->m_next_segment = m_current_segment;
00746         m_current_segment->m_segment_position0 = m_last_segment->m_segment_position1;
00747       }
00748       else
00749         m_first_segment = m_current_segment;
00750       m_last_segment = m_current_segment;
00751       m_current_segment->m_segment_position1 = m_current_segment->m_segment_position0 + (ON__UINT64)(malloc_size - header_size);
00752     }
00753 
00754     if (    m_current_position < m_current_segment->m_segment_position0 
00755          || m_current_segment->m_segment_position1 <= m_current_segment->m_segment_position0 
00756        )
00757     {
00758       ON_ERROR("Corrupt ON_Buffer");
00759       return 0;
00760     }
00761 
00762     if ( m_current_position >= m_current_segment->m_segment_position1 )
00763     {
00764       // happens when a seek puts the current position beyond the end of the buffer.
00765       if ( m_current_segment->m_segment_position1 > m_buffer_size )
00766         m_buffer_size = m_current_segment->m_segment_position1;
00767       m_current_segment = m_current_segment->m_next_segment;
00768       continue;
00769     }
00770             
00771     ON__UINT64 offset = m_current_position - m_current_segment->m_segment_position0;
00772     ON__UINT64 sz = (m_current_segment->m_segment_position1 - m_current_position);
00773 
00774     if ( sz > size )
00775       sz = size;
00776     memcpy( m_current_segment->m_segment_buffer + offset, buffer, (size_t)sz );
00777     m_current_position += sz;
00778     if ( m_buffer_size < m_current_position )
00779     {
00780       // wrote past the old end of the file
00781       m_buffer_size = m_current_position;
00782     }
00783     rc += sz;
00784     size -= sz;
00785     buffer = ((const unsigned char*)buffer) + sz;
00786     if ( size > 0 )
00787       m_current_segment = m_current_segment->m_next_segment;
00788   }
00789 
00790   return rc;
00791 }
00792 
00793 ON__UINT64 ON_Buffer::Read( ON__UINT64 size, void* buffer )
00794 {
00795   if ( 0 == size )
00796   {
00797     // not an error condition
00798     return 0;
00799   }
00800 
00801   if ( 0 == buffer )
00802   {
00803     // ON_Buffer error
00804     ON_ERROR("size parameter > 0 and buffer parameter is null.");
00805     return 0;
00806   }
00807 
00808   if ( m_current_position >= m_buffer_size )
00809   {
00810     // m_current_position == m_buffer_size is a common situation
00811     // and is not an error condition.
00812     // For example, it occurs when a previous Read() read up to the
00813     // end of the buffer and the caller is testing the number of 
00814     // bytes read to detect the end of buffer condition.
00815     if ( m_current_position > m_buffer_size )
00816     {
00817       ON_ERROR("Read attempted when current position > buffer size.");
00818     }
00819     return 0;
00820   }
00821 
00822   if ( !SetCurrentSegment(false) )
00823   {
00824     ON_ERROR("Corrupt ON_Buffer");
00825     return 0;
00826   }
00827 
00828   ON__UINT64 rc = 0;
00829   while ( size > 0 )
00830   {
00831     if( 0 == m_current_segment || 0 == m_current_segment->m_segment_buffer )
00832     {
00833       ON_ERROR("Corrupt ON_Buffer");
00834       return 0;
00835     }
00836 
00837     // set pos1 to the maximum position to be read from m_current_segment.
00838     ON__UINT64 pos1 = (m_buffer_size < m_current_segment->m_segment_position1)
00839                     ? m_buffer_size
00840                     : m_current_segment->m_segment_position1;
00841     if ( m_current_position < m_current_segment->m_segment_position0 || m_current_position >= pos1 )
00842     {
00843       ON_ERROR("Corrupt ON_Buffer");
00844       return 0;
00845     }
00846 
00847     ON__UINT64 offset = m_current_position - m_current_segment->m_segment_position0;           
00848     ON__UINT64 sz = pos1 - m_current_position;
00849 
00850     if ( sz > size )
00851       sz = size;
00852     memcpy( buffer, m_current_segment->m_segment_buffer + offset, (size_t)sz );
00853     m_current_position += sz;
00854     rc += sz;
00855     size -= sz;
00856     buffer = ((unsigned char*)buffer) + sz;
00857     if ( size > 0 )
00858     {
00859       if ( m_current_position == m_buffer_size && m_current_segment == m_last_segment )
00860       {
00861         // This is a common situation that occures when the read request is for a 
00862         // size larger than the remaining number of bytes in the buffer. For example,
00863         // when repeatedly reading into a fixed size buffer until reasing the end
00864         // of the file. This is not an error condition.
00865         break;
00866       }
00867       m_current_segment = m_current_segment->m_next_segment;
00868     }
00869   }
00870 
00871   return rc;
00872 }
00873 
00874 ON__UINT32 ON_Buffer::LastError() const
00875 {
00876   return m_last_error;
00877 }
00878 
00879   
00880 void ON_Buffer::ClearLastError()
00881 {
00882   m_last_error = 0;
00883 }
00884 
00885 
00886 ON_Buffer_ErrorHandler ON_Buffer::ErrorHandler() const
00887 {
00888   return m_error_handler;
00889 }
00890   
00891 void ON_Buffer::SetErrorHandler(ON_Buffer_ErrorHandler error_handler)
00892 {
00893   m_error_handler = error_handler;
00894 }
00895 
00896 bool ON_Buffer::WriteToBinaryArchive( ON_BinaryArchive& archive ) const
00897 {
00898   // The ON_Buffer::CRC32() calculation will call ON_ERROR if the segment list
00899   // is not perfect.  The code below that goes through the segments
00900   // checks for errors so that crashes are avoided, but does not make
00901   // additional calls to ON_ERROR.
00902   ON__UINT32 buffer_crc = CRC32(0);
00903 
00904   if ( !archive.BeginWrite3dmChunk(TCODE_OPENNURBS_BUFFER,1,0) )
00905     return false;
00906 
00907   bool rc = false;
00908   for(;;)
00909   {
00910     if ( !archive.WriteBigInt(m_buffer_size) )
00911       break;
00912     if ( !archive.WriteInt(buffer_crc) )
00913       break;
00914 
00915     bool buffer_rc = true;
00916     ON__UINT64 size = 0;
00917     for ( struct ON_BUFFER_SEGMENT* seg = m_first_segment; 
00918           0 != seg && size < m_buffer_size; 
00919           seg = seg->m_next_segment 
00920         )
00921     {
00922       if ( 0 == seg->m_segment_buffer )
00923         continue;
00924       if ( seg->m_segment_position1 <= seg->m_segment_position0 )
00925         continue;
00926       ON__UINT64 seg_size = (seg->m_segment_position1 - seg->m_segment_position0);
00927       if ( seg_size + size > m_buffer_size )
00928         seg_size = m_buffer_size - size;
00929       if ( !archive.WriteByte( (size_t)seg_size, seg->m_segment_buffer ) )
00930       {
00931         buffer_rc = false;
00932         break;
00933       }
00934       size += seg_size;
00935     }
00936     
00937     rc = true;
00938     break;
00939   }
00940 
00941   if ( !archive.EndWrite3dmChunk() )
00942     rc = false;
00943 
00944   return rc;
00945 }
00946 
00947 
00948 bool ON_Buffer::ReadFromBinaryArchive( ON_BinaryArchive& archive )
00949 {
00950   Destroy();
00951   
00952   int major_version = 0;
00953   int minor_version = 0;
00954   if ( !archive.BeginRead3dmChunk(TCODE_OPENNURBS_BUFFER,&major_version,&minor_version) )
00955     return false;
00956 
00957   ON_3DM_BIG_CHUNK c0;
00958   memset(&c0,0,sizeof(c0));
00959   archive.GetCurrentChunk(c0);
00960 
00961   ON__UINT64 saved_buffer_size = 0;
00962   ON__UINT32 saved_buffer_crc = 0;
00963   bool rc = false;
00964   void* a = 0;
00965   for(;;)
00966   {
00967     if ( 1 != major_version )
00968       break;
00969     
00970     if ( !archive.ReadBigInt(&saved_buffer_size) )
00971       break;
00972 
00973     if ( !archive.ReadInt(&saved_buffer_crc) )
00974       break;
00975 
00976     const ON__UINT64 extra_size = 24; // =
00977                                       //  4  ( major version number )
00978                                       // +4  ( minor version number )
00979                                       // +8  ( 64-bit buffer_size )
00980                                       // +4  ( 32-bit buffer_crc )
00981                                       // +4  ( 32-bit chunk crc )
00982     if ( 0 == minor_version )
00983     {
00984       if ( c0.Length() != extra_size + saved_buffer_size )
00985       {
00986         ON_ERROR("corrupt archive");
00987         break;
00988       }
00989     }
00990     else if ( c0.Length() < extra_size + saved_buffer_size )
00991     {
00992       // later versions may add more information
00993       // but there still needs to be enough room
00994       // to store the buffer.
00995       ON_ERROR("corrupt archive");
00996       break;
00997     }
00998 
00999     if ( saved_buffer_size > 0 )
01000     {
01001       ON__UINT64 a_capacity = saved_buffer_size;
01002       if ( a_capacity > 16*4096 )
01003         a_capacity = 16*4096;
01004       a = onmalloc((size_t)a_capacity);
01005       if ( 0 == a )
01006         break;
01007       ON__UINT64 size = 0;
01008       bool buffer_rc = true;
01009       while( size < saved_buffer_size )
01010       {
01011         ON__UINT64 read_size = a_capacity;
01012         if ( read_size > saved_buffer_size - size )
01013           read_size = saved_buffer_size - size;
01014         if ( !archive.ReadByte((size_t)read_size,a) )
01015         {
01016           buffer_rc = false;
01017           break;
01018         }
01019         // add to buffer
01020         Write(read_size,a);
01021         size += read_size;
01022       }
01023     
01024       if ( !buffer_rc )
01025         break;
01026     }
01027 
01028     rc = true;
01029     break;
01030   }
01031 
01032   if ( 0 != a )
01033     onfree(a);
01034 
01035   if ( !archive.EndRead3dmChunk() )
01036     rc = false;
01037 
01038   if ( rc )
01039   {
01040     Compact();
01041     const ON__UINT32 buffer_crc = CRC32(0);
01042     if ( buffer_crc != saved_buffer_crc || m_buffer_size != saved_buffer_size)
01043     {
01044       // The buffer's contents have been damaged.
01045       ON_ERROR("The buffer contents were corrupted during, writing, storage or reading.");
01046     }
01047   }
01048   else
01049   {
01050     Destroy();
01051   }
01052 
01053   return rc;
01054 }
01055 
01056 static bool ON_Buffer_StreamCallback( void* context, ON__UINT32 size, const void* buffer )
01057 {
01058   return ( size == ((ON_Buffer*)context)->Write(size,buffer) );
01059 }
01060 
01061 bool ON_Buffer::Compress( ON_Buffer& compressed_buffer ) const
01062 {
01063   bool rc = false;
01064   ON_CompressStream compressor;
01065   ON_Buffer* out = ( this == &compressed_buffer ) ? new ON_Buffer() : &compressed_buffer;
01066 
01067   out->Destroy();
01068 
01069   for (;;)
01070   {
01071     ON__UINT64 uncompressed_size = Size();
01072     if ( uncompressed_size <= 0 )
01073       break;
01074     if ( !compressor.SetCallback(ON_Buffer_StreamCallback,out) )
01075       break;
01076     if ( !compressor.Begin() )
01077       break;
01078 
01079     struct ON_BUFFER_SEGMENT* prev_seg = 0;
01080     struct ON_BUFFER_SEGMENT* seg = 0;
01081     for ( seg = m_first_segment; 0 != seg; seg = seg->m_next_segment )
01082     {
01083       const ON__UINT64 pos1 = (uncompressed_size < seg->m_segment_position1)
01084                             ? uncompressed_size 
01085                             : seg->m_segment_position1;
01086       if ( pos1 < seg->m_segment_position0 )
01087         break;
01088       if ( prev_seg != seg->m_prev_segment )
01089         break;
01090       if ( 0 == prev_seg )
01091       {
01092         if ( 0 != seg->m_segment_position0 )
01093           break;
01094       }
01095       else
01096       {
01097         if ( prev_seg->m_segment_position1 != seg->m_segment_position0 )
01098           break;
01099       }
01100       if ( !compressor.In(pos1 - seg->m_segment_position0,seg->m_segment_buffer) )
01101         break;
01102       prev_seg = seg;
01103     }
01104     if ( 0 != seg )
01105       break;
01106 
01107     if ( !compressor.End() )
01108       break;
01109 
01110     if ( compressor.InSize() != uncompressed_size )
01111       break;
01112     if ( compressor.InCRC() != CRC32(0) )
01113       break;
01114     if ( compressor.OutSize() != out->Size() )
01115       break;
01116     if ( compressor.OutCRC() != out->CRC32(0) )
01117       break;
01118 
01119     rc = true;
01120     break;
01121   }
01122 
01123   if ( !rc )
01124   {
01125     out->Destroy();
01126     if ( this == &compressed_buffer )
01127       delete out;
01128   }
01129   else
01130   {
01131     out->Compact();
01132     out->m_current_position = 0;
01133     out->m_current_segment = 0;
01134     if ( this == &compressed_buffer )
01135     {
01136       // transfer "out" to "this"
01137       compressed_buffer.Destroy();
01138       compressed_buffer.m_buffer_size = out->m_buffer_size;
01139       compressed_buffer.m_current_position = out->m_current_position;
01140       compressed_buffer.m_first_segment = out->m_first_segment;
01141       compressed_buffer.m_last_segment = out->m_last_segment;
01142       compressed_buffer.m_current_segment = out->m_current_segment;
01143       compressed_buffer.m_heap = out->m_heap;
01144       compressed_buffer.m_error_handler = out->m_error_handler;
01145       compressed_buffer.m_last_error = out->m_last_error;
01146       
01147       out->m_first_segment = 0;
01148       out->m_last_segment = 0;
01149       out->m_current_segment = 0;
01150       out->m_buffer_size = 0;
01151       delete out;
01152     }
01153   }
01154 
01155   return rc;
01156 }
01157 
01158 bool ON_Buffer::Uncompress( ON_Buffer& uncompressed_buffer ) const
01159 {
01160   bool rc = false;
01161   ON_UncompressStream uncompressor;
01162   ON_Buffer* out = ( this == &uncompressed_buffer ) ? new ON_Buffer() : &uncompressed_buffer;
01163 
01164   out->Destroy();
01165 
01166   for (;;)
01167   {
01168     ON__UINT64 compressed_size = Size();
01169     if ( compressed_size <= 0 )
01170       break;
01171     if ( !uncompressor.SetCallback(ON_Buffer_StreamCallback,out) )
01172       break;
01173     if ( !uncompressor.Begin() )
01174       break;
01175 
01176     struct ON_BUFFER_SEGMENT* prev_seg = 0;
01177     struct ON_BUFFER_SEGMENT* seg = 0;
01178     for ( seg = m_first_segment; 0 != seg; seg = seg->m_next_segment )
01179     {
01180       const ON__UINT64 pos1 = (compressed_size < seg->m_segment_position1)
01181                             ? compressed_size 
01182                             : seg->m_segment_position1;
01183       if ( pos1 < seg->m_segment_position0 )
01184         break;
01185       if ( prev_seg != seg->m_prev_segment )
01186         break;
01187       if ( 0 == prev_seg )
01188       {
01189         if ( 0 != seg->m_segment_position0 )
01190           break;
01191       }
01192       else
01193       {
01194         if ( prev_seg->m_segment_position1 != seg->m_segment_position0 )
01195           break;
01196       }
01197       if ( !uncompressor.In(pos1 - seg->m_segment_position0,seg->m_segment_buffer) )
01198         break;
01199       prev_seg = seg;
01200     }
01201     if ( 0 != seg )
01202       break;
01203 
01204     if ( !uncompressor.End() )
01205       break;
01206 
01207     if ( uncompressor.InSize() != compressed_size )
01208       break;
01209     if ( uncompressor.InCRC() != CRC32(0) )
01210       break;
01211     if ( uncompressor.OutSize() != out->Size() )
01212       break;
01213     if ( uncompressor.OutCRC() != out->CRC32(0) )
01214       break;
01215 
01216     rc = true;
01217     break;
01218   }
01219 
01220   if ( !rc )
01221   {
01222     out->Destroy();
01223     if ( this == &uncompressed_buffer )
01224       delete out;
01225   }
01226   else
01227   {
01228     out->Compact();
01229     out->m_current_position = 0;
01230     out->m_current_segment = 0;
01231     if ( this == &uncompressed_buffer )
01232     {
01233       // transfer "out" to "this"
01234       uncompressed_buffer.Destroy();
01235       uncompressed_buffer.m_buffer_size = out->m_buffer_size;
01236       uncompressed_buffer.m_current_position = out->m_current_position;
01237       uncompressed_buffer.m_first_segment = out->m_first_segment;
01238       uncompressed_buffer.m_last_segment = out->m_last_segment;
01239       uncompressed_buffer.m_current_segment = out->m_current_segment;
01240       uncompressed_buffer.m_heap = out->m_heap;
01241       uncompressed_buffer.m_error_handler = out->m_error_handler;
01242       uncompressed_buffer.m_last_error = out->m_last_error;
01243       
01244       out->m_first_segment = 0;
01245       out->m_last_segment = 0;
01246       out->m_current_segment = 0;
01247       out->m_buffer_size = 0;
01248       delete out;
01249     }
01250   }
01251 
01252   return rc;
01253 }
01254 
01255 
01256 
01257 
01258 ON_OBJECT_IMPLEMENT( ON_EmbeddedFile, ON_Object, "1247BEC9-D9A9-46B3-900F-39DE7A355BD3");
01259 
01260 bool ON_EmbeddedFile::Create( 
01261   const wchar_t* file_full_path_name,
01262   bool bCompress
01263   )
01264 {
01265   Destroy();
01266 
01267   // ~ON_Workspace will close the file
01268   FILE* fp = ON_FileStream::Open(file_full_path_name,L"rb");
01269   if ( 0 == fp )
01270     return false;
01271 
01272   bool rc = Create(fp,bCompress);
01273 
01274   ON_FileStream::Close(fp);
01275   if ( rc )
01276   {
01277     ON_CreateUuid(m_id);
01278     m_full_file_name = file_full_path_name;
01279   }
01280 
01281   return rc;
01282 }
01283 
01284 ON_EmbeddedFile::ON_EmbeddedFile()
01285 : m_id(ON_nil_uuid)
01286 , m_reserved(0)
01287 , m_file_size(0)
01288 , m_file_time(0)
01289 , m_file_crc(0)
01290 , m_buffer_crc(0)
01291 , m_bCompressedBuffer(0)
01292 {
01293   m_reserved3[0] = 0;
01294   m_reserved3[1] = 0;
01295   m_reserved3[2] = 0;
01296   m_reserved3[3] = 0;
01297   m_reserved3[4] = 0;
01298   m_reserved3[5] = 0;
01299   m_reserved3[6] = 0;
01300 }
01301 
01302 ON_EmbeddedFile::ON_EmbeddedFile(const ON_EmbeddedFile& src)
01303 : ON_Object(src)
01304 , m_id(src.m_id)
01305 , m_full_file_name(src.m_full_file_name)
01306 , m_relative_file_name(src.m_relative_file_name)
01307 , m_reserved(0)
01308 , m_file_size(src.m_file_size)
01309 , m_file_time(src.m_file_time)
01310 , m_file_crc(src.m_file_crc)
01311 , m_buffer_crc(src.m_buffer_crc)
01312 , m_buffer(src.m_buffer)
01313 , m_bCompressedBuffer(src.m_bCompressedBuffer)  //fixed 29 12 2011
01314 {
01315   m_reserved3[0] = 0;
01316   m_reserved3[1] = 0;
01317   m_reserved3[2] = 0;
01318   m_reserved3[3] = 0;
01319   m_reserved3[4] = 0;
01320   m_reserved3[5] = 0;
01321   m_reserved3[6] = 0;
01322 }
01323 
01324 ON_EmbeddedFile& ON_EmbeddedFile::operator=(const ON_EmbeddedFile& src)
01325 {
01326   if ( this != &src )
01327   {
01328     Destroy();
01329 
01330     ON_Object::operator=(src);
01331 
01332     m_id = src.m_id;
01333 
01334     m_full_file_name = src.m_full_file_name;
01335     m_relative_file_name = src.m_relative_file_name;
01336 
01337     m_file_size  = src.m_file_size;
01338     m_file_time  = src.m_file_time;
01339     m_file_crc   = src.m_file_crc;
01340     m_buffer_crc = src.m_buffer_crc;
01341     m_buffer     = src.m_buffer;
01342     m_bCompressedBuffer = src.m_bCompressedBuffer;   //fixed 29 12 2011
01343   }
01344   return *this;
01345 }
01346 
01347 ON_EmbeddedFile::~ON_EmbeddedFile()
01348 {
01349   Destroy();
01350 }
01351 
01352 void ON_EmbeddedFile::EmergencyDestroy()
01353 {
01354   ON_Object::EmergencyDestroy();
01355   m_buffer.EmergencyDestroy();
01356   m_full_file_name.EmergencyDestroy();
01357   m_relative_file_name.EmergencyDestroy();
01358   Destroy(); // zero all members
01359 }
01360 
01361 void ON_EmbeddedFile::Destroy()
01362 {
01363   ON_Object::PurgeUserData();
01364   DestroyBuffer();
01365   m_id = ON_nil_uuid;
01366   m_full_file_name.Destroy();
01367   m_relative_file_name.Destroy();
01368   m_file_size  = 0;
01369   m_file_time  = 0;
01370   m_file_crc   = 0;
01371   m_buffer_crc = 0;
01372 }
01373 
01374 void ON_EmbeddedFile::DestroyBuffer()
01375 {
01376   m_buffer.Destroy();
01377   m_buffer_crc = 0;
01378   m_bCompressedBuffer = false;
01379 }
01380 
01381 static bool CompressedStreamHandler( void* context, ON__UINT32 size, const void* buffer )
01382 {
01383   return (size == ((ON_Buffer*)context)->Write(size,buffer) );
01384 }
01385 
01386 bool ON_EmbeddedFile::Create( 
01387   FILE* fp,
01388   bool bCompress
01389   )
01390 {
01391   Destroy();
01392 
01393   if ( 0 == fp )
01394     return false;
01395   if ( !ON_FileStream::SeekFromStart(fp,0) )
01396     return false;
01397 
01398   ON__UINT64 file_size = 0;
01399   ON__UINT64 file_create_time = 0;
01400   ON__UINT64 file_last_modified_time = 0;
01401   if ( !ON_FileStream::GetFileInformation(fp,&file_size,&file_create_time,&file_last_modified_time) )
01402     return false;
01403 
01404   // copy file into buffer
01405   // ~ON_Workspace will free the memory
01406   ON_Workspace ws;
01407   const size_t buffer_capacity = 4090;
01408   ON__UINT64 buffer_size;
01409   void* buffer = (void*)ws.GetMemory(buffer_capacity);
01410   if ( 0 == buffer )
01411     return false;
01412 
01413   ON_CompressStream compress;
01414   if ( bCompress )
01415   {
01416     m_bCompressedBuffer = true;
01417     if ( !compress.SetCallback(CompressedStreamHandler,&m_buffer) )
01418       return false;
01419     if ( !compress.Begin() )
01420       return false;
01421   }
01422 
01423   for(;;)
01424   {
01425     buffer_size = ON_FileStream::Read(fp,buffer_capacity,buffer);
01426     if ( buffer_size <= 0 )
01427       break;
01428     m_file_size += buffer_size;
01429     m_file_crc = ON_CRC32(m_file_crc,(size_t)buffer_size,buffer);
01430     if ( bCompress )
01431     {
01432       if ( !compress.In(buffer_size,buffer) )
01433       {
01434         Destroy();
01435         return false;
01436       }
01437     }
01438     else
01439     {
01440       if ( !m_buffer.Write(buffer_size,buffer) )
01441       {
01442         Destroy();
01443         return false;
01444       }
01445     }
01446   }
01447 
01448   if ( bCompress )
01449   {
01450     if ( !compress.End() )
01451     {
01452         Destroy();
01453       return false;
01454     }
01455     if (    compress.InSize() != m_file_size
01456          || compress.InCRC() != m_file_crc
01457          || compress.OutSize() != m_buffer.Size()
01458        )
01459     {
01460       Destroy();
01461       return false;
01462     }
01463   }
01464 
01465   m_buffer_crc = m_buffer.CRC32(0);
01466 
01467   if ( bCompress )
01468   {
01469     if ( compress.OutCRC() != m_buffer_crc )
01470     {
01471       Destroy();
01472       return false;
01473     }
01474   }
01475 
01476   m_buffer.SeekFromStart(0);
01477 
01478   return true;
01479 }
01480 
01481 bool ON_EmbeddedFile::Extract( 
01482   const wchar_t* destination_filename
01483   ) const
01484 {
01485   if ( 0 == destination_filename || 0 == destination_filename[0] )
01486     return false;
01487   if ( m_buffer.Size() <= 0 )
01488     return false;
01489   FILE* fp = ON_FileStream::Open(destination_filename,L"wb");
01490   if ( 0 == fp )
01491     return false;
01492   bool rc = Extract(fp);
01493   ON_FileStream::Close(fp);
01494   return rc;
01495 }
01496 
01497 static bool UncompressedToFileHandler( void* context, ON__UINT32 size, const void* buffer )
01498 {
01499   return ( size == ON_FileStream::Write((FILE*)context,size,buffer) );
01500 }
01501 
01502 bool ON_EmbeddedFile::Extract( 
01503   FILE* fp
01504   ) const
01505 {
01506   ON_Workspace ws;
01507 
01508   if ( 0 == fp )
01509     return false;
01510   if ( m_buffer.Size() <= 0 )
01511     return false;
01512 
01513   ON_UncompressStream uncompress;
01514 
01515   if ( m_bCompressedBuffer )
01516   {
01517     if ( !uncompress.SetCallback(UncompressedToFileHandler,fp) )
01518       return false;
01519     if ( !uncompress.Begin() )
01520       return false;
01521   }
01522 
01523   const size_t buffer_capacity = 4088;
01524   void* buffer = ws.GetMemory(buffer_capacity);
01525   ON__UINT64 file_size = 0;
01526   ON__UINT32 file_crc = 0;
01527   if ( !const_cast<ON_Buffer*>(&m_buffer)->SeekFromStart(0) )
01528     return false;
01529   for(;;)
01530   {
01531     ON__UINT64 buffer_size = const_cast<ON_Buffer*>(&m_buffer)->Read(buffer_capacity,buffer);
01532     if ( buffer_size <= 0 )
01533       break;
01534     if ( m_bCompressedBuffer )
01535     {
01536       if ( !uncompress.In(buffer_size,buffer) )
01537         return false;
01538     }
01539     else
01540     {
01541       file_size += buffer_size;
01542       file_crc = ON_CRC32(file_crc,(size_t)buffer_size,buffer);
01543       if ( !ON_FileStream::Write(fp,(size_t)buffer_size,buffer) )
01544         return false;
01545     }
01546   }
01547 
01548   if ( m_bCompressedBuffer )
01549   {
01550     if ( !uncompress.End() )
01551       return false;
01552 
01553     file_size = uncompress.OutSize();
01554     file_crc = uncompress.OutCRC();
01555   }
01556 
01557   if ( file_size != m_file_size || file_crc != m_file_crc )
01558     return false;
01559 
01560   return true;
01561 }
01562 
01563 
01564 struct BufferAndSize
01565 {
01566   ON__UINT64 buffer_size;
01567   void* buffer;
01568 };
01569 
01570 static bool UncompressedToBufferHandler( void* context, ON__UINT32 size, const void* buffer )
01571 {
01572   struct BufferAndSize* bs = (struct BufferAndSize*)context;
01573   size_t sz = (bs->buffer_size < size) ? (size_t)bs->buffer_size  : (size_t)size;
01574   if ( sz > 0 )
01575   {
01576     memcpy(bs->buffer,buffer,sz);
01577     bs->buffer_size -= sz;
01578     bs->buffer = ((unsigned char*)bs->buffer) + sz;
01579   }
01580   return ( sz == size );
01581 }
01582 
01583 bool ON_EmbeddedFile::Extract( 
01584   void* out_buffer
01585   ) const
01586 {
01587   ON_Workspace ws;
01588 
01589   if ( m_buffer.Size() <= 0 )
01590     return false;
01591   if ( FileSize() <= 0 )
01592     return false;
01593   if ( 0 == out_buffer )
01594     return false;
01595 
01596   BufferAndSize bs;
01597   bs.buffer = out_buffer;
01598   bs.buffer_size = FileSize();
01599 
01600   ON_UncompressStream uncompress;
01601 
01602   if ( m_bCompressedBuffer )
01603   {
01604     if ( !uncompress.SetCallback(UncompressedToBufferHandler,&bs) )
01605       return false;
01606     if ( !uncompress.Begin() )
01607       return false;
01608   }
01609 
01610   const size_t buffer_capacity = 4088;
01611   void* buffer = ws.GetMemory(buffer_capacity);
01612   ON__UINT64 file_size = 0;
01613   ON__UINT32 file_crc = 0;
01614   if ( !const_cast<ON_Buffer*>(&m_buffer)->SeekFromStart(0) )
01615     return false;
01616   for(;;)
01617   {
01618     ON__UINT64 buffer_size = const_cast<ON_Buffer*>(&m_buffer)->Read(buffer_capacity,buffer);
01619     if ( buffer_size <= 0 )
01620       break;
01621     if ( m_bCompressedBuffer )
01622     {
01623       if ( !uncompress.In(buffer_size,buffer) )
01624         return false;
01625     }
01626     else
01627     {
01628       file_size += buffer_size;
01629       file_crc = ON_CRC32(file_crc,(size_t)buffer_size,buffer);
01630       size_t sz = (bs.buffer_size < buffer_size) ? (size_t)bs.buffer_size  : (size_t)buffer_size;
01631       if ( sz > 0 )
01632       {
01633         memcpy(bs.buffer,buffer,sz);
01634         bs.buffer_size -= sz;
01635         bs.buffer = ((unsigned char*)bs.buffer) + sz;
01636       }
01637       if ( sz != buffer_size )
01638         return false;
01639     }
01640   }
01641 
01642   if ( m_bCompressedBuffer )
01643   {
01644     if ( !uncompress.End() )
01645       return false;
01646 
01647     file_size = uncompress.OutSize();
01648     file_crc = uncompress.OutCRC();
01649   }
01650 
01651   if ( file_size != m_file_size || file_crc != m_file_crc )
01652     return false;
01653 
01654   return true;
01655 }
01656 
01657 const wchar_t* ON_EmbeddedFile::FullFileName() const
01658 {
01659   return m_full_file_name;
01660 }
01661 
01662 const wchar_t* ON_EmbeddedFile::RelativeFileName() const
01663 {
01664   return m_relative_file_name;
01665 }
01666 
01667 ON_UUID ON_EmbeddedFile::Id() const
01668 {
01669   return m_id;
01670 }
01671 
01672 void ON_EmbeddedFile::SetFullFileName( const wchar_t* full_file_name )
01673 {
01674   m_full_file_name = full_file_name;
01675 }
01676 
01677 void ON_EmbeddedFile::SetRelativeFileName( const wchar_t* relative_file_name )
01678 {
01679   m_relative_file_name = relative_file_name;
01680 }
01681 
01682 void ON_EmbeddedFile::SetId( ON_UUID id )
01683 {
01684   m_id = id;
01685 }
01686 
01687 ON__UINT64 ON_EmbeddedFile::FileSize() const
01688 {
01689   return m_file_size;
01690 }
01691 
01692 ON__UINT64 ON_EmbeddedFile::FileLastModifiedTime() const
01693 {
01694   return m_file_time;
01695 }
01696 
01697 ON__UINT32 ON_EmbeddedFile::FileCRC() const
01698 {
01699   return m_file_crc;
01700 }
01701 
01702 static bool ON_EmbeddedFileIsNotValid()
01703 {
01704   return ON_IsNotValid();
01705 }
01706   
01707 ON_BOOL32 ON_EmbeddedFile::IsValid( ON_TextLog* text_log ) const
01708 {
01709   if ( !m_buffer.IsValid(text_log) )
01710   {
01711     if ( 0 != text_log )
01712       text_log->Print("m_buffer is not valid.");
01713     return ON_EmbeddedFileIsNotValid();
01714   }
01715 
01716   if ( m_buffer_crc != m_buffer.CRC32(0) )
01717   {
01718     if ( 0 != text_log )
01719       text_log->Print("m_buffer_crc != m_buffer.CRC32(0)");
01720     return ON_EmbeddedFileIsNotValid();
01721   }
01722 
01723   if ( !m_bCompressedBuffer )
01724   {
01725     if ( m_file_size != m_buffer.Size() )
01726     {
01727       if ( 0 != text_log )
01728         text_log->Print("Uncompressed buffer - m_file_size != m_buffer.Size(0)");
01729       return ON_EmbeddedFileIsNotValid();
01730     }
01731     if ( m_file_crc != m_buffer_crc )
01732     {
01733       if ( 0 != text_log )
01734         text_log->Print("Uncompressed buffer - m_file_size != m_buffer.Size(0)");
01735       return ON_EmbeddedFileIsNotValid();
01736     }
01737   }
01738 
01739   return true;
01740 }
01741 
01742 ON_BOOL32 ON_EmbeddedFile::Write( ON_BinaryArchive& archive ) const
01743 {
01744   if ( !archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0) )
01745     return false;
01746 
01747   bool rc = false;
01748   for(;;)
01749   {
01750     // put header information in a sub-chunk
01751     if ( !archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0) )
01752       break;
01753     bool header_rc = false;
01754     for(;;)
01755     {
01756       if ( !archive.WriteUuid(m_id) )
01757         break;
01758       if ( !archive.WriteString(m_full_file_name) )
01759         break;
01760       if ( !archive.WriteString(m_relative_file_name) ) 
01761         break;
01762       if ( !archive.WriteBigInt(m_file_size) )
01763         break;
01764       if ( !archive.WriteBigInt(m_file_time) )
01765         break;
01766       if ( !archive.WriteInt(m_file_crc) )
01767         break;
01768       if ( !archive.WriteInt(m_buffer_crc) )
01769         break;
01770       if ( !archive.WriteChar(m_bCompressedBuffer) )
01771         break;
01772       header_rc = true;
01773       break;
01774     }
01775     if ( !archive.EndWrite3dmChunk() )
01776       break;
01777     if ( !header_rc )
01778       break;
01779 
01780     // m_buffer.WriteToBinaryArchive() creates its own chunk
01781     // with typecode = TCODE_OPENNURBS_BUFFER
01782     if ( !m_buffer.WriteToBinaryArchive(archive) )
01783       break;
01784 
01785     rc = true;
01786     break;
01787   }
01788 
01789   if ( !archive.EndWrite3dmChunk() )
01790     rc = false;
01791 
01792   return rc;
01793 }
01794 
01795 ON_BOOL32 ON_EmbeddedFile::Read( ON_BinaryArchive& archive )
01796 {
01797   Destroy();
01798 
01799   int major_version = 0;
01800   int minor_version = 0;
01801   if ( !archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version) )
01802     return false;
01803 
01804   bool rc = false;
01805   for(;;)
01806   {
01807     if ( 1 != major_version )
01808       break;
01809     // put header information in a sub-chunk
01810     int header_major_version = 0;
01811     int header_minor_version = 0;
01812     if ( !archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&header_major_version,&header_minor_version) )
01813       break;
01814     bool header_rc = false;
01815     for(;;)
01816     {
01817       if ( 1 != header_major_version )
01818         break;
01819       if ( !archive.ReadUuid(m_id) )
01820         break;
01821       if ( !archive.ReadString(m_full_file_name) )
01822         break;
01823       if ( !archive.ReadString(m_relative_file_name) ) 
01824         break;
01825 
01826       if ( !archive.ReadBigInt(&m_file_size) )
01827         break;
01828       if ( !archive.ReadBigInt(&m_file_time) )
01829         break;
01830       if ( !archive.ReadInt(&m_file_crc) )
01831         break;
01832       if ( !archive.ReadInt(&m_buffer_crc) )
01833         break;
01834       if ( !archive.ReadChar(&m_bCompressedBuffer) )
01835         break;
01836       header_rc = true;
01837       break;
01838     }
01839     if ( !archive.EndRead3dmChunk() )
01840       break;
01841     if ( !header_rc )
01842       break;
01843 
01844     // m_buffer.ReadToBinaryArchive() creates its own chunk
01845     // with typecode = TCODE_OPENNURBS_BUFFER
01846     if ( !m_buffer.ReadFromBinaryArchive(archive) )
01847       break;
01848 
01849     rc = true;
01850     break;
01851   }
01852 
01853   if ( !archive.EndRead3dmChunk() )
01854     rc = false;
01855 
01856   return rc;
01857 }
01858 
01859 


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