plug-in-rc.c 35.5 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program
2 3
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
4
 * plug-in-rc.c
5 6
 * Copyright (C) 2001  Sven Neumann <sven@gimp.org>
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3 of the License, or
10 11 12 13 14 15 16 17
 * (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
18
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19 20 21 22
 */

#include "config.h"

23
#include <gdk-pixbuf/gdk-pixbuf.h>
24
#include <gegl.h>
25

26 27
#include "libgimpbase/gimpbase.h"
#include "libgimpbase/gimpprotocol.h"
28
#include "libgimpconfig/gimpconfig.h"
29

30 31
#include "plug-in-types.h"

32 33
#include "core/gimp.h"

34
#include "pdb/gimp-pdb-compat.h"
35

36
#include "gimpplugindef.h"
37
#include "gimppluginprocedure.h"
38 39
#include "plug-in-rc.h"

40
#include "gimp-intl.h"
41 42


43
#define PLUG_IN_RC_FILE_VERSION 5
44 45


46
/*
47
 *  All deserialize functions return G_TOKEN_LEFT_PAREN on success,
48 49
 *  or the GTokenType they would have expected but didn't get,
 *  or G_TOKEN_ERROR if the function already set an error itself.
50 51
 */

52
static GTokenType plug_in_def_deserialize        (Gimp                 *gimp,
53 54
                                                  GScanner             *scanner,
                                                  GSList              **plug_in_defs);
55 56
static GTokenType plug_in_procedure_deserialize  (GScanner             *scanner,
                                                  Gimp                 *gimp,
57
                                                  GFile                *file,
58 59 60 61 62 63 64 65 66 67 68 69
                                                  GimpPlugInProcedure **proc);
static GTokenType plug_in_menu_path_deserialize  (GScanner             *scanner,
                                                  GimpPlugInProcedure  *proc);
static GTokenType plug_in_icon_deserialize       (GScanner             *scanner,
                                                  GimpPlugInProcedure  *proc);
static GTokenType plug_in_file_proc_deserialize  (GScanner             *scanner,
                                                  GimpPlugInProcedure  *proc);
static GTokenType plug_in_proc_arg_deserialize   (GScanner             *scanner,
                                                  Gimp                 *gimp,
                                                  GimpProcedure        *procedure,
                                                  gboolean              return_value);
static GTokenType plug_in_locale_def_deserialize (GScanner             *scanner,
70
                                                  GimpPlugInDef        *plug_in_def);
71
static GTokenType plug_in_help_def_deserialize   (GScanner             *scanner,
72
                                                  GimpPlugInDef        *plug_in_def);
73
static GTokenType plug_in_has_init_deserialize   (GScanner             *scanner,
74
                                                  GimpPlugInDef        *plug_in_def);
75 76 77 78


enum
{
79
  PROTOCOL_VERSION = 1,
80
  FILE_VERSION,
81
  PLUG_IN_DEF,
82 83
  PROC_DEF,
  LOCALE_DEF,
84
  HELP_DEF,
85
  HAS_INIT,
86
  PROC_ARG,
87
  MENU_PATH,
88
  ICON,
89 90
  LOAD_PROC,
  SAVE_PROC,
91 92 93
  EXTENSIONS,
  PREFIXES,
  MAGICS,
94
  PRIORITY,
95
  MIME_TYPES,
96
  HANDLES_URI,
97
  HANDLES_RAW,
98
  THUMB_LOADER
99 100 101
};


102
GSList *
103 104 105
plug_in_rc_parse (Gimp    *gimp,
                  GFile   *file,
                  GError **error)
106 107
{
  GScanner   *scanner;
108
  GEnumClass *enum_class;
109 110 111
  GSList     *plug_in_defs     = NULL;
  gint        protocol_version = GIMP_PROTOCOL_VERSION;
  gint        file_version     = PLUG_IN_RC_FILE_VERSION;
112 113
  GTokenType  token;

114
  g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
115
  g_return_val_if_fail (G_IS_FILE (file), NULL);
116
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
117

118
  scanner = gimp_scanner_new_gfile (file, error);
119

120
  if (! scanner)
121
    return NULL;
122

123 124
  enum_class = g_type_class_ref (GIMP_TYPE_ICON_TYPE);

125 126 127
  g_scanner_scope_add_symbol (scanner, 0,
                              "protocol-version",
                              GINT_TO_POINTER (PROTOCOL_VERSION));
128 129 130
  g_scanner_scope_add_symbol (scanner, 0,
                              "file-version",
                              GINT_TO_POINTER (FILE_VERSION));
131
  g_scanner_scope_add_symbol (scanner, 0,
132
                              "plug-in-def", GINT_TO_POINTER (PLUG_IN_DEF));
133

134
  g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF,
135
                              "proc-def", GINT_TO_POINTER (PROC_DEF));
136
  g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF,
137
                              "locale-def", GINT_TO_POINTER (LOCALE_DEF));
138
  g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF,
139
                              "help-def", GINT_TO_POINTER (HELP_DEF));
140
  g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF,
141
                              "has-init", GINT_TO_POINTER (HAS_INIT));
142
  g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF,
