1 /* LIBGIMP - The GIMP Library
2  * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
3  *
4  * Object properties deserialization routines
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 <cairo.h>
25 #include <gegl.h>
26 #include <gdk-pixbuf/gdk-pixbuf.h>
27 
28 #include "libgimpbase/gimpbase.h"
29 #include "libgimpcolor/gimpcolor.h"
30 #include "libgimpmath/gimpmath.h"
31 
32 #include "gimpconfigtypes.h"
33 
34 #include "gimpconfigwriter.h"
35 #include "gimpconfig-iface.h"
36 #include "gimpconfig-deserialize.h"
37 #include "gimpconfig-params.h"
38 #include "gimpconfig-path.h"
39 #include "gimpscanner.h"
40 
41 #include "libgimp/libgimp-intl.h"
42 
43 
44 /**
45  * SECTION: gimpconfig-deserialize
46  * @title: GimpConfig-deserialize
47  * @short_description: Deserializing code for libgimpconfig.
48  *
49  * Deserializing code for libgimpconfig.
50  **/
51 
52 
53 /*
54  *  All functions return G_TOKEN_RIGHT_PAREN on success,
55  *  the GTokenType they would have expected but didn't get
56  *  or G_TOKEN_NONE if they got the expected token but
57  *  couldn't parse it.
58  */
59 
60 static GTokenType  gimp_config_deserialize_value       (GValue     *value,
61                                                         GimpConfig *config,
62                                                         GParamSpec *prop_spec,
63                                                         GScanner   *scanner);
64 static GTokenType  gimp_config_deserialize_fundamental (GValue     *value,
65                                                         GParamSpec *prop_spec,
66                                                         GScanner   *scanner);
67 static GTokenType  gimp_config_deserialize_enum        (GValue     *value,
68                                                         GParamSpec *prop_spec,
69                                                         GScanner   *scanner);
70 static GTokenType  gimp_config_deserialize_memsize     (GValue     *value,
71                                                         GParamSpec *prop_spec,
72                                                         GScanner   *scanner);
73 static GTokenType  gimp_config_deserialize_path        (GValue     *value,
74                                                         GParamSpec *prop_spec,
75                                                         GScanner   *scanner);
76 static GTokenType  gimp_config_deserialize_rgb         (GValue     *value,
77                                                         GParamSpec *prop_spec,
78                                                         GScanner   *scanner);
79 static GTokenType  gimp_config_deserialize_matrix2     (GValue     *value,
80                                                         GParamSpec *prop_spec,
81                                                         GScanner   *scanner);
82 static GTokenType  gimp_config_deserialize_object      (GValue     *value,
83                                                         GimpConfig *config,
84                                                         GParamSpec *prop_spec,
85                                                         GScanner   *scanner,
86                                                         gint        nest_level);
87 static GTokenType  gimp_config_deserialize_value_array (GValue     *value,
88                                                         GimpConfig *config,
89                                                         GParamSpec *prop_spec,
90                                                         GScanner   *scanner);
91 static GTokenType  gimp_config_deserialize_unit        (GValue     *value,
92                                                         GParamSpec *prop_spec,
93                                                         GScanner   *scanner);
94 static GTokenType  gimp_config_deserialize_file_value  (GValue     *value,
95                                                         GParamSpec *prop_spec,
96                                                         GScanner   *scanner);
97 static GTokenType  gimp_config_deserialize_any         (GValue     *value,
98                                                         GParamSpec *prop_spec,
99                                                         GScanner   *scanner);
100 static GTokenType  gimp_config_skip_unknown_property   (GScanner   *scanner);
101 
102 static inline gboolean  scanner_string_utf8_valid (GScanner    *scanner,
103                                                    const gchar *token_name);
104 
105 static inline gboolean
scanner_string_utf8_valid(GScanner * scanner,const gchar * token_name)106 scanner_string_utf8_valid (GScanner    *scanner,
107                            const gchar *token_name)
108 {
109   if (g_utf8_validate (scanner->value.v_string, -1, NULL))
110     return TRUE;
111 
112   g_scanner_error (scanner,
113                    _("value for token %s is not a valid UTF-8 string"),
114                    token_name);
115 
116   return FALSE;
117 }
118 
119 /**
120  * gimp_config_deserialize_properties:
121  * @config: a #GimpConfig.
122  * @scanner: a #GScanner.
123  * @nest_level: the nest level
124  *
125  * This function uses the @scanner to configure the properties of @config.
126  *
127  * Return value: %TRUE on success, %FALSE otherwise.
128  *
129  * Since: 2.4
130  **/
131 gboolean
gimp_config_deserialize_properties(GimpConfig * config,GScanner * scanner,gint nest_level)132 gimp_config_deserialize_properties (GimpConfig *config,
133                                     GScanner   *scanner,
134                                     gint        nest_level)
135 {
136   GObjectClass  *klass;
137   GParamSpec   **property_specs;
138   guint          n_property_specs;
139   guint          i;
140   guint          scope_id;
141   guint          old_scope_id;
142   GTokenType     token;
143 
144   g_return_val_if_fail (GIMP_IS_CONFIG (config), FALSE);
145 
146   klass = G_OBJECT_GET_CLASS (config);
147   property_specs = g_object_class_list_properties (klass, &n_property_specs);
148 
149   if (! property_specs)
150     return TRUE;
151 
152   scope_id = g_type_qname (G_TYPE_FROM_INSTANCE (config));
153   old_scope_id = g_scanner_set_scope (scanner, scope_id);
154 
155   for (i = 0; i < n_property_specs; i++)
156     {
157       GParamSpec *prop_spec = property_specs[i];
158 
159       if (prop_spec->flags & GIMP_CONFIG_PARAM_SERIALIZE)
160         {
161           g_scanner_scope_add_symbol (scanner, scope_id,
162                                       prop_spec->name, prop_spec);
163         }
164     }
165 
166   g_free (property_specs);
167 
168   g_object_freeze_notify (G_OBJECT (config));
169 
170   token = G_TOKEN_LEFT_PAREN;
171 
172   while (TRUE)
173     {
174       GTokenType next = g_scanner_peek_next_token (scanner);
175 
176       if (next == G_TOKEN_EOF)
177         break;
178 
179       if (G_UNLIKELY (next != token &&
180                       ! (token == G_TOKEN_SYMBOL &&
181                          next  == G_TOKEN_IDENTIFIER)))
182         {
183           break;
184         }
185 
186       token = g_scanner_get_next_token (scanner);
187 
188       switch (token)
189         {
190         case G_TOKEN_LEFT_PAREN:
191           token = G_TOKEN_SYMBOL;
192           break;
193 
194         case G_TOKEN_IDENTIFIER:
195           token = gimp_config_skip_unknown_property (scanner);
196           break;
197 
198         case G_TOKEN_SYMBOL:
199           token = gimp_config_deserialize_property (config,
200                                                     scanner, nest_level);
201           break;
202 
203         case G_TOKEN_RIGHT_PAREN:
204           token = G_TOKEN_LEFT_PAREN;
205           break;
206 
207         default: /* do nothing */
208           break;
209         }
210     }
211 
212   g_scanner_set_scope (scanner, old_scope_id);
213 
214   g_object_thaw_notify (G_OBJECT (config));
215 
216   if (token == G_TOKEN_NONE)
217     return FALSE;
218 
219   return gimp_config_deserialize_return (scanner, token, nest_level);
220 }
221 
222 /**
223  * gimp_config_deserialize_property:
224  * @config: a #GimpConfig.
225  * @scanner: a #GScanner.
226  * @nest_level: the nest level
227  *
228  * This function deserializes a single property of @config. You
229  * shouldn't need to call this function directly. If possible, use
230  * gimp_config_deserialize_properties() instead.
231  *
232  * Return value: %G_TOKEN_RIGHT_PAREN on success, otherwise the
233  * expected #GTokenType or %G_TOKEN_NONE if the expected token was
234  * found but couldn't be parsed.
235  *
236  * Since: 2.4
237  **/
238 GTokenType
gimp_config_deserialize_property(GimpConfig * config,GScanner * scanner,gint nest_level)239 gimp_config_deserialize_property (GimpConfig *config,
240                                   GScanner   *scanner,
241                                   gint        nest_level)
242 {
243   GimpConfigInterface *config_iface = NULL;
244   GimpConfigInterface *parent_iface = NULL;
245   GParamSpec          *prop_spec;
246   GTokenType           token        = G_TOKEN_RIGHT_PAREN;
247   GValue               value        = G_VALUE_INIT;
248   guint                old_scope_id;
249 
250   old_scope_id = g_scanner_set_scope (scanner, 0);
251 
252   prop_spec = G_PARAM_SPEC (scanner->value.v_symbol);
253 
254   g_value_init (&value, prop_spec->value_type);
255 
256   if (G_TYPE_IS_OBJECT (prop_spec->owner_type))
257     {
258       GTypeClass *owner_class = g_type_class_peek (prop_spec->owner_type);
259 
260       config_iface = g_type_interface_peek (owner_class, GIMP_TYPE_CONFIG);
261 
262       /*  We must call deserialize_property() *only* if the *exact* class
263        *  which implements it is param_spec->owner_type's class.
264        *
265        *  Therefore, we ask param_spec->owner_type's immediate parent class
266        *  for it's GimpConfigInterface and check if we get a different
267        *  pointer.
268        *
269        *  (if the pointers are the same, param_spec->owner_type's
270        *   GimpConfigInterface is inherited from one of it's parent classes
271        *   and thus not able to handle param_spec->owner_type's properties).
272        */
273       if (config_iface)
274         {
275           GTypeClass *owner_parent_class;
276 
277           owner_parent_class = g_type_class_peek_parent (owner_class);
278 
279           parent_iface = g_type_interface_peek (owner_parent_class,
280                                                 GIMP_TYPE_CONFIG);
281         }
282     }
283 
284   if (config_iface                       &&
285       config_iface != parent_iface       && /* see comment above */
286       config_iface->deserialize_property &&
287       config_iface->deserialize_property (config,
288                                           prop_spec->param_id,
289                                           &value,
290                                           prop_spec,
291                                           scanner,
292                                           &token))
293     {
294       /* nop */
295     }
296   else
297     {
298       if (G_VALUE_HOLDS_OBJECT (&value) &&
299           G_VALUE_TYPE (&value) != G_TYPE_FILE)
300         {
301           token = gimp_config_deserialize_object (&value,
302                                                   config, prop_spec,
303                                                   scanner, nest_level);
304         }
305       else
306         {
307           token = gimp_config_deserialize_value (&value,
308                                                  config, prop_spec, scanner);
309         }
310     }
311 
312   if (token == G_TOKEN_RIGHT_PAREN &&
313       g_scanner_peek_next_token (scanner) == token)
314     {
315       if (! (G_VALUE_HOLDS_OBJECT (&value) &&
316              (prop_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE)))
317         g_object_set_property (G_OBJECT (config), prop_spec->name, &value);
318     }
319 #ifdef CONFIG_DEBUG
320   else
321     {
322       g_warning ("%s: couldn't deserialize property %s::%s of type %s",
323                  G_STRFUNC,
324                  g_type_name (G_TYPE_FROM_INSTANCE (config)),
325                  prop_spec->name,
326                  g_type_name (prop_spec->value_type));
327     }
328 #endif
329 
330   g_value_unset (&value);
331 
332   g_scanner_set_scope (scanner, old_scope_id);
333 
334   return token;
335 }
336 
337 static GTokenType
gimp_config_deserialize_value(GValue * value,GimpConfig * config,GParamSpec * prop_spec,GScanner * scanner)338 gimp_config_deserialize_value (GValue     *value,
339                                GimpConfig *config,
340                                GParamSpec *prop_spec,
341                                GScanner   *scanner)
342 {
343   if (G_TYPE_FUNDAMENTAL (prop_spec->value_type) == G_TYPE_ENUM)
344     {
345       return gimp_config_deserialize_enum (value, prop_spec, scanner);
346     }
347   else if (G_TYPE_IS_FUNDAMENTAL (prop_spec->value_type))
348     {
349       return gimp_config_deserialize_fundamental (value, prop_spec, scanner);
350     }
351   else if (prop_spec->value_type == GIMP_TYPE_MEMSIZE)
352     {
353       return gimp_config_deserialize_memsize (value, prop_spec, scanner);
354     }
355   else if (prop_spec->value_type == GIMP_TYPE_CONFIG_PATH)
356     {
357       return  gimp_config_deserialize_path (value, prop_spec, scanner);
358     }
359   else if (prop_spec->value_type == GIMP_TYPE_RGB)
360     {
361       return gimp_config_deserialize_rgb (value, prop_spec, scanner);
362     }
363   else if (prop_spec->value_type == GIMP_TYPE_MATRIX2)
364     {
365       return gimp_config_deserialize_matrix2 (value, prop_spec, scanner);
366     }
367   else if (prop_spec->value_type == GIMP_TYPE_VALUE_ARRAY)
368     {
369       return gimp_config_deserialize_value_array (value,
370                                                   config, prop_spec, scanner);
371     }
372   else if (prop_spec->value_type == GIMP_TYPE_UNIT)
373     {
374       return gimp_config_deserialize_unit (value, prop_spec, scanner);
375     }
376   else if (prop_spec->value_type == G_TYPE_FILE)
377     {
378       return gimp_config_deserialize_file_value (value, prop_spec, scanner);
379     }
380 
381   /*  This fallback will only work for value_types that
382    *  can be transformed from a string value.
383    */
384   return gimp_config_deserialize_any (value, prop_spec, scanner);
385 }
386 
387 static GTokenType
gimp_config_deserialize_fundamental(GValue * value,GParamSpec * prop_spec,GScanner * scanner)388 gimp_config_deserialize_fundamental (GValue     *value,
389                                      GParamSpec *prop_spec,
390                                      GScanner   *scanner)
391 {
392   GTokenType token;
393   GTokenType next_token;
394   GType      value_type;
395   gboolean   negate = FALSE;
396 
397   value_type = G_TYPE_FUNDAMENTAL (prop_spec->value_type);
398 
399   switch (value_type)
400     {
401     case G_TYPE_STRING:
402       token = G_TOKEN_STRING;
403       break;
404 
405     case G_TYPE_BOOLEAN:
406       token = G_TOKEN_IDENTIFIER;
407       break;
408 
409     case G_TYPE_INT:
410     case G_TYPE_LONG:
411     case G_TYPE_INT64:
412       if (g_scanner_peek_next_token (scanner) == '-')
413         {
414           negate = TRUE;
415           g_scanner_get_next_token (scanner);
416         }
417       /*  fallthrough  */
418     case G_TYPE_UINT:
419     case G_TYPE_ULONG:
420     case G_TYPE_UINT64:
421       token = G_TOKEN_INT;
422       break;
423 
424     case G_TYPE_FLOAT:
425     case G_TYPE_DOUBLE:
426       if (g_scanner_peek_next_token (scanner) == '-')
427         {
428           negate = TRUE;
429           g_scanner_get_next_token (scanner);
430         }
431       token = G_TOKEN_FLOAT;
432       break;
433 
434     default:
435       g_assert_not_reached ();
436       break;
437     }
438 
439   next_token = g_scanner_peek_next_token (scanner);
440 
441   /* we parse integers into floats too, because g_ascii_dtostr()
442    * serialized whole number without decimal point
443    */
444   if (next_token != token &&
445       ! (token == G_TOKEN_FLOAT && next_token == G_TOKEN_INT))
446     {
447       return token;
448     }
449 
450   g_scanner_get_next_token (scanner);
451 
452   switch (value_type)
453     {
454     case G_TYPE_STRING:
455       if (scanner_string_utf8_valid (scanner, prop_spec->name))
456         g_value_set_string (value, scanner->value.v_string);
457       else
458         return G_TOKEN_NONE;
459       break;
460 
461     case G_TYPE_BOOLEAN:
462       if (! g_ascii_strcasecmp (scanner->value.v_identifier, "yes") ||
463           ! g_ascii_strcasecmp (scanner->value.v_identifier, "true"))
464         g_value_set_boolean (value, TRUE);
465       else if (! g_ascii_strcasecmp (scanner->value.v_identifier, "no") ||
466                ! g_ascii_strcasecmp (scanner->value.v_identifier, "false"))
467         g_value_set_boolean (value, FALSE);
468       else
469         {
470           g_scanner_error
471             (scanner,
472              /* please don't translate 'yes' and 'no' */
473              _("expected 'yes' or 'no' for boolean token %s, got '%s'"),
474              prop_spec->name, scanner->value.v_identifier);
475           return G_TOKEN_NONE;
476         }
477       break;
478 
479     case G_TYPE_INT:
480       g_value_set_int (value, (negate ?
481                                - (gint) scanner->value.v_int64 :
482                                  (gint) scanner->value.v_int64));
483       break;
484     case G_TYPE_UINT:
485       g_value_set_uint (value, scanner->value.v_int64);
486       break;
487 
488     case G_TYPE_LONG:
489       g_value_set_long (value, (negate ?
490                                 - (glong) scanner->value.v_int64 :
491                                   (glong) scanner->value.v_int64));
492       break;
493     case G_TYPE_ULONG:
494       g_value_set_ulong (value, scanner->value.v_int64);
495       break;
496 
497     case G_TYPE_INT64:
498       g_value_set_int64 (value, (negate ?
499                                  - (gint64) scanner->value.v_int64 :
500                                    (gint64) scanner->value.v_int64));
501       break;
502     case G_TYPE_UINT64:
503       g_value_set_uint64 (value, scanner->value.v_int64);
504       break;
505 
506     case G_TYPE_FLOAT:
507       if (next_token == G_TOKEN_FLOAT)
508         g_value_set_float (value, negate ?
509                            - scanner->value.v_float :
510                              scanner->value.v_float);
511       else
512         g_value_set_float (value, negate ?
513                            - (gfloat) scanner->value.v_int :
514                              (gfloat) scanner->value.v_int);
515       break;
516 
517     case G_TYPE_DOUBLE:
518       if (next_token == G_TOKEN_FLOAT)
519         g_value_set_double (value, negate ?
520                             - scanner->value.v_float:
521                               scanner->value.v_float);
522       else
523         g_value_set_double (value, negate ?
524                             - (gdouble) scanner->value.v_int:
525                               (gdouble) scanner->value.v_int);
526       break;
527 
528     default:
529       g_assert_not_reached ();
530       break;
531     }
532 
533   return G_TOKEN_RIGHT_PAREN;
534 }
535 
536 static GTokenType
gimp_config_deserialize_enum(GValue * value,GParamSpec * prop_spec,GScanner * scanner)537 gimp_config_deserialize_enum (GValue     *value,
538                               GParamSpec *prop_spec,
539                               GScanner   *scanner)
540 {
541   GEnumClass *enum_class;
542   GEnumValue *enum_value;
543 
544   enum_class = g_type_class_peek (G_VALUE_TYPE (value));
545 
546   switch (g_scanner_peek_next_token (scanner))
547     {
548     case G_TOKEN_IDENTIFIER:
549       g_scanner_get_next_token (scanner);
550 
551       enum_value = g_enum_get_value_by_nick (enum_class,
552                                              scanner->value.v_identifier);
553       if (! enum_value)
554         enum_value = g_enum_get_value_by_name (enum_class,
555                                                scanner->value.v_identifier);
556       if (! enum_value)
557         {
558           /*  if the value was not found, check if we have a compat
559            *  enum to find the ideitifier
560            */
561           GQuark quark       = g_quark_from_static_string ("gimp-compat-enum");
562           GType  compat_type = (GType) g_type_get_qdata (G_VALUE_TYPE (value),
563                                                          quark);
564 
565           if (compat_type)
566             {
567               GEnumClass *compat_class = g_type_class_ref (compat_type);
568 
569               enum_value = g_enum_get_value_by_nick (compat_class,
570                                                      scanner->value.v_identifier);
571               if (! enum_value)
572                 enum_value = g_enum_get_value_by_name (compat_class,
573                                                        scanner->value.v_identifier);
574 
575               /*  finally, if we found a compat value, make sure the
576                *  same value exists in the original enum
577                */
578               if (enum_value)
579                 enum_value = g_enum_get_value (enum_class, enum_value->value);
580 
581               g_type_class_unref (compat_class);
582            }
583         }
584 
585       if (! enum_value)
586         {
587           g_scanner_error (scanner,
588                            _("invalid value '%s' for token %s"),
589                            scanner->value.v_identifier, prop_spec->name);
590           return G_TOKEN_NONE;
591         }
592       break;
593 
594     case G_TOKEN_INT:
595       g_scanner_get_next_token (scanner);
596 
597       enum_value = g_enum_get_value (enum_class,
598                                      (gint) scanner->value.v_int64);
599 
600       if (! enum_value)
601         {
602           g_scanner_error (scanner,
603                            _("invalid value '%ld' for token %s"),
604                            (glong) scanner->value.v_int64, prop_spec->name);
605           return G_TOKEN_NONE;
606         }
607       break;
608 
609     default:
610       return G_TOKEN_IDENTIFIER;
611     }
612 
613   g_value_set_enum (value, enum_value->value);
614 
615   return G_TOKEN_RIGHT_PAREN;
616 }
617 
618 static GTokenType
gimp_config_deserialize_memsize(GValue * value,GParamSpec * prop_spec,GScanner * scanner)619 gimp_config_deserialize_memsize (GValue     *value,
620                                  GParamSpec *prop_spec,
621                                  GScanner   *scanner)
622 {
623   gchar   *orig_cset_first = scanner->config->cset_identifier_first;
624   gchar   *orig_cset_nth   = scanner->config->cset_identifier_nth;
625   guint64  memsize;
626 
627   scanner->config->cset_identifier_first = G_CSET_DIGITS;
628   scanner->config->cset_identifier_nth   = G_CSET_DIGITS "gGmMkKbB";
629 
630   if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER)
631     return G_TOKEN_IDENTIFIER;
632 
633   g_scanner_get_next_token (scanner);
634 
635   scanner->config->cset_identifier_first = orig_cset_first;
636   scanner->config->cset_identifier_nth   = orig_cset_nth;
637 
638   if (! gimp_memsize_deserialize (scanner->value.v_identifier, &memsize))
639     return G_TOKEN_NONE;
640 
641   g_value_set_uint64 (value, memsize);
642 
643   return G_TOKEN_RIGHT_PAREN;
644 }
645 
646 static GTokenType
gimp_config_deserialize_path(GValue * value,GParamSpec * prop_spec,GScanner * scanner)647 gimp_config_deserialize_path (GValue     *value,
648                               GParamSpec *prop_spec,
649                               GScanner   *scanner)
650 {
651   GError *error = NULL;
652 
653   if (g_scanner_peek_next_token (scanner) != G_TOKEN_STRING)
654     return G_TOKEN_STRING;
655 
656   g_scanner_get_next_token (scanner);
657 
658   if (!scanner_string_utf8_valid (scanner, prop_spec->name))
659     return G_TOKEN_NONE;
660 
661   if (scanner->value.v_string)
662     {
663       /*  Check if the string can be expanded
664        *  and converted to the filesystem encoding.
665        */
666       gchar *expand = gimp_config_path_expand (scanner->value.v_string,
667                                                TRUE, &error);
668 
669       if (!expand)
670         {
671           g_scanner_error (scanner,
672                            _("while parsing token '%s': %s"),
673                            prop_spec->name, error->message);
674           g_error_free (error);
675 
676           return G_TOKEN_NONE;
677         }
678 
679       g_free (expand);
680 
681       g_value_set_static_string (value, scanner->value.v_string);
682     }
683 
684   return G_TOKEN_RIGHT_PAREN;
685 }
686 
687 static GTokenType
gimp_config_deserialize_rgb(GValue * value,GParamSpec * prop_spec,GScanner * scanner)688 gimp_config_deserialize_rgb (GValue     *value,
689                              GParamSpec *prop_spec,
690                              GScanner   *scanner)
691 {
692   GimpRGB rgb;
693 
694   if (! gimp_scanner_parse_color (scanner, &rgb))
695     return G_TOKEN_NONE;
696 
697   g_value_set_boxed (value, &rgb);
698 
699   return G_TOKEN_RIGHT_PAREN;
700 }
701 
702 static GTokenType
gimp_config_deserialize_matrix2(GValue * value,GParamSpec * prop_spec,GScanner * scanner)703 gimp_config_deserialize_matrix2 (GValue     *value,
704                                  GParamSpec *prop_spec,
705                                  GScanner   *scanner)
706 {
707   GimpMatrix2 matrix;
708 
709   if (! gimp_scanner_parse_matrix2 (scanner, &matrix))
710     return G_TOKEN_NONE;
711 
712   g_value_set_boxed (value, &matrix);
713 
714   return G_TOKEN_RIGHT_PAREN;
715 }
716 
717 static GTokenType
gimp_config_deserialize_object(GValue * value,GimpConfig * config,GParamSpec * prop_spec,GScanner * scanner,gint nest_level)718 gimp_config_deserialize_object (GValue     *value,
719                                 GimpConfig *config,
720                                 GParamSpec *prop_spec,
721                                 GScanner   *scanner,
722                                 gint        nest_level)
723 {
724   GimpConfigInterface *config_iface;
725   GimpConfig          *prop_object;
726 
727   g_object_get_property (G_OBJECT (config), prop_spec->name, value);
728 
729   prop_object = g_value_get_object (value);
730 
731   if (! prop_object)
732     {
733       /*  if the object property is not GIMP_CONFIG_PARAM_AGGREGATE, read
734        *  the type of the object and create it
735        */
736       if (! (prop_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE))
737         {
738           gchar *type_name;
739           GType  type;
740 
741           if (! gimp_scanner_parse_string (scanner, &type_name))
742             return G_TOKEN_STRING;
743 
744           if (! (type_name && *type_name))
745             {
746               g_scanner_error (scanner, "Type name is empty");
747               g_free (type_name);
748               return G_TOKEN_NONE;
749             }
750 
751           type = g_type_from_name (type_name);
752           g_free (type_name);
753 
754           if (! g_type_is_a (type, prop_spec->value_type))
755             return G_TOKEN_STRING;
756 
757           prop_object = g_object_new (type, NULL);
758 
759           g_value_take_object (value, prop_object);
760         }
761       else
762         {
763           return G_TOKEN_RIGHT_PAREN;
764         }
765     }
766 
767   config_iface = GIMP_CONFIG_GET_INTERFACE (prop_object);
768 
769   if (! config_iface)
770     return gimp_config_deserialize_any (value, prop_spec, scanner);
771 
772   if (! config_iface->deserialize (prop_object, scanner, nest_level + 1, NULL))
773     return G_TOKEN_NONE;
774 
775   return G_TOKEN_RIGHT_PAREN;
776 }
777 
778 static GTokenType
gimp_config_deserialize_value_array(GValue * value,GimpConfig * config,GParamSpec * prop_spec,GScanner * scanner)779 gimp_config_deserialize_value_array (GValue     *value,
780                                      GimpConfig *config,
781                                      GParamSpec *prop_spec,
782                                      GScanner   *scanner)
783 {
784   GimpParamSpecValueArray *array_spec;
785   GimpValueArray          *array;
786   GValue                   array_value = G_VALUE_INIT;
787   gint                     n_values;
788   GTokenType               token;
789   gint                     i;
790 
791   array_spec = GIMP_PARAM_SPEC_VALUE_ARRAY (prop_spec);
792 
793   if (! gimp_scanner_parse_int (scanner, &n_values))
794     return G_TOKEN_INT;
795 
796   array = gimp_value_array_new (n_values);
797 
798   for (i = 0; i < n_values; i++)
799     {
800       g_value_init (&array_value, array_spec->element_spec->value_type);
801 
802       token = gimp_config_deserialize_value (&array_value,
803                                              config,
804                                              array_spec->element_spec,
805                                              scanner);
806 
807       if (token == G_TOKEN_RIGHT_PAREN)
808         gimp_value_array_append (array, &array_value);
809 
810       g_value_unset (&array_value);
811 
812       if (token != G_TOKEN_RIGHT_PAREN)
813         return token;
814     }
815 
816   g_value_take_boxed (value, array);
817 
818   return G_TOKEN_RIGHT_PAREN;
819 }
820 
821 /* This function is entirely sick, so is our method of serializing
822  * units, which we write out as (unit foo bar) instead of
823  * (unit "foo bar"). The assumption that caused this shit was that a
824  * unit's "identifier" is really an identifier in the C-ish sense,
825  * when in fact it's just a random user entered string.
826  *
827  * Here, we try to parse at least the default units shipped with gimp,
828  * and we add code to parse (unit "foo bar") in order to be compatible
829  * with future correct unit serializing.
830  */
831 static GTokenType
gimp_config_deserialize_unit(GValue * value,GParamSpec * prop_spec,GScanner * scanner)832 gimp_config_deserialize_unit (GValue     *value,
833                               GParamSpec *prop_spec,
834                               GScanner   *scanner)
835 {
836   gchar      *old_cset_skip_characters;
837   gchar      *old_cset_identifier_first;
838   gchar      *old_cset_identifier_nth;
839   GString    *buffer;
840   GValue      src = G_VALUE_INIT;
841   GTokenType  token;
842 
843   /* parse the next token *before* reconfiguring the scanner, so it
844    * skips whitespace first
845    */
846   token = g_scanner_peek_next_token (scanner);
847 
848   if (token == G_TOKEN_STRING)
849     return gimp_config_deserialize_any (value, prop_spec, scanner);
850 
851   old_cset_skip_characters  = scanner->config->cset_skip_characters;
852   old_cset_identifier_first = scanner->config->cset_identifier_first;
853   old_cset_identifier_nth   = scanner->config->cset_identifier_nth;
854 
855   scanner->config->cset_skip_characters  = "";
856   scanner->config->cset_identifier_first = ( G_CSET_a_2_z G_CSET_A_2_Z "." );
857   scanner->config->cset_identifier_nth   = ( G_CSET_a_2_z G_CSET_A_2_Z
858                                              G_CSET_DIGITS "-_." );
859 
860   buffer = g_string_new ("");
861 
862   while (g_scanner_peek_next_token (scanner) != G_TOKEN_RIGHT_PAREN)
863     {
864       token = g_scanner_peek_next_token (scanner);
865 
866       if (token == G_TOKEN_IDENTIFIER)
867         {
868           g_scanner_get_next_token (scanner);
869           g_string_append (buffer, scanner->value.v_identifier);
870         }
871       else if (token == G_TOKEN_CHAR)
872         {
873           g_scanner_get_next_token (scanner);
874           g_string_append_c (buffer, scanner->value.v_char);
875         }
876       else if (token == ' ')
877         {
878           g_scanner_get_next_token (scanner);
879           g_string_append_c (buffer, token);
880         }
881       else
882         {
883           token = G_TOKEN_IDENTIFIER;
884           goto cleanup;
885         }
886     }
887 
888   g_value_init (&src, G_TYPE_STRING);
889   g_value_set_static_string (&src, buffer->str);
890   g_value_transform (&src, value);
891   g_value_unset (&src);
892 
893   token = G_TOKEN_RIGHT_PAREN;
894 
895  cleanup:
896 
897   g_string_free (buffer, TRUE);
898 
899   scanner->config->cset_skip_characters  = old_cset_skip_characters;
900   scanner->config->cset_identifier_first = old_cset_identifier_first;
901   scanner->config->cset_identifier_nth   = old_cset_identifier_nth;
902 
903   return token;
904 }
905 
906 static GTokenType
gimp_config_deserialize_file_value(GValue * value,GParamSpec * prop_spec,GScanner * scanner)907 gimp_config_deserialize_file_value (GValue     *value,
908                                     GParamSpec *prop_spec,
909                                     GScanner   *scanner)
910 {
911   GTokenType token;
912 
913   token = g_scanner_peek_next_token (scanner);
914 
915   if (token != G_TOKEN_IDENTIFIER &&
916       token != G_TOKEN_STRING)
917     {
918       return G_TOKEN_STRING;
919     }
920 
921   g_scanner_get_next_token (scanner);
922 
923   if (token == G_TOKEN_IDENTIFIER)
924     {
925       /* this is supposed to parse a literal "NULL" only, but so what... */
926       g_value_set_object (value, NULL);
927     }
928   else
929     {
930       gchar *path = gimp_config_path_expand (scanner->value.v_string, TRUE,
931                                              NULL);
932 
933       if (path)
934         {
935           GFile *file = g_file_new_for_path (path);
936 
937           g_value_take_object (value, file);
938           g_free (path);
939         }
940       else
941         {
942           g_value_set_object (value, NULL);
943         }
944     }
945 
946   return G_TOKEN_RIGHT_PAREN;
947 }
948 
949 static GTokenType
gimp_config_deserialize_any(GValue * value,GParamSpec * prop_spec,GScanner * scanner)950 gimp_config_deserialize_any (GValue     *value,
951                              GParamSpec *prop_spec,
952                              GScanner   *scanner)
953 {
954   GValue     src = G_VALUE_INIT;
955   GTokenType token;
956 
957   if (!g_value_type_transformable (G_TYPE_STRING, prop_spec->value_type))
958     {
959       g_warning ("%s: %s can not be transformed from a string",
960                  G_STRFUNC, g_type_name (prop_spec->value_type));
961       return G_TOKEN_NONE;
962     }
963 
964   token = g_scanner_peek_next_token (scanner);
965 
966   if (token != G_TOKEN_IDENTIFIER &&
967       token != G_TOKEN_STRING)
968     {
969       return G_TOKEN_IDENTIFIER;
970     }
971 
972   g_scanner_get_next_token (scanner);
973 
974   g_value_init (&src, G_TYPE_STRING);
975 
976   if (token == G_TOKEN_IDENTIFIER)
977     g_value_set_static_string (&src, scanner->value.v_identifier);
978   else
979     g_value_set_static_string (&src, scanner->value.v_string);
980 
981   g_value_transform (&src, value);
982   g_value_unset (&src);
983 
984   return G_TOKEN_RIGHT_PAREN;
985 }
986 
987 static GTokenType
gimp_config_skip_unknown_property(GScanner * scanner)988 gimp_config_skip_unknown_property (GScanner *scanner)
989 {
990   gint open_paren = 0;
991 
992   while (TRUE)
993     {
994       GTokenType token = g_scanner_peek_next_token (scanner);
995 
996       switch (token)
997         {
998         case G_TOKEN_LEFT_PAREN:
999           open_paren++;
1000           g_scanner_get_next_token (scanner);
1001           break;
1002 
1003         case G_TOKEN_RIGHT_PAREN:
1004           if (open_paren == 0)
1005             return token;
1006 
1007           open_paren--;
1008           g_scanner_get_next_token (scanner);
1009           break;
1010 
1011         case G_TOKEN_EOF:
1012           return token;
1013 
1014         default:
1015           g_scanner_get_next_token (scanner);
1016           break;
1017         }
1018     }
1019 }
1020