Coverage Report

Created: 2025-06-16 07:00

/src/imagemagick/coders/xcf.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                            X   X   CCCC  FFFFF                              %
7
%                             X X   C      F                                  %
8
%                              X    C      FFF                                %
9
%                             X X   C      F                                  %
10
%                            X   X   CCCC  F                                  %
11
%                                                                             %
12
%                                                                             %
13
%                        Read GIMP XCF Image Format                           %
14
%                                                                             %
15
%                              Software Design                                %
16
%                              Leonard Rosenthol                              %
17
%                               November 2001                                 %
18
%                                                                             %
19
%                                                                             %
20
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
21
%  dedicated to making software imaging solutions freely available.           %
22
%                                                                             %
23
%  You may not use this file except in compliance with the License.  You may  %
24
%  obtain a copy of the License at                                            %
25
%                                                                             %
26
%    https://imagemagick.org/script/license.php                               %
27
%                                                                             %
28
%  Unless required by applicable law or agreed to in writing, software        %
29
%  distributed under the License is distributed on an "AS IS" BASIS,          %
30
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31
%  See the License for the specific language governing permissions and        %
32
%  limitations under the License.                                             %
33
%                                                                             %
34
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35
%
36
%
37
*/
38

39
/*
40
  Include declarations.
41
*/
42
#include "MagickCore/studio.h"
43
#include "MagickCore/blob.h"
44
#include "MagickCore/blob-private.h"
45
#include "MagickCore/cache.h"
46
#include "MagickCore/color.h"
47
#include "MagickCore/composite.h"
48
#include "MagickCore/exception.h"
49
#include "MagickCore/exception-private.h"
50
#include "MagickCore/image.h"
51
#include "MagickCore/image-private.h"
52
#include "MagickCore/list.h"
53
#include "MagickCore/magick.h"
54
#include "MagickCore/memory_.h"
55
#include "MagickCore/pixel.h"
56
#include "MagickCore/pixel-accessor.h"
57
#include "MagickCore/property.h"
58
#include "MagickCore/quantize.h"
59
#include "MagickCore/quantum-private.h"
60
#include "MagickCore/resource_.h"
61
#include "MagickCore/static.h"
62
#include "MagickCore/string_.h"
63
#include "MagickCore/string-private.h"
64
#include "MagickCore/module.h"
65

66
/*
67
  Typedef declarations.
68
*/
69
typedef enum
70
{
71
  GIMP_RGB,
72
  GIMP_GRAY,
73
  GIMP_INDEXED
74
} GimpImageBaseType;
75
76
typedef enum
77
{
78
  PROP_END                   =  0,
79
  PROP_COLORMAP              =  1,
80
  PROP_ACTIVE_LAYER          =  2,
81
  PROP_ACTIVE_CHANNEL        =  3,
82
  PROP_SELECTION             =  4,
83
  PROP_FLOATING_SELECTION    =  5,
84
  PROP_OPACITY               =  6,
85
  PROP_MODE                  =  7,
86
  PROP_VISIBLE               =  8,
87
  PROP_LINKED                =  9,
88
  PROP_PRESERVE_TRANSPARENCY = 10,
89
  PROP_APPLY_MASK            = 11,
90
  PROP_EDIT_MASK             = 12,
91
  PROP_SHOW_MASK             = 13,
92
  PROP_SHOW_MASKED           = 14,
93
  PROP_OFFSETS               = 15,
94
  PROP_COLOR                 = 16,
95
  PROP_COMPRESSION           = 17,
96
  PROP_GUIDES                = 18,
97
  PROP_RESOLUTION            = 19,
98
  PROP_TATTOO                = 20,
99
  PROP_PARASITES             = 21,
100
  PROP_UNIT                  = 22,
101
  PROP_PATHS                 = 23,
102
  PROP_USER_UNIT             = 24
103
} PropType;
104
105
typedef enum
106
{
107
  COMPRESS_NONE              =  0,
108
  COMPRESS_RLE               =  1,
109
  COMPRESS_ZLIB              =  2,  /* unused */
110
  COMPRESS_FRACTAL           =  3   /* unused */
111
} XcfCompressionType;
112
113
typedef struct
114
{
115
  size_t
116
    version,
117
    width,
118
    height,
119
    image_type,
120
    bytes_per_pixel;
121
122
  int
123
    compression;
124
125
  size_t
126
    file_size;
127
128
  size_t
129
    number_layers;
130
} XCFDocInfo;
131
132
typedef struct
133
{
134
  char
135
    name[1024];
136
137
  unsigned int
138
    active;
139
140
  size_t
141
    width,
142
    height,
143
    type,
144
    alpha,
145
    visible,
146
    linked,
147
    preserve_trans,
148
    apply_mask,
149
    show_mask,
150
    edit_mask,
151
    floating_offset;
152
153
  ssize_t
154
    offset_x,
155
    offset_y;
156
157
  size_t
158
    mode,
159
    tattoo;
160
161
  Image
162
    *image;
163
} XCFLayerInfo;
164
165
20.0k
#define TILE_WIDTH   64
166
15.5k
#define TILE_HEIGHT  64
167
1.75k
#define GIMP_MIN_RESOLUTION  5e-3f
168
1.20k
#define GIMP_MAX_RESOLUTION  65536.0f
169
170
typedef struct
171
{
172
  unsigned char
173
    red,
174
    green,
175
    blue,
176
    alpha;
177
} XCFPixelInfo;
178

179
/*
180
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
181
%                                                                             %
182
%                                                                             %
183
%                                                                             %
184
%   I s X C F                                                                 %
185
%                                                                             %
186
%                                                                             %
187
%                                                                             %
188
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
189
%
190
%  IsXCF() returns MagickTrue if the image format type, identified by the
191
%  magick string, is XCF (GIMP native format).
192
%
193
%  The format of the IsXCF method is:
194
%
195
%      MagickBooleanType IsXCF(const unsigned char *magick,const size_t length)
196
%
197
%  A description of each parameter follows:
198
%
199
%    o magick: compare image format pattern against these bytes.
200
%
201
%    o length: Specifies the length of the magick string.
202
%
203
%
204
*/
205
static MagickBooleanType IsXCF(const unsigned char *magick,const size_t length)
206
0
{
207
0
  if (length < 8)
208
0
    return(MagickFalse);
209
0
  if (LocaleNCompare((char *) magick,"gimp xcf",8) == 0)
210
0
    return(MagickTrue);
211
0
  return(MagickFalse);
212
0
}
213

214
typedef enum
215
{
216
  GIMP_LAYER_MODE_NORMAL_LEGACY,
217
  GIMP_LAYER_MODE_DISSOLVE,
218
  GIMP_LAYER_MODE_BEHIND_LEGACY,
219
  GIMP_LAYER_MODE_MULTIPLY_LEGACY,
220
  GIMP_LAYER_MODE_SCREEN_LEGACY,
221
  GIMP_LAYER_MODE_OVERLAY_LEGACY,
222
  GIMP_LAYER_MODE_DIFFERENCE_LEGACY,
223
  GIMP_LAYER_MODE_ADDITION_LEGACY,
224
  GIMP_LAYER_MODE_SUBTRACT_LEGACY,
225
  GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY,
226
  GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY,
227
  GIMP_LAYER_MODE_HSV_HUE_LEGACY,
228
  GIMP_LAYER_MODE_HSV_SATURATION_LEGACY,
229
  GIMP_LAYER_MODE_HSL_COLOR_LEGACY,
230
  GIMP_LAYER_MODE_HSV_VALUE_LEGACY,
231
  GIMP_LAYER_MODE_DIVIDE_LEGACY,
232
  GIMP_LAYER_MODE_DODGE_LEGACY,
233
  GIMP_LAYER_MODE_BURN_LEGACY,
234
  GIMP_LAYER_MODE_HARDLIGHT_LEGACY,
235
  GIMP_LAYER_MODE_SOFTLIGHT_LEGACY,
236
  GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY,
237
  GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY,
238
  GIMP_LAYER_MODE_COLOR_ERASE_LEGACY,
239
  GIMP_LAYER_MODE_OVERLAY,
240
  GIMP_LAYER_MODE_LCH_HUE,
241
  GIMP_LAYER_MODE_LCH_CHROMA,
242
  GIMP_LAYER_MODE_LCH_COLOR,
243
  GIMP_LAYER_MODE_LCH_LIGHTNESS,
244
  GIMP_LAYER_MODE_NORMAL,
245
  GIMP_LAYER_MODE_BEHIND,
246
  GIMP_LAYER_MODE_MULTIPLY,
247
  GIMP_LAYER_MODE_SCREEN,
248
  GIMP_LAYER_MODE_DIFFERENCE,
249
  GIMP_LAYER_MODE_ADDITION,
250
  GIMP_LAYER_MODE_SUBTRACT,
251
  GIMP_LAYER_MODE_DARKEN_ONLY,
252
  GIMP_LAYER_MODE_LIGHTEN_ONLY,
253
  GIMP_LAYER_MODE_HSV_HUE,
254
  GIMP_LAYER_MODE_HSV_SATURATION,
255
  GIMP_LAYER_MODE_HSL_COLOR,
256
  GIMP_LAYER_MODE_HSV_VALUE,
257
  GIMP_LAYER_MODE_DIVIDE,
258
  GIMP_LAYER_MODE_DODGE,
259
  GIMP_LAYER_MODE_BURN,
260
  GIMP_LAYER_MODE_HARDLIGHT,
261
  GIMP_LAYER_MODE_SOFTLIGHT,
262
  GIMP_LAYER_MODE_GRAIN_EXTRACT,
263
  GIMP_LAYER_MODE_GRAIN_MERGE,
264
  GIMP_LAYER_MODE_VIVID_LIGHT,
265
  GIMP_LAYER_MODE_PIN_LIGHT,
266
  GIMP_LAYER_MODE_LINEAR_LIGHT,
267
  GIMP_LAYER_MODE_HARD_MIX,
268
  GIMP_LAYER_MODE_EXCLUSION,
269
  GIMP_LAYER_MODE_LINEAR_BURN,
270
  GIMP_LAYER_MODE_LUMA_DARKEN_ONLY,
271
  GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY,
272
  GIMP_LAYER_MODE_LUMINANCE,
273
  GIMP_LAYER_MODE_COLOR_ERASE,
274
  GIMP_LAYER_MODE_ERASE,
275
  GIMP_LAYER_MODE_MERGE,
276
  GIMP_LAYER_MODE_SPLIT,
277
  GIMP_LAYER_MODE_PASS_THROUGH,
278
} GimpLayerMode;
279
280
/*
281
  Simple utility routine to convert between PSD blending modes and
282
  ImageMagick compositing operators
283
*/
284
static CompositeOperator GIMPBlendModeToCompositeOperator(
285
  size_t blendMode)