143
                              "proc-arg", GINT_TO_POINTER (PROC_ARG));
144 145
  g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF,
                              "menu-path", GINT_TO_POINTER (MENU_PATH));
146 147
  g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF,
                              "icon", GINT_TO_POINTER (ICON));
148
  g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF,
149
                              "load-proc", GINT_TO_POINTER (LOAD_PROC));
150
  g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF,
151 152 153
                              "save-proc", GINT_TO_POINTER (SAVE_PROC));

  g_scanner_scope_add_symbol (scanner, LOAD_PROC,
154
                              "extensions", GINT_TO_POINTER (EXTENSIONS));
155
  g_scanner_scope_add_symbol (scanner, LOAD_PROC,
156
                              "prefixes", GINT_TO_POINTER (PREFIXES));
157
  g_scanner_scope_add_symbol (scanner, LOAD_PROC,
158
                              "magics", GINT_TO_POINTER (MAGICS));
159 160
  g_scanner_scope_add_symbol (scanner, LOAD_PROC,
                              "priority", GINT_TO_POINTER (PRIORITY));
161
  g_scanner_scope_add_symbol (scanner, LOAD_PROC,
162
                              "mime-types", GINT_TO_POINTER (MIME_TYPES));
163 164
  g_scanner_scope_add_symbol (scanner, LOAD_PROC,
                              "handles-uri", GINT_TO_POINTER (HANDLES_URI));
165 166
  g_scanner_scope_add_symbol (scanner, LOAD_PROC,
                              "handles-raw", GINT_TO_POINTER (HANDLES_RAW));
167
  g_scanner_scope_add_symbol (scanner, LOAD_PROC,
168
                              "thumb-loader", GINT_TO_POINTER (THUMB_LOADER));
169

170
  g_scanner_scope_add_symbol (scanner, SAVE_PROC,
171
                              "extensions", GINT_TO_POINTER (EXTENSIONS));
172
  g_scanner_scope_add_symbol (scanner, SAVE_PROC,
173
                              "prefixes", GINT_TO_POINTER (PREFIXES));
174 175
  g_scanner_scope_add_symbol (scanner, SAVE_PROC,
                              "priority", GINT_TO_POINTER (PRIORITY));
176
  g_scanner_scope_add_symbol (scanner, SAVE_PROC,
177
                              "mime-types", GINT_TO_POINTER (MIME_TYPES));
178 179
  g_scanner_scope_add_symbol (scanner, SAVE_PROC,
                              "handles-uri", GINT_TO_POINTER (HANDLES_URI));
180

181
  token = G_TOKEN_LEFT_PAREN;
182

183 184
  while (protocol_version == GIMP_PROTOCOL_VERSION   &&
         file_version     == PLUG_IN_RC_FILE_VERSION &&
185
         g_scanner_peek_next_token (scanner) == token)
186
    {
187
      token = g_scanner_get_next_token (scanner);
188

189
      switch (token)
190
        {
191
        case G_TOKEN_LEFT_PAREN:
192 193 194
          token = G_TOKEN_SYMBOL;
          break;

195
        case G_TOKEN_SYMBOL:
196
          switch (GPOINTER_TO_INT (scanner->value.v_symbol))
197
            {
198 199
            case PROTOCOL_VERSION:
              token = G_TOKEN_INT;
200 201 202 203 204 205 206
              if (gimp_scanner_parse_int (scanner, &protocol_version))
                token = G_TOKEN_RIGHT_PAREN;
              break;

            case FILE_VERSION:
              token = G_TOKEN_INT;
              if (gimp_scanner_parse_int (scanner, &file_version))
207 208
                token = G_TOKEN_RIGHT_PAREN;
              break;
209

210
            case PLUG_IN_DEF:
211
              g_scanner_set_scope (scanner, PLUG_IN_DEF);
212
              token = plug_in_def_deserialize (gimp, scanner, &plug_in_defs);
213
              g_scanner_set_scope (scanner, 0);
214 215 216
              break;
            default:
              break;
217
            }
218
              break;
219

220 221 222
        case G_TOKEN_RIGHT_PAREN:
          token = G_TOKEN_LEFT_PAREN;
          break;
223

224 225 226 227
        default: /* do nothing */
          break;
        }
    }
228

229 230 231
  if (protocol_version != GIMP_PROTOCOL_VERSION   ||
      file_version     != PLUG_IN_RC_FILE_VERSION ||
      token            != G_TOKEN_LEFT_PAREN)
232
    {
233
      if (protocol_version != GIMP_PROTOCOL_VERSION)
234 235 236 237
        {
          g_set_error (error,
                       GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_VERSION,
                       _("Skipping '%s': wrong GIMP protocol version."),
238
                       gimp_file_get_utf8_name (file));
239
        }
240 241 242 243 244
      else if (file_version != PLUG_IN_RC_FILE_VERSION)
        {
          g_set_error (error,
                       GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_VERSION,
                       _("Skipping '%s': wrong pluginrc file format version."),
245
                       gimp_file_get_utf8_name (file));
246
        }
247
      else if (token != G_TOKEN_ERROR)
248 249 250 251 252 253
        {
          g_scanner_get_next_token (scanner);
          g_scanner_unexp_token (scanner, token, NULL, NULL, NULL,
                                 _("fatal parse error"), TRUE);
        }

254
      g_slist_free_full (plug_in_defs, (GDestroyNotify) g_object_unref);
255
      plug_in_defs = NULL;
256 257
    }

