/** * SECTION:gkeyfileencoder * @Title: GKeyfileEncoder * @Short_Description: Encodes and decodes data to key files * * #GKeyfileEncoder is a #GEncoder implementation that stores data in * specially formatted key files. */ #include "config.h" #include "gkeyfileencoder.h" #include "gencoder.h" #include "gioerror.h" #include "glibintl.h" #include #define DEFAULT_SECTION_NAME "General" #define TYPE_KEY "Type" struct _GKeyfileEncoder { GEncoder parent_instance; char *section_name; GKeyFile *key_file; }; struct _GKeyfileEncoderClass { GEncoderClass parent_class; }; enum { PROP_0, PROP_SECTION_NAME, PROP_LAST }; static GParamSpec *obj_pspec[PROP_LAST] = { NULL, }; G_DEFINE_TYPE (GKeyfileEncoder, g_keyfile_encoder, G_TYPE_ENCODER) static void g_keyfile_encoder_finalize (GObject *gobject) { GKeyfileEncoder *self = G_KEYFILE_ENCODER (gobject); g_free (self->section_name); if (self->key_file != NULL) g_key_file_free (self->key_file); G_OBJECT_CLASS (g_keyfile_encoder_parent_class)->finalize (gobject); }; static void g_keyfile_encoder_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { GKeyfileEncoder *self = G_KEYFILE_ENCODER (gobject); switch (prop_id) { case PROP_SECTION_NAME: g_keyfile_encoder_set_section_name (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void g_keyfile_encoder_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { GKeyfileEncoder *self = G_KEYFILE_ENCODER (gobject); switch (prop_id) { case PROP_SECTION_NAME: g_value_set_string (value, self->section_name); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static gboolean g_keyfile_encoder_read_from_bytes (GEncoder *encoder, GBytes *bytes, GError **error) { GKeyfileEncoder *self = G_KEYFILE_ENCODER (encoder); GError *internal_error = NULL; GKeyFile *key_file; gchar **keys; gsize keys_len, i; gboolean res = TRUE; if (self->key_file != NULL) g_key_file_free (self->key_file); key_file = g_key_file_new (); g_key_file_load_from_data (key_file, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), 0, &internal_error); if (internal_error != NULL) goto propagate_error_and_return; keys = g_key_file_get_keys (key_file, self->section_name, &keys_len, &internal_error); if (internal_error != NULL) goto propagate_error_and_return; for (i = 0; i < keys_len; i++) { GError *key_error = NULL; char *value_type; char *value_str; GVariant *value; value_type = g_key_file_get_value (key_file, keys[i], TYPE_KEY, &key_error); if (key_error != NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Unable to load encoded data: %s", key_error->message); g_error_free (key_error); res = FALSE; break; } value_str = g_key_file_get_value (key_file, self->section_name, keys[i], &key_error); if (key_error != NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Unable to load encoded data: %s", key_error->message); g_error_free (key_error); g_free (value_type); res = FALSE; break; } value = g_variant_parse (G_VARIANT_TYPE (value_type), value_str, NULL, NULL, &key_error); if (key_error != NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Unable to load encoded data: %s", key_error->message); g_error_free (key_error); g_free (value_str); g_free (value_type); res = FALSE; break; } g_encoder_add_key (encoder, keys[i], value); g_variant_unref (value); g_free (value_str); g_free (value_type); } g_strfreev (keys); g_key_file_unref (key_file); return res; propagate_error_and_return: g_propagate_error (error, internal_error); return FALSE; } static GBytes * g_keyfile_encoder_write_to_bytes (GEncoder *encoder, GError **error) { GKeyfileEncoder *self = G_KEYFILE_ENCODER (encoder); GError *internal_error = NULL; char *data; gsize len; g_encoder_close (encoder); if (self->key_file == NULL) return NULL; data = g_key_file_to_data (self->key_file, &len, &internal_error); if (internal_error) { g_propagate_error (error, internal_error); return NULL; } return g_bytes_new_take (data, len); } static void g_keyfile_encoder_closed (GEncoder *encoder, GVariant *data) { GKeyfileEncoder *self = G_KEYFILE_ENCODER (encoder); GVariantIter iter; GVariant *entry; if (self->key_file != NULL) g_key_file_free (self->key_file); self->key_file = g_key_file_new (); g_variant_iter_init (&iter, data); while ((entry = g_variant_iter_next_value (&iter)) != NULL) { GVariant *key = g_variant_get_child_value (entry, 0); GVariant *tmp = g_variant_get_child_value (entry, 1); GVariant *value; char *value_str; value = g_variant_get_variant (tmp); value_str = g_variant_print (value, FALSE); g_key_file_set_value (self->key_file, self->section_name, g_variant_get_string (key, NULL), value_str); g_key_file_set_value (self->key_file, g_variant_get_string (key, NULL), TYPE_KEY, (const char *) g_variant_get_type (value)); g_free (value_str); g_variant_unref (value); g_variant_unref (tmp); g_variant_unref (key); g_variant_unref (entry); } } static void g_keyfile_encoder_class_init (GKeyfileEncoderClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GEncoderClass *encoder_class = G_ENCODER_CLASS (klass); gobject_class->set_property = g_keyfile_encoder_set_property; gobject_class->get_property = g_keyfile_encoder_get_property; gobject_class->finalize = g_keyfile_encoder_finalize; encoder_class->closed = g_keyfile_encoder_closed; encoder_class->read_from_bytes = g_keyfile_encoder_read_from_bytes; encoder_class->write_to_bytes = g_keyfile_encoder_write_to_bytes; /** * GKeyfileEncoder:section-name: * * The name of the key file section to use when encoding and decoding * values. * * Since: 2.38 */ obj_pspec[PROP_SECTION_NAME] = g_param_spec_string ("section-name", "Section Name", "The name of the keyfile section to use when encoding and decoding", DEFAULT_SECTION_NAME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (gobject_class, PROP_LAST, obj_pspec); } static void g_keyfile_encoder_init (GKeyfileEncoder *self) { self->section_name = g_strdup (DEFAULT_SECTION_NAME); } /** * g_keyfile_encoder_new: * * Creates a new #GKeyfileEncoder. * * You can use this class to encode and decode data to and from a * specially formated #GKeyFile. * * Return value: (transfer full): the newly created #GKeyfileEncoder. * Use g_object_unref() to free the resources allocated when done. * * Since: 2.38 */ GEncoder * g_keyfile_encoder_new (void) { return g_object_new (G_TYPE_KEYFILE_ENCODER, NULL); } /** * g_keyfile_encoder_set_section_name: * @encoder: a #GKeyfileEncoder * @section_name: the section used for the keys * * Sets the section name to be used to store the keys. * * Since: 2.38 */ void g_keyfile_encoder_set_section_name (GKeyfileEncoder *encoder, const char *section_name) { g_return_if_fail (G_IS_KEYFILE_ENCODER (encoder)); g_return_if_fail (section_name != NULL); if (strcmp (encoder->section_name, section_name) == 0) return; g_free (encoder->section_name); encoder->section_name = g_strdup (section_name); g_object_notify_by_pspec (G_OBJECT (encoder), obj_pspec[PROP_SECTION_NAME]); } /** * g_keyfile_encoder_get_section_name: * @encoder: a #GKeyfileEncoder * * Retrieves the section name set using g_keyfile_encoder_set_section_name(). * * Return value: (transfer none): the section name. The returned string * is owned by the #GKeyfileEncoder and it should not be modified or * freed. * * Since: 2.38 */ const char * g_keyfile_encoder_get_section_name (GKeyfileEncoder *encoder) { g_return_val_if_fail (G_IS_KEYFILE_ENCODER (encoder), NULL); return encoder->section_name; }