286
4.89k
{
287
4.89k
  switch ( blendMode )
288
4.89k
  {
289
4.79k
    case GIMP_LAYER_MODE_NORMAL_LEGACY:
290
4.79k
    case GIMP_LAYER_MODE_NORMAL:
291
4.79k
      return(OverCompositeOp);
292
17
    case GIMP_LAYER_MODE_DISSOLVE:
293
17
      return(DissolveCompositeOp);
294
4
    case GIMP_LAYER_MODE_MULTIPLY_LEGACY:
295
4
    case GIMP_LAYER_MODE_MULTIPLY:
296
4
      return(MultiplyCompositeOp);
297
0
    case GIMP_LAYER_MODE_SCREEN_LEGACY:
298
0
    case GIMP_LAYER_MODE_SCREEN:
299
0
      return(ScreenCompositeOp);
300
1
    case GIMP_LAYER_MODE_OVERLAY_LEGACY:
301
1
    case GIMP_LAYER_MODE_OVERLAY:
302
1
      return(OverlayCompositeOp);
303
0
    case GIMP_LAYER_MODE_DIFFERENCE_LEGACY:
304
1
    case GIMP_LAYER_MODE_DIFFERENCE:
305
1
      return(DifferenceCompositeOp);
306
0
    case GIMP_LAYER_MODE_ADDITION_LEGACY:
307
0
    case GIMP_LAYER_MODE_ADDITION:
308
0
      return(ModulusAddCompositeOp);
309
0
    case GIMP_LAYER_MODE_SUBTRACT_LEGACY:
310
0
    case GIMP_LAYER_MODE_SUBTRACT:
311
0
      return(ModulusSubtractCompositeOp);
312
1
    case GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY:
313
1
    case GIMP_LAYER_MODE_DARKEN_ONLY:
314
10
    case GIMP_LAYER_MODE_LUMA_DARKEN_ONLY:
315
10
      return(DarkenCompositeOp);
316
0
    case GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY:
317
0
    case GIMP_LAYER_MODE_LIGHTEN_ONLY:
318
0
      return(LightenCompositeOp);
319
0
    case GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY:
320
0
      return(LightenCompositeOp);
321
0
    case GIMP_LAYER_MODE_HSV_HUE_LEGACY:
322
0
    case GIMP_LAYER_MODE_HSV_HUE:
323
0
      return(HueCompositeOp);
324
0
    case GIMP_LAYER_MODE_HSV_SATURATION_LEGACY:
325
0
    case GIMP_LAYER_MODE_HSV_SATURATION:
326
0
      return(SaturateCompositeOp);
327
1
    case GIMP_LAYER_MODE_HSL_COLOR_LEGACY:
328
4
    case GIMP_LAYER_MODE_HSL_COLOR:
329
4
      return(ColorizeCompositeOp);
330
1
    case GIMP_LAYER_MODE_DODGE_LEGACY:
331
1
    case GIMP_LAYER_MODE_DODGE:
332
1
      return(ColorDodgeCompositeOp);
333
0
    case GIMP_LAYER_MODE_BURN_LEGACY:
334
1
    case GIMP_LAYER_MODE_BURN:
335
1
      return(ColorBurnCompositeOp);
336
0
    case GIMP_LAYER_MODE_HARDLIGHT_LEGACY:
337
0
    case GIMP_LAYER_MODE_HARDLIGHT:
338
0
      return(HardLightCompositeOp);
339
0
    case GIMP_LAYER_MODE_DIVIDE_LEGACY:
340
0
    case GIMP_LAYER_MODE_DIVIDE:
341
0
      return(DivideDstCompositeOp);
342
    /* these are the ones we don't support...yet */
343
61
    default:
344
61
      return(OverCompositeOp);
345
4.89k
  }
346
4.89k
}
347

348
/*
349
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350
%                                                                             %
351
%                                                                             %
352
%                                                                             %
353
+   R e a d B l o b S t r i n g W i t h L o n g S i z e                       %
354
%                                                                             %
355
%                                                                             %
356
%                                                                             %
357
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358
%
359
%  ReadBlobStringWithLongSize reads characters from a blob or file
360
%  starting with a ssize_t length byte and then characters to that length
361
%
362
%  The format of the ReadBlobStringWithLongSize method is:
363
%
364
%      char *ReadBlobStringWithLongSize(Image *image,char *string,
365
%        ExceptionInfo *exception)
366
%
367
%  A description of each parameter follows:
368
%
369
%    o image: the image.
370
%
371
%    o string: the address of a character buffer.
372
%
373
%    o exception: return any errors or warnings in this structure.
374
%
375
*/
376
377
static char *ReadBlobStringWithLongSize(Image *image,char *string,size_t max,
378
  ExceptionInfo *exception)
379
6.35k
{
380
6.35k
  int
381
6.35k
    c;
382
383
6.35k
  MagickOffsetType
384
6.35k
    offset;
385
386
6.35k
  ssize_t
387
6.35k
    i;
388
389
6.35k
  size_t
390
6.35k
    length;
391
392
6.35k
  assert(image != (Image *) NULL);
393
6.35k
  assert(image->signature == MagickCoreSignature);
394
6.35k
  assert(max != 0);
395
6.35k
  if (IsEventLogging() != MagickFalse)
396
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
397
6.35k
  length=ReadBlobMSBLong(image);
398
304k
  for (i=0; i < (ssize_t) MagickMin(length,max-1); i++)
399
297k
  {
400
297k
    c=ReadBlobByte(image);
401
297k
    if (c == EOF)
402
29
      return((char *) NULL);
403
297k
    string[i]=(char) c;
404
297k
  }
405
6.32k
  string[i]='\0';
406
6.32k
  offset=SeekBlob(image,((MagickOffsetType) length-i),SEEK_CUR);
407
6.32k
  if (offset < 0)
408
0
    (void) ThrowMagickException(exception,GetMagickModule(),
409
0
      CorruptImageError,"ImproperImageHeader","`%s'",image->filename);
410
6.32k
  return(string);
411
6.35k
}
412
413
static MagickOffsetType GetXCFOffset(Image *image, XCFDocInfo *inDocInfo)
414
46.1k
{
415
46.1k
  if (inDocInfo->version >= 4)
416
5.81k
    return (MagickOffsetType) ReadBlobMSBLongLong(image);
417
40.3k
  else
418
40.3k
    return (MagickOffsetType) ReadBlobMSBLong(image);
419
46.1k
}
420
421
static MagickBooleanType load_tile(Image *image,Image *tile_image,
422
  XCFDocInfo *inDocInfo,XCFLayerInfo *inLayerInfo,size_t data_length,
423
  ExceptionInfo *exception)
