//----------------------------------------------------------------------------- // Project : SDK Core // // Category : SDK Core Interfaces // Filename : pluginterfaces/base/funknown.cpp // Created by : Steinberg, 01/2004 // Description : Basic Interface // //----------------------------------------------------------------------------- // This file is part of a Steinberg SDK. It is subject to the license terms // in the LICENSE file found in the top-level directory of this distribution // and at www.steinberg.net/sdklicenses. // No part of the SDK, including this file, may be copied, modified, propagated, // or distributed except according to the terms contained in the LICENSE file. //----------------------------------------------------------------------------- #include "funknown.h" #include "fstrdefs.h" #include #if SMTG_OS_WINDOWS #include #if defined(__MINGW32__) /* UUID */ #include #include #include #endif #endif #if SMTG_OS_MACOS #include #include #if defined(__GNUC__) && (__GNUC__ >= 4) && !__LP64__ // on 32 bit Mac OS X we can safely ignore the format warnings as sizeof(int) == sizeof(long) #pragma GCC diagnostic ignored "-Wformat" #endif #endif #if SMTG_OS_LINUX #if !defined (SMTG_USE_STDATOMIC_H) #if defined (_LIBCPP_VERSION) #define SMTG_USE_STDATOMIC_H 1 #else #include #endif #endif /* UUID */ #include #include #include #endif #if defined (SMTG_USE_STDATOMIC_H) && SMTG_USE_STDATOMIC_H #include #endif namespace Steinberg { //------------------------------------------------------------------------ #if COM_COMPATIBLE #if SMTG_OS_WINDOWS #define GuidStruct GUID #else struct GuidStruct { uint32 Data1; uint16 Data2; uint16 Data3; uint8 Data4[8]; }; #endif #endif static void toString8 (char8* string, const char* data, int32 i1, int32 i2); static void fromString8 (const char8* string, char* data, int32 i1, int32 i2); static uint32 makeLong (uint8 b1, uint8 b2, uint8 b3, uint8 b4); //------------------------------------------------------------------------ // FUnknownPrivate //------------------------------------------------------------------------ namespace FUnknownPrivate { //------------------------------------------------------------------------ int32 PLUGIN_API atomicAdd (int32& var, int32 d) { #if SMTG_USE_STDATOMIC_H return atomic_fetch_add (reinterpret_cast (&var), d) +d; #elif SMTG_OS_WINDOWS return InterlockedExchangeAdd ((volatile long int*)&var, d) + d; #elif SMTG_OS_MACOS return OSAtomicAdd32Barrier (d, (int32_t*)&var); #elif SMTG_OS_LINUX __gnu_cxx::__atomic_add (&var, d); return var; #else #warning implement me! var += d; return var; #endif } } // FUnknownPrivate //------------------------------------------------------------------------ // FUID implementation //------------------------------------------------------------------------ FUID::FUID () { memset (data, 0, sizeof (TUID)); } //------------------------------------------------------------------------ FUID::FUID (uint32 l1, uint32 l2, uint32 l3, uint32 l4) { from4Int (l1, l2, l3, l4); } //------------------------------------------------------------------------ FUID::FUID (const FUID& f) { memcpy (data, f.data, sizeof (TUID)); } //------------------------------------------------------------------------ #if SMTG_CPP11_STDLIBSUPPORT FUID::FUID (FUID&& other) { memcpy (data, other.data, sizeof (TUID)); } FUID& FUID::operator= (FUID&& other) { memcpy (data, other.data, sizeof (TUID)); return *this; } #endif //------------------------------------------------------------------------ bool FUID::generate () { #if SMTG_OS_WINDOWS #if defined(_M_ARM64) || defined(_M_ARM) //#warning implement me! return false; #elif defined(__MINGW32__) boost::uuids::uuid u = boost::uuids::random_generator()(); memcpy(data, (const void*)&u, 16); return true; #else GUID guid; HRESULT hr = CoCreateGuid (&guid); switch (hr) { case RPC_S_OK: memcpy (data, (char*)&guid, sizeof (TUID)); return true; case RPC_S_UUID_LOCAL_ONLY: default: return false; } #endif #elif SMTG_OS_MACOS CFUUIDRef uuid = CFUUIDCreate (kCFAllocatorDefault); if (uuid) { CFUUIDBytes bytes = CFUUIDGetUUIDBytes (uuid); memcpy (data, (char*)&bytes, sizeof (TUID)); CFRelease (uuid); return true; } return false; #elif SMTG_OS_LINUX boost::uuids::uuid u = boost::uuids::random_generator()(); memcpy(data, (const void*)&u, 16); return true; #else #warning implement me! return false; #endif } //------------------------------------------------------------------------ bool FUID::isValid () const { TUID nulluid = {0}; return memcmp (data, nulluid, sizeof (TUID)) != 0; } //------------------------------------------------------------------------ FUID& FUID::operator= (const FUID& f) { memcpy (data, f.data, sizeof (TUID)); return *this; } //------------------------------------------------------------------------ void FUID::from4Int (uint32 l1, uint32 l2, uint32 l3, uint32 l4) { #if COM_COMPATIBLE data [0] = (char)((l1 & 0x000000FF) ); data [1] = (char)((l1 & 0x0000FF00) >> 8); data [2] = (char)((l1 & 0x00FF0000) >> 16); data [3] = (char)((l1 & 0xFF000000) >> 24); data [4] = (char)((l2 & 0x00FF0000) >> 16); data [5] = (char)((l2 & 0xFF000000) >> 24); data [6] = (char)((l2 & 0x000000FF) ); data [7] = (char)((l2 & 0x0000FF00) >> 8); data [8] = (char)((l3 & 0xFF000000) >> 24); data [9] = (char)((l3 & 0x00FF0000) >> 16); data [10] = (char)((l3 & 0x0000FF00) >> 8); data [11] = (char)((l3 & 0x000000FF) ); data [12] = (char)((l4 & 0xFF000000) >> 24); data [13] = (char)((l4 & 0x00FF0000) >> 16); data [14] = (char)((l4 & 0x0000FF00) >> 8); data [15] = (char)((l4 & 0x000000FF) ); #else data [0] = (char)((l1 & 0xFF000000) >> 24); data [1] = (char)((l1 & 0x00FF0000) >> 16); data [2] = (char)((l1 & 0x0000FF00) >> 8); data [3] = (char)((l1 & 0x000000FF) ); data [4] = (char)((l2 & 0xFF000000) >> 24); data [5] = (char)((l2 & 0x00FF0000) >> 16); data [6] = (char)((l2 & 0x0000FF00) >> 8); data [7] = (char)((l2 & 0x000000FF) ); data [8] = (char)((l3 & 0xFF000000) >> 24); data [9] = (char)((l3 & 0x00FF0000) >> 16); data [10] = (char)((l3 & 0x0000FF00) >> 8); data [11] = (char)((l3 & 0x000000FF) ); data [12] = (char)((l4 & 0xFF000000) >> 24); data [13] = (char)((l4 & 0x00FF0000) >> 16); data [14] = (char)((l4 & 0x0000FF00) >> 8); data [15] = (char)((l4 & 0x000000FF) ); #endif } //------------------------------------------------------------------------ void FUID::to4Int (uint32& d1, uint32& d2, uint32& d3, uint32& d4) const { d1 = getLong1 (); d2 = getLong2 (); d3 = getLong3 (); d4 = getLong4 (); } //------------------------------------------------------------------------ uint32 FUID::getLong1 () const { #if COM_COMPATIBLE return makeLong (data[3], data[2], data[1], data[0]); #else return makeLong (data[0], data[1], data[2], data[3]); #endif } //------------------------------------------------------------------------ uint32 FUID::getLong2 () const { #if COM_COMPATIBLE return makeLong (data[5], data[4], data[7], data[6]); #else return makeLong (data[4], data[5], data[6], data[7]); #endif } //------------------------------------------------------------------------ uint32 FUID::getLong3 () const { #if COM_COMPATIBLE return makeLong (data[8], data[9], data[10], data[11]); #else return makeLong (data[8], data[9], data[10], data[11]); #endif } //------------------------------------------------------------------------ uint32 FUID::getLong4 () const { #if COM_COMPATIBLE return makeLong (data[12], data[13], data[14], data[15]); #else return makeLong (data[12], data[13], data[14], data[15]); #endif } //------------------------------------------------------------------------ void FUID::toString (char8* string) const { if (!string) return; #if COM_COMPATIBLE GuidStruct* g = (GuidStruct*)data; char8 s[17]; Steinberg::toString8 (s, data, 8, 16); sprintf (string, "%08X%04X%04X%s", g->Data1, g->Data2, g->Data3, s); #else Steinberg::toString8 (string, data, 0, 16); #endif } //------------------------------------------------------------------------ bool FUID::fromString (const char8* string) { if (!string || !*string) return false; if (strlen (string) != 32) return false; #if COM_COMPATIBLE GuidStruct g; char s[33]; strcpy (s, string); s[8] = 0; sscanf (s, "%x", &g.Data1); strcpy (s, string + 8); s[4] = 0; sscanf (s, "%hx", &g.Data2); strcpy (s, string + 12); s[4] = 0; sscanf (s, "%hx", &g.Data3); memcpy (data, &g, 8); Steinberg::fromString8 (string + 16, data, 8, 16); #else Steinberg::fromString8 (string, data, 0, 16); #endif return true; } //------------------------------------------------------------------------ bool FUID::fromRegistryString (const char8* string) { if (!string || !*string) return false; if (strlen (string) != 38) return false; // e.g. {c200e360-38c5-11ce-ae62-08002b2b79ef} #if COM_COMPATIBLE GuidStruct g; char8 s[10]; strncpy (s, string + 1, 8); s[8] = 0; sscanf (s, "%x", &g.Data1); strncpy (s, string + 10, 4); s[4] = 0; sscanf (s, "%hx", &g.Data2); strncpy (s, string + 15, 4); s[4] = 0; sscanf (s, "%hx", &g.Data3); memcpy (data, &g, 8); Steinberg::fromString8 (string + 20, data, 8, 10); Steinberg::fromString8 (string + 25, data, 10, 16); #else Steinberg::fromString8 (string + 1, data, 0, 4); Steinberg::fromString8 (string + 10, data, 4, 6); Steinberg::fromString8 (string + 15, data, 6, 8); Steinberg::fromString8 (string + 20, data, 8, 10); Steinberg::fromString8 (string + 25, data, 10, 16); #endif return true; } //------------------------------------------------------------------------ void FUID::toRegistryString (char8* string) const { // e.g. {c200e360-38c5-11ce-ae62-08002b2b79ef} #if COM_COMPATIBLE GuidStruct* g = (GuidStruct*)data; char8 s1[5]; Steinberg::toString8 (s1, data, 8, 10); char8 s2[13]; Steinberg::toString8 (s2, data, 10, 16); sprintf (string, "{%08X-%04X-%04X-%s-%s}", g->Data1, g->Data2, g->Data3, s1, s2); #else char8 s1[9]; Steinberg::toString8 (s1, data, 0, 4); char8 s2[5]; Steinberg::toString8 (s2, data, 4, 6); char8 s3[5]; Steinberg::toString8 (s3, data, 6, 8); char8 s4[5]; Steinberg::toString8 (s4, data, 8, 10); char8 s5[13]; Steinberg::toString8 (s5, data, 10, 16); sprintf (string, "{%s-%s-%s-%s-%s}", s1, s2, s3, s4, s5); #endif } //------------------------------------------------------------------------ void FUID::print (char8* string, int32 style) const { if (!string) // no string: debug output { char8 str[128]; print (str, style); #if SMTG_OS_WINDOWS OutputDebugStringA (str); OutputDebugStringA ("\n"); #else fprintf (stdout, "%s\n", str); #endif return; } uint32 l1, l2, l3, l4; to4Int (l1, l2, l3, l4); switch (style) { case kINLINE_UID: sprintf (string, "INLINE_UID (0x%08X, 0x%08X, 0x%08X, 0x%08X)", l1, l2, l3, l4); break; case kDECLARE_UID: sprintf (string, "DECLARE_UID (0x%08X, 0x%08X, 0x%08X, 0x%08X)", l1, l2, l3, l4); break; case kFUID: sprintf (string, "FUID (0x%08X, 0x%08X, 0x%08X, 0x%08X)", l1, l2, l3, l4); break; case kCLASS_UID: default: sprintf (string, "DECLARE_CLASS_IID (Interface, 0x%08X, 0x%08X, 0x%08X, 0x%08X)", l1, l2, l3, l4); break; } } //------------------------------------------------------------------------ // helpers //------------------------------------------------------------------------ static uint32 makeLong (uint8 b1, uint8 b2, uint8 b3, uint8 b4) { return (uint32 (b1) << 24) | (uint32 (b2) << 16) | (uint32 (b3) << 8) | uint32 (b4); } //------------------------------------------------------------------------ static void toString8 (char8* string, const char* data, int32 i1, int32 i2) { *string = 0; for (int32 i = i1; i < i2; i++) { char8 s[3]; sprintf (s, "%02X", (uint8)data[i]); strcat (string, s); } } //------------------------------------------------------------------------ static void fromString8 (const char8* string, char* data, int32 i1, int32 i2) { for (int32 i = i1; i < i2; i++) { char8 s[3]; s[0] = *string++; s[1] = *string++; s[2] = 0; int32 d = 0; sscanf (s, "%2x", &d); data[i] = (char)d; } } //------------------------------------------------------------------------ } // namespace Steinberg