Blame glib/guuid.c

Packit ae235b
/* guuid.c - UUID functions
Packit ae235b
 *
Packit ae235b
 * Copyright (C) 2013-2015, 2017 Red Hat, Inc.
Packit ae235b
 *
Packit ae235b
 * This library is free software; you can redistribute it and/or modify
Packit ae235b
 * it under the terms of the GNU Lesser General Public License as
Packit ae235b
 * published by the Free Software Foundation; either version 2.1 of the
Packit ae235b
 * licence, or (at your option) any later version.
Packit ae235b
 *
Packit ae235b
 * This is distributed in the hope that it will be useful, but WITHOUT
Packit ae235b
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
Packit ae235b
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
Packit ae235b
 * License for more details.
Packit ae235b
 *
Packit ae235b
 * You should have received a copy of the GNU Lesser General Public
Packit ae235b
 * License along with this library; if not, write to the Free Software
Packit ae235b
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
Packit ae235b
 * USA.
Packit ae235b
 *
Packit ae235b
 * Authors: Marc-André Lureau <marcandre.lureau@redhat.com>
Packit ae235b
 */
Packit ae235b
Packit ae235b
#include "config.h"
Packit ae235b
#include <string.h>
Packit ae235b
Packit ae235b
#include "gi18n.h"
Packit ae235b
#include "gstrfuncs.h"
Packit ae235b
#include "grand.h"
Packit ae235b
#include "gmessages.h"
Packit ae235b
#include "gchecksum.h"
Packit ae235b
Packit ae235b
#include "guuid.h"
Packit ae235b
Packit ae235b
typedef struct {
Packit ae235b
  guint8 bytes[16];
Packit ae235b
} GUuid;
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * SECTION:uuid
Packit ae235b
 * @title: GUuid
Packit ae235b
 * @short_description: a universally unique identifier
Packit ae235b
 *
Packit ae235b
 * A UUID, or Universally unique identifier, is intended to uniquely
Packit ae235b
 * identify information in a distributed environment. For the