424
270
{
425
270
  ssize_t
426
270
    y;
427
428
270
  ssize_t
429
270
    x;
430
431
270
  Quantum
432
270
    *q;
433
434
270
  size_t
435
270
    extent;
436
437
270
  ssize_t
438
270
    count;
439
440
270
  unsigned char
441
270
    *graydata;
442
443
270
  XCFPixelInfo
444
270
    *xcfdata,
445
270
    *xcfodata;
446
447
270
  extent=0;
448
270
  if (inDocInfo->image_type == GIMP_GRAY)
449
109
    extent=tile_image->columns*tile_image->rows*sizeof(*graydata);
450
161
  else
451
161
    if (inDocInfo->image_type == GIMP_RGB)
452
161
      extent=tile_image->columns*tile_image->rows*sizeof(*xcfdata);
453
270
  if (extent > data_length)
454
26
    ThrowBinaryException(CorruptImageError,"NotEnoughPixelData",
455
270
      image->filename);
456
244
  xcfdata=(XCFPixelInfo *) AcquireQuantumMemory(MagickMax(data_length,
457
244
    tile_image->columns*tile_image->rows),sizeof(*xcfdata));
458
244
  if (xcfdata == (XCFPixelInfo *) NULL)
459
0
    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
460
244
      image->filename);
461
244
  xcfodata=xcfdata;
462
244
  graydata=(unsigned char *) xcfdata;  /* used by gray and indexed */
463
244
  count=ReadBlob(image,data_length,(unsigned char *) xcfdata);
464
244
  if (count != (ssize_t) data_length)
465
169
    {
466
169
      xcfodata=(XCFPixelInfo *) RelinquishMagickMemory(xcfodata);
467
169
      ThrowBinaryException(CorruptImageError,"NotEnoughPixelData",
468
169
        image->filename);
469
0
    }
470
1.98k
  for (y=0; y < (ssize_t) tile_image->rows; y++)
471
1.90k
  {
472
1.90k
    q=GetAuthenticPixels(tile_image,0,y,tile_image->columns,1,exception);
473
1.90k
    if (q == (Quantum *) NULL)
474
0
      break;
475
1.90k
    if (inDocInfo->image_type == GIMP_GRAY)
476
1.11k
      {
477
3.30k
        for (x=0; x < (ssize_t) tile_image->columns; x++)
478
2.18k
        {
479
2.18k
          SetPixelGray(tile_image,ScaleCharToQuantum(*graydata),q);
480
2.18k
          SetPixelAlpha(tile_image,ScaleCharToQuantum((unsigned char)
481
2.18k
            inLayerInfo->alpha),q);
482
2.18k
          graydata++;
483
2.18k
          q+=(ptrdiff_t) GetPixelChannels(tile_image);
484
2.18k
        }
485
1.11k
      }
486
792
    else
487
792
      if (inDocInfo->image_type == GIMP_RGB)
488
792
        {
489
2.09k
          for (x=0; x < (ssize_t) tile_image->columns; x++)
490
1.30k
          {
491
1.30k
            SetPixelRed(tile_image,ScaleCharToQuantum(xcfdata->red),q);
492
1.30k
            SetPixelGreen(tile_image,ScaleCharToQuantum(xcfdata->green),q);
493
1.30k
            SetPixelBlue(tile_image,ScaleCharToQuantum(xcfdata->blue),q);
494
1.30k
            SetPixelAlpha(tile_image,xcfdata->alpha == 255U ? TransparentAlpha :
495
1.30k
              ScaleCharToQuantum((unsigned char) inLayerInfo->alpha),q);
496
1.30k
            xcfdata++;
497
1.30k
            q+=(ptrdiff_t) GetPixelChannels(tile_image);
498
1.30k
          }
499
792
        }
500
1.90k
     if (SyncAuthenticPixels(tile_image,exception) == MagickFalse)
501
0
       break;
502
1.90k
  }
503
75
  xcfodata=(XCFPixelInfo *) RelinquishMagickMemory(xcfodata);
504
75
  return MagickTrue;
505
244
}
506
507
static MagickBooleanType load_tile_rle(Image *image,Image *tile_image,
508
  XCFDocInfo *inDocInfo,XCFLayerInfo *inLayerInfo,size_t data_length,
509
  ExceptionInfo *exception)
510
5.14k
{
511
5.14k
  MagickOffsetType
512
5.14k
    size;
513
514
5.14k
  Quantum
515
5.14k
    alpha,
516
5.14k
    data;
517
518
5.14k
  Quantum
519
5.14k
    *q;
520
521
5.14k
  size_t
522
5.14k
    length;
523
524
5.14k
  ssize_t
525
5.14k
    bytes_per_pixel,
526
5.14k
    count,
527
5.14k
    i,
528
5.14k
    j;
529
530
5.14k
  unsigned char
531
5.14k
    pixel,
532
5.14k
    *xcfdata,
533
5.14k
    *xcfodata,
534
5.14k
    *xcfdatalimit;
535
536
5.14k
  bytes_per_pixel=(ssize_t) inDocInfo->bytes_per_pixel;
537
5.14k
  xcfdata=(unsigned char *) AcquireQuantumMemory(data_length,sizeof(*xcfdata));
538
5.14k
  if (xcfdata == (unsigned char *) NULL)
539
4
    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
540
5.14k
      image->filename);
541
5.14k
  (void) memset(xcfdata,0,(size_t) data_length*sizeof(*xcfdata));
542
5.14k
  xcfodata=xcfdata;
543
5.14k
  count=ReadBlob(image, (size_t) data_length, xcfdata);
544
5.14k
  xcfdatalimit = xcfodata+count-1;
545
5.14k
  alpha=ScaleCharToQuantum((unsigned char) inLayerInfo->alpha);
546
6.71k
  for (i=0; i < bytes_per_pixel; i++)
547
1.88k
  {
548
1.88k
    q=GetAuthenticPixels(tile_image,0,0,tile_image->columns,tile_image->rows,
549
1.88k
      exception);
550
1.88k
    if (q == (Quantum *) NULL)
551
0
      continue;
552
1.88k
    size=(MagickOffsetType) (tile_image->rows*tile_image->columns);
553
34.6k
    while (size > 0)
554
33.0k
    {
555
33.0k
      if (xcfdata > xcfdatalimit)
556
116
        goto bogus_rle;
557
32.9k
      pixel=(*xcfdata++);
558
32.9k
      length=(size_t) pixel;
559
32.9k
      if (length >= 128)
560
4.60k
        {
561
4.60k
          length=255-(length-1);
562
4.60k
          if (length == 128)
563
446
            {
564
446
              if (xcfdata >= xcfdatalimit)
565
7
                goto bogus_rle;
566
439
              length=(size_t) ((*xcfdata << 8) + xcfdata[1]) & 0xffff;
567
439
              xcfdata+=2;
568
439
            }
569
4.60k
          size-=(MagickOffsetType) length;
570
4.60k
          if (size < 0)
571
32
            goto bogus_rle;
572
4.57k
          if ((length < 1) || (length > data_length))
573
21
            goto bogus_rle;
574
4.54k
          if (&xcfdata[length-1] > xcfdatalimit)
575
66
            goto bogus_rle;
576
45.9k
          while (length-- > 0)
577
41.4k
          {
578
41.4k
            data=ScaleCharToQuantum(*xcfdata++);
579
41.4k
            switch (i)
580
41.4k
            {
581
24.3k
              case 0:
582
24.3k
              {
583
24.3k
                if (inDocInfo->image_type == GIMP_GRAY)
584
16.7k
                  SetPixelGray(tile_image,data,q);
585
7.61k
                else
586
7.61k
                  {
587
7.61k
                    SetPixelRed(tile_image,data,q);
588
7.61k
                    SetPixelGreen(tile_image,data,q);
589
7.61k
                    SetPixelBlue(tile_image,data,q);
590
7.61k
                  }
591
24.3k
                SetPixelAlpha(tile_image,alpha,q);
592
24.3k
                break;
593
0
              }
594
10.0k
              case 1:
595
10.0k
              {
596
10.0k
                if (inDocInfo->image_type == GIMP_GRAY)
597
7.72k
                  SetPixelAlpha(tile_image,data,q);
598
2.33k
                else
599
2.33k
                  SetPixelGreen(tile_image,data,q);
600
10.0k
                break;
601
0
              }
602
1.99k
              case 2:
603
1.99k
              {
604
1.99k
                SetPixelBlue(tile_image,data,q);
605
1.99k
                break;
606
0
              }
607
3.41k
              case 3:
608
3.41k
              {
609
3.41k
                SetPixelAlpha(tile_image,data,q);
610
3.41k
                break;
611
0
              }
612
41.4k
            }
613
41.4k
            q+=(ptrdiff_t) GetPixelChannels(tile_image);
614
41.4k
          }
615
4.48k
        }
616
28.3k
      else
617
28.3k
        {
618
28.3k
          length+=1;
619
28.3k
          if (length == 128)
620
467
            {
621
467
              if (xcfdata >= xcfdatalimit)
622
1
                goto bogus_rle;
623
466
              length=(size_t) ((*xcfdata << 8) + xcfdata[1]) & 0xffff;
624
466
              xcfdata+=2;
625
466
            }
626
28.3k
          size-=(MagickOffsetType) length;
627
28.3k
          if (size < 0)
628
43
            goto bogus_rle;
629
28.3k
          if (xcfdata > xcfdatalimit)
630
29
            goto bogus_rle;
631
28.2k
          pixel=(*xcfdata++);
632
1.02M
          for (j=0; j < (ssize_t) length; j++)
633
996k
          {
634
996k
            data=ScaleCharToQuantum(pixel);
635
996k
            switch (i)
636
996k
            {
637
549k
              case 0:
638
549k
              {
639
549k
                if (inDocInfo->image_type == GIMP_GRAY)
640
320k
                  SetPixelGray(tile_image,data,q);
641
229k
                else
642
229k
                  {
643
229k
                    SetPixelRed(tile_image,data,q);
644
229k
                    SetPixelGreen(tile_image,data,q);
645
229k
                    SetPixelBlue(tile_image,data,q);
646
229k
                  }
647
549k
                SetPixelAlpha(tile_image,alpha,q);
648
549k
                break;
649
0
              }
650
242k
              case 1:
651
242k
              {
652
242k
                if (inDocInfo->image_type == GIMP_GRAY)
653
145k
                  SetPixelAlpha(tile_image,data,q);
654
96.5k
                else
655
96.5k
                  SetPixelGreen(tile_image,data,q);
656
242k
                break;
657
0
              }
658
132k
              case 2:
659
132k
              {
660
132k
                SetPixelBlue(tile_image,data,q);
661
132k
                break;
662
0
              }
663
50.8k
              case 3:
664
50.8k
              {
665
50.8k
                SetPixelAlpha(tile_image,data,q);
666
50.8k
                break;
667
0
              }
668
996k
            }
669
996k
            q+=(ptrdiff_t) GetPixelChannels(tile_image);
670
996k
          }
671
28.2k
        }
672
32.9k
    }
673
1.57k
    if (SyncAuthenticPixels(tile_image,exception) == MagickFalse)
674
0
      break;
675
1.57k
  }
