• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-2020 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   register 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   register ssize_t
427     x;
428 
429   register 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   register 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   register 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(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     }
1046 
1047   InitXCFImage(outLayer,exception);
1048 
1049   /* set the compositing mode */
1050   outLayer->image->compose = GIMPBlendModeToCompositeOperator( outLayer->mode );
1051   if ( outLayer->visible == MagickFalse )
1052     {
1053       /* BOGUS: should really be separate member var! */
1054       outLayer->image->compose = NoCompositeOp;
1055     }
1056 
1057   /* read the hierarchy and layer mask offsets */
1058   hierarchy_offset = GetXCFOffset(image,inDocInfo);
1059   layer_mask_offset = GetXCFOffset(image,inDocInfo);
1060 
1061   /* read in the hierarchy */
1062   offset=SeekBlob(image, hierarchy_offset, SEEK_SET);
1063   if (offset != hierarchy_offset)
1064     ThrowBinaryException(CorruptImageError,"InvalidImageHeader",
1065       image->filename);
1066   if (load_hierarchy (image, inDocInfo, outLayer, exception) == 0)
1067     return(MagickFalse);
1068 
1069   /* read in the layer mask */
1070   if (layer_mask_offset != 0)
1071     {
1072       offset=SeekBlob(image, (MagickOffsetType) layer_mask_offset, SEEK_SET);
1073 
1074 #if 0  /* BOGUS: support layer masks! */
1075       layer_mask = xcf_load_layer_mask (info, gimage);
1076       if (layer_mask == 0)
1077   goto error;
1078 
1079       /* set the offsets of the layer_mask */
1080       GIMP_DRAWABLE (layer_mask)->offset_x = GIMP_DRAWABLE (layer)->offset_x;
1081       GIMP_DRAWABLE (layer_mask)->offset_y = GIMP_DRAWABLE (layer)->offset_y;
1082 
1083       gimp_layer_add_mask (layer, layer_mask, MagickFalse);
1084 
1085       layer->mask->apply_mask = apply_mask;
1086       layer->mask->edit_mask  = edit_mask;
1087       layer->mask->show_mask  = show_mask;
1088 #endif
1089   }
1090 
1091   /* attach the floating selection... */
1092 #if 0  /* BOGUS: we may need to read this, even if we don't support it! */
1093   if (add_floating_sel)
1094     {
1095       GimpLayer *floating_sel;
1096 
1097       floating_sel = info->floating_sel;
1098       floating_sel_attach (floating_sel, GIMP_DRAWABLE (layer));
1099     }
1100 #endif
1101 
1102   return MagickTrue;
1103 }
1104 
1105 /*
1106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1107 %                                                                             %
1108 %                                                                             %
1109 %                                                                             %
1110 %   R e a d X C F I m a g e                                                   %
1111 %                                                                             %
1112 %                                                                             %
1113 %                                                                             %
1114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1115 %
1116 %  ReadXCFImage() reads a GIMP (GNU Image Manipulation Program) image
1117 %  file and returns it.  It allocates the memory necessary for the new Image
1118 %  structure and returns a pointer to the new image.
1119 %
1120 %  The format of the ReadXCFImage method is:
1121 %
1122 %      image=ReadXCFImage(image_info)
1123 %
1124 %  A description of each parameter follows:
1125 %
1126 %    o image_info: the image info.
1127 %
1128 %    o exception: return any errors or warnings in this structure.
1129 %
1130 */
ReadXCFImage(const ImageInfo * image_info,ExceptionInfo * exception)1131 static Image *ReadXCFImage(const ImageInfo *image_info,ExceptionInfo *exception)
1132 {
1133   char
1134     magick[14];
1135 
1136   Image
1137     *image;
1138 
1139   int
1140     foundPropEnd = 0;
1141 
1142   MagickBooleanType
1143     status;
1144 
1145   MagickOffsetType
1146     offset;
1147 
1148   register ssize_t
1149     i;
1150 
1151   size_t
1152     image_type,
1153     precision,
1154     length;
1155 
1156   ssize_t
1157     count;
1158 
1159   XCFDocInfo
1160     doc_info;
1161 
1162   /*
1163     Open image file.
1164   */
1165   assert(image_info != (const ImageInfo *) NULL);
1166   assert(image_info->signature == MagickCoreSignature);
1167   if (image_info->debug != MagickFalse)
1168     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1169       image_info->filename);
1170   assert(exception != (ExceptionInfo *) NULL);
1171   assert(exception->signature == MagickCoreSignature);
1172   image=AcquireImage(image_info,exception);
1173   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1174   if (status == MagickFalse)
1175     {
1176       image=DestroyImageList(image);
1177       return((Image *) NULL);
1178     }
1179   count=ReadBlob(image,sizeof(magick),(unsigned char *) magick);
1180   if ((count != sizeof(magick)) ||
1181       (LocaleNCompare((char *) magick,"gimp xcf",8) != 0))
1182     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1183   (void) memset(&doc_info,0,sizeof(XCFDocInfo));
1184   doc_info.version=StringToUnsignedLong(magick+10);
1185   doc_info.width=ReadBlobMSBLong(image);
1186   doc_info.height=ReadBlobMSBLong(image);
1187   if ((doc_info.width > 262144) || (doc_info.height > 262144))
1188     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1189   doc_info.image_type=ReadBlobMSBLong(image);
1190   precision=150;
1191   if (doc_info.version >= 4)
1192     {
1193       precision=ReadBlobMSBLong(image);
1194       if (precision == 0)
1195         precision=150;
1196       if (precision != 150)
1197         ThrowReaderException(CoderError,"DataStorageTypeIsNotSupported");
1198     }
1199   /*
1200     Initialize image attributes.
1201   */
1202   image->columns=doc_info.width;
1203   image->rows=doc_info.height;
1204   image_type=doc_info.image_type;
1205   doc_info.file_size=GetBlobSize(image);
1206   image->compression=NoCompression;
1207   image->depth=8;
1208   status=SetImageExtent(image,image->columns,image->rows,exception);
1209   if (status == MagickFalse)
1210     return(DestroyImageList(image));
1211   if (status != MagickFalse)
1212     status=ResetImagePixels(image,exception);
1213   if (image_type == GIMP_INDEXED)
1214     ThrowReaderException(CoderError,"ColormapTypeNotSupported");
1215   if (image_type == GIMP_RGB)
1216     SetImageColorspace(image,sRGBColorspace,exception);
1217   else if (image_type == GIMP_GRAY)
1218     SetImageColorspace(image,GRAYColorspace,exception);
1219   else
1220     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1221   (void) SetImageBackgroundColor(image,exception);
1222   (void) SetImageAlpha(image,OpaqueAlpha,exception);
1223   /*
1224     Read properties.
1225   */
1226   while ((foundPropEnd == MagickFalse) && (EOFBlob(image) == MagickFalse))
1227   {
1228     PropType prop_type = (PropType) ReadBlobMSBLong(image);
1229     size_t prop_size = ReadBlobMSBLong(image);
1230 
1231     switch (prop_type)
1232     {
1233       case PROP_END:
1234         foundPropEnd=1;
1235         break;
1236       case PROP_COLORMAP:
1237       {
1238         /* Cannot rely on prop_size here--the value is set incorrectly
1239            by some Gimp versions.
1240         */
1241         size_t num_colours = ReadBlobMSBLong(image);
1242         if (DiscardBlobBytes(image,3*num_colours) == MagickFalse)
1243           ThrowFileException(exception,CorruptImageError,
1244             "UnexpectedEndOfFile",image->filename);
1245     /*
1246       if (info->file_version == 0)
1247       {
1248         gint i;
1249 
1250         g_message (_("XCF warning: version 0 of XCF file format\n"
1251            "did not save indexed colormaps correctly.\n"
1252            "Substituting grayscale map."));
1253         info->cp +=
1254           xcf_read_int32 (info->fp, (guint32*) &gimage->num_cols, 1);
1255         gimage->cmap = g_new (guchar, gimage->num_cols*3);
1256         xcf_seek_pos (info, info->cp + gimage->num_cols);
1257         for (i = 0; i<gimage->num_cols; i++)
1258           {
1259             gimage->cmap[i*3+0] = i;
1260             gimage->cmap[i*3+1] = i;
1261             gimage->cmap[i*3+2] = i;
1262           }
1263       }
1264       else
1265       {
1266         info->cp +=
1267           xcf_read_int32 (info->fp, (guint32*) &gimage->num_cols, 1);
1268         gimage->cmap = g_new (guchar, gimage->num_cols*3);
1269         info->cp +=
1270           xcf_read_int8 (info->fp,
1271                    (guint8*) gimage->cmap, gimage->num_cols*3);
1272       }
1273      */
1274         break;
1275       }
1276       case PROP_COMPRESSION:
1277       {
1278         doc_info.compression = ReadBlobByte(image);
1279         if ((doc_info.compression != COMPRESS_NONE) &&
1280             (doc_info.compression != COMPRESS_RLE) &&
1281             (doc_info.compression != COMPRESS_ZLIB) &&
1282             (doc_info.compression != COMPRESS_FRACTAL))
1283           ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression");
1284       }
1285       break;
1286 
1287       case PROP_GUIDES:
1288       {
1289          /* just skip it - we don't care about guides */
1290         if (DiscardBlobBytes(image,prop_size) == MagickFalse)
1291           ThrowFileException(exception,CorruptImageError,
1292             "UnexpectedEndOfFile",image->filename);
1293       }
1294       break;
1295 
1296     case PROP_RESOLUTION:
1297       {
1298         /* float xres = (float) */ (void) ReadBlobMSBLong(image);
1299         /* float yres = (float) */ (void) ReadBlobMSBLong(image);
1300 
1301         /*
1302         if (xres < GIMP_MIN_RESOLUTION || xres > GIMP_MAX_RESOLUTION ||
1303             yres < GIMP_MIN_RESOLUTION || yres > GIMP_MAX_RESOLUTION)
1304         {
1305         g_message ("Warning, resolution out of range in XCF file");
1306         xres = gimage->gimp->config->default_xresolution;
1307         yres = gimage->gimp->config->default_yresolution;
1308         }
1309         */
1310 
1311 
1312         /* BOGUS: we don't write these yet because we aren't
1313               reading them properly yet :(
1314               image->resolution.x = xres;
1315               image->resolution.y = yres;
1316         */
1317       }
1318       break;
1319 
1320     case PROP_TATTOO:
1321       {
1322         /* we need to read it, even if we ignore it */
1323         /*size_t  tattoo_state = */ (void) ReadBlobMSBLong(image);
1324       }
1325       break;
1326 
1327     case PROP_PARASITES:
1328       {
1329         /* BOGUS: we may need these for IPTC stuff */
1330         if (DiscardBlobBytes(image,prop_size) == MagickFalse)
1331           ThrowFileException(exception,CorruptImageError,
1332             "UnexpectedEndOfFile",image->filename);
1333         /*
1334       gssize_t         base = info->cp;
1335       GimpParasite *p;
1336 
1337       while (info->cp - base < prop_size)
1338         {
1339           p = xcf_load_parasite (info);
1340           gimp_image_parasite_attach (gimage, p);
1341           gimp_parasite_free (p);
1342         }
1343       if (info->cp - base != prop_size)
1344         g_message ("Error detected while loading an image's parasites");
1345       */
1346           }
1347       break;
1348 
1349     case PROP_UNIT:
1350       {
1351         /* BOGUS: ignore for now... */
1352       /*size_t unit =  */ (void) ReadBlobMSBLong(image);
1353       }
1354       break;
1355 
1356     case PROP_PATHS:
1357       {
1358       /* BOGUS: just skip it for now */
1359         if (DiscardBlobBytes(image,prop_size) == MagickFalse)
1360           ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1361             image->filename);
1362 
1363         /*
1364       PathList *paths = xcf_load_bzpaths (gimage, info);
1365       gimp_image_set_paths (gimage, paths);
1366       */
1367       }
1368       break;
1369 
1370     case PROP_USER_UNIT:
1371       {
1372         char  unit_string[1000];
1373         /*BOGUS: ignored for now */
1374         /*float  factor = (float) */ (void) ReadBlobMSBLong(image);
1375         /* size_t digits =  */ (void) ReadBlobMSBLong(image);
1376         for (i=0; i<5; i++)
1377          (void) ReadBlobStringWithLongSize(image, unit_string,
1378            sizeof(unit_string),exception);
1379       }
1380      break;
1381 
1382       default:
1383       {
1384         int buf[16];
1385         ssize_t amount;
1386 
1387       /* read over it... */
1388       while ((prop_size > 0) && (EOFBlob(image) == MagickFalse))
1389       {
1390         amount=(ssize_t) MagickMin(16, prop_size);
1391         amount=(ssize_t) ReadBlob(image,(size_t) amount,(unsigned char *) &buf);
1392         if (!amount)
1393           ThrowReaderException(CorruptImageError,"CorruptImage");
1394         prop_size -= (size_t) MagickMin(16,(size_t) amount);
1395       }
1396     }
1397     break;
1398   }
1399   }
1400   if (foundPropEnd == MagickFalse)
1401     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1402 
1403   if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
1404     {
1405       ; /* do nothing, were just pinging! */
1406     }
1407   else
1408     {
1409       int
1410         current_layer = 0,
1411         foundAllLayers = MagickFalse,
1412         number_layers = 0;
1413 
1414       MagickOffsetType
1415         oldPos=TellBlob(image);
1416 
1417       XCFLayerInfo
1418         *layer_info;
1419 
1420       /*
1421         The read pointer.
1422       */
1423       do
1424       {
1425         offset=GetXCFOffset(image,&doc_info);
1426         if (offset == 0)
1427           foundAllLayers=MagickTrue;
1428         else
1429           number_layers++;
1430         if (EOFBlob(image) != MagickFalse)
1431           {
1432             ThrowFileException(exception,CorruptImageError,
1433               "UnexpectedEndOfFile",image->filename);
1434             break;
1435           }
1436     } while (foundAllLayers == MagickFalse);
1437     if (AcquireMagickResource(ListLengthResource,number_layers) == MagickFalse)
1438       ThrowReaderException(ResourceLimitError,"ListLengthExceedsLimit");
1439     doc_info.number_layers=number_layers;
1440     offset=SeekBlob(image,oldPos,SEEK_SET); /* restore the position! */
1441     if (offset < 0)
1442       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1443     /* allocate our array of layer info blocks */
1444     length=(size_t) number_layers;
1445     layer_info=(XCFLayerInfo *) AcquireQuantumMemory(length,
1446       sizeof(*layer_info));
1447     if (layer_info == (XCFLayerInfo *) NULL)
1448       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1449     (void) memset(layer_info,0,number_layers*sizeof(XCFLayerInfo));
1450     for ( ; ; )
1451     {
1452       MagickBooleanType
1453         layer_ok;
1454 
1455       MagickOffsetType
1456         saved_pos;
1457 
1458       /* read in the offset of the next layer */
1459       offset=GetXCFOffset(image,&doc_info);
1460       /* if the offset is 0 then we are at the end
1461       *  of the layer list.
1462       */
1463       if (offset == 0)
1464         break;
1465       /* save the current position as it is where the
1466       *  next layer offset is stored.
1467       */
1468       saved_pos=TellBlob(image);
1469       /* seek to the layer offset */
1470       layer_ok=MagickFalse;
1471       if (SeekBlob(image,offset,SEEK_SET) == offset)
1472         {
1473           /* read in the layer */
1474           layer_ok=ReadOneLayer(image_info,image,&doc_info,
1475             &layer_info[current_layer],current_layer,exception);
1476         }
1477       if (layer_ok == MagickFalse)
1478         {
1479           ssize_t j;
1480 
1481           for (j=0; j <= current_layer; j++)
1482             if (layer_info[j].image != (Image *) NULL)
1483               layer_info[j].image=DestroyImage(layer_info[j].image);
1484           layer_info=(XCFLayerInfo *) RelinquishMagickMemory(layer_info);
1485           ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
1486         }
1487       /* restore the saved position so we'll be ready to
1488       *  read the next offset.
1489       */
1490       offset=SeekBlob(image, saved_pos, SEEK_SET);
1491       current_layer++;
1492     }
1493 #if 0
1494         {
1495         /* NOTE: XCF layers are REVERSED from composite order! */
1496         signed int  j;
1497         for (j=number_layers-1; j>=0; j--) {
1498           /* BOGUS: need to consider layer blending modes!! */
1499 
1500           if ( layer_info[j].visible ) { /* only visible ones, please! */
1501             CompositeImage(image, OverCompositeOp, layer_info[j].image,
1502                      layer_info[j].offset_x, layer_info[j].offset_y );
1503              layer_info[j].image =DestroyImage( layer_info[j].image );
1504 
1505             /* If we do this, we'll get REAL gray images! */
1506             if ( image_type == GIMP_GRAY ) {
1507               QuantizeInfo  qi;
1508               GetQuantizeInfo(&qi);
1509               qi.colorspace = GRAYColorspace;
1510               QuantizeImage( &qi, layer_info[j].image );
1511             }
1512           }
1513         }
1514       }
1515 #else
1516       {
1517         /* NOTE: XCF layers are REVERSED from composite order! */
1518         ssize_t  j;
1519 
1520         /* now reverse the order of the layers as they are put
1521            into subimages
1522         */
1523         for (j=(ssize_t) number_layers-1; j >= 0; j--)
1524           AppendImageToList(&image,layer_info[j].image);
1525       }
1526 #endif
1527 
1528     layer_info=(XCFLayerInfo *) RelinquishMagickMemory(layer_info);
1529 
1530 #if 0  /* BOGUS: do we need the channels?? */
1531     while (MagickTrue)
1532     {
1533       /* read in the offset of the next channel */
1534       info->cp += xcf_read_int32 (info->fp, &offset, 1);
1535 
1536       /* if the offset is 0 then we are at the end
1537       *  of the channel list.
1538       */
1539       if (offset == 0)
1540         break;
1541 
1542       /* save the current position as it is where the
1543       *  next channel offset is stored.
1544       */
1545       saved_pos = info->cp;
1546 
1547       /* seek to the channel offset */
1548       xcf_seek_pos (info, offset);
1549 
1550       /* read in the layer */
1551       channel = xcf_load_channel (info, gimage);
1552       if (channel == 0)
1553         goto error;
1554 
1555       num_successful_elements++;
1556 
1557       /* add the channel to the image if its not the selection */
1558       if (channel != gimage->selection_mask)
1559         gimp_image_add_channel (gimage, channel, -1);
1560 
1561       /* restore the saved position so we'll be ready to
1562       *  read the next offset.
1563       */
1564       xcf_seek_pos (info, saved_pos);
1565     }
1566 #endif
1567   }
1568 
1569   (void) CloseBlob(image);
1570   if (GetNextImageInList(image) != (Image *) NULL)
1571     DestroyImage(RemoveFirstImageFromList(&image));
1572   if (image_type == GIMP_GRAY)
1573     image->type=GrayscaleType;
1574   return(GetFirstImageInList(image));
1575 }
1576 
1577 /*
1578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1579 %                                                                             %
1580 %                                                                             %
1581 %                                                                             %
1582 %   R e g i s t e r X C F I m a g e                                           %
1583 %                                                                             %
1584 %                                                                             %
1585 %                                                                             %
1586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1587 %
1588 %  RegisterXCFImage() adds attributes for the XCF image format to
1589 %  the list of supported formats.  The attributes include the image format
1590 %  tag, a method to read and/or write the format, whether the format
1591 %  supports the saving of more than one frame to the same file or blob,
1592 %  whether the format supports native in-memory I/O, and a brief
1593 %  description of the format.
1594 %
1595 %  The format of the RegisterXCFImage method is:
1596 %
1597 %      size_t RegisterXCFImage(void)
1598 %
1599 */
RegisterXCFImage(void)1600 ModuleExport size_t RegisterXCFImage(void)
1601 {
1602   MagickInfo
1603     *entry;
1604 
1605   entry=AcquireMagickInfo("XCF","XCF","GIMP image");
1606   entry->decoder=(DecodeImageHandler *) ReadXCFImage;
1607   entry->magick=(IsImageFormatHandler *) IsXCF;
1608   entry->flags|=CoderDecoderSeekableStreamFlag;
1609   (void) RegisterMagickInfo(entry);
1610   return(MagickImageCoderSignature);
1611 }
1612 
1613 /*
1614 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1615 %                                                                             %
1616 %                                                                             %
1617 %                                                                             %
1618 %   U n r e g i s t e r X C F I m a g e                                       %
1619 %                                                                             %
1620 %                                                                             %
1621 %                                                                             %
1622 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1623 %
1624 %  UnregisterXCFImage() removes format registrations made by the
1625 %  XCF module from the list of supported formats.
1626 %
1627 %  The format of the UnregisterXCFImage method is:
1628 %
1629 %      UnregisterXCFImage(void)
1630 %
1631 */
UnregisterXCFImage(void)1632 ModuleExport void UnregisterXCFImage(void)
1633 {
1634   (void) UnregisterMagickInfo("XCF");
1635 }
1636