opennurbs_userdata.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 ON_VIRTUAL_OBJECT_IMPLEMENT(ON_UserData,ON_Object,"850324A7-050E-11d4-BFFA-0010830122F0");
00020 
00021 ON_UserData::ON_UserData()
00022             : m_userdata_uuid(ON_nil_uuid), 
00023               m_application_uuid(ON_nil_uuid),
00024               m_userdata_copycount(0),
00025               m_userdata_xform(1),
00026               m_userdata_owner(0),
00027               m_userdata_next(0)
00028 {}
00029 
00030 ON_UserData::ON_UserData(const ON_UserData& src) 
00031             : ON_Object(src),
00032               m_userdata_uuid(src.m_userdata_uuid), 
00033               m_application_uuid(src.m_application_uuid),
00034               m_userdata_copycount(src.m_userdata_copycount),
00035               m_userdata_xform(src.m_userdata_xform),
00036               m_userdata_owner(0), // do not copy owner
00037               m_userdata_next(0)   // do not copy next
00038 {
00039   if ( m_userdata_copycount) 
00040   {
00041     m_userdata_copycount++;
00042     if ( !m_userdata_copycount )
00043       m_userdata_copycount = 1;
00044   }
00045 }
00046 
00047 //virtual
00048 ON_BOOL32 ON_UserData::Archive() const
00049 {
00050   // If you want your userdata to be saved, you must override 
00051   // ON_UserData::Archive() and have it return true.
00052   return false;
00053 }
00054 
00055 //virtual
00056 ON_BOOL32 ON_UserData::Transform(const ON_Xform& x )
00057 {
00058   m_userdata_xform = x*m_userdata_xform;
00059   return true;
00060 }
00061 
00062 ON_UserData& ON_UserData::operator=(const ON_UserData& src)
00063 {
00064   // 16 January 2004 Dale Lear
00065   //    Do not copy the m_userdata_uuid, m_application_uuid,
00066   //    m_userdata_owner, or m_userdata_next values.
00067   //    The m_userdata_uuid and m_application_uuid are
00068   //    set when the class is constructed and should not be 
00069   //    changed.  The m_userdata_owner and m_userdata_next
00070   //    values are set when the user data is attached
00071   //    to a parent object.
00072   if ( this != &src ) 
00073   {
00074     ON_Object::operator=(src);
00075     m_userdata_copycount = src.m_userdata_copycount;
00076     m_userdata_xform = src.m_userdata_xform;
00077     if ( 0 != m_userdata_copycount )
00078     {
00079       m_userdata_copycount++;
00080       if ( !m_userdata_copycount )
00081         m_userdata_copycount = 1;
00082     }
00083   }
00084 
00085   return *this;
00086 }
00087 
00088 ON_UserData::~ON_UserData()
00089 {
00090   ON_Object* owner = m_userdata_owner;
00091   if ( owner ) {
00092     // remove this piece of user data from owner->m_userdata_list
00093     ON_UserData* prev = 0;
00094     ON_UserData* p;
00095     for ( p = owner->m_userdata_list; p; prev = p, p = p->m_userdata_next ) {
00096       if ( p == this ) {
00097         if ( prev ) {
00098           prev->m_userdata_next = p->m_userdata_next;
00099         }
00100         else {
00101           owner->m_userdata_list = p->m_userdata_next;
00102         }
00103         p->m_userdata_next = 0;
00104         p->m_userdata_owner = 0;
00105         break;
00106       }
00107     }
00108   }
00109 }
00110 
00111 void ON_UserData::Dump( ON_TextLog& text_log ) const
00112 {
00113   text_log.Print("User Data:\n");
00114   text_log.PushIndent();
00115 
00116   // print class name and class uuid
00117   ON_Object::Dump(text_log);
00118 
00119   // developer's user data description
00120   ON_wString description;
00121   const_cast<ON_UserData*>(this)->GetDescription(description);
00122   if ( description.IsEmpty() )
00123     description = L"none";
00124   const wchar_t* ws = description;
00125   text_log.Print("user data description: %ls\n",ws);
00126   text_log.Print("user data uuid: ");
00127   text_log.Print(m_userdata_uuid);
00128   text_log.Print("\n");
00129   text_log.Print("user data copy count: %d\n",this->m_userdata_copycount);
00130 
00131   // archive setting
00132   text_log.Print("user data saved in 3dm archive: %s\n",Archive() ? "yes" : "no");
00133 
00134   text_log.PopIndent();
00135 }
00136 
00137 unsigned int ON_UserData::SizeOf() const
00138 {
00139   unsigned int sz = ON_Object::SizeOf();
00140   sz += (sizeof(*this) - sizeof(ON_Object));
00141   return sz;
00142 }
00143 
00144 ON_BOOL32 ON_UserData::IsValid( ON_TextLog* text_log ) const
00145 {
00146   if ( 0 == ON_UuidCompare( &m_userdata_uuid, &ON_nil_uuid ) )
00147   {
00148     if ( 0 != text_log )
00149     {
00150       text_log->Print("invalid userdata - m_userdata_uuid = nil\n");
00151     }
00152     return false;
00153   }
00154 
00155   if ( 0 == ON_UuidCompare( m_userdata_uuid, ON_UserData::ClassId()->Uuid() ) )
00156   {
00157     if ( 0 != text_log )
00158     {
00159       text_log->Print("invalid userdata - m_userdata_uuid in use. Use guidgen to get a unique id.\n");
00160     }
00161     return false;
00162   }
00163 
00164   if ( Archive() && 0 == ON_UuidCompare( ClassId()->Uuid(), ON_UserData::ClassId()->Uuid() ) )
00165   {
00166     // 8 January 2004 Dale Lear:
00167     //  I added this test to help developers remember to use
00168     //  the ON_DECLARE_OBJECT/ON_IMPLEMENT_OBJECT macros when
00169     //  they create user data that gets archived.
00170     if ( 0 != text_log )
00171     {
00172       text_log->Print("invalid userdata - classes derived from ON_UserData that get saved in 3dm archives must have a class id and name defined by ON_OBJECT_DECLARE/ON_OBJECT_IMPLEMENT.\n");
00173     }
00174     return false;
00175   }
00176 
00177   return true;
00178 }
00179 
00180 ON_Object* ON_UserData::Owner() const
00181 {
00182   return m_userdata_owner;
00183 }
00184 
00185 ON_UserData* ON_UserData::Next() const
00186 {
00187   return m_userdata_next;
00188 }
00189 
00190 ON_UUID ON_UserData::UserDataClassUuid() const
00191 {
00192   const ON_ClassId* cid = ClassId();
00193   return ( cid == &ON_UnknownUserData::m_ON_UnknownUserData_class_id )
00194           ? ((ON_UnknownUserData*)this)->m_unknownclass_uuid
00195           : cid->Uuid();
00196 }
00197 
00198 ON_BOOL32 ON_UserData::IsUnknownUserData() const
00199 {
00200   return (ClassId() == &ON_UnknownUserData::m_ON_UnknownUserData_class_id)?true:false;
00201 }
00202 
00203 ON_BOOL32 ON_UserData::GetDescription( ON_wString& description )
00204 {
00205   return true;
00206 }
00207 
00208 
00209 ON_OBJECT_IMPLEMENT(ON_UnknownUserData,ON_UserData,"850324A8-050E-11d4-BFFA-0010830122F0");
00210 
00211 ON_UnknownUserData::ON_UnknownUserData() 
00212 : m_unknownclass_uuid(ON_nil_uuid)
00213 , m_sizeof_buffer(0)
00214 , m_buffer(0)
00215 , m_3dm_version(0)
00216 , m_3dm_opennurbs_version(0)
00217 {}
00218 
00219 ON_UnknownUserData::ON_UnknownUserData(const ON_UnknownUserData& src) 
00220 : ON_UserData(src)
00221 , m_unknownclass_uuid(ON_nil_uuid)
00222 , m_sizeof_buffer(0)
00223 , m_buffer(0)
00224 , m_3dm_version(0)
00225 , m_3dm_opennurbs_version(0)
00226 {
00227   if ( m_userdata_copycount > 0 && src.m_sizeof_buffer > 0 && src.m_buffer ) 
00228   {
00229     // For most kinds of user data except ON_UnknownUserData,
00230     // m_userdata_uuid is set by the constructor and should not
00231     // be copied from src (which may be a derived class).  However,
00232     // for ON_UnknownUserData, the value of m_userdata_uuid is 
00233     // varies because it is set by the missing userdata class. 
00234     // So it has to be copied here.
00235     m_userdata_uuid = src.m_userdata_uuid;
00236 
00237     m_unknownclass_uuid = src.m_unknownclass_uuid;
00238     m_sizeof_buffer = src.m_sizeof_buffer;
00239     m_buffer = onmemdup( src.m_buffer, src.m_sizeof_buffer);
00240     m_3dm_version = src.m_3dm_version;
00241     m_3dm_opennurbs_version = src.m_3dm_opennurbs_version;
00242   }
00243 }
00244 
00245 ON_UnknownUserData& ON_UnknownUserData::operator=(const ON_UnknownUserData& src)
00246 {
00247   if ( this != &src ) 
00248   {
00249     m_sizeof_buffer = 0;
00250     if ( 0 != m_buffer )
00251     {
00252       onfree(m_buffer);
00253       m_buffer = 0;
00254     }
00255 
00256     // ON_UserData::operator= handles setting m_userdata_copycount and
00257     // m_userdata_xform.
00258     ON_UserData::operator=(src);
00259 
00260     // For most kinds of user data except ON_UnknownUserData,
00261     // m_userdata_uuid and m_application_uuid are set by the
00262     // constructor and should not be altered by an operator=.  
00263     // However, for ON_UnknownUserData, the value of m_userdata_uuid 
00264     // and m_application_uuid vary because they are set by the
00265     // missing userdata class.  So they have to be copied here.
00266     m_userdata_uuid = src.m_userdata_uuid;
00267     m_application_uuid = src.m_application_uuid; // fix added 26 January 2010
00268 
00269     if ( m_userdata_copycount > 0 && src.m_sizeof_buffer > 0 && src.m_buffer ) 
00270     {
00271       m_unknownclass_uuid = src.m_unknownclass_uuid;
00272       m_sizeof_buffer = src.m_sizeof_buffer;
00273       m_buffer = onmemdup( src.m_buffer, src.m_sizeof_buffer);
00274       m_3dm_version = src.m_3dm_version;
00275       m_3dm_opennurbs_version = src.m_3dm_opennurbs_version;
00276     }
00277     else 
00278     {
00279       // The unknown user data is not supposed to copy
00280       m_userdata_uuid = ON_nil_uuid;
00281       m_unknownclass_uuid = ON_nil_uuid;
00282       m_sizeof_buffer = 0;
00283       m_buffer = 0;
00284       m_3dm_version = 0;
00285       m_3dm_opennurbs_version = 0;
00286     }
00287   }
00288   return *this;
00289 }
00290 
00291 ON_UnknownUserData::~ON_UnknownUserData()
00292 {
00293   if ( m_buffer )
00294     onfree(m_buffer);
00295 }
00296 
00297 unsigned int ON_UnknownUserData::SizeOf() const
00298 {
00299   return ON_UserData::SizeOf() 
00300     + (sizeof(ON_UnknownUserData)-sizeof(ON_UserData))
00301     + m_sizeof_buffer;
00302 }
00303 
00304 ON_BOOL32 ON_UnknownUserData::GetDescription( ON_wString& s )
00305 {
00306   s = "Unknown user data. (Definition of class was not available when object was read.)";
00307   return true;
00308 }
00309 
00310 ON_BOOL32 ON_UnknownUserData::IsValid( ON_TextLog* text_log ) const
00311 {
00312   ON_BOOL32 rc = ON_UserData::IsValid(text_log);
00313   
00314   // valid unknown user data must have something in it
00315   if (rc) 
00316     rc = (m_sizeof_buffer>0);
00317   if (rc) 
00318     rc = (m_buffer != NULL);
00319   
00320   // the unknown class uuid cannot be nil
00321   if (rc) 
00322     rc = ON_UuidCompare( &m_unknownclass_uuid, &ON_nil_uuid );
00323   
00324   // the unknown class uuid cannot be the ON_UnknownUserData class uuid
00325   if (rc) {
00326     ON_UUID ON_UnknownUserData_classuuid = ON_UnknownUserData::m_ON_UnknownUserData_class_id.Uuid();
00327     rc = ON_UuidCompare( &m_unknownclass_uuid, &ON_UnknownUserData_classuuid );
00328   }
00329   return rc?true:false;
00330 }
00331 
00332 void ON_UnknownUserData::Dump( ON_TextLog& dump ) const
00333 {
00334   ON_UserData::Dump(dump);
00335   dump.PushIndent();
00336   dump.Print( "unknown class uuid: ");
00337   dump.Print( m_unknownclass_uuid );
00338   dump.Print( "\n");
00339   dump.Print( "Data size in 3dm archive: %d bytes\n",m_sizeof_buffer);
00340   dump.PopIndent();
00341 }
00342 
00343 ON_BOOL32 ON_UnknownUserData::Archive() const
00344 {
00345   // 22 January 2004 Dale Lear
00346   //   Since unknown userdata is only created when
00347   //   an archive is read, it has to be saved.
00348   return true;
00349 }
00350 
00351 ON_BOOL32 ON_UnknownUserData::Write( ON_BinaryArchive& file ) const
00352 {
00353   return file.WriteByte(m_sizeof_buffer,m_buffer);
00354 }
00355 
00356 ON_BOOL32 ON_UnknownUserData::Read( ON_BinaryArchive& file )
00357 {
00358   m_buffer = onrealloc( m_buffer, m_sizeof_buffer );
00359   m_3dm_version = file.Archive3dmVersion();
00360   return file.ReadByte(m_sizeof_buffer,m_buffer);
00361 }
00362 
00363 
00364 class ON_UnknownUserDataArchive : public ON_BinaryArchive
00365 {
00366   // This class is used to define an ON_BinaryArchive that can be used
00367   // in ON_UnknownUserData::Convert() to initialize a ON_UserData class
00368   // from a memory buffer.
00369 public:
00370   ON_UnknownUserDataArchive( const ON_UnknownUserData& );
00371   ~ON_UnknownUserDataArchive();
00372 
00373   // ON_BinaryArchive overrides
00374   size_t CurrentPosition( // current offset (in bytes) into archive ( like ftell() )
00375                 ) const; 
00376   bool SeekFromCurrentPosition( // seek from current position ( like fseek( ,SEEK_CUR) )
00377                 int // byte offset ( >= -CurrentPostion() )
00378                 ); 
00379   bool SeekFromStart(  // seek from current position ( like fseek( ,SEEK_SET) )
00380                 size_t // byte offset ( >= 0 )
00381                 );
00382   bool AtEnd() const; // true if at end of file
00383 
00384 protected:
00385   size_t Read( size_t, void* ); // return actual number of bytes read (like fread())
00386   size_t Write( size_t, const void* );
00387   bool Flush();
00388 
00389 private:
00390   ON_UnknownUserDataArchive();
00391 
00392   size_t m_sizeof_buffer;
00393   const unsigned char* m_buffer;
00394   size_t m_buffer_position;
00395 };
00396 
00397 ON_UnknownUserDataArchive::ON_UnknownUserDataArchive( const ON_UnknownUserData& ud ) : ON_BinaryArchive( ON::read3dm )
00398 {
00399   SetArchive3dmVersion(ud.m_3dm_version);
00400   m_sizeof_buffer = ud.m_sizeof_buffer;
00401   m_buffer = (const unsigned char*)ud.m_buffer;
00402   m_buffer_position = 0;
00403 }
00404 
00405 ON_UnknownUserDataArchive::~ON_UnknownUserDataArchive()
00406 {
00407 }
00408 
00409 size_t ON_UnknownUserDataArchive::CurrentPosition() const
00410 {
00411   return m_buffer_position;
00412 }
00413 
00414 bool ON_UnknownUserDataArchive::SeekFromCurrentPosition( int offset )
00415 {
00416   bool rc = false;
00417   if ( offset >= 0 || m_buffer_position >= ((size_t)(-offset)) )
00418   {
00419     size_t newpos = m_buffer_position + offset;
00420     if ( newpos < m_sizeof_buffer ) 
00421     {
00422       m_buffer_position = newpos;
00423       rc = true;
00424     }
00425   }
00426   return rc;
00427 }
00428 
00429 bool ON_UnknownUserDataArchive::SeekFromStart( size_t offset )
00430 {
00431   bool rc = false;
00432   if ( offset < m_sizeof_buffer ) 
00433   {
00434     if ( offset > 0 )
00435       m_buffer_position = offset;
00436     else
00437       m_buffer_position = 0;
00438     rc = true;
00439   }
00440   return rc;
00441 }
00442 
00443 bool ON_UnknownUserDataArchive::AtEnd() const
00444 {
00445   return (m_buffer_position >= m_sizeof_buffer) ? true : false;
00446 }
00447 
00448 size_t ON_UnknownUserDataArchive::Read( size_t count, void* buffer )
00449 {
00450   size_t maxcount = 0;
00451 
00452   if ( m_sizeof_buffer > m_buffer_position ) 
00453   {
00454     maxcount = m_sizeof_buffer - m_buffer_position;
00455   }
00456 
00457   if ( count > maxcount )
00458   {
00459     count = maxcount;
00460   }
00461 
00462   if ( count > 0 ) 
00463   {
00464     memcpy( buffer, m_buffer+m_buffer_position, count );
00465     m_buffer_position += count;
00466   }
00467 
00468   return count;
00469 }
00470 
00471 size_t ON_UnknownUserDataArchive::Write( size_t, const void* )
00472 {
00473   // ON_UnknownUserDataArchive does not support Write() and Flush()
00474   return 0;
00475 }
00476 
00477 bool ON_UnknownUserDataArchive::Flush()
00478 {
00479   // ON_UnknownUserDataArchive does not support Write() and Flush()
00480   return false;
00481 }
00482 
00483 ON_UserData* ON_UnknownUserData::Convert() const
00484 {
00485   ON_UserData* ud = NULL;
00486   if ( IsValid() ) {
00487     const ON_ClassId* pID = ON_ClassId::ClassId( m_unknownclass_uuid );
00488     // if pID is NULL, it means the definiton of the unknown user data
00489     // is still not available
00490     if ( pID ) {
00491       // The class definition has been dynamically loaded since the
00492       // user data was read from an archive.  Use the class's Read()
00493       // to convert the buffer into a valid class
00494       ON_Object* pObject = pID->Create();
00495       if ( pObject ) {
00496         ud = ON_UserData::Cast(pObject);
00497         if ( !ud )
00498           delete pObject;
00499         else 
00500         {
00501           // use class's Read() function to initialize class members from buffer
00502           ON_UnknownUserDataArchive file(*this);
00503           // copy values that would be set by reading the base class
00504           ud->m_userdata_copycount = m_userdata_copycount;
00505           ud->m_userdata_xform = m_userdata_xform;
00506           ud->Read(file);
00507         }
00508       }
00509     }
00510   }
00511   return ud;
00512 }
00513 
00514 bool ON_UserDataHolder::MoveUserDataFrom( const ON_Object& source_object )
00515 {
00516   PurgeUserData();
00517   MoveUserData(*const_cast<ON_Object*>(&source_object));
00518   return (0 != FirstUserData());
00519 }
00520 
00521 bool ON_UserDataHolder::MoveUserDataTo(  const ON_Object& source_object, bool bAppend )
00522 {
00523   if ( !bAppend )
00524   {
00525     const_cast<ON_Object*>(&source_object)->PurgeUserData();
00526   }
00527   const_cast<ON_Object*>(&source_object)->MoveUserData(*this);
00528   PurgeUserData();
00529   return (0 != source_object.FirstUserData());
00530 }
00531 
00532 ON_BOOL32 ON_UserDataHolder::IsValid( ON_TextLog* text_log ) const
00533 {
00534   return true;
00535 }
00536 
00537 
00539 //
00540 // Built in tool for attaching arbitrary string userdata
00541 // to any opennurbs object.  The savvy user will probably
00542 // use XML in the string.
00543 
00544 
00545 ON_UserString::ON_UserString()
00546 {
00547 }
00548 
00549 ON_UserString::~ON_UserString()
00550 {
00551 }
00552 
00553 
00554 bool ON_UserString::Write(ON_BinaryArchive& archive) const
00555 {
00556   bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
00557   if (!rc)
00558     return false;
00559 
00560   for(;;)
00561   {
00562     rc = archive.WriteString(m_key);
00563     if (!rc) break;
00564     rc = archive.WriteString(m_string_value);
00565     if (!rc) break;
00566 
00567     break;
00568   }
00569 
00570   if ( !archive.EndWrite3dmChunk() )
00571     rc = false;
00572 
00573   return rc;
00574 }
00575 
00576 bool ON_UserString::Read(ON_BinaryArchive& archive)
00577 {
00578   m_key.Empty();
00579   m_string_value.Empty();
00580 
00581   int major_version = 0;
00582   int minor_version = 0;
00583   bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
00584   if (!rc)
00585     return false;
00586 
00587   for(;;)
00588   {
00589     rc = ( 1 == major_version );
00590     if (!rc) break;
00591     rc = archive.ReadString(m_key);
00592     if (!rc) break;
00593     rc = archive.ReadString(m_string_value);
00594     if (!rc) break;
00595 
00596     break;
00597   }
00598 
00599   if ( !archive.EndRead3dmChunk() )
00600     rc = false;
00601 
00602   return rc;
00603 }
00604 
00605 void ON_UserString::Dump(ON_TextLog& text_log) const
00606 {
00607   const wchar_t* ws = m_key;
00608   if ( !ws )
00609     ws = L"";
00610   text_log.Print("Key: %ls\n", ws);
00611   
00612   ws = m_string_value;
00613   if ( !ws )
00614     ws = L"";
00615   text_log.Print("Value: %ls\n",ws);
00616 }
00617 
00618 ON_OBJECT_IMPLEMENT(ON_UserStringList,ON_UserData,"CE28DE29-F4C5-4faa-A50A-C3A6849B6329");
00619 
00620 ON_UserStringList::ON_UserStringList()
00621 {
00622   m_userdata_uuid = ON_UserStringList::m_ON_UserStringList_class_id.Uuid();
00623   m_application_uuid = ON_opennurbs4_id; // opennurbs.dll reads/writes this userdata
00624                                          // The id must be the version 4 id because
00625                                          // V5 SaveAs V4 needs to work.
00626   m_userdata_copycount = 1;
00627 }
00628 
00629 ON_UserStringList::~ON_UserStringList()
00630 {
00631 }
00632 
00633 ON_BOOL32 ON_UserStringList::GetDescription( ON_wString& description )
00634 {
00635   description.Format("User text (%d entries)",m_e.Count());
00636   return true;
00637 }
00638 
00639 ON_BOOL32 ON_UserStringList::Archive() const
00640 {
00641   return true;
00642 }
00643 
00644 unsigned int ON_UserStringList::SizeOf() const
00645 {
00646   unsigned int sz = ON_UserData::SizeOf();
00647   sz += sizeof(*this) - sizeof(ON_UserData);
00648   sz += m_e.SizeOfArray();
00649   int i = m_e.Count();
00650   while (i--)
00651     sz += m_e[i].m_string_value.Length()*sizeof(wchar_t);
00652   return sz;
00653 }
00654 
00655 
00656 ON__UINT32 ON_UserStringList::DataCRC(ON__UINT32 current_remainder) const
00657 {
00658   int count = m_e.Count();
00659   for ( int i = 0; i < count; i++ )
00660   {
00661     current_remainder = m_e[i].m_key.DataCRC(current_remainder);
00662     current_remainder = m_e[i].m_string_value.DataCRC(current_remainder);
00663   }
00664   return current_remainder;
00665 }
00666 
00667 
00668 void ON_UserStringList::Dump( ON_TextLog& text_log ) const
00669 {
00670   int i, count = m_e.Count();
00671   text_log.Print("%d entries\n",count);
00672   text_log.PushIndent();
00673   for ( i = 0; i < count; i++ )
00674   {
00675     m_e[i].Dump(text_log);
00676   }
00677   text_log.PopIndent();
00678 }
00679 
00680 ON_BOOL32 ON_UserStringList::Write(ON_BinaryArchive& archive) const
00681 {
00682   bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
00683   if ( !rc )
00684     return false;
00685 
00686   for(;;)
00687   {
00688     int count = m_e.Count();
00689     rc = archive.WriteInt(count);
00690     if(!rc) break;
00691 
00692     for ( int i = 0; i < count && rc; i++ )
00693     {
00694       rc = m_e[i].Write(archive);
00695     }
00696     if (!rc) break;
00697 
00698     break;
00699   }
00700 
00701   if ( !archive.EndWrite3dmChunk() )
00702     rc = false;
00703 
00704   return rc;
00705 }
00706 
00707 ON_BOOL32 ON_UserStringList::Read(ON_BinaryArchive& archive)
00708 {
00709   int major_version = 0;
00710   int minor_version = 0;
00711   bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
00712   if ( !rc )
00713     return false;
00714 
00715   for(;;)
00716   {
00717     rc = (1 == major_version);
00718     if (!rc) break;
00719 
00720     int count = 0;
00721     rc = archive.ReadInt(&count);
00722     if(!rc) break;
00723 
00724     for ( int i = 0; i < count; i++ )
00725     {
00726       rc = m_e.AppendNew().Read(archive);
00727       if ( !rc) 
00728       {
00729         m_e.Remove();
00730         break;
00731       }
00732     }
00733     if (!rc) break;
00734 
00735     break;
00736   }
00737 
00738   if ( !archive.EndRead3dmChunk() )
00739     rc = false;
00740 
00741   return rc;
00742 }
00743 
00744 
00745 bool ON_UserStringList::SetUserString( const wchar_t* key, const wchar_t* string_value )
00746 {
00747   if ( !key || !key[0] )
00748     return false;
00749 
00750   int i, count = m_e.Count();
00751   for (i = 0; i < count; i++ )
00752   {
00753     if ( !m_e[i].m_key.CompareNoCase(key) )
00754     {
00755       if ( string_value && string_value[0] )
00756       {
00757         m_e[i].m_string_value = string_value;
00758       }
00759       else
00760       {
00761         m_e.Remove(i);
00762       }
00763       m_userdata_copycount++;
00764       return true;
00765     }
00766   }
00767 
00768   if ( string_value && string_value[0] )
00769   {
00770     ON_UserString& e = m_e.AppendNew();
00771     e.m_key = key;
00772     e.m_string_value = string_value;
00773     m_userdata_copycount++;
00774     return true;
00775   }
00776 
00777   return false;
00778 }
00779 
00780 bool ON_UserStringList::GetUserString( const wchar_t* key, ON_wString& string_value ) const
00781 {
00782   if ( key && key[0] )
00783   {
00784     int i, count = m_e.Count();
00785     for (i = 0; i < count; i++ )
00786     {
00787       if ( !m_e[i].m_key.CompareNoCase(key) )
00788       {
00789         string_value = m_e[i].m_string_value;
00790         return true;
00791       }
00792     }
00793   }
00794 
00795   string_value.Empty();
00796   return false;
00797 }
00798 
00799 static int cmp_hash_2dex_ij(const void* a, const void* b)
00800 {
00801   const int* ai = (const int*)a;
00802   const int* bi = (const int*)b;
00803   // 26 January 2012 Dale Lear
00804   //    Part of the fix for http://dev.mcneel.com/bugtrack/?q=97693
00805   //
00806   //    The "i" values are actually 32 bit hashes of a string
00807   //    and are often large.  The sign of (ai[0] - bi[0]) cannot
00808   //    be used to compare ai[0] and bi[0] because integer
00809   //    overflow occures with values that are large.
00810   //
00815 
00816   if ( ai[0] < bi[0] )
00817     return -1;
00818   if ( ai[0] > bi[0] )
00819     return 1;
00820   if ( ai[1] < bi[1] )
00821     return -1;
00822   if ( ai[1] > bi[1] )
00823     return 1;
00824   return 0;
00825 }
00826 
00827 int ON_UserStringList::SetUserStrings( int count, const ON_UserString* us, bool bReplace )
00828 {
00829   int added_count = 0;
00830   int i;
00831 
00832   if ( count <= 0 || 0 == us )
00833     return 0;
00834 
00835   if ( 1 == count )
00836   {
00837     // skip the hash table hoo haa
00838     if (  us[0].m_key.IsEmpty() )
00839       return 0;
00840     for ( i = 0; i < m_e.Count(); i++ )
00841     {
00842       if ( m_e[i].m_key.CompareNoCase(us[0].m_key ) )
00843         continue;
00844       if ( bReplace )
00845       {
00846         if ( us[0].m_string_value.IsEmpty() )
00847           m_e.Remove(i);
00848         else
00849           m_e[i] = us[0];
00850         added_count++;
00851       }
00852       break;
00853     }
00854     return added_count;
00855   }
00856 
00857   size_t k0, k1;
00858   int count0 = m_e.Count();
00859   size_t count0_plus_count = (size_t)(count0 + count);
00860   ON_2dex* hash = (ON_2dex*)onmalloc( (count0_plus_count + count)*sizeof(hash[0]) );
00861   ON_2dex* hash1 =  hash + (count0_plus_count);
00862   const ON_2dex* h;
00863   int deleted_count = 0;
00864 
00865   for ( i = 0; i < count0; i++ )
00866   {
00867     hash[i].i = (int)m_e[i].m_key.DataCRCLower(0);
00868     hash[i].j = i;
00869   }
00870 
00871   for ( i = 0; i < count; i++ )
00872   {
00873     hash1[i].i = (int)us[i].m_key.DataCRCLower(0);
00874     hash1[i].j = i;
00875     hash[i+count0].i = hash1[i].i;
00876     hash[i+count0].j = hash1[i].j+count0;
00877   }
00878   ON_qsort(hash,count0_plus_count,sizeof(hash[0]),cmp_hash_2dex_ij);
00879 
00880   m_e.Reserve(count0+count);
00881   for ( i = 0; i < count; i++)
00882   {
00883     if ( us[i].m_key.IsEmpty() )
00884       continue;
00885 
00886     // Set k0, k1 so that hash[k0]....,hash[k1-1] are 
00887     // the hash[] entries keys with the same hash code
00888     // as us[i].m_key.
00889     h = ON_BinarySearch2dexArray(hash1[i].i,hash,count0_plus_count);
00890     if ( 0 == h )
00891     {
00892       ON_ERROR("There is a bug in this function.");
00893       continue;
00894     }
00895     k0 = h-hash;
00896     while ( k0 > 0 && h[-1].i == h[0].i )
00897     {
00898       // set h = first element in hash[] with this hash code.
00899       k0--;
00900       h--;
00901     }
00902     for (k1 = k0+1; k1 < count0_plus_count; k1++ )
00903     {
00904       if ( hash[k1].i != hash[k0].i )
00905         break;
00906       if ( hash[k1].j > i+count0 )
00907         break;
00908     }
00909 
00910     if ( hash[k0].j >= count0 )
00911     {
00912       // There are no entries in m_e[] with key matching hash,
00913       // so us[i].m_key is not present in m_e.
00914       if ( !us[i].m_string_value.IsEmpty() )
00915       {
00916         hash[k0].j = count0++;
00917         m_e.Append(us[i]);
00918         added_count++;
00919       }
00920       continue;
00921     }
00922 
00923     for (/* empty init*/; k0 < k1; k0++ )
00924     {
00925       if ( hash[k0].j < count0 )
00926       {
00927         if ( m_e[hash[k0].j].m_key.CompareNoCase(us[i].m_key) )
00928           continue; // different keys with same hash
00929         if ( bReplace )
00930         {
00931           m_e[hash[k0].j] = us[i];
00932           added_count++;
00933           if ( us[i].m_string_value.IsEmpty() )
00934             deleted_count++;
00935         }
00936         break;
00937       }
00938     }
00939 
00940     if ( k0 >= k1 )
00941     {
00942       // hash is unique up to this point, so us[i].m_key is unique, 
00943       // so we add it if it is valid.
00944       if ( !us[i].m_string_value.IsEmpty() )
00945       {
00946         hash[k0].j = count0++;
00947         m_e.Append(us[i]);
00948         added_count++;
00949       }
00950     }
00951   }
00952 
00953   onfree(hash);
00954 
00955   // remove deleted items.
00956   i = m_e.Count();
00957   while ( i-- > 0 && deleted_count > 0 )
00958   {
00959     if ( m_e[i].m_string_value.IsEmpty() )
00960     {
00961       m_e.Remove(i);
00962       deleted_count--;
00963     }
00964   }
00965 
00966   return added_count;
00967 }
00968 
00969 
00970 
00971 
00972 
00973 bool ON_Object::SetUserString( const wchar_t* key, const wchar_t* string_value )
00974 {
00975   ON_UserStringList* us = ON_UserStringList::Cast(GetUserData(ON_UserStringList::m_ON_UserStringList_class_id.Uuid()));
00976   bool b = false;
00977   if ( !us )
00978   {
00979     us = new ON_UserStringList();
00980     if ( !AttachUserData(us) )
00981     {
00982       delete us;
00983       us = 0;
00984     }
00985     else
00986     {
00987       b = true;
00988     }
00989   }
00990 
00991   if ( us )
00992   {
00993     if ( us->SetUserString(key,string_value) )
00994     {
00995       if ( b && 2 == us->m_userdata_copycount )
00996       {
00997         // user data is brand new - roll back the 
00998         // m_userdata_copycount++ that happens in 
00999         // SetUserString().
01000         us->m_userdata_copycount = 1;
01001       }
01002       b = true;
01003     }
01004     else if ( b )
01005     {
01006       // user data was new-ed up and has nothing in it
01007       // because the input was bogus.
01008       delete us;
01009       us = 0;
01010       b = false;
01011     }
01012   }
01013   return b;
01014 }
01015 
01016 
01017 int ON_Object::SetUserStrings( int count, const ON_UserString* user_strings, bool bReplace )
01018 {
01019   if ( 0 == count || 0 == user_strings )
01020     return 0;
01021 
01022   int add_count = 0;
01023   int del_count = 0;
01024   for ( int i = 0; i < count; i++ )
01025   {
01026     if ( user_strings[i].m_key.IsEmpty() )
01027       continue;
01028     if ( user_strings[i].m_string_value.IsEmpty() )
01029       del_count++;
01030     else
01031       add_count++;
01032   }
01033   if ( 0 == add_count && 0 == del_count )
01034     return 0;
01035 
01036   ON_UserStringList* us = ON_UserStringList::Cast(GetUserData(ON_UserStringList::m_ON_UserStringList_class_id.Uuid()));
01037   if ( !us && add_count > 0)
01038   {
01039     us = new ON_UserStringList();
01040     if ( !AttachUserData(us) )
01041     {
01042       delete us;
01043       us = 0;
01044     }
01045   }
01046 
01047   return us ? us->SetUserStrings(count,user_strings,bReplace ) : 0;
01048 }
01049 
01050 
01051 bool ON_Object::GetUserString( const wchar_t* key, ON_wString& string_value ) const
01052 {
01053   string_value.Empty();
01054   const ON_UserStringList* us = ON_UserStringList::Cast(GetUserData(ON_UserStringList::m_ON_UserStringList_class_id.Uuid()));
01055   return us ? us->GetUserString(key,string_value) : false;
01056 }
01057 
01058 int ON_Object::UserStringCount() const
01059 {
01060   const ON_UserStringList* us = ON_UserStringList::Cast(GetUserData(ON_UserStringList::m_ON_UserStringList_class_id.Uuid()));
01061   return ( 0 != us )
01062          ? us->m_e.Count()
01063          : 0;
01064 }
01065 
01066 
01067 int ON_Object::GetUserStrings( 
01068   ON_ClassArray<ON_UserString>& user_strings 
01069   ) const
01070 {
01071   const int count0 = user_strings.Count();
01072   const ON_UserStringList* us = ON_UserStringList::Cast(GetUserData(ON_UserStringList::m_ON_UserStringList_class_id.Uuid()));
01073   if ( us )
01074     user_strings.Append(us->m_e.Count(),us->m_e.Array());
01075 
01076   return user_strings.Count() - count0;
01077 }
01078 
01079 int ON_Object::GetUserStringKeys( 
01080   ON_ClassArray<ON_wString>& user_string_keys 
01081   ) const
01082 {
01083   const int count0 = user_string_keys.Count();
01084   const ON_UserStringList* us = ON_UserStringList::Cast(GetUserData(ON_UserStringList::m_ON_UserStringList_class_id.Uuid()));
01085   if ( us )
01086   {
01087     user_string_keys.Reserve( count0 + us->m_e.Count() );
01088     for (int i = 0; i < us->m_e.Count(); i++ )
01089     {
01090       user_string_keys.Append(us->m_e[i].m_key);
01091     }
01092   }
01093 
01094   return user_string_keys.Count() - count0;
01095 }
01096 
01097 ON_OBJECT_IMPLEMENT(ON_DocumentUserStringList,ON_Object,"06F3218E-F5EC-4f6c-B74C-14583F0ED7BC");
01098 
01099 ON_DocumentUserStringList::ON_DocumentUserStringList()
01100 {
01101 }
01102 
01103 ON_DocumentUserStringList::~ON_DocumentUserStringList()
01104 {
01105 }
01106 
01107 ON_BOOL32 ON_DocumentUserStringList::IsValid( ON_TextLog* text_log ) const
01108 {
01109   return true;
01110 }
01111 
01112 void ON_DocumentUserStringList::Dump( ON_TextLog& ) const
01113 {
01114 }
01115 
01116 ON__UINT32 ON_DocumentUserStringList::DataCRC(ON__UINT32 current_remainder) const
01117 {
01118   const ON_UserStringList* us = ON_UserStringList::Cast(GetUserData(ON_UserStringList::m_ON_UserStringList_class_id.Uuid()));
01119   if ( us )
01120     current_remainder = us->DataCRC(current_remainder);
01121   return current_remainder;
01122 }
01123 
01124 ON_BOOL32 ON_DocumentUserStringList::Write(ON_BinaryArchive& binary_archive) const
01125 {
01126   //  The key/value pairs are saved as ON_UserStringList user data.
01127 
01128   // A single char with value 1 is written to permit adding additional
01129   // information later.  In that case change the 1 to a 2, uncomment the
01130   // begin block code, and the IO will still work.
01131   //
01132   unsigned char c = 1;
01133   bool rc = binary_archive.WriteChar(c);
01134 
01142 
01147 
01148   return rc;
01149 }
01150 
01151 ON_BOOL32 ON_DocumentUserStringList::Read(ON_BinaryArchive& binary_archive)
01152 {
01153   //  The key/value pairs are saved as ON_UserStringList user data.
01154 
01155   unsigned char c = 0;
01156   bool rc =  binary_archive.ReadChar(&c);
01157   if ( !rc || c < 1 || c > 2 )
01158     return false;
01159 
01160   if ( 2 == c )
01161   {
01162     // The code in this if(2==c) will not be used unless
01163     // the 1 in Write is changed to a 2.  This code is here
01164     // so old versions of Rhino will be able to skip over
01165     // any new information that is added at a later date.
01166     int major_version = 0;
01167     int minor_version = 0;
01168     rc = binary_archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
01169     if (!rc)
01170       return false;
01171     for(;;)
01172     {
01173       rc = (1 == major_version);
01174       if (!rc) break;
01175 
01178 
01179       break;
01180     }
01181     if (!binary_archive.EndRead3dmChunk() )
01182       rc = false;
01183   }
01184 
01185   return rc;
01186 }


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