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