258 259
  g_type_class_unref (enum_class);

260
  gimp_scanner_destroy (scanner);
261

262
  return g_slist_reverse (plug_in_defs);
263 264 265
}

static GTokenType
266 267 268
plug_in_def_deserialize (Gimp      *gimp,
                         GScanner  *scanner,
                         GSList   **plug_in_defs)
269
{
270
  GimpPlugInDef       *plug_in_def;
271
  GimpPlugInProcedure *proc = NULL;
272
  gchar               *path;
273
  GFile               *file;
274
  gint64               mtime;
275
  GTokenType           token;
276
  GError              *error = NULL;
277

278
  if (! gimp_scanner_parse_string (scanner, &path))
279
    return G_TOKEN_STRING;
280

281 282 283 284 285 286
  if (! (path && *path))
    {
      g_scanner_error (scanner, "plug-in filename is empty");
      return G_TOKEN_ERROR;
    }

287
  file = gimp_file_new_for_config_path (path, &error);
288 289
  g_free (path);

290 291 292 293 294 295 296 297 298
  if (! file)
    {
      g_scanner_error (scanner,
                       "unable to parse plug-in filename: %s",
                       error->message);
      g_clear_error (&error);
      return G_TOKEN_ERROR;
    }

299 300 301
  plug_in_def = gimp_plug_in_def_new (file);
  g_object_unref (file);

302
  if (! gimp_scanner_parse_int64 (scanner, &mtime))
303
    {
304
      g_object_unref (plug_in_def);
305 306 307
      return G_TOKEN_INT;
    }

308 309
  plug_in_def->mtime = mtime;

310
  token = G_TOKEN_LEFT_PAREN;
311

312
  while (g_scanner_peek_next_token (scanner) == token)
313 314
    {
      token = g_scanner_get_next_token (scanner);
315

316
      switch (token)
317
        {
318 319
        case G_TOKEN_LEFT_PAREN:
          token = G_TOKEN_SYMBOL;
320
          break;
321

322 323 324 325
        case G_TOKEN_SYMBOL:
          switch (GPOINTER_TO_INT (scanner->value.v_symbol))
            {
            case PROC_DEF:
326
              token = plug_in_procedure_deserialize (scanner, gimp,
327
                                                     plug_in_def->file,
328
                                                     &proc);
329

330
              if (token == G_TOKEN_LEFT_PAREN)
331
                gimp_plug_in_def_add_procedure (plug_in_def, proc);
332 333

              if (proc)
334
                g_object_unref (proc);
335
              break;
336

337 338 339
            case LOCALE_DEF:
              token = plug_in_locale_def_deserialize (scanner, plug_in_def);
              break;
340

341 342 343
            case HELP_DEF:
              token = plug_in_help_def_deserialize (scanner, plug_in_def);
              break;
344

345 346 347
            case HAS_INIT:
              token = plug_in_has_init_deserialize (scanner, plug_in_def);
              break;
348 349 350

            default:
              break;
351
            }
352 353 354 355
          break;

        case G_TOKEN_RIGHT_PAREN:
          token = G_TOKEN_LEFT_PAREN;
356
          break;
357

358
        default:
359
          break;
360 361 362
        }
    }

363
  if (token == G_TOKEN_LEFT_PAREN)
364
    {
365
      token = G_TOKEN_RIGHT_PAREN;
366

367
      if (gimp_scanner_parse_token (scanner, token))
368
        {
369
          *plug_in_defs = g_slist_prepend (*plug_in_defs, plug_in_def);
370 371 372
          return G_TOKEN_LEFT_PAREN;
        }
    }
373

374
  g_object_unref (plug_in_def);
375

376 377 378 379
  return token;
}

static GTokenType
380 381
plug_in_procedure_deserialize (GScanner             *scanner,
                               Gimp                 *gimp,
382
                               GFile                *file,
383
                               GimpPlugInProcedure **proc)
