1 /*
2   SDL_image:  An example image loading library for use with SDL
3   Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 /* This is a XCF image file loading framework */
23 
24 #include "SDL_endian.h"
25 #include "SDL_image.h"
26 
27 #ifdef LOAD_XCF
28 
29 #if DEBUG
30 static char prop_names [][30] = {
31   "end",
32   "colormap",
33   "active_layer",
34   "active_channel",
35   "selection",
36   "floating_selection",
37   "opacity",
38   "mode",
39   "visible",
40   "linked",
41   "preserve_transparency",
42   "apply_mask",
43   "edit_mask",
44   "show_mask",
45   "show_masked",
46   "offsets",
47   "color",
48   "compression",
49   "guides",
50   "resolution",
51   "tattoo",
52   "parasites",
53   "unit",
54   "paths",
55   "user_unit"
56 };
57 #endif
58 
59 
60 typedef enum
61 {
62   PROP_END = 0,
63   PROP_COLORMAP = 1,
64   PROP_ACTIVE_LAYER = 2,
65   PROP_ACTIVE_CHANNEL = 3,
66   PROP_SELECTION = 4,
67   PROP_FLOATING_SELECTION = 5,
68   PROP_OPACITY = 6,
69   PROP_MODE = 7,
70   PROP_VISIBLE = 8,
71   PROP_LINKED = 9,
72   PROP_PRESERVE_TRANSPARENCY = 10,
73   PROP_APPLY_MASK = 11,
74   PROP_EDIT_MASK = 12,
75   PROP_SHOW_MASK = 13,
76   PROP_SHOW_MASKED = 14,
77   PROP_OFFSETS = 15,
78   PROP_COLOR = 16,
79   PROP_COMPRESSION = 17,
80   PROP_GUIDES = 18,
81   PROP_RESOLUTION = 19,
82   PROP_TATTOO = 20,
83   PROP_PARASITES = 21,
84   PROP_UNIT = 22,
85   PROP_PATHS = 23,
86   PROP_USER_UNIT = 24
87 } xcf_prop_type;
88 
89 typedef enum {
90   COMPR_NONE    = 0,
91   COMPR_RLE     = 1,
92   COMPR_ZLIB    = 2,
93   COMPR_FRACTAL = 3
94 } xcf_compr_type;
95 
96 typedef enum {
97   IMAGE_RGB       = 0,
98   IMAGE_GREYSCALE = 1,
99   IMAGE_INDEXED   = 2
100 } xcf_image_type;
101 
102 typedef struct {
103   Uint32 id;
104   Uint32 length;
105   union {
106     struct {
107       Uint32 num;
108       char * cmap;
109     } colormap; // 1
110     struct {
111       Uint32 drawable_offset;
112     } floating_selection; // 5
113     Sint32 opacity;
114     Sint32 mode;
115     int    visible;
116     int    linked;
117     int    preserve_transparency;
118     int    apply_mask;
119     int    show_mask;
120     struct {
121       Sint32 x;
122       Sint32 y;
123     } offset;
124     unsigned char color [3];
125     Uint8 compression;
126     struct {
127       Sint32 x;
128       Sint32 y;
129     } resolution;
130     struct {
131       char * name;
132       Uint32 flags;
133       Uint32 size;
134       char * data;
135     } parasite;
136   } data;
137 } xcf_prop;
138 
139 typedef struct {
140   char   sign [14];
141   Uint32 file_version;
142   Uint32 width;
143   Uint32 height;
144   Sint32 image_type;
145   Uint32 precision;
146   xcf_prop * properties;
147 
148   Uint32 * layer_file_offsets;
149   Uint32 * channel_file_offsets;
150 
151   xcf_compr_type compr;
152   Uint32         cm_num;
153   unsigned char * cm_map;
154 } xcf_header;
155 
156 typedef struct {
157   Uint32 width;
158   Uint32 height;
159   Sint32 layer_type;
160   char * name;
161   xcf_prop * properties;
162 
163   Uint32 hierarchy_file_offset;
164   Uint32 layer_mask_offset;
165 
166   Uint32 offset_x;
167   Uint32 offset_y;
168   int visible;
169 } xcf_layer;
170 
171 typedef struct {
172   Uint32 width;
173   Uint32 height;
174   char * name;
175   xcf_prop * properties;
176 
177   Uint32 hierarchy_file_offset;
178 
179   Uint32 color;
180   Uint32 opacity;
181   int selection;
182   int visible;
183 } xcf_channel;
184 
185 typedef struct {
186   Uint32 width;
187   Uint32 height;
188   Uint32 bpp;
189 
190   Uint32 * level_file_offsets;
191 } xcf_hierarchy;
192 
193 typedef struct {
194   Uint32 width;
195   Uint32 height;
196 
197   Uint32 * tile_file_offsets;
198 } xcf_level;
199 
200 typedef unsigned char * xcf_tile;
201 
202 typedef unsigned char * (* load_tile_type) (SDL_RWops *, Uint32, int, int, int);
203 
204 
205 /* See if an image is contained in a data source */
IMG_isXCF(SDL_RWops * src)206 int IMG_isXCF(SDL_RWops *src)
207 {
208     Sint64 start;
209     int is_XCF;
210     char magic[14];
211 
212     if ( !src )
213         return 0;
214     start = SDL_RWtell(src);
215     is_XCF = 0;
216     if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
217         if (SDL_strncmp(magic, "gimp xcf ", 9) == 0) {
218             is_XCF = 1;
219         }
220     }
221     SDL_RWseek(src, start, RW_SEEK_SET);
222     return(is_XCF);
223 }
224 
read_string(SDL_RWops * src)225 static char * read_string (SDL_RWops * src) {
226   Sint64 remaining;
227   Uint32 tmp;
228   char * data;
229 
230   tmp = SDL_ReadBE32(src);
231   remaining = SDL_RWsize(src) - SDL_RWtell(src);
232   if (tmp > 0 && (Sint32)tmp <= remaining) {
233     data = (char *) SDL_malloc (sizeof (char) * tmp);
234     if (data) {
235       SDL_RWread(src, data, tmp, 1);
236       data[tmp - 1] = '\0';
237     }
238   }
239   else {
240     data = NULL;
241   }
242   return data;
243 }
244 
read_offset(SDL_RWops * src,const xcf_header * h)245 static Uint64 read_offset (SDL_RWops * src, const xcf_header * h) {
246   Uint64 offset;  // starting with version 11, offsets are 64 bits
247   offset = (h->file_version >= 11) ? (Uint64)SDL_ReadBE32 (src) << 32 : 0;
248   offset |= SDL_ReadBE32 (src);
249   return offset;
250 }
251 
252 
Swap32(Uint32 v)253 static Uint32 Swap32 (Uint32 v) {
254   return
255     ((v & 0x000000FF) << 16)
256     |  ((v & 0x0000FF00))
257     |  ((v & 0x00FF0000) >> 16)
258     |  ((v & 0xFF000000));
259 }
260 
xcf_read_property(SDL_RWops * src,xcf_prop * prop)261 static int xcf_read_property (SDL_RWops * src, xcf_prop * prop) {
262   Uint32 len;
263   prop->id = SDL_ReadBE32 (src);
264   prop->length = SDL_ReadBE32 (src);
265 
266 #if DEBUG
267   printf ("%.8X: %s(%u): %u\n", SDL_RWtell (src), prop->id < 25 ? prop_names [prop->id] : "unknown", prop->id, prop->length);
268 #endif
269 
270   switch (prop->id) {
271   case PROP_COLORMAP:
272     prop->data.colormap.num = SDL_ReadBE32 (src);
273     prop->data.colormap.cmap = (char *) SDL_malloc (sizeof (char) * prop->data.colormap.num * 3);
274     SDL_RWread (src, prop->data.colormap.cmap, prop->data.colormap.num*3, 1);
275     break;
276 
277   case PROP_OFFSETS:
278     prop->data.offset.x = SDL_ReadBE32 (src);
279     prop->data.offset.y = SDL_ReadBE32 (src);
280     break;
281   case PROP_OPACITY:
282     prop->data.opacity = SDL_ReadBE32 (src);
283     break;
284   case PROP_COMPRESSION:
285   case PROP_COLOR:
286     if (prop->length > sizeof(prop->data)) {
287         len = sizeof(prop->data);
288     } else {
289         len = prop->length;
290     }
291     SDL_RWread(src, &prop->data, len, 1);
292     break;
293   case PROP_VISIBLE:
294     prop->data.visible = SDL_ReadBE32 (src);
295     break;
296   default:
297     //    SDL_RWread (src, &prop->data, prop->length, 1);
298     if (SDL_RWseek (src, prop->length, RW_SEEK_CUR) < 0)
299       return 0;  // ERROR
300   }
301   return 1;  // OK
302 }
303 
free_xcf_header(xcf_header * h)304 static void free_xcf_header (xcf_header * h) {
305   if (h->cm_num)
306     SDL_free (h->cm_map);
307   if (h->layer_file_offsets)
308     SDL_free (h->layer_file_offsets);
309   SDL_free (h);
310 }
311 
read_xcf_header(SDL_RWops * src)312 static xcf_header * read_xcf_header (SDL_RWops * src) {
313   xcf_header * h;
314   xcf_prop prop;
315 
316   h = (xcf_header *) SDL_malloc (sizeof (xcf_header));
317   if (!h) {
318     return NULL;
319   }
320   SDL_RWread (src, h->sign, 14, 1);
321   h->width       = SDL_ReadBE32 (src);
322   h->height      = SDL_ReadBE32 (src);
323   h->image_type  = SDL_ReadBE32 (src);
324   h->file_version = (h->sign[10] - '0') * 100 + (h->sign[11] - '0') * 10 + (h->sign[12] - '0');
325 #ifdef DEBUG
326   printf ("XCF signature : %.14s (version %u)\n", h->sign, h->file_version);
327   printf (" (%u,%u) type=%u\n", h->width, h->height, h->image_type);
328 #endif
329   if (h->file_version >= 4)
330     h->precision = SDL_ReadBE32 (src);
331   else
332     h->precision = 150;
333 
334   h->properties = NULL;
335   h->layer_file_offsets = NULL;
336   h->compr      = COMPR_NONE;
337   h->cm_num = 0;
338   h->cm_map = NULL;
339 
340   // Just read, don't save
341   do {
342     if (!xcf_read_property (src, &prop)) {
343       free_xcf_header (h);
344       return NULL;
345     }
346     if (prop.id == PROP_COMPRESSION)
347       h->compr = (xcf_compr_type)prop.data.compression;
348     else if (prop.id == PROP_COLORMAP) {
349       // unused var: int i;
350       Uint32 cm_num;
351       unsigned char *cm_map;
352 
353       cm_num = prop.data.colormap.num;
354       cm_map = (unsigned char *) SDL_realloc(h->cm_map, sizeof (unsigned char) * 3 * cm_num);
355       if (cm_map) {
356         h->cm_num = cm_num;
357         h->cm_map = cm_map;
358         SDL_memcpy (h->cm_map, prop.data.colormap.cmap, 3*sizeof (char)*h->cm_num);
359       }
360       SDL_free (prop.data.colormap.cmap);
361 
362       if (!cm_map) {
363         free_xcf_header(h);
364         return NULL;
365       }
366     }
367   } while (prop.id != PROP_END);
368 
369   return h;
370 }
371 
free_xcf_layer(xcf_layer * l)372 static void free_xcf_layer (xcf_layer * l) {
373   SDL_free (l->name);
374   SDL_free (l);
375 }
376 
read_xcf_layer(SDL_RWops * src,const xcf_header * h)377 static xcf_layer * read_xcf_layer (SDL_RWops * src, const xcf_header * h) {
378   xcf_layer * l;
379   xcf_prop    prop;
380 
381   l = (xcf_layer *) SDL_malloc (sizeof (xcf_layer));
382   l->width  = SDL_ReadBE32 (src);
383   l->height = SDL_ReadBE32 (src);
384   l->layer_type = SDL_ReadBE32 (src);
385 
386   l->name = read_string (src);
387 #ifdef DEBUG
388   printf ("layer (%d,%d) type=%d '%s'\n", l->width, l->height, l->layer_type, l->name);
389 #endif
390 
391   do {
392     if (!xcf_read_property (src, &prop)) {
393       free_xcf_layer (l);
394       return NULL;
395     }
396     if (prop.id == PROP_OFFSETS) {
397       l->offset_x = prop.data.offset.x;
398       l->offset_y = prop.data.offset.y;
399     } else if (prop.id == PROP_VISIBLE) {
400       l->visible = prop.data.visible ? 1 : 0;
401     } else if (prop.id == PROP_COLORMAP) {
402       SDL_free (prop.data.colormap.cmap);
403     }
404   } while (prop.id != PROP_END);
405 
406   l->hierarchy_file_offset = read_offset (src, h);
407   l->layer_mask_offset     = read_offset (src, h);
408 
409   return l;
410 }
411 
free_xcf_channel(xcf_channel * c)412 static void free_xcf_channel (xcf_channel * c) {
413   SDL_free (c->name);
414   SDL_free (c);
415 }
416 
read_xcf_channel(SDL_RWops * src,const xcf_header * h)417 static xcf_channel * read_xcf_channel (SDL_RWops * src, const xcf_header * h) {
418   xcf_channel * l;
419   xcf_prop    prop;
420 
421   l = (xcf_channel *) SDL_malloc (sizeof (xcf_channel));
422   l->width  = SDL_ReadBE32 (src);
423   l->height = SDL_ReadBE32 (src);
424 
425   l->name = read_string (src);
426 #ifdef DEBUG
427   printf ("channel (%u,%u) '%s'\n", l->width, l->height, l->name);
428 #endif
429 
430   l->selection = 0;
431   do {
432     if (!xcf_read_property (src, &prop)) {
433       free_xcf_channel (l);
434       return NULL;
435     }
436     switch (prop.id) {
437     case PROP_OPACITY:
438       l->opacity = prop.data.opacity << 24;
439       break;
440     case PROP_COLOR:
441       l->color = ((Uint32) prop.data.color[0] << 16)
442     | ((Uint32) prop.data.color[1] << 8)
443     | ((Uint32) prop.data.color[2]);
444       break;
445     case PROP_SELECTION:
446       l->selection = 1;
447       break;
448     case PROP_VISIBLE:
449       l->visible = prop.data.visible ? 1 : 0;
450       break;
451     default:
452         ;
453     }
454   } while (prop.id != PROP_END);
455 
456   l->hierarchy_file_offset = read_offset (src, h);
457 
458   return l;
459 }
460 
free_xcf_hierarchy(xcf_hierarchy * h)461 static void free_xcf_hierarchy (xcf_hierarchy * h) {
462   SDL_free (h->level_file_offsets);
463   SDL_free (h);
464 }
465 
read_xcf_hierarchy(SDL_RWops * src,const xcf_header * head)466 static xcf_hierarchy * read_xcf_hierarchy (SDL_RWops * src, const xcf_header * head) {
467   xcf_hierarchy * h;
468   int i;
469 
470   h = (xcf_hierarchy *) SDL_malloc (sizeof (xcf_hierarchy));
471   h->width  = SDL_ReadBE32 (src);
472   h->height = SDL_ReadBE32 (src);
473   h->bpp    = SDL_ReadBE32 (src);
474 
475   h->level_file_offsets = NULL;
476   i = 0;
477   do {
478     h->level_file_offsets = (Uint32 *) SDL_realloc (h->level_file_offsets, sizeof (Uint32) * (i+1));
479     h->level_file_offsets [i] = read_offset (src, head);
480   } while (h->level_file_offsets [i++]);
481 
482   return h;
483 }
484 
free_xcf_level(xcf_level * l)485 static void free_xcf_level (xcf_level * l) {
486   SDL_free (l->tile_file_offsets);
487   SDL_free (l);
488 }
489 
read_xcf_level(SDL_RWops * src,const xcf_header * h)490 static xcf_level * read_xcf_level (SDL_RWops * src, const xcf_header * h) {
491   xcf_level * l;
492   int i;
493 
494   l = (xcf_level *) SDL_malloc (sizeof (xcf_level));
495   l->width  = SDL_ReadBE32 (src);
496   l->height = SDL_ReadBE32 (src);
497 
498   l->tile_file_offsets = NULL;
499   i = 0;
500   do {
501     l->tile_file_offsets = (Uint32 *) SDL_realloc (l->tile_file_offsets, sizeof (Uint32) * (i+1));
502     l->tile_file_offsets [i] = read_offset (src, h);
503   } while (l->tile_file_offsets [i++]);
504 
505   return l;
506 }
507 
free_xcf_tile(unsigned char * t)508 static void free_xcf_tile (unsigned char * t) {
509   SDL_free (t);
510 }
511 
load_xcf_tile_none(SDL_RWops * src,Uint32 len,int bpp,int x,int y)512 static unsigned char * load_xcf_tile_none (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
513   unsigned char * load;
514 
515   load = (unsigned char *) SDL_malloc (len); // expect this is okay
516   if (load != NULL)
517     SDL_RWread (src, load, len, 1);
518 
519   return load;
520 }
521 
load_xcf_tile_rle(SDL_RWops * src,Uint32 len,int bpp,int x,int y)522 static unsigned char * load_xcf_tile_rle (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
523   unsigned char * load, * t, * data, * d;
524   Uint32 reallen;
525   int i, size, count, j, length;
526   unsigned char val;
527 
528   if (len == 0) {  /* probably bogus data. */
529     return NULL;
530   }
531 
532   t = load = (unsigned char *) SDL_malloc (len);
533   if (load == NULL)
534     return NULL;
535   reallen = SDL_RWread (src, t, 1, len);
536 
537   data = (unsigned char *) SDL_calloc (1, x*y*bpp);
538   for (i = 0; i < bpp; i++) {
539     d    = data + i;
540     size = x*y;
541     count = 0;
542 
543     while (size > 0) {
544       val = *t++;
545 
546       length = val;
547       if (length >= 128) {
548         length = 255 - (length - 1);
549         if (length == 128) {
550           length = (*t << 8) + t[1];
551           t += 2;
552         }
553 
554         if (((size_t) (t - load) + length) >= len) {
555           break;  /* bogus data */
556         } else if (length > size) {
557           break;  /* bogus data */
558         }
559 
560         count += length;
561         size -= length;
562 
563         while (length-- > 0) {
564           *d = *t++;
565           d += bpp;
566         }
567       } else {
568         length += 1;
569         if (length == 128) {
570           length = (*t << 8) + t[1];
571           t += 2;
572         }
573 
574         if (((size_t) (t - load)) >= len) {
575           break;  /* bogus data */
576         } else if (length > size) {
577           break;  /* bogus data */
578         }
579 
580         count += length;
581         size -= length;
582 
583         val = *t++;
584 
585         for (j = 0; j < length; j++) {
586           *d = val;
587           d += bpp;
588         }
589       }
590     }
591 
592     if (size > 0) {
593       break;  /* just drop out, untouched data initialized to zero. */
594     }
595 
596   }
597 
598   SDL_free (load);
599   return (data);
600 }
601 
rgb2grey(Uint32 a)602 static Uint32 rgb2grey (Uint32 a) {
603   Uint8 l;
604   l = (Uint8)(0.2990 * ((a & 0x00FF0000) >> 16)
605     + 0.5870 * ((a & 0x0000FF00) >>  8)
606     + 0.1140 * ((a & 0x000000FF)));
607 
608   return (l << 16) | (l << 8) | l;
609 }
610 
create_channel_surface(SDL_Surface * surf,xcf_image_type itype,Uint32 color,Uint32 opacity)611 static void create_channel_surface (SDL_Surface * surf, xcf_image_type itype, Uint32 color, Uint32 opacity) {
612   Uint32 c = 0;
613 
614   switch (itype) {
615   case IMAGE_RGB:
616   case IMAGE_INDEXED:
617     c = opacity | color;
618     break;
619   case IMAGE_GREYSCALE:
620     c = opacity | rgb2grey (color);
621     break;
622   }
623   SDL_FillRect (surf, NULL, c);
624 }
625 
626 static int
do_layer_surface(SDL_Surface * surface,SDL_RWops * src,xcf_header * head,xcf_layer * layer,load_tile_type load_tile)627 do_layer_surface(SDL_Surface * surface, SDL_RWops * src, xcf_header * head, xcf_layer * layer, load_tile_type load_tile)
628 {
629     xcf_hierarchy  *hierarchy;
630     xcf_level      *level;
631     unsigned char  *tile;
632     Uint8          *p8;
633     Uint16         *p16;
634     Uint32         *p;
635     int            i, j;
636     Uint32         x, y, tx, ty, ox, oy;
637     Uint32         *row;
638     Uint32         length;
639 
640     SDL_RWseek(src, layer->hierarchy_file_offset, RW_SEEK_SET);
641     hierarchy = read_xcf_hierarchy(src, head);
642 
643     if (hierarchy->bpp > 4) {  /* unsupported. */
644         SDL_Log("Unknown Gimp image bpp (%u)\n", (unsigned int) hierarchy->bpp);
645         free_xcf_hierarchy(hierarchy);
646         return 1;
647     }
648 
649     if ((hierarchy->width > 20000) || (hierarchy->height > 20000)) {  /* arbitrary limit to avoid integer overflow. */
650         SDL_Log("Gimp image too large (%ux%u)\n", (unsigned int) hierarchy->width, (unsigned int) hierarchy->height);
651         free_xcf_hierarchy(hierarchy);
652         return 1;
653     }
654 
655     level = NULL;
656     for (i = 0; hierarchy->level_file_offsets[i]; i++) {
657         if (SDL_RWseek(src, hierarchy->level_file_offsets[i], RW_SEEK_SET) < 0)
658             break;
659         if (i > 0) // skip level except the 1st one, just like GIMP does
660             continue;
661         level = read_xcf_level(src, head);
662 
663         ty = tx = 0;
664         for (j = 0; level->tile_file_offsets[j]; j++) {
665             SDL_RWseek(src, level->tile_file_offsets[j], RW_SEEK_SET);
666             ox = tx + 64 > level->width ? level->width % 64 : 64;
667             oy = ty + 64 > level->height ? level->height % 64 : 64;
668             length = ox*oy*6;
669 
670             if (level->tile_file_offsets[j + 1] > level->tile_file_offsets[j]) {
671                 length = level->tile_file_offsets[j + 1] - level->tile_file_offsets[j];
672             }
673             tile = load_tile(src, length, hierarchy->bpp, ox, oy);
674 
675             if (!tile) {
676                 if (hierarchy) {
677                     free_xcf_hierarchy(hierarchy);
678                 }
679                 if (level) {
680                     free_xcf_level(level);
681                 }
682                 return 1;
683             }
684 
685             p8 = tile;
686             p16 = (Uint16 *) p8;
687             p = (Uint32 *) p8;
688             for (y = ty; y < ty + oy; y++) {
689                 if ((y >= surface->h) || ((tx+ox) > surface->w)) {
690                     break;
691                 }
692                 row = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch + tx * 4);
693                 switch (hierarchy->bpp) {
694                 case 4:
695                     for (x = tx; x < tx + ox; x++)
696                         *row++ = Swap32(*p++);
697                     break;
698                 case 3:
699                     for (x = tx; x < tx + ox; x++) {
700                         *row = 0xFF000000;
701                         *row |= ((Uint32)*p8++ << 16);
702                         *row |= ((Uint32)*p8++ << 8);
703                         *row |= ((Uint32)*p8++ << 0);
704                         row++;
705                     }
706                     break;
707                 case 2:
708                     /* Indexed / Greyscale + Alpha */
709                     switch (head->image_type) {
710                     case IMAGE_INDEXED:
711                         for (x = tx; x < tx + ox; x++) {
712                             *row = ((Uint32)(head->cm_map[*p8 * 3]) << 16);
713                             *row |= ((Uint32)(head->cm_map[*p8 * 3 + 1]) << 8);
714                             *row |= ((Uint32)(head->cm_map[*p8++ * 3 + 2]) << 0);
715                             *row |= ((Uint32)*p8++ << 24);
716                             row++;
717                         }
718                         break;
719                     case IMAGE_GREYSCALE:
720                         for (x = tx; x < tx + ox; x++) {
721                             *row = ((Uint32)*p8 << 16);
722                             *row |= ((Uint32)*p8 << 8);
723                             *row |= ((Uint32)*p8++ << 0);
724                             *row |= ((Uint32)*p8++ << 24);
725                             row++;
726                         }
727                         break;
728                     default:
729                         SDL_Log("Unknown Gimp image type (%d)\n", head->image_type);
730                         if (hierarchy) {
731                             free_xcf_hierarchy(hierarchy);
732                         }
733                         if (level)
734                             free_xcf_level(level);
735                         return 1;
736                     }
737                     break;
738                 case 1:
739                     /* Indexed / Greyscale */
740                     switch (head->image_type) {
741                     case IMAGE_INDEXED:
742                         for (x = tx; x < tx + ox; x++) {
743                             *row++ = 0xFF000000
744                                 | ((Uint32)(head->cm_map[*p8 * 3]) << 16)
745                                 | ((Uint32)(head->cm_map[*p8 * 3 + 1]) << 8)
746                                 | ((Uint32)(head->cm_map[*p8 * 3 + 2]) << 0);
747                             p8++;
748                         }
749                         break;
750                     case IMAGE_GREYSCALE:
751                         for (x = tx; x < tx + ox; x++) {
752                             *row++ = 0xFF000000
753                                 | (((Uint32)(*p8)) << 16)
754                                 | (((Uint32)(*p8)) << 8)
755                                 | (((Uint32)(*p8)) << 0);
756                             ++p8;
757                         }
758                         break;
759                     default:
760                         SDL_Log("Unknown Gimp image type (%d)\n", head->image_type);
761                         if (tile)
762                             free_xcf_tile(tile);
763                         if (level)
764                             free_xcf_level(level);
765                         if (hierarchy)
766                             free_xcf_hierarchy(hierarchy);
767                         return 1;
768                     }
769                     break;
770                 }
771             }
772             free_xcf_tile(tile);
773 
774             tx += 64;
775             if (tx >= level->width) {
776                 tx = 0;
777                 ty += 64;
778             }
779             if (ty >= level->height) {
780                 break;
781             }
782         }
783         free_xcf_level(level);
784     }
785 
786     free_xcf_hierarchy(hierarchy);
787 
788     return 0;
789 }
790 
IMG_LoadXCF_RW(SDL_RWops * src)791 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
792 {
793   Sint64 start;
794   const char *error = NULL;
795   SDL_Surface *surface, *lays;
796   xcf_header * head;
797   xcf_layer  * layer;
798   xcf_channel ** channel;
799   int chnls, i, offsets;
800   Sint64 offset, fp;
801 
802   unsigned char * (* load_tile) (SDL_RWops *, Uint32, int, int, int);
803 
804   if (!src) {
805     /* The error message has been set in SDL_RWFromFile */
806     return NULL;
807   }
808   start = SDL_RWtell(src);
809 
810   /* Initialize the data we will clean up when we're done */
811   surface = NULL;
812 
813   head = read_xcf_header(src);
814   if (!head) {
815     return NULL;
816   }
817 
818   switch (head->compr) {
819   case COMPR_NONE:
820     load_tile = load_xcf_tile_none;
821     break;
822   case COMPR_RLE:
823     load_tile = load_xcf_tile_rle;
824     break;
825   default:
826     SDL_Log("Unsupported Compression.\n");
827     free_xcf_header (head);
828     return NULL;
829   }
830 
831   /* Create the surface of the appropriate type */
832   surface = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
833                  0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
834 
835   if ( surface == NULL ) {
836     error = "Out of memory";
837     goto done;
838   }
839 
840   offsets = 0;
841 
842   while ((offset = read_offset (src, head))) {
843     head->layer_file_offsets = (Uint32 *) SDL_realloc (head->layer_file_offsets, sizeof (Uint32) * (offsets+1));
844     head->layer_file_offsets [offsets] = (Uint32)offset;
845     offsets++;
846   }
847   fp = SDL_RWtell (src);
848 
849   lays = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
850               0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
851 
852   if ( lays == NULL ) {
853     error = "Out of memory";
854     goto done;
855   }
856 
857   // Blit layers backwards, because Gimp saves them highest first
858   for (i = offsets; i > 0; i--) {
859     SDL_Rect rs, rd;
860     SDL_RWseek (src, head->layer_file_offsets [i-1], RW_SEEK_SET);
861 
862     layer = read_xcf_layer (src, head);
863     if (layer != NULL) {
864       do_layer_surface (lays, src, head, layer, load_tile);
865       rs.x = 0;
866       rs.y = 0;
867       rs.w = layer->width;
868       rs.h = layer->height;
869       rd.x = layer->offset_x;
870       rd.y = layer->offset_y;
871       rd.w = layer->width;
872       rd.h = layer->height;
873 
874       if (layer->visible)
875         SDL_BlitSurface (lays, &rs, surface, &rd);
876       free_xcf_layer (layer);
877     }
878   }
879 
880   SDL_FreeSurface (lays);
881 
882   SDL_RWseek (src, fp, RW_SEEK_SET);
883 
884   // read channels
885   channel = NULL;
886   chnls   = 0;
887   while ((offset = read_offset (src, head))) {
888     channel = (xcf_channel **) SDL_realloc (channel, sizeof (xcf_channel *) * (chnls+1));
889     fp = SDL_RWtell (src);
890     SDL_RWseek (src, offset, RW_SEEK_SET);
891     channel [chnls] = (read_xcf_channel (src, head));
892     if (channel [chnls] != NULL)
893       chnls++;
894     SDL_RWseek (src, fp, RW_SEEK_SET);
895   }
896 
897   if (chnls) {
898     SDL_Surface * chs;
899 
900     chs = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
901                0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
902 
903     if (chs == NULL) {
904       error = "Out of memory";
905       goto done;
906     }
907     for (i = 0; i < chnls; i++) {
908       //      printf ("CNLBLT %i\n", i);
909       if (!channel [i]->selection && channel [i]->visible) {
910     create_channel_surface (chs, (xcf_image_type)head->image_type, channel [i]->color, channel [i]->opacity);
911     SDL_BlitSurface (chs, NULL, surface, NULL);
912       }
913       free_xcf_channel (channel [i]);
914     }
915     SDL_free(channel);
916 
917     SDL_FreeSurface (chs);
918   }
919 
920 done:
921   free_xcf_header (head);
922   if ( error ) {
923     SDL_RWseek(src, start, RW_SEEK_SET);
924     if ( surface ) {
925       SDL_FreeSurface(surface);
926       surface = NULL;
927     }
928     IMG_SetError("%s", error);
929   }
930 
931   return(surface);
932 }
933 
934 #else
935 
936 /* See if an image is contained in a data source */
IMG_isXCF(SDL_RWops * src)937 int IMG_isXCF(SDL_RWops *src)
938 {
939   return(0);
940 }
941 
942 /* Load a XCF type image from an SDL datasource */
IMG_LoadXCF_RW(SDL_RWops * src)943 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
944 {
945   return(NULL);
946 }
947 
948 #endif /* LOAD_XCF */
949