gimpconfig-deserialize.c 23.4 KB
Newer Older
1 2 3 4
/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * Object properties deserialization routines
5
 * Copyright (C) 2001-2002  Sven Neumann <sven@gimp.org>
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "config.h"

#include <glib-object.h>

26
#include "libgimpbase/gimpbase.h"
27
#include "libgimpcolor/gimpcolor.h"
28
#include "libgimpmath/gimpmath.h"
29

30 31
#include "config-types.h"

32
#include "gimpconfig.h"
33
#include "gimpconfig-deserialize.h"
34
#include "gimpconfig-params.h"
35
#include "gimpconfig-path.h"
36
#include "gimpconfig-types.h"
37
#include "gimpscanner.h"
38

39
#include "gimp-intl.h"
40

41

42
/*
43 44 45 46 47
 *  All functions return G_TOKEN_RIGHT_PAREN on success,
 *  the GTokenType they would have expected but didn't get
 *  or G_TOKEN_NONE if they got the expected token but
 *  couldn't parse it.
 */
48

Sven Neumann's avatar
Sven Neumann committed
49
static GTokenType  gimp_config_deserialize_unknown     (GimpConfig *config,
50
                                                        GScanner   *scanner);
Sven Neumann's avatar
Sven Neumann committed
51
static GTokenType  gimp_config_deserialize_property    (GimpConfig *config,
52 53
                                                        GScanner   *scanner,
                                                        gint        nest_level);
54
static GTokenType  gimp_config_deserialize_value       (GValue     *value,
Sven Neumann's avatar
Sven Neumann committed
55
                                                        GimpConfig *config,
56 57
                                                        GParamSpec *prop_spec,
                                                        GScanner   *scanner);
58 59 60 61 62 63 64 65 66 67 68 69
static GTokenType  gimp_config_deserialize_fundamental (GValue     *value,
                                                        GParamSpec *prop_spec,
                                                        GScanner   *scanner);
static GTokenType  gimp_config_deserialize_enum        (GValue     *value,
                                                        GParamSpec *prop_spec,
                                                        GScanner   *scanner);
static GTokenType  gimp_config_deserialize_memsize     (GValue     *value,
                                                        GParamSpec *prop_spec,
                                                        GScanner   *scanner);
static GTokenType  gimp_config_deserialize_path        (GValue     *value,
                                                        GParamSpec *prop_spec,
                                                        GScanner   *scanner);
70 71 72
static GTokenType  gimp_config_deserialize_color       (GValue     *value,
                                                        GParamSpec *prop_spec,
                                                        GScanner   *scanner);
73 74 75
static GTokenType  gimp_config_deserialize_matrix2     (GValue     *value,
                                                        GParamSpec *prop_spec,
                                                        GScanner   *scanner);
76
static GTokenType  gimp_config_deserialize_object      (GValue     *value,
Sven Neumann's avatar
Sven Neumann committed
77
                                                        GimpConfig *config,
78 79 80
                                                        GParamSpec *prop_spec,
                                                        GScanner   *scanner,
                                                        gint        nest_level);
81
static GTokenType  gimp_config_deserialize_value_array (GValue     *value,
Sven Neumann's avatar
Sven Neumann committed
82
                                                        GimpConfig *config,
83 84
                                                        GParamSpec *prop_spec,
                                                        GScanner   *scanner);
85 86 87
static GTokenType  gimp_config_deserialize_any         (GValue     *value,
                                                        GParamSpec *prop_spec,
                                                        GScanner   *scanner);
88

89
static inline gboolean  scanner_string_utf8_valid (GScanner    *scanner,
90
                                                   const gchar *token_name);
91

92