384
{
385 386
  GimpProcedure   *procedure;
  GTokenType       token;
387
  gchar           *str;
388 389 390 391 392
  gint             proc_type;
  gint             n_args;
  gint             n_return_vals;
  gint             n_menu_paths;
  gint             i;
393

394
  if (! gimp_scanner_parse_string (scanner, &str))
395
    return G_TOKEN_STRING;
396

397 398 399 400 401 402
  if (! (str && *str))
    {
      g_scanner_error (scanner, "procedure name is empty");
      return G_TOKEN_ERROR;
    }

403
  if (! gimp_scanner_parse_int (scanner, &proc_type))
404 405 406 407 408
    {
      g_free (str);
      return G_TOKEN_INT;
    }

409 410 411 412 413 414 415 416 417
  if (proc_type != GIMP_PLUGIN &&
      proc_type != GIMP_EXTENSION)
    {
      g_free (str);
      g_scanner_error (scanner, "procedure type %d is out of range",
                       proc_type);
      return G_TOKEN_ERROR;
    }

418
  procedure = gimp_plug_in_procedure_new (proc_type, file);
419 420 421

  *proc = GIMP_PLUG_IN_PROCEDURE (procedure);

422 423 424
  gimp_object_take_name (GIMP_OBJECT (procedure),
                         gimp_canonicalize_identifier (str));

425
  procedure->original_name = str;
426

427
  if (! gimp_scanner_parse_string (scanner, &procedure->blurb))
428
    return G_TOKEN_STRING;
429
  if (! gimp_scanner_parse_string (scanner, &procedure->help))
430
    return G_TOKEN_STRING;
431
  if (! gimp_scanner_parse_string (scanner, &procedure->author))
432
    return G_TOKEN_STRING;
433
  if (! gimp_scanner_parse_string (scanner, &procedure->copyright))
434
    return G_TOKEN_STRING;
435
  if (! gimp_scanner_parse_string (scanner, &procedure->date))
436
    return G_TOKEN_STRING;
437
  if (! gimp_scanner_parse_string (scanner, &(*proc)->menu_label))
438
    return G_TOKEN_STRING;
439 440

  if (! gimp_scanner_parse_int (scanner, &n_menu_paths))
441
    return G_TOKEN_INT;
442 443 444

  for (i = 0; i < n_menu_paths; i++)
    {
445
      token = plug_in_menu_path_deserialize (scanner, *proc);
446 447 448 449
      if (token != G_TOKEN_LEFT_PAREN)
        return token;
    }

450
  token = plug_in_icon_deserialize (scanner, *proc);
451 452 453
  if (token != G_TOKEN_LEFT_PAREN)
    return token;

454
  token = plug_in_file_proc_deserialize (scanner, *proc);
455 456 457
  if (token != G_TOKEN_LEFT_PAREN)
    return token;

458
  if (! gimp_scanner_parse_string (scanner, &str))
459
    return G_TOKEN_STRING;
460

461
  gimp_plug_in_procedure_set_image_types (*proc, str);
462
  g_free (str);
463

464
  if (! gimp_scanner_parse_int (scanner, (gint *) &n_args))
465
    return G_TOKEN_INT;
466
  if (! gimp_scanner_parse_int (scanner, (gint *) &n_return_vals))
467
    return G_TOKEN_INT;
468

469
  for (i = 0; i < n_args; i++)
470
    {
471
      token = plug_in_proc_arg_deserialize (scanner, gimp, procedure, FALSE);
472
      if (token != G_TOKEN_LEFT_PAREN)
473 474 475
        return token;
    }

476
  for (i = 0; i < n_return_vals; i++)
477
    {
478
      token = plug_in_proc_arg_deserialize (scanner, gimp, procedure, TRUE);
479
      if (token != G_TOKEN_LEFT_PAREN)
480 481
        return token;
    }
482

483
  if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN))
484 485
    return G_TOKEN_RIGHT_PAREN;

486
  return G_TOKEN_LEFT_PAREN;
487 488
}

489
static GTokenType
490 491
plug_in_menu_path_deserialize (GScanner            *scanner,
                               GimpPlugInProcedure *proc)
492 493 494 495 496 497 498 499 500 501 502 503 504
{
  gchar *menu_path;

  if (! gimp_scanner_parse_token (scanner, G_TOKEN_LEFT_PAREN))
    return G_TOKEN_LEFT_PAREN;

  if (! gimp_scanner_parse_token (scanner, G_TOKEN_SYMBOL) ||
      GPOINTER_TO_INT (scanner->value.v_symbol) != MENU_PATH)
    return G_TOKEN_SYMBOL;

  if (! gimp_scanner_parse_string (scanner, &menu_path))
    return G_TOKEN_STRING;

505
  proc->menu_paths = g_list_append (proc->menu_paths, menu_path);
506 507 508 509 510 511 512

  if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN))
    return G_TOKEN_RIGHT_PAREN;

  return G_TOKEN_LEFT_PAREN;
}

513
static GTokenType
514 515
plug_in_icon_deserialize (GScanner            *scanner,
                          GimpPlugInProcedure *proc)