676
4.82k
  xcfodata=(unsigned char *) RelinquishMagickMemory(xcfodata);
677
4.82k
  return(MagickTrue);
678
679
315
  bogus_rle:
680
315
  if (xcfodata != (unsigned char *) NULL)
681
315
    xcfodata=(unsigned char *) RelinquishMagickMemory(xcfodata);
682
315
  return(MagickFalse);
683
5.14k
}
684
685
static MagickBooleanType load_level(Image *image,XCFDocInfo *inDocInfo,
686
  XCFLayerInfo *inLayerInfo,ExceptionInfo *exception)
687
4.66k
{
688
4.66k
  int
689
4.66k
    destLeft = 0,
690
4.66k
    destTop = 0;
691
692
4.66k
  Image*
693
4.66k
    tile_image;
694
695
4.66k
  MagickBooleanType
696
4.66k
    status;
697
698
4.66k
  MagickOffsetType
699
4.66k
    saved_pos,
700
4.66k
    offset,
701
4.66k
    offset2;
702
703
4.66k
  ssize_t
704
4.66k
    i;
705
706
4.66k
  size_t
707
4.66k
    width,
708
4.66k
    height,
709
4.66k
    ntiles,
710
4.66k
    ntile_rows,
711
4.66k
    ntile_cols,
712
4.66k
    tile_image_width,
713
4.66k
    tile_image_height;
714
715
  /* start reading the data */
716
4.66k
  width=ReadBlobMSBLong(image);
717
4.66k
  height=ReadBlobMSBLong(image);
718
719
  /*
720
    Read in the first tile offset.  If it is '0', then this tile level is empty
721
    and we can simply return.
722
  */
723
4.66k
  offset=GetXCFOffset(image,inDocInfo);
724
4.66k
  if (EOFBlob(image) != MagickFalse)
725
1
    ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
726
4.66k
      image->filename);
727
4.66k
  if (offset == 0)
728
2.10k
    {
729
2.10k
      (void) SetImageBackgroundColor(image,exception);
730
2.10k
      return(MagickTrue);
731
2.10k
    }
732
  /*
733
    Initialise the reference for the in-memory tile-compression
734
  */
735
2.55k
  ntile_rows=(height+TILE_HEIGHT-1)/TILE_HEIGHT;
736
2.55k
  ntile_cols=(width+TILE_WIDTH-1)/TILE_WIDTH;
737
2.55k
  ntiles=ntile_rows*ntile_cols;
738
7.45k
  for (i = 0; i < (ssize_t) ntiles; i++)
739
5.87k
  {
740
5.87k
    status=MagickFalse;
741
5.87k
    if (offset == 0)
742
5.74k
      ThrowBinaryException(CorruptImageError,"NotEnoughTiles",image->filename);
743
    /*
744
      Save the current position as it is where the next tile offset is stored.
745
    */
746
5.74k
    saved_pos=TellBlob(image);
747
    /* read in the offset of the next tile so we can calculate the amount
748
       of data needed for this tile*/
749
5.74k
    offset2=GetXCFOffset(image,inDocInfo);
750
5.74k
    if ((MagickSizeType) offset2 >= inDocInfo->file_size)
751
211
      ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
752
5.74k
        image->filename);
753
    /* if the offset is 0 then we need to read in the maximum possible
754
       allowing for negative compression */
755
5.53k
    if (offset2 == 0)
756
2.18k
      offset2=(MagickOffsetType) (offset + TILE_WIDTH * TILE_WIDTH * 4* 1.5);
757
    /* seek to the tile offset */
758
5.53k
    if ((offset > offset2) || (SeekBlob(image, offset, SEEK_SET) != offset))
759
120
      ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
760
5.53k
        image->filename);
761
762
      /*
763
        Allocate the image for the tile.  NOTE: the last tile in a row or
764
        column may not be a full tile!
765
      */
766
5.41k
      tile_image_width=(size_t) (destLeft == (int) ntile_cols-1 ?
767
3.48k
        (int) width % TILE_WIDTH : TILE_WIDTH);
768
5.41k
      if (tile_image_width == 0)
769
239
        tile_image_width=TILE_WIDTH;
770
5.41k
      tile_image_height = (size_t) (destTop == (int) ntile_rows-1 ?
771
4.56k
        (int) height % TILE_HEIGHT : TILE_HEIGHT);
772
5.41k
      if (tile_image_height == 0)
773
163
        tile_image_height=TILE_HEIGHT;
774
5.41k
      tile_image=CloneImage(inLayerInfo->image,tile_image_width,
775
5.41k
        tile_image_height,MagickTrue,exception);
776
5.41k
      if (tile_image == (Image *) NULL)
777
0
        ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
778
5.41k
          image->filename);
779
5.41k
      (void) SetImageBackgroundColor(tile_image,exception);
780
781
      /* read in the tile */
782
5.41k
      switch (inDocInfo->compression)
783
5.41k
      {
784
270
        case COMPRESS_NONE:
785
270
          status=load_tile(image,tile_image,inDocInfo,inLayerInfo,(size_t)
786
270
            (offset2-offset),exception);
787
270
          break;
788
5.14k
        case COMPRESS_RLE:
789
5.14k
          status=load_tile_rle(image,tile_image,inDocInfo,inLayerInfo,(size_t)
790
5.14k
            (offset2-offset),exception);
791
5.14k
          break;
792
2
        case COMPRESS_ZLIB:
793
2
          tile_image=DestroyImage(tile_image);
794
2
          ThrowBinaryException(CoderError,"ZipCompressNotSupported",
795
0
            image->filename)
796
2
        case COMPRESS_FRACTAL:
797
2
          tile_image=DestroyImage(tile_image);
798
2
          ThrowBinaryException(CoderError,"FractalCompressNotSupported",
799
5.41k
            image->filename)
800
5.41k
      }
801
802
      /* composite the tile onto the layer's image, and then destroy it */
803
5.41k
      if (status != MagickFalse)
804
4.90k
        (void) CompositeImage(inLayerInfo->image,tile_image,CopyCompositeOp,
805
4.90k
          MagickTrue,destLeft * TILE_WIDTH,destTop*TILE_HEIGHT,exception);
806
5.41k
      tile_image=DestroyImage(tile_image);
807
808
5.41k
      if (status == MagickFalse)
809
514
        return(MagickFalse);
810
      /* adjust tile position */
811
4.90k
      destLeft++;
812
4.90k
      if (destLeft >= (int) ntile_cols)
813
1.85k
        {
814
1.85k
          destLeft = 0;
815
1.85k
          destTop++;
816
1.85k
        }
817
      /* restore the saved position so we'll be ready to
818
       *  read the next offset.
819
       */
820
4.90k
      offset=SeekBlob(image, saved_pos, SEEK_SET);
821
      /* read in the offset of the next tile */
822
4.90k
      offset=GetXCFOffset(image,inDocInfo);
