1//
2// UUID.cpp
3//
4// Library: Foundation
5// Package: UUID
6// Module: UUID
7//
8// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/UUID.h"
16#include "Poco/ByteOrder.h"
17#include "Poco/Exception.h"
18#include <algorithm>
19#include <cstring>
20
21
22namespace Poco {
23
24
25UUID::UUID():
26 _timeLow(0),
27 _timeMid(0),
28 _timeHiAndVersion(0),
29 _clockSeq(0)
30{
31 std::memset(_node, 0, sizeof(_node));
32}
33
34
35UUID::UUID(const UUID& uuid):
36 _timeLow(uuid._timeLow),
37 _timeMid(uuid._timeMid),
38 _timeHiAndVersion(uuid._timeHiAndVersion),
39 _clockSeq(uuid._clockSeq)
40{
41 std::memcpy(_node, uuid._node, sizeof(_node));
42}
43
44
45UUID::UUID(const std::string& uuid)
46{
47 parse(uuid);
48}
49
50
51UUID::UUID(const char* uuid)
52{
53 poco_check_ptr (uuid);
54 parse(std::string(uuid));
55}
56
57
58UUID::UUID(UInt32 timeLow, UInt32 timeMid, UInt32 timeHiAndVersion, UInt16 clockSeq, UInt8 node[]):
59 _timeLow(timeLow),
60 _timeMid(timeMid),
61 _timeHiAndVersion(timeHiAndVersion),
62 _clockSeq(clockSeq)
63{
64 std::memcpy(_node, node, sizeof(_node));
65}
66
67
68UUID::UUID(const char* bytes, Version uuidVersion)
69{
70 UInt32 i32;
71 UInt16 i16;
72 std::memcpy(&i32, bytes, sizeof(i32));
73 _timeLow = ByteOrder::fromNetwork(i32);
74 bytes += sizeof(i32);
75 std::memcpy(&i16, bytes, sizeof(i16));
76 _timeMid = ByteOrder::fromNetwork(i16);
77 bytes += sizeof(i16);
78 std::memcpy(&i16, bytes, sizeof(i16));
79 _timeHiAndVersion = ByteOrder::fromNetwork(i16);
80 bytes += sizeof(i16);
81 std::memcpy(&i16, bytes, sizeof(i16));
82 _clockSeq = ByteOrder::fromNetwork(i16);
83 bytes += sizeof(i16);
84 std::memcpy(_node, bytes, sizeof(_node));
85
86 _timeHiAndVersion &= 0x0FFF;
87 _timeHiAndVersion |= (uuidVersion << 12);
88 _clockSeq &= 0x3FFF;
89 _clockSeq |= 0x8000;
90}
91
92
93UUID::~UUID()
94{
95}
96
97
98UUID& UUID::operator = (const UUID& uuid)
99{
100 if (&uuid != this)
101 {
102 _timeLow = uuid._timeLow;
103 _timeMid = uuid._timeMid;
104 _timeHiAndVersion = uuid._timeHiAndVersion;
105 _clockSeq = uuid._clockSeq;
106 std::memcpy(_node, uuid._node, sizeof(_node));
107 }
108 return *this;
109}
110
111
112void UUID::swap(UUID& uuid)
113{
114 std::swap(_timeLow, uuid._timeLow);
115 std::swap(_timeMid, uuid._timeMid);
116 std::swap(_timeHiAndVersion, uuid._timeHiAndVersion);
117 std::swap(_clockSeq, uuid._clockSeq);
118 std::swap_ranges(_node, _node + 6, &uuid._node[0]);
119}
120
121
122void UUID::parse(const std::string& uuid)
123{
124 if (!tryParse(uuid))
125 throw SyntaxException(uuid);
126}
127
128
129bool UUID::tryParse(const std::string& uuid)
130{
131 if (uuid.size() < 32)
132 return false;
133
134 bool haveHyphens = false;
135 if (uuid[8] == '-' && uuid[13] == '-' && uuid[18] == '-' && uuid[23] == '-')
136 {
137 if (uuid.size() == 36)
138 haveHyphens = true;
139 else
140 return false;
141 }
142 else if (uuid.size() != 32)
143 return false;
144
145 UUID newUUID;
146 std::string::const_iterator it = uuid.begin();
147 newUUID._timeLow = 0;
148 for (int i = 0; i < 8; ++i)
149 {
150 Int16 n = nibble(*it++);
151 if (n < 0) return false;
152 newUUID._timeLow = (newUUID._timeLow << 4) | n;
153 }
154 if (haveHyphens) ++it;
155 newUUID._timeMid = 0;
156 for (int i = 0; i < 4; ++i)
157 {
158 Int16 n = nibble(*it++);
159 if (n < 0) return false;
160 newUUID._timeMid = (newUUID._timeMid << 4) | n;
161 }
162 if (haveHyphens) ++it;
163 newUUID._timeHiAndVersion = 0;
164 for (int i = 0; i < 4; ++i)
165 {
166 Int16 n = nibble(*it++);
167 if (n < 0) return false;
168 newUUID._timeHiAndVersion = (newUUID._timeHiAndVersion << 4) | n;
169 }
170 if (haveHyphens) ++it;
171 newUUID._clockSeq = 0;
172 for (int i = 0; i < 4; ++i)
173 {
174 Int16 n = nibble(*it++);
175 if (n < 0) return false;
176 newUUID._clockSeq = (newUUID._clockSeq << 4) | n;
177 }
178 if (haveHyphens) ++it;
179 for (int i = 0; i < 6; ++i)
180 {
181 Int16 n1 = nibble(*it++);
182 if (n1 < 0) return false;
183 Int16 n2 = nibble(*it++);
184 if (n2 < 0) return false;
185
186 newUUID._node[i] = (n1 << 4) | n2;
187 }
188 swap(newUUID);
189
190 return true;
191}
192
193
194std::string UUID::toString() const
195{
196 std::string result;
197 result.reserve(36);
198 appendHex(result, _timeLow);
199 result += '-';
200 appendHex(result, _timeMid);
201 result += '-';
202 appendHex(result, _timeHiAndVersion);
203 result += '-';
204 appendHex(result, _clockSeq);
205 result += '-';
206 for (int i = 0; i < sizeof(_node); ++i)
207 appendHex(result, _node[i]);
208 return result;
209}
210
211
212void UUID::copyFrom(const char* buffer)
213{
214 UInt32 i32;
215 UInt16 i16;
216 std::memcpy(&i32, buffer, sizeof(i32));
217 _timeLow = ByteOrder::fromNetwork(i32);
218 buffer += sizeof(i32);
219 std::memcpy(&i16, buffer, sizeof(i16));
220 _timeMid = ByteOrder::fromNetwork(i16);
221 buffer += sizeof(i16);
222 std::memcpy(&i16, buffer, sizeof(i16));
223 _timeHiAndVersion = ByteOrder::fromNetwork(i16);
224 buffer += sizeof(i16);
225 std::memcpy(&i16, buffer, sizeof(i16));
226 _clockSeq = ByteOrder::fromNetwork(i16);
227 buffer += sizeof(i16);
228 std::memcpy(_node, buffer, sizeof(_node));
229}
230
231
232void UUID::copyTo(char* buffer) const
233{
234 UInt32 i32 = ByteOrder::toNetwork(_timeLow);
235 std::memcpy(buffer, &i32, sizeof(i32));
236 buffer += sizeof(i32);
237 UInt16 i16 = ByteOrder::toNetwork(_timeMid);
238 std::memcpy(buffer, &i16, sizeof(i16));
239 buffer += sizeof(i16);
240 i16 = ByteOrder::toNetwork(_timeHiAndVersion);
241 std::memcpy(buffer, &i16, sizeof(i16));
242 buffer += sizeof(i16);
243 i16 = ByteOrder::toNetwork(_clockSeq);
244 std::memcpy(buffer, &i16, sizeof(i16));
245 buffer += sizeof(i16);
246 std::memcpy(buffer, _node, sizeof(_node));
247}
248
249
250int UUID::variant() const
251{
252 int v = _clockSeq >> 13;
253 if ((v & 6) == 6)
254 return v;
255 else if (v & 4)
256 return 2;
257 else
258 return 0;
259}
260
261
262int UUID::compare(const UUID& uuid) const
263{
264 if (_timeLow != uuid._timeLow) return _timeLow < uuid._timeLow ? -1 : 1;
265 if (_timeMid != uuid._timeMid) return _timeMid < uuid._timeMid ? -1 : 1;
266 if (_timeHiAndVersion != uuid._timeHiAndVersion) return _timeHiAndVersion < uuid._timeHiAndVersion ? -1 : 1;
267 if (_clockSeq != uuid._clockSeq) return _clockSeq < uuid._clockSeq ? -1 : 1;
268 for (int i = 0; i < sizeof(_node); ++i)
269 {
270 if (_node[i] < uuid._node[i])
271 return -1;
272 else if (_node[i] > uuid._node[i])
273 return 1;
274 }
275 return 0;
276}
277
278
279void UUID::appendHex(std::string& str, UInt8 n)
280{
281 static const char* digits = "0123456789abcdef";
282 str += digits[(n >> 4) & 0xF];
283 str += digits[n & 0xF];
284}
285
286
287void UUID::appendHex(std::string& str, UInt16 n)
288{
289 appendHex(str, UInt8(n >> 8));
290 appendHex(str, UInt8(n & 0xFF));
291}
292
293
294void UUID::appendHex(std::string& str, UInt32 n)
295{
296 appendHex(str, UInt16(n >> 16));
297 appendHex(str, UInt16(n & 0xFFFF));
298}
299
300
301Int16 UUID::nibble(char hex)
302{
303 if (hex >= 'a' && hex <= 'f')
304 return hex - 'a' + 10;
305 else if (hex >= 'A' && hex <= 'F')
306 return hex - 'A' + 10;
307 else if (hex >= '0' && hex <= '9')
308 return hex - '0';
309 else
310 return -1;
311}
312
313
314void UUID::fromNetwork()
315{
316 _timeLow = ByteOrder::fromNetwork(_timeLow);
317 _timeMid = ByteOrder::fromNetwork(_timeMid);
318 _timeHiAndVersion = ByteOrder::fromNetwork(_timeHiAndVersion);
319 _clockSeq = ByteOrder::fromNetwork(_clockSeq);
320}
321
322
323void UUID::toNetwork()
324{
325 _timeLow = ByteOrder::toNetwork(_timeLow);
326 _timeMid = ByteOrder::toNetwork(_timeMid);
327 _timeHiAndVersion = ByteOrder::toNetwork(_timeHiAndVersion);
328 _clockSeq = ByteOrder::toNetwork(_clockSeq);
329}
330
331
332namespace
333{
334 static UUID uuidNull;
335 static UUID uuidDNS("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
336 static UUID uuidURI("6ba7b811-9dad-11d1-80b4-00c04fd430c8");
337 static UUID uuidOID("6ba7b812-9dad-11d1-80b4-00c04fd430c8");
338 static UUID uuidX500("6ba7b814-9dad-11d1-80b4-00c04fd430c8");
339}
340
341
342const UUID& UUID::null()
343{
344 return uuidNull;
345}
346
347
348const UUID& UUID::dns()
349{
350 return uuidDNS;
351}
352
353
354const UUID& UUID::uri()
355{
356 return uuidURI;
357}
358
359
360const UUID& UUID::oid()
361{
362 return uuidOID;
363}
364
365
366const UUID& UUID::x500()
367{
368 return uuidX500;
369}
370
371
372} // namespace Poco
373