[glib] guuid: Add UUID helper functions to GLib



commit 215c9b7951d9bab08c276bb24b9e631bb22374ab
Author: Bastien Nocera <hadess hadess net>
Date:   Mon Jan 23 04:17:11 2017 +0100

    guuid: Add UUID helper functions to GLib
    
    Many UUID users will just need a random string, which can be generated
    simply by calling the function g_uuid_string_random().
    
    Based on original patch by
    Marc-André Lureau <marcandre lureau gmail com>
    
    https://bugzilla.gnome.org/show_bug.cgi?id=639078

 docs/reference/glib/glib-docs.xml     |    1 +
 docs/reference/glib/glib-sections.txt |    7 +
 glib/Makefile.am                      |    2 +
 glib/glib.h                           |    1 +
 glib/guuid.c                          |  231 +++++++++++++++++++++++++++++++++
 glib/guuid.h                          |   42 ++++++
 glib/tests/.gitignore                 |    1 +
 glib/tests/Makefile.am                |    1 +
 glib/tests/guuid.c                    |   71 ++++++++++
 po/POTFILES.in                        |    1 +
 10 files changed, 358 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/glib/glib-docs.xml b/docs/reference/glib/glib-docs.xml
index f30e44b..4f6795a 100644
--- a/docs/reference/glib/glib-docs.xml
+++ b/docs/reference/glib/glib-docs.xml
@@ -94,6 +94,7 @@
     <xi:include href="xml/testing.xml" />
     <xi:include href="xml/gunix.xml" />
     <xi:include href="xml/windows.xml" />
+    <xi:include href="xml/uuid.xml" />
   </chapter>
 
   <chapter id="glib-data-types">
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 4745446..924d58f 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -3403,3 +3403,10 @@ g_hostname_is_ascii_encoded
 <SUBSECTION>
 g_hostname_is_ip_address
 </SECTION>
+
+<SECTION>
+<FILE>uuid</FILE>
+<TITLE>GUuid</TITLE>
+g_uuid_string_is_valid
+g_uuid_string_random
+</SECTION>
diff --git a/glib/Makefile.am b/glib/Makefile.am
index 2aeaddd..87cca42 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -188,6 +188,7 @@ libglib_2_0_la_SOURCES =    \
        gunicodeprivate.h       \
        gurifuncs.c             \
        gutils.c                \
+       guuid.c                 \
        gvariant.h              \
        gvariant.c              \
        gvariant-core.h         \
@@ -309,6 +310,7 @@ glibsubinclude_HEADERS = \
        gunicode.h      \
        gurifuncs.h     \
        gutils.h        \
+       guuid.h         \
        gvarianttype.h  \
        gvariant.h      \
        gversion.h      \
diff --git a/glib/glib.h b/glib/glib.h
index 1212d13..9fd2229 100644
--- a/glib/glib.h
+++ b/glib/glib.h
@@ -90,6 +90,7 @@
 #include <glib/gunicode.h>
 #include <glib/gurifuncs.h>
 #include <glib/gutils.h>
+#include <glib/guuid.h>
 #include <glib/gvarianttype.h>
 #include <glib/gvariant.h>
 #include <glib/gversion.h>
