Coverage Report

Created: 2026-06-05 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}