• 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-2019 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 (offset == 0)
720     return(MagickTrue);
721   /*
722     Initialise the reference for the in-memory tile-compression
723   */
724   ntile_rows=(height+TILE_HEIGHT-1)/TILE_HEIGHT;
725   ntile_cols=(width+TILE_WIDTH-1)/TILE_WIDTH;
726   ntiles=ntile_rows*ntile_cols;
727   for (i = 0; i < (ssize_t) ntiles; i++)
728   {
729     status=MagickFalse;
730     if (offset == 0)
731       ThrowBinaryException(CorruptImageError,"NotEnoughTiles",image->filename);
732     /*
733       Save the current position as it is where the next tile offset is stored.
734     */
735     saved_pos=TellBlob(image);
736     /* read in the offset of the next tile so we can calculate the amount
737        of data needed for this tile*/
738     offset2=GetXCFOffset(image,inDocInfo);
739     if ((MagickSizeType) offset2 >= inDocInfo->file_size)
740       ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
741         image->filename);
742     /* if the offset is 0 then we need to read in the maximum possible
743        allowing for negative compression */
744     if (offset2 == 0)
745       offset2=(MagickOffsetType) (offset + TILE_WIDTH * TILE_WIDTH * 4* 1.5);
746     /* seek to the tile offset */
747     if ((offset > offset2) || (SeekBlob(image, offset, SEEK_SET) != offset))
748       ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
749         image->filename);
750 
751       /*
752         Allocate the image for the tile.  NOTE: the last tile in a row or
753         column may not be a full tile!
754       */
755       tile_image_width=(size_t) (destLeft == (int) ntile_cols-1 ?
756         (int) width % TILE_WIDTH : TILE_WIDTH);
757       if (tile_image_width == 0)
758         tile_image_width=TILE_WIDTH;
759       tile_image_height = (size_t) (destTop == (int) ntile_rows-1 ?
760         (int) height % TILE_HEIGHT : TILE_HEIGHT);
761       if (tile_image_height == 0)
762         tile_image_height=TILE_HEIGHT;
763       tile_image=CloneImage(inLayerInfo->image,tile_image_width,
764         tile_image_height,MagickTrue,exception);
765       if (tile_image == (Image *) NULL)
766         ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
767           image->filename);
768       (void) SetImageBackgroundColor(tile_image,exception);
769 
770       /* read in the tile */
771       switch (inDocInfo->compression)
772       {
773         case COMPRESS_NONE:
774           status=load_tile(image,tile_image,inDocInfo,inLayerInfo,(size_t)
775             (offset2-offset),exception);
776           break;
777         case COMPRESS_RLE:
778           status=load_tile_rle(image,tile_image,inDocInfo,inLayerInfo,(size_t)
779             (offset2-offset),exception);
780           break;
781         case COMPRESS_ZLIB:
782           tile_image=DestroyImage(tile_image);
783           ThrowBinaryException(CoderError,"ZipCompressNotSupported",
784             image->filename)
785         case COMPRESS_FRACTAL:
786           tile_image=DestroyImage(tile_image);
787           ThrowBinaryException(CoderError,"FractalCompressNotSupported",
788             image->filename)
789       }
790 
791       /* composite the tile onto the layer's image, and then destroy it */
792       if (status != MagickFalse)
793         (void) CompositeImage(inLayerInfo->image,tile_image,CopyCompositeOp,
794           MagickTrue,destLeft * TILE_WIDTH,destTop*TILE_HEIGHT,exception);
795       tile_image=DestroyImage(tile_image);
796 
797       if (status == MagickFalse)
798         return(MagickFalse);
799       /* adjust tile position */
800       destLeft++;
801       if (destLeft >= (int) ntile_cols)
802         {
803           destLeft = 0;
804           destTop++;
805         }
806       /* restore the saved position so we'll be ready to
807        *  read the next offset.
808        */
809       offset=SeekBlob(image, saved_pos, SEEK_SET);
810       /* read in the offset of the next tile */
811       offset=GetXCFOffset(image,inDocInfo);
812     }
813   if (offset != 0)
814     ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename)
815   return(MagickTrue);
816 }
817 
load_hierarchy(Image * image,XCFDocInfo * inDocInfo,XCFLayerInfo * inLayer,ExceptionInfo * exception)818 static MagickBooleanType load_hierarchy(Image *image,XCFDocInfo *inDocInfo,
819    XCFLayerInfo *inLayer, ExceptionInfo *exception)
820 {
821   MagickOffsetType
822     saved_pos,
823     offset,
824     junk;
825 
826   (void) ReadBlobMSBLong(image); /* width */
827   (void) ReadBlobMSBLong(image); /* height */
828   inDocInfo->bytes_per_pixel=ReadBlobMSBLong(image);
829 
830   /* load in the levels...we make sure that the number of levels
831    *  calculated when the TileManager was created is the same
832    *  as the number of levels found in the file.
833    */
834   offset=GetXCFOffset(image,inDocInfo);  /* top level */
835   if ((MagickSizeType) offset >= GetBlobSize(image))
836     ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
837       image->filename);
838 
839   /* discard offsets for layers below first, if any.
840    */
841   do
842   {
843     junk=(MagickOffsetType) ReadBlobMSBLong(image);
844   }
845   while (junk != 0);
846 
847   /* save the current position as it is where the
848    *  next level offset is stored.
849    */
850   saved_pos=TellBlob(image);
851 
852   /* seek to the level offset */
853   if (SeekBlob(image, offset, SEEK_SET) != offset)
854     ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
855       image->filename);
856 
857   /* read in the level */
858   if (load_level (image, inDocInfo, inLayer, exception) == 0)
859     return(MagickFalse);
860   /* restore the saved position so we'll be ready to
861    *  read the next offset.
862    */
863   offset=SeekBlob(image, saved_pos, SEEK_SET);
864   return(MagickTrue);
865 }
866 
InitXCFImage(XCFLayerInfo * outLayer,ExceptionInfo * exception)867 static void InitXCFImage(XCFLayerInfo *outLayer,ExceptionInfo *exception)
868 {
869   outLayer->image->page.x=outLayer->offset_x;
870   outLayer->image->page.y=outLayer->offset_y;
871   outLayer->image->page.width=outLayer->width;
872   outLayer->image->page.height=outLayer->height;
873   (void) SetImageProperty(outLayer->image,"label",(char *)outLayer->name,
874     exception);
875 }
876 
ReadOneLayer(const ImageInfo * image_info,Image * image,XCFDocInfo * inDocInfo,XCFLayerInfo * outLayer,const ssize_t layer,ExceptionInfo * exception)877 static MagickBooleanType ReadOneLayer(const ImageInfo *image_info,Image* image,
878   XCFDocInfo* inDocInfo,XCFLayerInfo *outLayer,const ssize_t layer,
879   ExceptionInfo *exception)
880 {
881   MagickBooleanType
882     status;
883 
884   MagickOffsetType
885     offset;
886 
887   unsigned int
888     foundPropEnd = 0;
889 
890   MagickOffsetType
891     hierarchy_offset,
892     layer_mask_offset;
893 
894   /* clear the block! */
895   (void) memset( outLayer, 0, sizeof( XCFLayerInfo ) );
896   /* read in the layer width, height, type and name */
897   outLayer->width = ReadBlobMSBLong(image);
898   outLayer->height = ReadBlobMSBLong(image);
899   outLayer->type = ReadBlobMSBLong(image);
900   (void) ReadBlobStringWithLongSize(image, outLayer->name,
901     sizeof(outLayer->name),exception);
902   if (EOFBlob(image) != MagickFalse)
903     ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
904       image->filename);
905   if ((outLayer->width == 0) || (outLayer->height == 0))
906     ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
907       image->filename);
908   /* read the layer properties! */
909   foundPropEnd = 0;
910   while ( (foundPropEnd == MagickFalse) && (EOFBlob(image) == MagickFalse) ) {
911   PropType    prop_type = (PropType) ReadBlobMSBLong(image);
912   size_t  prop_size = ReadBlobMSBLong(image);
913     switch (prop_type)
914     {
915     case PROP_END:
916       foundPropEnd = 1;
917       break;
918     case PROP_ACTIVE_LAYER:
919       outLayer->active = 1;
920       break;
921     case PROP_FLOATING_SELECTION:
922       outLayer->floating_offset = ReadBlobMSBLong(image);
923       break;
924     case PROP_OPACITY:
925       outLayer->alpha = ReadBlobMSBLong(image);
926       break;
927     case PROP_VISIBLE:
928       outLayer->visible = ReadBlobMSBLong(image);
929       break;
930     case PROP_LINKED:
931       outLayer->linked = ReadBlobMSBLong(image);
932       break;
933     case PROP_PRESERVE_TRANSPARENCY:
934       outLayer->preserve_trans = ReadBlobMSBLong(image);
935       break;
936     case PROP_APPLY_MASK:
937       outLayer->apply_mask = ReadBlobMSBLong(image);
938       break;
939     case PROP_EDIT_MASK:
940       outLayer->edit_mask = ReadBlobMSBLong(image);
941       break;
942     case PROP_SHOW_MASK:
943       outLayer->show_mask = ReadBlobMSBLong(image);
944       break;
945     case PROP_OFFSETS:
946       outLayer->offset_x = ReadBlobMSBSignedLong(image);
947       outLayer->offset_y = ReadBlobMSBSignedLong(image);
948       break;
949     case PROP_MODE:
950       outLayer->mode = ReadBlobMSBLong(image);
951       break;
952     case PROP_TATTOO:
953       outLayer->preserve_trans = ReadBlobMSBLong(image);
954       break;
955      case PROP_PARASITES:
956      {
957        if (DiscardBlobBytes(image,prop_size) == MagickFalse)
958          ThrowFileException(exception,CorruptImageError,
959            "UnexpectedEndOfFile",image->filename);
960 
961         /*
962        ssize_t base = info->cp;
963        GimpParasite *p;
964        while (info->cp - base < prop_size)
965        {
966        p = xcf_load_parasite(info);
967        gimp_drawable_parasite_attach(GIMP_DRAWABLE(layer), p);
968        gimp_parasite_free(p);
969        }
970        if (info->cp - base != prop_size)
971        g_message ("Error detected while loading a layer's parasites");
972        */
973      }
974      break;
975     default:
976       /* g_message ("unexpected/unknown layer property: %d (skipping)",
977          prop_type); */
978 
979       {
980       int buf[16];
981       ssize_t amount;
982 
983       /* read over it... */
984       while ((prop_size > 0) && (EOFBlob(image) == MagickFalse))
985         {
986         amount = (ssize_t) MagickMin(16, prop_size);
987         amount = ReadBlob(image, (size_t) amount, (unsigned char *) &buf);
988         if (!amount)
989           ThrowBinaryException(CorruptImageError,"CorruptImage",
990             image->filename);
991         prop_size -= (size_t) MagickMin(16, (size_t) amount);
992         }
993       }
994       break;
995     }
996   }
997   if (EOFBlob(image) != MagickFalse)
998     ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
999       image->filename);
1000   if (foundPropEnd == MagickFalse)
1001     return(MagickFalse);
1002   /* allocate the image for this layer */
1003   if (image_info->number_scenes != 0)
1004     {
1005       ssize_t
1006         scene;
1007 
1008       scene=inDocInfo->number_layers-layer-1;
1009       if (scene > (ssize_t) (image_info->scene+image_info->number_scenes-1))
1010         {
1011           outLayer->image=CloneImage(image,0,0,MagickTrue,exception);
1012           if (outLayer->image == (Image *) NULL)
1013             return(MagickFalse);
1014           InitXCFImage(outLayer,exception);
1015           return(MagickTrue);
1016         }
1017     }
1018   outLayer->image=CloneImage(image,outLayer->width, outLayer->height,MagickTrue,
1019     exception);
1020   if (outLayer->image == (Image *) NULL)
1021     return(MagickFalse);
1022   outLayer->width=outLayer->image->columns;
1023   status=SetImageExtent(outLayer->image,outLayer->image->columns,
1024     outLayer->image->rows,exception);
1025   if (status != MagickFalse)
1026     status=ResetImagePixels(image,exception);
1027   if (status == MagickFalse)
1028     {
1029       outLayer->image=DestroyImageList(outLayer->image);
1030       return(MagickFalse);
1031     }
1032   /* clear the image based on the layer opacity */
1033   outLayer->image->background_color.alpha=
1034     ScaleCharToQuantum((unsigned char) outLayer->alpha);
1035   if (outLayer->alpha != 255U)
1036     {
1037       outLayer->image->background_color.alpha_trait=BlendPixelTrait;
1038       outLayer->image->alpha_trait=BlendPixelTrait;
1039     }
1040 
1041   InitXCFImage(outLayer,exception);
1042 
1043   /* set the compositing mode */
1044   outLayer->image->compose = GIMPBlendModeToCompositeOperator( outLayer->mode );
1045   if ( outLayer->visible == MagickFalse )
1046     {
1047       /* BOGUS: should really be separate member var! */
1048       outLayer->image->compose = NoCompositeOp;
1049     }
1050 
1051   /* read the hierarchy and layer mask offsets */
1052   hierarchy_offset = GetXCFOffset(image,inDocInfo);
1053   layer_mask_offset = GetXCFOffset(image,inDocInfo);
1054 
1055   /* read in the hierarchy */
1056   offset=SeekBlob(image, hierarchy_offset, SEEK_SET);
1057   if (offset != hierarchy_offset)
1058     (void) ThrowMagickException(exception,GetMagickModule(),
1059       CorruptImageError,"InvalidImageHeader","`%s'",image->filename);
1060   if (load_hierarchy (image, inDocInfo, outLayer, exception) == 0)
1061     return(MagickFalse);
1062 
1063   /* read in the layer mask */
1064   if (layer_mask_offset != 0)
1065     {
1066       offset=SeekBlob(image, (MagickOffsetType) layer_mask_offset, SEEK_SET);
1067 
1068 #if 0  /* BOGUS: support layer masks! */
1069       layer_mask = xcf_load_layer_mask (info, gimage);
1070       if (layer_mask == 0)
1071   goto error;
1072 
1073       /* set the offsets of the layer_mask */
1074       GIMP_DRAWABLE (layer_mask)->offset_x = GIMP_DRAWABLE (layer)->offset_x;
1075       GIMP_DRAWABLE (layer_mask)->offset_y = GIMP_DRAWABLE (layer)->offset_y;
1076 
1077       gimp_layer_add_mask (layer, layer_mask, MagickFalse);
1078 
1079       layer->mask->apply_mask = apply_mask;
1080       layer->mask->edit_mask  = edit_mask;
1081       layer->mask->show_mask  = show_mask;
1082 #endif
1083   }
1084 
1085   /* attach the floating selection... */
1086 #if 0  /* BOGUS: we may need to read this, even if we don't support it! */
1087   if (add_floating_sel)
1088     {
1089       GimpLayer *floating_sel;
1090 
1091       floating_sel = info->floating_sel;
1092       floating_sel_attach (floating_sel, GIMP_DRAWABLE (layer));
1093     }
1094 #endif
1095 
1096   return MagickTrue;
1097 }
1098 
1099 /*
1100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1101 %                                                                             %
1102 %                                                                             %
1103 %                                                                             %
1104 %   R e a d X C F I m a g e                                                   %
1105 %                                                                             %
1106 %                                                                             %
1107 %                                                                             %
1108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1109 %
1110 %  ReadXCFImage() reads a GIMP (GNU Image Manipulation Program) image
1111 %  file and returns it.  It allocates the memory necessary for the new Image
1112 %  structure and returns a pointer to the new image.
1113 %
1114 %  The format of the ReadXCFImage method is:
1115 %
1116 %      image=ReadXCFImage(image_info)
1117 %
1118 %  A description of each parameter follows:
1119 %
1120 %    o image_info: the image info.
1121 %
1122 %    o exception: return any errors or warnings in this structure.
1123 %
1124 */
ReadXCFImage(const ImageInfo * image_info,ExceptionInfo * exception)1125 static Image *ReadXCFImage(const ImageInfo *image_info,ExceptionInfo *exception)
1126 {
1127   char
1128     magick[14];
1129 
1130   Image
1131     *image;
1132 
1133   int
1134     foundPropEnd = 0;
1135 
1136   MagickBooleanType
1137     status;
1138 
1139   MagickOffsetType
1140     offset;
1141 
1142   register ssize_t
1143     i;
1144 
1145   size_t
1146     image_type,
1147     precision,
1148     length;
1149 
1150   ssize_t
1151     count;
1152 
1153   XCFDocInfo
1154     doc_info;
1155 
1156   /*
1157     Open image file.
1158   */
1159   assert(image_info != (const ImageInfo *) NULL);
1160   assert(image_info->signature == MagickCoreSignature);
1161   if (image_info->debug != MagickFalse)
1162     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1163       image_info->filename);
1164   assert(exception != (ExceptionInfo *) NULL);
1165   assert(exception->signature == MagickCoreSignature);
1166   image=AcquireImage(image_info,exception);
1167   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1168   if (status == MagickFalse)
1169     {
1170       image=DestroyImageList(image);
1171       return((Image *) NULL);
1172     }
1173   count=ReadBlob(image,sizeof(magick),(unsigned char *) magick);
1174   if ((count != sizeof(magick)) ||
1175       (LocaleNCompare((char *) magick,"gimp xcf",8) != 0))
1176     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1177   (void) memset(&doc_info,0,sizeof(XCFDocInfo));
1178   doc_info.version=StringToUnsignedLong(magick+10);
1179   doc_info.width=ReadBlobMSBLong(image);
1180   doc_info.height=ReadBlobMSBLong(image);
1181   if ((doc_info.width > 262144) || (doc_info.height > 262144))
1182     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1183   doc_info.image_type=ReadBlobMSBLong(image);
1184   precision=150;
1185   if (doc_info.version >= 4)
1186     {
1187       precision=ReadBlobMSBLong(image);
1188       if (precision == 0)
1189         precision=150;
1190       if (precision != 150)
1191         ThrowReaderException(CoderError,"DataStorageTypeIsNotSupported");
1192     }
1193   /*
1194     Initialize image attributes.
1195   */
1196   image->columns=doc_info.width;
1197   image->rows=doc_info.height;
1198   image_type=doc_info.image_type;
1199   doc_info.file_size=GetBlobSize(image);
1200   image->compression=NoCompression;
1201   image->depth=8;
1202   status=SetImageExtent(image,image->columns,image->rows,exception);
1203   if (status == MagickFalse)
1204     return(DestroyImageList(image));
1205   if (status != MagickFalse)
1206     status=ResetImagePixels(image,exception);
1207   if (image_type == GIMP_INDEXED)
1208     ThrowReaderException(CoderError,"ColormapTypeNotSupported");
1209   if (image_type == GIMP_RGB)
1210     SetImageColorspace(image,sRGBColorspace,exception);
1211   else if (image_type == GIMP_GRAY)
1212     SetImageColorspace(image,GRAYColorspace,exception);
1213   else
1214     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1215   (void) SetImageBackgroundColor(image,exception);
1216   (void) SetImageAlpha(image,OpaqueAlpha,exception);
1217   /*
1218     Read properties.
1219   */
1220   while ((foundPropEnd == MagickFalse) && (EOFBlob(image) == MagickFalse))
1221   {
1222     PropType prop_type = (PropType) ReadBlobMSBLong(image);
1223     size_t prop_size = ReadBlobMSBLong(image);
1224 
1225     switch (prop_type)
1226     {
1227       case PROP_END:
1228         foundPropEnd=1;
1229         break;
1230       case PROP_COLORMAP:
1231       {
1232         /* Cannot rely on prop_size here--the value is set incorrectly
1233            by some Gimp versions.
1234         */
1235         size_t num_colours = ReadBlobMSBLong(image);
1236         if (DiscardBlobBytes(image,3*num_colours) == MagickFalse)
1237           ThrowFileException(exception,CorruptImageError,
1238             "UnexpectedEndOfFile",image->filename);
1239     /*
1240       if (info->file_version == 0)
1241       {
1242         gint i;
1243 
1244         g_message (_("XCF warning: version 0 of XCF file format\n"
1245            "did not save indexed colormaps correctly.\n"
1246            "Substituting grayscale map."));
1247         info->cp +=
1248           xcf_read_int32 (info->fp, (guint32*) &gimage->num_cols, 1);
1249         gimage->cmap = g_new (guchar, gimage->num_cols*3);
1250         xcf_seek_pos (info, info->cp + gimage->num_cols);
1251         for (i = 0; i<gimage->num_cols; i++)
1252           {
1253             gimage->cmap[i*3+0] = i;
1254             gimage->cmap[i*3+1] = i;
1255             gimage->cmap[i*3+2] = i;
1256           }
1257       }
1258       else
1259       {
1260         info->cp +=
1261           xcf_read_int32 (info->fp, (guint32*) &gimage->num_cols, 1);
1262         gimage->cmap = g_new (guchar, gimage->num_cols*3);
1263         info->cp +=
1264           xcf_read_int8 (info->fp,
1265                    (guint8*) gimage->cmap, gimage->num_cols*3);
1266       }
1267      */
1268         break;
1269       }
1270       case PROP_COMPRESSION:
1271       {
1272         doc_info.compression = ReadBlobByte(image);
1273         if ((doc_info.compression != COMPRESS_NONE) &&
1274             (doc_info.compression != COMPRESS_RLE) &&
1275             (doc_info.compression != COMPRESS_ZLIB) &&
1276             (doc_info.compression != COMPRESS_FRACTAL))
1277           ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression");
1278       }
1279       break;
1280 
1281       case PROP_GUIDES:
1282       {
1283          /* just skip it - we don't care about guides */
1284         if (DiscardBlobBytes(image,prop_size) == MagickFalse)
1285           ThrowFileException(exception,CorruptImageError,
1286             "UnexpectedEndOfFile",image->filename);
1287       }
1288       break;
1289 
1290     case PROP_RESOLUTION:
1291       {
1292         /* float xres = (float) */ (void) ReadBlobMSBLong(image);
1293         /* float yres = (float) */ (void) ReadBlobMSBLong(image);
1294 
1295         /*
1296         if (xres < GIMP_MIN_RESOLUTION || xres > GIMP_MAX_RESOLUTION ||
1297             yres < GIMP_MIN_RESOLUTION || yres > GIMP_MAX_RESOLUTION)
1298         {
1299         g_message ("Warning, resolution out of range in XCF file");
1300         xres = gimage->gimp->config->default_xresolution;
1301         yres = gimage->gimp->config->default_yresolution;
1302         }
1303         */
1304 
1305 
1306         /* BOGUS: we don't write these yet because we aren't
1307               reading them properly yet :(
1308               image->resolution.x = xres;
1309               image->resolution.y = yres;
1310         */
1311       }
1312       break;
1313 
1314     case PROP_TATTOO:
1315       {
1316         /* we need to read it, even if we ignore it */
1317         /*size_t  tattoo_state = */ (void) ReadBlobMSBLong(image);
1318       }
1319       break;
1320 
1321     case PROP_PARASITES:
1322       {
1323         /* BOGUS: we may need these for IPTC stuff */
1324         if (DiscardBlobBytes(image,prop_size) == MagickFalse)
1325           ThrowFileException(exception,CorruptImageError,
1326             "UnexpectedEndOfFile",image->filename);
1327         /*
1328       gssize_t         base = info->cp;
1329       GimpParasite *p;
1330 
1331       while (info->cp - base < prop_size)
1332         {
1333           p = xcf_load_parasite (info);
1334           gimp_image_parasite_attach (gimage, p);
1335           gimp_parasite_free (p);
1336         }
1337       if (info->cp - base != prop_size)
1338         g_message ("Error detected while loading an image's parasites");
1339       */
1340           }
1341       break;
1342 
1343     case PROP_UNIT:
1344       {
1345         /* BOGUS: ignore for now... */
1346       /*size_t unit =  */ (void) ReadBlobMSBLong(image);
1347       }
1348       break;
1349 
1350     case PROP_PATHS:
1351       {
1352       /* BOGUS: just skip it for now */
1353         if (DiscardBlobBytes(image,prop_size) == MagickFalse)
1354           ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1355             image->filename);
1356 
1357         /*
1358       PathList *paths = xcf_load_bzpaths (gimage, info);
1359       gimp_image_set_paths (gimage, paths);
1360       */
1361       }
1362       break;
1363 
1364     case PROP_USER_UNIT:
1365       {
1366         char  unit_string[1000];
1367         /*BOGUS: ignored for now */
1368         /*float  factor = (float) */ (void) ReadBlobMSBLong(image);
1369         /* size_t digits =  */ (void) ReadBlobMSBLong(image);
1370         for (i=0; i<5; i++)
1371          (void) ReadBlobStringWithLongSize(image, unit_string,
1372            sizeof(unit_string),exception);
1373       }
1374      break;
1375 
1376       default:
1377       {
1378         int buf[16];
1379         ssize_t amount;
1380 
1381       /* read over it... */
1382       while ((prop_size > 0) && (EOFBlob(image) == MagickFalse))
1383       {
1384         amount=(ssize_t) MagickMin(16, prop_size);
1385         amount=(ssize_t) ReadBlob(image,(size_t) amount,(unsigned char *) &buf);
1386         if (!amount)
1387           ThrowReaderException(CorruptImageError,"CorruptImage");
1388         prop_size -= (size_t) MagickMin(16,(size_t) amount);
1389       }
1390     }
1391     break;
1392   }
1393   }
1394   if (foundPropEnd == MagickFalse)
1395     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1396 
1397   if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
1398     {
1399       ; /* do nothing, were just pinging! */
1400     }
1401   else
1402     {
1403       int
1404         current_layer = 0,
1405         foundAllLayers = MagickFalse,
1406         number_layers = 0;
1407 
1408       MagickOffsetType
1409         oldPos=TellBlob(image);
1410 
1411       XCFLayerInfo
1412         *layer_info;
1413 
1414       /*
1415         The read pointer.
1416       */
1417       do
1418       {
1419         offset=GetXCFOffset(image,&doc_info);
1420         if (offset == 0)
1421           foundAllLayers=MagickTrue;
1422         else
1423           number_layers++;
1424         if (EOFBlob(image) != MagickFalse)
1425           {
1426             ThrowFileException(exception,CorruptImageError,
1427               "UnexpectedEndOfFile",image->filename);
1428             break;
1429           }
1430     } while (foundAllLayers == MagickFalse);
1431     if (AcquireMagickResource(ListLengthResource,number_layers) == MagickFalse)
1432       ThrowReaderException(ResourceLimitError,"ListLengthExceedsLimit");
1433     doc_info.number_layers=number_layers;
1434     offset=SeekBlob(image,oldPos,SEEK_SET); /* restore the position! */
1435     if (offset < 0)
1436       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1437     /* allocate our array of layer info blocks */
1438     length=(size_t) number_layers;
1439     layer_info=(XCFLayerInfo *) AcquireQuantumMemory(length,
1440       sizeof(*layer_info));
1441     if (layer_info == (XCFLayerInfo *) NULL)
1442       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1443     (void) memset(layer_info,0,number_layers*sizeof(XCFLayerInfo));
1444     for ( ; ; )
1445     {
1446       MagickBooleanType
1447         layer_ok;
1448 
1449       MagickOffsetType
1450         saved_pos;
1451 
1452       /* read in the offset of the next layer */
1453       offset=GetXCFOffset(image,&doc_info);
1454       /* if the offset is 0 then we are at the end
1455       *  of the layer list.
1456       */
1457       if (offset == 0)
1458         break;
1459       /* save the current position as it is where the
1460       *  next layer offset is stored.
1461       */
1462       saved_pos=TellBlob(image);
1463       /* seek to the layer offset */
1464       layer_ok=MagickFalse;
1465       if (SeekBlob(image,offset,SEEK_SET) == offset)
1466         {
1467           /* read in the layer */
1468           layer_ok=ReadOneLayer(image_info,image,&doc_info,
1469             &layer_info[current_layer],current_layer,exception);
1470         }
1471       if (layer_ok == MagickFalse)
1472         {
1473           ssize_t j;
1474 
1475           for (j=0; j <= current_layer; j++)
1476             if (layer_info[j].image != (Image *) NULL)
1477               layer_info[j].image=DestroyImage(layer_info[j].image);
1478           layer_info=(XCFLayerInfo *) RelinquishMagickMemory(layer_info);
1479           ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
1480         }
1481       /* restore the saved position so we'll be ready to
1482       *  read the next offset.
1483       */
1484       offset=SeekBlob(image, saved_pos, SEEK_SET);
1485       current_layer++;
1486     }
1487 #if 0
1488         {
1489         /* NOTE: XCF layers are REVERSED from composite order! */
1490         signed int  j;
1491         for (j=number_layers-1; j>=0; j--) {
1492           /* BOGUS: need to consider layer blending modes!! */
1493 
1494           if ( layer_info[j].visible ) { /* only visible ones, please! */
1495             CompositeImage(image, OverCompositeOp, layer_info[j].image,
1496                      layer_info[j].offset_x, layer_info[j].offset_y );
1497              layer_info[j].image =DestroyImage( layer_info[j].image );
1498 
1499             /* If we do this, we'll get REAL gray images! */
1500             if ( image_type == GIMP_GRAY ) {
1501               QuantizeInfo  qi;
1502               GetQuantizeInfo(&qi);
1503               qi.colorspace = GRAYColorspace;
1504               QuantizeImage( &qi, layer_info[j].image );
1505             }
1506           }
1507         }
1508       }
1509 #else
1510       {
1511         /* NOTE: XCF layers are REVERSED from composite order! */
1512         ssize_t  j;
1513 
1514         /* now reverse the order of the layers as they are put
1515            into subimages
1516         */
1517         for (j=(ssize_t) number_layers-1; j >= 0; j--)
1518           AppendImageToList(&image,layer_info[j].image);
1519       }
1520 #endif
1521 
1522     layer_info=(XCFLayerInfo *) RelinquishMagickMemory(layer_info);
1523 
1524 #if 0  /* BOGUS: do we need the channels?? */
1525     while (MagickTrue)
1526     {
1527       /* read in the offset of the next channel */
1528       info->cp += xcf_read_int32 (info->fp, &offset, 1);
1529 
1530       /* if the offset is 0 then we are at the end
1531       *  of the channel list.
1532       */
1533       if (offset == 0)
1534         break;
1535 
1536       /* save the current position as it is where the
1537       *  next channel offset is stored.
1538       */
1539       saved_pos = info->cp;
1540 
1541       /* seek to the channel offset */
1542       xcf_seek_pos (info, offset);
1543 
1544       /* read in the layer */
1545       channel = xcf_load_channel (info, gimage);
1546       if (channel == 0)
1547         goto error;
1548 
1549       num_successful_elements++;
1550 
1551       /* add the channel to the image if its not the selection */
1552       if (channel != gimage->selection_mask)
1553         gimp_image_add_channel (gimage, channel, -1);
1554 
1555       /* restore the saved position so we'll be ready to
1556       *  read the next offset.
1557       */
1558       xcf_seek_pos (info, saved_pos);
1559     }
1560 #endif
1561   }
1562 
1563   (void) CloseBlob(image);
1564   if (GetNextImageInList(image) != (Image *) NULL)
1565     DestroyImage(RemoveFirstImageFromList(&image));
1566   if (image_type == GIMP_GRAY)
1567     image->type=GrayscaleType;
1568   return(GetFirstImageInList(image));
1569 }
1570 
1571 /*
1572 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1573 %                                                                             %
1574 %                                                                             %
1575 %                                                                             %
1576 %   R e g i s t e r X C F I m a g e                                           %
1577 %                                                                             %
1578 %                                                                             %
1579 %                                                                             %
1580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1581 %
1582 %  RegisterXCFImage() adds attributes for the XCF image format to
1583 %  the list of supported formats.  The attributes include the image format
1584 %  tag, a method to read and/or write the format, whether the format
1585 %  supports the saving of more than one frame to the same file or blob,
1586 %  whether the format supports native in-memory I/O, and a brief
1587 %  description of the format.
1588 %
1589 %  The format of the RegisterXCFImage method is:
1590 %
1591 %      size_t RegisterXCFImage(void)
1592 %
1593 */
RegisterXCFImage(void)1594 ModuleExport size_t RegisterXCFImage(void)
1595 {
1596   MagickInfo
1597     *entry;
1598 
1599   entry=AcquireMagickInfo("XCF","XCF","GIMP image");
1600   entry->decoder=(DecodeImageHandler *) ReadXCFImage;
1601   entry->magick=(IsImageFormatHandler *) IsXCF;
1602   entry->flags|=CoderDecoderSeekableStreamFlag;
1603   (void) RegisterMagickInfo(entry);
1604   return(MagickImageCoderSignature);
1605 }
1606 
1607 /*
1608 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1609 %                                                                             %
1610 %                                                                             %
1611 %                                                                             %
1612 %   U n r e g i s t e r X C F I m a g e                                       %
1613 %                                                                             %
1614 %                                                                             %
1615 %                                                                             %
1616 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1617 %
1618 %  UnregisterXCFImage() removes format registrations made by the
1619 %  XCF module from the list of supported formats.
1620 %
1621 %  The format of the UnregisterXCFImage method is:
1622 %
1623 %      UnregisterXCFImage(void)
1624 %
1625 */
UnregisterXCFImage(void)1626 ModuleExport void UnregisterXCFImage(void)
1627 {
1628   (void) UnregisterMagickInfo("XCF");
1629 }
1630