├── .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 |
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.
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------