GnuCashew ~ GnuCash Enabled Web
GCW
Loading...
Searching...
No Matches
guid.cpp
Go to the documentation of this file.
1/*
2The MIT License (MIT)
3
4Copyright (c) 2014 Graeme Hill (http://graemehill.ca)
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in
14all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22THE SOFTWARE.
23*/
24
25#include <cstring>
26#include "guid.hpp"
27
28#ifdef GUID_LIBUUID
29#include <uuid/uuid.h>
30#endif
31
32#ifdef GUID_CFUUID
33#include <CoreFoundation/CFUUID.h>
34#endif
35
36#ifdef GUID_WINDOWS
37#include <objbase.h>
38#endif
39
40#ifdef GUID_ANDROID
41#include <jni.h>
42#include <cassert>
43#endif
44
45BEGIN_XG_NAMESPACE
46
47#ifdef GUID_ANDROID
48AndroidGuidInfo androidInfo;
49
50AndroidGuidInfo AndroidGuidInfo::fromJniEnv(JNIEnv *env)
51{
52 AndroidGuidInfo info;
53 info.env = env;
54 auto localUuidClass = env->FindClass("java/util/UUID");
55 info.uuidClass = (jclass)env->NewGlobalRef(localUuidClass);
56 env->DeleteLocalRef(localUuidClass);
57 info.newGuidMethod = env->GetStaticMethodID(
58 info.uuidClass, "randomUUID", "()Ljava/util/UUID;");
59 info.mostSignificantBitsMethod = env->GetMethodID(
60 info.uuidClass, "getMostSignificantBits", "()J");
61 info.leastSignificantBitsMethod = env->GetMethodID(
62 info.uuidClass, "getLeastSignificantBits", "()J");
63 info.initThreadId = std::this_thread::get_id();
64 return info;
65}
66
67void initJni(JNIEnv *env)
68{
69 androidInfo = AndroidGuidInfo::fromJniEnv(env);
70}
71#endif
72
73// overload << so that it's easy to convert to a string
74std::ostream &operator<<(std::ostream &s, const Guid &guid)
75{
76 std::ios_base::fmtflags f(s.flags()); // politely don't leave the ostream in hex mode
77 s << std::hex << std::setfill('0')
78 << std::setw(2) << (int)guid._bytes[0]
79 << std::setw(2) << (int)guid._bytes[1]
80 << std::setw(2) << (int)guid._bytes[2]
81 << std::setw(2) << (int)guid._bytes[3]
82 << "-"
83 << std::setw(2) << (int)guid._bytes[4]
84 << std::setw(2) << (int)guid._bytes[5]
85 << "-"
86 << std::setw(2) << (int)guid._bytes[6]
87 << std::setw(2) << (int)guid._bytes[7]
88 << "-"
89 << std::setw(2) << (int)guid._bytes[8]
90 << std::setw(2) << (int)guid._bytes[9]
91 << "-"
92 << std::setw(2) << (int)guid._bytes[10]
93 << std::setw(2) << (int)guid._bytes[11]
94 << std::setw(2) << (int)guid._bytes[12]
95 << std::setw(2) << (int)guid._bytes[13]
96 << std::setw(2) << (int)guid._bytes[14]
97 << std::setw(2) << (int)guid._bytes[15];
98 s.flags(f);
99 return s;
100}
101
102bool operator<(const xg::Guid &lhs, const xg::Guid &rhs)
103{
104 return lhs.bytes() < rhs.bytes();
105}
106
107bool Guid::isValid() const
108{
109 xg::Guid empty;
110 return *this != empty;
111}
112
113// convert to string using std::snprintf() and std::string
114std::string Guid::str() const
115{
116 char one[10], two[6], three[6], four[6], five[14];
117
118 snprintf(one, 10, "%02x%02x%02x%02x",
119 _bytes[0], _bytes[1], _bytes[2], _bytes[3]);
120 snprintf(two, 6, "%02x%02x",
121 _bytes[4], _bytes[5]);
122 snprintf(three, 6, "%02x%02x",
123 _bytes[6], _bytes[7]);
124 snprintf(four, 6, "%02x%02x",
125 _bytes[8], _bytes[9]);
126 snprintf(five, 14, "%02x%02x%02x%02x%02x%02x",
127 _bytes[10], _bytes[11], _bytes[12], _bytes[13], _bytes[14], _bytes[15]);
128 const std::string sep("-");
129 std::string out(one);
130
131 out += sep + two;
132 out += sep + three;
133 out += sep + four;
134 out += sep + five;
135
136 return out;
137}
138
139// conversion operator for std::string
140Guid::operator std::string() const
141{
142 return str();
143}
144
145// Access underlying bytes
146const std::array<unsigned char, 16>& Guid::bytes() const
147{
148 return _bytes;
149}
150
151// create a guid from vector of bytes
152Guid::Guid(const std::array<unsigned char, 16> &bytes) : _bytes(bytes)
153{ }
154
155// create a guid from vector of bytes
156Guid::Guid(std::array<unsigned char, 16> &&bytes) : _bytes(std::move(bytes))
157{ }
158
159// converts a single hex char to a number (0 - 15)
160unsigned char hexDigitToChar(char ch)
161{
162 // 0-9
163 if (ch > 47 && ch < 58)
164 return ch - 48;
165
166 // a-f
167 if (ch > 96 && ch < 103)
168 return ch - 87;
169
170 // A-F
171 if (ch > 64 && ch < 71)
172 return ch - 55;
173
174 return 0;
175}
176
177bool isValidHexChar(char ch)
178{
179 // 0-9
180 if (ch > 47 && ch < 58)
181 return true;
182
183 // a-f
184 if (ch > 96 && ch < 103)
185 return true;
186
187 // A-F
188 if (ch > 64 && ch < 71)
189 return true;
190
191 return false;
192}
193
194// converts the two hexadecimal characters to an unsigned char (a byte)
195unsigned char hexPairToChar(char a, char b)
196{
197 return hexDigitToChar(a) * 16 + hexDigitToChar(b);
198}
199
200// create a guid from string
201Guid::Guid(std::string_view fromString)
202{
203 char charOne = '\0';
204 char charTwo = '\0';
205 bool lookingForFirstChar = true;
206 unsigned nextByte = 0;
207
208 for (const char &ch : fromString)
209 {
210 if (ch == '-')
211 continue;
212
213 if (nextByte >= 16 || !isValidHexChar(ch))
214 {
215 // Invalid string so bail
216 zeroify();
217 return;
218 }
219
220 if (lookingForFirstChar)
221 {
222 charOne = ch;
223 lookingForFirstChar = false;
224 }
225 else
226 {
227 charTwo = ch;
228 auto byte = hexPairToChar(charOne, charTwo);
229 _bytes[nextByte++] = byte;
230 lookingForFirstChar = true;
231 }
232 }
233
234 // if there were fewer than 16 bytes in the string then guid is bad
235 if (nextByte < 16)
236 {
237 zeroify();
238 return;
239 }
240}
241
242// create empty guid
243Guid::Guid() : _bytes{ {0} }
244{ }
245
246// set all bytes to zero
247void Guid::zeroify()
248{
249 std::fill(_bytes.begin(), _bytes.end(), static_cast<unsigned char>(0));
250}
251
252// overload equality operator
253bool Guid::operator==(const Guid &other) const
254{
255 return _bytes == other._bytes;
256}
257
258// overload inequality operator
259bool Guid::operator!=(const Guid &other) const
260{
261 return !((*this) == other);
262}
263
264// member swap function
265void Guid::swap(Guid &other)
266{
267 _bytes.swap(other._bytes);
268}
269
270// This is the linux friendly implementation, but it could work on other
271// systems that have libuuid available
272#ifdef GUID_LIBUUID
273Guid newGuid()
274{
275 std::array<unsigned char, 16> data;
276 static_assert(std::is_same<unsigned char[16], uuid_t>::value, "Wrong type!");
277 uuid_generate(data.data());
278 return Guid{std::move(data)};
279}
280#endif
281
282// this is the mac and ios version
283#ifdef GUID_CFUUID
284Guid newGuid()
285{
286 auto newId = CFUUIDCreate(NULL);
287 auto bytes = CFUUIDGetUUIDBytes(newId);
288 CFRelease(newId);
289
290 std::array<unsigned char, 16> byteArray =
291 {{
292 bytes.byte0,
293 bytes.byte1,
294 bytes.byte2,
295 bytes.byte3,
296 bytes.byte4,
297 bytes.byte5,
298 bytes.byte6,
299 bytes.byte7,
300 bytes.byte8,
301 bytes.byte9,
302 bytes.byte10,
303 bytes.byte11,
304 bytes.byte12,
305 bytes.byte13,
306 bytes.byte14,
307 bytes.byte15
308 }};
309 return Guid{std::move(byteArray)};
310}
311#endif
312
313// obviously this is the windows version
314#ifdef GUID_WINDOWS
315Guid newGuid()
316{
317 GUID newId;
318 CoCreateGuid(&newId);
319
320 std::array<unsigned char, 16> bytes =
321 {
322 (unsigned char)((newId.Data1 >> 24) & 0xFF),
323 (unsigned char)((newId.Data1 >> 16) & 0xFF),
324 (unsigned char)((newId.Data1 >> 8) & 0xFF),
325 (unsigned char)((newId.Data1) & 0xff),
326
327 (unsigned char)((newId.Data2 >> 8) & 0xFF),
328 (unsigned char)((newId.Data2) & 0xff),
329
330 (unsigned char)((newId.Data3 >> 8) & 0xFF),
331 (unsigned char)((newId.Data3) & 0xFF),
332
333 (unsigned char)newId.Data4[0],
334 (unsigned char)newId.Data4[1],
335 (unsigned char)newId.Data4[2],
336 (unsigned char)newId.Data4[3],
337 (unsigned char)newId.Data4[4],
338 (unsigned char)newId.Data4[5],
339 (unsigned char)newId.Data4[6],
340 (unsigned char)newId.Data4[7]
341 };
342
343 return Guid{std::move(bytes)};
344}
345#endif
346
347// android version that uses a call to a java api
348#ifdef GUID_ANDROID
349Guid newGuid(JNIEnv *env)
350{
351 assert(env != androidInfo.env || std::this_thread::get_id() == androidInfo.initThreadId);
352
353 jobject javaUuid = env->CallStaticObjectMethod(
354 androidInfo.uuidClass, androidInfo.newGuidMethod);
355 jlong mostSignificant = env->CallLongMethod(javaUuid,
356 androidInfo.mostSignificantBitsMethod);
357 jlong leastSignificant = env->CallLongMethod(javaUuid,
358 androidInfo.leastSignificantBitsMethod);
359
360 std::array<unsigned char, 16> bytes =
361 {
362 (unsigned char)((mostSignificant >> 56) & 0xFF),
363 (unsigned char)((mostSignificant >> 48) & 0xFF),
364 (unsigned char)((mostSignificant >> 40) & 0xFF),
365 (unsigned char)((mostSignificant >> 32) & 0xFF),
366 (unsigned char)((mostSignificant >> 24) & 0xFF),
367 (unsigned char)((mostSignificant >> 16) & 0xFF),
368 (unsigned char)((mostSignificant >> 8) & 0xFF),
369 (unsigned char)((mostSignificant) & 0xFF),
370 (unsigned char)((leastSignificant >> 56) & 0xFF),
371 (unsigned char)((leastSignificant >> 48) & 0xFF),
372 (unsigned char)((leastSignificant >> 40) & 0xFF),
373 (unsigned char)((leastSignificant >> 32) & 0xFF),
374 (unsigned char)((leastSignificant >> 24) & 0xFF),
375 (unsigned char)((leastSignificant >> 16) & 0xFF),
376 (unsigned char)((leastSignificant >> 8) & 0xFF),
377 (unsigned char)((leastSignificant) & 0xFF)
378 };
379
380 env->DeleteLocalRef(javaUuid);
381
382 return Guid{std::move(bytes)};
383}
384
385Guid newGuid()
386{
387 return newGuid(androidInfo.env);
388}
389#endif
390
391
392END_XG_NAMESPACE
393
394// Specialization for std::swap<Guid>() --
395// call member swap function of lhs, passing rhs
396namespace std
397{
398 template <>
399 void swap(xg::Guid &lhs, xg::Guid &rhs) noexcept
400 {
401 lhs.swap(rhs);
402 }
403}
bool operator<(const xg::Guid &lhs, const xg::Guid &rhs)
Definition guid.cpp:102
bool isValidHexChar(char ch)
Definition guid.cpp:177
unsigned char hexPairToChar(char a, char b)
Definition guid.cpp:195
unsigned char hexDigitToChar(char ch)
Definition guid.cpp:160
BEGIN_XG_NAMESPACE std::ostream & operator<<(std::ostream &s, const Guid &guid)
Definition guid.cpp:74
auto newGuid() -> std::string
Generate new GUID string value.
Definition Core.cpp:235
Definition guid.cpp:397
void swap(xg::Guid &lhs, xg::Guid &rhs) noexcept
Definition guid.cpp:399