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 : : /* Memory management routines ***************************************/
91 : :
92 : : /**
93 : : * Allocates and returns a new GncGUID containing the same value as the
94 : : * gnc::GUID passed in.
95 : : */
96 : : GncGUID *
97 : 114 : guid_convert_create (gnc::GUID const & guid)
98 : : {
99 : 114 : GncGUID temp = guid;
100 : 228 : return guid_copy (&temp);
101 : : }
102 : :
103 : : GncGUID *
104 : 95994 : guid_malloc (void)
105 : : {
106 : 95994 : return new GncGUID;
107 : : }
108 : :
109 : : void
110 : 97354 : guid_free (GncGUID *guid)
111 : : {
112 : 97354 : if (!guid) return;
113 : 94800 : if (guid == s_null_gncguid)
114 : : /* Don't delete that! */
115 : 0 : return;
116 : 94800 : delete guid;
117 : : }
118 : :
119 : : GncGUID *
120 : 17122 : guid_copy (const GncGUID *guid)
121 : : {
122 : 17122 : if (!guid) return nullptr;
123 : 17122 : auto ret = guid_malloc ();
124 : 17122 : *ret = *guid;
125 : 17122 : return ret;
126 : : }
127 : :
128 : : /*It looks like we are expected to provide the same pointer every time from this function*/
129 : : const GncGUID *
130 : 146950 : guid_null (void)
131 : : {
132 : 146950 : return s_null_gncguid;
133 : : }
134 : :
135 : : static void
136 : 2455125 : guid_assign (GncGUID & target, gnc::GUID const & source)
137 : : {
138 : 2455125 : std::copy (source.begin(), source.end(), target.reserved);
139 : 2455125 : }
140 : :
141 : : /*Takes an allocated guid pointer and constructs it in place*/
142 : : void
143 : 137138 : guid_replace (GncGUID *guid)
144 : : {
145 : 137138 : if (!guid) return;
146 : 137138 : gnc::GUID temp_random {gnc::GUID::create_random ()};
147 : 137138 : guid_assign (*guid, temp_random);
148 : : }
149 : :
150 : : GncGUID *
151 : 13469 : guid_new (void)
152 : : {
153 : 13469 : auto ret = guid_new_return ();
154 : 26938 : return guid_copy (&ret);
155 : : }
156 : :
157 : : GncGUID
158 : 13578 : guid_new_return (void)
159 : : {
160 : 13578 : return gnc::GUID::create_random ();
161 : : }
162 : :
163 : : gchar *
164 : 395 : guid_to_string (const GncGUID * guid)
165 : : {
166 : 395 : if (!guid) return nullptr;
167 : 395 : gnc::GUID temp {*guid};
168 : 395 : auto temp_str = temp.to_string ();
169 : 790 : return g_strdup (temp_str.c_str ());
170 : 395 : }
171 : :
172 : : gchar *
173 : 55182 : guid_to_string_buff (const GncGUID * guid, gchar *str)
174 : : {
175 : 55182 : if (!str || !guid) return nullptr;
176 : :
177 : 55182 : gnc::GUID temp {*guid};
178 : 55182 : auto val = temp.to_string ();
179 : : /*We need to be sure to copy the terminating null character.
180 : : * The standard guarantees that std::basic_string::c_str ()
181 : : * returns with a terminating null character, too.*/
182 : 55182 : std::copy (val.c_str (), val.c_str () + val.size () + 1, str);
183 : 55182 : return str + val.size ();
184 : 55182 : }
185 : :
186 : : gboolean
187 : 10393 : string_to_guid (const char * str, GncGUID * guid)
188 : : {
189 : 10393 : if (!guid || !str || !*str) return false;
190 : :
191 : : try
192 : : {
193 : 10292 : guid_assign (*guid, gnc::GUID::from_string (str));
194 : : }
195 : 0 : catch (...)
196 : : {
197 : 0 : PINFO("Failed to construct a GUID from %s", str);
198 : 0 : return false;
199 : 0 : }
200 : 10292 : return true;
201 : : }
202 : :
203 : : gboolean
204 : 2255714 : guid_equal (const GncGUID *guid_1, const GncGUID *guid_2)
205 : : {
206 : 2255714 : if (!guid_1 || !guid_2)
207 : 1769 : return !guid_1 && !guid_2;
208 : 2253945 : gnc::GUID temp1 {*guid_1};
209 : 2253945 : gnc::GUID temp2 {*guid_2};
210 : 2253945 : return temp1 == temp2;
211 : : }
212 : :
213 : : gint
214 : 41218 : guid_compare (const GncGUID *guid_1, const GncGUID *guid_2)
215 : : {
216 : 41218 : if (!guid_1 || !guid_2)
217 : 0 : return !guid_1 && !guid_2;
218 : 41218 : gnc::GUID temp1 {*guid_1};
219 : 41218 : gnc::GUID temp2 {*guid_2};
220 : 41218 : if (temp1 < temp2)
221 : 1374 : return -1;
222 : 39844 : if (temp1 == temp2)
223 : 12922 : return 0;
224 : 26922 : return 1;
225 : : }
226 : :
227 : : guint
228 : 550016 : guid_hash_to_guint (gconstpointer ptr)
229 : : {
230 : 550016 : if (!ptr)
231 : : {
232 : 0 : PERR ("received nullptr guid pointer.");
233 : 0 : return 0;
234 : : }
235 : 550016 : GncGUID const & guid = * reinterpret_cast <GncGUID const *> (ptr);
236 : 550016 : gnc::GUID const & temp {guid};
237 : :
238 : 550016 : guint hash {0};
239 : 550016 : std::for_each (temp.begin (), temp.end (), [&hash] (unsigned char a) {
240 : 8800256 : hash <<=4;
241 : 8800256 : hash |= a;
242 : 8800256 : });
243 : 550016 : return hash;
244 : : }
245 : :
246 : : gint
247 : 184548 : guid_g_hash_table_equal (gconstpointer guid_a, gconstpointer guid_b)
248 : : {
249 : 184548 : return guid_equal (reinterpret_cast<const GncGUID*> (guid_a),
250 : 184548 : reinterpret_cast<const GncGUID*> (guid_b));
251 : : }
252 : :
253 : : GHashTable *
254 : 5873 : guid_hash_table_new (void)
255 : : {
256 : 5873 : return g_hash_table_new (guid_hash_to_guint, guid_g_hash_table_equal);
257 : : }
258 : :
259 : : /***************************/
260 : : static void
261 : 0 : gnc_string_to_guid (const GValue *src, GValue *dest)
262 : : {
263 : : /* FIXME: add more checks*/
264 : : GncGUID *guid;
265 : : const gchar *as_string;
266 : :
267 : 0 : g_return_if_fail (G_VALUE_HOLDS_STRING (src) &&
268 : : GNC_VALUE_HOLDS_GUID (dest));
269 : :
270 : 0 : as_string = g_value_get_string (src);
271 : :
272 : 0 : guid = g_new0 (GncGUID, 1);
273 : 0 : string_to_guid (as_string, guid);
274 : :
275 : 0 : g_value_take_boxed (dest, guid);
276 : : }
277 : :
278 : : static void
279 : 0 : gnc_guid_to_string (const GValue *src, GValue *dest)
280 : : {
281 : : const gchar *str;
282 : :
283 : 0 : g_return_if_fail (G_VALUE_HOLDS_STRING (dest) &&
284 : : GNC_VALUE_HOLDS_GUID (src));
285 : :
286 : 0 : str = guid_to_string (gnc_value_get_guid (src));
287 : :
288 : 0 : g_value_set_string (dest, str);
289 : : }
290 : :
291 : 3560 : G_DEFINE_BOXED_TYPE_WITH_CODE (GncGUID, gnc_guid, guid_copy, guid_free,
292 : : g_value_register_transform_func (G_TYPE_STRING,
293 : : g_define_type_id,
294 : : gnc_string_to_guid);
295 : :
296 : : g_value_register_transform_func (g_define_type_id,
297 : : G_TYPE_STRING,
298 : : gnc_guid_to_string);
299 : : )
300 : :
301 : : namespace gnc
302 : : {
303 : :
304 : : GUID
305 : 150716 : GUID::create_random () noexcept
306 : : {
307 : : static boost::uuids::random_generator gen;
308 : 150716 : return {gen ()};
309 : : }
310 : :
311 : 161136 : GUID::GUID (boost::uuids::uuid const & other) noexcept
312 : 161136 : : implementation (other)
313 : : {
314 : 161136 : }
315 : :
316 : : GUID const &
317 : 0 : GUID::null_guid () noexcept
318 : : {
319 : 0 : return s_null_guid;
320 : : }
321 : :
322 : : std::string
323 : 56645 : GUID::to_string () const noexcept
324 : : {
325 : 56645 : auto const & val = boost::uuids::to_string (implementation);
326 : 56645 : std::string ret;
327 : 56645 : std::for_each (val.begin (), val.end (), [&ret] (char a) {
328 : 2039220 : if (a != '-') ret.push_back (a);
329 : 2039220 : });
330 : 56645 : return ret;
331 : 56645 : }
332 : :
333 : : GUID
334 : 10306 : GUID::from_string (const char* str)
335 : : {
336 : 10306 : if (!str)
337 : 0 : throw guid_syntax_exception {};
338 : : try
339 : : {
340 : : static boost::uuids::string_generator strgen;
341 : 10306 : return strgen (str);
342 : : }
343 : 0 : catch (...)
344 : : {
345 : 0 : throw guid_syntax_exception {};
346 : 0 : }
347 : : }
348 : :
349 : : bool
350 : 7 : GUID::is_valid_guid (const char* str)
351 : : {
352 : : try
353 : : {
354 : : static boost::uuids::string_generator strgen;
355 : 7 : strgen (str);
356 : 1 : return true;
357 : : }
358 : 6 : catch (...)
359 : : {
360 : 6 : return false;
361 : 6 : }
362 : : }
363 : :
364 : 0 : guid_syntax_exception::guid_syntax_exception () noexcept
365 : 0 : : invalid_argument {"Invalid syntax for guid."}
366 : : {
367 : 0 : }
368 : :
369 : 7491400 : GUID::GUID (GncGUID const & other) noexcept
370 : 7491400 : : implementation {{other.reserved[0] , other.reserved[1]
371 : 7491400 : , other.reserved[2], other.reserved[3]
372 : 7491400 : , other.reserved[4], other.reserved[5]
373 : 7491400 : , other.reserved[6], other.reserved[7]
374 : 7491400 : , other.reserved[8], other.reserved[9]
375 : 7491400 : , other.reserved[10], other.reserved[11]
376 : 7491400 : , other.reserved[12], other.reserved[13]
377 : 7491400 : , other.reserved[14], other.reserved[15]}
378 : : }
379 : : {
380 : :
381 : 7491400 : }
382 : :
383 : : auto
384 : 3005141 : GUID::end () const noexcept -> decltype (implementation.end ())
385 : : {
386 : 3005141 : return implementation.end ();
387 : : }
388 : :
389 : : auto
390 : 3005141 : GUID::begin () const noexcept -> decltype (implementation.begin ())
391 : : {
392 : 3005141 : return implementation.begin ();
393 : : }
394 : :
395 : : bool
396 : 41218 : GUID::operator < (GUID const & other) noexcept
397 : : {
398 : 41218 : return implementation < other.implementation;
399 : : }
400 : :
401 : 2293997 : bool operator == (GUID const & lhs, GncGUID const & rhs) noexcept
402 : : {
403 : 2293997 : return lhs.implementation == GUID(rhs).implementation;
404 : : }
405 : :
406 : : bool
407 : 0 : operator != (GUID const & one, GUID const & two) noexcept
408 : : {
409 : 0 : return one.implementation != two.implementation;
410 : : }
411 : :
412 : 8 : GUID & GUID::operator = (GUID && other) noexcept
413 : : {
414 : 8 : boost::uuids::swap (other.implementation, implementation);
415 : 8 : return *this;
416 : : }
417 : :
418 : 2307695 : GUID::operator GncGUID () const noexcept
419 : : {
420 : : GncGUID ret;
421 : 2307695 : guid_assign (ret, *this);
422 : 2307695 : return ret;
423 : : }
424 : :
425 : : } // namespace gnc
426 : :
427 : : bool
428 : 208 : operator==(const GncGUID& lhs, const GncGUID& rhs)
429 : : {
430 : 208 : return gnc::GUID{lhs} == gnc::GUID{rhs};
431 : : }
|