823
4.90k
    }
824
1.58k
  if (offset != 0)
825
76
    ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename)
826
1.51k
  return(MagickTrue);
827
1.58k
}
828
829
static MagickBooleanType load_hierarchy(Image *image,XCFDocInfo *inDocInfo,
830
   XCFLayerInfo *inLayer, ExceptionInfo *exception)
831
4.81k
{
832
4.81k
  MagickOffsetType
833
4.81k
    saved_pos,
834
4.81k
    offset,
835
4.81k
    junk;
836
837
4.81k
  (void) ReadBlobMSBLong(image); /* width */
838
4.81k
  (void) ReadBlobMSBLong(image); /* height */
839
4.81k
  inDocInfo->bytes_per_pixel=ReadBlobMSBLong(image);
840
841
  /* load in the levels...we make sure that the number of levels
842
   *  calculated when the TileManager was created is the same
843
   *  as the number of levels found in the file.
844
   */
845
4.81k
  offset=GetXCFOffset(image,inDocInfo);  /* top level */
846
4.81k
  if ((MagickSizeType) offset >= GetBlobSize(image))
847
150
    ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
848
4.81k
      image->filename);
849
850
  /* discard offsets for layers below first, if any.
851
   */
852
4.66k
  do
853
12.7k
  {
854
12.7k
    junk=(MagickOffsetType) ReadBlobMSBLong(image);
855
12.7k
  }
856
12.7k
  while (junk != 0);
857
858
  /* save the current position as it is where the
859
   *  next level offset is stored.
860
   */
861
4.66k
  saved_pos=TellBlob(image);
862
863
  /* seek to the level offset */
864
4.66k
  if (SeekBlob(image, offset, SEEK_SET) != offset)
865
0
    ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
866
4.66k
      image->filename);
867
868
  /* read in the level */
869
4.66k
  if (load_level (image, inDocInfo, inLayer, exception) == 0)
870
1.04k
    return(MagickFalse);
871
  /* restore the saved position so we'll be ready to
872
   *  read the next offset.
873
   */
874
3.61k
  offset=SeekBlob(image, saved_pos, SEEK_SET);
875
3.61k
  return(MagickTrue);
876
4.66k
}
877
878
static void InitXCFImage(XCFLayerInfo *outLayer,ExceptionInfo *exception)
879
4.89k
{
880
4.89k
  outLayer->image->page.x=outLayer->offset_x;
881
4.89k
  outLayer->image->page.y=outLayer->offset_y;
882
4.89k
  outLayer->image->page.width=outLayer->width;
883
4.89k
  outLayer->image->page.height=outLayer->height;
884
4.89k
  (void) SetImageProperty(outLayer->image,"label",(char *) outLayer->name,
885
4.89k
    exception);
886
4.89k
}
887
888
static MagickBooleanType ReadOneLayer(const ImageInfo *image_info,Image* image,
889
  XCFDocInfo* inDocInfo,XCFLayerInfo *outLayer,const ssize_t layer,
890
  ExceptionInfo *exception)
891
5.46k
{
892
5.46k
  MagickBooleanType
893
5.46k
    status;
894
895
5.46k
  MagickOffsetType
896
5.46k
    offset;
897
898
5.46k
  unsigned int
899
5.46k
    foundPropEnd = 0;
900
901
5.46k
  MagickOffsetType
902
5.46k
    hierarchy_offset,
903
5.46k
    layer_mask_offset;
904
905
  /* clear the block! */
906
5.46k
  (void) memset( outLayer, 0, sizeof( XCFLayerInfo ) );
907
  /* read in the layer width, height, type and name */
908
5.46k
  outLayer->width = ReadBlobMSBLong(image);
909
5.46k
  outLayer->height = ReadBlobMSBLong(image);
910
5.46k
  outLayer->type = ReadBlobMSBLong(image);
911
5.46k
  (void) ReadBlobStringWithLongSize(image, outLayer->name,
912
5.46k
    sizeof(outLayer->name),exception);
913
5.46k
  if (EOFBlob(image) != MagickFalse)
914
288
    ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
915
5.46k
      image->filename);
916
5.17k
  if ((outLayer->width == 0) || (outLayer->height == 0))
917
7
    ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
918
5.17k
      image->filename);
919
  /* read the layer properties! */
920
5.16k
  foundPropEnd = 0;
921
16.8k
  while ( (foundPropEnd == MagickFalse) && (EOFBlob(image) == MagickFalse) ) {
922
11.6k
  PropType    prop_type = (PropType) ReadBlobMSBLong(image);
923
11.6k
  size_t  prop_size = ReadBlobMSBLong(image);
924
11.6k
    switch (prop_type)
925
11.6k
    {
926
5.02k
    case PROP_END:
927
5.02k
      foundPropEnd = 1;
928
5.02k
      break;
929
209
    case PROP_ACTIVE_LAYER:
930
209
      outLayer->active = 1;
931
209
      break;
932
226
    case PROP_FLOATING_SELECTION:
933
226
      outLayer->floating_offset = ReadBlobMSBLong(image);
934
226
      break;
935
294
    case PROP_OPACITY:
936
294
      outLayer->alpha = ReadBlobMSBLong(image);
937
294
      break;
938
561
    case PROP_VISIBLE:
939
561
      outLayer->visible = ReadBlobMSBLong(image);
940
561
      break;
941
280
    case PROP_LINKED:
942
280
      outLayer->linked = ReadBlobMSBLong(image);
943
280
      break;
944
520
    case PROP_PRESERVE_TRANSPARENCY:
945
520
      outLayer->preserve_trans = ReadBlobMSBLong(image);
946
520
      break;
947
230
    case PROP_APPLY_MASK:
948
230
      outLayer->apply_mask = ReadBlobMSBLong(image);
949
230
      break;
950
223
    case PROP_EDIT_MASK:
951
223
      outLayer->edit_mask = ReadBlobMSBLong(image);
952
223
      break;
953
246
    case PROP_SHOW_MASK:
954
246
      outLayer->show_mask = ReadBlobMSBLong(image);
955
246
      break;
956
465
    case PROP_OFFSETS:
957
465
      outLayer->offset_x = ReadBlobMSBSignedLong(image);
958
465
      outLayer->offset_y = ReadBlobMSBSignedLong(image);
959
465
      break;
960
305
    case PROP_MODE:
961
305
      outLayer->mode = ReadBlobMSBLong(image);
962
305
      break;
963
238
    case PROP_TATTOO:
964
238
      outLayer->preserve_trans = ReadBlobMSBLong(image);
965
238
      break;
966
555
     case PROP_PARASITES:
967
555
     {
968
555
       if (DiscardBlobBytes(image,prop_size) == MagickFalse)
969
3
         ThrowFileException(exception,CorruptImageError,
970
555
           "UnexpectedEndOfFile",image->filename);
971
972
        /*
973
       ssize_t base = info->cp;
974
       GimpParasite *p;
975
       while (info->cp - base < prop_size)
976
       {
977
       p = xcf_load_parasite(info);
978
       gimp_drawable_parasite_attach(GIMP_DRAWABLE(layer), p);
979
       gimp_parasite_free(p);
980
       }
981
       if (info->cp - base != prop_size)
982
       g_message ("Error detected while loading a layer's parasites");
983
       */
984
555
     }
985
555
     break;
986
2.31k
    default:
987
      /* g_message ("unexpected/unknown layer property: %d (skipping)",
988
         prop_type); */
989
990
2.31k
      {
991
2.31k
      int buf[16];
992
2.31k
      ssize_t amount;
993
994
      /* read over it... */
995
4.55k
      while ((prop_size > 0) && (EOFBlob(image) == MagickFalse))
996
2.26k
        {
997
2.26k
        amount = (ssize_t) MagickMin(16, prop_size);
998
2.26k
        amount = ReadBlob(image, (size_t) amount, (unsigned char *) &buf);
999
2.26k
        if (!amount)
1000
18
          ThrowBinaryException(CorruptImageError,"CorruptImage",
1001
2.26k
            image->filename);
1002
2.24k
        prop_size -= (size_t) MagickMin(16, (size_t) amount);
1003
2.24k
        }
1004
2.31k
      }
1005
2.29k
      break;
1006
11.6k
    }
1007
11.6k
  }
1008
5.14k
  if (EOFBlob(image) != MagickFalse)
1009
151
    ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
1010
5.14k
      image->filename);
1011
4.99k
  if (foundPropEnd == MagickFalse)
1012
0
    return(MagickFalse);
1013
  /* allocate the image for this layer */
1014
4.99k
  if (image_info->number_scenes != 0)
1015
0
    {
1016
0
      ssize_t
1017
0
        scene;
1018
1019
0
      scene=(ssize_t) inDocInfo->number_layers-layer-1;
1020
0
      if (scene > (ssize_t) (image_info->scene+image_info->number_scenes-1))
1021
0
        {
1022
0
          outLayer->image=CloneImage(image,0,0,MagickTrue,exception);
1023
0
          if (outLayer->image == (Image *) NULL)
1024
0
            return(MagickFalse);
1025
0
          InitXCFImage(outLayer,exception);
1026
0
          return(MagickTrue);
1027
0
        }
1028
0
    }
