1
/* LIBGIMP - The GIMP Library
2
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
4
* Object properties deserialization routines
5
* Copyright (C) 2001-2002 Sven Neumann <sven@gimp.org>
7
* This library is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2 of the License, or (at your option) any later version.
12
* This library is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Library General Public License for more details.
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this library; if not, write to the
19
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20
* Boston, MA 02111-1307, USA.
25
#include <glib-object.h>
27
#include "libgimpbase/gimpbase.h"
28
#include "libgimpcolor/gimpcolor.h"
29
#include "libgimpmath/gimpmath.h"
31
#include "gimpconfigtypes.h"
33
#include "gimpconfigwriter.h"
34
#include "gimpconfig-iface.h"
35
#include "gimpconfig-deserialize.h"
36
#include "gimpconfig-params.h"
37
#include "gimpconfig-path.h"
38
#include "gimpscanner.h"
40
#include "libgimp/libgimp-intl.h"
44
* All functions return G_TOKEN_RIGHT_PAREN on success,
45
* the GTokenType they would have expected but didn't get
46
* or G_TOKEN_NONE if they got the expected token but
50
static GTokenType gimp_config_deserialize_value (GValue *value,
52
GParamSpec *prop_spec,
54
static GTokenType gimp_config_deserialize_fundamental (GValue *value,
55
GParamSpec *prop_spec,
57
static GTokenType gimp_config_deserialize_enum (GValue *value,
58
GParamSpec *prop_spec,
60
static GTokenType gimp_config_deserialize_memsize (GValue *value,
61
GParamSpec *prop_spec,
63
static GTokenType gimp_config_deserialize_path (GValue *value,
64
GParamSpec *prop_spec,
66
static GTokenType gimp_config_deserialize_rgb (GValue *value,
67
GParamSpec *prop_spec,
69
static GTokenType gimp_config_deserialize_matrix2 (GValue *value,
70
GParamSpec *prop_spec,
72
static GTokenType gimp_config_deserialize_object (GValue *value,
74
GParamSpec *prop_spec,
77
static GTokenType gimp_config_deserialize_value_array (GValue *value,
79
GParamSpec *prop_spec,
81
static GTokenType gimp_config_deserialize_any (GValue *value,
82
GParamSpec *prop_spec,
85
static inline gboolean scanner_string_utf8_valid (GScanner *scanner,
86
const gchar *token_name);
88
static inline gboolean
89
scanner_string_utf8_valid (GScanner *scanner,
90
const gchar *token_name)
92
if (g_utf8_validate (scanner->value.v_string, -1, NULL))
95
g_scanner_error (scanner,
96
_("value for token %s is not a valid UTF-8 string"),
103
* gimp_config_deserialize_properties:
104
* @config: a #GimpConfig.
105
* @scanner: a #GScanner.
108
* This function uses the @scanner to configure the properties of @config.
110
* Return value: %TRUE on success, %FALSE otherwise.
115
gimp_config_deserialize_properties (GimpConfig *config,
120
GParamSpec **property_specs;
121
guint n_property_specs;
128
g_return_val_if_fail (GIMP_IS_CONFIG (config), FALSE);
130
klass = G_OBJECT_GET_CLASS (config);
131
property_specs = g_object_class_list_properties (klass, &n_property_specs);
136
scope_id = g_type_qname (G_TYPE_FROM_INSTANCE (config));
137
old_scope_id = g_scanner_set_scope (scanner, scope_id);
139
for (i = 0; i < n_property_specs; i++)
141
GParamSpec *prop_spec = property_specs[i];
143
if (prop_spec->flags & GIMP_CONFIG_PARAM_SERIALIZE)
145
g_scanner_scope_add_symbol (scanner, scope_id,
146
prop_spec->name, prop_spec);
150
g_free (property_specs);
152
g_object_freeze_notify (G_OBJECT (config));
154
token = G_TOKEN_LEFT_PAREN;
158
next = g_scanner_peek_next_token (scanner);
163
token = g_scanner_get_next_token (scanner);
167
case G_TOKEN_LEFT_PAREN:
168
token = G_TOKEN_SYMBOL;
172
token = gimp_config_deserialize_property (config,
173
scanner, nest_level);
176
case G_TOKEN_RIGHT_PAREN:
177
token = G_TOKEN_LEFT_PAREN;
180
default: /* do nothing */
185
g_scanner_set_scope (scanner, old_scope_id);
187
g_object_thaw_notify (G_OBJECT (config));
189
if (token == G_TOKEN_NONE)
192
return gimp_config_deserialize_return (scanner, token, nest_level);
196
* gimp_config_deserialize_property:
197
* @config: a #GimpConfig.
198
* @scanner: a #GScanner.
201
* This function deserializes a single property of @config. You
202
* shouldn't need to call this function directly. If possible, use
203
* gimp_config_deserialize_properties() instead.
205
* Return value: %G_TOKEN_RIGHT_PAREN on success, otherwise the
206
* expected #GTokenType or %G_TOKEN_NONE if the expected token was
207
* found but couldn't be parsed.
212
gimp_config_deserialize_property (GimpConfig *config,
216
GimpConfigInterface *config_iface = NULL;
217
GimpConfigInterface *parent_iface = NULL;
218
GParamSpec *prop_spec;
219
GTokenType token = G_TOKEN_RIGHT_PAREN;
220
GValue value = { 0, };
223
old_scope_id = g_scanner_set_scope (scanner, 0);
225
prop_spec = G_PARAM_SPEC (scanner->value.v_symbol);
227
g_value_init (&value, prop_spec->value_type);
229
if (G_TYPE_IS_OBJECT (prop_spec->owner_type))
231
GTypeClass *owner_class = g_type_class_peek (prop_spec->owner_type);
233
config_iface = g_type_interface_peek (owner_class, GIMP_TYPE_CONFIG);
235
/* We must call deserialize_property() *only* if the *exact* class
236
* which implements it is param_spec->owner_type's class.
238
* Therefore, we ask param_spec->owner_type's immediate parent class
239
* for it's GimpConfigInterface and check if we get a different
242
* (if the pointers are the same, param_spec->owner_type's
243
* GimpConfigInterface is inherited from one of it's parent classes
244
* and thus not able to handle param_spec->owner_type's properties).
248
GTypeClass *owner_parent_class;
250
owner_parent_class = g_type_class_peek_parent (owner_class);
252
parent_iface = g_type_interface_peek (owner_parent_class,
258
config_iface != parent_iface && /* see comment above */
259
config_iface->deserialize_property &&
260
config_iface->deserialize_property (config,
271
if (G_VALUE_HOLDS_OBJECT (&value))
272
token = gimp_config_deserialize_object (&value,
274
scanner, nest_level);
276
token = gimp_config_deserialize_value (&value,
277
config, prop_spec, scanner);
280
if (token == G_TOKEN_RIGHT_PAREN &&
281
g_scanner_peek_next_token (scanner) == token)
283
if (! (G_VALUE_HOLDS_OBJECT (&value) &&
284
(prop_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE)))
285
g_object_set_property (G_OBJECT (config), prop_spec->name, &value);
290
g_warning ("%s: couldn't deserialize property %s::%s of type %s",
292
g_type_name (G_TYPE_FROM_INSTANCE (config)),
294
g_type_name (prop_spec->value_type));
298
g_value_unset (&value);
300
g_scanner_set_scope (scanner, old_scope_id);
306
gimp_config_deserialize_value (GValue *value,
308
GParamSpec *prop_spec,
311
if (G_TYPE_FUNDAMENTAL (prop_spec->value_type) == G_TYPE_ENUM)
313
return gimp_config_deserialize_enum (value, prop_spec, scanner);
315
else if (G_TYPE_IS_FUNDAMENTAL (prop_spec->value_type))
317
return gimp_config_deserialize_fundamental (value, prop_spec, scanner);
319
else if (prop_spec->value_type == GIMP_TYPE_MEMSIZE)
321
return gimp_config_deserialize_memsize (value, prop_spec, scanner);
323
else if (prop_spec->value_type == GIMP_TYPE_CONFIG_PATH)
325
return gimp_config_deserialize_path (value, prop_spec, scanner);
327
else if (prop_spec->value_type == GIMP_TYPE_RGB)
329
return gimp_config_deserialize_rgb (value, prop_spec, scanner);
331
else if (prop_spec->value_type == GIMP_TYPE_MATRIX2)
333
return gimp_config_deserialize_matrix2 (value, prop_spec, scanner);
335
else if (prop_spec->value_type == G_TYPE_VALUE_ARRAY)
337
return gimp_config_deserialize_value_array (value,
338
config, prop_spec, scanner);
341
/* This fallback will only work for value_types that
342
* can be transformed from a string value.
344
return gimp_config_deserialize_any (value, prop_spec, scanner);
348
gimp_config_deserialize_fundamental (GValue *value,
349
GParamSpec *prop_spec,
354
gboolean negate = FALSE;
356
value_type = G_TYPE_FUNDAMENTAL (prop_spec->value_type);
361
token = G_TOKEN_STRING;
365
token = G_TOKEN_IDENTIFIER;
371
if (g_scanner_peek_next_token (scanner) == '-')
374
g_scanner_get_next_token (scanner);
385
if (g_scanner_peek_next_token (scanner) == '-')
388
g_scanner_get_next_token (scanner);
390
token = G_TOKEN_FLOAT;
394
token = G_TOKEN_NONE;
395
g_assert_not_reached ();
399
if (g_scanner_peek_next_token (scanner) != token)
404
g_scanner_get_next_token (scanner);
409
if (scanner_string_utf8_valid (scanner, prop_spec->name))
410
g_value_set_static_string (value, scanner->value.v_string);
416
if (! g_ascii_strcasecmp (scanner->value.v_identifier, "yes") ||
417
! g_ascii_strcasecmp (scanner->value.v_identifier, "true"))
418
g_value_set_boolean (value, TRUE);
419
else if (! g_ascii_strcasecmp (scanner->value.v_identifier, "no") ||
420
! g_ascii_strcasecmp (scanner->value.v_identifier, "false"))
421
g_value_set_boolean (value, FALSE);
426
/* please don't translate 'yes' and 'no' */
427
_("expected 'yes' or 'no' for boolean token %s, got '%s'"),
428
prop_spec->name, scanner->value.v_identifier);
434
g_value_set_int (value, (negate ?
435
- scanner->value.v_int64 :
436
scanner->value.v_int64));
439
g_value_set_uint (value, scanner->value.v_int64);
443
g_value_set_long (value, (negate ?
444
- scanner->value.v_int64 :
445
scanner->value.v_int64));
448
g_value_set_ulong (value, scanner->value.v_int64);
452
g_value_set_int64 (value, (negate ?
453
- scanner->value.v_int64 :
454
scanner->value.v_int64));
457
g_value_set_uint64 (value, scanner->value.v_int64);
461
g_value_set_float (value, negate ?
462
- scanner->value.v_float : scanner->value.v_float);
465
g_value_set_double (value, negate ?
466
- scanner->value.v_float: scanner->value.v_float);
470
g_assert_not_reached ();
474
return G_TOKEN_RIGHT_PAREN;
478
gimp_config_deserialize_enum (GValue *value,
479
GParamSpec *prop_spec,
482
GEnumClass *enum_class;
483
GEnumValue *enum_value;
485
enum_class = g_type_class_peek (G_VALUE_TYPE (value));
487
switch (g_scanner_peek_next_token (scanner))
489
case G_TOKEN_IDENTIFIER:
490
g_scanner_get_next_token (scanner);
492
enum_value = g_enum_get_value_by_nick (enum_class,
493
scanner->value.v_identifier);
495
enum_value = g_enum_get_value_by_name (enum_class,
496
scanner->value.v_identifier);
500
g_scanner_error (scanner,
501
_("invalid value '%s' for token %s"),
502
scanner->value.v_identifier, prop_spec->name);
508
g_scanner_get_next_token (scanner);
510
enum_value = g_enum_get_value (enum_class,
511
(gint) scanner->value.v_int64);
515
g_scanner_error (scanner,
516
_("invalid value '%ld' for token %s"),
517
(glong) scanner->value.v_int64, prop_spec->name);
523
return G_TOKEN_IDENTIFIER;
526
g_value_set_enum (value, enum_value->value);
528
return G_TOKEN_RIGHT_PAREN;
532
gimp_config_deserialize_memsize (GValue *value,
533
GParamSpec *prop_spec,
536
gchar *orig_cset_first = scanner->config->cset_identifier_first;
537
gchar *orig_cset_nth = scanner->config->cset_identifier_nth;
540
scanner->config->cset_identifier_first = G_CSET_DIGITS;
541
scanner->config->cset_identifier_nth = G_CSET_DIGITS "gGmMkKbB";
543
if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER)
544
return G_TOKEN_IDENTIFIER;
546
g_scanner_get_next_token (scanner);
548
scanner->config->cset_identifier_first = orig_cset_first;
549
scanner->config->cset_identifier_nth = orig_cset_nth;
551
if (! gimp_memsize_deserialize (scanner->value.v_identifier, &memsize))
554
g_value_set_uint64 (value, memsize);
556
return G_TOKEN_RIGHT_PAREN;
560
gimp_config_deserialize_path (GValue *value,
561
GParamSpec *prop_spec,
564
GError *error = NULL;
566
if (g_scanner_peek_next_token (scanner) != G_TOKEN_STRING)
567
return G_TOKEN_STRING;
569
g_scanner_get_next_token (scanner);
571
if (!scanner_string_utf8_valid (scanner, prop_spec->name))
574
if (scanner->value.v_string)
576
/* Check if the string can be expanded
577
* and converted to the filesystem encoding.
579
gchar *expand = gimp_config_path_expand (scanner->value.v_string,
584
g_scanner_error (scanner,
585
_("while parsing token '%s': %s"),
586
prop_spec->name, error->message);
587
g_error_free (error);
594
g_value_set_static_string (value, scanner->value.v_string);
597
return G_TOKEN_RIGHT_PAREN;
601
gimp_config_deserialize_rgb (GValue *value,
602
GParamSpec *prop_spec,
607
if (! gimp_scanner_parse_color (scanner, &rgb))
610
g_value_set_boxed (value, &rgb);
612
return G_TOKEN_RIGHT_PAREN;
616
gimp_config_deserialize_matrix2 (GValue *value,
617
GParamSpec *prop_spec,
622
if (! gimp_scanner_parse_matrix2 (scanner, &matrix))
625
g_value_set_boxed (value, &matrix);
627
return G_TOKEN_RIGHT_PAREN;
631
gimp_config_deserialize_object (GValue *value,
633
GParamSpec *prop_spec,
637
GimpConfigInterface *config_iface;
638
GimpConfig *prop_object;
640
g_object_get_property (G_OBJECT (config), prop_spec->name, value);
642
prop_object = g_value_get_object (value);
646
/* if the object property is not GIMP_CONFIG_PARAM_AGGREGATE, read
647
* the type of the object and create it
649
if (! (prop_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE))
654
if (! gimp_scanner_parse_string (scanner, &type_name))
655
return G_TOKEN_STRING;
657
type = g_type_from_name (type_name);
660
if (! g_type_is_a (type, prop_spec->value_type))
661
return G_TOKEN_STRING;
663
prop_object = g_object_new (type, NULL);
665
g_value_take_object (value, prop_object);
669
return G_TOKEN_RIGHT_PAREN;
673
config_iface = GIMP_CONFIG_GET_INTERFACE (prop_object);
676
return gimp_config_deserialize_any (value, prop_spec, scanner);
678
if (! config_iface->deserialize (prop_object, scanner, nest_level + 1, NULL))
681
return G_TOKEN_RIGHT_PAREN;
685
gimp_config_deserialize_value_array (GValue *value,
687
GParamSpec *prop_spec,
690
GParamSpecValueArray *array_spec;
692
GValue array_value = { 0, };
697
array_spec = G_PARAM_SPEC_VALUE_ARRAY (prop_spec);
699
if (! gimp_scanner_parse_int (scanner, &n_values))
702
array = g_value_array_new (n_values);
704
for (i = 0; i < n_values; i++)
706
g_value_init (&array_value, array_spec->element_spec->value_type);
708
token = gimp_config_deserialize_value (&array_value,
710
array_spec->element_spec,
713
if (token == G_TOKEN_RIGHT_PAREN)
714
g_value_array_append (array, &array_value);
716
g_value_unset (&array_value);
718
if (token != G_TOKEN_RIGHT_PAREN)
722
g_value_take_boxed (value, array);
724
return G_TOKEN_RIGHT_PAREN;
728
gimp_config_deserialize_any (GValue *value,
729
GParamSpec *prop_spec,
734
if (!g_value_type_transformable (G_TYPE_STRING, prop_spec->value_type))
736
g_warning ("%s: %s can not be transformed from a string",
737
G_STRFUNC, g_type_name (prop_spec->value_type));
741
if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER)
742
return G_TOKEN_IDENTIFIER;
744
g_scanner_get_next_token (scanner);
746
g_value_init (&src, G_TYPE_STRING);
747
g_value_set_static_string (&src, scanner->value.v_identifier);
748
g_value_transform (&src, value);
749
g_value_unset (&src);
751
return G_TOKEN_RIGHT_PAREN;