93 94
/**
 * gimp_config_deserialize_properties:
Sven Neumann's avatar
Sven Neumann committed
95
 * @config: a #GimpConfig.
96
 * @scanner: a #GScanner.
97
 * @nest_level:
98
 * @store_unknown_tokens: %TRUE if you want to store unknown tokens.
99
 *
Sven Neumann's avatar
Sven Neumann committed
100
 * This function uses the @scanner to configure the properties of @config.
101 102 103
 *
 * The store_unknown_tokens parameter is a special feature for #GimpRc.
 * If it set to %TRUE, unknown tokens (e.g. tokens that don't refer to
Sven Neumann's avatar
Sven Neumann committed
104
 * a property of @config) with string values are attached to @config as
105 106
 * unknown tokens. GimpConfig has a couple of functions to handle the
 * attached key/value pairs.
107 108
 *
 * Return value:
109
 **/
110
gboolean
111 112 113 114
gimp_config_deserialize_properties (GimpConfig *config,
                                    GScanner   *scanner,
                                    gint        nest_level,
                                    gboolean    store_unknown_tokens)
115
{
116 117 118 119 120 121 122
  GObjectClass  *klass;
  GParamSpec   **property_specs;
  guint          n_property_specs;
  guint          i;
  guint          scope_id;
  guint          old_scope_id;
  GTokenType	 token;
123
  GTokenType	 next;
124

125
  g_return_val_if_fail (GIMP_IS_CONFIG (config), FALSE);
126

127
  klass = G_OBJECT_GET_CLASS (config);
128
  property_specs = g_object_class_list_properties (klass, &n_property_specs);
129

130 131
  if (!property_specs)
    return TRUE;
132

133
  scope_id = g_type_qname (G_TYPE_FROM_INSTANCE (config));
134 135 136 137 138 139
  old_scope_id = g_scanner_set_scope (scanner, scope_id);

  for (i = 0; i < n_property_specs; i++)
    {
      GParamSpec *prop_spec = property_specs[i];

140
      if (prop_spec->flags & GIMP_PARAM_SERIALIZE)
141
        {
142
          g_scanner_scope_add_symbol (scanner, scope_id,
143 144 145 146
                                      prop_spec->name, prop_spec);
        }
    }

147 148
  g_free (property_specs);

149
  g_object_freeze_notify (G_OBJECT (config));
150

151
  token = G_TOKEN_LEFT_PAREN;
152 153

  while (TRUE)
154
    {
155 156 157
      next = g_scanner_peek_next_token (scanner);

      if (next != token &&
158 159
          ! (store_unknown_tokens &&
             token == G_TOKEN_SYMBOL && next == G_TOKEN_IDENTIFIER))
160 161 162
        {
          break;
        }
163 164

      token = g_scanner_get_next_token (scanner);
165

166 167 168 169 170
      switch (token)
        {
        case G_TOKEN_LEFT_PAREN:
          token = G_TOKEN_SYMBOL;
          break;
171

172
        case G_TOKEN_IDENTIFIER:
173
          token = gimp_config_deserialize_unknown (config, scanner);
174 175
          break;

176
        case G_TOKEN_SYMBOL:
177
          token = gimp_config_deserialize_property (config,
178
                                                    scanner, nest_level);
179 180 181 182 183 184 185 186 187 188 189
          break;

        case G_TOKEN_RIGHT_PAREN:
          token = G_TOKEN_LEFT_PAREN;
          break;

        default: /* do nothing */
          break;
        }
    }

190 191
  g_scanner_set_scope (scanner, old_scope_id);

192
  g_object_thaw_notify (G_OBJECT (config));
193

194 195 196
  if (token == G_TOKEN_NONE)
    return FALSE;

197 198 199 200 201 202 203 204 205 206
  /* If store_unknown_tokens is TRUE but the unknown token value couldn't
     be parsed the default error message is rather confusing.
     We try to produce something more meaningful here ... */
  if ((store_unknown_tokens &&
       token == G_TOKEN_STRING && next == G_TOKEN_IDENTIFIER))
    {
      g_scanner_unexp_token (scanner, G_TOKEN_SYMBOL, NULL, NULL, NULL,
			     _("fatal parse error"), TRUE);
      return FALSE;
    }
207

208
  return gimp_config_deserialize_return (scanner, token, nest_level);
209 210
}

