/src/dcmtk/ofstd/libsrc/ofuuidgn.cc
Line | Count | Source |
1 | | /* |
2 | | * |
3 | | * Copyright (C) 2026, OFFIS e.V. |
4 | | * All rights reserved. See COPYRIGHT file for details. |
5 | | * |
6 | | * This software and supporting documentation were developed by |
7 | | * |
8 | | * OFFIS e.V. |
9 | | * R&D Division Health |
10 | | * Escherweg 2 |
11 | | * D-26121 Oldenburg, Germany |
12 | | * |
13 | | * |
14 | | * Module: ofstd |
15 | | * |
16 | | * Author: Harald Roesen |
17 | | * |
18 | | * Purpose: Implementation of a Universally Unique IDentifier (UUID) Generator. |
19 | | * |
20 | | */ |
21 | | |
22 | | #include "dcmtk/config/osconfig.h" |
23 | | |
24 | | #include "dcmtk/ofstd/ofstd.h" |
25 | | #include "dcmtk/ofstd/ofuuidgn.h" |
26 | | |
27 | | |
28 | | BEGIN_EXTERN_C |
29 | | #ifdef HAVE_SYS_TIME_H |
30 | | #include <sys/time.h> |
31 | | #endif |
32 | | END_EXTERN_C |
33 | | |
34 | | #ifdef HAVE_WINDOWS_H |
35 | | #define WIN32_LEAN_AND_MEAN |
36 | | #include <windows.h> |
37 | | #endif |
38 | | |
39 | | |
40 | | OFUUIDGenerator::Uint32_32 OFUUIDGenerator::last_ms_since_epoch_ = OFUUIDGenerator::Uint32_32(); |
41 | | Uint16 OFUUIDGenerator::rand_b_field_ = 0; |
42 | | |
43 | | |
44 | | OFshared_ptr<OFUUID> |
45 | 0 | OFUUIDGenerator::create(rnd8 const & rnd) { |
46 | 0 | static OFMutex mutex; |
47 | |
|
48 | 0 | mutex.lock(); |
49 | |
|
50 | 0 | OFUUIDGenerator::initializeIfNecessary(); |
51 | |
|
52 | 0 | Uint32_32 const ms_since_epoch = getMillisecondsSinceEpoch(); |
53 | 0 | if (ms_since_epoch > OFUUIDGenerator::last_ms_since_epoch_) { |
54 | 0 | OFUUIDGenerator::last_ms_since_epoch_ = ms_since_epoch; |
55 | 0 | OFUUIDGenerator::rand_b_field_ = 1; |
56 | 0 | } |
57 | 0 | else { |
58 | 0 | ++OFUUIDGenerator::rand_b_field_; |
59 | | |
60 | | // The field 'rand_b' in UUIDv7 uses 12 bits (0x0fff), so look out for |
61 | | // possible overflow. |
62 | 0 | if (OFUUIDGenerator::rand_b_field_ > 0x0fff) { |
63 | 0 | OFUUIDGenerator::last_ms_since_epoch_.ladd(1); |
64 | 0 | OFUUIDGenerator::rand_b_field_ = 1; |
65 | 0 | } |
66 | 0 | } |
67 | |
|
68 | 0 | mutex.unlock(); |
69 | |
|
70 | 0 | OFUUID * const ofuuid = new (std::nothrow) OFUUID(); |
71 | 0 | if (ofuuid != NULL) { |
72 | 0 | setupOFUUIDDataMember(ofuuid, rnd); |
73 | 0 | } |
74 | |
|
75 | 0 | return OFshared_ptr<OFUUID>(ofuuid); |
76 | 0 | } |
77 | | |
78 | | OFUUIDGenerator::Uint32_32 |
79 | 0 | OFUUIDGenerator::getMillisecondsSinceEpoch() { |
80 | | // Will ultimately hold the milliseconds from January 1, 1970. |
81 | 0 | Uint32_32 ms_since_unix_epoch; |
82 | |
|
83 | | #ifdef _WIN32 |
84 | | |
85 | | // 'ft' is the number of 100ns ticks since January 1, 1601 (UTC). |
86 | | FILETIME ft; |
87 | | GetSystemTimeAsFileTime(&ft); |
88 | | |
89 | | // 'uli' is (also) the number of 100ns ticks since January 1, 1601 (UTC), |
90 | | // but we want the number of milliseconds since January 1, 1970; so lets |
91 | | // calculate... |
92 | | ULARGE_INTEGER uli; |
93 | | uli.LowPart = ft.dwLowDateTime; |
94 | | uli.HighPart = ft.dwHighDateTime; |
95 | | |
96 | | // 'uli' is now the number of milliseconds since January 1, 1601 (UTC). |
97 | | uli.QuadPart /= 10; |
98 | | |
99 | | // Add the number of milliseconds from January 1, 1601 (UTC) until |
100 | | // January 1, 1970. The number of days between these two days is 36524. |
101 | | uli.QuadPart += ( OFstatic_cast(unsigned __int64, 36524) |
102 | | * OFstatic_cast(unsigned __int64, 60 * 60 * 24) // seconds per day |
103 | | * OFstatic_cast(unsigned __int64, 1000 * 1000)); // milliseconds per second |
104 | | ms_since_unix_epoch.ladd(OFstatic_cast(Uint32, uli.LowPart)); |
105 | | ms_since_unix_epoch.hadd(OFstatic_cast(Uint32, uli.HighPart)); |
106 | | |
107 | | #else |
108 | | |
109 | | // struct timeval { |
110 | | // time_t tv_sec; /* seconds */ |
111 | | // suseconds_t tv_usec; /* microseconds */ |
112 | | // }; |
113 | 0 | struct timeval tp; |
114 | | |
115 | | // 'tp' is offset from January 1, 1970 (Unix epoch) |
116 | 0 | gettimeofday(&tp, NULL); |
117 | | |
118 | | // 'tp.tv_usec' holds microseconds but milliseconds are needed |
119 | 0 | ms_since_unix_epoch = tp.tv_usec / 1000; // 1000 microseconds per millisecond |
120 | | |
121 | | // 'tp.tv_sec' holds seconds but milliseconds are needed |
122 | | // Multiplication by 1000, i.e. the number of milliseconds per second will |
123 | | // likely overflow a 32bit integer |
124 | | // |
125 | | // Some math: |
126 | | // Let: (ah * 2^16 + al) = tp.tv_sec (i) and (ii) |
127 | | // (bh * 2^16 + bl) = 1000 (iii) and (iv) |
128 | | // |
129 | | // It follows: tp.tv_sec * 1000 |
130 | | // = (ah * 2^16 + al) * (bh * 2^16 + bl) |
131 | | // = al * bl (v) |
132 | | // + (ah * bl + al * bh) * 2^16 (vii) and (viii) |
133 | | // + ah * bh * 2^32 (vi) |
134 | | // |
135 | 0 | Uint32 const ah = OFstatic_cast(Uint32, tp.tv_sec >> 16); // (i) |
136 | 0 | Uint32 const al = tp.tv_sec & 0xffff; // (ii) |
137 | 0 | Uint32 const bh = 1000 >> 16; // milliseconds per second // (iii) |
138 | 0 | Uint32 const bl = 1000 & 0xffff; // milliseconds per second // (iv) |
139 | |
|
140 | 0 | ms_since_unix_epoch.ladd(al * bl); // (v) |
141 | 0 | ms_since_unix_epoch.hadd(ah * bh); // (vi) |
142 | |
|
143 | 0 | Uint32 add = ((ah * bl + al * bh) & 0x0000ffff) << 16; // (vii) |
144 | 0 | ms_since_unix_epoch.ladd(add); |
145 | |
|
146 | 0 | add = ((ah * bl + al * bh) & 0xffff0000) >> 16; // (viii) |
147 | 0 | ms_since_unix_epoch.hadd(add); |
148 | |
|
149 | 0 | #endif |
150 | |
|
151 | 0 | return ms_since_unix_epoch; |
152 | 0 | } |
153 | | |
154 | | Uint8 |
155 | 0 | OFUUIDGenerator::getRND8() { |
156 | 0 | static OFRandom rnd; |
157 | |
|
158 | 0 | return rnd.getRND8(); |
159 | 0 | } |
160 | | |
161 | | OFBool |
162 | 0 | OFUUIDGenerator::initializeIfNecessary() { |
163 | 0 | if (OFUUIDGenerator::last_ms_since_epoch_ != 0) { |
164 | 0 | return OFTrue; |
165 | 0 | } |
166 | | |
167 | 0 | OFUUIDGenerator::last_ms_since_epoch_ = OFUUIDGenerator::getMillisecondsSinceEpoch(); |
168 | |
|
169 | 0 | return (OFUUIDGenerator::last_ms_since_epoch_ != 0); |
170 | 0 | } |
171 | | |
172 | 0 | OFUUIDGenerator::OFUUIDGenerator() { |
173 | | // DELIBERATELY EMPTY |
174 | 0 | } |
175 | | |
176 | | void |
177 | | OFUUIDGenerator::setupOFUUIDDataMember(OFUUID * const ofuuid, |
178 | 0 | rnd8 const & rnd) { |
179 | | // [ofuuid.data_[0], ofuuid.data_[1]] := last_ms_since_epoch_.high_ & 0x00ff |
180 | | // Only the lower 16 bits are used, so mask the upper ones. (cf. RFC9562, section 5.7) |
181 | 0 | Uint32 value = OFUUIDGenerator::last_ms_since_epoch_.high_; |
182 | 0 | for (int i = 1; i >=0 ; --i) { |
183 | 0 | ofuuid->data_[OFstatic_cast(size_t, i)] = OFstatic_cast(Uint8, value); |
184 | 0 | value >>= 8; |
185 | 0 | } |
186 | | |
187 | | // [ofuuid.data_[2], ofuuid.data_[5]] := last_ms_since_epoch_.low_ |
188 | | // All 32 bits are used. (cf. RFC9562, section 5.7) |
189 | 0 | value = OFUUIDGenerator::last_ms_since_epoch_.low_; |
190 | 0 | for (int i = 5; i >= 2; --i) { |
191 | 0 | ofuuid->data_[OFstatic_cast(size_t, i)] = OFstatic_cast(Uint8, value); |
192 | 0 | value >>= 8; |
193 | 0 | } |
194 | | |
195 | | // [ofuuid.data_[6], ofuuid.data_[7]] := OFUUIDGenerator::rand_b_field_, |
196 | | // except for the version bits - see below. |
197 | 0 | value = OFUUIDGenerator::rand_b_field_; |
198 | 0 | for (int i = 7; i >= 6; --i) { |
199 | 0 | ofuuid->data_[OFstatic_cast(size_t, i)] = OFstatic_cast(Uint8, value); |
200 | 0 | value >>= 8; |
201 | 0 | } |
202 | | |
203 | | // The four (4) most significant bits of ofuuid.data_[6] will contain the UUID |
204 | | // version (cf. RFC9562, sections 4.2 and 5.7) |
205 | 0 | (ofuuid->data_[6] &= 0x0f) |= OFUUIDGenerator::OFUUID_VERSION_MASK; |
206 | | |
207 | | // [ofuuid.data_[8], ofuuid.data_[15]] are filled with random data, except for |
208 | | // the variant bits - see below. |
209 | 0 | for (size_t i = 8; i < 16; ++i) { |
210 | 0 | ofuuid->data_[i] = rnd(); |
211 | 0 | } |
212 | | |
213 | | // The two (2) most significant bits of ofuuid.data_[8] will contain the UUID |
214 | | // variant (cf. RFC9562, sections 4.2 and 5.7) |
215 | 0 | (ofuuid->data_[8] &= 0x3f) |= OFUUIDGenerator::OFUUID_VARIANT_MASK; |
216 | 0 | } |
217 | | |
218 | 0 | OFUUIDGenerator::~OFUUIDGenerator() { |
219 | | // DELIBERATELY EMPTY |
220 | 0 | } |
221 | | |
222 | | |
223 | | |
224 | | OFUUIDGenerator::Uint32_32 & |
225 | 0 | OFUUIDGenerator::Uint32_32::hadd(Uint32 const value) { |
226 | 0 | high_ += value; |
227 | |
|
228 | 0 | return *this; |
229 | 0 | } |
230 | | |
231 | | OFUUIDGenerator::Uint32_32 & |
232 | 0 | OFUUIDGenerator::Uint32_32::ladd(Uint32 const value) { |
233 | 0 | if (OFStandard::check32BitAddOverflow(low_, value)) { |
234 | 0 | ++high_; |
235 | 0 | } |
236 | 0 | low_ += value; |
237 | |
|
238 | 0 | return *this; |
239 | 0 | } |
240 | | |
241 | | OFBool |
242 | 0 | OFUUIDGenerator::Uint32_32::operator!=(OFUUIDGenerator::Uint32_32 const & rhs) const { |
243 | 0 | return !(*this == rhs); |
244 | 0 | } |
245 | | |
246 | | OFBool |
247 | 0 | OFUUIDGenerator::Uint32_32::operator<(Uint32_32 const & rhs) const { |
248 | 0 | if (this->high_ < rhs.high_) { |
249 | 0 | return OFTrue; |
250 | 0 | } |
251 | | |
252 | 0 | if (this->high_ > rhs.high_) { |
253 | 0 | return OFFalse; |
254 | 0 | } |
255 | | |
256 | 0 | return (this->low_ < rhs.low_); |
257 | 0 | } |
258 | | |
259 | | OFBool |
260 | 0 | OFUUIDGenerator::Uint32_32::operator<=(Uint32_32 const & rhs) const { |
261 | 0 | return !(rhs < *this); |
262 | 0 | } |
263 | | |
264 | | OFUUIDGenerator::Uint32_32 & |
265 | 0 | OFUUIDGenerator::Uint32_32::operator=(Uint32 const value) { |
266 | 0 | high_ = 0; |
267 | 0 | low_ = value; |
268 | |
|
269 | 0 | return *this; |
270 | 0 | } |
271 | | |
272 | | OFBool |
273 | 0 | OFUUIDGenerator::Uint32_32::operator==(OFUUIDGenerator::Uint32_32 const & rhs) const { |
274 | 0 | return (this->high_ == rhs.high_) && (this->low_ == rhs.low_); |
275 | 0 | } |
276 | | |
277 | | OFBool |
278 | 0 | OFUUIDGenerator::Uint32_32::operator>(Uint32_32 const & rhs) const { |
279 | 0 | return (rhs < *this); |
280 | 0 | } |
281 | | |
282 | | OFBool |
283 | 0 | OFUUIDGenerator::Uint32_32::operator>=(Uint32_32 const & rhs) const { |
284 | 0 | return !(*this < rhs); |
285 | 0 | } |
286 | | |
287 | | OFUUIDGenerator::Uint32_32::Uint32_32() : |
288 | 3 | high_(0), |
289 | 3 | low_(0) { |
290 | 3 | } |
291 | | |
292 | | OFUUIDGenerator::Uint32_32::Uint32_32(OFUUIDGenerator::Uint32_32 const & other) : |
293 | 0 | high_(other.high_), |
294 | 0 | low_(other.low_) { |
295 | 0 | } |
296 | | |
297 | | OFUUIDGenerator::Uint32_32::Uint32_32(Uint32 const value) : |
298 | 0 | high_(0), |
299 | 0 | low_(value) { |
300 | 0 | } |
301 | | |
302 | 0 | OFUUIDGenerator::Uint32_32::~Uint32_32() { |
303 | | // DELIBERATELY EMPTY |
304 | 0 | } |