123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667 |
- /* LIBGIMP - The GIMP Library
- * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
- *
- * Object properties serialization routines
- * Copyright (C) 2001-2002 Sven Neumann <sven@gimp.org>
- *
- * 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 3 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
- * Library 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
- * <https://www.gnu.org/licenses/>.
- */
- #include "config.h"
- #include <cairo.h>
- #include <gegl.h>
- #include <gdk-pixbuf/gdk-pixbuf.h>
- #include "libgimpbase/gimpbase.h"
- #include "libgimpmath/gimpmath.h"
- #include "libgimpcolor/gimpcolor.h"
- #include "gimpconfigtypes.h"
- #include "gimpconfigwriter.h"
- #include "gimpconfig-array.h"
- #include "gimpconfig-iface.h"
- #include "gimpconfig-params.h"
- #include "gimpconfig-path.h"
- #include "gimpconfig-serialize.h"
- #include "gimpconfig-utils.h"
- /**
- * SECTION: gimpconfig-serialize
- * @title: GimpConfig-serialize
- * @short_description: Serializing for libgimpconfig.
- *
- * Serializing interface for libgimpconfig.
- **/
- /**
- * gimp_config_serialize_properties:
- * @config: a #GimpConfig.
- * @writer: a #GimpConfigWriter.
- *
- * This function writes all object properties to the @writer.
- *
- * Returns: %TRUE if serialization succeeded, %FALSE otherwise
- *
- * Since: 2.4
- **/
- gboolean
- gimp_config_serialize_properties (GimpConfig *config,
- GimpConfigWriter *writer)
- {
- GObjectClass *klass;
- GParamSpec **property_specs;
- guint n_property_specs;
- guint i;
- gboolean success = TRUE;
- g_return_val_if_fail (G_IS_OBJECT (config), FALSE);
- klass = G_OBJECT_GET_CLASS (config);
- property_specs = g_object_class_list_properties (klass, &n_property_specs);
- if (! property_specs)
- return success;
- for (i = 0; i < n_property_specs; i++)
- {
- GParamSpec *prop_spec = property_specs[i];
- if (! (prop_spec->flags & GIMP_CONFIG_PARAM_SERIALIZE))
- continue;
- /* Some properties may fail writing, which shouldn't break serializing
- * more properties, yet final result would be a (partial) failure.
- */
- if (! gimp_config_serialize_property (config, prop_spec, writer))
- success = FALSE;
- }
- g_free (property_specs);
- return success;
- }
- /**
- * gimp_config_serialize_changed_properties:
- * @config: a #GimpConfig.
- * @writer: a #GimpConfigWriter.
- *
- * This function writes all object properties that have been changed from
- * their default values to the @writer.
- *
- * Returns: %TRUE if serialization succeeded, %FALSE otherwise
- *
- * Since: 2.4
- **/
- gboolean
- gimp_config_serialize_changed_properties (GimpConfig *config,
- GimpConfigWriter *writer)
- {
- GObjectClass *klass;
- GParamSpec **property_specs;
- guint n_property_specs;
- guint i;
- GValue value = G_VALUE_INIT;
- gboolean success = TRUE;
- g_return_val_if_fail (G_IS_OBJECT (config), FALSE);
- klass = G_OBJECT_GET_CLASS (config);
- property_specs = g_object_class_list_properties (klass, &n_property_specs);
- if (! property_specs)
- return success;
- for (i = 0; i < n_property_specs; i++)
- {
- GParamSpec *prop_spec = property_specs[i];
- if (! (prop_spec->flags & GIMP_CONFIG_PARAM_SERIALIZE))
- continue;
- g_value_init (&value, prop_spec->value_type);
- g_object_get_property (G_OBJECT (config), prop_spec->name, &value);
- if (! g_param_value_defaults (prop_spec, &value))
- {
- /* Some properties may fail writing, which shouldn't break serializing
- * more properties, yet final result would be a (partial) failure.
- */
- if (! gimp_config_serialize_property (config, prop_spec, writer))
- success = FALSE;
- }
- g_value_unset (&value);
- }
- g_free (property_specs);
- return success;
- }
- /**
- * gimp_config_serialize_property:
- * @config: a #GimpConfig.
- * @param_spec: a #GParamSpec.
- * @writer: a #GimpConfigWriter.
- *
- * This function serializes a single object property to the @writer.
- *
- * Returns: %TRUE if serialization succeeded, %FALSE otherwise
- *
- * Since: 2.4
- **/
- gboolean
- gimp_config_serialize_property (GimpConfig *config,
- GParamSpec *param_spec,
- GimpConfigWriter *writer)
- {
- GimpConfigInterface *config_iface = NULL;
- GimpConfigInterface *parent_iface = NULL;
- GValue value = G_VALUE_INIT;
- gboolean success = FALSE;
- if (! (param_spec->flags & GIMP_CONFIG_PARAM_SERIALIZE))
- return FALSE;
- if (param_spec->flags & GIMP_CONFIG_PARAM_IGNORE)
- return TRUE;
- g_value_init (&value, param_spec->value_type);
- g_object_get_property (G_OBJECT (config), param_spec->name, &value);
- if (param_spec->flags & GIMP_CONFIG_PARAM_DEFAULTS &&
- g_param_value_defaults (param_spec, &value))
- {
- g_value_unset (&value);
- return TRUE;
- }
- if (G_TYPE_IS_OBJECT (param_spec->owner_type))
- {
- GTypeClass *owner_class = g_type_class_peek (param_spec->owner_type);
- config_iface = g_type_interface_peek (owner_class, GIMP_TYPE_CONFIG);
- /* We must call serialize_property() *only* if the *exact* class
- * which implements it is param_spec->owner_type's class.
- *
- * Therefore, we ask param_spec->owner_type's immediate parent class
- * for it's GimpConfigInterface and check if we get a different
- * pointer.
- *
- * (if the pointers are the same, param_spec->owner_type's
- * GimpConfigInterface is inherited from one of it's parent classes
- * and thus not able to handle param_spec->owner_type's properties).
- */
- if (config_iface)
- {
- GTypeClass *owner_parent_class;
- owner_parent_class = g_type_class_peek_parent (owner_class);
- parent_iface = g_type_interface_peek (owner_parent_class,
- GIMP_TYPE_CONFIG);
- }
- }
- if (config_iface &&
- config_iface != parent_iface && /* see comment above */
- config_iface->serialize_property &&
- config_iface->serialize_property (config,
- param_spec->param_id,
- (const GValue *) &value,
- param_spec,
- writer))
- {
- success = TRUE;
- }
- /* If there is no serialize_property() method *or* if it returned
- * FALSE, continue with the default implementation
- */
- if (! success)
- {
- if (G_VALUE_TYPE (&value) == GIMP_TYPE_PARASITE)
- {
- GimpParasite *parasite = g_value_get_boxed (&value);
- gimp_config_writer_open (writer, param_spec->name);
- if (parasite)
- {
- const gchar *name;
- gconstpointer data;
- guint32 data_length;
- gulong flags;
- name = gimp_parasite_get_name (parasite);
- gimp_config_writer_string (writer, name);
- flags = gimp_parasite_get_flags (parasite);
- data = gimp_parasite_get_data (parasite, &data_length);
- gimp_config_writer_printf (writer, "%lu %u", flags, data_length);
- gimp_config_writer_data (writer, data_length, data);
- success = TRUE;
- }
- if (success)
- gimp_config_writer_close (writer);
- else
- gimp_config_writer_revert (writer);
- }
- else if (G_VALUE_TYPE (&value) == G_TYPE_BYTES)
- {
- GBytes *bytes = g_value_get_boxed (&value);
- gimp_config_writer_open (writer, param_spec->name);
- if (bytes)
- {
- gconstpointer data;
- gsize data_length;
- data = g_bytes_get_data (bytes, &data_length);
- gimp_config_writer_printf (writer, "%" G_GSIZE_FORMAT, data_length);
- gimp_config_writer_data (writer, data_length, data);
- }
- else
- {
- gimp_config_writer_printf (writer, "%s", "NULL");
- }
- success = TRUE;
- gimp_config_writer_close (writer);
- }
- else if (GIMP_VALUE_HOLDS_COLOR (&value))
- {
- GeglColor *color = g_value_get_object (&value);
- gboolean free_color = FALSE;
- gimp_config_writer_open (writer, param_spec->name);
- if (color)
- {
- const gchar *encoding;
- const Babl *format = gegl_color_get_format (color);
- const Babl *space;
- GBytes *bytes;
- gconstpointer data;
- gsize data_length;
- int profile_length = 0;
- gimp_config_writer_open (writer, "color");
- if (babl_format_is_palette (format))
- {
- guint8 pixel[40];
- /* As a special case, we don't want to serialize
- * palette colors, because they are just too much
- * dependent on external data and cannot be
- * deserialized back safely. So we convert them first.
- */
- free_color = TRUE;
- color = gegl_color_duplicate (color);
- format = babl_format_with_space ("R'G'B'A u8", format);
- gegl_color_get_pixel (color, format, pixel);
- gegl_color_set_pixel (color, format, pixel);
- }
- encoding = babl_format_get_encoding (format);
- gimp_config_writer_string (writer, encoding);
- bytes = gegl_color_get_bytes (color, format);
- data = g_bytes_get_data (bytes, &data_length);
- gimp_config_writer_printf (writer, "%" G_GSIZE_FORMAT, data_length);
- gimp_config_writer_data (writer, data_length, data);
- space = babl_format_get_space (format);
- if (space != babl_space ("sRGB"))
- {
- guint8 *profile_data;
- profile_data = (guint8 *) babl_space_get_icc (babl_format_get_space (format),
- &profile_length);
- gimp_config_writer_printf (writer, "%u", profile_length);
- if (profile_data)
- gimp_config_writer_data (writer, profile_length, profile_data);
- }
- else
- {
- gimp_config_writer_printf (writer, "%u", profile_length);
- }
- g_bytes_unref (bytes);
- gimp_config_writer_close (writer);
- }
- else
- {
- gimp_config_writer_printf (writer, "%s", "NULL");
- }
- success = TRUE;
- gimp_config_writer_close (writer);
- if (free_color)
- g_object_unref (color);
- }
- else if (G_VALUE_HOLDS_OBJECT (&value) &&
- G_VALUE_TYPE (&value) != G_TYPE_FILE)
- {
- GimpConfigInterface *config_iface = NULL;
- GimpConfig *prop_object;
- prop_object = g_value_get_object (&value);
- if (prop_object)
- config_iface = GIMP_CONFIG_GET_IFACE (prop_object);
- else
- success = TRUE;
- if (config_iface)
- {
- gimp_config_writer_open (writer, param_spec->name);
- /* if the object property is not GIMP_CONFIG_PARAM_AGGREGATE,
- * deserializing will need to know the exact type
- * in order to create the object
- */
- if (! (param_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE))
- {
- GType object_type = G_TYPE_FROM_INSTANCE (prop_object);
- gimp_config_writer_string (writer, g_type_name (object_type));
- }
- success = config_iface->serialize (prop_object, writer, NULL);
- if (success)
- gimp_config_writer_close (writer);
- else
- gimp_config_writer_revert (writer);
- }
- }
- else
- {
- GString *str = g_string_new (NULL);
- if (G_VALUE_TYPE (&value) == G_TYPE_STRV)
- {
- success = gimp_config_serialize_strv (&value, str);
- }
- else
- {
- success = gimp_config_serialize_value (&value, str, TRUE);
- }
- if (success)
- {
- gimp_config_writer_open (writer, param_spec->name);
- gimp_config_writer_print (writer, str->str, str->len);
- gimp_config_writer_close (writer);
- }
- g_string_free (str, TRUE);
- }
- if (! success)
- {
- /* don't warn for empty string properties */
- if (G_VALUE_HOLDS_STRING (&value))
- {
- success = TRUE;
- }
- else
- {
- g_warning ("couldn't serialize property %s::%s of type %s",
- g_type_name (G_TYPE_FROM_INSTANCE (config)),
- param_spec->name,
- g_type_name (param_spec->value_type));
- }
- }
- }
- g_value_unset (&value);
- return success;
- }
- /**
- * gimp_config_serialize_property_by_name:
- * @config: a #GimpConfig.
- * @prop_name: the property's name.
- * @writer: a #GimpConfigWriter.
- *
- * This function serializes a single object property to the @writer.
- *
- * Returns: %TRUE if serialization succeeded, %FALSE otherwise
- *
- * Since: 2.6
- **/
- gboolean
- gimp_config_serialize_property_by_name (GimpConfig *config,
- const gchar *prop_name,
- GimpConfigWriter *writer)
- {
- GParamSpec *pspec;
- pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (config),
- prop_name);
- if (! pspec)
- return FALSE;
- return gimp_config_serialize_property (config, pspec, writer);
- }
- /**
- * gimp_config_serialize_value:
- * @value: a #GValue.
- * @str: a #GString.
- * @escaped: whether to escape string values.
- *
- * This utility function appends a string representation of #GValue to @str.
- *
- * Returns: %TRUE if serialization succeeded, %FALSE otherwise.
- *
- * Since: 2.4
- **/
- gboolean
- gimp_config_serialize_value (const GValue *value,
- GString *str,
- gboolean escaped)
- {
- if (G_VALUE_HOLDS_BOOLEAN (value))
- {
- gboolean bool;
- bool = g_value_get_boolean (value);
- g_string_append (str, bool ? "yes" : "no");
- return TRUE;
- }
- if (G_VALUE_HOLDS_ENUM (value))
- {
- GEnumClass *enum_class = g_type_class_peek (G_VALUE_TYPE (value));
- GEnumValue *enum_value = g_enum_get_value (enum_class,
- g_value_get_enum (value));
- if (enum_value && enum_value->value_nick)
- {
- g_string_append (str, enum_value->value_nick);
- return TRUE;
- }
- else
- {
- g_warning ("Couldn't get nick for enum_value of %s",
- G_ENUM_CLASS_TYPE_NAME (enum_class));
- return FALSE;
- }
- }
- if (G_VALUE_HOLDS_STRING (value))
- {
- const gchar *cstr = g_value_get_string (value);
- if (!cstr)
- return FALSE;
- if (escaped)
- gimp_config_string_append_escaped (str, cstr);
- else
- g_string_append (str, cstr);
- return TRUE;
- }
- if (G_VALUE_HOLDS_DOUBLE (value) || G_VALUE_HOLDS_FLOAT (value))
- {
- gdouble v_double;
- gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
- if (G_VALUE_HOLDS_DOUBLE (value))
- v_double = g_value_get_double (value);
- else
- v_double = (gdouble) g_value_get_float (value);
- g_ascii_dtostr (buf, sizeof (buf), v_double);
- g_string_append (str, buf);
- return TRUE;
- }
- if (GIMP_VALUE_HOLDS_MATRIX2 (value))
- {
- GimpMatrix2 *trafo;
- trafo = g_value_get_boxed (value);
- if (trafo)
- {
- gchar buf[4][G_ASCII_DTOSTR_BUF_SIZE];
- gint i, j, k;
- for (i = 0, k = 0; i < 2; i++)
- for (j = 0; j < 2; j++, k++)
- g_ascii_dtostr (buf[k], G_ASCII_DTOSTR_BUF_SIZE,
- trafo->coeff[i][j]);
- g_string_append_printf (str, "(matrix %s %s %s %s)",
- buf[0], buf[1], buf[2], buf[3]);
- }
- else
- {
- g_string_append (str, "(matrix 1.0 1.0 1.0 1.0)");
- }
- return TRUE;
- }
- if (G_VALUE_TYPE (value) == GIMP_TYPE_VALUE_ARRAY)
- {
- GimpValueArray *array;
- array = g_value_get_boxed (value);
- if (array)
- {
- gint length = gimp_value_array_length (array);
- gint i;
- g_string_append_printf (str, "%d", length);
- for (i = 0; i < length; i++)
- {
- g_string_append (str, " ");
- if (! gimp_config_serialize_value (gimp_value_array_index (array,
- i),
- str, TRUE))
- return FALSE;
- }
- }
- else
- {
- g_string_append (str, "0");
- }
- return TRUE;
- }
- if (G_VALUE_TYPE (value) == G_TYPE_FILE)
- {
- GFile *file = g_value_get_object (value);
- if (file)
- {
- gchar *path = g_file_get_path (file);
- gchar *unexpand = NULL;
- if (path)
- {
- unexpand = gimp_config_path_unexpand (path, TRUE, NULL);
- g_free (path);
- }
- if (unexpand)
- {
- if (escaped)
- gimp_config_string_append_escaped (str, unexpand);
- else
- g_string_append (str, unexpand);
- g_free (unexpand);
- }
- else
- {
- g_string_append (str, "NULL");
- }
- }
- else
- {
- g_string_append (str, "NULL");
- }
- return TRUE;
- }
- if (g_value_type_transformable (G_VALUE_TYPE (value), G_TYPE_STRING))
- {
- GValue tmp_value = G_VALUE_INIT;
- g_value_init (&tmp_value, G_TYPE_STRING);
- g_value_transform (value, &tmp_value);
- g_string_append (str, g_value_get_string (&tmp_value));
- g_value_unset (&tmp_value);
- return TRUE;
- }
- return FALSE;
- }
|