211
static GTokenType
Sven Neumann's avatar
Sven Neumann committed
212
gimp_config_deserialize_unknown (GimpConfig *config,
213
                                 GScanner   *scanner)
214 215
{
  gchar *key;
216 217 218
  guint  old_scope_id;

  old_scope_id = g_scanner_set_scope (scanner, 0);
219 220 221 222 223 224 225

  if (g_scanner_peek_next_token (scanner) != G_TOKEN_STRING)
    return G_TOKEN_STRING;

  key = g_strdup (scanner->value.v_identifier);

  g_scanner_get_next_token (scanner);
226

227 228
  g_scanner_set_scope (scanner, old_scope_id);

229 230 231 232 233
  if (!scanner_string_utf8_valid (scanner, key))
    {
      g_free (key);
      return G_TOKEN_NONE;
    }
Sven Neumann's avatar
Sven Neumann committed
234

Sven Neumann's avatar
Sven Neumann committed
235
  gimp_config_add_unknown_token (config, key, scanner->value.v_string);
Sven Neumann's avatar
Sven Neumann committed
236
  g_free (key);
237

238 239 240 241
  return G_TOKEN_RIGHT_PAREN;
}

static GTokenType
242
gimp_config_deserialize_property (GimpConfig *config,
243 244
                                  GScanner   *scanner,
                                  gint        nest_level)
245
{
246
  GTypeClass          *owner_class;
247
  GimpConfigInterface *config_iface;
248
  GimpConfigInterface *parent_iface;
249 250 251
  GParamSpec          *prop_spec;
  GTokenType           token = G_TOKEN_RIGHT_PAREN;
  GValue               value = { 0, };
252 253 254
  guint                old_scope_id;

  old_scope_id = g_scanner_set_scope (scanner, 0);
255

256
  prop_spec = G_PARAM_SPEC (scanner->value.v_symbol);
257

258 259
  g_value_init (&value, prop_spec->value_type);

260 261
  owner_class = g_type_class_peek (prop_spec->owner_type);

262
  config_iface = g_type_interface_peek (owner_class, GIMP_TYPE_CONFIG);
263

264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
  /*  We must call deserialize_property() *only* if the *exact* class
   *  which implements it is param_spec->owner_type's class.
   *
   *  Therefore, we ask param_spec->owner_type's immediate parent class
   *  for it's GimpConfigInterface and check if we get a different pointer.
   *
   *  (if the pointers are the same, param_spec->owner_type's
   *   GimpConfigInterface is inherited from one of it's parent classes
   *   and thus not able to handle param_spec->owner_type's properties).
   */
  if (config_iface)
    {
      GTypeClass *owner_parent_class;

      owner_parent_class = g_type_class_peek_parent (owner_class),

      parent_iface = g_type_interface_peek (owner_parent_class,
                                            GIMP_TYPE_CONFIG);
    }

284
  if (config_iface                       &&
285
      config_iface != parent_iface       && /* see comment above */
286 287 288 289 290 291 292
      config_iface->deserialize_property &&
      config_iface->deserialize_property (config,
                                          prop_spec->param_id,
                                          &value,
                                          prop_spec,
                                          scanner,
                                          &token))
293 294 295 296 297
    {
      /* nop */
    }
  else
    {
298 299
      if (G_VALUE_HOLDS_OBJECT (&value))
        token = gimp_config_deserialize_object (&value,
300
                                                config, prop_spec,
301 302 303
                                                scanner, nest_level);
      else
        token = gimp_config_deserialize_value (&value,
304
                                               config, prop_spec, scanner);
305
    }
306

307 308 309
  if (token == G_TOKEN_RIGHT_PAREN &&
      g_scanner_peek_next_token (scanner) == token)
    {
310 311
      if (! (G_VALUE_HOLDS_OBJECT (&value) &&
             (prop_spec->flags & GIMP_PARAM_AGGREGATE)))
312
        g_object_set_property (G_OBJECT (config), prop_spec->name, &value);
313
    }
314
#ifdef CONFIG_DEBUG
315
  else
316
    {
317 318
      g_warning ("%s: couldn't deserialize property %s::%s of type %s",
                 G_STRFUNC,
319
                 g_type_name (G_TYPE_FROM_INSTANCE (config)),
320
                 prop_spec->name,
321 322
                 g_type_name (prop_spec->value_type));
    }
323
#endif
324

325
  g_value_unset (&value);
326

327 328
  g_scanner_set_scope (scanner, old_scope_id);

329
  return token;
330 331
}

