2017-08-25 08:43:18 -04:00
|
|
|
// UUID.h
|
|
|
|
|
|
|
|
// Defines the cUUID class representing a Universally Unique Identifier
|
|
|
|
|
|
|
|
#include "Globals.h"
|
|
|
|
#include "UUID.h"
|
|
|
|
|
2017-08-30 10:00:06 -04:00
|
|
|
#include "mbedtls/md5.h"
|
2017-08-25 08:43:18 -04:00
|
|
|
|
|
|
|
|
|
|
|
/** UUID normalised in textual form. */
|
|
|
|
struct sShortUUID
|
|
|
|
{
|
|
|
|
char Data[32]{};
|
|
|
|
bool IsValid = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Returns the given UUID in shortened form with IsValid indicating success.
|
|
|
|
Doesn't check digits are hexadecimal but does check dashes if long form. */
|
|
|
|
static sShortUUID ShortenUUID(const AString & a_StringUUID)
|
|
|
|
{
|
|
|
|
sShortUUID UUID;
|
|
|
|
switch (a_StringUUID.size())
|
|
|
|
{
|
|
|
|
case 32:
|
|
|
|
{
|
|
|
|
// Already a short UUID
|
|
|
|
std::memcpy(UUID.Data, a_StringUUID.data(), 32);
|
|
|
|
UUID.IsValid = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 36:
|
|
|
|
{
|
|
|
|
// Long UUID, confirm dashed
|
|
|
|
if (
|
|
|
|
(a_StringUUID[ 8] != '-') ||
|
|
|
|
(a_StringUUID[13] != '-') ||
|
|
|
|
(a_StringUUID[18] != '-') ||
|
|
|
|
(a_StringUUID[23] != '-')
|
|
|
|
)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy everying but the dashes from the string
|
|
|
|
std::memcpy(UUID.Data, a_StringUUID.data(), 8);
|
|
|
|
std::memcpy(UUID.Data + 8, a_StringUUID.data() + 9, 4);
|
|
|
|
std::memcpy(UUID.Data + 12, a_StringUUID.data() + 14, 4);
|
|
|
|
std::memcpy(UUID.Data + 16, a_StringUUID.data() + 19, 4);
|
|
|
|
std::memcpy(UUID.Data + 20, a_StringUUID.data() + 24, 12);
|
|
|
|
UUID.IsValid = true;
|
|
|
|
}
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
return UUID;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Returns the integer value of the hex digit or 0xff if invalid. */
|
|
|
|
static Byte FromHexDigit(char a_Hex)
|
|
|
|
{
|
|
|
|
if (('0' <= a_Hex) && (a_Hex <= '9'))
|
|
|
|
{
|
|
|
|
return static_cast<Byte>(a_Hex - '0');
|
|
|
|
}
|
|
|
|
if (('a' <= a_Hex) && (a_Hex <= 'f'))
|
|
|
|
{
|
2017-08-29 09:34:09 -04:00
|
|
|
return static_cast<Byte>(10 + (a_Hex - 'a'));
|
2017-08-25 08:43:18 -04:00
|
|
|
}
|
|
|
|
if (('A' <= a_Hex) && (a_Hex <= 'F'))
|
|
|
|
{
|
2017-08-29 09:34:09 -04:00
|
|
|
return static_cast<Byte>(10 + (a_Hex - 'A'));
|
2017-08-25 08:43:18 -04:00
|
|
|
}
|
|
|
|
return 0xff;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** From a number in the range [0, 16), returns the corresponding hex digit in lowercase. */
|
|
|
|
static char ToHexDigit(UInt8 a_Nibble)
|
|
|
|
{
|
|
|
|
ASSERT((a_Nibble & 0xf0) == 0);
|
|
|
|
return static_cast<char>(
|
|
|
|
(a_Nibble < 10) ?
|
|
|
|
('0' + a_Nibble) :
|
|
|
|
('a' + (a_Nibble - 10))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// cUUID:
|
|
|
|
|
|
|
|
bool cUUID::FromString(const AString & a_StringUUID)
|
|
|
|
{
|
|
|
|
sShortUUID Norm = ShortenUUID(a_StringUUID);
|
|
|
|
if (!Norm.IsValid)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::array<Byte, 16> ParsedUUID{{0}};
|
|
|
|
for (size_t i = 0; i != m_UUID.size(); ++i)
|
|
|
|
{
|
|
|
|
Byte HighNibble = FromHexDigit(Norm.Data[2 * i ]);
|
|
|
|
Byte LowNibble = FromHexDigit(Norm.Data[2 * i + 1]);
|
|
|
|
if ((HighNibble > 0x0f) || (LowNibble > 0x0f))
|
|
|
|
{
|
|
|
|
// Invalid hex digit
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ParsedUUID[i] = static_cast<Byte>((HighNibble << 4) | LowNibble);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parsed successfully
|
|
|
|
m_UUID = ParsedUUID;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AString cUUID::ToShortString() const
|
|
|
|
{
|
|
|
|
AString ShortString(32, '\0');
|
|
|
|
for (size_t i = 0; i != m_UUID.size(); ++i)
|
|
|
|
{
|
|
|
|
Byte HighNibble = (m_UUID[i] >> 4) & 0x0f;
|
|
|
|
Byte LowNibble = m_UUID[i] & 0x0f;
|
|
|
|
|
|
|
|
ShortString[2 * i ] = ToHexDigit(HighNibble);
|
|
|
|
ShortString[2 * i + 1] = ToHexDigit(LowNibble);
|
|
|
|
}
|
|
|
|
return ShortString;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AString cUUID::ToLongString() const
|
|
|
|
{
|
|
|
|
AString LongString = ToShortString();
|
|
|
|
LongString.reserve(36);
|
|
|
|
|
|
|
|
// Convert to long form by inserting the dashes
|
|
|
|
auto First = LongString.begin();
|
|
|
|
LongString.insert(First + 8, '-');
|
|
|
|
LongString.insert(First + 13, '-');
|
|
|
|
LongString.insert(First + 18, '-');
|
|
|
|
LongString.insert(First + 23, '-');
|
|
|
|
|
|
|
|
return LongString;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UInt8 cUUID::Version() const
|
|
|
|
{
|
|
|
|
return static_cast<UInt8>((m_UUID[6] >> 4) & 0x0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UInt8 cUUID::Variant() const
|
|
|
|
{
|
2018-04-07 18:20:53 -04:00
|
|
|
const Byte VariantBits = static_cast<Byte>((m_UUID[8] >> 5) & 0x07);
|
2017-08-25 08:43:18 -04:00
|
|
|
|
|
|
|
/* Variant bits format:
|
|
|
|
bits | variant | Description
|
|
|
|
-----|---------|----------------------
|
|
|
|
0xx | 0 | Obsolete
|
|
|
|
10x | 1 | Standard UUID
|
|
|
|
110 | 2 | Microsoft Legacy GUID
|
|
|
|
111 | 3 | Reserved
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ((VariantBits & 0x04) == 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else if ((VariantBits & 0x02) == 0)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else if ((VariantBits & 0x01) == 0)
|
|
|
|
{
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::array<Byte, 16> cUUID::ToRaw() const
|
|
|
|
{
|
|
|
|
std::array<Byte, 16> Raw(m_UUID);
|
|
|
|
if (Variant() == 2)
|
|
|
|
{
|
|
|
|
// Convert to microsoft mixed-endian format
|
|
|
|
// First 3 components are host-endian, last 2 are network
|
|
|
|
auto First = reinterpret_cast<UInt32 *>(Raw.data());
|
|
|
|
*First = ntohl(*First);
|
|
|
|
|
|
|
|
auto Second = reinterpret_cast<UInt16 *>(&Raw[4]);
|
|
|
|
*Second = ntohs(*Second);
|
|
|
|
|
|
|
|
auto Third = Second + 1;
|
|
|
|
*Third = ntohs(*Third);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Raw;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cUUID::FromRaw(const std::array<Byte, 16> & a_Raw)
|
|
|
|
{
|
|
|
|
m_UUID = a_Raw;
|
|
|
|
if (Variant() != 2)
|
|
|
|
{
|
|
|
|
// Standard big-endian formats
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert from microsoft mixed-endian format
|
|
|
|
// First 3 components are host-endian, last 2 are network
|
|
|
|
auto First = reinterpret_cast<UInt32 *>(m_UUID.data());
|
|
|
|
*First = htonl(*First);
|
|
|
|
|
|
|
|
auto Second = reinterpret_cast<UInt16 *>(&m_UUID[4]);
|
|
|
|
*Second = htons(*Second);
|
|
|
|
|
|
|
|
auto Third = Second + 1;
|
|
|
|
*Third = htons(*Third);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cUUID cUUID::GenerateVersion3(const AString & a_Name)
|
|
|
|
{
|
|
|
|
cUUID UUID;
|
|
|
|
// Generate an md5 checksum, and use it as base for the ID:
|
|
|
|
const Byte * ByteString = reinterpret_cast<const Byte *>(a_Name.data());
|
2017-08-30 10:00:06 -04:00
|
|
|
mbedtls_md5(ByteString, a_Name.length(), UUID.m_UUID.data());
|
2017-08-25 08:43:18 -04:00
|
|
|
|
|
|
|
// Insert version number
|
|
|
|
UUID.m_UUID[6] = (UUID.m_UUID[6] & 0x0f) | 0x30;
|
|
|
|
|
2018-07-19 19:30:09 -04:00
|
|
|
// Insert variant number
|
|
|
|
UUID.m_UUID[8] = (UUID.m_UUID[8] & 0x3f) | 0x80;
|
2017-08-25 08:43:18 -04:00
|
|
|
|
|
|
|
return UUID;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|