478 lines
12 KiB
C++
478 lines
12 KiB
C++
//-----------------------------------------------------------------------------
|
|
// 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 <stdio.h>
|
|
|
|
#if SMTG_OS_WINDOWS
|
|
#include <objbase.h>
|
|
|
|
#if defined(__MINGW32__)
|
|
/* UUID */
|
|
#include <string>
|
|
#include <boost/uuid/uuid.hpp>
|
|
#include <boost/uuid/uuid_generators.hpp>
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if SMTG_OS_MACOS
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
#include <libkern/OSAtomic.h>
|
|
|
|
#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
|
|
#include <ext/atomicity.h>
|
|
/* UUID */
|
|
#include <string>
|
|
#include <boost/uuid/uuid.hpp>
|
|
#include <boost/uuid/uuid_generators.hpp>
|
|
#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_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
|