332 333
static GTokenType
gimp_config_deserialize_value (GValue     *value,
Sven Neumann's avatar
Sven Neumann committed
334
                               GimpConfig *config,
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
                               GParamSpec *prop_spec,
                               GScanner   *scanner)
{
  if (G_TYPE_FUNDAMENTAL (prop_spec->value_type) == G_TYPE_ENUM)
    {
      return gimp_config_deserialize_enum (value, prop_spec, scanner);
    }
  else if (G_TYPE_IS_FUNDAMENTAL (prop_spec->value_type))
    {
      return gimp_config_deserialize_fundamental (value, prop_spec, scanner);
    }
  else if (prop_spec->value_type == GIMP_TYPE_MEMSIZE)
    {
      return gimp_config_deserialize_memsize (value, prop_spec, scanner);
    }
  else if (prop_spec->value_type == GIMP_TYPE_PATH)
    {
352
      return  gimp_config_deserialize_path (value, prop_spec, scanner);
353 354 355 356 357
    }
  else if (prop_spec->value_type == GIMP_TYPE_COLOR)
    {
      return gimp_config_deserialize_color (value, prop_spec, scanner);
    }
358 359 360 361
  else if (prop_spec->value_type == GIMP_TYPE_MATRIX2)
    {
      return gimp_config_deserialize_matrix2 (value, prop_spec, scanner);
    }
362 363 364
  else if (prop_spec->value_type == G_TYPE_VALUE_ARRAY)
    {
      return gimp_config_deserialize_value_array (value,
Sven Neumann's avatar
Sven Neumann committed
365
                                                  config, prop_spec, scanner);
366 367 368 369 370 371 372 373
    }

  /*  This fallback will only work for value_types that
   *  can be transformed from a string value.
   */
  return gimp_config_deserialize_any (value, prop_spec, scanner);
}

374
static GTokenType
375 376
gimp_config_deserialize_fundamental (GValue     *value,
                                     GParamSpec *prop_spec,
377
                                     GScanner   *scanner)