516 517 518 519 520
{
  GEnumClass   *enum_class;
  GEnumValue   *enum_value;
  GimpIconType  icon_type;
  gint          icon_data_length;
Sven Neumann's avatar
Sven Neumann committed
521 522
  gchar        *icon_name;
  guint8       *icon_data;
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578

  if (! gimp_scanner_parse_token (scanner, G_TOKEN_LEFT_PAREN))
    return G_TOKEN_LEFT_PAREN;

  if (! gimp_scanner_parse_token (scanner, G_TOKEN_SYMBOL) ||
      GPOINTER_TO_INT (scanner->value.v_symbol) != ICON)
    return G_TOKEN_SYMBOL;

  enum_class = g_type_class_peek (GIMP_TYPE_ICON_TYPE);

  switch (g_scanner_peek_next_token (scanner))
    {
    case G_TOKEN_IDENTIFIER:
      g_scanner_get_next_token (scanner);

      enum_value = g_enum_get_value_by_nick (G_ENUM_CLASS (enum_class),
                                             scanner->value.v_identifier);
      if (!enum_value)
        enum_value = g_enum_get_value_by_name (G_ENUM_CLASS (enum_class),
                                               scanner->value.v_identifier);

      if (!enum_value)
        {
          g_scanner_error (scanner,
                           _("invalid value '%s' for icon type"),
                           scanner->value.v_identifier);
          return G_TOKEN_NONE;
        }
      break;

    case G_TOKEN_INT:
      g_scanner_get_next_token (scanner);

      enum_value = g_enum_get_value (enum_class,
                                     (gint) scanner->value.v_int64);

      if (!enum_value)
        {
          g_scanner_error (scanner,
                           _("invalid value '%ld' for icon type"),
                           (glong) scanner->value.v_int64);
          return G_TOKEN_NONE;
        }
      break;

    default:
      return G_TOKEN_IDENTIFIER;
    }

  icon_type = enum_value->value;

  if (! gimp_scanner_parse_int (scanner, &icon_data_length))
    return G_TOKEN_INT;

  switch (icon_type)
    {
579
    case GIMP_ICON_TYPE_ICON_NAME:
580 581 582
    case GIMP_ICON_TYPE_IMAGE_FILE:
      icon_data_length = -1;

Sven Neumann's avatar
Sven Neumann committed
583
      if (! gimp_scanner_parse_string_no_validate (scanner, &icon_name))
584
        return G_TOKEN_STRING;
Sven Neumann's avatar
Sven Neumann committed
585

586
      icon_data = (guint8 *) icon_name;
587 588 589 590 591 592 593 594 595 596 597
      break;

    case GIMP_ICON_TYPE_INLINE_PIXBUF:
      if (icon_data_length < 0)
        return G_TOKEN_STRING;

      if (! gimp_scanner_parse_data (scanner, icon_data_length, &icon_data))
        return G_TOKEN_STRING;
      break;
    }

598 599
  gimp_plug_in_procedure_take_icon (proc, icon_type,
                                    icon_data, icon_data_length);
600 601 602 603 604 605 606

  if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN))
    return G_TOKEN_RIGHT_PAREN;

  return G_TOKEN_LEFT_PAREN;
}

607
static GTokenType
608 609
plug_in_file_proc_deserialize (GScanner            *scanner,
                               GimpPlugInProcedure *proc)
610
{
611 612
  GTokenType token;
  gint       symbol;
613

614 615 616 617 618 619 620 621 622 623
  if (! gimp_scanner_parse_token (scanner, G_TOKEN_LEFT_PAREN))
    return G_TOKEN_LEFT_PAREN;

  if (! gimp_scanner_parse_token (scanner, G_TOKEN_SYMBOL))
    return G_TOKEN_SYMBOL;

  symbol = GPOINTER_TO_INT (scanner->value.v_symbol);
  if (symbol != LOAD_PROC && symbol != SAVE_PROC)
    return G_TOKEN_SYMBOL;

624
  proc->file_proc = TRUE;
625 626 627

  g_scanner_set_scope (scanner, symbol);

628 629
  while (g_scanner_peek_next_token (scanner) == G_TOKEN_LEFT_PAREN)
    {
630
      token = g_scanner_get_next_token (scanner);
631

632 633
      if (token != G_TOKEN_LEFT_PAREN)
        return token;
634

635 636
      if (! gimp_scanner_parse_token (scanner, G_TOKEN_SYMBOL))
        return G_TOKEN_SYMBOL;
637

638 639 640 641
      symbol = GPOINTER_TO_INT (scanner->value.v_symbol);

      switch (symbol)
        {
642
        case EXTENSIONS:
643 644 645 646 647 648 649 650 651
          {
            gchar *extensions;

            if (! gimp_scanner_parse_string (scanner, &extensions))
              return G_TOKEN_STRING;

            g_free (proc->extensions);
            proc->extensions = extensions;
          }
652 653
          break;

654
        case PREFIXES:
655 656 657 658 659 660 661 662 663
          {
            gchar *prefixes;

            if (! gimp_scanner_parse_string (scanner, &prefixes))
              return G_TOKEN_STRING;

            g_free (proc->prefixes);
            proc->extensions = prefixes;
          }
664 665
          break;

666
        case MAGICS:
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686
          {
            gchar *magics;

            if (! gimp_scanner_parse_string_no_validate (scanner, &magics))
              return G_TOKEN_STRING;

            g_free (proc->magics);
            proc->magics = magics;
          }
          break;

        case PRIORITY:
          {
            gint priority;

            if (! gimp_scanner_parse_int (scanner, &priority))
              return G_TOKEN_INT;

            gimp_plug_in_procedure_set_priority (proc, priority);
          }
687 688
          break;

689
        case MIME_TYPES:
690 691 692 693 694 695 696 697 698 699
          {
            gchar *mime_types;

            if (! gimp_scanner_parse_string (scanner, &mime_types))
              return G_TOKEN_STRING;

            gimp_plug_in_procedure_set_mime_types (proc, mime_types);

            g_free (mime_types);
          }
700
          break;
701

702 703 704 705
        case HANDLES_URI:
          gimp_plug_in_procedure_set_handles_uri (proc);
          break;

706 707 708 709
        case HANDLES_RAW:
          gimp_plug_in_procedure_set_handles_raw (proc);
          break;

710
        case THUMB_LOADER:
711 712 713 714 715 716 717 718 719 720
          {
            gchar *thumb_loader;

            if (! gimp_scanner_parse_string (scanner, &thumb_loader))
              return G_TOKEN_STRING;

            gimp_plug_in_procedure_set_thumb_loader (proc, thumb_loader);

            g_free (thumb_loader);
          }
721 722 723 724 725 726 727 728
          break;

        default:
           return G_TOKEN_SYMBOL;
        }
      if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN))
        return G_TOKEN_RIGHT_PAREN;
    }