1029
4.99k
  outLayer->image=CloneImage(image,outLayer->width, outLayer->height,MagickTrue,
1030
4.99k
    exception);
1031
4.99k
  if (outLayer->image == (Image *) NULL)
1032
99
    return(MagickFalse);
1033
4.89k
  outLayer->width=outLayer->image->columns;
1034
4.89k
  status=SetImageExtent(outLayer->image,outLayer->image->columns,
1035
4.89k
    outLayer->image->rows,exception);
1036
4.89k
  if (status != MagickFalse)
1037
4.89k
    status=ResetImagePixels(outLayer->image,exception);
1038
4.89k
  if (status == MagickFalse)
1039
0
    {
1040
0
      outLayer->image=DestroyImageList(outLayer->image);
1041
0
      return(MagickFalse);
1042
0
    }
1043
  /* clear the image based on the layer opacity */
1044
4.89k
  outLayer->image->background_color.alpha=
1045
4.89k
    ScaleCharToQuantum((unsigned char) outLayer->alpha);
1046
4.89k
  if (outLayer->alpha != 255U)
1047
4.88k
    {
1048
4.88k
      outLayer->image->background_color.alpha_trait=BlendPixelTrait;
1049
4.88k
      outLayer->image->alpha_trait=BlendPixelTrait;
1050
4.88k
      (void) SetImageBackgroundColor(outLayer->image,exception);
1051
4.88k
    }
1052
1053
4.89k
  InitXCFImage(outLayer,exception);
1054
1055
  /* set the compositing mode */
1056
4.89k
  outLayer->image->compose = GIMPBlendModeToCompositeOperator( outLayer->mode );
1057
4.89k
  if ( outLayer->visible == MagickFalse )
1058
4.76k
    {
1059
      /* BOGUS: should really be separate member var! */
1060
4.76k
      outLayer->image->compose = NoCompositeOp;
1061
4.76k
    }
1062
1063
  /* read the hierarchy and layer mask offsets */
1064
4.89k
  hierarchy_offset = GetXCFOffset(image,inDocInfo);
1065
4.89k
  layer_mask_offset = GetXCFOffset(image,inDocInfo);
1066
1067
  /* read in the hierarchy */
1068
4.89k
  offset=SeekBlob(image, hierarchy_offset, SEEK_SET);
1069
4.89k
  if (offset != hierarchy_offset)
1070
85
    ThrowBinaryException(CorruptImageError,"InvalidImageHeader",
1071
4.89k
      image->filename);
1072
4.81k
  if (load_hierarchy (image, inDocInfo, outLayer, exception) == 0)
1073
1.19k
    return(MagickFalse);
1074
1075
  /* read in the layer mask */
1076
3.61k
  if (layer_mask_offset != 0)
1077
2.33k
    {
1078
2.33k
      offset=SeekBlob(image, (MagickOffsetType) layer_mask_offset, SEEK_SET);
1079
1080
#if 0  /* BOGUS: support layer masks! */
1081
      layer_mask = xcf_load_layer_mask (info, gimage);
1082
      if (layer_mask == 0)
1083
  goto error;
1084
1085
      /* set the offsets of the layer_mask */
1086
      GIMP_DRAWABLE (layer_mask)->offset_x = GIMP_DRAWABLE (layer)->offset_x;
1087
      GIMP_DRAWABLE (layer_mask)->offset_y = GIMP_DRAWABLE (layer)->offset_y;
1088
1089
      gimp_layer_add_mask (layer, layer_mask, MagickFalse);
1090
1091
      layer->mask->apply_mask = apply_mask;
1092
      layer->mask->edit_mask  = edit_mask;
1093
      layer->mask->show_mask  = show_mask;
1094
#endif
1095
2.33k
  }
1096
1097
  /* attach the floating selection... */
1098
#if 0  /* BOGUS: we may need to read this, even if we don't support it! */
1099
  if (add_floating_sel)
1100
    {
1101
      GimpLayer *floating_sel;
1102
1103
      floating_sel = info->floating_sel;
1104
      floating_sel_attach (floating_sel, GIMP_DRAWABLE (layer));
1105
    }
1106
#endif
1107
1108
3.61k
  return MagickTrue;
1109
4.81k
}
1110

1111
/*
1112
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1113
%                                                                             %
1114
%                                                                             %
1115
%                                                                             %
1116
%   R e a d X C F I m a g e                                                   %
1117
%                                                                             %
1118
%                                                                             %
1119
%                                                                             %
1120
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1121
%
1122
%  ReadXCFImage() reads a GIMP (GNU Image Manipulation Program) image
1123
%  file and returns it.  It allocates the memory necessary for the new Image
1124
%  structure and returns a pointer to the new image.
1125
%
1126
%  The format of the ReadXCFImage method is:
1127
%
1128
%      image=ReadXCFImage(image_info)
1129
%
1130
%  A description of each parameter follows:
1131
%
1132
%    o image_info: the image info.
1133
%
1134
%    o exception: return any errors or warnings in this structure.
1135
%
1136
*/
1137
static Image *ReadXCFImage(const ImageInfo *image_info,ExceptionInfo *exception)
1138
3.25k
{
1139
3.25k
  char
1140
3.25k
    magick[14];
1141
1142
3.25k
  Image
1143
3.25k
    *image;
1144
1145
3.25k
  int
1146
3.25k
    foundPropEnd = 0;
1147
1148
3.25k
  MagickBooleanType
1149
3.25k
    status;
1150
1151
3.25k
  MagickOffsetType
1152
3.25k
    offset;
1153
1154
3.25k
  ssize_t
1155
3.25k
    i;
1156
1157
3.25k
  size_t
1158
3.25k
    image_type,
1159
3.25k
    length;
1160
1161
3.25k
  ssize_t
1162
3.25k
    count;
1163
1164
3.25k
  XCFDocInfo
1165
3.25k
    doc_info;
1166
1167
  /*
1168
    Open image file.
1169
  */
1170
3.25k
  assert(image_info != (const ImageInfo *) NULL);
1171
3.25k
  assert(image_info->signature == MagickCoreSignature);
1172
3.25k
  assert(exception != (ExceptionInfo *) NULL);
1173
3.25k
  assert(exception->signature == MagickCoreSignature);
1174
3.25k
  if (IsEventLogging() != MagickFalse)
1175
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1176
0
      image_info->filename);
1177
3.25k
  image=AcquireImage(image_info,exception);
1178
3.25k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1179
3.25k
  if (status == MagickFalse)
1180
0
    {
1181
0
      image=DestroyImageList(image);
1182
0
      return((Image *) NULL);
1183
0
    }
1184
3.25k
  count=ReadBlob(image,sizeof(magick),(unsigned char *) magick);
1185
3.25k
  if ((count != sizeof(magick)) ||
1186
3.25k
      (LocaleNCompare((char *) magick,"gimp xcf",8) != 0))
1187
3.20k
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1188
3.20k
  (void) memset(&doc_info,0,sizeof(XCFDocInfo));
1189
3.20k
  doc_info.version=StringToUnsignedLong(magick+10);
1190
3.20k
  doc_info.width=ReadBlobMSBLong(image);
1191
3.20k
  doc_info.height=ReadBlobMSBLong(image);
1192
3.20k
  if ((doc_info.width > 262144) || (doc_info.height > 262144))
1193
3.13k
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1194
3.13k
  doc_info.image_type=ReadBlobMSBLong(image);
1195
3.13k
  if (doc_info.version >= 4)
1196
936
    {
1197
936
      size_t
1198
936
        precision;
1199
1200
936
      precision=ReadBlobMSBLong(image);
1201
936
      if ((precision == 0) && (doc_info.version == 4))
1202
724
        precision=150;
1203
936
      if ((precision == 100) && (doc_info.version < 7))
1204
2
        precision=150;
1205
      /* we only support 8-bit gamma integer */
1206
936
      if (precision != 150)
1207
814
        ThrowReaderException(CoderError,"DataStorageTypeIsNotSupported");
1208
814
    }
1209
  /*
1210
    Initialize image attributes.
1211
  */
1212
3.01k
  image->columns=doc_info.width;
1213
3.01k
  image->rows=doc_info.height;
1214
3.01k
  image_type=doc_info.image_type;
1215
3.01k
  doc_info.file_size=(size_t) GetBlobSize(image);
1216
3.01k
  image->compression=NoCompression;
1217
3.01k
  image->depth=8;
1218
3.01k
  status=SetImageExtent(image,image->columns,image->rows,exception);
1219
3.01k
  if (status == MagickFalse)
1220
86
    return(DestroyImageList(image));