378
{
379
  GTokenType token;
Sven Neumann's avatar
Sven Neumann committed
380 381
  GType      value_type;
  gboolean   negate = FALSE;
382

Sven Neumann's avatar
Sven Neumann committed
383 384 385
  value_type = G_TYPE_FUNDAMENTAL (prop_spec->value_type);

  switch (value_type)
386 387
    {
    case G_TYPE_STRING:
388
      token = G_TOKEN_STRING;
389
      break;
390

391
    case G_TYPE_BOOLEAN:
392
      token = G_TOKEN_IDENTIFIER;
393
      break;
394

395 396
    case G_TYPE_INT:
    case G_TYPE_LONG:
397
    case G_TYPE_INT64:
Sven Neumann's avatar
Sven Neumann committed
398 399 400 401 402 403 404
      if (g_scanner_peek_next_token (scanner) == '-')
        {
          negate = TRUE;
          g_scanner_get_next_token (scanner);
        }
      /*  fallthrough  */
    case G_TYPE_UINT:
405
    case G_TYPE_ULONG:
406
    case G_TYPE_UINT64:
407
      token = G_TOKEN_INT;
408
      break;
409

410 411
    case G_TYPE_FLOAT:
    case G_TYPE_DOUBLE:
412 413 414 415 416
      if (g_scanner_peek_next_token (scanner) == '-')
        {
          negate = TRUE;
          g_scanner_get_next_token (scanner);
        }
417
      token = G_TOKEN_FLOAT;
418
      break;
419

420
    default:
421
      token = G_TOKEN_NONE;
422
      g_assert_not_reached ();
423
      break;
424 425
    }

426
  if (g_scanner_peek_next_token (scanner) != token)
Sven Neumann's avatar
Sven Neumann committed
427 428 429
    {
      return token;
    }
430 431 432

  g_scanner_get_next_token (scanner);

Sven Neumann's avatar
Sven Neumann committed
433
  switch (value_type)
434
    {
435
    case G_TYPE_STRING:
436
      if (scanner_string_utf8_valid (scanner, prop_spec->name))
437
        g_value_set_static_string (value, scanner->value.v_string);
438 439
      else
        return G_TOKEN_NONE;
440
      break;
441

442 443 444 445 446 447 448
    case G_TYPE_BOOLEAN:
      if (! g_ascii_strcasecmp (scanner->value.v_identifier, "yes") ||
          ! g_ascii_strcasecmp (scanner->value.v_identifier, "true"))
        g_value_set_boolean (value, TRUE);
      else if (! g_ascii_strcasecmp (scanner->value.v_identifier, "no") ||
               ! g_ascii_strcasecmp (scanner->value.v_identifier, "false"))
        g_value_set_boolean (value, FALSE);
449
      else
450
        {
451 452
          g_scanner_error
            (scanner,
453
             /* please don't translate 'yes' and 'no' */
454
             _("expected 'yes' or 'no' for boolean token %s, got '%s'"),
455
             prop_spec->name, scanner->value.v_identifier);
456
          return G_TOKEN_NONE;
457 458 459 460
        }
      break;

    case G_TYPE_INT:
Sven Neumann's avatar
Sven Neumann committed
461
      g_value_set_int (value, (negate ?
462 463
                               - scanner->value.v_int64 :
                               scanner->value.v_int64));
464 465
      break;
    case G_TYPE_UINT:
466
      g_value_set_uint (value, scanner->value.v_int64);
467
      break;
468

469
    case G_TYPE_LONG:
Sven Neumann's avatar
Sven Neumann committed
470
      g_value_set_long (value, (negate ?
471 472
                                - scanner->value.v_int64 :
                                scanner->value.v_int64));
473 474
      break;
    case G_TYPE_ULONG:
475 476 477 478 479 480 481
      g_value_set_ulong (value, scanner->value.v_int64);
      break;

    case G_TYPE_INT64:
      g_value_set_int64 (value, (negate ?
                                 - scanner->value.v_int64 :
                                 scanner->value.v_int64));
482
      break;
483 484 485 486
    case G_TYPE_UINT64:
      g_value_set_uint64 (value, scanner->value.v_int64);
      break;

487
    case G_TYPE_FLOAT:
488 489
      g_value_set_float (value, negate ?
                         - scanner->value.v_float : scanner->value.v_float);
490 491
      break;
    case G_TYPE_DOUBLE:
492 493
      g_value_set_double (value, negate ?
                          - scanner->value.v_float: scanner->value.v_float);
494
      break;
495

496
    default:
497 498
      g_assert_not_reached ();
      break;
499
    }
500

501
  return G_TOKEN_RIGHT_PAREN;
502 503
}

504
static GTokenType
505 506
gimp_config_deserialize_enum (GValue     *value,
                              GParamSpec *prop_spec,
507
                              GScanner   *scanner)
