From cac08af3dc5cf09bc5c19eb55c7785bfc4db4f74 Mon Sep 17 00:00:00 2001 From: Clifford Allan Jansen Date: Thu, 2 May 2013 18:18:00 +0000 Subject: QPID-4792: convert between UUIDs and GUIDs as needed for Microsoft APIs git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1478471 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/cpp/src/qpid/sys/windows/uuid.cpp | 96 +++++++++++++++++++++++++++++----- 1 file changed, 83 insertions(+), 13 deletions(-) (limited to 'qpid/cpp/src') diff --git a/qpid/cpp/src/qpid/sys/windows/uuid.cpp b/qpid/cpp/src/qpid/sys/windows/uuid.cpp index 3316ecbc00..d4f57fcab6 100644 --- a/qpid/cpp/src/qpid/sys/windows/uuid.cpp +++ b/qpid/cpp/src/qpid/sys/windows/uuid.cpp @@ -19,6 +19,14 @@ * */ +/* + * UUIDs and GUIDs (both RFC 4122) differ on byte positions of the + * internal representation. This matters when encoding to the wire + * and adhering to versioning info. Microsoft APIs used here operate + * on GUIDs even if the name implies UUIDs. AMQP expects the UUID 128 + * bit format which is used here unless otherwise noted. + */ + #include #ifdef uuid_t /* Done in rpcdce.h */ # undef uuid_t @@ -28,7 +36,37 @@ #include +namespace { +inline void iswap (char *p1, char *p2) { + char t = *p1; + *p1 = *p2; + *p2 = t; +} + +void toUuid (const UUID *guid, uuid_t uuid) { + // copy then swap bytes + memcpy ((char *) uuid, (char *) guid, qpid::sys::UuidSize); + char *p = (char *) uuid; + iswap (p, p+3); + iswap (p+1, p+2); + iswap (p+4, p+5); + iswap (p+6, p+7); +} + +void printHex (const unsigned char *bytes, char *buf, int n) { + static char hexrep[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f'}; + for (;n ; n--) { + unsigned char b = *bytes++; + *buf++ = hexrep[b >> 4]; + *buf++ = hexrep[b & 0xf]; + } +} +} // namespace + + void uuid_clear (uuid_t uu) { + // all zeros, no change between GUID and UUID UuidCreateNil (reinterpret_cast(uu)); } @@ -37,7 +75,10 @@ void uuid_copy (uuid_t dst, const uuid_t src) { } void uuid_generate (uuid_t out) { - UuidCreate (reinterpret_cast(out)); + UUID guid; + UuidCreate (&guid); + // Version 4 GUID, convert to UUID + toUuid (&guid, out); } int uuid_is_null (const uuid_t uu) { @@ -46,22 +87,51 @@ int uuid_is_null (const uuid_t uu) { } int uuid_parse (const char *in, uuid_t uu) { - return UuidFromString ((unsigned char*)in, (UUID*)uu) == RPC_S_OK ? 0 : -1; + UUID guid; + if (UuidFromString ((unsigned char*)in, &guid) != RPC_S_OK) + return -1; + toUuid (&guid, uu); + return 0; } void uuid_unparse (const uuid_t uu, char *out) { - unsigned char *formatted; - if (UuidToString((UUID*)uu, &formatted) == RPC_S_OK) { -#ifdef _MSC_VER - strncpy_s (out, 36+1, (char*)formatted, _TRUNCATE); -#else - strncpy (out, (char*)formatted, 36+1); -#endif - RpcStringFree(&formatted); - } + const uint8_t *in = uu; + out[8] = out[13] = out[18] = out[23] = '-'; + printHex (in, out, 4); + printHex (in+4, out+9, 2); + printHex (in+6, out+14, 2); + printHex (in+8, out+19, 2); + printHex (in+10, out+24, 6); + out[36] = '\0'; +} + +namespace { + +typedef struct { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_hi_and_reserved; + uint8_t clock_seq_low; + uint8_t node[6]; +} rfc_uuid_t; + +#undef RFC_CMP +#define RFC_CMP(a, b) if (a != b) return (a < b) ? -1 : 1 + } int uuid_compare (const uuid_t a, const uuid_t b) { - RPC_STATUS unused; - return !UuidEqual((UUID*)a, (UUID*)b, &unused); + // Could convert each to a GUID and then use UuidEqual(), + // but RFC test is straight forward + rfc_uuid_t* u1 = (rfc_uuid_t *) a; + rfc_uuid_t* u2 = (rfc_uuid_t *) b; + RFC_CMP (u1->time_low, u2->time_low); + RFC_CMP (u1->time_mid, u2->time_mid); + RFC_CMP (u1->time_hi_and_version, u2->time_hi_and_version); + RFC_CMP (u1->clock_seq_hi_and_reserved, u2->clock_seq_hi_and_reserved); + RFC_CMP (u1->clock_seq_low, u2->clock_seq_low); + for (int i = 0; i < 6; i++) + RFC_CMP (u1->node[i], u2->node[i]); + return 0; } -- cgit v1.2.1