~ubuntu-branches/ubuntu/jaunty/gimp/jaunty-security

« back to all changes in this revision

Viewing changes to app/xcf/xcf.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2007-05-02 16:33:03 UTC
  • mto: This revision was merged to the branch mainline in revision 12.
  • Revision ID: james.westby@ubuntu.com-20070502163303-6wchheivjxgjtlna
Tags: upstream-2.3.16
ImportĀ upstreamĀ versionĀ 2.3.16

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* The GIMP -- an image manipulation program
 
1
/* GIMP - The GNU Image Manipulation Program
2
2
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3
3
 *
4
4
 * This program is free software; you can redistribute it and/or modify
19
19
#include "config.h"
20
20
 
21
21
#include <errno.h>
22
 
#include <stdio.h>
23
22
#include <stdlib.h>
24
23
#include <string.h>
25
24
 
26
25
#include <glib-object.h>
 
26
#include <glib/gstdio.h>
27
27
 
28
28
#include "libgimpbase/gimpbase.h"
29
29
 
31
31
 
32
32
#include "core/gimp.h"
33
33
#include "core/gimpimage.h"
34
 
 
35
 
#include "pdb/procedural_db.h"
36
 
 
37
 
#include "plug-in/plug-ins.h"
38
 
#include "plug-in/plug-in-proc-def.h"
 
34
#include "core/gimpparamspecs.h"
 
35
#include "core/gimpprogress.h"
 
36
 
 
37
#include "plug-in/gimppluginmanager.h"
 
38
#include "plug-in/gimppluginprocedure.h"
39
39
 
40
40
#include "xcf.h"
41
41
#include "xcf-private.h"
47
47
 
48
48
 
49
49
typedef GimpImage * GimpXcfLoaderFunc (Gimp    *gimp,
50
 
                                       XcfInfo *info);
51
 
 
52
 
 
53
 
static Argument * xcf_load_invoker (Gimp         *gimp,
54
 
                                    GimpContext  *context,
55
 
                                    GimpProgress *progress,
56
 
                                    Argument     *args);
57
 
static Argument * xcf_save_invoker (Gimp         *gimp,
58
 
                                    GimpContext  *context,
59
 
                                    GimpProgress *progress,
60
 
                                    Argument     *args);
61
 
 
62
 
 
63
 
static ProcArg xcf_load_args[] =
64
 
{
65
 
  { GIMP_PDB_INT32,
66
 
    "dummy_param",
67
 
    "dummy parameter" },
68
 
  { GIMP_PDB_STRING,
69
 
    "filename",
70
 
    "The name of the file to load, in the on-disk character set and encoding" },
71
 
  { GIMP_PDB_STRING,
72
 
    "raw_filename",
73
 
    "The basename of the file, in UTF-8" }
74
 
};
75
 
 
76
 
static ProcArg xcf_load_return_vals[] =
77
 
{
78
 
  { GIMP_PDB_IMAGE,
79
 
    "image",
80
 
    "Output image" }
81
 
};
82
 
 
83
 
static PlugInProcDef xcf_plug_in_load_proc =
84
 
{
85
 
  "gimp_xcf_load",
86
 
  N_("GIMP XCF image"),
87
 
  NULL,
88
 
  GIMP_ICON_TYPE_STOCK_ID,
89
 
  -1,
90
 
  "gimp-wilber",
91
 
  NULL, /* ignored for load */
92
 
  0,    /* ignored for load */
93
 
  0,
94
 
  FALSE,
95
 
  {
96
 
    "gimp_xcf_load",
97
 
    "loads file saved in the .xcf file format",
98
 
    "The xcf file format has been designed specifically for loading and "
99
 
    "saving tiled and layered images in the GIMP. This procedure will load "
100
 
    "the specified file.",
101
 
    "Spencer Kimball & Peter Mattis",
102
 
    "Spencer Kimball & Peter Mattis",
103
 
    "1995-1996",
104
 
    NULL,
105
 
    GIMP_INTERNAL,
106
 
    3,
107
 
    xcf_load_args,
108
 
    1,
109
 
    xcf_load_return_vals,
110
 
    { { xcf_load_invoker } },
111
 
  },
112
 
  "xcf",
113
 
  "",
