GnuCash  4.8a-132-gcdaeb421d+
guid.cpp
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 extern "C"
27 {
28 
29 #ifdef HAVE_CONFIG_H
30 # include <config.h>
31 #endif
32 
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
35 #endif
36 #include <ctype.h>
37 #include <stdint.h>
38 #ifdef HAVE_DIRENT_H
39 # include <dirent.h>
40 #endif
41 #include <glib.h>
42 #include <glib/gstdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <sys/stat.h>
46 #ifdef HAVE_SYS_TIMES_H
47 # include <sys/times.h>
48 #endif
49 #include <time.h>
50 #ifdef HAVE_UNISTD_H
51 # include <unistd.h>
52 #endif
53 #include "qof.h"
54 
55 }
56 #include <boost/uuid/uuid.hpp>
57 #include <boost/uuid/uuid_generators.hpp>
58 #include <boost/uuid/uuid_io.hpp>
59 #include <sstream>
60 #include <string>
61 
62 /* This static indicates the debugging module that this .o belongs to. */
63 static QofLogModule log_module = QOF_MOD_ENGINE;
64 
72 const GncGUID*
73 gnc_value_get_guid (const GValue *value)
74 {
75  if (!value) return nullptr;
76  GncGUID *val;
77 
78  g_return_val_if_fail (value && G_IS_VALUE (value), NULL);
79  g_return_val_if_fail (GNC_VALUE_HOLDS_GUID (value), NULL);
80 
81  val = (GncGUID*) g_value_get_boxed (value);
82 
83  return val;
84 }
85 
86 GncGUID * guid_convert_create (gnc::GUID const &);
87 
88 static gnc::GUID s_null_guid {boost::uuids::uuid { {0}}};
89 static GncGUID * s_null_gncguid {guid_convert_create (s_null_guid)};
90 
91 /* Memory management routines ***************************************/
92 
97 GncGUID *
98 guid_convert_create (gnc::GUID const & guid)
99 {
100  GncGUID temp = guid;
101  return guid_copy (&temp);
102 }
103 
104 GncGUID *
106 {
107  return new GncGUID;
108 }
109 
110 void
111 guid_free (GncGUID *guid)
112 {
113  if (!guid) return;
114  if (guid == s_null_gncguid)
115  /* Don't delete that! */
116  return;
117  delete guid;
118 }
119 
120 GncGUID *
121 guid_copy (const GncGUID *guid)
122 {
123  if (!guid) return nullptr;
124  auto ret = guid_malloc ();
125  memcpy (ret, guid, sizeof (GncGUID));
126  return ret;
127 }
128 
129 /*It looks like we are expected to provide the same pointer every time from this function*/
130 const GncGUID *
131 guid_null (void)
132 {
133  return s_null_gncguid;
134 }
135 
136 static void
137 guid_assign (GncGUID & target, gnc::GUID const & source)
138 {
139  memcpy (&target, &source, sizeof (GncGUID));
140 }
141 
142 /*Takes an allocated guid pointer and constructs it in place*/
143 void
145 {
146  if (!guid) return;
147  gnc::GUID temp_random {gnc::GUID::create_random ()};
148  guid_assign (*guid, temp_random);
149 }
150 
151 GncGUID *
152 guid_new (void)
153 {
154  auto ret = guid_new_return ();
155  return guid_copy (&ret);
156 }
157 
158 GncGUID
160 {
161  return gnc::GUID::create_random ();
162 }
163 
164 gchar *
165 guid_to_string (const GncGUID * guid)
166 {
167  if (!guid) return nullptr;
168  gnc::GUID temp {*guid};
169  auto temp_str = temp.to_string ();
170  return g_strdup (temp_str.c_str ());
171 }
172 
173 gchar *
174 guid_to_string_buff (const GncGUID * guid, gchar *str)
175 {
176  if (!str || !guid) return NULL;
177 
178  gnc::GUID temp {*guid};
179  auto val = temp.to_string ();
180  /*We need to be sure to copy the terminating null character.
181  * The standard guarantees that std::basic_string::c_str ()
182  * returns with a terminating null character, too.*/
183  std::copy (val.c_str (), val.c_str () + val.size () + 1, str);
184  return str + val.size ();
185 }
186 
187 gboolean
188 string_to_guid (const char * str, GncGUID * guid)
189 {
190  if (!guid || !str) return false;
191 
192  try
193  {
194  guid_assign (*guid, gnc::GUID::from_string (str));
195  }
196  catch (...)
197  {
198  return false;
199  }
200  return true;
201 }
202 
203 gboolean
204 guid_equal (const GncGUID *guid_1, const GncGUID *guid_2)
205 {
206  if (!guid_1 || !guid_2)
207  return !guid_1 && !guid_2;
208  gnc::GUID temp1 {*guid_1};
209  gnc::GUID temp2 {*guid_2};
210  return temp1 == temp2;
211 }
212 
213 gint
214 guid_compare (const GncGUID *guid_1, const GncGUID *guid_2)
215 {
216  if (!guid_1 || !guid_2)
217  return !guid_1 && !guid_2;
218  gnc::GUID temp1 {*guid_1};
219  gnc::GUID temp2 {*guid_2};
220  if (temp1 < temp2)
221  return -1;
222  if (temp1 == temp2)
223  return 0;
224  return 1;
225 }
226 
227 guint
228 guid_hash_to_guint (gconstpointer ptr)
229 {
230  if (!ptr)
231  {
232  PERR ("received NULL guid pointer.");
233  return 0;
234  }
235  GncGUID const & guid = * reinterpret_cast <GncGUID const *> (ptr);
236  gnc::GUID const & temp {guid};
237 
238  guint hash {0};
239  unsigned retspot {0};
240  std::for_each (temp.begin (), temp.end (), [&hash] (unsigned char a) {
241  hash <<=4;
242  hash |= a;
243  });
244  return hash;
245 }
246 
247 gint
248 guid_g_hash_table_equal (gconstpointer guid_a, gconstpointer guid_b)
249 {
250  return guid_equal (reinterpret_cast<const GncGUID*> (guid_a),
251  reinterpret_cast<const GncGUID*> (guid_b));
252 }
253 
254 GHashTable *
256 {
257  return g_hash_table_new (guid_hash_to_guint, guid_g_hash_table_equal);
258 }
259 
260 /***************************/
261 static void
262 gnc_string_to_guid (const GValue *src, GValue *dest)
263 {
264  /* FIXME: add more checks*/
265  GncGUID *guid;
266  const gchar *as_string;
267 
268  g_return_if_fail (G_VALUE_HOLDS_STRING (src) &&
269  GNC_VALUE_HOLDS_GUID (dest));
270 
271  as_string = g_value_get_string (src);
272 
273  guid = g_new0 (GncGUID, 1);
274  string_to_guid (as_string, guid);
275 
276  g_value_take_boxed (dest, guid);
277 }
278 
279 static void
280 gnc_guid_to_string (const GValue *src, GValue *dest)
281 {
282  const gchar *str;
283 
284  g_return_if_fail (G_VALUE_HOLDS_STRING (dest) &&
285  GNC_VALUE_HOLDS_GUID (src));
286 
287  str = guid_to_string (gnc_value_get_guid (src));
288 
289  g_value_set_string (dest, str);
290 }
291 
292 GType
293 gnc_guid_get_type (void)
294 {
295  static GType type = 0;
296 
297  if (G_UNLIKELY (type == 0))
298  {
299  type = g_boxed_type_register_static ("GncGUID",
300  (GBoxedCopyFunc)guid_copy,
301  (GBoxedFreeFunc)guid_free);
302 
303  g_value_register_transform_func (G_TYPE_STRING,
304  type,
305  gnc_string_to_guid);
306 
307  g_value_register_transform_func (type,
308  G_TYPE_STRING,
309  gnc_guid_to_string);
310  }
311 
312  return type;
313 }
314 
315 namespace gnc
316 {
317 
318 GUID
319 GUID::create_random () noexcept
320 {
321  static boost::uuids::random_generator gen;
322  return {gen ()};
323 }
324 
325 GUID::GUID (boost::uuids::uuid const & other) noexcept
326  : implementation (other)
327 {
328 }
329 
330 GUID const &
331 GUID::null_guid () noexcept
332 {
333  return s_null_guid;
334 }
335 
336 std::string
337 GUID::to_string () const noexcept
338 {
339  auto const & val = boost::uuids::to_string (implementation);
340  std::string ret;
341  std::for_each (val.begin (), val.end (), [&ret] (char a) {
342  if (a != '-') ret.push_back (a);
343  });
344  return ret;
345 }
346 
347 GUID
348 GUID::from_string (std::string const & str)
349 {
350  try
351  {
352  static boost::uuids::string_generator strgen;
353  return strgen (str);
354  }
355  catch (...)
356  {
357  throw guid_syntax_exception {};
358  }
359 }
360 
361 bool
362 GUID::is_valid_guid (std::string const & str)
363 {
364  try
365  {
366  static boost::uuids::string_generator strgen;
367  auto a = strgen (str);
368  return true;
369  }
370  catch (...)
371  {
372  return false;
373  }
374 }
375 
376 guid_syntax_exception::guid_syntax_exception () noexcept
377  : invalid_argument {"Invalid syntax for guid."}
378 {
379 }
380 
381 GUID::GUID (GncGUID const & other) noexcept
382 : implementation {{other.reserved[0] , other.reserved[1]
383  , other.reserved[2], other.reserved[3]
384  , other.reserved[4], other.reserved[5]
385  , other.reserved[6], other.reserved[7]
386  , other.reserved[8], other.reserved[9]
387  , other.reserved[10], other.reserved[11]
388  , other.reserved[12], other.reserved[13]
389  , other.reserved[14], other.reserved[15]}
390  }
391 {
392 
393 }
394 
395 auto
396 GUID::end () const noexcept -> decltype (implementation.end ())
397 {
398  return implementation.end ();
399 }
400 
401 auto
402 GUID::begin () const noexcept -> decltype (implementation.begin ())
403 {
404  return implementation.begin ();
405 }
406 
407 bool
408 GUID::operator < (GUID const & other) noexcept
409 {
410  return implementation < other.implementation;
411 }
412 
413 bool operator == (GUID const & lhs, GncGUID const & rhs) noexcept
414 {
415  return lhs.implementation == GUID(rhs).implementation;
416 }
417 
418 bool
419 operator != (GUID const & one, GUID const & two) noexcept
420 {
421  return one.implementation != two.implementation;
422 }
423 
424 GUID & GUID::operator = (GUID && other) noexcept
425 {
426  boost::uuids::swap (other.implementation, implementation);
427  return *this;
428 }
429 
430 GUID::operator GncGUID () const noexcept
431 {
432  GncGUID ret;
433  guid_assign (ret, *this);
434  return ret;
435 }
436 
437 } // namespace gnc
void guid_replace(GncGUID *guid)
Generate a new guid.
Definition: guid.cpp:144
GncGUID guid_new_return(void)
Generate a new id.
Definition: guid.cpp:159
GncGUID * guid_copy(const GncGUID *guid)
Returns a newly allocated GncGUID that matches the passed-in GUID.
Definition: guid.cpp:121
gboolean string_to_guid(const gchar *string, GncGUID *guid)
Given a string, replace the given guid with the parsed one unless the given value is null...
GncGUID * guid_new(void)
Allocate and construct a new GUID.
Definition: guid.cpp:152
GHashTable * guid_hash_table_new(void)
Returns a GHashTable with <GUID*> as key and a <gpointer> as value and no destructor functions for ke...
Definition: guid.cpp:255
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Definition: guid.cpp:174
guint guid_hash_to_guint(gconstpointer ptr)
Hash function for a GUID.
Definition: guid.cpp:228
const GncGUID * gnc_value_get_guid(const GValue *value)
gnc_value_get_guid
Definition: guid.cpp:73
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
GncGUID * guid_malloc(void)
Allocate memory for a GUID.
Definition: guid.cpp:105
gboolean guid_equal(const GncGUID *guid_1, const GncGUID *guid_2)
Given two GUIDs, return TRUE if they are non-NULL and equal.
Definition: guid.cpp:204
gchar * guid_to_string(const GncGUID *guid)
The guid_to_string() routine returns a null-terminated string encoding of the id. ...
Definition: guid.cpp:165
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:131
The type used to store guids in C.
Definition: guid.h:75
gint guid_g_hash_table_equal(gconstpointer guid_a, gconstpointer guid_b)
Equality function for two GUIDs in a GHashTable.
Definition: guid.cpp:248