00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00037 #include "blocxx/BLOCXX_config.h"
00038 #include "blocxx/UUID.hpp"
00039 #include "blocxx/NonRecursiveMutex.hpp"
00040 #include "blocxx/NonRecursiveMutexLock.hpp"
00041 #include "blocxx/Types.hpp"
00042 #include "blocxx/Format.hpp"
00043 #include "blocxx/RandomNumber.hpp"
00044 #include "blocxx/ExceptionIds.hpp"
00045
00046 #if !defined(BLOCXX_WIN32)
00047 #include <sys/time.h>
00048 #endif
00049
00050 #include <string.h>
00051 #include <stdlib.h>
00052 #include <ctype.h>
00053
00054 namespace BLOCXX_NAMESPACE
00055 {
00056
00057 BLOCXX_DEFINE_EXCEPTION_WITH_ID(UUID);
00058
00059 namespace {
00060
00061 typedef UInt64 uuid_time_t;
00062 struct uuid_node_t
00063 {
00064 unsigned char nodeId[6];
00065 };
00066 struct uuid_state
00067 {
00068 uuid_time_t timestamp;
00069 uuid_node_t nodeId;
00070 UInt16 clockSequence;
00071 };
00072
00073 uuid_state g_state;
00074 NonRecursiveMutex g_guard;
00075
00076 #ifdef BLOCXX_WIN32
00077
00078
00079 static const unsigned __int64 epoch = 116444736000000000L;
00080
00081 int gettimeofday(struct timeval * tp, int bogusParm)
00082 {
00083 FILETIME file_time;
00084 SYSTEMTIME system_time;
00085 ULARGE_INTEGER ularge;
00086
00087 GetSystemTime(&system_time);
00088 SystemTimeToFileTime(&system_time, &file_time);
00089 ularge.LowPart = file_time.dwLowDateTime;
00090 ularge.HighPart = file_time.dwHighDateTime;
00091
00092 tp->tv_sec = (long) ((ularge.QuadPart - epoch) / 10000000L);
00093 tp->tv_usec = (long) (system_time.wMilliseconds * 1000);
00094
00095 return 0;
00096 }
00097 #endif
00098
00100 void getSystemTime(uuid_time_t *uuid_time)
00101 {
00102 struct timeval tp;
00103 gettimeofday(&tp, 0);
00104
00105
00106
00107 *uuid_time =
00108 (static_cast<unsigned long long>(tp.tv_sec) * 10000000) +
00109 (tp.tv_usec * 10) +
00110 ((static_cast<unsigned long long>(0x01B21DD2)) << 32) +
00111 0x13814000;
00112 }
00114
00115 uuid_time_t timeLast;
00116 UInt16 uuidsThisTick;
00117 bool currentTimeInited = false;
00118 void getCurrentTime(uuid_time_t * timestamp)
00119 {
00120 uuid_time_t timeNow;
00121 if (!currentTimeInited)
00122 {
00123 getSystemTime(&timeLast);
00124 uuidsThisTick = 0;
00125 currentTimeInited = true;
00126 }
00127 getSystemTime(&timeNow);
00128 if (timeLast != timeNow)
00129 {
00130 uuidsThisTick = 0;
00131 timeLast = timeNow;
00132 }
00133 else
00134 {
00135 uuidsThisTick++;
00136 }
00137
00138 *timestamp = timeNow + uuidsThisTick;
00139 }
00141 void getRandomBytes(void* buf, size_t len)
00142 {
00143 RandomNumber rn;
00144 unsigned char* cp = reinterpret_cast<unsigned char*>(buf);
00145 for (size_t i = 0; i < len; ++cp, ++i)
00146 {
00147
00148 *cp = rn.getNextNumber() >> 13;
00149 }
00150 }
00152
00153 unsigned char nodeId[6];
00154 bool nodeIdInitDone = false;
00155 void getNodeIdentifier(uuid_node_t *node)
00156 {
00157
00158
00159
00160 if (!nodeIdInitDone)
00161 {
00162 getRandomBytes(nodeId, sizeof(nodeId));
00163
00164 nodeId[0] |= 0x80;
00165 nodeIdInitDone = true;
00166 }
00167 memcpy(node->nodeId, nodeId, sizeof(node->nodeId));
00168 }
00170 inline unsigned char decodeHex(char c)
00171 {
00172 if (isdigit(c))
00173 {
00174 return c - '0';
00175 }
00176 else
00177 {
00178 c = toupper(c);
00179 return c - 'A' + 0xA;
00180 }
00181 }
00183 inline unsigned char fromHexStr(char c1, char c2, const String& uuidStr)
00184 {
00185 if (!isxdigit(c1) || !isxdigit(c2))
00186 {
00187 BLOCXX_THROW(UUIDException, Format("Invalid UUID: %1", uuidStr).c_str());
00188 }
00189 return (decodeHex(c1) << 4) | decodeHex(c2);
00190 }
00192 inline char toHexHi(unsigned char c)
00193 {
00194 unsigned char t = c >> 4;
00195 return t >= 10 ? t - 10 + 'a' : t + '0';
00196 }
00198 inline char toHexLow(unsigned char c)
00199 {
00200 unsigned char t = c & 0xF;
00201 return t >= 10 ? t - 10 + 'a' : t + '0';
00202 }
00203 }
00205 UUID::UUID()
00206 {
00207 NonRecursiveMutexLock l(g_guard);
00208 uuid_time_t timestamp;
00209 getCurrentTime(×tamp);
00210 uuid_node_t node;
00211 getNodeIdentifier(&node);
00212 uuid_time_t last_time = g_state.timestamp;
00213 UInt16 clockseq = g_state.clockSequence;
00214 uuid_node_t last_node = g_state.nodeId;
00215
00216 if (timestamp < last_time)
00217 {
00218 ++clockseq;
00219 }
00220
00221 g_state.timestamp = last_time;
00222 g_state.clockSequence = clockseq;
00223 g_state.nodeId = last_node;
00224 l.release();
00225
00226
00227 UInt32 tmp = static_cast<UInt32>(timestamp & 0xFFFFFFFF);
00228 m_uuid[3] = static_cast<UInt8>(tmp);
00229 tmp >>= 8;
00230 m_uuid[2] = static_cast<UInt8>(tmp);
00231 tmp >>= 8;
00232 m_uuid[1] = static_cast<UInt8>(tmp);
00233 tmp >>= 8;
00234 m_uuid[0] = static_cast<UInt8>(tmp);
00235
00236 tmp = static_cast<UInt16>((timestamp >> 32) & 0xFFFF);
00237 m_uuid[5] = static_cast<UInt8>(tmp);
00238 tmp >>= 8;
00239 m_uuid[4] = static_cast<UInt8>(tmp);
00240
00241 tmp = static_cast<UInt16>(((timestamp >> 48) & 0x0FFF) | (1 << 12));
00242 m_uuid[7] = static_cast<UInt8>(tmp);
00243 tmp >>= 8;
00244 m_uuid[6] = static_cast<UInt8>(tmp);
00245
00246 tmp = clockseq & 0xFF;
00247 m_uuid[9] = static_cast<UInt8>(tmp);
00248
00249 tmp = (clockseq & 0x3F00) >> 8 | 0x80;
00250 m_uuid[8] = static_cast<UInt8>(tmp);
00251 memcpy(m_uuid+10, &node, 6);
00252 }
00254 UUID::UUID(const String& uuidStr)
00255 {
00256 const char* s = uuidStr.c_str();
00257 if (uuidStr.length() != 36 || s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-')
00258 {
00259 BLOCXX_THROW(UUIDException, Format("Invalid UUID: %1", uuidStr).c_str());
00260 }
00261 m_uuid[0] = fromHexStr(s[0], s[1], uuidStr);
00262 m_uuid[1] = fromHexStr(s[2], s[3], uuidStr);
00263 m_uuid[2] = fromHexStr(s[4], s[5], uuidStr);
00264 m_uuid[3] = fromHexStr(s[6], s[7], uuidStr);
00265 m_uuid[4] = fromHexStr(s[9], s[10], uuidStr);
00266 m_uuid[5] = fromHexStr(s[11], s[12], uuidStr);
00267 m_uuid[6] = fromHexStr(s[14], s[15], uuidStr);
00268 m_uuid[7] = fromHexStr(s[16], s[17], uuidStr);
00269 m_uuid[8] = fromHexStr(s[19], s[20], uuidStr);
00270 m_uuid[9] = fromHexStr(s[21], s[22], uuidStr);
00271 m_uuid[10] = fromHexStr(s[24], s[25], uuidStr);
00272 m_uuid[11] = fromHexStr(s[26], s[27], uuidStr);
00273 m_uuid[12] = fromHexStr(s[28], s[29], uuidStr);
00274 m_uuid[13] = fromHexStr(s[30], s[31], uuidStr);
00275 m_uuid[14] = fromHexStr(s[32], s[33], uuidStr);
00276 m_uuid[15] = fromHexStr(s[34], s[35], uuidStr);
00277 }
00279 String
00280 UUID::toString() const
00281 {
00282
00283
00284 const size_t uuidlen = 37;
00285 char* buf = new char[uuidlen];
00286 buf[0] = toHexHi(m_uuid[0]); buf[1] = toHexLow(m_uuid[0]);
00287 buf[2] = toHexHi(m_uuid[1]); buf[3] = toHexLow(m_uuid[1]);
00288 buf[4] = toHexHi(m_uuid[2]); buf[5] = toHexLow(m_uuid[2]);
00289 buf[6] = toHexHi(m_uuid[3]); buf[7] = toHexLow(m_uuid[3]);
00290 buf[8] = '-';
00291 buf[9] = toHexHi(m_uuid[4]); buf[10] = toHexLow(m_uuid[4]);
00292 buf[11] = toHexHi(m_uuid[5]); buf[12] = toHexLow(m_uuid[5]);
00293 buf[13] = '-';
00294 buf[14] = toHexHi(m_uuid[6]); buf[15] = toHexLow(m_uuid[6]);
00295 buf[16] = toHexHi(m_uuid[7]); buf[17] = toHexLow(m_uuid[7]);
00296 buf[18] = '-';
00297 buf[19] = toHexHi(m_uuid[8]); buf[20] = toHexLow(m_uuid[8]);
00298 buf[21] = toHexHi(m_uuid[9]); buf[22] = toHexLow(m_uuid[9]);
00299 buf[23] = '-';
00300 buf[24] = toHexHi(m_uuid[10]); buf[25] = toHexLow(m_uuid[10]);
00301 buf[26] = toHexHi(m_uuid[11]); buf[27] = toHexLow(m_uuid[11]);
00302 buf[28] = toHexHi(m_uuid[12]); buf[29] = toHexLow(m_uuid[12]);
00303 buf[30] = toHexHi(m_uuid[13]); buf[31] = toHexLow(m_uuid[13]);
00304 buf[32] = toHexHi(m_uuid[14]); buf[33] = toHexLow(m_uuid[14]);
00305 buf[34] = toHexHi(m_uuid[15]); buf[35] = toHexLow(m_uuid[15]);
00306 buf[36] = '\0';
00307 return String(String::E_TAKE_OWNERSHIP, buf, uuidlen-1);
00308 }
00310 bool operator==(const UUID& x, const UUID& y)
00311 {
00312 return memcmp(x.m_uuid, y.m_uuid, sizeof(x.m_uuid)) == 0;
00313 }
00315 bool operator<(const UUID& x, const UUID& y)
00316 {
00317 return memcmp(x.m_uuid, y.m_uuid, sizeof(x.m_uuid)) < 0;
00318 }
00320 bool operator!=(const UUID& x, const UUID& y)
00321 {
00322 return !(x == y);
00323 }
00324
00325 }
00326