114
 
  "0,string,gimp\\040xcf\\040",
115
 
  "image/x-xcf",
116
 
  NULL, /* fill me in at runtime */
117
 
  NULL, /* fill me in at runtime */
118
 
  NULL  /* fill me in at runtime */
119
 
};
120
 
 
121
 
static ProcArg xcf_save_args[] =
122
 
{
123
 
  { GIMP_PDB_INT32,
124
 
    "dummy_param",
125
 
    "dummy parameter" },
126
 
  { GIMP_PDB_IMAGE,
127
 
    "image",
128
 
    "Input image" },
129
 
  { GIMP_PDB_DRAWABLE,
130
 
    "drawable",
131
 
    "Active drawable of input image" },
132
 
  { GIMP_PDB_STRING,
133
 
    "filename",
134
 
    "The name of the file to save the image in, in the on-disk character set and encoding" },
135
 
  { GIMP_PDB_STRING,
136
 
    "raw_filename",
137
 
    "The basename of the file, in UTF-8" }
138
 
};
139
 
 
140
 
static PlugInProcDef xcf_plug_in_save_proc =
141
 
{
142
 
  "gimp_xcf_save",
143
 
  N_("GIMP XCF image"),
144
 
  NULL,
145
 
  GIMP_ICON_TYPE_STOCK_ID,
146
 
  -1,
147
 
  "gimp-wilber",
148
 
  "RGB*, GRAY*, INDEXED*",
149
 
  0, /* fill me in at runtime */
150
 
  0,
151
 
  FALSE,
152
 
  {
153
 
    "gimp_xcf_save",
154
 
    "saves file in the .xcf file format",
155
 
    "The xcf file format has been designed specifically for loading and "
156
 
    "saving tiled and layered images in the GIMP. This procedure will save "
157
 
    "the specified image in the xcf file format.",
158
 
    "Spencer Kimball & Peter Mattis",
159
 
    "Spencer Kimball & Peter Mattis",
160
 
    "1995-1996",
161
 
    NULL,
162
 
    GIMP_INTERNAL,
163
 
    5,
164
 
    xcf_save_args,
165
 
    0,
166
 
    NULL,
167
 
    { { xcf_save_invoker } },
168
 
  },
169
 
  "xcf",
170
 
  "",
171
 
  NULL,
172
 
  "image/x-xcf",
173
 
  NULL, /* fill me in at runtime */
174
 
  NULL, /* fill me in at runtime */
175
 
  NULL  /* fill me in at runtime */
176
 
};
177
 
 
178
 
 
179
 
static GimpXcfLoaderFunc *xcf_loaders[] =
 
50
                                       XcfInfo *info);
 
51
 
 
52
 
 
53
static GValueArray * xcf_load_invoker (GimpProcedure     *procedure,
 
54
                                       Gimp              *gimp,
 
55
                                       GimpContext       *context,
 
56
                                       GimpProgress      *progress,
 
57
                                       const GValueArray *args);
 
58
static GValueArray * xcf_save_invoker (GimpProcedure     *procedure,
 
59
                                       Gimp              *gimp,
 
60
                                       GimpContext       *context,
 
61
                                       GimpProgress      *progress,
 
62
                                       const GValueArray *args);
 