508 509 510 511 512
{
  GEnumClass *enum_class;
  GEnumValue *enum_value;

  enum_class = g_type_class_peek (G_VALUE_TYPE (value));
513 514

  switch (g_scanner_peek_next_token (scanner))
515
    {
516 517 518
    case G_TOKEN_IDENTIFIER:
      g_scanner_get_next_token (scanner);

519
      enum_value = g_enum_get_value_by_nick (G_ENUM_CLASS (enum_class),
520 521
					     scanner->value.v_identifier);
      if (!enum_value)
522
	enum_value = g_enum_get_value_by_name (G_ENUM_CLASS (enum_class),
523 524 525 526
					       scanner->value.v_identifier);

      if (!enum_value)
	{
527 528
	  g_scanner_error (scanner,
			   _("invalid value '%s' for token %s"),
529 530 531 532
			   scanner->value.v_identifier, prop_spec->name);
	  return G_TOKEN_NONE;
	}
      break;
533

534 535 536
    case G_TOKEN_INT:
      g_scanner_get_next_token (scanner);

537 538
      enum_value = g_enum_get_value (enum_class,
                                     (gint) scanner->value.v_int64);
539 540 541

      if (!enum_value)
	{
542 543
	  g_scanner_error (scanner,
			   _("invalid value '%ld' for token %s"),
544
			   (glong) scanner->value.v_int64, prop_spec->name);
545 546 547
	  return G_TOKEN_NONE;
	}
      break;
548

549 550
    default:
      return G_TOKEN_IDENTIFIER;
551
    }
552

553 554
  g_value_set_enum (value, enum_value->value);

555
  return G_TOKEN_RIGHT_PAREN;
556 557
}

558 559 560 561 562
static GTokenType
gimp_config_deserialize_memsize (GValue     *value,
                                 GParamSpec *prop_spec,
                                 GScanner   *scanner)
{
563 564
  gchar *orig_cset_first = scanner->config->cset_identifier_first;
  gchar *orig_cset_nth   = scanner->config->cset_identifier_nth;
565 566 567

  scanner->config->cset_identifier_first = G_CSET_DIGITS;
  scanner->config->cset_identifier_nth   = G_CSET_DIGITS "gGmMkKbB";
568

569 570
  if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER)
    return G_TOKEN_IDENTIFIER;
571

572 573 574 575
  g_scanner_get_next_token (scanner);

  scanner->config->cset_identifier_first = orig_cset_first;
  scanner->config->cset_identifier_nth   = orig_cset_nth;
576

577 578 579 580
  if (gimp_memsize_set_from_string (value, scanner->value.v_identifier))
    return G_TOKEN_RIGHT_PAREN;
  else
    return G_TOKEN_NONE;
581 582 583 584 585 586 587
}

static GTokenType
gimp_config_deserialize_path (GValue     *value,
                              GParamSpec *prop_spec,
                              GScanner   *scanner)
{
588
  GError *error = NULL;
589

590 591 592 593 594
  if (g_scanner_peek_next_token (scanner) != G_TOKEN_STRING)
    return G_TOKEN_STRING;

  g_scanner_get_next_token (scanner);

595 596 597
  if (!scanner_string_utf8_valid (scanner, prop_spec->name))
    return G_TOKEN_NONE;

598 599 600
  if (scanner->value.v_string)
    {
      /*  Check if the string can be expanded
601
       *  and converted to the filesystem encoding.
602 603 604
       */
      gchar *expand = gimp_config_path_expand (scanner->value.v_string,
                                               TRUE, &error);
605

606 607 608
      if (!expand)
        {
          g_scanner_error (scanner,
609
                           _("while parsing token '%s': %s"),
610 611
                           prop_spec->name, error->message);
          g_error_free (error);
612

613 614
          return G_TOKEN_NONE;
        }
615

616
      g_free (expand);
617

618 619
      g_value_set_static_string (value, scanner->value.v_string);
    }
620 621 622 623

  return G_TOKEN_RIGHT_PAREN;
}

624 625 626 627 628
static GTokenType
gimp_config_deserialize_color (GValue     *value,
                               GParamSpec *prop_spec,
                               GScanner   *scanner)
{
629
  GimpRGB color;
630

631 632
  if (! gimp_scanner_parse_color (scanner, &color))
    return G_TOKEN_NONE;
633

634
  g_value_set_boxed (value, &color);
635

636
  return G_TOKEN_RIGHT_PAREN;
637 638
}