1221
2.93k
  if (status != MagickFalse)
1222
2.93k
    status=ResetImagePixels(image,exception);
1223
2.93k
  if (image_type == GIMP_INDEXED)
1224
2.92k
    ThrowReaderException(CoderError,"ColormapTypeNotSupported");
1225
2.92k
  if (image_type == GIMP_RGB)
1226
2.14k
    SetImageColorspace(image,sRGBColorspace,exception);
1227
781
  else if (image_type == GIMP_GRAY)
1228
712
    SetImageColorspace(image,GRAYColorspace,exception);
1229
69
  else
1230
2.86k
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1231
2.86k
  (void) SetImageBackgroundColor(image,exception);
1232
2.86k
  (void) SetImageAlpha(image,OpaqueAlpha,exception);
1233
  /*
1234
    Read properties.
1235
  */
1236
12.4k
  while ((foundPropEnd == MagickFalse) && (EOFBlob(image) == MagickFalse))
1237
9.63k
  {
1238
9.63k
    PropType prop_type = (PropType) ReadBlobMSBLong(image);
1239
9.63k
    size_t prop_size = ReadBlobMSBLong(image);
1240
1241
9.63k
    switch (prop_type)
1242
9.63k
    {
1243
2.45k
      case PROP_END:
1244
2.45k
        foundPropEnd=1;
1245
2.45k
        break;
1246
214
      case PROP_COLORMAP:
1247
214
      {
1248
        /* Cannot rely on prop_size here--the value is set incorrectly
1249
           by some Gimp versions.
1250
        */
1251
214
        size_t num_colors = ReadBlobMSBLong(image);
1252
214
        if (DiscardBlobBytes(image,3*num_colors) == MagickFalse)
1253
8
          ThrowFileException(exception,CorruptImageError,
1254
214
            "UnexpectedEndOfFile",image->filename);
1255
    /*
1256
      if (info->file_version == 0)
1257
      {
1258
        gint i;
1259
1260
        g_message (_("XCF warning: version 0 of XCF file format\n"
1261
           "did not save indexed colormaps correctly.\n"
1262
           "Substituting grayscale map."));
1263
        info->cp +=
1264
          xcf_read_int32 (info->fp, (guint32*) &gimage->num_cols, 1);
1265
        gimage->cmap = g_new (guchar, gimage->num_cols*3);
1266
        xcf_seek_pos (info, info->cp + gimage->num_cols);
1267
        for (i = 0; i<gimage->num_cols; i++)
1268
          {
1269
            gimage->cmap[i*3+0] = i;
1270
            gimage->cmap[i*3+1] = i;
1271
            gimage->cmap[i*3+2] = i;
1272
          }
1273
      }
1274
      else
1275
      {
1276
        info->cp +=
1277
          xcf_read_int32 (info->fp, (guint32*) &gimage->num_cols, 1);
1278
        gimage->cmap = g_new (guchar, gimage->num_cols*3);
1279
        info->cp +=
1280
          xcf_read_int8 (info->fp,
1281
                   (guint8*) gimage->cmap, gimage->num_cols*3);
1282
      }
1283
     */
1284
214
        break;
1285
0
      }
1286
1.85k
      case PROP_COMPRESSION:
1287
1.85k
      {
1288
1.85k
        doc_info.compression = ReadBlobByte(image);
1289
1.85k
        if ((doc_info.compression != COMPRESS_NONE) &&
1290
1.85k
            (doc_info.compression != COMPRESS_RLE) &&
1291
1.85k
            (doc_info.compression != COMPRESS_ZLIB) &&
1292
1.85k
            (doc_info.compression != COMPRESS_FRACTAL))
1293
1.83k
          ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression");
1294
1.83k
      }
1295
0
      break;
1296
1297
246
      case PROP_GUIDES:
1298
246
      {
1299
         /* just skip it - we don't care about guides */
1300
246
        if (DiscardBlobBytes(image,prop_size) == MagickFalse)
1301
13
          ThrowFileException(exception,CorruptImageError,
1302
246
            "UnexpectedEndOfFile",image->filename);
1303
246
      }
1304
246
      break;
1305
1306
1.14k
    case PROP_RESOLUTION:
1307
1.14k
      {
1308
1.14k
        float
1309
1.14k
          x,
1310
1.14k
          y;
1311
1312
1.14k
        x=ReadBlobFloat(image);
1313
1.14k
        y=ReadBlobFloat(image);
1314
1.14k
        if ((x >= GIMP_MIN_RESOLUTION) && (x <= GIMP_MAX_RESOLUTION) &&
1315
1.14k
            (y >= GIMP_MIN_RESOLUTION) && (y <= GIMP_MAX_RESOLUTION))
1316
198
          {
1317
198
            image->resolution.x=(double) x;
1318
198
            image->resolution.y=(double) y;
1319
198
            image->units=PixelsPerInchResolution;
1320
198
          }
1321
1.14k
      }
1322
1.14k
      break;
1323
1324
212
    case PROP_TATTOO:
1325
212
      {
1326
        /* we need to read it, even if we ignore it */
1327
212
        /*size_t  tattoo_state = */ (void) ReadBlobMSBLong(image);
1328
212
      }
1329
212
      break;
1330
1331
444
    case PROP_PARASITES:
1332
444
      {
1333
        /* BOGUS: we may need these for IPTC stuff */
1334
444
        if (DiscardBlobBytes(image,prop_size) == MagickFalse)
1335
40
          ThrowFileException(exception,CorruptImageError,
1336
444
            "UnexpectedEndOfFile",image->filename);
1337
        /*
1338
      gssize_t         base = info->cp;
1339
      GimpParasite *p;
1340
1341
      while (info->cp - base < prop_size)
1342
        {
1343
          p = xcf_load_parasite (info);
1344
          gimp_image_parasite_attach (gimage, p);
1345
          gimp_parasite_free (p);
1346
        }
1347
      if (info->cp - base != prop_size)
1348
        g_message ("Error detected while loading an image's parasites");
1349
      */
1350
444
          }
1351
444
      break;
1352
1353
198
    case PROP_UNIT:
1354
198
      {
1355
        /* BOGUS: ignore for now... */
1356
198
      /*size_t unit =  */ (void) ReadBlobMSBLong(image);
1357
198
      }
1358
198
      break;
1359
1360
250
    case PROP_PATHS:
1361
250
      {
1362
      /* BOGUS: just skip it for now */
1363
250
        if (DiscardBlobBytes(image,prop_size) == MagickFalse)
1364
24
          ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1365
250
            image->filename);
1366
1367
        /*
1368
      PathList *paths = xcf_load_bzpaths (gimage, info);
1369
      gimp_image_set_paths (gimage, paths);
1370
      */
1371
250
      }
1372
250
      break;
1373
1374
178
    case PROP_USER_UNIT:
1375
178
      {
1376
178
        char  unit_string[1000];
1377
        /*BOGUS: ignored for now */
1378
178
        /*float  factor = (float) */ (void) ReadBlobMSBLong(image);
1379
178
        /* size_t digits =  */ (void) ReadBlobMSBLong(image);
1380
1.06k
        for (i=0; i<5; i++)
1381
890
         (void) ReadBlobStringWithLongSize(image, unit_string,
1382
890
           sizeof(unit_string),exception);
1383
178
      }
1384
178
     break;
1385
1386
2.43k
      default:
1387
2.43k
      {
1388
2.43k
        int buf[16];
1389
2.43k
        ssize_t amount;
1390
1391
      /* read over it... */
1392
6.79k
      while ((prop_size > 0) && (EOFBlob(image) == MagickFalse))
1393
4.42k
      {
1394
4.42k
        amount=(ssize_t) MagickMin(16, prop_size);
1395
4.42k
        amount=(ssize_t) ReadBlob(image,(size_t) amount,(unsigned char *) &buf);
1396
4.42k
        if (!amount)
1397
4.36k
          ThrowReaderException(CorruptImageError,"CorruptImage");
1398
4.36k
        prop_size -= (size_t) MagickMin(16,(size_t) amount);
1399
4.36k
      }
1400
2.43k
    }
1401
2.37k
    break;
1402
9.63k
  }
1403
9.63k
  }
1404
2.78k
  if (foundPropEnd == MagickFalse)
1405
2.45k
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1406
1407
2.45k
  if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
1408
0
    {
1409
0
      ; /* do nothing, were just pinging! */
1410
0
    }
1411
2.45k
  else