63
 
 
64
 
 
65
static GimpXcfLoaderFunc * const xcf_loaders[] =
180
66
{
181
67
  xcf_load_image,   /* version 0 */
182
68
  xcf_load_image,   /* version 1 */
187
73
void
188
74
xcf_init (Gimp *gimp)
189
75
{
 
76
  GimpPlugInProcedure *proc;
 
77
  GimpProcedure       *procedure;
 
78
 
190
79
  g_return_if_fail (GIMP_IS_GIMP (gimp));
191
80
 
192
81
  /* So this is sort of a hack, but its better than it was before.  To
197
86
   * though they are internal.  The only thing it requires is using a
198
87
   * PlugInProcDef struct.  -josh
199
88
   */
200
 
  procedural_db_register (gimp, &xcf_plug_in_save_proc.db_info);
201
 
  xcf_plug_in_save_proc.image_types_val =
202
 
    plug_ins_image_types_parse (xcf_plug_in_save_proc.image_types);
203
 
  plug_ins_add_internal (gimp, &xcf_plug_in_save_proc);
204
 
 
205
 
  procedural_db_register (gimp, &xcf_plug_in_load_proc.db_info);
206
 
  xcf_plug_in_load_proc.image_types_val =
207
 
    plug_ins_image_types_parse (xcf_plug_in_load_proc.image_types);
208
 
  plug_ins_add_internal (gimp, &xcf_plug_in_load_proc);
 
89
 
 
90
  /*  gimp-xcf-save  */
 
91
  procedure = gimp_plug_in_procedure_new (GIMP_PLUGIN, "gimp-xcf-save");
 
92
  procedure->proc_type    = GIMP_INTERNAL;
 
93
  procedure->marshal_func = xcf_save_invoker;
 
94
 
 
95
  proc = GIMP_PLUG_IN_PROCEDURE (procedure);
 
96
  proc->menu_label = g_strdup (N_("GIMP XCF image"));
 
97
  gimp_plug_in_procedure_set_icon (proc, GIMP_ICON_TYPE_STOCK_ID,
 
98
                                   (const guint8 *) "gimp-wilber",
 
99
                                   strlen ("gimp-wilber") + 1);
 
100
  gimp_plug_in_procedure_set_image_types (proc, "RGB*, GRAY*, INDEXED*");
 
101
  gimp_plug_in_procedure_set_file_proc (proc, "xcf", "", NULL);
 
102
  gimp_plug_in_procedure_set_mime_type (proc, "image/xcf");
 
103
 
 
104
  gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-xcf-save");
 
105
  gimp_procedure_set_static_strings (procedure,
 
106
                                     "gimp-xcf-save",
 
107
                                     "Saves file in the .xcf file format",
 
108
                                     "The XCF file format has been designed "
 
109
                                     "specifically for loading and saving "
 
110
                                     "tiled and layered images in the GIMP. "
 
111
                                     "This procedure will save the specified "
 
112
                                     "image in the xcf file format.",
 
113
                                     "Spencer Kimball & Peter Mattis",
 
114
                                     "Spencer Kimball & Peter Mattis",
 
115
                                     "1995-1996",
 
116
                                     NULL);
 
117
 
 
118
  gimp_procedure_add_argument (procedure,
 
119
                               gimp_param_spec_int32 ("dummy-param",
 
120
                                                      "Dummy Param",
 
121
                                                      "Dummy parameter",
 
122
                                                      G_MININT32, G_MAXINT32, 0,
 
123
                                                      GIMP_PARAM_READWRITE));
 
124
  gimp_procedure_add_argument (procedure,
 
125
                               gimp_param_spec_image_id ("image",
 
126
                                                         "Image",
 
127
                                                         "Input image",
 
128
                                                         gimp, FALSE,
 
129
                                                         GIMP_PARAM_READWRITE));
 
130
  gimp_procedure_add_argument (procedure,
 
131
                               gimp_param_spec_drawable_id ("drawable",
 
132
                                                            "Drawable",
 
133
                                                            "Active drawable of input image",
 
134
                                                            gimp, TRUE,
 
135
                                                            GIMP_PARAM_READWRITE));
 
136
  gimp_procedure_add_argument (procedure,
 
137
                               gimp_param_spec_string ("filename",
 
138
                                                       "Filename",
 
139
                                                       "The name of the file "
 
140
                                                       "to save the image in, "
 
141
                                                       "in the on-disk "
 
142
                                                       "character set and "
 
143
                                                       "encoding",
 
144
                                                       TRUE, FALSE, NULL,
 
145
                                                       GIMP_PARAM_READWRITE));
 
146
  gimp_procedure_add_argument (procedure,
 
147
                               gimp_param_spec_string ("raw-filename",
 
148
                                                       "Raw filename",
 
149
                                                       "The basename of the "
 
150
                                                       "file, in UTF-8",
 
151
                                                       FALSE, FALSE, NULL,
 
152
                                                       GIMP_PARAM_READWRITE));
 
153
  gimp_plug_in_manager_add_procedure (gimp->plug_in_manager, proc);
 
154
  g_object_unref (procedure);
 
155
 
 
156
  /*  gimp-xcf-load  */
 
157
  procedure = gimp_plug_in_procedure_new (GIMP_PLUGIN, "gimp-xcf-load");
 
158
  procedure->proc_type    = GIMP_INTERNAL;
 
159
  procedure->marshal_func = xcf_load_invoker;
 
160
 
 
161
  proc = GIMP_PLUG_IN_PROCEDURE (procedure);
 
162
  proc->menu_label = g_strdup (N_("GIMP XCF image"));
 
163
  gimp_plug_in_procedure_set_icon (proc, GIMP_ICON_TYPE_STOCK_ID,
 
164
                                   (const guint8 *) "gimp-wilber",
 
165
                                   strlen ("gimp-wilber") + 1);
 
166
  gimp_plug_in_procedure_set_image_types (proc, NULL);
 
167
  gimp_plug_in_procedure_set_file_proc (proc, "xcf", "",
 
168
                                        "0,string,gimp\\040xcf\\040");
 
169
  gimp_plug_in_procedure_set_mime_type (proc, "image/xcf");
 
170
 
 
171
  gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-xcf-load");
 
172
  gimp_procedure_set_static_strings (procedure,
 
173
                                     "gimp-xcf-load",
 
174
                                     "Loads file saved in the .xcf file format",
 
175
                                     "The XCF file format has been designed "
 
176
                                     "specifically for loading and saving "
 
177
                                     "tiled and layered images in the GIMP. "
 
178
                                     "This procedure will load the specified "
 
179
                                     "file.",
 
180
                                     "Spencer Kimball & Peter Mattis",
 
181
                                     "Spencer Kimball & Peter Mattis",
 
182
                                     "1995-1996",
 
183
                                     NULL);
 
184
 
 
185
  gimp_procedure_add_argument (procedure,
 
186
                               gimp_param_spec_int32 ("dummy-param",
 
187
                                                      "Dummy Param",
 
188
                                                      "Dummy parameter",
 
189
                                                      G_MININT32, G_MAXINT32, 0,
 
190
                                                      GIMP_PARAM_READWRITE));
 
191
  gimp_procedure_add_argument (procedure,
 
192
                               gimp_param_spec_string ("filename",
 
193
                                                       "Filename",
 
194
                                                       "The name of the file "
 
195
                                                       "to load, in the "
 
196
                                                       "on-disk character "
 
197
                                                       "set and encoding",
 
198
                                                       TRUE, FALSE, NULL,
 
199
                                                       GIMP_PARAM_READWRITE));
 
200
  gimp_procedure_add_argument (procedure,
 
201
                               gimp_param_spec_string ("raw-filename",
 
202
                                                       "Raw filename",
 
203
                                                       "The basename of the "
 
204
                                                       "file, in UTF-8",
 
205
                                                       FALSE, FALSE, NULL,
 
206
                                                       GIMP_PARAM_READWRITE));
 
207
 
 
208
  gimp_procedure_add_return_value (procedure,
 
209
                                   gimp_param_spec_image_id ("image",
 
210
                                                             "Image",
 
211
                                                             "Output image",
 
212
                                                             gimp, FALSE,
 
213
                                                             GIMP_PARAM_READWRITE));
 
214
  gimp_plug_in_manager_add_procedure (gimp->plug_in_manager, proc);
 
215
  g_object_unref (procedure);
209
216
}
210
217
 
211
218
void
214
221
  g_return_if_fail (GIMP_IS_GIMP (gimp));
215
222
}
216
223
 
