├── .gitignore ├── .gitmodules ├── README.md ├── tests ├── uuid_test.c └── uuid_test.cpp ├── uuid.c └── uuid.h /.gitignore: -------------------------------------------------------------------------------- 1 | /tests/build -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/cryptorand"] 2 | path = external/cryptorand 3 | url = https://github.com/mackron/cryptorand.git 4 | [submodule "external/md5"] 5 | path = external/md5 6 | url = https://github.com/mackron/md5.git 7 | [submodule "external/sha1"] 8 | path = external/sha1 9 | url = https://github.com/mackron/sha1.git 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

UUID Generator

2 | 3 |

4 | discord 5 | twitter 6 |

7 | 8 | This supports all UUID versions defined in RFC 4122 except version 2. For version 3 and 5 you will 9 | need to provide your own MD5 and SHA-1 hashing implementation by defining the some macros before 10 | the implementation of this library. Below is an example: 11 | 12 | #define UUID_MD5_CTX_TYPE md5_context 13 | #define UUID_MD5_INIT(ctx) md5_init(ctx) 14 | #define UUID_MD5_FINAL(ctx, digest) md5_finalize(ctx, (unsigned char*)(digest)) 15 | #define UUID_MD5_UPDATE(ctx, src, sz) md5_update(ctx, src, (size_t)(sz)) 16 | 17 | #define UUID_SHA1_CTX_TYPE sha1_context 18 | #define UUID_SHA1_INIT(ctx) sha1_init(ctx) 19 | #define UUID_SHA1_FINAL(ctx, digest) sha1_finalize(ctx, (unsigned char*)(digest)) 20 | #define UUID_SHA1_UPDATE(ctx, src, sz) sha1_update(ctx, src, (size_t)(sz)); 21 | 22 | A public domain MD5 and SHA-1 hashing implmentation can be found here: 23 | 24 | * https://github.com/mackron/md5 25 | * https://github.com/mackron/sha1 26 | 27 | These are included as submodules in this repository for your convenience but need not be used if 28 | you would rather use a different implementation. If you want to use these libraries, instead of 29 | defining the above macros you can just include them before the implementation like so and they'll 30 | automatically be detected: 31 | 32 | #include "external/md5/md5.c" // <-- Enables version 3. 33 | #include "external/sha1/sha1.c" // <-- Enables version 5. 34 | 35 | #define UUID_IMPLEMENTATION 36 | #include "uuid.h" 37 | 38 | There is no need to link to anything with this library. You can use UUID_IMPLEMENTATION to define 39 | the implementation section, or you can use uuid.c if you prefer a traditional header/source pair. 40 | 41 | Use the following APIs to generate a UUID: 42 | 43 | uuid1(unsigned char* pUUID, uuid_rand* pRNG); 44 | uuid3(unsigned char* pUUID, const unsigned char* pNamespaceUUID, const char* pName); 45 | uuid4(unsigned char* pUUID, uuid_rand* pRNG); 46 | uuid5(unsigned char* pUUID, const unsigned char* pNamespaceUUID, const char* pName); 47 | uuid_ordered(unsigned char* pUUID, uuid_rand* pRNG); 48 | 49 | If you want to use a time-based ordered UUID you can use `uuid_ordered()`. Note that this is not 50 | officially allowed by RFC 4122. This does not encode a version as it would break ordering. 51 | 52 | Use the following APIs to format the UUID as a string: 53 | 54 | uuid_format(char* pDst, size_t dstCap, const unsigned char* pUUID); 55 | 56 | The size of the UUID buffer must be at least `UUID_SIZE` (16 bytes). For formatted strings the 57 | destination buffer should be at least `UUID_SIZE_FORMATTED`. 58 | 59 | Example: 60 | 61 | unsigned char uuid[UUID_SIZE]; 62 | uuid4(uuid, NULL); 63 | 64 | char str[UUID_SIZE_FORMATTED]; 65 | uuid_format(str, sizeof(str), uuid); 66 | 67 | With the code above the default random number generator will be used (second parameter). If you 68 | want to use your own random number generator, you can pass in a random number generator: 69 | 70 | uuid4(uuid, &myRNG); 71 | 72 | The default random number generator is cryptorand: https://github.com/mackron/cryptorand. If you 73 | have access to the implementation section, you can make use of this easily: 74 | 75 | uuid_cryptorand rng; 76 | uuid_cryprorand_init(&rng); 77 | 78 | for (i = 0; i < count; i += 1) { 79 | uuid4(uuid, &rng); 80 | 81 | // ... do something with the UUID ... 82 | } 83 | 84 | uuiid_cryptorand_uninit(&rng); 85 | 86 | Alternatively you can implement your own random number generator by inheritting from 87 | `uuid_rand_callbacks` like so: 88 | 89 | typedef struct 90 | { 91 | uuid_rand_callbacks cb; 92 | } my_rng; 93 | 94 | static uuid_result my_rng_generate(uuid_rand* pRNG, void* pBufferOut, size_t byteCount) 95 | { 96 | my_rng* pMyRNG = (my_rng*)pRNG; 97 | 98 | // ... do random number generation here. Output byteCount bytes to pBufferOut. 99 | 100 | return UUID_SUCCESS; 101 | } 102 | 103 | ... 104 | 105 | // Initialize your random number generator. 106 | my_rng myRNG; 107 | rng.cb.onGenerator = my_rng_generate; 108 | 109 | // Generate your GUID. 110 | uuid4(uuid, &myRNG); 111 | 112 | You can disable cryptorand and compile time with `UUID_NO_CRYPTORAND`, but by doing so you will be 113 | required to specify your own random number generator. This is useful if you already have a good 114 | quality random number generator in your code base and want to save a little bit of space. -------------------------------------------------------------------------------- /tests/uuid_test.c: -------------------------------------------------------------------------------- 1 | #include "../external/md5/md5.c" /* <-- Enables version 3. */ 2 | #include "../external/sha1/sha1.c" /* <-- Enables version 5. */ 3 | 4 | /* 5 | The macros below can be used to enable a custom MD5 and/or SHA-1 implementation. 6 | */ 7 | #if 0 8 | #define UUID_MD5_CTX_TYPE md5_context 9 | #define UUID_MD5_INIT(ctx) md5_init(ctx) 10 | #define UUID_MD5_FINAL(ctx, digest) md5_finalize(ctx, (unsigned char*)(digest)) 11 | #define UUID_MD5_UPDATE(ctx, src, sz) md5_update(ctx, src, (size_t)(sz)) 12 | 13 | #define UUID_SHA1_CTX_TYPE sha1_context 14 | #define UUID_SHA1_INIT(ctx) sha1_init(ctx) 15 | #define UUID_SHA1_FINAL(ctx, digest) sha1_finalize(ctx, (unsigned char*)(digest)) 16 | #define UUID_SHA1_UPDATE(ctx, src, sz) sha1_update(ctx, src, (size_t)(sz)); 17 | #endif 18 | 19 | #define UUID_IMPLEMENTATION 20 | #include "../uuid.h" 21 | 22 | #include 23 | 24 | int main(int argc, char** argv) 25 | { 26 | unsigned char uuid[UUID_SIZE]; 27 | char uuidFormatted[UUID_SIZE_FORMATTED]; 28 | size_t i; 29 | size_t count = 10; 30 | 31 | 32 | printf("uuid1()\n"); 33 | { 34 | for (i = 0; i < count; i += 1) { 35 | uuid1(uuid, NULL); 36 | uuid_format(uuidFormatted, sizeof(uuidFormatted), uuid); 37 | printf("%s\n", uuidFormatted); 38 | } 39 | } 40 | printf("\n"); 41 | 42 | 43 | printf("uuid3()\n"); 44 | { 45 | for (i = 0; i < count; i += 1) { 46 | unsigned char ns[] = {0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}; /* "6ba7b811-9dad-11d1-80b4-00c04fd430c8" */ 47 | /*unsigned char ns[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};*/ /* "00000000-0000-0000-0000-000000000000" */ 48 | 49 | uuid3(uuid, ns, "Hello, World!"); 50 | uuid_format(uuidFormatted, sizeof(uuidFormatted), uuid); 51 | printf("%s\n", uuidFormatted); 52 | } 53 | } 54 | printf("\n"); 55 | 56 | 57 | printf("uuid4()\n"); 58 | { 59 | for (i = 0; i < count; i += 1) { 60 | uuid4(uuid, NULL); 61 | uuid_format(uuidFormatted, sizeof(uuidFormatted), uuid); 62 | printf("%s\n", uuidFormatted); 63 | } 64 | } 65 | printf("\n"); 66 | 67 | 68 | printf("uuid5()\n"); 69 | { 70 | for (i = 0; i < count; i += 1) { 71 | unsigned char ns[] = {0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}; /* "6ba7b811-9dad-11d1-80b4-00c04fd430c8" */ 72 | /*unsigned char ns[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};*/ /* "00000000-0000-0000-0000-000000000000" */ 73 | 74 | uuid5(uuid, ns, "Hello, World!"); 75 | uuid_format(uuidFormatted, sizeof(uuidFormatted), uuid); 76 | printf("%s\n", uuidFormatted); 77 | } 78 | } 79 | printf("\n"); 80 | 81 | 82 | printf("uuid_ordered()\n"); 83 | { 84 | for (i = 0; i < count; i += 1) { 85 | uuid_ordered(uuid, NULL); 86 | uuid_format(uuidFormatted, sizeof(uuidFormatted), uuid); 87 | printf("%s\n", uuidFormatted); 88 | } 89 | } 90 | printf("\n"); 91 | 92 | 93 | (void)argc; 94 | (void)argv; 95 | 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /tests/uuid_test.cpp: -------------------------------------------------------------------------------- 1 | #include "uuid_test.c" 2 | -------------------------------------------------------------------------------- /uuid.c: -------------------------------------------------------------------------------- 1 | #define UUID_IMPLEMENTATION 2 | #include "uuid.h" 3 | -------------------------------------------------------------------------------- /uuid.h: -------------------------------------------------------------------------------- 1 | /* 2 | UUID generation. Choice of public domain or MIT-0. See license statements at the end of this file. 3 | 4 | David Reid - mackron@gmail.com 5 | */ 6 | 7 | /* 8 | This supports all UUID versions defined in RFC 4122 except version 2. For version 3 and 5 you will 9 | need to provide your own MD5 and SHA-1 hashing implementation by defining the some macros before 10 | the implementation of this library. Below is an example: 11 | 12 | #define UUID_MD5_CTX_TYPE md5_context 13 | #define UUID_MD5_INIT(ctx) md5_init(ctx) 14 | #define UUID_MD5_FINAL(ctx, digest) md5_finalize(ctx, (unsigned char*)(digest)) 15 | #define UUID_MD5_UPDATE(ctx, src, sz) md5_update(ctx, src, (size_t)(sz)) 16 | 17 | #define UUID_SHA1_CTX_TYPE sha1_context 18 | #define UUID_SHA1_INIT(ctx) sha1_init(ctx) 19 | #define UUID_SHA1_FINAL(ctx, digest) sha1_finalize(ctx, (unsigned char*)(digest)) 20 | #define UUID_SHA1_UPDATE(ctx, src, sz) sha1_update(ctx, src, (size_t)(sz)); 21 | 22 | A public domain MD5 and SHA-1 hashing implmentation can be found here: 23 | 24 | * https://github.com/mackron/md5 25 | * https://github.com/mackron/sha1 26 | 27 | These are included as submodules in this repository for your convenience but need not be used if 28 | you would rather use a different implementation. If you want to use these libraries, instead of 29 | defining the above macros you can just include them before the implementation like so and they'll 30 | automatically be detected: 31 | 32 | #include "external/md5/md5.c" // <-- Enables version 3. 33 | #include "external/sha1/sha1.c" // <-- Enables version 5. 34 | 35 | #define UUID_IMPLEMENTATION 36 | #include "uuid.h" 37 | 38 | There is no need to link to anything with this library. You can use UUID_IMPLEMENTATION to define 39 | the implementation section, or you can use uuid.c if you prefer a traditional header/source pair. 40 | 41 | Use the following APIs to generate a UUID: 42 | 43 | uuid1(unsigned char* pUUID, uuid_rand* pRNG); 44 | uuid3(unsigned char* pUUID, const unsigned char* pNamespaceUUID, const char* pName); 45 | uuid4(unsigned char* pUUID, uuid_rand* pRNG); 46 | uuid5(unsigned char* pUUID, const unsigned char* pNamespaceUUID, const char* pName); 47 | uuid_ordered(unsigned char* pUUID, uuid_rand* pRNG); 48 | 49 | If you want to use a time-based ordered UUID you can use `uuid_ordered()`. Note that this is not 50 | officially allowed by RFC 4122. This does not encode a version as it would break ordering. 51 | 52 | Use the following APIs to format the UUID as a string: 53 | 54 | uuid_format(char* pDst, size_t dstCap, const unsigned char* pUUID); 55 | 56 | The size of the UUID buffer must be at least `UUID_SIZE` (16 bytes). For formatted strings the 57 | destination buffer should be at least `UUID_SIZE_FORMATTED`. 58 | 59 | Example: 60 | 61 | unsigned char uuid[UUID_SIZE]; 62 | uuid4(uuid, NULL); 63 | 64 | char str[UUID_SIZE_FORMATTED]; 65 | uuid_format(str, sizeof(str), uuid); 66 | 67 | With the code above the default random number generator will be used (second parameter). If you 68 | want to use your own random number generator, you can pass in a random number generator: 69 | 70 | uuid4(uuid, &myRNG); 71 | 72 | The default random number generator is cryptorand: https://github.com/mackron/cryptorand. If you 73 | have access to the implementation section, you can make use of this easily: 74 | 75 | uuid_cryptorand rng; 76 | uuid_cryprorand_init(&rng); 77 | 78 | for (i = 0; i < count; i += 1) { 79 | uuid4(uuid, &rng); 80 | 81 | // ... do something with the UUID ... 82 | } 83 | 84 | uuiid_cryptorand_uninit(&rng); 85 | 86 | Alternatively you can implement your own random number generator by inheritting from 87 | `uuid_rand_callbacks` like so: 88 | 89 | typedef struct 90 | { 91 | uuid_rand_callbacks cb; 92 | } my_rng; 93 | 94 | static uuid_result my_rng_generate(uuid_rand* pRNG, void* pBufferOut, size_t byteCount) 95 | { 96 | my_rng* pMyRNG = (my_rng*)pRNG; 97 | 98 | // ... do random number generation here. Output byteCount bytes to pBufferOut. 99 | 100 | return UUID_SUCCESS; 101 | } 102 | 103 | ... 104 | 105 | // Initialize your random number generator. 106 | my_rng myRNG; 107 | rng.cb.onGenerator = my_rng_generate; 108 | 109 | // Generate your GUID. 110 | uuid4(uuid, &myRNG); 111 | 112 | You can disable cryptorand and compile time with `UUID_NO_CRYPTORAND`, but by doing so you will be 113 | required to specify your own random number generator. This is useful if you already have a good 114 | quality random number generator in your code base and want to save a little bit of space. 115 | */ 116 | #ifndef uuid_h 117 | #define uuid_h 118 | 119 | #ifdef __cplusplus 120 | extern "C" { 121 | #endif 122 | 123 | #include 124 | 125 | #if !defined(UUID_API) 126 | #define UUID_API 127 | #endif 128 | 129 | #define UUID_SIZE 16 130 | #define UUID_SIZE_FORMATTED 37 131 | 132 | typedef enum 133 | { 134 | UUID_SUCCESS = 0, 135 | UUID_ERROR = -1, 136 | UUID_INVALID_ARGS = -2, 137 | UUID_INVALID_OPERATION = -3, 138 | UUID_NOT_IMPLEMENTED = -29 139 | } uuid_result; 140 | 141 | typedef void uuid_rand; 142 | typedef struct 143 | { 144 | uuid_result (* onGenerate)(uuid_rand* pRNG, void* pBufferOut, size_t byteCount); 145 | } uuid_rand_callbacks; 146 | 147 | UUID_API uuid_result uuid_rand_generate(uuid_rand* pRNG, void* pBufferOut, size_t byteCount); 148 | 149 | 150 | /* Generation. */ 151 | UUID_API uuid_result uuid1(unsigned char* pUUID, uuid_rand* pRNG); 152 | UUID_API uuid_result uuid3(unsigned char* pUUID, const unsigned char* pNamespaceUUID, const char* pName); 153 | UUID_API uuid_result uuid4(unsigned char* pUUID, uuid_rand* pRNG); 154 | UUID_API uuid_result uuid5(unsigned char* pUUID, const unsigned char* pNamespaceUUID, const char* pName); 155 | UUID_API uuid_result uuid_ordered(unsigned char* pUUID, uuid_rand* pRNG); 156 | 157 | /* Formatting. */ 158 | UUID_API uuid_result uuid_format(char* dst, size_t dstCap, const unsigned char* pUUID); 159 | 160 | #ifdef __cplusplus 161 | } 162 | #endif 163 | #endif /* uuid_h */ 164 | 165 | #if defined(UUID_IMPLEMENTATION) 166 | #ifndef uuid_c 167 | #define uuid_c 168 | 169 | typedef unsigned short uuid_uint16; 170 | typedef unsigned int uuid_uint32; 171 | #if defined(_MSC_VER) 172 | typedef unsigned __int64 uuid_uint64; 173 | #else 174 | typedef unsigned long long uuid_uint64; 175 | #endif 176 | 177 | #include 178 | #define UUID_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) 179 | #define UUID_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) 180 | #define UUID_ZERO_OBJECT(o) UUID_ZERO_MEMORY((o), sizeof(*o)) 181 | 182 | #ifndef UUID_ASSERT 183 | #include 184 | #define UUID_ASSERT(condition) assert(condition) 185 | #endif 186 | 187 | #include /* For timespec. */ 188 | 189 | #ifndef TIME_UTC 190 | #define TIME_UTC 1 191 | #endif 192 | 193 | /* 194 | We use `timespec` as the bridge for the cross-platform part of time retrieval. The annoying thing 195 | about this is that support varies depending on the age of the compiler. Since we're not exposing 196 | any of our timing functions publicly, the easiest way is to just define our own timespec-compatible 197 | struct and convert between the standard version and our version, depending on the compiler. 198 | */ 199 | #if 1 200 | struct uuid_timespec 201 | { 202 | time_t tv_sec; 203 | long tv_nsec; 204 | }; 205 | #else 206 | #if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(__DMC__) || (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE < 500) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE < 199309L) || defined(__STRICT_ANSI__) /* 1900 = Visual Studio 2015 */ 207 | struct uuid_timespec 208 | { 209 | time_t tv_sec; 210 | long tv_nsec; 211 | }; 212 | #else 213 | #define uuid_timespec timespec 214 | #endif 215 | #endif 216 | 217 | 218 | /* Define default MD5 and SHA-1 implementations if available. */ 219 | #if !defined(UUID_MD5_CTX_TYPE) 220 | #if defined(md5_h) && defined(MD5_SIZE) && defined(MD5_SIZE_FORMATTED) /* <-- Is this enough to detect our default MD5 implementation reliably? */ 221 | #define UUID_MD5_CTX_TYPE md5_context 222 | #define UUID_MD5_INIT(ctx) md5_init(ctx) 223 | #define UUID_MD5_FINAL(ctx, digest) md5_finalize(ctx, (unsigned char*)(digest)) 224 | #define UUID_MD5_UPDATE(ctx, src, sz) md5_update(ctx, src, (size_t)(sz)) 225 | #endif 226 | #endif 227 | 228 | #if !defined(UUID_SHA1_CTX_TYPE) 229 | #if defined(sha1_h) && defined(SHA1_SIZE) && defined(SHA1_SIZE_FORMATTED) /* <-- Is this enough to detect our default SHA-1 implementation reliably? */ 230 | #define UUID_SHA1_CTX_TYPE sha1_context 231 | #define UUID_SHA1_INIT(ctx) sha1_init(ctx) 232 | #define UUID_SHA1_FINAL(ctx, digest) sha1_finalize(ctx, (unsigned char*)(digest)) 233 | #define UUID_SHA1_UPDATE(ctx, src, sz) sha1_update(ctx, src, (size_t)(sz)); 234 | #endif 235 | #endif 236 | 237 | 238 | UUID_API uuid_result uuid_rand_generate(uuid_rand* pRNG, void* pBufferOut, size_t byteCount) 239 | { 240 | uuid_rand_callbacks* pCallbacks = (uuid_rand_callbacks*)pRNG; 241 | 242 | if (pBufferOut == NULL) { 243 | return UUID_INVALID_ARGS; 244 | } 245 | 246 | UUID_ZERO_MEMORY(pBufferOut, byteCount); 247 | 248 | if (pCallbacks == NULL || pCallbacks->onGenerate == NULL) { 249 | return UUID_INVALID_ARGS; 250 | } 251 | 252 | return pCallbacks->onGenerate(pRNG, pBufferOut, byteCount); 253 | } 254 | 255 | 256 | #if !defined(UUID_NO_CRYPTORAND) 257 | #define CRYPTORAND_IMPLEMENTATION 258 | #include "external/cryptorand/cryptorand.h" 259 | 260 | static uuid_result uuid_result_from_cryptorand(cryptorand_result result) 261 | { 262 | return (uuid_result)result; 263 | } 264 | 265 | typedef struct 266 | { 267 | uuid_rand_callbacks base; 268 | cryptorand rng; 269 | } uuid_cryptorand; 270 | 271 | static uuid_result uuid_cryptorand_generate(uuid_rand* pRNG, void* pBufferOut, size_t byteCount) 272 | { 273 | uuid_result result; 274 | 275 | if (pRNG == NULL) { 276 | return UUID_INVALID_ARGS; 277 | } 278 | 279 | result = uuid_result_from_cryptorand(cryptorand_generate(&((uuid_cryptorand*)pRNG)->rng, pBufferOut, byteCount)); 280 | if (result != UUID_SUCCESS) { 281 | return result; 282 | } 283 | 284 | return UUID_SUCCESS; 285 | } 286 | 287 | static uuid_result uuid_cryptorand_init(uuid_cryptorand* pRNG) 288 | { 289 | uuid_result result; 290 | 291 | if (pRNG == NULL) { 292 | return UUID_INVALID_ARGS; 293 | } 294 | 295 | UUID_ZERO_OBJECT(pRNG); 296 | 297 | result = uuid_result_from_cryptorand(cryptorand_init(&pRNG->rng)); 298 | if (result != UUID_SUCCESS) { 299 | return result; /* Failed to initialize RNG. */ 300 | } 301 | 302 | pRNG->base.onGenerate = uuid_cryptorand_generate; 303 | 304 | return UUID_SUCCESS; 305 | } 306 | 307 | static void uuid_cryptorand_uninit(uuid_cryptorand* pRNG) 308 | { 309 | if (pRNG == NULL) { 310 | return; 311 | } 312 | 313 | cryptorand_uninit(&pRNG->rng); 314 | UUID_ZERO_OBJECT(pRNG); 315 | } 316 | #endif /* UUID_NO_CRYPTORAND */ 317 | 318 | 319 | #if defined(_WIN32) 320 | #include 321 | 322 | static int uuid_timespec_get(struct uuid_timespec* ts, int base) 323 | { 324 | FILETIME ft; 325 | LONGLONG current100Nanoseconds; 326 | 327 | if (ts == NULL) { 328 | return 0; /* 0 = error. */ 329 | } 330 | 331 | ts->tv_sec = 0; 332 | ts->tv_nsec = 0; 333 | 334 | /* Currently only supporting UTC. */ 335 | if (base != TIME_UTC) { 336 | return 0; /* 0 = error. */ 337 | } 338 | 339 | GetSystemTimeAsFileTime(&ft); 340 | current100Nanoseconds = (((LONGLONG)ft.dwHighDateTime << 32) | (LONGLONG)ft.dwLowDateTime); 341 | current100Nanoseconds = current100Nanoseconds - ((LONGLONG)116444736 * 1000000000); /* Windows to Unix epoch. Normal value is 116444736000000000LL, but VC6 doesn't like 64-bit constants. */ 342 | 343 | ts->tv_sec = (time_t)(current100Nanoseconds / 10000000); 344 | ts->tv_nsec = (long)((current100Nanoseconds - (ts->tv_sec * 10000000)) * 100); 345 | 346 | return base; 347 | } 348 | #else 349 | #include /* For timeval. */ 350 | 351 | static struct uuid_timespec uuid_timespec_from_timeval(struct timeval* tv) 352 | { 353 | struct uuid_timespec ts; 354 | 355 | ts.tv_sec = tv->tv_sec; 356 | ts.tv_nsec = tv->tv_usec * 1000; 357 | 358 | return ts; 359 | } 360 | 361 | static int uuid_timespec_get(struct uuid_timespec* ts, int base) 362 | { 363 | UUID_ZERO_OBJECT(ts); 364 | 365 | /* 366 | This is annoying to get working on all compilers. Here's the hierarchy: 367 | 368 | * If using C11, use timespec_get(); else 369 | * If _POSIX_C_SOURCE >= 199309L, use clock_gettime(CLOCK_REALTIME, ...); else 370 | * Fall back to gettimeofday(). 371 | */ 372 | #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__APPLE__) 373 | { 374 | int result; 375 | struct timespec _ts; 376 | 377 | result = timespec_get(&_ts, base); 378 | if (result == 0) { 379 | return result; /* Failed to get the time. */ 380 | } 381 | 382 | ts->tv_sec = _ts.tv_sec; 383 | ts->tv_nsec = _ts.tv_nsec; 384 | 385 | return result; 386 | } 387 | #else 388 | { 389 | if (base != TIME_UTC) { 390 | return 0; /* Only TIME_UTC is supported. 0 = error. */ 391 | } 392 | 393 | #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L 394 | { 395 | struct timespec _ts; 396 | 397 | if (clock_gettime(CLOCK_REALTIME, &_ts) != 0) { 398 | return 0; /* Failed to retrieve the time. 0 = error. */ 399 | } 400 | 401 | ts->tv_sec = _ts.tv_sec; 402 | ts->tv_nsec = _ts.tv_nsec; 403 | 404 | /* Getting here means we were successful. On success, need to return base (strange...) */ 405 | return base; 406 | } 407 | #else 408 | { 409 | struct timeval tv; 410 | if (gettimeofday(&tv, NULL) != 0) { 411 | return 0; /* Failed to retrieve the time. 0 = error. */ 412 | } 413 | 414 | *ts = uuid_timespec_from_timeval(&tv); 415 | return base; 416 | } 417 | #endif /* _POSIX_C_SOURCE >= 199309L */ 418 | } 419 | #endif /* C11 */ 420 | } 421 | #endif 422 | 423 | static uuid_result uuid_get_time(uuid_uint64* pTime) 424 | { 425 | struct uuid_timespec ts; 426 | 427 | if (pTime == NULL) { 428 | return UUID_INVALID_ARGS; 429 | } 430 | 431 | *pTime = 0; 432 | 433 | if (uuid_timespec_get(&ts, TIME_UTC) == 0) { 434 | return UUID_ERROR; /* Failed to retrieve time. */ 435 | } 436 | 437 | *pTime = (ts.tv_sec * 10000000) + (ts.tv_nsec / 100); /* In 100-nanoseconds resolution. */ 438 | *pTime += (((uuid_uint64)0x01B21DD2 << 32) | 0x13814000); /* Conversion from Unix Epoch to UUID Epoch. Weird format here is for compatibility with VC6 because it doesn't like 64-bit constants. */ 439 | 440 | return UUID_SUCCESS; 441 | } 442 | 443 | static uuid_result uuid1_internal(unsigned char* pUUID, uuid_rand* pRNG) 444 | { 445 | uuid_result result; 446 | uuid_uint64 time; 447 | uuid_uint32 timeLow; 448 | uuid_uint16 timeMid; 449 | uuid_uint16 timeHiAndVersion; 450 | 451 | UUID_ASSERT(pUUID != NULL); 452 | UUID_ASSERT(pRNG != NULL); 453 | 454 | result = uuid_get_time(&time); 455 | if (result != UUID_SUCCESS) { 456 | return result; 457 | } 458 | 459 | timeLow = (uuid_uint32) ((time >> 0) & 0xFFFFFFFF); 460 | timeMid = (uuid_uint16) ((time >> 32) & 0x0000FFFF); 461 | timeHiAndVersion = (uuid_uint16)(((time >> 48) & 0x00000FFF) | 0x1000); 462 | 463 | /* Time Low */ 464 | pUUID[0] = (unsigned char)((timeLow >> 24) & 0xFF); 465 | pUUID[1] = (unsigned char)((timeLow >> 16) & 0xFF); 466 | pUUID[2] = (unsigned char)((timeLow >> 8) & 0xFF); 467 | pUUID[3] = (unsigned char)((timeLow >> 0) & 0xFF); 468 | 469 | /* Time Mid */ 470 | pUUID[4] = (unsigned char)((timeMid >> 8) & 0xFF); 471 | pUUID[5] = (unsigned char)((timeMid >> 0) & 0xFF); 472 | 473 | /* Time High and Version */ 474 | pUUID[6] = (unsigned char)((timeHiAndVersion >> 8) & 0xFF); 475 | pUUID[7] = (unsigned char)((timeHiAndVersion >> 0) & 0xFF); 476 | 477 | /* For the clock sequence and node ID we're always using a random number. */ 478 | result = uuid_rand_generate(pRNG, pUUID + 8, UUID_SIZE - 8); 479 | if (result != UUID_SUCCESS) { 480 | UUID_ZERO_MEMORY(pUUID, UUID_SIZE); 481 | return result; 482 | } 483 | 484 | /* Byte 8 needs to be updated to reflect the variant. In our case it'll always be Variant 1. */ 485 | pUUID[8] = (unsigned char)(0x80 | (pUUID[8] & 0x3F)); 486 | 487 | return UUID_SUCCESS; 488 | } 489 | 490 | static uuid_result uuid3_internal(unsigned char* pUUID, const unsigned char* pNamespaceUUID, const char* pName) 491 | { 492 | #if defined(UUID_MD5_CTX_TYPE) 493 | unsigned char hash[16]; 494 | UUID_MD5_CTX_TYPE ctx; 495 | 496 | UUID_MD5_INIT(&ctx); 497 | { 498 | UUID_MD5_UPDATE(&ctx, pNamespaceUUID, UUID_SIZE); 499 | UUID_MD5_UPDATE(&ctx, (const unsigned char*)pName, strlen(pName)); 500 | } 501 | UUID_MD5_FINAL(&ctx, hash); 502 | 503 | UUID_COPY_MEMORY(pUUID, hash, UUID_SIZE); 504 | 505 | /* Byte 6 needs to be updated so the version number is set appropriately. */ 506 | pUUID[6] = (unsigned char)(0x30 | (pUUID[6] & 0x0F)); 507 | 508 | /* Byte 8 needs to be updated to reflect the variant. In our case it'll always be Variant 1. */ 509 | pUUID[8] = (unsigned char)(0x80 | (pUUID[8] & 0x3F)); 510 | 511 | return UUID_SUCCESS; 512 | #else 513 | (void)pUUID; 514 | (void)pNamespaceUUID; 515 | (void)pName; 516 | return UUID_NOT_IMPLEMENTED; 517 | #endif 518 | } 519 | 520 | static uuid_result uuid4_internal(unsigned char* pUUID, uuid_rand* pRNG) 521 | { 522 | uuid_result result; 523 | 524 | UUID_ASSERT(pUUID != NULL); 525 | UUID_ASSERT(pRNG != NULL); 526 | 527 | /* First just generate some random numbers. */ 528 | result = uuid_rand_generate(pRNG, pUUID, UUID_SIZE); 529 | if (result != UUID_SUCCESS) { 530 | UUID_ZERO_MEMORY(pUUID, UUID_SIZE); 531 | return result; 532 | } 533 | 534 | /* Byte 6 needs to be updated so the version number is set appropriately. */ 535 | pUUID[6] = (unsigned char)(0x40 | (pUUID[6] & 0x0F)); 536 | 537 | /* Byte 8 needs to be updated to reflect the variant. In our case it'll always be Variant 1. */ 538 | pUUID[8] = (unsigned char)(0x80 | (pUUID[8] & 0x3F)); 539 | 540 | return UUID_SUCCESS; 541 | } 542 | 543 | static uuid_result uuid5_internal(unsigned char* pUUID, const unsigned char* pNamespaceUUID, const char* pName) 544 | { 545 | #if defined(UUID_SHA1_CTX_TYPE) 546 | unsigned char hash[20]; 547 | UUID_SHA1_CTX_TYPE ctx; 548 | 549 | UUID_SHA1_INIT(&ctx); 550 | { 551 | UUID_SHA1_UPDATE(&ctx, pNamespaceUUID, UUID_SIZE); 552 | UUID_SHA1_UPDATE(&ctx, (const unsigned char*)pName, strlen(pName)); 553 | } 554 | UUID_SHA1_FINAL(&ctx, hash); 555 | 556 | UUID_COPY_MEMORY(pUUID, hash, UUID_SIZE); 557 | 558 | /* Byte 6 needs to be updated so the version number is set appropriately. */ 559 | pUUID[6] = (unsigned char)(0x50 | (pUUID[6] & 0x0F)); 560 | 561 | /* Byte 8 needs to be updated to reflect the variant. In our case it'll always be Variant 1. */ 562 | pUUID[8] = (unsigned char)(0x80 | (pUUID[8] & 0x3F)); 563 | 564 | return UUID_SUCCESS; 565 | #else 566 | (void)pUUID; 567 | (void)pNamespaceUUID; 568 | (void)pName; 569 | return UUID_NOT_IMPLEMENTED; 570 | #endif 571 | } 572 | 573 | static uuid_result uuid_ordered_internal(unsigned char* pUUID, uuid_rand* pRNG) 574 | { 575 | uuid_result result; 576 | uuid_uint64 time; 577 | uuid_uint32 timeLow; 578 | uuid_uint16 timeMid; 579 | uuid_uint16 timeHi; 580 | 581 | UUID_ASSERT(pUUID != NULL); 582 | UUID_ASSERT(pRNG != NULL); 583 | 584 | result = uuid_get_time(&time); 585 | if (result != UUID_SUCCESS) { 586 | return result; 587 | } 588 | 589 | timeLow = (uuid_uint32)((time >> 0) & 0xFFFFFFFF); 590 | timeMid = (uuid_uint16)((time >> 32) & 0x0000FFFF); 591 | timeHi = (uuid_uint16)((time >> 48) & 0x00000FFF); 592 | 593 | /* Time High and Version */ 594 | pUUID[0] = (unsigned char)((timeHi >> 8) & 0xFF); 595 | pUUID[1] = (unsigned char)((timeHi >> 0) & 0xFF); 596 | 597 | /* Time Mid */ 598 | pUUID[2] = (unsigned char)((timeMid >> 8) & 0xFF); 599 | pUUID[3] = (unsigned char)((timeMid >> 0) & 0xFF); 600 | 601 | /* Time Low */ 602 | pUUID[4] = (unsigned char)((timeLow >> 24) & 0xFF); 603 | pUUID[5] = (unsigned char)((timeLow >> 16) & 0xFF); 604 | pUUID[6] = (unsigned char)((timeLow >> 8) & 0xFF); 605 | pUUID[7] = (unsigned char)((timeLow >> 0) & 0xFF); 606 | 607 | 608 | /* For the clock sequence and node ID we're always using a random number. */ 609 | result = uuid_rand_generate(pRNG, pUUID + 8, UUID_SIZE - 8); 610 | if (result != UUID_SUCCESS) { 611 | UUID_ZERO_MEMORY(pUUID, UUID_SIZE); 612 | return result; 613 | } 614 | 615 | /* Setting the version number breaks the ordering property of these UUIDs so I'm leaving this unset. */ 616 | /*pUUID[6] = (unsigned char)(0x40 | (pUUID[6] & 0x0F));*/ 617 | 618 | /* Byte 8 needs to be updated to reflect the variant. In our case it'll always be Variant 1. */ 619 | pUUID[8] = (unsigned char)(0x80 | (pUUID[8] & 0x3F)); 620 | 621 | return UUID_SUCCESS; 622 | } 623 | 624 | 625 | typedef enum 626 | { 627 | UUID_VERSION_1 = 1, /* Timed. */ 628 | UUID_VERSION_2 = 2, /* ??? */ 629 | UUID_VERSION_3 = 3, /* Named with MD5 hashing. */ 630 | UUID_VERSION_4 = 4, /* Random. */ 631 | UUID_VERSION_5 = 5, /* Named with SHA1 hashing. */ 632 | UUID_VERSION_ORDERED = 100 /* Unofficial. Similar to version 1, but the time part is swapped so that it's sorted by time. Useful for database keys. */ 633 | } uuid_version; 634 | 635 | static uuid_result uuidn(unsigned char* pUUID, uuid_rand* pRNG, const unsigned char* pNamespaceUUID, const char* pName, uuid_version version) 636 | { 637 | uuid_result result; 638 | #if !defined(UUID_NO_CRYPTORAND) 639 | uuid_cryptorand cryptorandRNG; 640 | #endif 641 | 642 | if (pUUID == NULL) { 643 | return UUID_INVALID_ARGS; 644 | } 645 | 646 | UUID_ZERO_MEMORY(pUUID, UUID_SIZE); 647 | 648 | /* Some versions need s random number generator. */ 649 | if (version == UUID_VERSION_1 || version == UUID_VERSION_4 || version == UUID_VERSION_ORDERED) { 650 | if (pRNG == NULL) { 651 | #if !defined(UUID_NO_CRYPTORAND) 652 | result = uuid_cryptorand_init(&cryptorandRNG); 653 | if (result != UUID_SUCCESS) { 654 | return result; 655 | } 656 | 657 | pRNG = &cryptorandRNG; 658 | #else 659 | return UUID_INVALID_ARGS; /* No random number generator available. */ 660 | #endif 661 | } 662 | } 663 | 664 | switch (version) 665 | { 666 | case UUID_VERSION_1: result = uuid1_internal(pUUID, pRNG); break; 667 | case UUID_VERSION_2: result = UUID_NOT_IMPLEMENTED; break; 668 | case UUID_VERSION_3: result = uuid3_internal(pUUID, pNamespaceUUID, pName); break; 669 | case UUID_VERSION_4: result = uuid4_internal(pUUID, pRNG); break; 670 | case UUID_VERSION_5: result = uuid5_internal(pUUID, pNamespaceUUID, pName); break; 671 | case UUID_VERSION_ORDERED: result = uuid_ordered_internal(pUUID, pRNG); break; 672 | default: result = UUID_INVALID_ARGS; break; /* Unknown or unsupported version. */ 673 | }; 674 | 675 | #if !defined(UUID_NO_CRYPTORAND) 676 | if (pRNG == &cryptorandRNG) { 677 | uuid_cryptorand_uninit(&cryptorandRNG); 678 | } 679 | #endif 680 | 681 | return result; 682 | } 683 | 684 | 685 | UUID_API uuid_result uuid1(unsigned char* pUUID, uuid_rand* pRNG) 686 | { 687 | return uuidn(pUUID, pRNG, NULL, NULL, UUID_VERSION_1); 688 | } 689 | 690 | UUID_API uuid_result uuid3(unsigned char* pUUID, const unsigned char* pNamespaceUUID, const char* pName) 691 | { 692 | return uuidn(pUUID, NULL, pNamespaceUUID, pName, UUID_VERSION_3); 693 | } 694 | 695 | UUID_API uuid_result uuid4(unsigned char* pUUID, uuid_rand* pRNG) 696 | { 697 | return uuidn(pUUID, pRNG, NULL, NULL, UUID_VERSION_4); 698 | } 699 | 700 | UUID_API uuid_result uuid5(unsigned char* pUUID, const unsigned char* pNamespaceUUID, const char* pName) 701 | { 702 | return uuidn(pUUID, NULL, pNamespaceUUID, pName, UUID_VERSION_5); 703 | } 704 | 705 | UUID_API uuid_result uuid_ordered(unsigned char* pUUID, uuid_rand* pRNG) 706 | { 707 | return uuidn(pUUID, pRNG, NULL, NULL, UUID_VERSION_ORDERED); 708 | } 709 | 710 | 711 | 712 | 713 | static void uuid_format_byte(char* dst, unsigned char byte) 714 | { 715 | const char* hex = "0123456789abcdef"; 716 | dst[0] = hex[(byte & 0xF0) >> 4]; 717 | dst[1] = hex[(byte & 0x0F) ]; 718 | } 719 | 720 | UUID_API uuid_result uuid_format(char* dst, size_t dstCap, const unsigned char* pUUID) 721 | { 722 | const char* format = "xxxx-xx-xx-xx-xxxxxx"; 723 | 724 | if (dst == NULL) { 725 | return UUID_INVALID_ARGS; 726 | } 727 | 728 | if (dstCap < UUID_SIZE_FORMATTED) { 729 | if (dstCap > 0) { 730 | dst[0] = '\0'; 731 | } 732 | 733 | return UUID_INVALID_ARGS; 734 | } 735 | 736 | if (pUUID == NULL) { 737 | dst[0] = '\0'; 738 | return UUID_INVALID_ARGS; 739 | } 740 | 741 | /* All we need to do here is convert the string to hex with dashes. */ 742 | for (;;) { 743 | if (format[0] == '\0') { 744 | break; 745 | } 746 | 747 | if (format[0] == 'x') { 748 | uuid_format_byte(dst, pUUID[0]); 749 | dst += 2; 750 | pUUID += 1; 751 | } else { 752 | dst[0] = format[0]; 753 | dst += 1; 754 | } 755 | 756 | format += 1; 757 | } 758 | 759 | /* Never forget to null terminate. */ 760 | dst[0] = '\0'; 761 | 762 | return UUID_SUCCESS; 763 | } 764 | 765 | #endif /* uuid_c */ 766 | #endif /* UUID_IMPLEMENTATION */ 767 | 768 | /* 769 | This software is available as a choice of the following licenses. Choose 770 | whichever you prefer. 771 | 772 | =============================================================================== 773 | ALTERNATIVE 1 - Public Domain (www.unlicense.org) 774 | =============================================================================== 775 | This is free and unencumbered software released into the public domain. 776 | 777 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 778 | software, either in source code form or as a compiled binary, for any purpose, 779 | commercial or non-commercial, and by any means. 780 | 781 | In jurisdictions that recognize copyright laws, the author or authors of this 782 | software dedicate any and all copyright interest in the software to the public 783 | domain. We make this dedication for the benefit of the public at large and to 784 | the detriment of our heirs and successors. We intend this dedication to be an 785 | overt act of relinquishment in perpetuity of all present and future rights to 786 | this software under copyright law. 787 | 788 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 789 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 790 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 791 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 792 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 793 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 794 | 795 | For more information, please refer to 796 | 797 | =============================================================================== 798 | ALTERNATIVE 2 - MIT No Attribution 799 | =============================================================================== 800 | Copyright 2022 David Reid 801 | 802 | Permission is hereby granted, free of charge, to any person obtaining a copy of 803 | this software and associated documentation files (the "Software"), to deal in 804 | the Software without restriction, including without limitation the rights to 805 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 806 | of the Software, and to permit persons to whom the Software is furnished to do 807 | so. 808 | 809 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 810 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 811 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 812 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 813 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 814 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 815 | SOFTWARE. 816 | */ 817 | --------------------------------------------------------------------------------