1412
2.45k
    {
1413
2.45k
      MagickBooleanType
1414
2.45k
        foundAllLayers = MagickFalse;
1415
1416
2.45k
      MagickOffsetType
1417
2.45k
        oldPos = TellBlob(image);
1418
1419
2.45k
      size_t
1420
2.45k
        number_layers = 0;
1421
1422
2.45k
      ssize_t
1423
2.45k
        current_layer = 0;
1424
1425
2.45k
      XCFLayerInfo
1426
2.45k
        *layer_info;
1427
1428
      /*
1429
        The read pointer.
1430
      */
1431
2.45k
      do
1432
10.3k
      {
1433
10.3k
        offset=GetXCFOffset(image,&doc_info);
1434
10.3k
        if (offset == 0)
1435
2.45k
          foundAllLayers=MagickTrue;
1436
7.84k
        else
1437
7.84k
          {
1438
7.84k
            number_layers++;
1439
7.84k
            if (AcquireMagickResource(ListLengthResource,number_layers) == MagickFalse)
1440
7.84k
              ThrowReaderException(ResourceLimitError,"ListLengthExceedsLimit");
1441
7.84k
          }
1442
10.2k
        if (EOFBlob(image) != MagickFalse)
1443
1.66k
          {
1444
1.66k
            ThrowFileException(exception,CorruptImageError,
1445
1.66k
              "UnexpectedEndOfFile",image->filename);
1446
1.66k
            break;
1447
1.66k
          }
1448
10.2k
    } while (foundAllLayers == MagickFalse);
1449
2.45k
    doc_info.number_layers=number_layers;
1450
2.45k
    offset=SeekBlob(image,oldPos,SEEK_SET); /* restore the position! */
1451
2.45k
    if (offset < 0)
1452
2.45k
      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1453
    /* allocate our array of layer info blocks */
1454
2.45k
    length=(size_t) number_layers;
1455
2.45k
    layer_info=(XCFLayerInfo *) AcquireQuantumMemory(length,
1456
2.45k
      sizeof(*layer_info));
1457
2.45k
    if (layer_info == (XCFLayerInfo *) NULL)
1458
2.31k
      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1459
2.31k
    (void) memset(layer_info,0,number_layers*sizeof(XCFLayerInfo));
1460
2.31k
    for ( ; ; )
1461
5.93k
    {
1462
5.93k
      MagickBooleanType
1463
5.93k
        layer_ok;
1464
1465
5.93k
      MagickOffsetType
1466
5.93k
        saved_pos;
1467
1468
      /* read in the offset of the next layer */
1469
5.93k
      offset=GetXCFOffset(image,&doc_info);
1470
      /* if the offset is 0 then we are at the end
1471
      *  of the layer list.
1472
      */
1473
5.93k
      if (offset == 0)
1474
285
        break;
1475
      /* save the current position as it is where the
1476
      *  next layer offset is stored.
1477
      */
1478
5.65k
      saved_pos=TellBlob(image);
1479
      /* seek to the layer offset */
1480
5.65k
      layer_ok=MagickFalse;
1481
5.65k
      if (SeekBlob(image,offset,SEEK_SET) == offset)
1482
5.46k
        {
1483
          /* read in the layer */
1484
5.46k
          layer_ok=ReadOneLayer(image_info,image,&doc_info,
1485
5.46k
            &layer_info[current_layer],current_layer,exception);
1486
5.46k
        }
1487
5.65k
      if (layer_ok == MagickFalse)
1488
2.03k
        {
1489
2.03k
          ssize_t j;
1490
1491
5.34k
          for (j=0; j <= current_layer; j++)
1492
3.31k
            if (layer_info[j].image != (Image *) NULL)
1493
2.55k
              layer_info[j].image=DestroyImage(layer_info[j].image);
1494
2.03k
          layer_info=(XCFLayerInfo *) RelinquishMagickMemory(layer_info);
1495
2.03k
          ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
1496
0
        }
1497
      /* restore the saved position so we'll be ready to
1498
      *  read the next offset.
1499
      */
1500
3.61k
      offset=SeekBlob(image, saved_pos, SEEK_SET);
1501
3.61k
      current_layer++;
1502
3.61k
    }
1503
#if 0
1504
        {
1505
        /* NOTE: XCF layers are REVERSED from composite order! */
1506
        signed int  j;
1507
        for (j=number_layers-1; j>=0; j--) {
1508
          /* BOGUS: need to consider layer blending modes!! */
1509
1510
          if ( layer_info[j].visible ) { /* only visible ones, please! */
1511
            CompositeImage(image, OverCompositeOp, layer_info[j].image,
1512
                     layer_info[j].offset_x, layer_info[j].offset_y );
1513
             layer_info[j].image =DestroyImage( layer_info[j].image );
1514
1515
            /* If we do this, we'll get REAL gray images! */
1516
            if ( image_type == GIMP_GRAY ) {
1517
              QuantizeInfo  qi;
1518
              GetQuantizeInfo(&qi);
1519
              qi.colorspace = GRAYColorspace;
1520
              QuantizeImage( &qi, layer_info[j].image );
1521
            }
1522
          }
1523
        }
1524
      }
1525
#else
1526
285
      {
1527
        /* NOTE: XCF layers are REVERSED from composite order! */
1528
285
        ssize_t  j;
1529
1530
        /* now reverse the order of the layers as they are put
1531
           into subimages
1532
        */
1533
2.62k
        for (j=(ssize_t) number_layers-1; j >= 0; j--)
1534
2.34k
          AppendImageToList(&image,layer_info[j].image);
1535
285
      }
1536
285
#endif
1537
1538
285
    layer_info=(XCFLayerInfo *) RelinquishMagickMemory(layer_info);
1539
1540
#if 0  /* BOGUS: do we need the channels?? */
1541
    while (MagickTrue)
1542
    {
1543
      /* read in the offset of the next channel */
1544
      info->cp += xcf_read_int32 (info->fp, &offset, 1);
1545
1546
      /* if the offset is 0 then we are at the end
1547
      *  of the channel list.
1548
      */
1549
      if (offset == 0)
1550
        break;
1551
1552
      /* save the current position as it is where the
1553
      *  next channel offset is stored.
1554
      */
1555
      saved_pos = info->cp;
1556
1557
      /* seek to the channel offset */
1558
      xcf_seek_pos (info, offset);
1559
1560
      /* read in the layer */
1561
      channel = xcf_load_channel (info, gimage);
1562
      if (channel == 0)
1563
        goto error;
1564
1565
      num_successful_elements++;
1566
1567
      /* add the channel to the image if its not the selection */
1568
      if (channel != gimage->selection_mask)
1569
        gimp_image_add_channel (gimage, channel, -1);
1570
1571
      /* restore the saved position so we'll be ready to
1572
      *  read the next offset.
1573
      */
1574
      xcf_seek_pos (info, saved_pos);
1575
    }
1576
#endif
1577
285
  }
1578
1579
285
  (void) CloseBlob(image);
1580
285
  if (GetNextImageInList(image) != (Image *) NULL)
1581
285
    DestroyImage(RemoveFirstImageFromList(&image));
1582
285
  if (image_type == GIMP_GRAY)
1583
35
    image->type=GrayscaleType;
1584
285
  return(GetFirstImageInList(image));
1585
2.45k
}
1586

1587
/*
1588
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589
%                                                                             %
1590
%                                                                             %
1591
%                                                                             %
1592
%   R e g i s t e r X C F I m a g e                                           %
1593
%                                                                             %
1594
%                                                                             %
1595
%                                                                             %
1596
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597
%
1598
%  RegisterXCFImage() adds attributes for the XCF image format to
1599
%  the list of supported formats.  The attributes include the image format
1600
%  tag, a method to read and/or write the format, whether the format
1601
%  supports the saving of more than one frame to the same file or blob,
1602
%  whether the format supports native in-memory I/O, and a brief
1603
%  description of the format.
1604
%
1605
%  The format of the RegisterXCFImage method is:
1606
%
1607
%      size_t RegisterXCFImage(void)
1608
%
1609
*/
1610
ModuleExport size_t RegisterXCFImage(void)
1611
10
{
1612
10
  MagickInfo
1613
10
    *entry;
1614
1615
10
  entry=AcquireMagickInfo("XCF","XCF","GIMP image");
1616
10
  entry->decoder=(DecodeImageHandler *) ReadXCFImage;
1617
10
  entry->magick=(IsImageFormatHandler *) IsXCF;
1618
10
  entry->flags|=CoderDecoderSeekableStreamFlag;
1619
10
  (void) RegisterMagickInfo(entry);
1620
10
  return(MagickImageCoderSignature);
1621
10
}
1622

1623
/*
1624
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1625
%                                                                             %
1626
%                                                                             %
1627
%                                                                             %
1628
%   U n r e g i s t e r X C F I m a g e                                       %
1629
%                                                                             %
1630
%                                                                             %
1631
%                                                                             %
1632
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1633
%
1634
%  UnregisterXCFImage() removes format registrations made by the
1635
%  XCF module from the list of supported formats.
1636
%
1637
%  The format of the UnregisterXCFImage method is:
1638
%
1639
%      UnregisterXCFImage(void)
1640
%
1641
*/
1642
ModuleExport void UnregisterXCFImage(void)
1643
0
{
1644
0
  (void) UnregisterMagickInfo("XCF");
1645
0
}