/* $NoKeywords: $ */ /* // // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved. // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert // McNeel & Associates. // // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF // MERCHANTABILITY ARE HEREBY DISCLAIMED. // // For complete openNURBS copyright information see . // //////////////////////////////////////////////////////////////// */ #include "opennurbs.h" #if defined(ON_RUNTIME_LINUX) #include "android_uuid/uuid.h" #endif #if !defined(ON_COMPILING_OPENNURBS) // This check is included in all opennurbs source .c and .cpp files to insure // ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled. // When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined // and the opennurbs .h files alter what is declared and how it is declared. #error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs #endif #if !defined(UUID_DEFINED) && !defined(GUID_DEFINED) // When ON_UUID is a typdef for Microsoft 's UUID, // the Microsoft compiler handles == and !=. // When a ON_UUID is not a typedef for a Microsoft UUID, // it is declared as a class and operator== and operator!= // need to be explicitly defined. bool operator==(const struct ON_UUID_struct& a, const struct ON_UUID_struct& b) { return (0==memcmp(&a,&b,sizeof(struct ON_UUID_struct))); } bool operator!=(const struct ON_UUID_struct& a, const struct ON_UUID_struct& b) { return (0!=memcmp(&a,&b,sizeof(struct ON_UUID_struct))); } #endif // used to map the correspondence between uuid strings and // ON_UUIDs as an array of 16 bytes. // for little endian CPUs (Intel, etc) static const int little_endian_rho[16] = {3,2,1,0, 5,4, 7,6, 8,9, 10,11,12,13,14,15}; // for big endian CPUs (Motorola, MIPS, Sparc, etc.) static const int big_endian_rho[16] = {0,1,2,3, 4,5, 6,7, 8,9, 10,11,12,13,14,15}; ON_UUID ON_CreateId() { ON_UUID id; ON_CreateUuid(id); return id; } static const ON_UUID not_unique_id_base = { 0, // unsigned long Data1; 0, // unsigned short Data2; // The Data 3 and Data4 values are based on the MAC address of a // network card that was destroyed circa 2000. 0x11dc, // unsigned short Data3; {0x98,0x85,0x00,0x13,0x72,0xc3,0x38,0x78} // unsigned char Data4[8]; }; static const ON_UUID ON_Internal_CreateNotUniqueSequentialId( ON__UINT64 index_64_bit ) { // Creates a not unique and repeatable UUID value that has a valid format. // // It is based on the MAC address of a network card that // was destroyed circa 2000. The Time portion of the UUID is generated // from index_64_bit and will generall be well before the current time. // The reason for using this complicated approach is to insure // data structures usisg these i values will pass validty checking // that tests to see if the UUID has a valid format. if (0 == index_64_bit) { ON_ERROR("index_64_bit parameter cannot be zero."); return ON_nil_uuid; } const ON__UINT64 d2 = 0x10000; const ON__UINT64 data2 = index_64_bit % d2; const ON__UINT64 data1 = index_64_bit / d2; if ( data1 > 0xFFFFFFFF ) { ON_ERROR("index_64_bit parameter is too large."); return ON_nil_uuid; } ON_UUID not_unique_id = not_unique_id_base; not_unique_id.Data1 = (ON__UINT32)data1; not_unique_id.Data2 = (ON__UINT16)data2; return not_unique_id; } ON_UUID ON_NotUniqueIdFromIndex( ON__UINT64 index_64_bit ) { return ON_Internal_CreateNotUniqueSequentialId(index_64_bit); } ON_UUID ON_NotUniqueIdFromIndex( ON__UINT32 index ) { return ON_Internal_CreateNotUniqueSequentialId((ON__UINT64)index); } ON_UUID ON_NextNotUniqueId( ON_UUID current_not_unique_id ) { if (ON_nil_uuid == current_not_unique_id) return ON_Internal_CreateNotUniqueSequentialId(1); const ON__UINT64 current_not_unique_id_index = ON_IndexFromNotUniqueId(current_not_unique_id); return ON_Internal_CreateNotUniqueSequentialId(current_not_unique_id_index+1); } ON__UINT64 ON_IndexFromNotUniqueId( ON_UUID not_unique_id ) { if ( not_unique_id.Data3 == not_unique_id_base.Data3 && *((const ON__UINT32*)(¬_unique_id.Data4[0])) == *((const ON__UINT32*)(¬_unique_id_base.Data4[0])) && *((const ON__UINT32*)(¬_unique_id.Data4[4])) == *((const ON__UINT32*)(¬_unique_id_base.Data4[4])) ) { const ON__UINT64 data1 = (ON__UINT64)not_unique_id.Data1; const ON__UINT64 data2 = (ON__UINT64)not_unique_id.Data2; const ON__UINT64 index = data1 * 0x10000 + data2; return index; } ON_ERROR("not_unique_id was not created by ON_NotUniqueIdFromIndex()."); return (ON_nil_uuid == not_unique_id) ? 0 : 0xFFFF00000000; } bool ON_CreateUuid( ON_UUID& new_uuid ) { // See http://www.faqs.org/rfcs/rfc4122.html for uuid details. #if 0 { // Use this code when testing reqires "repeatable uniqueness". // NEVER check in this code. static ON_UUID x = ON_nil_uid; x = ON_NextNotUniqueId(x); new_uuid = x; #pramga message("warning: NEVER COMMIT THIS CODE - ON_CreateUuid in TEST MODE.") } return true; #else #if defined(ON_COMPILER_MSC) // Header: Declared in Rpcdce.h. // Library: Use Rpcrt4.lib #pragma comment(lib, "Rpcrt4.lib") ::UuidCreate(&new_uuid); //::UuidCreateSequential(&new_uuid); // faster but computer MAC address // identifies the user and some // customers may object. return true; #elif defined(ON_COMPILER_CLANG) // Header: #include if ( ON::endian::little_endian == ON::Endian() ) { // Intel cpu mac // The uuid_generate() function returns a UUID in network or // big-endian order. The rest of OpenNURBS assumes that a UUID // is stored in native byte order, so we switch the byte order // of the UUID. uuid_t apple_osx_uuid; uuid_generate(apple_osx_uuid); unsigned char* dst = (unsigned char*)&new_uuid; const unsigned char* src = (const unsigned char*)&apple_osx_uuid; *dst++ = src[little_endian_rho[ 0]]; *dst++ = src[little_endian_rho[ 1]]; *dst++ = src[little_endian_rho[ 2]]; *dst++ = src[little_endian_rho[ 3]]; *dst++ = src[little_endian_rho[ 4]]; *dst++ = src[little_endian_rho[ 5]]; *dst++ = src[little_endian_rho[ 6]]; *dst++ = src[little_endian_rho[ 7]]; *dst++ = src[little_endian_rho[ 8]]; *dst++ = src[little_endian_rho[ 9]]; *dst++ = src[little_endian_rho[10]]; *dst++ = src[little_endian_rho[11]]; *dst++ = src[little_endian_rho[12]]; *dst++ = src[little_endian_rho[13]]; *dst++ = src[little_endian_rho[14]]; *dst = src[little_endian_rho[15]]; } else { // Motorola cpu mac uuid_generate((unsigned char*)&new_uuid); } #if defined (ON_DEBUG) // OS X generates version 4 UUIDs. Check that this is still true after changing the byte order. if ((new_uuid.Data3 & 0xF000) != 0x4000) ON_ERROR("ON_CreateUuid() failure 1"); if (new_uuid.Data4[0] < 0x80 || new_uuid.Data4[0] >= 0xC0) ON_ERROR("ON_CreateUuid() failure 2"); #endif return true; #else #if defined(ON_RUNTIME_LINUX) uuid_generate((unsigned char*)&new_uuid); return true; #else // You must supply a way to create unique ids or you // will not be able to write 3dm files. #error TODO - generate uuid memset(&new_uuid,0,sizeof(ON_UUID)); return false; #endif #endif #endif } const char* ON_ParseUuidString(const char* sUUID, ON_UUID* uuid) { // NOTE WELL: This code has to work on non-Windows OSs and on // both big and little endian CPUs. On Windows OSs // is must return the same result as // Windows's UuidFromString(). // // string has format like "85A08515-F383-11d3-BFE7-0010830122F0" // or like "85A08515-F383-11d3-BFE7-0010830122F0". // Hyphens are optional and ignored. // // Windows users can use "guidgen" to create UUID strings. /* #if defined(ON_DEBUG) && defined(ON_RUNTIME_WIN) RPC_STATUS st; union { ON_UUID uuid; unsigned char b[16]; } u1; st = UuidFromString( (unsigned char*)sUUID, &u1.uuid ); #endif */ static const int* rho = (ON::endian::big_endian == ON::Endian()) ? big_endian_rho : little_endian_rho; union { ON_UUID uuid; unsigned char b[16]; } u; bool bFailed; int bi, ci; unsigned char c; unsigned char byte_value[2]; memset(&u, 0, sizeof(u)); //for ( bi = 0; bi < 16; bi++ ) // u.b[bi] = 0; bFailed = sUUID ? false : true; if (!bFailed) { for (bi = 0; bi < 16; bi++) { ci = 0; byte_value[0] = 0; byte_value[1] = 0; while (ci < 2) { c = *sUUID; if (!c) { bFailed = true; break; } if (c >= 'A' && c <= 'F') { byte_value[ci++] = (c - 'A' + 10); } else if (c >= '0' && c <= '9') { byte_value[ci++] = (c - '0'); } else if (c >= 'a' && c <= 'f') { byte_value[ci++] = (c - 'a' + 10); } else if (c != '-') { bFailed = true; break; } sUUID++; } if (bFailed) break; u.b[rho[bi]] = 16 * byte_value[0] + byte_value[1]; } } if (bFailed) { // 09 August 2006 John Morse // There are times when Rhino is looking for a plug-in but the SDK or command // allows the plug-in to be specified by name or UUID. Rhino calls ON_UuidFromString() // to see if the string is a plug-in UUID so it knows if it should be comparing the string // or plug-in name when looking for a plug-in. The ON_ERROR line makes the Rhino commands // generate an OpenNURBS message box (in DEBUG builds) when the command completes and is // a pain so I commented it out per Dale Lear. //ON_ERROR("ON_UuidFromString(): bad string passed in"); u.uuid = ON_nil_uuid; } if (uuid) *uuid = u.uuid; return bFailed ? 0 : sUUID; } ON_UUID ON_UuidFromString( const char* sUUID ) { // NOTE WELL: This code has to work on non-Windows OSs and on // both big and little endian CPUs. On Windows OSs // is must return the same result as // Windows's UuidFromString(). // // string has format like "85A08515-F383-11d3-BFE7-0010830122F0" // or like "{85A08515-F383-11d3-BFE7-0010830122F0}". Brackets // and hyphens are optional and ignored. // // Windows users can use "guidgen" to create UUID strings. /* #if defined(ON_DEBUG) && defined(ON_RUNTIME_WIN) RPC_STATUS st; union { ON_UUID uuid; unsigned char b[16]; } u1; st = UuidFromString( (unsigned char*)sUUID, &u1.uuid ); #endif */ static const int* rho = (ON::endian::big_endian == ON::Endian()) ? big_endian_rho : little_endian_rho; union { ON_UUID uuid; unsigned char b[16]; } u; bool bFailed; int bi, ci; unsigned char c; unsigned char byte_value[2]; memset(&u,0,sizeof(u)); //for ( bi = 0; bi < 16; bi++ ) // u.b[bi] = 0; bFailed = sUUID ? false : true; if ( !bFailed ) { while ( *sUUID && *sUUID <= ' ' ) // skip leading white space sUUID++; if ( *sUUID == '{' ) sUUID++; for ( bi = 0; bi < 16; bi++ ) { ci = 0; byte_value[0] = 0; byte_value[1] = 0; while ( ci < 2 ) { c = *sUUID++; if ( !c ) { bFailed = true; break; } if ( c >= 'A' && c <= 'F' ) { byte_value[ci++] = (c-'A'+10); } else if ( c >= '0' && c <='9' ) { byte_value[ci++] = (c-'0'); } else if ( c >= 'a' && c <= 'f' ) { byte_value[ci++] = (c-'a'+10); } else if ( c != '-' ) { bFailed = true; break; } } if ( bFailed ) break; u.b[rho[bi]] = 16*byte_value[0] + byte_value[1]; } } if ( bFailed ) { // 09 August 2006 John Morse // There are times when Rhino is looking for a plug-in but the SDK or command // allows the plug-in to be specified by name or UUID. Rhino calls ON_UuidFromString() // to see if the string is a plug-in UUID so it knows if it should be comparing the string // or plug-in name when looking for a plug-in. The ON_ERROR line makes the Rhino commands // generate an OpenNURBS message box (in DEBUG builds) when the command completes and is // a pain so I commented it out per Dale Lear. //ON_ERROR("ON_UuidFromString(): bad string passed in"); u.uuid = ON_nil_uuid; } /* #if defined(ON_DEBUG) && defined(ON_RUNTIME_WIN) if ( memcmp( &u.uuid, &u1.uuid, 16 ) ) { ON_ERROR("ON_UuidFromString() failed"); } if ( UuidCompare( &u.uuid, &u1.uuid, &st ) ) { ON_ERROR("ON_UuidFromString() failed"); } if ( ON_UuidCompare( &u.uuid, &u1.uuid ) ) { ON_ERROR("ON_UuidCompare() failed"); } #endif */ return u.uuid; } ON_UUID ON_UuidFromString( const wchar_t* sUUID ) { wchar_t w; char s[64]; int i; if( nullptr == sUUID ) return ON_nil_uuid; while ( *sUUID && *sUUID <= ' ' ) // skip leading white space sUUID++; if ( *sUUID == '{' ) sUUID++; i = 0; while (i < 63 ) { w = *sUUID++; if ( w >= 'A' && w <= 'F' ) s[i++] = (char)w; else if ( w >= '0' && w <='9' ) s[i++] = (char)w; else if ( w >= 'a' && w <= 'f' ) s[i++] = (char)w; else if ( w != '-' ) break; } s[i] = 0; return ON_UuidFromString(s); } ON_UuidIndex::ON_UuidIndex(ON_UUID id, int index) : m_id(id) , m_i(index) {} int ON_UuidIndex::CompareIdAndIndex( const ON_UuidIndex* a, const ON_UuidIndex* b ) { int i; if ( !a ) return (b ? -1 : 0 ); if ( !b ) return 1; // compare id first if (0 == (i = ON_UuidCompare(&a->m_id, &b->m_id))) { if (a->m_i < b->m_i) i = -1; else if (a->m_i > b->m_i) i = 1; } return i; } int ON_UuidIndex::CompareIndexAndId( const ON_UuidIndex* a, const ON_UuidIndex* b ) { int i; if ( !a ) return (b ? -1 : 0 ); if ( !b ) return 1; // compare index first if (a->m_i < b->m_i) i = -1; else if (a->m_i > b->m_i) i = 1; else i = ON_UuidCompare(&a->m_id,&b->m_id); return i; } int ON_UuidIndex::CompareId( const ON_UuidIndex* a, const ON_UuidIndex* b ) { if ( !a ) return (b ? -1 : 0 ); if ( !b ) return 1; return ON_UuidCompare(&a->m_id,&b->m_id); } int ON_UuidIndex::CompareIndex( const ON_UuidIndex* a, const ON_UuidIndex* b ) { if ( !a ) return (b ? -1 : 0 ); if ( !b ) return 1; if (a->m_i < b->m_i) return -1; if (a->m_i > b->m_i) return 1; return 0; } int ON_UuidPtr::CompareIdAndPtr( const ON_UuidPtr* a, const ON_UuidPtr* b ) { int i; if ( !a ) return (b ? -1 : 0 ); if ( !b ) return 1; // compare id first if (0 == (i = ON_UuidCompare(&a->m_id, &b->m_id))) { if (a->m_ptr < b->m_ptr) i = -1; else if (a->m_ptr > b->m_ptr) i = 1; } return i; } int ON_UuidPtr::ComparePtrAndId( const ON_UuidPtr* a, const ON_UuidPtr* b ) { int i; if ( !a ) return (b ? -1 : 0 ); if ( !b ) return 1; if (a->m_ptr < b->m_ptr) i = -1; else if (a->m_ptr > b->m_ptr) i = 1; else i = ON_UuidCompare(&a->m_id,&b->m_id); return i; } int ON_UuidPtr::CompareId( const ON_UuidPtr* a, const ON_UuidPtr* b ) { if ( !a ) return (b ? -1 : 0 ); if ( !b ) return 1; return ON_UuidCompare(&a->m_id,&b->m_id); } int ON_UuidPtr::ComparePtr( const ON_UuidPtr* a, const ON_UuidPtr* b ) { if ( !a ) return (b ? -1 : 0 ); if ( !b ) return 1; if (a->m_ptr < b->m_ptr) return -1; if (a->m_ptr > b->m_ptr) return 1; return 0; } // Test code for ON_UuidCompare ////{ //// RPC_STATUS rpc_status = 0; //// ON_UUID a,b; //// size_t sz = sizeof(a); //// unsigned char* pa = (unsigned char*)&a; //// unsigned char* pb = (unsigned char*)&b; //// unsigned char u[10] = {0,1,3,63,64,65,127,128,129,255}; //// int x,y,z; //// for ( int aa = 0; aa < 10; aa++ ) for ( int bb = 0; bb < 10; bb++ ) //// { //// for ( size_t i = 0; i < sz; i++ ) //// { //// memset(pa,0,sz); //// pa[i] = u[aa]; //// for ( size_t j = 0; j < sz; j++ ) //// { //// memset(pb,0,sz); //// pb[j] = u[bb]; //// rpc_status = 0; //// y = ON_UuidCompare(&a,&b); //// z = ::UuidCompare(&a,&b,&rpc_status); //// if ( y != z ) //// { //// int mscomparediff = 99; //// } //// } //// } //// } ////} int ON_UuidCompare( const ON_UUID* a, const ON_UUID* b ) { // NOTE WELL: This code has to work the same way // on Windows and non-Windows OSs and on // both big and little endian CPUs // taking into account the way ON_UUIDs // are read/written by ON_BinaryArchive. // // On Windows, ::UuidCompare() must agree // with this function. if ( !a ) { return b ? -1 : 0; } if ( !b ) return 1; if ( a->Data1 < b->Data1 ) return -1; if ( a->Data1 > b->Data1 ) return 1; if ( a->Data2 < b->Data2 ) return -1; if ( a->Data2 > b->Data2 ) return 1; if ( a->Data3 < b->Data3 ) return -1; if ( a->Data3 > b->Data3 ) return 1; return memcmp(a->Data4,b->Data4,sizeof(a->Data4)); } int ON_UuidCompare( const ON_UUID& a, const ON_UUID& b) { return ON_UuidCompare(&a,&b); } bool ON_UuidIsNil( const ON_UUID& uuid ) { const ON__INT32* p = (const ON__INT32*)&uuid; return ( p[0] || p[1] || p[2] || p[3] ) ? false : true; } bool ON_UuidIsNotNil( const ON_UUID& uuid ) { const ON__INT32* p = (const ON__INT32*)&uuid; return ( p[0] || p[1] || p[2] || p[3] ) ? true : false; } char* ON_UuidToString( const ON_UUID& uuid, char* s) { // s - [out] The s[] char array must have length >= 37. // The returned char array will have a 36 // character uuid in s[0..35] and a null in s[36]. // NOTE WELL: // This code has to work on non-Windows OSs and on both big and // little endian CPUs. The result must satisfy // uuid == ON_UuidFromString(ON_UuidToString(uuid,s)) // 31 August 2005 Dale Lear // Changed upper case to lower case so result is // identical to the string returned by Windows' ::UuidToString(). //static const char x[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; static const char x[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; static const int addhyphen[16] = {0,0,0,1, 0,1, 0,1, 0,1, 0, 0, 0, 0, 0, 0}; const unsigned char* b = (const unsigned char*)&uuid; char* p; int i; static const int* rho = (ON::endian::big_endian == ON::Endian()) ? big_endian_rho : little_endian_rho; // 5 December 2002 Dale Lear: // There is either a bug in Purify (likely) or perhaps a bug in the // way Microsoft compiles c>>4 when c is an unsigned char. In any // case, changing c to an unsigned int makes purify happy and should // work just as well. // //unsigned char c; unsigned int c; if ( !s ) return 0; p = s; for ( i = 0; i < 16; i++ ) { c = b[rho[i]]; *p++ = x[c>>4]; // purify gripes here if c is an unsigned char - the code runs fine. *p++ = x[c&0x0F]; if ( addhyphen[i] ) *p++ = '-'; } *p = 0; #if defined(ON_DEBUG) { ON_UUID u = ON_UuidFromString(s); if ( ON_UuidCompare(&u,&uuid) ) { ON_ERROR("ON_UuidToString() bug"); // <- breakpoint here } } #endif return s; } wchar_t* ON_UuidToString( const ON_UUID& uuid, wchar_t* s) { // s - [out] The s[] char array must have length >= 37. // The returned char array will have a 36 // character uuid in s[0..35] and a null in s[36]. // NOTE WELL: // This code has to work on non-Windows OSs and on both big and // little endian CPUs. The result must satisfy // uuid == ON_UuidFromString(ON_UuidToString(uuid,s)) char x[37]; if ( s && ON_UuidToString(uuid,x) ) { int i; for (i = 0; i < 37; i++ ) { s[i] = (wchar_t)x[i]; } } else { s = 0; } return s; } const char* ON_UuidToString( const ON_UUID& uuid, ON_String& s ) { char x[37]; s = ON_UuidToString( uuid, x ); return s.Array(); } const wchar_t* ON_UuidToString( const ON_UUID& uuid, ON_wString& s ) { wchar_t x[37]; s = ON_UuidToString( uuid, x ); return s.Array(); } const ON_wString ON_IdToString( ON_UUID id ) { ON_wString s; ON_UuidToString(id, s); return s; } const ON_wString ON_AddIdPrefixToString( const ON_UUID id, const wchar_t* separator, const wchar_t* source ) { ON_wString s = ON_IdToString(id); s += separator; s += source; return s; } ON_DECL const ON_wString ON_RemoveIdPrefixFromString( const ON_UUID id, const wchar_t* separator, const wchar_t* source ) { ON_wString s(source); ON_wString prefix = ON_IdToString(id); prefix += separator; return s.RemovePrefix(prefix,ON_Locale::Ordinal,true); } ON_DECL const ON_wString ON_AddIdSuffixToString( const wchar_t* source, const wchar_t* separator, const ON_UUID id ) { ON_wString s(source); s += separator; s += ON_IdToString(id); return s; } ON_DECL const ON_wString ON_RemoveIdSuffixFromString( const wchar_t* source, const wchar_t* separator, const ON_UUID id ) { ON_wString s(source); ON_wString suffix(separator); suffix += ON_IdToString(id); return s.RemoveSuffix(suffix,ON_Locale::Ordinal,true); }