639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
static GTokenType
gimp_config_deserialize_matrix2 (GValue     *value,
                                 GParamSpec *prop_spec,
                                 GScanner   *scanner)
{
  GimpMatrix2 matrix;

  if (! gimp_scanner_parse_matrix2 (scanner, &matrix))
    return G_TOKEN_NONE;

  g_value_set_boxed (value, &matrix);

  return G_TOKEN_RIGHT_PAREN;
}

654 655
static GTokenType
gimp_config_deserialize_object (GValue     *value,
656
                                GimpConfig *config,
657 658 659 660
                                GParamSpec *prop_spec,
                                GScanner   *scanner,
                                gint        nest_level)
{
661 662
  GimpConfigInterface *config_iface;
  GimpConfig          *prop_object;
663

664
  g_object_get_property (G_OBJECT (config), prop_spec->name, value);
665 666 667 668 669 670

  prop_object = g_value_get_object (value);

  if (! prop_object)
    return G_TOKEN_RIGHT_PAREN;

671
  config_iface = GIMP_CONFIG_GET_INTERFACE (prop_object);
672

673
  if (! config_iface)
674
    return gimp_config_deserialize_any (value, prop_spec, scanner);
675

676
  if (! config_iface->deserialize (prop_object, scanner, nest_level + 1, NULL))
677 678 679 680 681
    return G_TOKEN_NONE;

  return G_TOKEN_RIGHT_PAREN;
}

682 683
static GTokenType
gimp_config_deserialize_value_array (GValue     *value,
684
                                     GimpConfig *config,
685 686 687 688 689 690 691 692 693 694 695 696
                                     GParamSpec *prop_spec,
                                     GScanner   *scanner)
{
  GParamSpecValueArray *array_spec;
  GValueArray          *array;
  GValue                array_value = { 0, };
  gint                  n_values;
  GTokenType            token;
  gint                  i;

  array_spec = G_PARAM_SPEC_VALUE_ARRAY (prop_spec);

697
  if (! gimp_scanner_parse_int (scanner, &n_values))
698 699 700 701 702 703 704 705 706
    return G_TOKEN_INT;

  array = g_value_array_new (n_values);

  for (i = 0; i < n_values; i++)
    {
      g_value_init (&array_value, array_spec->element_spec->value_type);

      token = gimp_config_deserialize_value (&array_value,
707
                                             config,
708 709 710 711 712 713 714 715 716 717 718 719
                                             array_spec->element_spec,
                                             scanner);

      if (token == G_TOKEN_RIGHT_PAREN)
        g_value_array_append (array, &array_value);

      g_value_unset (&array_value);

      if (token != G_TOKEN_RIGHT_PAREN)
        return token;
    }

720
  g_value_take_boxed (value, array);
721

722 723 724
  return G_TOKEN_RIGHT_PAREN;
}

725
static GTokenType
726 727
gimp_config_deserialize_any (GValue     *value,
                             GParamSpec *prop_spec,
728
                             GScanner   *scanner)
729
{
730
  GValue src = { 0, };
731 732 733 734

  if (!g_value_type_transformable (G_TYPE_STRING, prop_spec->value_type))
    {
      g_warning ("%s: %s can not be transformed from a string",
735
                 G_STRFUNC, g_type_name (prop_spec->value_type));
736
      return G_TOKEN_NONE;
737
    }
738

739 740
  if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER)
    return G_TOKEN_IDENTIFIER;
741 742 743 744

  g_scanner_get_next_token (scanner);

  g_value_init (&src, G_TYPE_STRING);
745
  g_value_set_static_string (&src, scanner->value.v_identifier);
746
  g_value_transform (&src, value);
747
  g_value_unset (&src);
748

749
  return G_TOKEN_RIGHT_PAREN;
750
}
751 752

static inline gboolean
753
scanner_string_utf8_valid (GScanner    *scanner,
754 755 756
                           const gchar *token_name)
{
  if (g_utf8_validate (scanner->value.v_string, -1, NULL))
757 758
    return TRUE;

759 760
  g_scanner_error (scanner,
                   _("value for token %s is not a valid UTF-8 string"),
761
                   token_name);
762 763

  return FALSE;
764
}