1 /* LIBGIMP - The GIMP Library
2 * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
4 * Config file serialization and deserialization interface
5 * Copyright (C) 2001-2002 Sven Neumann <sven@gimp.org>
7 * This library is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 3 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see
19 * <https://www.gnu.org/licenses/>.
28 #include "libgimpbase/gimpbase.h"
30 #include "gimpconfigtypes.h"
32 #include "gimpconfigwriter.h"
33 #include "gimpconfig-iface.h"
34 #include "gimpconfig-deserialize.h"
35 #include "gimpconfig-serialize.h"
36 #include "gimpconfig-params.h"
37 #include "gimpconfig-utils.h"
38 #include "gimpscanner.h"
40 #include "libgimp/libgimp-intl.h"
44 * SECTION: gimpconfig-iface
45 * @title: GimpConfig-iface
46 * @short_description: High-level API for libgimpconfig.
48 * High-level API for libgimpconfig.
53 * The GimpConfig serialization and deserialization interface.
57 /* local function prototypes */
59 static void gimp_config_iface_default_init (GimpConfigInterface
*iface
);
60 static void gimp_config_iface_base_init (GimpConfigInterface
*iface
);
62 static gboolean
gimp_config_iface_serialize (GimpConfig
*config
,
63 GimpConfigWriter
*writer
,
65 static gboolean
gimp_config_iface_deserialize (GimpConfig
*config
,
69 static GimpConfig
* gimp_config_iface_duplicate (GimpConfig
*config
);
70 static gboolean
gimp_config_iface_equal (GimpConfig
*a
,
72 static void gimp_config_iface_reset (GimpConfig
*config
);
73 static gboolean
gimp_config_iface_copy (GimpConfig
*src
,
78 /* private functions */
82 gimp_config_get_type (void)
84 static GType config_iface_type
= 0;
86 if (! config_iface_type
)
88 const GTypeInfo config_iface_info
=
90 sizeof (GimpConfigInterface
),
91 (GBaseInitFunc
) gimp_config_iface_base_init
,
92 (GBaseFinalizeFunc
) NULL
,
93 (GClassInitFunc
) gimp_config_iface_default_init
,
94 (GClassFinalizeFunc
) NULL
,
97 config_iface_type
= g_type_register_static (G_TYPE_INTERFACE
,
98 "GimpConfigInterface",
102 g_type_interface_add_prerequisite (config_iface_type
, G_TYPE_OBJECT
);
105 return config_iface_type
;
109 gimp_config_iface_default_init (GimpConfigInterface
*iface
)
111 iface
->serialize
= gimp_config_iface_serialize
;
112 iface
->deserialize
= gimp_config_iface_deserialize
;
113 iface
->duplicate
= gimp_config_iface_duplicate
;
114 iface
->equal
= gimp_config_iface_equal
;
115 iface
->reset
= gimp_config_iface_reset
;
116 iface
->copy
= gimp_config_iface_copy
;
120 gimp_config_iface_base_init (GimpConfigInterface
*iface
)
122 /* always set these to NULL since we don't want to inherit them
123 * from parent classes
125 iface
->serialize_property
= NULL
;
126 iface
->deserialize_property
= NULL
;
130 gimp_config_iface_serialize (GimpConfig
*config
,
131 GimpConfigWriter
*writer
,
134 return gimp_config_serialize_properties (config
, writer
);
138 gimp_config_iface_deserialize (GimpConfig
*config
,
143 return gimp_config_deserialize_properties (config
, scanner
, nest_level
);
147 gimp_config_iface_duplicate (GimpConfig
*config
)
149 GObject
*object
= G_OBJECT (config
);
150 GObjectClass
*klass
= G_OBJECT_GET_CLASS (object
);
151 GParamSpec
**property_specs
;
152 guint n_property_specs
;
153 gint n_construct_properties
= 0;
154 const gchar
**construct_names
= NULL
;
155 GValue
*construct_values
= NULL
;
159 property_specs
= g_object_class_list_properties (klass
, &n_property_specs
);
161 construct_names
= g_new0 (const gchar
*, n_property_specs
);
162 construct_values
= g_new0 (GValue
, n_property_specs
);
164 for (i
= 0; i
< n_property_specs
; i
++)
166 GParamSpec
*prop_spec
= property_specs
[i
];
168 if ((prop_spec
->flags
& G_PARAM_READABLE
) &&
169 (prop_spec
->flags
& G_PARAM_WRITABLE
) &&
170 (prop_spec
->flags
& G_PARAM_CONSTRUCT_ONLY
))
172 construct_names
[n_construct_properties
] = prop_spec
->name
;
174 g_value_init (&construct_values
[n_construct_properties
],
175 prop_spec
->value_type
);
176 g_object_get_property (object
, prop_spec
->name
,
177 &construct_values
[n_construct_properties
]);
179 n_construct_properties
++;
183 g_free (property_specs
);
185 dup
= g_object_new_with_properties (G_TYPE_FROM_INSTANCE (object
),
186 n_construct_properties
,
187 (const gchar
**) construct_names
,
188 (const GValue
*) construct_values
);
190 for (i
= 0; i
< n_construct_properties
; i
++)
191 g_value_unset (&construct_values
[i
]);
193 g_free (construct_names
);
194 g_free (construct_values
);
196 gimp_config_copy (config
, GIMP_CONFIG (dup
), 0);
198 return GIMP_CONFIG (dup
);
202 gimp_config_iface_equal (GimpConfig
*a
,
206 GParamSpec
**property_specs
;
207 guint n_property_specs
;
209 gboolean equal
= TRUE
;
211 klass
= G_OBJECT_GET_CLASS (a
);
213 property_specs
= g_object_class_list_properties (klass
, &n_property_specs
);
215 for (i
= 0; equal
&& i
< n_property_specs
; i
++)
217 GParamSpec
*prop_spec
;
218 GValue a_value
= G_VALUE_INIT
;
219 GValue b_value
= G_VALUE_INIT
;
221 prop_spec
= property_specs
[i
];
223 if (! (prop_spec
->flags
& G_PARAM_READABLE
))
226 g_value_init (&a_value
, prop_spec
->value_type
);
227 g_value_init (&b_value
, prop_spec
->value_type
);
228 g_object_get_property (G_OBJECT (a
), prop_spec
->name
, &a_value
);
229 g_object_get_property (G_OBJECT (b
), prop_spec
->name
, &b_value
);
231 if (g_param_values_cmp (prop_spec
, &a_value
, &b_value
))
233 if ((prop_spec
->flags
& GIMP_CONFIG_PARAM_AGGREGATE
) &&
234 G_IS_PARAM_SPEC_OBJECT (prop_spec
) &&
235 g_type_interface_peek (g_type_class_peek (prop_spec
->value_type
),
238 if (! gimp_config_is_equal_to (g_value_get_object (&a_value
),
239 g_value_get_object (&b_value
)))
250 g_value_unset (&a_value
);
251 g_value_unset (&b_value
);
254 g_free (property_specs
);
260 gimp_config_iface_reset (GimpConfig
*config
)
262 gimp_config_reset_properties (G_OBJECT (config
));
266 gimp_config_iface_copy (GimpConfig
*src
,
270 return gimp_config_sync (G_OBJECT (src
), G_OBJECT (dest
), flags
);
274 /* public functions */
278 * gimp_config_serialize_to_file:
279 * @config: a #GObject that implements the #GimpConfigInterface.
280 * @filename: the name of the file to write the configuration to.
281 * @header: optional file header (must be ASCII only)
282 * @footer: optional file footer (must be ASCII only)
283 * @data: user data passed to the serialize implementation.
284 * @error: return location for a possible error
286 * Serializes the object properties of @config to the file specified
287 * by @filename. If a file with that name already exists, it is
288 * overwritten. Basically this function opens @filename for you and
289 * calls the serialize function of the @config's #GimpConfigInterface.
291 * Return value: %TRUE if serialization succeeded, %FALSE otherwise.
296 gimp_config_serialize_to_file (GimpConfig
*config
,
297 const gchar
*filename
,
303 GimpConfigWriter
*writer
;
305 g_return_val_if_fail (GIMP_IS_CONFIG (config
), FALSE
);
306 g_return_val_if_fail (filename
!= NULL
, FALSE
);
307 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, FALSE
);
309 writer
= gimp_config_writer_new_file (filename
, TRUE
, header
, error
);
313 GIMP_CONFIG_GET_INTERFACE (config
)->serialize (config
, writer
, data
);
315 return gimp_config_writer_finish (writer
, footer
, error
);
319 * gimp_config_serialize_to_gfile:
320 * @config: a #GObject that implements the #GimpConfigInterface.
321 * @file: the #GFile to write the configuration to.
322 * @header: optional file header (must be ASCII only)
323 * @footer: optional file footer (must be ASCII only)
324 * @data: user data passed to the serialize implementation.
325 * @error: return location for a possible error
327 * Serializes the object properties of @config to the file specified
328 * by @file. If a file with that name already exists, it is
329 * overwritten. Basically this function opens @file for you and calls
330 * the serialize function of the @config's #GimpConfigInterface.
332 * Return value: %TRUE if serialization succeeded, %FALSE otherwise.
337 gimp_config_serialize_to_gfile (GimpConfig
*config
,
344 GimpConfigWriter
*writer
;
346 g_return_val_if_fail (GIMP_IS_CONFIG (config
), FALSE
);
347 g_return_val_if_fail (G_IS_FILE (file
), FALSE
);
348 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, FALSE
);
350 writer
= gimp_config_writer_new_gfile (file
, TRUE
, header
, error
);
354 GIMP_CONFIG_GET_INTERFACE (config
)->serialize (config
, writer
, data
);
356 return gimp_config_writer_finish (writer
, footer
, error
);
360 * gimp_config_serialize_to_stream:
361 * @config: a #GObject that implements the #GimpConfigInterface.
362 * @output: the #GOutputStream to write the configuration to.
363 * @header: optional file header (must be ASCII only)
364 * @footer: optional file footer (must be ASCII only)
365 * @data: user data passed to the serialize implementation.
366 * @error: return location for a possible error
368 * Serializes the object properties of @config to the stream specified
371 * Return value: %TRUE if serialization succeeded, %FALSE otherwise.
376 gimp_config_serialize_to_stream (GimpConfig
*config
,
377 GOutputStream
*output
,
383 GimpConfigWriter
*writer
;
385 g_return_val_if_fail (GIMP_IS_CONFIG (config
), FALSE
);
386 g_return_val_if_fail (G_IS_OUTPUT_STREAM (output
), FALSE
);
387 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, FALSE
);
389 writer
= gimp_config_writer_new_stream (output
, header
, error
);
393 GIMP_CONFIG_GET_INTERFACE (config
)->serialize (config
, writer
, data
);
395 return gimp_config_writer_finish (writer
, footer
, error
);
399 * gimp_config_serialize_to_fd:
400 * @config: a #GObject that implements the #GimpConfigInterface.
401 * @fd: a file descriptor, opened for writing
402 * @data: user data passed to the serialize implementation.
404 * Serializes the object properties of @config to the given file
407 * Return value: %TRUE if serialization succeeded, %FALSE otherwise.
412 gimp_config_serialize_to_fd (GimpConfig
*config
,
416 GimpConfigWriter
*writer
;
418 g_return_val_if_fail (GIMP_IS_CONFIG (config
), FALSE
);
419 g_return_val_if_fail (fd
> 0, FALSE
);
421 writer
= gimp_config_writer_new_fd (fd
);
425 GIMP_CONFIG_GET_INTERFACE (config
)->serialize (config
, writer
, data
);
427 return gimp_config_writer_finish (writer
, NULL
, NULL
);
431 * gimp_config_serialize_to_string:
432 * @config: a #GObject that implements the #GimpConfigInterface.
433 * @data: user data passed to the serialize implementation.
435 * Serializes the object properties of @config to a string.
437 * Return value: a newly allocated NUL-terminated string.
442 gimp_config_serialize_to_string (GimpConfig
*config
,
445 GimpConfigWriter
*writer
;
448 g_return_val_if_fail (GIMP_IS_CONFIG (config
), NULL
);
450 str
= g_string_new (NULL
);
451 writer
= gimp_config_writer_new_string (str
);
453 GIMP_CONFIG_GET_INTERFACE (config
)->serialize (config
, writer
, data
);
455 gimp_config_writer_finish (writer
, NULL
, NULL
);
457 return g_string_free (str
, FALSE
);
461 * gimp_config_deserialize_file:
462 * @config: a #GObject that implements the #GimpConfigInterface.
463 * @filename: the name of the file to read configuration from.
464 * @data: user data passed to the deserialize implementation.
465 * @error: return location for a possible error
467 * Opens the file specified by @filename, reads configuration data
468 * from it and configures @config accordingly. Basically this function
469 * creates a properly configured #GScanner for you and calls the
470 * deserialize function of the @config's #GimpConfigInterface.
472 * Return value: %TRUE if deserialization succeeded, %FALSE otherwise.
477 gimp_config_deserialize_file (GimpConfig
*config
,
478 const gchar
*filename
,
485 g_return_val_if_fail (GIMP_IS_CONFIG (config
), FALSE
);
486 g_return_val_if_fail (filename
!= NULL
, FALSE
);
487 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, FALSE
);
489 scanner
= gimp_scanner_new_file (filename
, error
);
493 g_object_freeze_notify (G_OBJECT (config
));
495 success
= GIMP_CONFIG_GET_INTERFACE (config
)->deserialize (config
,
498 g_object_thaw_notify (G_OBJECT (config
));
500 gimp_scanner_destroy (scanner
);
503 g_assert (error
== NULL
|| *error
!= NULL
);
509 * gimp_config_deserialize_gfile:
510 * @config: a #GObject that implements the #GimpConfigInterface.
511 * @file: the #GFile to read configuration from.
512 * @data: user data passed to the deserialize implementation.
513 * @error: return location for a possible error
515 * Opens the file specified by @file, reads configuration data from it
516 * and configures @config accordingly. Basically this function creates
517 * a properly configured #GScanner for you and calls the deserialize
518 * function of the @config's #GimpConfigInterface.
520 * Return value: %TRUE if deserialization succeeded, %FALSE otherwise.
525 gimp_config_deserialize_gfile (GimpConfig
*config
,
533 g_return_val_if_fail (GIMP_IS_CONFIG (config
), FALSE
);
534 g_return_val_if_fail (G_IS_FILE (file
), FALSE
);
535 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, FALSE
);
537 scanner
= gimp_scanner_new_gfile (file
, error
);
541 g_object_freeze_notify (G_OBJECT (config
));
543 success
= GIMP_CONFIG_GET_INTERFACE (config
)->deserialize (config
,
546 g_object_thaw_notify (G_OBJECT (config
));
548 gimp_scanner_destroy (scanner
);
551 g_assert (error
== NULL
|| *error
!= NULL
);
557 * gimp_config_deserialize_stream:
558 * @config: a #GObject that implements the #GimpConfigInterface.
559 * @input: the #GInputStream to read configuration from.
560 * @data: user data passed to the deserialize implementation.
561 * @error: return location for a possible error
563 * Reads configuration data from @input and configures @config
564 * accordingly. Basically this function creates a properly configured
565 * #GScanner for you and calls the deserialize function of the
566 * @config's #GimpConfigInterface.
568 * Return value: %TRUE if deserialization succeeded, %FALSE otherwise.
573 gimp_config_deserialize_stream (GimpConfig
*config
,
581 g_return_val_if_fail (GIMP_IS_CONFIG (config
), FALSE
);
582 g_return_val_if_fail (G_IS_INPUT_STREAM (input
), FALSE
);
583 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, FALSE
);
585 scanner
= gimp_scanner_new_stream (input
, error
);
589 g_object_freeze_notify (G_OBJECT (config
));
591 success
= GIMP_CONFIG_GET_INTERFACE (config
)->deserialize (config
,
594 g_object_thaw_notify (G_OBJECT (config
));
596 gimp_scanner_destroy (scanner
);
599 g_assert (error
== NULL
|| *error
!= NULL
);
605 * gimp_config_deserialize_string:
606 * @config: a #GObject that implements the #GimpConfigInterface.
607 * @text: string to deserialize (in UTF-8 encoding)
608 * @text_len: length of @text in bytes or -1
610 * @error: return location for a possible error
612 * Configures @config from @text. Basically this function creates a
613 * properly configured #GScanner for you and calls the deserialize
614 * function of the @config's #GimpConfigInterface.
616 * Returns: %TRUE if deserialization succeeded, %FALSE otherwise.
621 gimp_config_deserialize_string (GimpConfig
*config
,
630 g_return_val_if_fail (GIMP_IS_CONFIG (config
), FALSE
);
631 g_return_val_if_fail (text
!= NULL
|| text_len
== 0, FALSE
);
632 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, FALSE
);
634 scanner
= gimp_scanner_new_string (text
, text_len
, error
);
636 g_object_freeze_notify (G_OBJECT (config
));
638 success
= GIMP_CONFIG_GET_INTERFACE (config
)->deserialize (config
,
641 g_object_thaw_notify (G_OBJECT (config
));
643 gimp_scanner_destroy (scanner
);
646 g_assert (error
== NULL
|| *error
!= NULL
);
652 * gimp_config_deserialize_return:
653 * @scanner: a #GScanner
654 * @expected_token: the expected token
655 * @nest_level: the nest level
662 gimp_config_deserialize_return (GScanner
*scanner
,
663 GTokenType expected_token
,
666 GTokenType next_token
;
668 g_return_val_if_fail (scanner
!= NULL
, FALSE
);
670 next_token
= g_scanner_peek_next_token (scanner
);
672 if (expected_token
!= G_TOKEN_LEFT_PAREN
)
674 g_scanner_get_next_token (scanner
);
675 g_scanner_unexp_token (scanner
, expected_token
, NULL
, NULL
, NULL
,
676 _("fatal parse error"), TRUE
);
681 if (nest_level
> 0 && next_token
== G_TOKEN_RIGHT_PAREN
)
685 else if (next_token
!= G_TOKEN_EOF
)
687 g_scanner_get_next_token (scanner
);
688 g_scanner_unexp_token (scanner
, expected_token
, NULL
, NULL
, NULL
,
689 _("fatal parse error"), TRUE
);
699 * gimp_config_serialize:
700 * @config: a #GObject that implements the #GimpConfigInterface.
701 * @writer: the #GimpConfigWriter to use.
704 * Serialize the #GimpConfig object.
706 * Returns: %TRUE if serialization succeeded, %FALSE otherwise.
711 gimp_config_serialize (GimpConfig
*config
,
712 GimpConfigWriter
*writer
,
715 g_return_val_if_fail (GIMP_IS_CONFIG (config
), FALSE
);
717 return GIMP_CONFIG_GET_INTERFACE (config
)->serialize (config
,
723 * gimp_config_deserialize:
724 * @config: a #GObject that implements the #GimpConfigInterface.
725 * @scanner: the #GScanner to use.
726 * @nest_level: the nest level.
727 * @data: client data.
729 * Deserialize the #GimpConfig object.
731 * Returns: %TRUE if deserialization succeeded, %FALSE otherwise.
736 gimp_config_deserialize (GimpConfig
*config
,
741 g_return_val_if_fail (GIMP_IS_CONFIG (config
), FALSE
);
743 return GIMP_CONFIG_GET_INTERFACE (config
)->deserialize (config
,
750 * gimp_config_duplicate:
751 * @config: a #GObject that implements the #GimpConfigInterface.
753 * Creates a copy of the passed object by copying all object
754 * properties. The default implementation of the #GimpConfigInterface
755 * only works for objects that are completely defined by their
758 * Return value: the duplicated #GimpConfig object
763 gimp_config_duplicate (GimpConfig
*config
)
765 g_return_val_if_fail (GIMP_IS_CONFIG (config
), NULL
);
767 return GIMP_CONFIG_GET_INTERFACE (config
)->duplicate (config
);
771 * gimp_config_is_equal_to:
772 * @a: a #GObject that implements the #GimpConfigInterface.
773 * @b: another #GObject of the same type as @a.
775 * Compares the two objects. The default implementation of the
776 * #GimpConfigInterface compares the object properties and thus only
777 * works for objects that are completely defined by their
780 * Return value: %TRUE if the two objects are equal.
785 gimp_config_is_equal_to (GimpConfig
*a
,
788 g_return_val_if_fail (GIMP_IS_CONFIG (a
), FALSE
);
789 g_return_val_if_fail (GIMP_IS_CONFIG (b
), FALSE
);
790 g_return_val_if_fail (G_TYPE_FROM_INSTANCE (a
) == G_TYPE_FROM_INSTANCE (b
),
793 return GIMP_CONFIG_GET_INTERFACE (a
)->equal (a
, b
);
798 * @config: a #GObject that implements the #GimpConfigInterface.
800 * Resets the object to its default state. The default implementation of the
801 * #GimpConfigInterface only works for objects that are completely defined by
807 gimp_config_reset (GimpConfig
*config
)
809 g_return_if_fail (GIMP_IS_CONFIG (config
));
811 g_object_freeze_notify (G_OBJECT (config
));
813 GIMP_CONFIG_GET_INTERFACE (config
)->reset (config
);
815 g_object_thaw_notify (G_OBJECT (config
));
820 * @src: a #GObject that implements the #GimpConfigInterface.
821 * @dest: another #GObject of the same type as @a.
822 * @flags: a mask of GParamFlags
824 * Compares all read- and write-able properties from @src and @dest
825 * that have all @flags set. Differing values are then copied from
826 * @src to @dest. If @flags is 0, all differing read/write properties.
828 * Properties marked as "construct-only" are not touched.
830 * Return value: %TRUE if @dest was modified, %FALSE otherwise
835 gimp_config_copy (GimpConfig
*src
,
841 g_return_val_if_fail (GIMP_IS_CONFIG (src
), FALSE
);
842 g_return_val_if_fail (GIMP_IS_CONFIG (dest
), FALSE
);
843 g_return_val_if_fail (G_TYPE_FROM_INSTANCE (src
) == G_TYPE_FROM_INSTANCE (dest
),
846 g_object_freeze_notify (G_OBJECT (dest
));
848 changed
= GIMP_CONFIG_GET_INTERFACE (src
)->copy (src
, dest
, flags
);
850 g_object_thaw_notify (G_OBJECT (dest
));