729

730 731 732 733 734
  if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN))
    return G_TOKEN_RIGHT_PAREN;

  g_scanner_set_scope (scanner, PLUG_IN_DEF);

735 736 737
  return G_TOKEN_LEFT_PAREN;
}

738
static GTokenType
739 740 741 742
plug_in_proc_arg_deserialize (GScanner      *scanner,
                              Gimp          *gimp,
                              GimpProcedure *procedure,
                              gboolean       return_value)
743
{
744 745 746 747
  GTokenType  token;
  gint        arg_type;
  gchar      *name = NULL;
  gchar      *desc = NULL;
748
  GParamSpec *pspec;
749

750
  if (! gimp_scanner_parse_token (scanner, G_TOKEN_LEFT_PAREN))
751 752 753 754
    {
      token = G_TOKEN_LEFT_PAREN;
      goto error;
    }
755

756
  if (! gimp_scanner_parse_token (scanner, G_TOKEN_SYMBOL) ||
757
      GPOINTER_TO_INT (scanner->value.v_symbol) != PROC_ARG)
758 759 760 761
    {
      token = G_TOKEN_SYMBOL;
      goto error;
    }
762

763 764 765 766 767 768 769 770 771 772 773 774 775 776 777
  if (! gimp_scanner_parse_int (scanner, (gint *) &arg_type))
    {
      token = G_TOKEN_INT;
      goto error;
    }
  if (! gimp_scanner_parse_string (scanner, &name))
    {
      token = G_TOKEN_STRING;
      goto error;
    }
  if (! gimp_scanner_parse_string (scanner, &desc))
    {
      token = G_TOKEN_STRING;
      goto error;
    }
778

779
  if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN))
780 781 782 783
    {
      token = G_TOKEN_RIGHT_PAREN;
      goto error;
    }
784

785 786
  token = G_TOKEN_LEFT_PAREN;

787 788
  pspec = gimp_pdb_compat_param_spec (gimp, arg_type, name, desc);

789
  if (return_value)
790
    gimp_procedure_add_return_value (procedure, pspec);
791
  else
792
    gimp_procedure_add_argument (procedure, pspec);
793 794 795 796 797 798 799

 error:

  g_free (name);
  g_free (desc);

  return token;
800 801 802
}

static GTokenType
803 804
plug_in_locale_def_deserialize (GScanner      *scanner,
                                GimpPlugInDef *plug_in_def)
805
{
806
  gchar *domain_name;
807 808
  gchar *domain_path   = NULL;
  gchar *expanded_path = NULL;
809

810
  if (! gimp_scanner_parse_string (scanner, &domain_name))
811 812
    return G_TOKEN_STRING;

813 814
  if (gimp_scanner_parse_string (scanner, &domain_path))
    expanded_path = gimp_config_path_expand (domain_path, TRUE, NULL);
815

816
  gimp_plug_in_def_set_locale_domain (plug_in_def, domain_name, expanded_path);
817 818 819

  g_free (domain_name);
  g_free (domain_path);
820
  g_free (expanded_path);
821

822
  if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN))
823 824
    return G_TOKEN_RIGHT_PAREN;

825
  return G_TOKEN_LEFT_PAREN;
826 827
}

828
static GTokenType
829 830
plug_in_help_def_deserialize (GScanner      *scanner,
                              GimpPlugInDef *plug_in_def)
831
{
832 833
  gchar *domain_name;
  gchar *domain_uri;
834

835
  if (! gimp_scanner_parse_string (scanner, &domain_name))
836 837
    return G_TOKEN_STRING;

838 839
  if (! gimp_scanner_parse_string (scanner, &domain_uri))
    domain_uri = NULL;
840

841 842 843 844
  gimp_plug_in_def_set_help_domain (plug_in_def, domain_name, domain_uri);

  g_free (domain_name);
  g_free (domain_uri);
845

846
  if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN))
847 848
    return G_TOKEN_RIGHT_PAREN;

849
  return G_TOKEN_LEFT_PAREN;
850 851
}

852
static GTokenType
853 854
plug_in_has_init_deserialize (GScanner      *scanner,
                              GimpPlugInDef *plug_in_def)
855
{
856
  gimp_plug_in_def_set_has_init (plug_in_def, TRUE);
857

858
  if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN))
859 860 861 862 863
    return G_TOKEN_RIGHT_PAREN;

  return G_TOKEN_LEFT_PAREN;
}

864

865 866 867
/* serialize functions */

