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