1 /* LIBGIMP - The GIMP Library
2  * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
3  *
4  * Config file serialization and deserialization interface
5  * Copyright (C) 2001-2002  Sven Neumann <sven@gimp.org>
6  *
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.
11  *
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.
16  *
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/>.
20  */
21 
22 #include "config.h"
23 
24 #include <string.h>
25 
26 #include <gio/gio.h>
27 
28 #include "libgimpbase/gimpbase.h"
29 
30 #include "gimpconfigtypes.h"
31 
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"
39 
40 #include "libgimp/libgimp-intl.h"
41 
42 
43 /**
44  * SECTION: gimpconfig-iface
45  * @title: GimpConfig-iface
46  * @short_description: High-level API for libgimpconfig.
47  *
48  * High-level API for libgimpconfig.
49  **/
50 
51 
52 /*
53  * The GimpConfig serialization and deserialization interface.
54  */
55 
56 
57 /*  local function prototypes  */
58 
59 static void         gimp_config_iface_default_init (GimpConfigInterface *iface);
60 static void         gimp_config_iface_base_init    (GimpConfigInterface *iface);
61 
62 static gboolean     gimp_config_iface_serialize    (GimpConfig          *config,
63                                                     GimpConfigWriter    *writer,
64                                                     gpointer             data);
65 static gboolean     gimp_config_iface_deserialize  (GimpConfig          *config,
66                                                     GScanner            *scanner,
67                                                     gint                 nest_level,
68                                                     gpointer             data);
69 static GimpConfig * gimp_config_iface_duplicate    (GimpConfig          *config);
70 static gboolean     gimp_config_iface_equal        (GimpConfig          *a,
71                                                     GimpConfig          *b);
72 static void         gimp_config_iface_reset        (GimpConfig          *config);
73 static gboolean     gimp_config_iface_copy         (GimpConfig          *src,
74                                                     GimpConfig          *dest,
75                                                     GParamFlags          flags);
76 
77 
78 /*  private functions  */
79 
80 
81 GType
gimp_config_get_type(void)82 gimp_config_get_type (void)
83 {
84   static GType config_iface_type = 0;
85 
86   if (! config_iface_type)
87     {
88       const GTypeInfo config_iface_info =
89       {
90         sizeof (GimpConfigInterface),
91         (GBaseInitFunc)      gimp_config_iface_base_init,
92         (GBaseFinalizeFunc)  NULL,
93         (GClassInitFunc)     gimp_config_iface_default_init,
94         (GClassFinalizeFunc) NULL,
95       };
96 
97       config_iface_type = g_type_register_static (G_TYPE_INTERFACE,
98                                                   "GimpConfigInterface",
99                                                   &config_iface_info,
100                                                   0);
101 
102       g_type_interface_add_prerequisite (config_iface_type, G_TYPE_OBJECT);
103     }
104 
105   return config_iface_type;
106 }
107 
108 GType
gimp_config_interface_get_type(void)109 gimp_config_interface_get_type (void)
110 {
111   return gimp_config_get_type ();
112 }
113 
114 static void
gimp_config_iface_default_init(GimpConfigInterface * iface)115 gimp_config_iface_default_init (GimpConfigInterface *iface)
116 {
117   iface->serialize   = gimp_config_iface_serialize;
118   iface->deserialize = gimp_config_iface_deserialize;
119   iface->duplicate   = gimp_config_iface_duplicate;
120   iface->equal       = gimp_config_iface_equal;
121   iface->reset       = gimp_config_iface_reset;
122   iface->copy        = gimp_config_iface_copy;
123 }
124 
125 static void
gimp_config_iface_base_init(GimpConfigInterface * iface)126 gimp_config_iface_base_init (GimpConfigInterface *iface)
127 {
128   /*  always set these to NULL since we don't want to inherit them
129    *  from parent classes
130    */
131   iface->serialize_property   = NULL;
132   iface->deserialize_property = NULL;
133 }
134 
135 static gboolean
gimp_config_iface_serialize(GimpConfig * config,GimpConfigWriter * writer,gpointer data)136 gimp_config_iface_serialize (GimpConfig       *config,
137                              GimpConfigWriter *writer,
138                              gpointer          data)
139 {
140   return gimp_config_serialize_properties (config, writer);
141 }
142 
143 static gboolean
gimp_config_iface_deserialize(GimpConfig * config,GScanner * scanner,gint nest_level,gpointer data)144 gimp_config_iface_deserialize (GimpConfig *config,
145                                GScanner   *scanner,
146                                gint        nest_level,
147                                gpointer    data)
148 {
149   return gimp_config_deserialize_properties (config, scanner, nest_level);
150 }
151 
152 static GimpConfig *
gimp_config_iface_duplicate(GimpConfig * config)153 gimp_config_iface_duplicate (GimpConfig *config)
154 {
155   GObject       *object = G_OBJECT (config);
156   GObjectClass  *klass  = G_OBJECT_GET_CLASS (object);
157   GParamSpec   **property_specs;
158   guint          n_property_specs;
159   gint           n_construct_properties = 0;
160   const gchar  **construct_names        = NULL;
161   GValue        *construct_values       = NULL;
162   guint          i;
163   GObject       *dup;
164 
165   property_specs = g_object_class_list_properties (klass, &n_property_specs);
166 
167   construct_names  = g_new0 (const gchar *, n_property_specs);
168   construct_values = g_new0 (GValue,        n_property_specs);
169 
170   for (i = 0; i < n_property_specs; i++)
171     {
172       GParamSpec *prop_spec = property_specs[i];
173 
174       if ((prop_spec->flags & G_PARAM_READABLE) &&
175           (prop_spec->flags & G_PARAM_WRITABLE) &&
176           (prop_spec->flags & G_PARAM_CONSTRUCT_ONLY))
177         {
178           construct_names[n_construct_properties] = prop_spec->name;
179 
180           g_value_init (&construct_values[n_construct_properties],
181                         prop_spec->value_type);
182           g_object_get_property (object, prop_spec->name,
183                                  &construct_values[n_construct_properties]);
184 
185           n_construct_properties++;
186         }
187     }
188 
189   g_free (property_specs);
190 
191   dup = g_object_new_with_properties (G_TYPE_FROM_INSTANCE (object),
192                                       n_construct_properties,
193                                       (const gchar **) construct_names,
194                                       (const GValue *) construct_values);
195 
196   for (i = 0; i < n_construct_properties; i++)
197     g_value_unset (&construct_values[i]);
198 
199   g_free (construct_names);
200   g_free (construct_values);
201 
202   gimp_config_copy (config, GIMP_CONFIG (dup), 0);
203 
204   return GIMP_CONFIG (dup);
205 }
206 
207 static gboolean
gimp_config_iface_equal(GimpConfig * a,GimpConfig * b)208 gimp_config_iface_equal (GimpConfig *a,
209                          GimpConfig *b)
210 {
211   GObjectClass  *klass;
212   GParamSpec   **property_specs;
213   guint          n_property_specs;
214   guint          i;
215   gboolean       equal = TRUE;
216 
217   klass = G_OBJECT_GET_CLASS (a);
218 
219   property_specs = g_object_class_list_properties (klass, &n_property_specs);
220 
221   for (i = 0; equal && i < n_property_specs; i++)
222     {
223       GParamSpec  *prop_spec;
224       GValue       a_value = G_VALUE_INIT;
225       GValue       b_value = G_VALUE_INIT;
226 
227       prop_spec = property_specs[i];
228 
229       if (! (prop_spec->flags & G_PARAM_READABLE))
230         continue;
231 
232       g_value_init (&a_value, prop_spec->value_type);
233       g_value_init (&b_value, prop_spec->value_type);
234       g_object_get_property (G_OBJECT (a), prop_spec->name, &a_value);
235       g_object_get_property (G_OBJECT (b), prop_spec->name, &b_value);
236 
237       if (g_param_values_cmp (prop_spec, &a_value, &b_value))
238         {
239           if ((prop_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE) &&
240               G_IS_PARAM_SPEC_OBJECT (prop_spec)        &&
241               g_type_interface_peek (g_type_class_peek (prop_spec->value_type),
242                                      GIMP_TYPE_CONFIG))
243             {
244               if (! gimp_config_is_equal_to (g_value_get_object (&a_value),
245                                              g_value_get_object (&b_value)))
246                 {
247                   equal = FALSE;
248                 }
249             }
250           else
251             {
252               equal = FALSE;
253             }
254         }
255 
256       g_value_unset (&a_value);
257       g_value_unset (&b_value);
258     }
259 
260   g_free (property_specs);
261 
262   return equal;
263 }
264 
265 static void
gimp_config_iface_reset(GimpConfig * config)266 gimp_config_iface_reset (GimpConfig *config)
267 {
268   gimp_config_reset_properties (G_OBJECT (config));
269 }
270 
271 static gboolean
gimp_config_iface_copy(GimpConfig * src,GimpConfig * dest,GParamFlags flags)272 gimp_config_iface_copy (GimpConfig  *src,
273                         GimpConfig  *dest,
274                         GParamFlags  flags)
275 {
276   return gimp_config_sync (G_OBJECT (src), G_OBJECT (dest), flags);
277 }
278 
279 
280 /*  public functions  */
281 
282 
283 /**
284  * gimp_config_serialize_to_file:
285  * @config: a #GObject that implements the #GimpConfigInterface.
286  * @filename: the name of the file to write the configuration to.
287  * @header: optional file header (must be ASCII only)
288  * @footer: optional file footer (must be ASCII only)
289  * @data: user data passed to the serialize implementation.
290  * @error: return location for a possible error
291  *
292  * Serializes the object properties of @config to the file specified
293  * by @filename. If a file with that name already exists, it is
294  * overwritten. Basically this function opens @filename for you and
295  * calls the serialize function of the @config's #GimpConfigInterface.
296  *
297  * Return value: %TRUE if serialization succeeded, %FALSE otherwise.
298  *
299  * Since: 2.4
300  **/
301 gboolean
gimp_config_serialize_to_file(GimpConfig * config,const gchar * filename,const gchar * header,const gchar * footer,gpointer data,GError ** error)302 gimp_config_serialize_to_file (GimpConfig   *config,
303                                const gchar  *filename,
304                                const gchar  *header,
305                                const gchar  *footer,
306                                gpointer      data,
307                                GError      **error)
308 {
309   GimpConfigWriter *writer;
310 
311   g_return_val_if_fail (GIMP_IS_CONFIG (config), FALSE);
312   g_return_val_if_fail (filename != NULL, FALSE);
313   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
314 
315   writer = gimp_config_writer_new_file (filename, TRUE, header, error);
316   if (!writer)
317     return FALSE;
318 
319   GIMP_CONFIG_GET_INTERFACE (config)->serialize (config, writer, data);
320 
321   return gimp_config_writer_finish (writer, footer, error);
322 }
323 
324 /**
325  * gimp_config_serialize_to_gfile:
326  * @config: a #GObject that implements the #GimpConfigInterface.
327  * @file:   the #GFile to write the configuration to.
328  * @header: optional file header (must be ASCII only)
329  * @footer: optional file footer (must be ASCII only)
330  * @data: user data passed to the serialize implementation.
331  * @error: return location for a possible error
332  *
333  * Serializes the object properties of @config to the file specified
334  * by @file. If a file with that name already exists, it is
335  * overwritten. Basically this function opens @file for you and calls
336  * the serialize function of the @config's #GimpConfigInterface.
337  *
338  * Return value: %TRUE if serialization succeeded, %FALSE otherwise.
339  *
340  * Since: 2.10
341  **/
342 gboolean
gimp_config_serialize_to_gfile(GimpConfig * config,GFile * file,const gchar * header,const gchar * footer,gpointer data,GError ** error)343 gimp_config_serialize_to_gfile (GimpConfig   *config,
344                                 GFile        *file,
345                                 const gchar  *header,
346                                 const gchar  *footer,
347                                 gpointer      data,
348                                 GError      **error)
349 {
350   GimpConfigWriter *writer;
351 
352   g_return_val_if_fail (GIMP_IS_CONFIG (config), FALSE);
353   g_return_val_if_fail (G_IS_FILE (file), FALSE);
354   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
355 
356   writer = gimp_config_writer_new_gfile (file, TRUE, header, error);
357   if (!writer)
358     return FALSE;
359 
360   GIMP_CONFIG_GET_INTERFACE (config)->serialize (config, writer, data);
361 
362   return gimp_config_writer_finish (writer, footer, error);
363 }
364 
365 /**
366  * gimp_config_serialize_to_stream:
367  * @config: a #GObject that implements the #GimpConfigInterface.
368  * @output: the #GOutputStream to write the configuration to.
369  * @header: optional file header (must be ASCII only)
370  * @footer: optional file footer (must be ASCII only)
371  * @data: user data passed to the serialize implementation.
372  * @error: return location for a possible error
373  *
374  * Serializes the object properties of @config to the stream specified
375  * by @output.
376  *
377  * Return value: %TRUE if serialization succeeded, %FALSE otherwise.
378  *
379  * Since: 2.10
380  **/
381 gboolean
gimp_config_serialize_to_stream(GimpConfig * config,GOutputStream * output,const gchar * header,const gchar * footer,gpointer data,GError ** error)382 gimp_config_serialize_to_stream (GimpConfig     *config,
383                                  GOutputStream  *output,
384                                  const gchar    *header,
385                                  const gchar    *footer,
386                                  gpointer        data,
387                                  GError        **error)
388 {
389   GimpConfigWriter *writer;
390 
391   g_return_val_if_fail (GIMP_IS_CONFIG (config), FALSE);
392   g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), FALSE);
393   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
394 
395   writer = gimp_config_writer_new_stream (output, header, error);
396   if (!writer)
397     return FALSE;
398 
399   GIMP_CONFIG_GET_INTERFACE (config)->serialize (config, writer, data);
400 
401   return gimp_config_writer_finish (writer, footer, error);
402 }
403 
404 /**
405  * gimp_config_serialize_to_fd:
406  * @config: a #GObject that implements the #GimpConfigInterface.
407  * @fd: a file descriptor, opened for writing
408  * @data: user data passed to the serialize implementation.
409  *
410  * Serializes the object properties of @config to the given file
411  * descriptor.
412  *
413  * Return value: %TRUE if serialization succeeded, %FALSE otherwise.
414  *
415  * Since: 2.4
416  **/
417 gboolean
gimp_config_serialize_to_fd(GimpConfig * config,gint fd,gpointer data)418 gimp_config_serialize_to_fd (GimpConfig *config,
419                              gint        fd,
420                              gpointer    data)
421 {
422   GimpConfigWriter *writer;
423 
424   g_return_val_if_fail (GIMP_IS_CONFIG (config), FALSE);
425   g_return_val_if_fail (fd > 0, FALSE);
426 
427   writer = gimp_config_writer_new_fd (fd);
428   if (!writer)
429     return FALSE;
430 
431   GIMP_CONFIG_GET_INTERFACE (config)->serialize (config, writer, data);
432 
433   return gimp_config_writer_finish (writer, NULL, NULL);
434 }
435 
436 /**
437  * gimp_config_serialize_to_string:
438  * @config: a #GObject that implements the #GimpConfigInterface.
439  * @data: user data passed to the serialize implementation.
440  *
441  * Serializes the object properties of @config to a string.
442  *
443  * Return value: a newly allocated NUL-terminated string.
444  *
445  * Since: 2.4
446  **/
447 gchar *
gimp_config_serialize_to_string(GimpConfig * config,gpointer data)448 gimp_config_serialize_to_string (GimpConfig *config,
449                                  gpointer    data)
450 {
451   GimpConfigWriter *writer;
452   GString          *str;
453 
454   g_return_val_if_fail (GIMP_IS_CONFIG (config), NULL);
455 
456   str = g_string_new (NULL);
457   writer = gimp_config_writer_new_string (str);
458 
459   GIMP_CONFIG_GET_INTERFACE (config)->serialize (config, writer, data);
460 
461   gimp_config_writer_finish (writer, NULL, NULL);
462 
463   return g_string_free (str, FALSE);
464 }
465 
466 /**
467  * gimp_config_deserialize_file:
468  * @config: a #GObject that implements the #GimpConfigInterface.
469  * @filename: the name of the file to read configuration from.
470  * @data: user data passed to the deserialize implementation.
471  * @error: return location for a possible error
472  *
473  * Opens the file specified by @filename, reads configuration data
474  * from it and configures @config accordingly. Basically this function
475  * creates a properly configured #GScanner for you and calls the
476  * deserialize function of the @config's #GimpConfigInterface.
477  *
478  * Return value: %TRUE if deserialization succeeded, %FALSE otherwise.
479  *
480  * Since: 2.4
481  **/
482 gboolean
gimp_config_deserialize_file(GimpConfig * config,const gchar * filename,gpointer data,GError ** error)483 gimp_config_deserialize_file (GimpConfig   *config,
484                               const gchar  *filename,
485                               gpointer      data,
486                               GError      **error)
487 {
488   GScanner *scanner;
489   gboolean  success;
490 
491   g_return_val_if_fail (GIMP_IS_CONFIG (config), FALSE);
492   g_return_val_if_fail (filename != NULL, FALSE);
493   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
494 
495   scanner = gimp_scanner_new_file (filename, error);
496   if (! scanner)
497     return FALSE;
498 
499   g_object_freeze_notify (G_OBJECT (config));
500 
501   success = GIMP_CONFIG_GET_INTERFACE (config)->deserialize (config,
502                                                              scanner, 0, data);
503 
504   g_object_thaw_notify (G_OBJECT (config));
505 
506   gimp_scanner_destroy (scanner);
507 
508   if (! success)
509     g_assert (error == NULL || *error != NULL);
510 
511   return success;
512 }
513 
514 /**
515  * gimp_config_deserialize_gfile:
516  * @config: a #GObject that implements the #GimpConfigInterface.
517  * @file: the #GFile to read configuration from.
518  * @data: user data passed to the deserialize implementation.
519  * @error: return location for a possible error
520  *
521  * Opens the file specified by @file, reads configuration data from it
522  * and configures @config accordingly. Basically this function creates
523  * a properly configured #GScanner for you and calls the deserialize
524  * function of the @config's #GimpConfigInterface.
525  *
526  * Return value: %TRUE if deserialization succeeded, %FALSE otherwise.
527  *
528  * Since: 2.10
529  **/
530 gboolean
gimp_config_deserialize_gfile(GimpConfig * config,GFile * file,gpointer data,GError ** error)531 gimp_config_deserialize_gfile (GimpConfig  *config,
532                                GFile       *file,
533                                gpointer     data,
534                                GError     **error)
535 {
536   GScanner *scanner;
537   gboolean  success;
538 
539   g_return_val_if_fail (GIMP_IS_CONFIG (config), FALSE);
540   g_return_val_if_fail (G_IS_FILE (file), FALSE);
541   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
542 
543   scanner = gimp_scanner_new_gfile (file, error);
544   if (! scanner)
545     return FALSE;
546 
547   g_object_freeze_notify (G_OBJECT (config));
548 
549   success = GIMP_CONFIG_GET_INTERFACE (config)->deserialize (config,
550                                                              scanner, 0, data);
551 
552   g_object_thaw_notify (G_OBJECT (config));
553 
554   gimp_scanner_destroy (scanner);
555 
556   if (! success)
557     g_assert (error == NULL || *error != NULL);
558 
559   return success;
560 }
561 
562 /**
563  * gimp_config_deserialize_stream:
564  * @config: a #GObject that implements the #GimpConfigInterface.
565  * @input: the #GInputStream to read configuration from.
566  * @data: user data passed to the deserialize implementation.
567  * @error: return location for a possible error
568  *
569  * Reads configuration data from @input and configures @config
570  * accordingly. Basically this function creates a properly configured
571  * #GScanner for you and calls the deserialize function of the
572  * @config's #GimpConfigInterface.
573  *
574  * Return value: %TRUE if deserialization succeeded, %FALSE otherwise.
575  *
576  * Since: 2.10
577  **/
578 gboolean
gimp_config_deserialize_stream(GimpConfig * config,GInputStream * input,gpointer data,GError ** error)579 gimp_config_deserialize_stream (GimpConfig    *config,
580                                 GInputStream  *input,
581                                 gpointer       data,
582                                 GError       **error)
583 {
584   GScanner *scanner;
585   gboolean  success;
586 
587   g_return_val_if_fail (GIMP_IS_CONFIG (config), FALSE);
588   g_return_val_if_fail (G_IS_INPUT_STREAM (input), FALSE);
589   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
590 
591   scanner = gimp_scanner_new_stream (input, error);
592   if (! scanner)
593     return FALSE;
594 
595   g_object_freeze_notify (G_OBJECT (config));
596 
597   success = GIMP_CONFIG_GET_INTERFACE (config)->deserialize (config,
598                                                              scanner, 0, data);
599 
600   g_object_thaw_notify (G_OBJECT (config));
601 
602   gimp_scanner_destroy (scanner);
603 
604   if (! success)
605     g_assert (error == NULL || *error != NULL);
606 
607   return success;
608 }
609 
610 /**
611  * gimp_config_deserialize_string:
612  * @config:   a #GObject that implements the #GimpConfigInterface.
613  * @text:     string to deserialize (in UTF-8 encoding)
614  * @text_len: length of @text in bytes or -1
615  * @data:     client data
616  * @error:    return location for a possible error
617  *
618  * Configures @config from @text. Basically this function creates a
619  * properly configured #GScanner for you and calls the deserialize
620  * function of the @config's #GimpConfigInterface.
621  *
622  * Returns: %TRUE if deserialization succeeded, %FALSE otherwise.
623  *
624  * Since: 2.4
625  **/
626 gboolean
gimp_config_deserialize_string(GimpConfig * config,const gchar * text,gint text_len,gpointer data,GError ** error)627 gimp_config_deserialize_string (GimpConfig      *config,
628                                 const gchar  *text,
629                                 gint          text_len,
630                                 gpointer      data,
631                                 GError      **error)
632 {
633   GScanner *scanner;
634   gboolean  success;
635 
636   g_return_val_if_fail (GIMP_IS_CONFIG (config), FALSE);
637   g_return_val_if_fail (text != NULL || text_len == 0, FALSE);
638   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
639 
640   scanner = gimp_scanner_new_string (text, text_len, error);
641 
642   g_object_freeze_notify (G_OBJECT (config));
643 
644   success = GIMP_CONFIG_GET_INTERFACE (config)->deserialize (config,
645                                                              scanner, 0, data);
646 
647   g_object_thaw_notify (G_OBJECT (config));
648 
649   gimp_scanner_destroy (scanner);
650 
651   if (! success)
652     g_assert (error == NULL || *error != NULL);
653 
654   return success;
655 }
656 
657 /**
658  * gimp_config_deserialize_return:
659  * @scanner:        a #GScanner
660  * @expected_token: the expected token
661  * @nest_level:     the nest level
662  *
663  * Returns:
664  *
665  * Since: 2.4
666  **/
667 gboolean
gimp_config_deserialize_return(GScanner * scanner,GTokenType expected_token,gint nest_level)668 gimp_config_deserialize_return (GScanner     *scanner,
669                                 GTokenType    expected_token,
670                                 gint          nest_level)
671 {
672   GTokenType next_token;
673 
674   g_return_val_if_fail (scanner != NULL, FALSE);
675 
676   next_token = g_scanner_peek_next_token (scanner);
677 
678   if (expected_token != G_TOKEN_LEFT_PAREN)
679     {
680       g_scanner_get_next_token (scanner);
681       g_scanner_unexp_token (scanner, expected_token, NULL, NULL, NULL,
682                              _("fatal parse error"), TRUE);
683       return FALSE;
684     }
685   else
686     {
687       if (nest_level > 0 && next_token == G_TOKEN_RIGHT_PAREN)
688         {
689           return TRUE;
690         }
691       else if (next_token != G_TOKEN_EOF)
692         {
693           g_scanner_get_next_token (scanner);
694           g_scanner_unexp_token (scanner, expected_token, NULL, NULL, NULL,
695                                  _("fatal parse error"), TRUE);
696           return FALSE;
697         }
698     }
699 
700   return TRUE;
701 }
702 
703 
704 /**
705  * gimp_config_serialize:
706  * @config: a #GObject that implements the #GimpConfigInterface.
707  * @writer: the #GimpConfigWriter to use.
708  * @data: client data
709  *
710  * Serialize the #GimpConfig object.
711  *
712  * Returns: %TRUE if serialization succeeded, %FALSE otherwise.
713  *
714  * Since: 2.8
715  **/
716 gboolean
gimp_config_serialize(GimpConfig * config,GimpConfigWriter * writer,gpointer data)717 gimp_config_serialize (GimpConfig       *config,
718                        GimpConfigWriter *writer,
719                        gpointer          data)
720 {
721   g_return_val_if_fail (GIMP_IS_CONFIG (config), FALSE);
722 
723   return GIMP_CONFIG_GET_INTERFACE (config)->serialize (config,
724                                                         writer,
725                                                         data);
726 }
727 
728 /**
729  * gimp_config_deserialize:
730  * @config: a #GObject that implements the #GimpConfigInterface.
731  * @scanner: the #GScanner to use.
732  * @nest_level: the nest level.
733  * @data: client data.
734  *
735  * Deserialize the #GimpConfig object.
736  *
737  * Returns: %TRUE if deserialization succeeded, %FALSE otherwise.
738  *
739  * Since: 2.8
740  **/
741 gboolean
gimp_config_deserialize(GimpConfig * config,GScanner * scanner,gint nest_level,gpointer data)742 gimp_config_deserialize (GimpConfig *config,
743                          GScanner   *scanner,
744                          gint        nest_level,
745                          gpointer    data)
746 {
747   g_return_val_if_fail (GIMP_IS_CONFIG (config), FALSE);
748 
749   return GIMP_CONFIG_GET_INTERFACE (config)->deserialize (config,
750                                                           scanner,
751                                                           nest_level,
752                                                           data);
753 }
754 
755 /**
756  * gimp_config_duplicate:
757  * @config: a #GObject that implements the #GimpConfigInterface.
758  *
759  * Creates a copy of the passed object by copying all object
760  * properties. The default implementation of the #GimpConfigInterface
761  * only works for objects that are completely defined by their
762  * properties.
763  *
764  * Return value: the duplicated #GimpConfig object
765  *
766  * Since: 2.4
767  **/
768 gpointer
gimp_config_duplicate(GimpConfig * config)769 gimp_config_duplicate (GimpConfig *config)
770 {
771   g_return_val_if_fail (GIMP_IS_CONFIG (config), NULL);
772 
773   return GIMP_CONFIG_GET_INTERFACE (config)->duplicate (config);
774 }
775 
776 /**
777  * gimp_config_is_equal_to:
778  * @a: a #GObject that implements the #GimpConfigInterface.
779  * @b: another #GObject of the same type as @a.
780  *
781  * Compares the two objects. The default implementation of the
782  * #GimpConfigInterface compares the object properties and thus only
783  * works for objects that are completely defined by their
784  * properties.
785  *
786  * Return value: %TRUE if the two objects are equal.
787  *
788  * Since: 2.4
789  **/
790 gboolean
gimp_config_is_equal_to(GimpConfig * a,GimpConfig * b)791 gimp_config_is_equal_to (GimpConfig *a,
792                          GimpConfig *b)
793 {
794   g_return_val_if_fail (GIMP_IS_CONFIG (a), FALSE);
795   g_return_val_if_fail (GIMP_IS_CONFIG (b), FALSE);
796   g_return_val_if_fail (G_TYPE_FROM_INSTANCE (a) == G_TYPE_FROM_INSTANCE (b),
797                         FALSE);
798 
799   return GIMP_CONFIG_GET_INTERFACE (a)->equal (a, b);
800 }
801 
802 /**
803  * gimp_config_reset:
804  * @config: a #GObject that implements the #GimpConfigInterface.
805  *
806  * Resets the object to its default state. The default implementation of the
807  * #GimpConfigInterface only works for objects that are completely defined by
808  * their properties.
809  *
810  * Since: 2.4
811  **/
812 void
gimp_config_reset(GimpConfig * config)813 gimp_config_reset (GimpConfig *config)
814 {
815   g_return_if_fail (GIMP_IS_CONFIG (config));
816 
817   g_object_freeze_notify (G_OBJECT (config));
818 
819   GIMP_CONFIG_GET_INTERFACE (config)->reset (config);
820 
821   g_object_thaw_notify (G_OBJECT (config));
822 }
823 
824 /**
825  * gimp_config_copy:
826  * @src: a #GObject that implements the #GimpConfigInterface.
827  * @dest: another #GObject of the same type as @a.
828  * @flags: a mask of GParamFlags
829  *
830  * Compares all read- and write-able properties from @src and @dest
831  * that have all @flags set. Differing values are then copied from
832  * @src to @dest. If @flags is 0, all differing read/write properties.
833  *
834  * Properties marked as "construct-only" are not touched.
835  *
836  * Return value: %TRUE if @dest was modified, %FALSE otherwise
837  *
838  * Since: 2.6
839  **/
840 gboolean
gimp_config_copy(GimpConfig * src,GimpConfig * dest,GParamFlags flags)841 gimp_config_copy (GimpConfig  *src,
842                   GimpConfig  *dest,
843                   GParamFlags  flags)
844 {
845   gboolean changed;
846 
847   g_return_val_if_fail (GIMP_IS_CONFIG (src), FALSE);
848   g_return_val_if_fail (GIMP_IS_CONFIG (dest), FALSE);
849   g_return_val_if_fail (G_TYPE_FROM_INSTANCE (src) == G_TYPE_FROM_INSTANCE (dest),
850                         FALSE);
851 
852   g_object_freeze_notify (G_OBJECT (dest));
853 
854   changed = GIMP_CONFIG_GET_INTERFACE (src)->copy (src, dest, flags);
855 
856   g_object_thaw_notify (G_OBJECT (dest));
857 
858   return changed;
859 }
860