217
 
static Argument*
218
 
xcf_load_invoker (Gimp         *gimp,
219
 
                  GimpContext  *context,
220
 
                  GimpProgress *progress,
221
 
                  Argument     *args)
 
224
static GValueArray *
 
225
xcf_load_invoker (GimpProcedure     *procedure,
 
226
                  Gimp              *gimp,
 
227
                  GimpContext       *context,
 
228
                  GimpProgress      *progress,
 
229
                  const GValueArray *args)
222
230
{
223
231
  XcfInfo      info;
224
 
  Argument    *return_args;
225
 
  GimpImage   *gimage   = NULL;
 
232
  GValueArray *return_vals;
 
233
  GimpImage   *image   = NULL;
226
234
  const gchar *filename;
227
 
  gboolean     success  = FALSE;
 
235
  gboolean     success = FALSE;
228
236
  gchar        id[14];
229
237
 
230
238
  gimp_set_busy (gimp);
231
239
 
232
 
  filename = args[1].value.pdb_pointer;
 
240
  filename = g_value_get_string (&args->values[1]);
233
241
 
234
 
  info.fp = fopen (filename, "rb");
 
242
  info.fp = g_fopen (filename, "rb");
235
243
 
236
244
  if (info.fp)
237
245
    {
 
246
      info.gimp                  = gimp;
 
247
      info.progress              = progress;
238
248
      info.cp                    = 0;
239
249
      info.filename              = filename;
240
250
      info.tattoo_state          = 0;
247
257
      info.ref_count             = NULL;
248
258
      info.compression           = COMPRESS_NONE;
249
259
 
 
260
      if (progress)
 
261
        {
 
262
          gchar *name = g_filename_display_name (filename);
 
263
          gchar *msg  = g_strdup_printf (_("Opening '%s'"), name);
 
264
 
 
265
          gimp_progress_start (progress, msg, FALSE);
 
266
 
 
267
          g_free (msg);
 
268
          g_free (name);
 
269
        }
 
270
 
250
271
      success = TRUE;
251
272
 
252
 
      info.cp += xcf_read_int8 (info.fp, (guint8*) id, 14);
 
273
      info.cp += xcf_read_int8 (info.fp, (guint8 *) id, 14);
253
274
 
254
 
      if (strncmp (id, "gimp xcf ", 9) != 0)
255
 
        {
256
 
          success = FALSE;
257
 
        }
258
 
      else if (strcmp (id+9, "file") == 0)
259
 
        {
260
 
          info.file_version = 0;
261
 
        }
 
275
      if (! g_str_has_prefix (id, "gimp xcf "))
 
276
        {
 
277
          success = FALSE;
 
278
        }
 
279
      else if (strcmp (id + 9, "file") == 0)
 
280
        {
 
281
          info.file_version = 0;
 
282
        }
262
283
      else if (id[9] == 'v')
263
 
        {
264
 
          info.file_version = atoi (id + 10);
265
 
        }
 
284
        {
 
285
          info.file_version = atoi (id + 10);
 
286
        }
266
287
      else
267
 
        {
268
 
          success = FALSE;
269
 
        }
 
288
        {
 
289
          success = FALSE;
 
290
        }
270
291
 
271
292
      if (success)
272
 
        {
273
 
          if (info.file_version < G_N_ELEMENTS (xcf_loaders))
274
 
            {
275
 
              gimage = (*(xcf_loaders[info.file_version])) (gimp, &info);
 
293
        {
 
294
          if (info.file_version >= 0 &&
 
295
              info.file_version < G_N_ELEMENTS (xcf_loaders))
 
296
            {
 
297
              image = (*(xcf_loaders[info.file_version])) (gimp, &info);
276
298
 
277
 
              if (! gimage)
278
 
                success = FALSE;
279
 
            }
280
 
          else
281
 
            {
282
 
              g_message (_("XCF error: unsupported XCF file version %d "
283
 
                           "encountered"), info.file_version);
284
 
              success = FALSE;
285
 
            }
286
 
        }
 
299
              if (! image)
 
300
                success = FALSE;
 
301
            }
 
302
          else
 
303
            {
 
304
              gimp_message (gimp, G_OBJECT (progress), GIMP_MESSAGE_ERROR,
 
305
                            _("XCF error: unsupported XCF file version %d "
 
306
                              "encountered"), info.file_version);
 
307
              success = FALSE;
 
308
            }
 
309
        }
287
310
 
288
311
      fclose (info.fp);
 
312
 
 
313
      if (progress)
 
314
        gimp_progress_end (progress);
289
315
    }
290
316
  else
291
 
    g_message (_("Could not open '%s' for reading: %s"),
292
 
               gimp_filename_to_utf8 (filename), g_strerror (errno));
 
317
    {
 
318
      gimp_message (gimp, G_OBJECT (progress), GIMP_MESSAGE_ERROR,
 
319
                    _("Could not open '%s' for reading: %s"),
 
320
                    gimp_filename_to_utf8 (filename), g_strerror (errno));
 
321
    }
293
322
 
294
 
  return_args = procedural_db_return_args (&xcf_plug_in_load_proc.db_info,
295
 
                                           success);
 
323
  return_vals = gimp_procedure_get_return_values (procedure, success);
296
324
 
297
325
  if (success)
298
 
    return_args[1].value.pdb_int = gimp_image_get_ID (gimage);
 
326
    gimp_value_set_image (&return_vals->values[1], image);
299
327
 
300
328
  gimp_unset_busy (gimp);
301
329
 
302
 
  return return_args;
 
330
  return return_vals;
303
331
}
304
332
 
