/* * Copyright © 2010 Novell, Inc. * * SPDX-License-Identifier: LGPL-2.1-or-later * * 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 License, or (at your option) any later version. * * This library 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, see . * * Author: Vincent Untz */ #include "config.h" #include "gsettings-mapping.h" static GVariant * g_settings_set_mapping_int (const GValue *value, const GVariantType *expected_type) { GVariant *variant = NULL; gint64 l; if (G_VALUE_HOLDS_INT (value)) l = g_value_get_int (value); else if (G_VALUE_HOLDS_INT64 (value)) l = g_value_get_int64 (value); else return NULL; if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT16)) { if (G_MININT16 <= l && l <= G_MAXINT16) variant = g_variant_new_int16 ((gint16) l); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT16)) { if (0 <= l && l <= G_MAXUINT16) variant = g_variant_new_uint16 ((guint16) l); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT32)) { if (G_MININT32 <= l && l <= G_MAXINT32) variant = g_variant_new_int32 ((gint) l); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT32)) { if (0 <= l && l <= G_MAXUINT32) variant = g_variant_new_uint32 ((guint) l); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT64)) { if (G_MININT64 <= l && l <= G_MAXINT64) variant = g_variant_new_int64 ((gint64) l); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT64)) { if (0 <= l && (guint64) l <= G_MAXUINT64) variant = g_variant_new_uint64 ((guint64) l); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_HANDLE)) { if (0 <= l && l <= G_MAXUINT32) variant = g_variant_new_handle ((guint) l); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_DOUBLE)) variant = g_variant_new_double ((gdouble) l); return variant; } static GVariant * g_settings_set_mapping_float (const GValue *value, const GVariantType *expected_type) { GVariant *variant = NULL; gdouble d; gint64 l; if (G_VALUE_HOLDS_DOUBLE (value)) d = g_value_get_double (value); else return NULL; l = (gint64) d; if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT16)) { if (G_MININT16 <= l && l <= G_MAXINT16) variant = g_variant_new_int16 ((gint16) l); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT16)) { if (0 <= l && l <= G_MAXUINT16) variant = g_variant_new_uint16 ((guint16) l); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT32)) { if (G_MININT32 <= l && l <= G_MAXINT32) variant = g_variant_new_int32 ((gint) l); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT32)) { if (0 <= l && l <= G_MAXUINT32) variant = g_variant_new_uint32 ((guint) l); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT64)) { if (G_MININT64 <= l && l <= G_MAXINT64) variant = g_variant_new_int64 ((gint64) l); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT64)) { if (0 <= l && (guint64) l <= G_MAXUINT64) variant = g_variant_new_uint64 ((guint64) l); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_HANDLE)) { if (0 <= l && l <= G_MAXUINT32) variant = g_variant_new_handle ((guint) l); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_DOUBLE)) variant = g_variant_new_double ((gdouble) d); return variant; } static GVariant * g_settings_set_mapping_unsigned_int (const GValue *value, const GVariantType *expected_type) { GVariant *variant = NULL; guint64 u; if (G_VALUE_HOLDS_UINT (value)) u = g_value_get_uint (value); else if (G_VALUE_HOLDS_UINT64 (value)) u = g_value_get_uint64 (value); else return NULL; if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT16)) { if (u <= G_MAXINT16) variant = g_variant_new_int16 ((gint16) u); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT16)) { if (u <= G_MAXUINT16) variant = g_variant_new_uint16 ((guint16) u); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT32)) { if (u <= G_MAXINT32) variant = g_variant_new_int32 ((gint) u); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT32)) { if (u <= G_MAXUINT32) variant = g_variant_new_uint32 ((guint) u); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT64)) { if (u <= G_MAXINT64) variant = g_variant_new_int64 ((gint64) u); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT64)) { if (u <= G_MAXUINT64) variant = g_variant_new_uint64 ((guint64) u); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_HANDLE)) { if (u <= G_MAXUINT32) variant = g_variant_new_handle ((guint) u); } else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_DOUBLE)) variant = g_variant_new_double ((gdouble) u); return variant; } static gboolean g_settings_get_mapping_int (GValue *value, GVariant *variant) { const GVariantType *type; gint64 l; type = g_variant_get_type (variant); if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16)) l = g_variant_get_int16 (variant); else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32)) l = g_variant_get_int32 (variant); else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64)) l = g_variant_get_int64 (variant); else if (g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE)) l = g_variant_get_handle (variant); else return FALSE; if (G_VALUE_HOLDS_INT (value)) { g_value_set_int (value, l); return (G_MININT32 <= l && l <= G_MAXINT32); } else if (G_VALUE_HOLDS_UINT (value)) { g_value_set_uint (value, l); return (0 <= l && l <= G_MAXUINT32); } else if (G_VALUE_HOLDS_INT64 (value)) { g_value_set_int64 (value, l); return (G_MININT64 <= l && l <= G_MAXINT64); } else if (G_VALUE_HOLDS_UINT64 (value)) { g_value_set_uint64 (value, l); return (0 <= l && (guint64) l <= G_MAXUINT64); } else if (G_VALUE_HOLDS_DOUBLE (value)) { g_value_set_double (value, l); return TRUE; } return FALSE; } static gboolean g_settings_get_mapping_float (GValue *value, GVariant *variant) { const GVariantType *type; gdouble d; gint64 l; type = g_variant_get_type (variant); if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE)) d = g_variant_get_double (variant); else return FALSE; l = (gint64)d; if (G_VALUE_HOLDS_INT (value)) { g_value_set_int (value, l); return (G_MININT32 <= l && l <= G_MAXINT32); } else if (G_VALUE_HOLDS_UINT (value)) { g_value_set_uint (value, l); return (0 <= l && l <= G_MAXUINT32); } else if (G_VALUE_HOLDS_INT64 (value)) { g_value_set_int64 (value, l); return (G_MININT64 <= l && l <= G_MAXINT64); } else if (G_VALUE_HOLDS_UINT64 (value)) { g_value_set_uint64 (value, l); return (0 <= l && (guint64) l <= G_MAXUINT64); } else if (G_VALUE_HOLDS_DOUBLE (value)) { g_value_set_double (value, d); return TRUE; } return FALSE; } static gboolean g_settings_get_mapping_unsigned_int (GValue *value, GVariant *variant) { const GVariantType *type; guint64 u; type = g_variant_get_type (variant); if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16)) u = g_variant_get_uint16 (variant); else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32)) u = g_variant_get_uint32 (variant); else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64)) u = g_variant_get_uint64 (variant); else return FALSE; if (G_VALUE_HOLDS_INT (value)) { g_value_set_int (value, u); return (u <= G_MAXINT32); } else if (G_VALUE_HOLDS_UINT (value)) { g_value_set_uint (value, u); return (u <= G_MAXUINT32); } else if (G_VALUE_HOLDS_INT64 (value)) { g_value_set_int64 (value, u); return (u <= G_MAXINT64); } else if (G_VALUE_HOLDS_UINT64 (value)) { g_value_set_uint64 (value, u); return (u <= G_MAXUINT64); } else if (G_VALUE_HOLDS_DOUBLE (value)) { g_value_set_double (value, u); return TRUE; } return FALSE; } GVariant * g_settings_set_mapping (const GValue *value, const GVariantType *expected_type, gpointer user_data) { gchar *type_string; if (G_VALUE_HOLDS_BOOLEAN (value)) { if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_BOOLEAN)) return g_variant_new_boolean (g_value_get_boolean (value)); } else if (G_VALUE_HOLDS_CHAR (value) || G_VALUE_HOLDS_UCHAR (value)) { if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_BYTE)) { if (G_VALUE_HOLDS_CHAR (value)) return g_variant_new_byte (g_value_get_schar (value)); else return g_variant_new_byte (g_value_get_uchar (value)); } } else if (G_VALUE_HOLDS_INT (value) || G_VALUE_HOLDS_INT64 (value)) return g_settings_set_mapping_int (value, expected_type); else if (G_VALUE_HOLDS_DOUBLE (value)) return g_settings_set_mapping_float (value, expected_type); else if (G_VALUE_HOLDS_UINT (value) || G_VALUE_HOLDS_UINT64 (value)) return g_settings_set_mapping_unsigned_int (value, expected_type); else if (G_VALUE_HOLDS_STRING (value)) { if (g_value_get_string (value) == NULL) return NULL; else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_STRING)) return g_variant_new_string (g_value_get_string (value)); else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_BYTESTRING)) return g_variant_new_bytestring (g_value_get_string (value)); else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_OBJECT_PATH)) return g_variant_new_object_path (g_value_get_string (value)); else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_SIGNATURE)) return g_variant_new_signature (g_value_get_string (value)); } else if (G_VALUE_HOLDS (value, G_TYPE_STRV)) { if (g_value_get_boxed (value) == NULL) return NULL; return g_variant_new_strv ((const gchar **) g_value_get_boxed (value), -1); } else if (G_VALUE_HOLDS_ENUM (value)) { GEnumValue *enumval; GEnumClass *eclass; /* GParamSpecEnum holds a ref on the class so we just peek... */ eclass = g_type_class_peek (G_VALUE_TYPE (value)); enumval = g_enum_get_value (eclass, g_value_get_enum (value)); if (enumval) return g_variant_new_string (enumval->value_nick); else return NULL; } else if (G_VALUE_HOLDS_FLAGS (value)) { GVariantBuilder builder; GFlagsValue *flagsval; GFlagsClass *fclass; guint flags; fclass = g_type_class_peek (G_VALUE_TYPE (value)); flags = g_value_get_flags (value); g_variant_builder_init_static (&builder, G_VARIANT_TYPE ("as")); while (flags) { flagsval = g_flags_get_first_value (fclass, flags); if (flagsval == NULL) { g_variant_builder_clear (&builder); return NULL; } g_variant_builder_add (&builder, "s", flagsval->value_nick); flags &= ~flagsval->value; } return g_variant_builder_end (&builder); } type_string = g_variant_type_dup_string (expected_type); g_critical ("No GSettings bind handler for type \"%s\".", type_string); g_free (type_string); return NULL; } gboolean g_settings_get_mapping (GValue *value, GVariant *variant, gpointer user_data) { if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN)) { if (!G_VALUE_HOLDS_BOOLEAN (value)) return FALSE; g_value_set_boolean (value, g_variant_get_boolean (variant)); return TRUE; } else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTE)) { if (G_VALUE_HOLDS_UCHAR (value)) g_value_set_uchar (value, g_variant_get_byte (variant)); else if (G_VALUE_HOLDS_CHAR (value)) g_value_set_schar (value, (gint8)g_variant_get_byte (variant)); else return FALSE; return TRUE; } else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_INT16) || g_variant_is_of_type (variant, G_VARIANT_TYPE_INT32) || g_variant_is_of_type (variant, G_VARIANT_TYPE_INT64) || g_variant_is_of_type (variant, G_VARIANT_TYPE_HANDLE)) return g_settings_get_mapping_int (value, variant); else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_DOUBLE)) return g_settings_get_mapping_float (value, variant); else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT16) || g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32) || g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT64)) return g_settings_get_mapping_unsigned_int (value, variant); else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING) || g_variant_is_of_type (variant, G_VARIANT_TYPE_OBJECT_PATH) || g_variant_is_of_type (variant, G_VARIANT_TYPE_SIGNATURE)) { if (G_VALUE_HOLDS_STRING (value)) { g_value_set_string (value, g_variant_get_string (variant, NULL)); return TRUE; } else if (G_VALUE_HOLDS_ENUM (value)) { GEnumClass *eclass; GEnumValue *evalue; const gchar *nick; /* GParamSpecEnum holds a ref on the class so we just peek... */ eclass = g_type_class_peek (G_VALUE_TYPE (value)); nick = g_variant_get_string (variant, NULL); evalue = g_enum_get_value_by_nick (eclass, nick); if (evalue) { g_value_set_enum (value, evalue->value); return TRUE; } g_warning ("Unable to look up enum nick ‘%s’ via GType", nick); return FALSE; } } else if (g_variant_is_of_type (variant, G_VARIANT_TYPE ("as"))) { if (G_VALUE_HOLDS (value, G_TYPE_STRV)) { g_value_take_boxed (value, g_variant_dup_strv (variant, NULL)); return TRUE; } else if (G_VALUE_HOLDS_FLAGS (value)) { GFlagsClass *fclass; GFlagsValue *fvalue; const gchar *nick; GVariantIter iter; guint flags = 0; fclass = g_type_class_peek (G_VALUE_TYPE (value)); g_variant_iter_init (&iter, variant); while (g_variant_iter_next (&iter, "&s", &nick)) { fvalue = g_flags_get_value_by_nick (fclass, nick); if (fvalue) flags |= fvalue->value; else { g_warning ("Unable to lookup flags nick '%s' via GType", nick); return FALSE; } } g_value_set_flags (value, flags); return TRUE; } } else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTESTRING)) { g_value_set_string (value, g_variant_get_bytestring (variant)); return TRUE; } g_critical ("No GSettings bind handler for type \"%s\".", g_variant_get_type_string (variant)); return FALSE; } gboolean g_settings_mapping_is_compatible (GType gvalue_type, const GVariantType *variant_type) { gboolean ok = FALSE; if (gvalue_type == G_TYPE_BOOLEAN) ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE_BOOLEAN); else if (gvalue_type == G_TYPE_CHAR || gvalue_type == G_TYPE_UCHAR) ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE_BYTE); else if (gvalue_type == G_TYPE_INT || gvalue_type == G_TYPE_UINT || gvalue_type == G_TYPE_INT64 || gvalue_type == G_TYPE_UINT64 || gvalue_type == G_TYPE_DOUBLE) ok = (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT16) || g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT16) || g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT32) || g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT32) || g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT64) || g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT64) || g_variant_type_equal (variant_type, G_VARIANT_TYPE_HANDLE) || g_variant_type_equal (variant_type, G_VARIANT_TYPE_DOUBLE)); else if (gvalue_type == G_TYPE_STRING) ok = (g_variant_type_equal (variant_type, G_VARIANT_TYPE_STRING) || g_variant_type_equal (variant_type, G_VARIANT_TYPE ("ay")) || g_variant_type_equal (variant_type, G_VARIANT_TYPE_OBJECT_PATH) || g_variant_type_equal (variant_type, G_VARIANT_TYPE_SIGNATURE)); else if (gvalue_type == G_TYPE_STRV) ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE ("as")); else if (G_TYPE_IS_ENUM (gvalue_type)) ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE_STRING); else if (G_TYPE_IS_FLAGS (gvalue_type)) ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE ("as")); return ok; }