Branch data Line data Source code
1 : : /********************************************************************\
2 : : * guid.c -- globally unique ID implementation *
3 : : * Copyright (C) 2000 Dave Peticolas <peticola@cs.ucdavis.edu> *
4 : : * Copyright (C) 2014 Aaron Laws <dartmetrash@gmail.com> *
5 : : * *
6 : : * This program is free software; you can redistribute it and/or *
7 : : * modify it under the terms of the GNU General Public License as *
8 : : * published by the Free Software Foundation; either version 2 of *
9 : : * the License, or (at your option) any later version. *
10 : : * *
11 : : * This program is distributed in the hope that it will be useful, *
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 : : * GNU General Public License for more details. *
15 : : * *
16 : : * You should have received a copy of the GNU General Public License*
17 : : * along with this program; if not, contact: *
18 : : * *
19 : : * Free Software Foundation Voice: +1-617-542-5942 *
20 : : * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 : : * Boston, MA 02110-1301, USA gnu@gnu.org *
22 : : * *
23 : : \********************************************************************/
24 : :
25 : : #include "guid.hpp"
26 : : #include "guid.h"
27 : :
28 : : #ifdef HAVE_CONFIG_H
29 : : # include <config.h>
30 : : #endif
31 : :
32 : : #ifdef HAVE_SYS_TYPES_H
33 : : # include <sys/types.h>
34 : : #endif
35 : : #include <ctype.h>
36 : : #include <stdint.h>
37 : : #ifdef HAVE_DIRENT_H
38 : : # include <dirent.h>
39 : : #endif
40 : : #include <glib.h>
41 : : #include <glib/gstdio.h>
42 : : #include <stdlib.h>
43 : : #include <string.h>
44 : : #include <sys/stat.h>
45 : : #ifdef HAVE_SYS_TIMES_H
46 : : # include <sys/times.h>
47 : : #endif
48 : : #include <time.h>
49 : : #ifdef HAVE_UNISTD_H
50 : : # include <unistd.h>
51 : : #endif
52 : : #include "qof.h"
53 : :
54 : : #include <boost/uuid/uuid.hpp>
55 : : #include <boost/uuid/uuid_generators.hpp>
56 : : #include <boost/uuid/uuid_io.hpp>
57 : : #include <sstream>
58 : : #include <string>
59 : : #include <algorithm>
60 : :
61 : : /* This static indicates the debugging module that this .o belongs to. */
62 : : static QofLogModule log_module = QOF_MOD_ENGINE;
63 : :
64 : : /**
65 : : * gnc_value_get_guid
66 : : *
67 : : * @param value a @c GValue whose value we want to get.
68 : : *
69 : : * @return the value stored in @a value
70 : : */
71 : : const GncGUID*
72 : 0 : gnc_value_get_guid (const GValue *value)
73 : : {
74 : 0 : if (!value) return nullptr;
75 : : GncGUID *val;
76 : :
77 : 0 : g_return_val_if_fail (value && G_IS_VALUE (value), nullptr);
78 : 0 : g_return_val_if_fail (GNC_VALUE_HOLDS_GUID (value), nullptr);
79 : :
80 : 0 : val = (GncGUID*) g_value_get_boxed (value);
81 : :
82 : 0 : return val;
83 : : }
84 : :
85 : : GncGUID * guid_convert_create (gnc::GUID const &);
86 : :
87 : : static gnc::GUID s_null_guid {boost::uuids::uuid { {0}}};
88 : : static GncGUID * s_null_gncguid {guid_convert_create (s_null_guid)};
89 : :
90 : : static inline int
91 : 331008 : char_to_num (unsigned char c) noexcept
92 : : {
93 : 331008 : unsigned int digit = c - '0';
94 : 331008 : unsigned int alpha = (c | 0x20) - 'a';
95 : 331008 : return digit <= 9 ? digit : alpha <= 5 ? alpha + 10 : -1;
96 : : }
97 : :
98 : : static inline bool
99 : 10350 : fast_string_to_guid (const char* s, uint8_t* out) noexcept
100 : : {
101 : 10350 : if (strnlen (s, GUID_ENCODING_LENGTH + 1) != GUID_ENCODING_LENGTH) return false;
102 : 10344 : bool all_ok = true;
103 : 175848 : for (int i = 0; i < GUID_DATA_SIZE; i++)
104 : : {
105 : 165504 : int hi = char_to_num (*s++);
106 : 165504 : int lo = char_to_num (*s++);
107 : 165504 : all_ok &= (hi >= 0 && lo >= 0);
108 : 165504 : out[i] = (unsigned char)(((unsigned)hi << 4) | (unsigned)lo);
109 : : }
110 : 10344 : return all_ok;
111 : : }
112 : :
113 : : static inline void
114 : 33142 : fast_guid_to_string (const uint8_t* src, char* dest) noexcept
115 : : {
116 : : static constexpr char hex[] = "0123456789abcdef";
117 : 563414 : for (size_t i = 0; i < 16; i++)
118 : : {
119 : 530272 : uint8_t b = src[i];
120 : 530272 : *dest++ = hex[b >> 4];
121 : 530272 : *dest++ = hex[b & 0x0F];
122 : : }
123 : 33142 : }
124 : :
125 : : /* Memory management routines ***************************************/
126 : :
127 : : /**
128 : : * Allocates and returns a new GncGUID containing the same value as the
129 : : * gnc::GUID passed in.
130 : : */
131 : : GncGUID *
132 : 115 : guid_convert_create (gnc::GUID const & guid)
133 : : {
134 : 115 : GncGUID temp = guid;
135 : 230 : return guid_copy (&temp);
136 : : }
137 : :
138 : : GncGUID *
139 : 44171 : guid_malloc (void)
140 : : {
141 : 44171 : return new GncGUID;
142 : : }
143 : :
144 : : void
145 : 43985 : guid_free (GncGUID *guid)
146 : : {
147 : 43985 : if (!guid) return;
148 : 42963 : if (guid == s_null_gncguid)
149 : : /* Don't delete that! */
150 : 0 : return;
151 : 42963 : delete guid;
152 : : }
153 : :
154 : : GncGUID *
155 : 9103 : guid_copy (const GncGUID *guid)
156 : : {
157 : 9103 : if (!guid) return nullptr;
158 : 9103 : auto ret = guid_malloc ();
159 : 9103 : *ret = *guid;
160 : 9103 : return ret;
161 : : }
162 : :
163 : : /*It looks like we are expected to provide the same pointer every time from this function*/
164 : : const GncGUID *
165 : 144275 : guid_null (void)
166 : : {
167 : 144275 : return s_null_gncguid;
168 : : }
169 : :
170 : : static void
171 : 512496 : guid_assign (GncGUID & target, gnc::GUID const & source)
172 : : {
173 : 512496 : std::copy (source.begin(), source.end(), target.reserved);
174 : 512496 : }
175 : :
176 : : /*Takes an allocated guid pointer and constructs it in place*/
177 : : void
178 : 134588 : guid_replace (GncGUID *guid)
179 : : {
180 : 134588 : if (!guid) return;
181 : 134588 : gnc::GUID temp_random {gnc::GUID::create_random ()};
182 : 134588 : guid_assign (*guid, temp_random);
183 : : }
184 : :
185 : : GncGUID *
186 : 4990 : guid_new (void)
187 : : {
188 : 4990 : auto ret = guid_new_return ();
189 : 9980 : return guid_copy (&ret);
190 : : }
191 : :
192 : : GncGUID
193 : 5055 : guid_new_return (void)
194 : : {
195 : 5055 : return gnc::GUID::create_random ();
196 : : }
197 : :
198 : : gchar *
199 : 395 : guid_to_string (const GncGUID * guid)
200 : : {
201 : 395 : if (!guid) return nullptr;
202 : 395 : char* buffer = g_new (char, GUID_ENCODING_LENGTH + 1);
203 : 395 : guid_to_string_buff (guid, buffer);
204 : 395 : return buffer;
205 : : }
206 : :
207 : : gchar *
208 : 32339 : guid_to_string_buff (const GncGUID * guid, gchar *str)
209 : : {
210 : 32339 : if (!str || !guid) return nullptr;
211 : 32339 : fast_guid_to_string (guid->reserved, str);
212 : 32339 : str[GUID_ENCODING_LENGTH] = '\0';
213 : 32339 : return str;
214 : : }
215 : :
216 : : gboolean
217 : 10430 : string_to_guid (const char * str, GncGUID * guid)
218 : : {
219 : 10430 : if (!guid || !str || !*str) return false;
220 : :
221 : 10329 : if (fast_string_to_guid (str, guid->reserved))
222 : 10329 : return true;
223 : :
224 : : try
225 : : {
226 : 0 : guid_assign (*guid, gnc::GUID::from_string (str));
227 : : }
228 : 0 : catch (...)
229 : : {
230 : 0 : PINFO("Failed to construct a GUID from %s", str);
231 : 0 : return false;
232 : 0 : }
233 : 0 : return true;
234 : : }
235 : :
236 : : gboolean
237 : 469457 : guid_equal (const GncGUID *guid_1, const GncGUID *guid_2)
238 : : {
239 : 469457 : if (guid_1 == guid_2) return true;
240 : 364247 : if (!guid_1 || !guid_2) return false;
241 : 364176 : gnc::GUID temp1 {*guid_1};
242 : 364176 : gnc::GUID temp2 {*guid_2};
243 : 364176 : return temp1 == temp2;
244 : : }
245 : :
246 : : gint
247 : 9579 : guid_compare (const GncGUID *guid_1, const GncGUID *guid_2)
248 : : {
249 : 9579 : if (guid_1 == guid_2) return 0;
250 : 9577 : if (!guid_1) return -1;
251 : 9577 : if (!guid_2) return 1;
252 : 9577 : gnc::GUID temp1 {*guid_1};
253 : 9577 : gnc::GUID temp2 {*guid_2};
254 : 9577 : if (temp1 < temp2)
255 : 1039 : return -1;
256 : 8538 : if (temp1 == temp2)
257 : 2038 : return 0;
258 : 6500 : return 1;
259 : : }
260 : :
261 : : guint
262 : 519946 : guid_hash_to_guint (gconstpointer ptr)
263 : : {
264 : 519946 : if (!ptr)
265 : : {
266 : 0 : PERR ("received nullptr guid pointer.");
267 : 0 : return 0;
268 : : }
269 : 519946 : GncGUID const & guid = * reinterpret_cast <GncGUID const *> (ptr);
270 : 519946 : gnc::GUID const & temp {guid};
271 : :
272 : 519946 : guint hash {0};
273 : 519946 : std::for_each (temp.begin (), temp.end (), [&hash] (unsigned char a) {
274 : 8319136 : hash <<=4;
275 : 8319136 : hash |= a;
276 : 8319136 : });
277 : 519946 : return hash;
278 : : }
279 : :
280 : : gint
281 : 162135 : guid_g_hash_table_equal (gconstpointer guid_a, gconstpointer guid_b)
282 : : {
283 : 162135 : return guid_equal (reinterpret_cast<const GncGUID*> (guid_a),
284 : 162135 : reinterpret_cast<const GncGUID*> (guid_b));
285 : : }
286 : :
287 : : GHashTable *
288 : 5964 : guid_hash_table_new (void)
289 : : {
290 : 5964 : return g_hash_table_new (guid_hash_to_guint, guid_g_hash_table_equal);
291 : : }
292 : :
293 : : /***************************/
294 : : static void
295 : 0 : gnc_string_to_guid (const GValue *src, GValue *dest)
296 : : {
297 : : /* FIXME: add more checks*/
298 : : GncGUID *guid;
299 : : const gchar *as_string;
300 : :
301 : 0 : g_return_if_fail (G_VALUE_HOLDS_STRING (src) &&
302 : : GNC_VALUE_HOLDS_GUID (dest));
303 : :
304 : 0 : as_string = g_value_get_string (src);
305 : :
306 : 0 : guid = g_new0 (GncGUID, 1);
307 : 0 : string_to_guid (as_string, guid);
308 : :
309 : 0 : g_value_take_boxed (dest, guid);
310 : : }
311 : :
312 : : static void
313 : 0 : gnc_guid_to_string (const GValue *src, GValue *dest)
314 : : {
315 : : const gchar *str;
316 : :
317 : 0 : g_return_if_fail (G_VALUE_HOLDS_STRING (dest) &&
318 : : GNC_VALUE_HOLDS_GUID (src));
319 : :
320 : 0 : str = guid_to_string (gnc_value_get_guid (src));
321 : :
322 : 0 : g_value_set_string (dest, str);
323 : : }
324 : :
325 : 1175 : G_DEFINE_BOXED_TYPE_WITH_CODE (GncGUID, gnc_guid, guid_copy, guid_free,
326 : : g_value_register_transform_func (G_TYPE_STRING,
327 : : g_define_type_id,
328 : : gnc_string_to_guid);
329 : :
330 : : g_value_register_transform_func (g_define_type_id,
331 : : G_TYPE_STRING,
332 : : gnc_guid_to_string);
333 : : )
334 : :
335 : : namespace gnc
336 : : {
337 : :
338 : : GUID
339 : 139643 : GUID::create_random () noexcept
340 : : {
341 : : static boost::uuids::random_generator gen;
342 : 139643 : return {gen ()};
343 : : }
344 : :
345 : 139772 : GUID::GUID (boost::uuids::uuid const & other) noexcept
346 : 139772 : : implementation (other)
347 : : {
348 : 139772 : }
349 : :
350 : : GUID const &
351 : 0 : GUID::null_guid () noexcept
352 : : {
353 : 0 : return s_null_guid;
354 : : }
355 : :
356 : : std::string
357 : 803 : GUID::to_string () const noexcept
358 : : {
359 : 803 : std::string out;
360 : 803 : out.resize (implementation.size() * 2);
361 : 803 : fast_guid_to_string (implementation.data, out.data());
362 : 803 : return out;
363 : : }
364 : :
365 : : GUID
366 : 14 : GUID::from_string (const char* str)
367 : : {
368 : 14 : if (!str)
369 : 0 : throw guid_syntax_exception {};
370 : :
371 : 14 : if (boost::uuids::uuid u; fast_string_to_guid(str, u.data))
372 : 14 : return u;
373 : : try
374 : : {
375 : : static boost::uuids::string_generator strgen;
376 : 0 : return strgen (str);
377 : : }
378 : 0 : catch (...)
379 : : {
380 : 0 : throw guid_syntax_exception {};
381 : 0 : }
382 : : }
383 : :
384 : : bool
385 : 7 : GUID::is_valid_guid (const char* str)
386 : : {
387 : : uint8_t bytes[16];
388 : 7 : if (fast_string_to_guid(str, bytes))
389 : 1 : return true;
390 : : try
391 : : {
392 : : static boost::uuids::string_generator strgen;
393 : 6 : strgen (str);
394 : 0 : return true;
395 : : }
396 : 6 : catch (...)
397 : : {
398 : 6 : return false;
399 : 6 : }
400 : : }
401 : :
402 : 0 : guid_syntax_exception::guid_syntax_exception () noexcept
403 : 0 : : invalid_argument {"Invalid syntax for guid."}
404 : : {
405 : 0 : }
406 : :
407 : 1641023 : GUID::GUID (GncGUID const & other) noexcept
408 : 1641023 : : implementation {{other.reserved[0] , other.reserved[1]
409 : 1641023 : , other.reserved[2], other.reserved[3]
410 : 1641023 : , other.reserved[4], other.reserved[5]
411 : 1641023 : , other.reserved[6], other.reserved[7]
412 : 1641023 : , other.reserved[8], other.reserved[9]
413 : 1641023 : , other.reserved[10], other.reserved[11]
414 : 1641023 : , other.reserved[12], other.reserved[13]
415 : 1641023 : , other.reserved[14], other.reserved[15]}
416 : : }
417 : : {
418 : :
419 : 1641023 : }
420 : :
421 : : auto
422 : 1032442 : GUID::end () const noexcept -> decltype (implementation.end ())
423 : : {
424 : 1032442 : return implementation.end ();
425 : : }
426 : :
427 : : auto
428 : 1032442 : GUID::begin () const noexcept -> decltype (implementation.begin ())
429 : : {
430 : 1032442 : return implementation.begin ();
431 : : }
432 : :
433 : : bool
434 : 9577 : GUID::operator < (GUID const & other) noexcept
435 : : {
436 : 9577 : return implementation < other.implementation;
437 : : }
438 : :
439 : 372732 : bool operator == (GUID const & lhs, GncGUID const & rhs) noexcept
440 : : {
441 : 372732 : return lhs.implementation == GUID(rhs).implementation;
442 : : }
443 : :
444 : : bool
445 : 0 : operator != (GUID const & one, GUID const & two) noexcept
446 : : {
447 : 0 : return one.implementation != two.implementation;
448 : : }
449 : :
450 : 8 : GUID & GUID::operator = (GUID && other) noexcept
451 : : {
452 : 8 : boost::uuids::swap (other.implementation, implementation);
453 : 8 : return *this;
454 : : }
455 : :
456 : 377908 : GUID::operator GncGUID () const noexcept
457 : : {
458 : : GncGUID ret;
459 : 377908 : guid_assign (ret, *this);
460 : 377908 : return ret;
461 : : }
462 : :
463 : : } // namespace gnc
464 : :
465 : : bool
466 : 18 : operator==(const GncGUID& lhs, const GncGUID& rhs)
467 : : {
468 : 18 : return gnc::GUID{lhs} == gnc::GUID{rhs};
469 : : }
|