diff --git a/glib/guuid.c b/glib/guuid.c
new file mode 100644
index 0000000..0f48bfb
--- /dev/null
+++ b/glib/guuid.c
@@ -0,0 +1,231 @@
+/* guuid.c - UUID functions
+ *
+ * Copyright (C) 2013-2015, 2017 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * licence, or (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA.
+ *
+ * Authors: Marc-André Lureau <marcandre lureau redhat com>
+ */
+
+#include "config.h"
+#include <string.h>
+
+#include "gi18n.h"
+#include "gstrfuncs.h"
+#include "grand.h"
+#include "gmessages.h"
+#include "gchecksum.h"
+
+#include "guuid.h"
+
+typedef struct {
+  guint8 bytes[16];
+} GUuid;
+
+/**
+ * SECTION:uuid
+ * @title: GUuid
+ * @short_description: a universally unique identifier
+ *
+ * A UUID, or Universally unique identifier, is intended to uniquely
+ * identify information in a distributed environment. For the
+ * definition of UUID, see [RFC 4122](https://tools.ietf.org/html/rfc4122.html).
+ *
+ * The creation of UUIDs does not require a centralized authority.
+ *
+ * UUIDs are of relatively small size (128 bits, or 16 bytes). The
+ * common string representation (ex:
+ * 1d6c0810-2bd6-45f3-9890-0268422a6f14) needs 37 bytes.
+ *
+ * The UUID specification defines 5 versions, and calling
+ * g_uuid_string_random() will generate a unique (or rather random)
+ * UUID of the most common version, version 4.
+ *
+ * Since: 2.52
+ */
+
+/*
+ * g_uuid_to_string:
+ * @uuid: a #GUuid
+ *
+ * Creates a string representation of @uuid, of the form
+ * 06e023d5-86d8-420e-8103-383e4566087a (no braces nor urn:uuid:
+ * prefix).
+ *
+ * Returns: (transfer full): A string that should be freed with g_free().
+ * Since: STATIC
+ */
+static gchar *
+g_uuid_to_string (const GUuid *uuid)
+{
+  const guint8 *bytes;
+
+  g_return_val_if_fail (uuid != NULL, NULL);
+
+  bytes = uuid->bytes;
+
+  return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x"
+                          "-%02x%02x%02x%02x%02x%02x",
+                          bytes[0], bytes[1], bytes[2], bytes[3],
+                          bytes[4], bytes[5], bytes[6], bytes[7],
+                          bytes[8], bytes[9], bytes[10], bytes[11],
+                          bytes[12], bytes[13], bytes[14], bytes[15]);
+}
+
+static gboolean
+uuid_parse_string (const gchar *str,
+                   GUuid       *uuid)
+{
+  GUuid tmp;
+  guint8 *bytes = tmp.bytes;
+  gint i, j, hi, lo;
+  guint expected_len = 36;
+
+  if (g_str_has_prefix (str, "urn:uuid:"))
+    str += 9;
+  else if (g_str_has_prefix (str, "{urn:uuid:"))
+    expected_len += 11;
+  else if (str[0] == '{')
+    expected_len += 2;
+
+  if (strlen (str) != expected_len)
+    return FALSE;
+
+  if (str[0] == '{')
+    {
+      if (str[expected_len - 1] != '}')
+        return FALSE;
+
+      str++;
+    }
+
+  if (g_str_has_prefix (str, "urn:uuid:"))
+    str += 9;
+
+  for (i = 0, j = 0; i < 16;)
+    {
+      if (j == 8 || j == 13 || j == 18 || j == 23)
+        {
+          if (str[j++] != '-')
+            return FALSE;
+
+          continue;
+        }
+
+      hi = g_ascii_xdigit_value (str[j++]);
+      lo = g_ascii_xdigit_value (str[j++]);
+
+      if (hi == -1 || lo == -1)
+        return FALSE;
+
+      bytes[i++] = hi << 8 | lo;
+    }
+
+  if (uuid != NULL)
+    *uuid = tmp;
+
+  return TRUE;
+}
+
+/**
+ * g_uuid_string_is_valid:
+ * @str: a string representing a UUID
+ *
+ * Parses the string @str and verify if it is a UUID.
+ *
+ * The function accepts the following syntaxes:
+ *
+ * - simple forms (e.g. `f81d4fae-7dec-11d0-a765-00a0c91e6bf6`)
+ * - simple forms with curly braces (e.g.
+ *   `{urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6}`)
+ * - URN (e.g. `urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6`)
+ *
+ * Note that hyphens are required within the UUID string itself,
+ * as per the aforementioned RFC.
+ *
+ * Returns: %TRUE if @str is a valid UUID, %FALSE otherwise.
+ * Since: 2.52
+ */
+gboolean
+g_uuid_string_is_valid (const gchar *str)
+{
+  g_return_val_if_fail (str != NULL, FALSE);
+
+  return uuid_parse_string (str, NULL);
+}
+
+static void
+uuid_set_version (GUuid *uuid, guint version)
+{
+  guint8 *bytes = uuid->bytes;
+
+  /*
+   * Set the four most significant bits (bits 12 through 15) of the
+   * time_hi_and_version field to the 4-bit version number from
+   * Section 4.1.3.
+   */
+  bytes[6] &= 0x0f;
+  bytes[6] |= version << 4;
+  /*
+   * Set the two most significant bits (bits 6 and 7) of the
+   * clock_seq_hi_and_reserved to zero and one, respectively.
+   */
+  bytes[8] &= 0x3f;
+  bytes[8] |= 0x80;
+}
+
+/*
+ * g_uuid_generate_v4:
+ * @uuid: a #GUuid
+ *
+ * Generates a random UUID (RFC 4122 version 4).
+ * Since: STATIC
+ */
+static void
+g_uuid_generate_v4 (GUuid *uuid)
+{
+  int i;
+  guint8 *bytes;
+  guint32 *ints;
+
+  g_return_if_fail (uuid != NULL);
+
+  bytes = uuid->bytes;
+  ints = (guint32 *) bytes;
+  for (i = 0; i < 4; i++)
+    ints[i] = g_random_int ();
+
+  uuid_set_version (uuid, 4);
+}
+
+/**
+ * g_uuid_string_random:
+ *
+ * Generates a random UUID (RFC 4122 version 4) as a string.
+ *
+ * Returns: (transfer full): A string that should be freed with g_free().
+ * Since: 2.52
+ */
+gchar *
+g_uuid_string_random (void)
+{
+  GUuid uuid;
+
+  g_uuid_generate_v4 (&uuid);
+
+  return g_uuid_to_string (&uuid);
+}
+
diff --git a/glib/guuid.h b/glib/guuid.h
new file mode 100644
index 0000000..c653188
--- /dev/null
+++ b/glib/guuid.h
@@ -0,0 +1,42 @@
+/* guuid.h - UUID functions
+ *
+ * Copyright (C) 2013-2015, 2017 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * licence, or (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA.
+ *
+ * Authors: Marc-André Lureau <marcandre lureau redhat com>
+ */
+
+#ifndef __G_UUID_H__
+#define __G_UUID_H__
+
+#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+GLIB_AVAILABLE_IN_2_52
+gboolean      g_uuid_string_is_valid       (const gchar   *str);
+
+GLIB_AVAILABLE_IN_2_52
+gchar *       g_uuid_string_random         (void);
+
+G_END_DECLS
+
+#endif  /* __G_UUID_H__ */
diff --git a/glib/tests/.gitignore b/glib/tests/.gitignore
index 03aee70..9e4c147 100644
--- a/glib/tests/.gitignore
+++ b/glib/tests/.gitignore
@@ -22,6 +22,7 @@ environment
 error
 fileutils
 gdatetime