305
 
static Argument *
306
 
xcf_save_invoker (Gimp         *gimp,
307
 
                  GimpContext  *context,
308
 
                  GimpProgress *progress,
309
 
                  Argument     *args)
 
333
static GValueArray *
 
334
xcf_save_invoker (GimpProcedure     *procedure,
 
335
                  Gimp              *gimp,
 
336
                  GimpContext       *context,
 
337
                  GimpProgress      *progress,
 
338
                  const GValueArray *args)
310
339
{
311
340
  XcfInfo      info;
312
 
  Argument    *return_args;
313
 
  GimpImage   *gimage;
 
341
  GValueArray *return_vals;
 
342
  GimpImage   *image;
314
343
  const gchar *filename;
315
 
  gboolean     success  = FALSE;
 
344
  gboolean     success = FALSE;
316
345
 
317
346
  gimp_set_busy (gimp);
318
347
 
319
 
  gimage   = gimp_image_get_by_ID (gimp, args[1].value.pdb_int);
320
 
  filename = args[3].value.pdb_pointer;
 
348
  image    = gimp_value_get_image (&args->values[1], gimp);
 
349
  filename = g_value_get_string (&args->values[3]);
321
350
 
322
 
  info.fp = fopen (filename, "wb");
 
351
  info.fp = g_fopen (filename, "wb");
323
352
 
324
353
  if (info.fp)
325
354
    {
 
355
      info.gimp                  = gimp;
 
356
      info.progress              = progress;
326
357
      info.cp                    = 0;
327
358
      info.filename              = filename;
328
359
      info.active_layer          = NULL;
334
365
      info.ref_count             = NULL;
335
366
      info.compression           = COMPRESS_RLE;
336
367
 
337
 
      xcf_save_choose_format (&info, gimage);
338
 
 
339
 
      success = xcf_save_image (&info, gimage);
 
368
      if (progress)
 
369
        {
 
370
          gchar *name = g_filename_display_name (filename);
 
371
          gchar *msg  = g_strdup_printf (_("Saving '%s'"), name);
 
372
 
 
373
          gimp_progress_start (progress, msg, FALSE);
 
374
 
 
375
          g_free (msg);
 
376
          g_free (name);
 
377
        }
 
378
 
 
379
      xcf_save_choose_format (&info, image);
 
380
 
 
381
      success = xcf_save_image (&info, image);
 
382
 
340
383
      if (fclose (info.fp) == EOF)
341
384
        {
342
 
          g_message (_("Error saving XCF file: %s"), g_strerror (errno));
 
385
          gimp_message (gimp, G_OBJECT (progress), GIMP_MESSAGE_ERROR,
 
386
                        _("Error saving XCF file: %s"), g_strerror (errno));
343
387
 
344
388
          success = FALSE;
345
389
        }
 
390
 
 
391
      if (progress)
 
392
        gimp_progress_end (progress);
346
393
    }
347
394
  else
348
 
    g_message (_("Could not open '%s' for writing: %s"),
349
 
               gimp_filename_to_utf8 (filename), g_strerror (errno));
 
395
    {
 
396
      gimp_message (gimp, G_OBJECT (progress), GIMP_MESSAGE_ERROR,
 
397
                    _("Could not open '%s' for writing: %s"),
 
398
                    gimp_filename_to_utf8 (filename), g_strerror (errno));
 
399
    }
350
400
 
351
 
  return_args = procedural_db_return_args (&xcf_plug_in_save_proc.db_info,
352
 
                                           success);
 
401
  return_vals = gimp_procedure_get_return_values (procedure, success);
353
402
 
354
403
  gimp_unset_busy (gimp);
355
404
 
356
 
  return return_args;
 
405
  return return_vals;
357
406
}