mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-02 10:00:38 +01:00
Make UID output comply RFC 4122 (#306)
* Make UID output comply RFC 4122 * Update format specifier to explicit unsigned char type
This commit is contained in:
parent
c535672e55
commit
2a41326de2
@ -31,53 +31,52 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef WIN_NT
|
||||
#include <rpc.h>
|
||||
#else
|
||||
#include "fb_types.h"
|
||||
|
||||
struct UUID // Compatible with Win32 UUID struct layout.
|
||||
{
|
||||
ULONG Data1;
|
||||
USHORT Data2;
|
||||
USHORT Data3;
|
||||
UCHAR Data4[8];
|
||||
};
|
||||
#endif
|
||||
|
||||
namespace Firebird {
|
||||
|
||||
typedef UUID Guid;
|
||||
|
||||
const int GUID_BUFF_SIZE = 39;
|
||||
const int GUID_BODY_SIZE = 36;
|
||||
|
||||
const char* const GUID_LEGACY_FORMAT =
|
||||
"{%04hX%04hX-%04hX-%04hX-%04hX-%04hX%04hX%04hX}";
|
||||
const char* const GUID_NEW_FORMAT =
|
||||
"{%02hX%02hX%02hX%02hX-%02hX%02hX-%02hX%02hX-%02hX%02hX-%02hX%02hX%02hX%02hX%02hX%02hX}";
|
||||
|
||||
struct Guid
|
||||
{
|
||||
union
|
||||
{
|
||||
USHORT data[8];
|
||||
ULONG alignment; // makes sure C-cast to Win32GUID works correctly
|
||||
};
|
||||
};
|
||||
|
||||
struct Win32GUID // Compatible with Win32 GUID struct layout.
|
||||
{
|
||||
ULONG data1;
|
||||
USHORT data2;
|
||||
USHORT data3;
|
||||
UCHAR data4[8];
|
||||
};
|
||||
// Some versions of MSVC cannot recognize hh specifier but MSVC 2015 has it.
|
||||
const char* const GUID_FORMAT =
|
||||
"{%08X-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}";
|
||||
|
||||
void GenerateRandomBytes(void* buffer, FB_SIZE_T size);
|
||||
// Generates platform-depended UUID compatible with RFC 4122
|
||||
void GenerateGuid(Guid* guid);
|
||||
|
||||
// These functions receive buffers of at least GUID_BUFF_SIZE length.
|
||||
// Warning: they are BROKEN in little-endian and should not be used on new code.
|
||||
|
||||
inline void GuidToString(char* buffer, const Guid* guid)
|
||||
{
|
||||
sprintf(buffer, GUID_LEGACY_FORMAT,
|
||||
guid->data[0], guid->data[1], guid->data[2], guid->data[3],
|
||||
guid->data[4], guid->data[5], guid->data[6], guid->data[7]);
|
||||
sprintf(buffer, GUID_FORMAT,
|
||||
guid->Data1, guid->Data2, guid->Data3,
|
||||
guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
|
||||
guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
|
||||
}
|
||||
|
||||
inline void StringToGuid(Guid* guid, const char* buffer)
|
||||
{
|
||||
sscanf(buffer, GUID_LEGACY_FORMAT,
|
||||
&guid->data[0], &guid->data[1], &guid->data[2], &guid->data[3],
|
||||
&guid->data[4], &guid->data[5], &guid->data[6], &guid->data[7]);
|
||||
sscanf(buffer, GUID_FORMAT,
|
||||
&guid->Data1, &guid->Data2, &guid->Data3,
|
||||
&guid->Data4[0], &guid->Data4[1], &guid->Data4[2], &guid->Data4[3],
|
||||
&guid->Data4[4], &guid->Data4[5], &guid->Data4[6], &guid->Data4[7]);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -71,9 +71,8 @@ void GenerateGuid(Guid* guid)
|
||||
{
|
||||
GenerateRandomBytes(guid, sizeof(Guid));
|
||||
|
||||
Win32GUID* wg = (Win32GUID*) guid;
|
||||
wg->data3 = (4 << 12) | (wg->data3 & 0xFFF); // version 4
|
||||
wg->data4[0] = 0x80 | (wg->data4[0] & 0x3F); // variant
|
||||
guid->Data3 = (4 << 12) | (guid->Data3 & 0xFFF); // version 4
|
||||
guid->Data4[0] = 0x80 | (guid->Data4[0] & 0x3F); // variant
|
||||
}
|
||||
|
||||
|
||||
|
@ -76,7 +76,7 @@ void GenerateRandomBytes(void* buffer, FB_SIZE_T size)
|
||||
|
||||
void GenerateGuid(Guid* guid)
|
||||
{
|
||||
const HRESULT error = CoCreateGuid((GUID*) guid);
|
||||
const HRESULT error = CoCreateGuid(guid);
|
||||
if (!SUCCEEDED(error))
|
||||
Firebird::system_call_failed::raise("CoCreateGuid", error);
|
||||
}
|
||||
|
@ -354,7 +354,7 @@ namespace Jrd
|
||||
if (readOnly())
|
||||
return;
|
||||
|
||||
if (!dbb_guid.alignment) // hackery way to check whether it was loaded
|
||||
if (!dbb_guid.Data1) // It would be better to full check but one field should be enough
|
||||
{
|
||||
GenerateGuid(&dbb_guid);
|
||||
PAG_set_db_guid(tdbb, dbb_guid);
|
||||
|
@ -2346,26 +2346,20 @@ dsc* evlCharToUuid(thread_db* tdbb, const SysFunction* function, const NestValue
|
||||
}
|
||||
}
|
||||
|
||||
// convert to binary representation
|
||||
char buffer[GUID_BUFF_SIZE];
|
||||
buffer[0] = '{';
|
||||
buffer[37] = '}';
|
||||
buffer[38] = '\0';
|
||||
memcpy(buffer + 1, data, GUID_BODY_SIZE);
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#pragma message("Support of hh size modifier is not sure")
|
||||
#endif
|
||||
|
||||
USHORT bytes[16];
|
||||
sscanf(buffer, GUID_NEW_FORMAT,
|
||||
UCHAR bytes[16];
|
||||
sscanf(reinterpret_cast<const char*>(data),
|
||||
"%02hhX%02hhX%02hhX%02hhX-%02hhX%02hhX-%02hhX%02hhX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX",
|
||||
&bytes[0], &bytes[1], &bytes[2], &bytes[3],
|
||||
&bytes[4], &bytes[5], &bytes[6], &bytes[7],
|
||||
&bytes[8], &bytes[9], &bytes[10], &bytes[11],
|
||||
&bytes[12], &bytes[13], &bytes[14], &bytes[15]);
|
||||
|
||||
UCHAR resultData[16];
|
||||
for (unsigned i = 0; i < 16; ++i)
|
||||
resultData[i] = (UCHAR) bytes[i];
|
||||
|
||||
dsc result;
|
||||
result.makeText(16, ttype_binary, resultData);
|
||||
result.makeText(16, ttype_binary, bytes);
|
||||
EVL_make_value(tdbb, &result, impure);
|
||||
|
||||
return &impure->vlu_desc;
|
||||
@ -4111,29 +4105,30 @@ dsc* evlGenUuid(thread_db* tdbb, const SysFunction*, const NestValueArray& args,
|
||||
{
|
||||
fb_assert(args.getCount() == 0);
|
||||
|
||||
Guid fbguid;
|
||||
fb_assert(sizeof(fbguid.data) == 16);
|
||||
Guid guid;
|
||||
static_assert(sizeof(guid) == 16, "Guid size mismatch");
|
||||
|
||||
GenerateGuid(&fbguid);
|
||||
Win32GUID* guid = (Win32GUID*)&fbguid;
|
||||
GenerateGuid(&guid);
|
||||
|
||||
// Convert platform-depended UUID into platform-independent form
|
||||
// according to RFC 4122
|
||||
UCHAR data[16];
|
||||
data[0] = (guid->data1 >> 24) & 0xFF;
|
||||
data[1] = (guid->data1 >> 16) & 0xFF;
|
||||
data[2] = (guid->data1 >> 8) & 0xFF;
|
||||
data[3] = guid->data1 & 0xFF;
|
||||
data[4] = (guid->data2 >> 8) & 0xFF;
|
||||
data[5] = guid->data2 & 0xFF;
|
||||
data[6] = (guid->data3 >> 8) & 0xFF;
|
||||
data[7] = guid->data3 & 0xFF;
|
||||
data[8] = guid->data4[0];
|
||||
data[9] = guid->data4[1];
|
||||
data[10] = guid->data4[2];
|
||||
data[11] = guid->data4[3];
|
||||
data[12] = guid->data4[4];
|
||||
data[13] = guid->data4[5];
|
||||
data[14] = guid->data4[6];
|
||||
data[15] = guid->data4[7];
|
||||
data[0] = (guid.Data1 >> 24) & 0xFF;
|
||||
data[1] = (guid.Data1 >> 16) & 0xFF;
|
||||
data[2] = (guid.Data1 >> 8) & 0xFF;
|
||||
data[3] = guid.Data1 & 0xFF;
|
||||
data[4] = (guid.Data2 >> 8) & 0xFF;
|
||||
data[5] = guid.Data2 & 0xFF;
|
||||
data[6] = (guid.Data3 >> 8) & 0xFF;
|
||||
data[7] = guid.Data3 & 0xFF;
|
||||
data[8] = guid.Data4[0];
|
||||
data[9] = guid.Data4[1];
|
||||
data[10] = guid.Data4[2];
|
||||
data[11] = guid.Data4[3];
|
||||
data[12] = guid.Data4[4];
|
||||
data[13] = guid.Data4[5];
|
||||
data[14] = guid.Data4[6];
|
||||
data[15] = guid.Data4[7];
|
||||
|
||||
dsc result;
|
||||
result.makeText(16, ttype_binary, data);
|
||||
@ -6277,15 +6272,16 @@ dsc* evlUuidToChar(thread_db* tdbb, const SysFunction* function, const NestValue
|
||||
Arg::Str(function->name));
|
||||
}
|
||||
|
||||
char buffer[GUID_BUFF_SIZE];
|
||||
sprintf(buffer, GUID_NEW_FORMAT,
|
||||
USHORT(data[0]), USHORT(data[1]), USHORT(data[2]), USHORT(data[3]), USHORT(data[4]),
|
||||
USHORT(data[5]), USHORT(data[6]), USHORT(data[7]), USHORT(data[8]), USHORT(data[9]),
|
||||
USHORT(data[10]), USHORT(data[11]), USHORT(data[12]), USHORT(data[13]), USHORT(data[14]),
|
||||
USHORT(data[15]));
|
||||
UCHAR buffer[GUID_BUFF_SIZE];
|
||||
sprintf(reinterpret_cast<char*>(buffer),
|
||||
"%02hhX%02hhX%02hhX%02hhX-%02hhX%02hhX-%02hhX%02hhX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX",
|
||||
data[0], data[1], data[2], data[3], data[4],
|
||||
data[5], data[6], data[7], data[8], data[9],
|
||||
data[10], data[11], data[12], data[13], data[14],
|
||||
data[15]);
|
||||
|
||||
dsc result;
|
||||
result.makeText(GUID_BODY_SIZE, ttype_ascii, reinterpret_cast<UCHAR*>(buffer) + 1);
|
||||
result.makeText(GUID_BODY_SIZE, ttype_ascii, buffer);
|
||||
EVL_make_value(tdbb, &result, impure);
|
||||
|
||||
return &impure->vlu_desc;
|
||||
|
@ -97,6 +97,7 @@ Config::Config()
|
||||
logArchiveTimeout(DEFAULT_LOG_ARCHIVE_TIMEOUT),
|
||||
syncReplicas(getPool()),
|
||||
logSourceDirectory(getPool()),
|
||||
sourceGuid{},
|
||||
verboseLogging(false),
|
||||
applyIdleTimeout(DEFAULT_APPLY_IDLE_TIMEOUT),
|
||||
applyErrorTimeout(DEFAULT_APPLY_ERROR_TIMEOUT),
|
||||
@ -105,7 +106,6 @@ Config::Config()
|
||||
reportErrors(false),
|
||||
disableOnError(true)
|
||||
{
|
||||
sourceGuid.alignment = 0;
|
||||
}
|
||||
|
||||
Config::Config(const Config& other)
|
||||
@ -123,6 +123,7 @@ Config::Config(const Config& other)
|
||||
logArchiveTimeout(other.logArchiveTimeout),
|
||||
syncReplicas(getPool(), other.syncReplicas),
|
||||
logSourceDirectory(getPool(), other.logSourceDirectory),
|
||||
sourceGuid{},
|
||||
verboseLogging(other.verboseLogging),
|
||||
applyIdleTimeout(other.applyIdleTimeout),
|
||||
applyErrorTimeout(other.applyErrorTimeout),
|
||||
@ -131,7 +132,6 @@ Config::Config(const Config& other)
|
||||
reportErrors(other.reportErrors),
|
||||
disableOnError(other.disableOnError)
|
||||
{
|
||||
sourceGuid.alignment = 0;
|
||||
}
|
||||
|
||||
// This routine is used to match the database on the master side.
|
||||
|
@ -350,7 +350,7 @@ namespace
|
||||
|
||||
bool checkGuid(const Guid& guid)
|
||||
{
|
||||
if (!m_config->sourceGuid.alignment)
|
||||
if (!m_config->sourceGuid.Data1)
|
||||
return true;
|
||||
|
||||
if (!memcmp(&guid, &m_config->sourceGuid, sizeof(Guid)))
|
||||
|
Loading…
Reference in New Issue
Block a user