+guuid
 gvariant
 gwakeup
 gwakeup-fallback
diff --git a/glib/tests/Makefile.am b/glib/tests/Makefile.am
index a6bcef0..43b11f0 100644
--- a/glib/tests/Makefile.am
+++ b/glib/tests/Makefile.am
@@ -59,6 +59,7 @@ test_programs = \
        error                           \
        fileutils                       \
        gdatetime                       \
+       guuid                           \
        gvariant                        \
        hash                            \
        hmac                            \
diff --git a/glib/tests/guuid.c b/glib/tests/guuid.c
new file mode 100644
index 0000000..437749f
--- /dev/null
+++ b/glib/tests/guuid.c
@@ -0,0 +1,71 @@
+/* guuid.c
+ *
+ * Copyright (C) 2013-2015, 2017 Red Hat, Inc.
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "config.h"
+
+#undef G_DISABLE_ASSERT
+
+#include <glib.h>
+#include <string.h>
+
+static void
+test_guuid_string (void)
+{
+  g_assert_false (g_uuid_string_is_valid ("00010203-0405-0607-0809"));
+  g_assert_false (g_uuid_string_is_valid ("zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz"));
+  g_assert_false (g_uuid_string_is_valid ("000102030405060708090a0b0c0d0e0f"));
+
+  g_assert_true (g_uuid_string_is_valid ("00010203-0405-0607-0809-0a0b0c0d0e0f"));
+  g_assert_true (g_uuid_string_is_valid ("7d444840-9dc0-11d1-b245-5ffdce74fad2"));
+  g_assert_true (g_uuid_string_is_valid ("e902893a-9d22-3c7e-a7b8-d6e313b71d9f"));
+  g_assert_true (g_uuid_string_is_valid ("6ba7b810-9dad-11d1-80b4-00c04fd430c8"));
+  g_assert_true (g_uuid_string_is_valid ("{urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6}"));
+  g_assert_true (g_uuid_string_is_valid ("urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6"));
+}
+
+static void
+test_guuid_random (void)
+{
+  gchar *str1, *str2;
+
+  str1 = g_uuid_string_random ();
+  g_assert_cmpuint (strlen (str1), ==, 36);
+  g_assert_true (g_uuid_string_is_valid (str1));
+
+  str2 = g_uuid_string_random ();
+  g_assert_cmpuint (strlen (str2), ==, 36);
+  g_assert_true (g_uuid_string_is_valid (str2));
+  g_assert_cmpstr (str1, !=, str2);
+
+  g_free (str1);
+  g_free (str2);
+}
+
+int
+main (int argc, char **argv)
+{
+  g_test_init (&argc, &argv, NULL);
+  g_test_bug_base ("http://bugzilla.gnome.org/";);
+
+  /* GUuid Tests */
+  g_test_add_func ("/uuid/string", test_guuid_string);
+  g_test_add_func ("/uuid/random", test_guuid_random);
+
+  return g_test_run ();
+}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index a549f05..4cb4150 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -195,4 +195,5 @@ glib/gspawn.c
 glib/gspawn-win32.c
 glib/gutf8.c
 glib/gutils.c
+glib/guuid.c
 gobject/gbinding.c


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]