Blame gio/gdbusutils.c

Packit ae235b
/* GDBus - GLib D-Bus Library
Packit ae235b
 *
Packit ae235b
 * Copyright (C) 2008-2010 Red Hat, Inc.
Packit ae235b
 *
Packit ae235b
 * This library is free software; you can redistribute it and/or
Packit ae235b
 * modify it under the terms of the GNU Lesser General Public
Packit ae235b
 * License as published by the Free Software Foundation; either
Packit ae235b
 * version 2.1 of the License, or (at your option) any later version.
Packit ae235b
 *
Packit ae235b
 * This library is distributed in the hope that it will be useful,
Packit ae235b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit ae235b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit ae235b
 * Lesser General Public License for more details.
Packit ae235b
 *
Packit ae235b
 * You should have received a copy of the GNU Lesser General
Packit ae235b
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit ae235b
 *
Packit ae235b
 * Author: David Zeuthen <davidz@redhat.com>
Packit ae235b
 */
Packit ae235b
Packit ae235b
#include "config.h"
Packit ae235b
Packit ae235b
#include <stdlib.h>
Packit ae235b
#include <string.h>
Packit ae235b
Packit ae235b
#include "gdbusutils.h"
Packit ae235b
Packit ae235b
#include "glibintl.h"
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * SECTION:gdbusutils
Packit ae235b
 * @title: D-Bus Utilities
Packit ae235b
 * @short_description: Various utilities related to D-Bus
Packit ae235b
 * @include: gio/gio.h
Packit ae235b
 *
Packit ae235b
 * Various utility routines related to D-Bus.
Packit ae235b
 */
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
is_valid_bus_name_character (gint c,
Packit ae235b
                             gboolean allow_hyphen)