Packit ae235b
 * definition of UUID, see [RFC 4122](https://tools.ietf.org/html/rfc4122.html).
Packit ae235b
 *
Packit ae235b
 * The creation of UUIDs does not require a centralized authority.
Packit ae235b
 *
Packit ae235b
 * UUIDs are of relatively small size (128 bits, or 16 bytes). The
Packit ae235b
 * common string representation (ex:
Packit ae235b
 * 1d6c0810-2bd6-45f3-9890-0268422a6f14) needs 37 bytes.
Packit ae235b
 *
Packit ae235b
 * The UUID specification defines 5 versions, and calling
Packit ae235b
 * g_uuid_string_random() will generate a unique (or rather random)
Packit ae235b
 * UUID of the most common version, version 4.
Packit ae235b
 *
Packit ae235b
 * Since: 2.52
Packit ae235b
 */
Packit ae235b
Packit ae235b
/*
Packit ae235b
 * g_uuid_to_string:
Packit ae235b
 * @uuid: a #GUuid
Packit ae235b
 *
Packit ae235b
 * Creates a string representation of @uuid, of the form
Packit ae235b
 * 06e023d5-86d8-420e-8103-383e4566087a (no braces nor urn:uuid:
Packit ae235b
 * prefix).
Packit ae235b
 *
Packit ae235b
 * Returns: (transfer full): A string that should be freed with g_free().
Packit ae235b
 * Since: STATIC
Packit ae235b
 */
Packit ae235b
static gchar *
Packit ae235b
g_uuid_to_string (const GUuid *uuid)
Packit ae235b
{
Packit ae235b
  const guint8 *bytes;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (uuid != NULL, NULL);
Packit ae235b
Packit ae235b
  bytes = uuid->bytes;
Packit ae235b
Packit ae235b
  return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x"
Packit ae235b
                          "-%02x%02x%02x%02x%02x%02x",
Packit ae235b
                          bytes[0], bytes[1], bytes[2], bytes[3],
Packit ae235b
                          bytes[4], bytes[5], bytes[6], bytes[7],
Packit ae235b
                          bytes[8], bytes[9], bytes[10], bytes[11],
Packit ae235b
                          bytes[12], bytes[13], bytes[14], bytes[15]);
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
uuid_parse_string (const gchar *str,
Packit ae235b
                   GUuid       *uuid)
Packit ae235b
{
Packit ae235b
  GUuid tmp;
Packit ae235b
  guint8 *bytes = tmp.bytes;
Packit ae235b
  gint i, j, hi, lo;
Packit ae235b
  guint expected_len = 36;
Packit ae235b
Packit ae235b
  if (strlen (str) != expected_len)
Packit ae235b
    return FALSE;
Packit ae235b
Packit ae235b
  for (i = 0, j = 0; i < 16;)
Packit ae235b
    {
Packit ae235b
      if (j == 8 || j == 13 || j == 18 || j == 23)
Packit ae235b
        {
Packit ae235b
          if (str[j++] != '-')
Packit ae235b
            return FALSE;
Packit ae235b
Packit ae235b
          continue;
Packit ae235b
        }
Packit ae235b
Packit ae235b
      hi = g_ascii_xdigit_value (str[j++]);
Packit ae235b
      lo = g_ascii_xdigit_value (str[j++]);
Packit ae235b
Packit ae235b
      if (hi == -1 || lo == -1)
Packit ae235b
        return FALSE;
Packit ae235b
Packit ae235b
      bytes[i++] = hi << 8 | lo;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (uuid != NULL)
Packit ae235b
    *uuid = tmp;
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_uuid_string_is_valid:
Packit ae235b
 * @str: a string representing a UUID
Packit ae235b
 *
Packit ae235b
 * Parses the string @str and verify if it is a UUID.
Packit ae235b
 *
Packit ae235b
 * The function accepts the following syntax:
Packit ae235b
 *
Packit ae235b
 * - simple forms (e.g. `f81d4fae-7dec-11d0-a765-00a0c91e6bf6`)
Packit ae235b
 *
Packit ae235b
 * Note that hyphens are required within the UUID string itself,
Packit ae235b
 * as per the aforementioned RFC.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if @str is a valid UUID, %FALSE otherwise.
Packit ae235b
 * Since: 2.52
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_uuid_string_is_valid (const gchar *str)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (str != NULL, FALSE);
Packit ae235b
Packit ae235b
  return uuid_parse_string (str, NULL);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
uuid_set_version (GUuid *uuid, guint version)
Packit ae235b
{
Packit ae235b
  guint8 *bytes = uuid->bytes;
Packit ae235b
Packit ae235b
  /*
Packit ae235b
   * Set the four most significant bits (bits 12 through 15) of the
Packit ae235b
   * time_hi_and_version field to the 4-bit version number from
Packit ae235b
   * Section 4.1.3.
Packit ae235b
   */
Packit ae235b
  bytes[6] &= 0x0f;
Packit ae235b
  bytes[6] |= version << 4;
Packit ae235b
  /*
Packit ae235b
   * Set the two most significant bits (bits 6 and 7) of the
Packit ae235b
   * clock_seq_hi_and_reserved to zero and one, respectively.
Packit ae235b
   */
Packit ae235b
  bytes[8] &= 0x3f;
Packit ae235b
  bytes[8] |= 0x80;
Packit ae235b
}
Packit ae235b
Packit ae235b
/*
Packit ae235b
 * g_uuid_generate_v4:
Packit ae235b
 * @uuid: a #GUuid
Packit ae235b
 *
Packit ae235b
 * Generates a random UUID (RFC 4122 version 4).
Packit ae235b
 * Since: STATIC
Packit ae235b
 */
Packit ae235b
static void
Packit ae235b
g_uuid_generate_v4 (GUuid *uuid)
Packit ae235b
{
Packit ae235b
  int i;
Packit ae235b
  guint8 *bytes;
Packit ae235b
  guint32 *ints;
Packit ae235b
Packit ae235b
  g_return_if_fail (uuid != NULL);
Packit ae235b
Packit ae235b
  bytes = uuid->bytes;
Packit ae235b
  ints = (guint32 *) bytes;
Packit ae235b
  for (i = 0; i < 4; i++)
Packit ae235b
    ints[i] = g_random_int ();
Packit ae235b
Packit ae235b
  uuid_set_version (uuid, 4);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_uuid_string_random:
Packit ae235b
 *
Packit ae235b
 * Generates a random UUID (RFC 4122 version 4) as a string.
Packit ae235b
 *
Packit ae235b
 * Returns: (transfer full): A string that should be freed with g_free().
Packit ae235b
 * Since: 2.52
Packit ae235b
 */
Packit ae235b
gchar *
Packit ae235b
g_uuid_string_random (void)
Packit ae235b
{
Packit ae235b
  GUuid uuid;
Packit ae235b
Packit ae235b
  g_uuid_generate_v4 (&uuid);
Packit ae235b
Packit ae235b
  return g_uuid_to_string (&uuid);
Packit ae235b
}
Packit ae235b