gboolean
868 869 870
plug_in_rc_write (GSList  *plug_in_defs,
                  GFile   *file,
                  GError **error)
871
{
872
  GimpConfigWriter *writer;
873
  GEnumClass       *enum_class;
874 875
  GSList           *list;

876 877 878 879 880
  writer = gimp_config_writer_new_gfile (file,
                                         FALSE,
                                         "GIMP pluginrc\n\n"
                                         "This file can safely be removed and "
                                         "will be automatically regenerated by "
881
                                         "querying the installed plug-ins.",
882
                                         error);
883
  if (!writer)
884 885
    return FALSE;

886 887
  enum_class = g_type_class_ref (GIMP_TYPE_ICON_TYPE);

888 889 890
  gimp_config_writer_open (writer, "protocol-version");
  gimp_config_writer_printf (writer, "%d", GIMP_PROTOCOL_VERSION);
  gimp_config_writer_close (writer);
891 892 893 894 895

  gimp_config_writer_open (writer, "file-version");
  gimp_config_writer_printf (writer, "%d", PLUG_IN_RC_FILE_VERSION);
  gimp_config_writer_close (writer);

896 897
  gimp_config_writer_linefeed (writer);

898 899
  for (list = plug_in_defs; list; list = list->next)
    {
900
      GimpPlugInDef *plug_in_def = list->data;
901

902
      if (plug_in_def->procedures)
903
        {
904
          GSList *list2;
905
          gchar  *path;
906

907 908
          path = gimp_file_get_config_path (plug_in_def->file, NULL);
          if (! path)
909
            continue;
910

911
          gimp_config_writer_open (writer, "plug-in-def");
912
          gimp_config_writer_string (writer, path);
913 914
          gimp_config_writer_printf (writer, "%"G_GINT64_FORMAT,
                                     plug_in_def->mtime);
915

916
          g_free (path);
917

918 919
          for (list2 = plug_in_def->procedures; list2; list2 = list2->next)
            {
920 921 922 923 924
              GimpPlugInProcedure *proc      = list2->data;
              GimpProcedure       *procedure = GIMP_PROCEDURE (proc);
              GEnumValue          *enum_value;
              GList               *list3;
              gint                 i;
925

926 927
              if (proc->installed_during_init)
                continue;
928

929 930
              gimp_config_writer_open (writer, "proc-def");
              gimp_config_writer_printf (writer, "\"%s\" %d",
931 932
                                         procedure->original_name,
                                         procedure->proc_type);
933
              gimp_config_writer_linefeed (writer);
934
              gimp_config_writer_string (writer, procedure->blurb);
935
              gimp_config_writer_linefeed (writer);
936 937 938 939 940 941 942 943 944 945
              gimp_config_writer_string (writer, procedure->help);
              gimp_config_writer_linefeed (writer);
              gimp_config_writer_string (writer, procedure->author);
              gimp_config_writer_linefeed (writer);
              gimp_config_writer_string (writer, procedure->copyright);
              gimp_config_writer_linefeed (writer);
              gimp_config_writer_string (writer, procedure->date);
              gimp_config_writer_linefeed (writer);
              gimp_config_writer_string (writer, proc->menu_label);
              gimp_config_writer_linefeed (writer);
946 947

              gimp_config_writer_printf (writer, "%d",
948 949
                                         g_list_length (proc->menu_paths));
              for (list3 = proc->menu_paths; list3; list3 = list3->next)
950 951 952 953 954
                {
                  gimp_config_writer_open (writer, "menu-path");
                  gimp_config_writer_string (writer, list3->data);
                  gimp_config_writer_close (writer);
                }
955 956

              gimp_config_writer_open (writer, "icon");
957
              enum_value = g_enum_get_value (enum_class, proc->icon_type);
958 959
              gimp_config_writer_identifier (writer, enum_value->value_nick);
              gimp_config_writer_printf (writer, "%d",
960
                                         proc->icon_data_length);
961

962
              switch (proc->icon_type)
963
                {
964
                case GIMP_ICON_TYPE_ICON_NAME:
965
                case GIMP_ICON_TYPE_IMAGE_FILE:
966
                  gimp_config_writer_string (writer, (gchar *) proc->icon_data);
967 968 969
                  break;

                case GIMP_ICON_TYPE_INLINE_PIXBUF:
970 971
                  gimp_config_writer_data (writer, proc->icon_data_length,
                                           proc->icon_data);
972 973 974 975 976
                  break;
                }

              gimp_config_writer_close (writer);

977
              if (proc->file_proc)
978 979
                {
                  gimp_config_writer_open (writer,
980
                                           proc->image_types ?
981 982
                                           "save-proc" : "load-proc");

983
                  if (proc->extensions && *proc->extensions)
984
                    {
985
                      gimp_config_writer_open (writer, "extensions");
986
                      gimp_config_writer_string (writer, proc->extensions);
987 988 989
                      gimp_config_writer_close (writer);
                    }

990
                  if (proc->prefixes && *proc->prefixes)
991
                    {
992
                      gimp_config_writer_open (writer, "prefixes");
993
                      gimp_config_writer_string (writer, proc->prefixes);
994 995 996
                      gimp_config_writer_close (writer);
                    }

997
                  if (proc->magics && *proc->magics)
998
                    {
999
                      gimp_config_writer_open (writer, "magics");
1000
                      gimp_config_writer_string (writer, proc->magics);
1001 1002 1003
                      gimp_config_writer_close (writer);
                    }

1004 1005 1006 1007 1008 1009 1010
                  if (proc->priority)
                    {
                      gimp_config_writer_open (writer, "priority");
                      gimp_config_writer_printf (writer, "%d", proc->priority);
                      gimp_config_writer_close (writer);
                    }

1011
                  if (proc->mime_types && *proc->mime_types)
1012
                    {
1013 1014
                      gimp_config_writer_open (writer, "mime-types");
                      gimp_config_writer_string (writer, proc->mime_types);
1015 1016 1017
                      gimp_config_writer_close (writer);
                    }

1018 1019 1020 1021 1022 1023 1024
                  if (proc->priority)
                    {
                      gimp_config_writer_open (writer, "priority");
                      gimp_config_writer_printf (writer, "%d", proc->priority);
                      gimp_config_writer_close (writer);
                    }

1025 1026 1027 1028 1029 1030
                  if (proc->handles_uri)
                    {
                      gimp_config_writer_open (writer, "handles-uri");
                      gimp_config_writer_close (writer);
                    }

1031 1032 1033 1034 1035 1036
                  if (proc->handles_raw && ! proc->image_types)
                    {
                      gimp_config_writer_open (writer, "handles-raw");
                      gimp_config_writer_close (writer);
                    }

1037
                  if (proc->thumb_loader)
1038 1039
                    {
                      gimp_config_writer_open (writer, "thumb-loader");
1040
                      gimp_config_writer_string (writer, proc->thumb_loader);
1041 1042 1043 1044 1045 1046
                      gimp_config_writer_close (writer);
                    }

                  gimp_config_writer_close (writer);
                }

1047 1048
              gimp_config_writer_linefeed (writer);

1049 1050
              gimp_config_writer_string (writer, proc->image_types);
              gimp_config_writer_linefeed (writer);
1051

1052
              gimp_config_writer_printf (writer, "%d %d",
1053 1054
                                         procedure->num_args,
                                         procedure->num_values);
1055

1056 1057
              for (i = 0; i < procedure->num_args; i++)
                {
1058
                  GParamSpec *pspec = procedure->args[i];
1059

1060 1061
                  gimp_config_writer_open (writer, "proc-arg");
                  gimp_config_writer_printf (writer, "%d",
1062
                                             gimp_pdb_compat_arg_type_from_gtype (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1063

1064
                  gimp_config_writer_string (writer,
1065
                                             g_param_spec_get_name (pspec));
1066
                  gimp_config_writer_string (writer,
1067
                                             g_param_spec_get_blurb (pspec));
1068

1069
                  gimp_config_writer_close (writer);
1070
                }
1071

1072 1073
              for (i = 0; i < procedure->num_values; i++)
                {
1074
                  GParamSpec *pspec = procedure->values[i];
1075

1076
                  gimp_config_writer_open (writer, "proc-arg");
1077
                  gimp_config_writer_printf (writer, "%d",
1078
                                             gimp_pdb_compat_arg_type_from_gtype (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1079

1080
                  gimp_config_writer_string (writer,
1081
                                             g_param_spec_get_name (pspec));
1082
                  gimp_config_writer_string (writer,
1083
                                             g_param_spec_get_blurb (pspec));
1084

1085
                  gimp_config_writer_close (writer);
1086
                }
1087

1088 1089
              gimp_config_writer_close (writer);
            }
1090

1091 1092
          if (plug_in_def->locale_domain_name)
            {
1093
              gimp_config_writer_open (writer, "locale-def");
1094 1095
              gimp_config_writer_string (writer,
                                         plug_in_def->locale_domain_name);
1096

1097
              if (plug_in_def->locale_domain_path)
1098 1099 1100 1101 1102 1103 1104 1105 1106
                {
                  path = gimp_config_path_unexpand (plug_in_def->locale_domain_path,
                                                    TRUE, NULL);
                  if (path)
                    {
                      gimp_config_writer_string (writer, path);
                      g_free (path);
                    }
                }
1107 1108

              gimp_config_writer_close (writer);
1109
            }
1110

1111 1112 1113
          if (plug_in_def->help_domain_name)
            {
              gimp_config_writer_open (writer, "help-def");
1114 1115
              gimp_config_writer_string (writer,
                                         plug_in_def->help_domain_name);
1116

1117 1118
              if (plug_in_def->help_domain_uri)
                gimp_config_writer_string (writer,
1119 1120 1121
                                           plug_in_def->help_domain_uri);

             gimp_config_writer_close (writer);
1122
            }
1123

1124 1125 1126
          if (plug_in_def->has_init)
            {
              gimp_config_writer_open (writer, "has-init");
1127
              gimp_config_writer_close (writer);
1128
            }
1129

1130 1131
          gimp_config_writer_close (writer);
        }
1132 1133
    }

1134 1135
  g_type_class_unref (enum_class);

1136
  return gimp_config_writer_finish (writer, "end of pluginrc", error);
1137