Packit ae235b
{
Packit ae235b
  return
Packit ae235b
    (c >= '0' && c <= '9') ||
Packit ae235b
    (c >= 'A' && c <= 'Z') ||
Packit ae235b
    (c >= 'a' && c <= 'z') ||
Packit ae235b
    (c == '_') ||
Packit ae235b
    (allow_hyphen && c == '-');
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
is_valid_initial_bus_name_character (gint c,
Packit ae235b
                                     gboolean allow_initial_digit,
Packit ae235b
                                     gboolean allow_hyphen)
Packit ae235b
{
Packit ae235b
  if (allow_initial_digit)
Packit ae235b
    return is_valid_bus_name_character (c, allow_hyphen);
Packit ae235b
  else
Packit ae235b
    return
Packit ae235b
      (c >= 'A' && c <= 'Z') ||
Packit ae235b
      (c >= 'a' && c <= 'z') ||
Packit ae235b
      (c == '_') ||
Packit ae235b
      (allow_hyphen && c == '-');
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
is_valid_name (const gchar *start,
Packit ae235b
               guint len,
Packit ae235b
               gboolean allow_initial_digit,
Packit ae235b
               gboolean allow_hyphen)
Packit ae235b
{
Packit ae235b
  gboolean ret;
Packit ae235b
  const gchar *s;
Packit ae235b
  const gchar *end;
Packit ae235b
  gboolean has_dot;
Packit ae235b
Packit ae235b
  ret = FALSE;
Packit ae235b
Packit ae235b
  if (len == 0)
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  s = start;
Packit ae235b
  end = s + len;
Packit ae235b
  has_dot = FALSE;
Packit ae235b
  while (s != end)
Packit ae235b
    {
Packit ae235b
      if (*s == '.')
Packit ae235b
        {
Packit ae235b
          s += 1;
Packit ae235b
          if (G_UNLIKELY (!is_valid_initial_bus_name_character (*s, allow_initial_digit, allow_hyphen)))
Packit ae235b
            goto out;
Packit ae235b
          has_dot = TRUE;
Packit ae235b
        }
Packit ae235b
      else if (G_UNLIKELY (!is_valid_bus_name_character (*s, allow_hyphen)))
Packit ae235b
        {
Packit ae235b
          goto out;
Packit ae235b
        }
Packit ae235b
      s += 1;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (G_UNLIKELY (!has_dot))
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  ret = TRUE;
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  return ret;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_dbus_is_name:
Packit ae235b
 * @string: The string to check.
Packit ae235b
 *
Packit ae235b
 * Checks if @string is a valid D-Bus bus name (either unique or well-known).
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if valid, %FALSE otherwise.
Packit ae235b
 *
Packit ae235b
 * Since: 2.26
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_dbus_is_name (const gchar *string)
Packit ae235b
{
Packit ae235b
  guint len;
Packit ae235b
  gboolean ret;
Packit ae235b
  const gchar *s;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (string != NULL, FALSE);
Packit ae235b
Packit ae235b
  ret = FALSE;
Packit ae235b
Packit ae235b
  len = strlen (string);
Packit ae235b
  if (G_UNLIKELY (len == 0 || len > 255))
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  s = string;
Packit ae235b
  if (*s == ':')
Packit ae235b
    {
Packit ae235b
      /* handle unique name */
Packit ae235b
      if (!is_valid_name (s + 1, len - 1, TRUE, TRUE))
Packit ae235b
        goto out;
Packit ae235b
      ret = TRUE;
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  else if (G_UNLIKELY (*s == '.'))
Packit ae235b
    {
Packit ae235b
      /* can't start with a . */
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  else if (G_UNLIKELY (!is_valid_initial_bus_name_character (*s, FALSE, TRUE)))
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  ret = is_valid_name (s + 1, len - 1, FALSE, TRUE);
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  return ret;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_dbus_is_unique_name:
Packit ae235b
 * @string: The string to check.
Packit ae235b
 *
Packit ae235b
 * Checks if @string is a valid D-Bus unique bus name.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if valid, %FALSE otherwise.
Packit ae235b
 *
Packit ae235b
 * Since: 2.26
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_dbus_is_unique_name (const gchar *string)
Packit ae235b
{
Packit ae235b
  gboolean ret;
Packit ae235b
  guint len;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (string != NULL, FALSE);
Packit ae235b
Packit ae235b
  ret = FALSE;
Packit ae235b
Packit ae235b
  len = strlen (string);
Packit ae235b
  if (G_UNLIKELY (len == 0 || len > 255))
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  if (G_UNLIKELY (*string != ':'))
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  if (G_UNLIKELY (!is_valid_name (string + 1, len - 1, TRUE, TRUE)))
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  ret = TRUE;
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  return ret;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_dbus_is_member_name:
Packit ae235b
 * @string: The string to check.
Packit ae235b
 *
Packit ae235b
 * Checks if @string is a valid D-Bus member (e.g. signal or method) name.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if valid, %FALSE otherwise.
Packit ae235b
 *
Packit ae235b
 * Since: 2.26
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_dbus_is_member_name (const gchar *string)
Packit ae235b
{
Packit ae235b
  gboolean ret;
Packit ae235b
  guint n;
Packit ae235b
Packit ae235b
  ret = FALSE;
Packit ae235b
  if (G_UNLIKELY (string == NULL))
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  if (G_UNLIKELY (!is_valid_initial_bus_name_character (string[0], FALSE, FALSE)))
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  for (n = 1; string[n] != '\0'; n++)
Packit ae235b
    {
Packit ae235b
      if (G_UNLIKELY (!is_valid_bus_name_character (string[n], FALSE)))
Packit ae235b
        {
Packit ae235b
          goto out;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
  ret = TRUE;
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  return ret;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_dbus_is_interface_name:
Packit ae235b
 * @string: The string to check.
Packit ae235b
 *
Packit ae235b
 * Checks if @string is a valid D-Bus interface name.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if valid, %FALSE otherwise.
Packit ae235b
 *
Packit ae235b
 * Since: 2.26
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_dbus_is_interface_name (const gchar *string)
Packit ae235b
{
Packit ae235b
  guint len;
Packit ae235b
  gboolean ret;
Packit ae235b
  const gchar *s;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (string != NULL, FALSE);
Packit ae235b
Packit ae235b
  ret = FALSE;
Packit ae235b
Packit ae235b
  len = strlen (string);
Packit ae235b
  if (G_UNLIKELY (len == 0 || len > 255))
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  s = string;
Packit ae235b
  if (G_UNLIKELY (*s == '.'))
Packit ae235b
    {
Packit ae235b
      /* can't start with a . */
Packit ae235b
      goto out;
Packit ae235b
    }
Packit ae235b
  else if (G_UNLIKELY (!is_valid_initial_bus_name_character (*s, FALSE, FALSE)))
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  ret = is_valid_name (s + 1, len - 1, FALSE, FALSE);
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  return ret;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* ---------------------------------------------------------------------------------------------------- */
Packit ae235b
Packit ae235b
/* TODO: maybe move to glib? if so, it should conform to http://en.wikipedia.org/wiki/Guid and/or
Packit ae235b
 *       http://tools.ietf.org/html/rfc4122 - specifically it should have hyphens then.
Packit ae235b
 */
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_dbus_generate_guid:
Packit ae235b
 *
Packit ae235b
 * Generate a D-Bus GUID that can be used with
Packit ae235b
 * e.g. g_dbus_connection_new().
Packit ae235b
 *
Packit ae235b
 * See the D-Bus specification regarding what strings are valid D-Bus
Packit ae235b
 * GUID (for example, D-Bus GUIDs are not RFC-4122 compliant).
Packit ae235b
 *
Packit ae235b
 * Returns: A valid D-Bus GUID. Free with g_free().
Packit ae235b
 *
Packit ae235b
 * Since: 2.26
Packit ae235b
 */
Packit ae235b
gchar *
Packit ae235b
g_dbus_generate_guid (void)
Packit ae235b
{
Packit ae235b
  GString *s;
Packit ae235b
  GTimeVal now;
Packit ae235b
  guint32 r1;
Packit ae235b
  guint32 r2;
Packit ae235b
  guint32 r3;
Packit ae235b
Packit ae235b
  s = g_string_new (NULL);
Packit ae235b
Packit ae235b
  r1 = g_random_int ();
Packit ae235b
  r2 = g_random_int ();
Packit ae235b
  r3 = g_random_int ();
Packit ae235b
  g_get_current_time (&now;;
Packit ae235b
Packit ae235b
  g_string_append_printf (s, "%08x", r1);
Packit ae235b
  g_string_append_printf (s, "%08x", r2);
Packit ae235b
  g_string_append_printf (s, "%08x", r3);
Packit ae235b
  g_string_append_printf (s, "%08x", (guint32) now.tv_sec);
Packit ae235b
Packit ae235b
  return g_string_free (s, FALSE);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_dbus_is_guid:
Packit ae235b
 * @string: The string to check.
Packit ae235b
 *
Packit ae235b
 * Checks if @string is a D-Bus GUID.
Packit ae235b
 *
Packit ae235b
 * See the D-Bus specification regarding what strings are valid D-Bus
Packit ae235b
 * GUID (for example, D-Bus GUIDs are not RFC-4122 compliant).
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if @string is a guid, %FALSE otherwise.
Packit ae235b
 *
Packit ae235b
 * Since: 2.26
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_dbus_is_guid (const gchar *string)
Packit ae235b
{
Packit ae235b
  gboolean ret;
Packit ae235b
  guint n;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (string != NULL, FALSE);
Packit ae235b
Packit ae235b
  ret = FALSE;
Packit ae235b
Packit ae235b
  for (n = 0; n < 32; n++)
Packit ae235b
    {
Packit ae235b
      if (!g_ascii_isxdigit (string[n]))
Packit ae235b
        goto out;
Packit ae235b
    }
Packit ae235b
  if (string[32] != '\0')
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  ret = TRUE;
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  return ret;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* ---------------------------------------------------------------------------------------------------- */
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_dbus_gvariant_to_gvalue:
Packit ae235b
 * @value: A #GVariant.
Packit ae235b
 * @out_gvalue: (out): Return location pointing to a zero-filled (uninitialized) #GValue.
Packit ae235b
 *
Packit ae235b
 * Converts a #GVariant to a #GValue. If @value is floating, it is consumed.
Packit ae235b
 *
Packit ae235b
 * The rules specified in the g_dbus_gvalue_to_gvariant() function are
Packit ae235b
 * used - this function is essentially its reverse form. So, a #GVariant
Packit ae235b
 * containing any basic or string array type will be converted to a #GValue
Packit ae235b
 * containing a basic value or string array. Any other #GVariant (handle,
Packit ae235b
 * variant, tuple, dict entry) will be converted to a #GValue containing that
Packit ae235b
 * #GVariant.
Packit ae235b
 *
Packit ae235b
 * The conversion never fails - a valid #GValue is always returned in
Packit ae235b
 * @out_gvalue.
Packit ae235b
 *
Packit ae235b
 * Since: 2.30
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_dbus_gvariant_to_gvalue (GVariant  *value,
Packit ae235b
                           GValue    *out_gvalue)
Packit ae235b
{
Packit ae235b
  const GVariantType *type;
Packit ae235b
  gchar **array;
Packit ae235b
Packit ae235b
  g_return_if_fail (value != NULL);
Packit ae235b
  g_return_if_fail (out_gvalue != NULL);
Packit ae235b
Packit ae235b
  memset (out_gvalue, '\0', sizeof (GValue));
Packit ae235b
Packit ae235b
  switch (g_variant_classify (value))
Packit ae235b
    {
Packit ae235b
    case G_VARIANT_CLASS_BOOLEAN:
Packit ae235b
      g_value_init (out_gvalue, G_TYPE_BOOLEAN);
Packit ae235b
      g_value_set_boolean (out_gvalue, g_variant_get_boolean (value));
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    case G_VARIANT_CLASS_BYTE:
Packit ae235b
      g_value_init (out_gvalue, G_TYPE_UCHAR);
Packit ae235b
      g_value_set_uchar (out_gvalue, g_variant_get_byte (value));
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    case G_VARIANT_CLASS_INT16:
Packit ae235b
      g_value_init (out_gvalue, G_TYPE_INT);
Packit ae235b
      g_value_set_int (out_gvalue, g_variant_get_int16 (value));
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    case G_VARIANT_CLASS_UINT16:
Packit ae235b
      g_value_init (out_gvalue, G_TYPE_UINT);
Packit ae235b
      g_value_set_uint (out_gvalue, g_variant_get_uint16 (value));
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    case G_VARIANT_CLASS_INT32:
Packit ae235b
      g_value_init (out_gvalue, G_TYPE_INT);
Packit ae235b
      g_value_set_int (out_gvalue, g_variant_get_int32 (value));
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    case G_VARIANT_CLASS_UINT32:
Packit ae235b
      g_value_init (out_gvalue, G_TYPE_UINT);
Packit ae235b
      g_value_set_uint (out_gvalue, g_variant_get_uint32 (value));
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    case G_VARIANT_CLASS_INT64:
Packit ae235b
      g_value_init (out_gvalue, G_TYPE_INT64);
Packit ae235b
      g_value_set_int64 (out_gvalue, g_variant_get_int64 (value));
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    case G_VARIANT_CLASS_UINT64:
Packit ae235b
      g_value_init (out_gvalue, G_TYPE_UINT64);
Packit ae235b
      g_value_set_uint64 (out_gvalue, g_variant_get_uint64 (value));
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    case G_VARIANT_CLASS_DOUBLE:
Packit ae235b
      g_value_init (out_gvalue, G_TYPE_DOUBLE);
Packit ae235b
      g_value_set_double (out_gvalue, g_variant_get_double (value));
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    case G_VARIANT_CLASS_STRING:
Packit ae235b
      g_value_init (out_gvalue, G_TYPE_STRING);
Packit ae235b
      g_value_set_string (out_gvalue, g_variant_get_string (value, NULL));
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    case G_VARIANT_CLASS_OBJECT_PATH:
Packit ae235b
      g_value_init (out_gvalue, G_TYPE_STRING);
Packit ae235b
      g_value_set_string (out_gvalue, g_variant_get_string (value, NULL));
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    case G_VARIANT_CLASS_SIGNATURE:
Packit ae235b
      g_value_init (out_gvalue, G_TYPE_STRING);
Packit ae235b
      g_value_set_string (out_gvalue, g_variant_get_string (value, NULL));
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    case G_VARIANT_CLASS_ARRAY:
Packit ae235b
      type = g_variant_get_type (value);
Packit ae235b
      switch (g_variant_type_peek_string (type)[1])
Packit ae235b
        {
Packit ae235b
        case G_VARIANT_CLASS_BYTE:
Packit ae235b
          g_value_init (out_gvalue, G_TYPE_STRING);
Packit ae235b
          g_value_set_string (out_gvalue, g_variant_get_bytestring (value));
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case G_VARIANT_CLASS_STRING:
Packit ae235b
          g_value_init (out_gvalue, G_TYPE_STRV);
Packit ae235b
          array = g_variant_dup_strv (value, NULL);
Packit ae235b
          g_value_take_boxed (out_gvalue, array);
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case G_VARIANT_CLASS_OBJECT_PATH:
Packit ae235b
          g_value_init (out_gvalue, G_TYPE_STRV);
Packit ae235b
          array = g_variant_dup_objv (value, NULL);
Packit ae235b
          g_value_take_boxed (out_gvalue, array);
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case G_VARIANT_CLASS_ARRAY:
Packit ae235b
          switch (g_variant_type_peek_string (type)[2])
Packit ae235b
            {
Packit ae235b
            case G_VARIANT_CLASS_BYTE:
Packit ae235b
              g_value_init (out_gvalue, G_TYPE_STRV);
Packit ae235b
              array = g_variant_dup_bytestring_array (value, NULL);
Packit ae235b
              g_value_take_boxed (out_gvalue, array);
Packit ae235b
              break;
Packit ae235b
Packit ae235b
            default:
Packit ae235b
              g_value_init (out_gvalue, G_TYPE_VARIANT);
Packit ae235b
              g_value_set_variant (out_gvalue, value);
Packit ae235b
              break;
Packit ae235b
            }
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        default:
Packit ae235b
          g_value_init (out_gvalue, G_TYPE_VARIANT);
Packit ae235b
          g_value_set_variant (out_gvalue, value);
Packit ae235b
          break;
Packit ae235b
        }
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    case G_VARIANT_CLASS_HANDLE:
Packit ae235b
    case G_VARIANT_CLASS_VARIANT:
Packit ae235b
    case G_VARIANT_CLASS_MAYBE:
Packit ae235b
    case G_VARIANT_CLASS_TUPLE:
Packit ae235b
    case G_VARIANT_CLASS_DICT_ENTRY:
Packit ae235b
      g_value_init (out_gvalue, G_TYPE_VARIANT);
Packit ae235b
      g_value_set_variant (out_gvalue, value);
Packit ae235b
      break;
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_dbus_gvalue_to_gvariant:
Packit ae235b
 * @gvalue: A #GValue to convert to a #GVariant
Packit ae235b
 * @type: A #GVariantType
Packit ae235b
 *
Packit ae235b
 * Converts a #GValue to a #GVariant of the type indicated by the @type
Packit ae235b
 * parameter.
Packit ae235b
 *
Packit ae235b
 * The conversion is using the following rules:
Packit ae235b
 *
Packit ae235b
 * - #G_TYPE_STRING: 's', 'o', 'g' or 'ay'
Packit ae235b
 * - #G_TYPE_STRV: 'as', 'ao' or 'aay'
Packit ae235b
 * - #G_TYPE_BOOLEAN: 'b'
Packit ae235b
 * - #G_TYPE_UCHAR: 'y'
Packit ae235b
 * - #G_TYPE_INT: 'i', 'n'
Packit ae235b
 * - #G_TYPE_UINT: 'u', 'q'
Packit ae235b
 * - #G_TYPE_INT64 'x'
Packit ae235b
 * - #G_TYPE_UINT64: 't'
Packit ae235b
 * - #G_TYPE_DOUBLE: 'd'
Packit ae235b
 * - #G_TYPE_VARIANT: Any #GVariantType
Packit ae235b
 *
Packit ae235b
 * This can fail if e.g. @gvalue is of type #G_TYPE_STRING and @type
Packit ae235b
 * is ['i'][G-VARIANT-TYPE-INT32:CAPS]. It will also fail for any #GType
Packit ae235b
 * (including e.g. #G_TYPE_OBJECT and #G_TYPE_BOXED derived-types) not
Packit ae235b
 * in the table above.
Packit ae235b
 *
Packit ae235b
 * Note that if @gvalue is of type #G_TYPE_VARIANT and its value is
Packit ae235b
 * %NULL, the empty #GVariant instance (never %NULL) for @type is
Packit ae235b
 * returned (e.g. 0 for scalar types, the empty string for string types,
Packit ae235b
 * '/' for object path types, the empty array for any array type and so on).
Packit ae235b
 *
Packit ae235b
 * See the g_dbus_gvariant_to_gvalue() function for how to convert a
Packit ae235b
 * #GVariant to a #GValue.
Packit ae235b
 *
Packit ae235b
 * Returns: A #GVariant (never floating) of #GVariantType @type holding
Packit ae235b
 *     the data from @gvalue or %NULL in case of failure. Free with
Packit ae235b
 *     g_variant_unref().
Packit ae235b
 *
Packit ae235b
 * Since: 2.30
Packit ae235b
 */
Packit ae235b
GVariant *
Packit ae235b
g_dbus_gvalue_to_gvariant (const GValue       *gvalue,
Packit ae235b
                           const GVariantType *type)
Packit ae235b
{
Packit ae235b
  GVariant *ret;
Packit ae235b
  const gchar *s;
Packit ae235b
  const gchar * const *as;
Packit ae235b
  const gchar *empty_strv[1] = {NULL};
Packit ae235b
Packit ae235b
  g_return_val_if_fail (gvalue != NULL, NULL);
Packit ae235b
  g_return_val_if_fail (type != NULL, NULL);
Packit ae235b
Packit ae235b
  ret = NULL;
Packit ae235b
Packit ae235b
  /* @type can easily be e.g. "s" with the GValue holding a GVariant - for example this
Packit ae235b
   * can happen when using the org.gtk.GDBus.C.ForceGVariant annotation with the
Packit ae235b
   * gdbus-codegen(1) tool.
Packit ae235b
   */
Packit ae235b
  if (G_VALUE_TYPE (gvalue) == G_TYPE_VARIANT)
Packit ae235b
    {
Packit ae235b
      ret = g_value_dup_variant (gvalue);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      switch (g_variant_type_peek_string (type)[0])
Packit ae235b
        {
Packit ae235b
        case G_VARIANT_CLASS_BOOLEAN:
Packit ae235b
          ret = g_variant_ref_sink (g_variant_new_boolean (g_value_get_boolean (gvalue)));
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case G_VARIANT_CLASS_BYTE:
Packit ae235b
          ret = g_variant_ref_sink (g_variant_new_byte (g_value_get_uchar (gvalue)));
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case G_VARIANT_CLASS_INT16:
Packit ae235b
          ret = g_variant_ref_sink (g_variant_new_int16 (g_value_get_int (gvalue)));
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case G_VARIANT_CLASS_UINT16:
Packit ae235b
          ret = g_variant_ref_sink (g_variant_new_uint16 (g_value_get_uint (gvalue)));
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case G_VARIANT_CLASS_INT32:
Packit ae235b
          ret = g_variant_ref_sink (g_variant_new_int32 (g_value_get_int (gvalue)));
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case G_VARIANT_CLASS_UINT32:
Packit ae235b
          ret = g_variant_ref_sink (g_variant_new_uint32 (g_value_get_uint (gvalue)));
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case G_VARIANT_CLASS_INT64:
Packit ae235b
          ret = g_variant_ref_sink (g_variant_new_int64 (g_value_get_int64 (gvalue)));
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case G_VARIANT_CLASS_UINT64:
Packit ae235b
          ret = g_variant_ref_sink (g_variant_new_uint64 (g_value_get_uint64 (gvalue)));
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case G_VARIANT_CLASS_DOUBLE:
Packit ae235b
          ret = g_variant_ref_sink (g_variant_new_double (g_value_get_double (gvalue)));
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case G_VARIANT_CLASS_STRING:
Packit ae235b
          s = g_value_get_string (gvalue);
Packit ae235b
          if (s == NULL)
Packit ae235b
            s = "";
Packit ae235b
          ret = g_variant_ref_sink (g_variant_new_string (s));
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case G_VARIANT_CLASS_OBJECT_PATH:
Packit ae235b
          s = g_value_get_string (gvalue);
Packit ae235b
          if (s == NULL)
Packit ae235b
            s = "/";
Packit ae235b
          ret = g_variant_ref_sink (g_variant_new_object_path (s));
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case G_VARIANT_CLASS_SIGNATURE:
Packit ae235b
          s = g_value_get_string (gvalue);
Packit ae235b
          if (s == NULL)
Packit ae235b
            s = "";
Packit ae235b
          ret = g_variant_ref_sink (g_variant_new_signature (s));
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case G_VARIANT_CLASS_ARRAY:
Packit ae235b
          switch (g_variant_type_peek_string (type)[1])
Packit ae235b
            {
Packit ae235b
            case G_VARIANT_CLASS_BYTE:
Packit ae235b
              s = g_value_get_string (gvalue);
Packit ae235b
              if (s == NULL)
Packit ae235b
                s = "";
Packit ae235b
              ret = g_variant_ref_sink (g_variant_new_bytestring (s));
Packit ae235b
              break;
Packit ae235b
Packit ae235b
            case G_VARIANT_CLASS_STRING:
Packit ae235b
              as = g_value_get_boxed (gvalue);
Packit ae235b
              if (as == NULL)
Packit ae235b
                as = empty_strv;
Packit ae235b
              ret = g_variant_ref_sink (g_variant_new_strv (as, -1));
Packit ae235b
              break;
Packit ae235b
Packit ae235b
            case G_VARIANT_CLASS_OBJECT_PATH:
Packit ae235b
              as = g_value_get_boxed (gvalue);
Packit ae235b
              if (as == NULL)
Packit ae235b
                as = empty_strv;
Packit ae235b
              ret = g_variant_ref_sink (g_variant_new_objv (as, -1));
Packit ae235b
              break;
Packit ae235b
Packit ae235b
            case G_VARIANT_CLASS_ARRAY:
Packit ae235b
              switch (g_variant_type_peek_string (type)[2])
Packit ae235b
                {
Packit ae235b
                case G_VARIANT_CLASS_BYTE:
Packit ae235b
                  as = g_value_get_boxed (gvalue);
Packit ae235b
                  if (as == NULL)
Packit ae235b
                    as = empty_strv;
Packit ae235b
                  ret = g_variant_ref_sink (g_variant_new_bytestring_array (as, -1));
Packit ae235b
                  break;
Packit ae235b
Packit ae235b
                default:
Packit ae235b
                  ret = g_value_dup_variant (gvalue);
Packit ae235b
                  break;
Packit ae235b
                }
Packit ae235b
              break;
Packit ae235b
Packit ae235b
            default:
Packit ae235b
              ret = g_value_dup_variant (gvalue);
Packit ae235b
              break;
Packit ae235b
            }
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case G_VARIANT_CLASS_HANDLE:
Packit ae235b
        case G_VARIANT_CLASS_VARIANT:
Packit ae235b
        case G_VARIANT_CLASS_MAYBE:
Packit ae235b
        case G_VARIANT_CLASS_TUPLE:
Packit ae235b
        case G_VARIANT_CLASS_DICT_ENTRY:
Packit ae235b
          ret = g_value_dup_variant (gvalue);
Packit ae235b
          break;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* Could be that the GValue is holding a NULL GVariant - in that case,
Packit ae235b
   * we return an "empty" GVariant instead of a NULL GVariant
Packit ae235b
   */
Packit ae235b
  if (ret == NULL)
Packit ae235b
    {
Packit ae235b
      GVariant *untrusted_empty;
Packit ae235b
      untrusted_empty = g_variant_new_from_data (type, NULL, 0, FALSE, NULL, NULL);
Packit ae235b
      ret = g_variant_take_ref (g_variant_get_normal_form (untrusted_empty));
Packit ae235b
      g_variant_unref (untrusted_empty);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_assert (!g_variant_is_floating (ret));
Packit ae235b
Packit ae235b
  return ret;
Packit ae235b
}