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 | |
22 | namespace Poco { |
23 | |
24 | |
25 | UUID::UUID(): |
26 | _timeLow(0), |
27 | _timeMid(0), |
28 | _timeHiAndVersion(0), |
29 | _clockSeq(0) |
30 | { |
31 | std::memset(_node, 0, sizeof(_node)); |
32 | } |
33 | |
34 | |
35 | UUID::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 | |
45 | UUID::UUID(const std::string& uuid) |
46 | { |
47 | parse(uuid); |
48 | } |
49 | |
50 | |
51 | UUID::UUID(const char* uuid) |
52 | { |
53 | poco_check_ptr (uuid); |
54 | parse(std::string(uuid)); |
55 | } |
56 | |
57 | |
58 | UUID::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 | |
68 | UUID::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 | |
93 | UUID::~UUID() |
94 | { |
95 | } |
96 | |
97 | |
98 | UUID& 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 | |
112 | void 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 | |
122 | void UUID::parse(const std::string& uuid) |
123 | { |
124 | if (!tryParse(uuid)) |
125 | throw SyntaxException(uuid); |
126 | } |
127 | |
128 | |
129 | bool 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 | |
194 | std::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 | |
212 | void 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 | |
232 | void 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 | |
250 | int 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 | |
262 | int 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 | |
279 | void 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 | |
287 | void UUID::appendHex(std::string& str, UInt16 n) |
288 | { |
289 | appendHex(str, UInt8(n >> 8)); |
290 | appendHex(str, UInt8(n & 0xFF)); |
291 | } |
292 | |
293 | |
294 | void UUID::appendHex(std::string& str, UInt32 n) |
295 | { |
296 | appendHex(str, UInt16(n >> 16)); |
297 | appendHex(str, UInt16(n & 0xFFFF)); |
298 | } |
299 | |
300 | |
301 | Int16 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 | |
314 | void 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 | |
323 | void 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 | |
332 | namespace |
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 | |
342 | const UUID& UUID::null() |
343 | { |
344 | return uuidNull; |
345 | } |
346 | |
347 | |
348 | const UUID& UUID::dns() |
349 | { |
350 | return uuidDNS; |
351 | } |
352 | |
353 | |
354 | const UUID& UUID::uri() |
355 | { |
356 | return uuidURI; |
357 | } |
358 | |
359 | |
360 | const UUID& UUID::oid() |
361 | { |
362 | return uuidOID; |
363 | } |
364 | |
365 | |
366 | const UUID& UUID::x500() |
367 | { |
368 | return uuidX500; |
369 | } |
370 | |
371 | |
372 | } // namespace Poco |
373 | |