IMG_xcf.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 08 May 2018 20:26:48 -0700
changeset 580 887b1e03cad1
parent 575 36e9e2255178
child 585 170d7d32e4a8
permissions -rwxr-xr-x
Fixed building the SDL_image static library on OS X
     1 /*
     2   SDL_image:  An example image loading library for use with SDL
     3   Copyright (C) 1997-2018 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 width;
   142   Uint32 height;
   143   Sint32 image_type;
   144   xcf_prop * properties;
   145 
   146   Uint32 * layer_file_offsets;
   147   Uint32 * channel_file_offsets;
   148 
   149   xcf_compr_type compr;
   150   Uint32         cm_num;
   151   unsigned char * cm_map;
   152 } xcf_header;
   153 
   154 typedef struct {
   155   Uint32 width;
   156   Uint32 height;
   157   Sint32 layer_type;
   158   char * name;
   159   xcf_prop * properties;
   160 
   161   Uint32 hierarchy_file_offset;
   162   Uint32 layer_mask_offset;
   163 
   164   Uint32 offset_x;
   165   Uint32 offset_y;
   166   int visible;
   167 } xcf_layer;
   168 
   169 typedef struct {
   170   Uint32 width;
   171   Uint32 height;
   172   char * name;
   173   xcf_prop * properties;
   174 
   175   Uint32 hierarchy_file_offset;
   176 
   177   Uint32 color;
   178   Uint32 opacity;
   179   int selection;
   180   int visible;
   181 } xcf_channel;
   182 
   183 typedef struct {
   184   Uint32 width;
   185   Uint32 height;
   186   Uint32 bpp;
   187 
   188   Uint32 * level_file_offsets;
   189 } xcf_hierarchy;
   190 
   191 typedef struct {
   192   Uint32 width;
   193   Uint32 height;
   194 
   195   Uint32 * tile_file_offsets;
   196 } xcf_level;
   197 
   198 typedef unsigned char * xcf_tile;
   199 
   200 typedef unsigned char * (* load_tile_type) (SDL_RWops *, Uint32, int, int, int);
   201 
   202 
   203 /* See if an image is contained in a data source */
   204 int IMG_isXCF(SDL_RWops *src)
   205 {
   206     Sint64 start;
   207     int is_XCF;
   208     char magic[14];
   209 
   210     if ( !src )
   211         return 0;
   212     start = SDL_RWtell(src);
   213     is_XCF = 0;
   214     if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
   215         if (SDL_strncmp(magic, "gimp xcf ", 9) == 0) {
   216             is_XCF = 1;
   217         }
   218     }
   219     SDL_RWseek(src, start, RW_SEEK_SET);
   220     return(is_XCF);
   221 }
   222 
   223 static char * read_string (SDL_RWops * src) {
   224   Uint32 tmp;
   225   char * data;
   226 
   227   tmp = SDL_ReadBE32 (src);
   228   if (tmp > 0) {
   229     data = (char *) SDL_malloc (sizeof (char) * tmp);
   230     SDL_RWread (src, data, tmp, 1);
   231   }
   232   else {
   233     data = NULL;
   234   }
   235 
   236   return data;
   237 }
   238 
   239 
   240 static Uint32 Swap32 (Uint32 v) {
   241   return
   242     ((v & 0x000000FF) << 16)
   243     |  ((v & 0x0000FF00))
   244     |  ((v & 0x00FF0000) >> 16)
   245     |  ((v & 0xFF000000));
   246 }
   247 
   248 static void xcf_read_property (SDL_RWops * src, xcf_prop * prop) {
   249   Uint32 len;
   250   prop->id = SDL_ReadBE32 (src);
   251   prop->length = SDL_ReadBE32 (src);
   252 
   253 #if DEBUG
   254   printf ("%.8X: %s: %d\n", SDL_RWtell (src), prop->id < 25 ? prop_names [prop->id] : "unknown", prop->length);
   255 #endif
   256 
   257   switch (prop->id) {
   258   case PROP_COLORMAP:
   259     prop->data.colormap.num = SDL_ReadBE32 (src);
   260     prop->data.colormap.cmap = (char *) SDL_malloc (sizeof (char) * prop->data.colormap.num * 3);
   261     SDL_RWread (src, prop->data.colormap.cmap, prop->data.colormap.num*3, 1);
   262     break;
   263 
   264   case PROP_OFFSETS:
   265     prop->data.offset.x = SDL_ReadBE32 (src);
   266     prop->data.offset.y = SDL_ReadBE32 (src);
   267     break;
   268   case PROP_OPACITY:
   269     prop->data.opacity = SDL_ReadBE32 (src);
   270     break;
   271   case PROP_COMPRESSION:
   272   case PROP_COLOR:
   273     if (prop->length > sizeof(prop->data)) {
   274         len = sizeof(prop->data);
   275     } else {
   276         len = prop->length;
   277     }
   278     SDL_RWread(src, &prop->data, len, 1);
   279     break;
   280   case PROP_VISIBLE:
   281     prop->data.visible = SDL_ReadBE32 (src);
   282     break;
   283   default:
   284     //    SDL_RWread (src, &prop->data, prop->length, 1);
   285     SDL_RWseek (src, prop->length, RW_SEEK_CUR);
   286   }
   287 }
   288 
   289 static void free_xcf_header (xcf_header * h) {
   290   if (h->cm_num)
   291     SDL_free (h->cm_map);
   292   if (h->layer_file_offsets)
   293     SDL_free (h->layer_file_offsets);
   294   SDL_free (h);
   295 }
   296 
   297 static xcf_header * read_xcf_header (SDL_RWops * src) {
   298   xcf_header * h;
   299   xcf_prop prop;
   300 
   301   h = (xcf_header *) SDL_malloc (sizeof (xcf_header));
   302   if (!h) {
   303     return NULL;
   304   }
   305   SDL_RWread (src, h->sign, 14, 1);
   306   h->width       = SDL_ReadBE32 (src);
   307   h->height      = SDL_ReadBE32 (src);
   308   h->image_type  = SDL_ReadBE32 (src);
   309 
   310   h->properties = NULL;
   311   h->layer_file_offsets = NULL;
   312   h->compr      = COMPR_NONE;
   313   h->cm_num = 0;
   314   h->cm_map = NULL;
   315 
   316   // Just read, don't save
   317   do {
   318     xcf_read_property (src, &prop);
   319     if (prop.id == PROP_COMPRESSION)
   320       h->compr = (xcf_compr_type)prop.data.compression;
   321     else if (prop.id == PROP_COLORMAP) {
   322       // unused var: int i;
   323       Uint32 cm_num;
   324       unsigned char *cm_map;
   325 
   326       cm_num = prop.data.colormap.num;
   327       cm_map = (unsigned char *) SDL_realloc(h->cm_map, sizeof (unsigned char) * 3 * cm_num);
   328       if (cm_map) {
   329         h->cm_num = cm_num;
   330         h->cm_map = cm_map;
   331         SDL_memcpy (h->cm_map, prop.data.colormap.cmap, 3*sizeof (char)*h->cm_num);
   332       }
   333       SDL_free (prop.data.colormap.cmap);
   334 
   335       if (!cm_map) {
   336         free_xcf_header(h);
   337         return NULL;
   338       }
   339     }
   340   } while (prop.id != PROP_END);
   341 
   342   return h;
   343 }
   344 
   345 static void free_xcf_layer (xcf_layer * l) {
   346   SDL_free (l->name);
   347   SDL_free (l);
   348 }
   349 
   350 static xcf_layer * read_xcf_layer (SDL_RWops * src) {
   351   xcf_layer * l;
   352   xcf_prop    prop;
   353 
   354   l = (xcf_layer *) SDL_malloc (sizeof (xcf_layer));
   355   l->width  = SDL_ReadBE32 (src);
   356   l->height = SDL_ReadBE32 (src);
   357   l->layer_type = SDL_ReadBE32 (src);
   358 
   359   l->name = read_string (src);
   360 
   361   do {
   362     xcf_read_property (src, &prop);
   363     if (prop.id == PROP_OFFSETS) {
   364       l->offset_x = prop.data.offset.x;
   365       l->offset_y = prop.data.offset.y;
   366     } else if (prop.id == PROP_VISIBLE) {
   367       l->visible = prop.data.visible ? 1 : 0;
   368     }
   369   } while (prop.id != PROP_END);
   370 
   371   l->hierarchy_file_offset = SDL_ReadBE32 (src);
   372   l->layer_mask_offset     = SDL_ReadBE32 (src);
   373 
   374   return l;
   375 }
   376 
   377 static void free_xcf_channel (xcf_channel * c) {
   378   SDL_free (c->name);
   379   SDL_free (c);
   380 }
   381 
   382 static xcf_channel * read_xcf_channel (SDL_RWops * src) {
   383   xcf_channel * l;
   384   xcf_prop    prop;
   385 
   386   l = (xcf_channel *) SDL_malloc (sizeof (xcf_channel));
   387   l->width  = SDL_ReadBE32 (src);
   388   l->height = SDL_ReadBE32 (src);
   389 
   390   l->name = read_string (src);
   391 
   392   l->selection = 0;
   393   do {
   394     xcf_read_property (src, &prop);
   395     switch (prop.id) {
   396     case PROP_OPACITY:
   397       l->opacity = prop.data.opacity << 24;
   398       break;
   399     case PROP_COLOR:
   400       l->color = ((Uint32) prop.data.color[0] << 16)
   401     | ((Uint32) prop.data.color[1] << 8)
   402     | ((Uint32) prop.data.color[2]);
   403       break;
   404     case PROP_SELECTION:
   405       l->selection = 1;
   406       break;
   407     case PROP_VISIBLE:
   408       l->visible = prop.data.visible ? 1 : 0;
   409       break;
   410     default:
   411         ;
   412     }
   413   } while (prop.id != PROP_END);
   414 
   415   l->hierarchy_file_offset = SDL_ReadBE32 (src);
   416 
   417   return l;
   418 }
   419 
   420 static void free_xcf_hierarchy (xcf_hierarchy * h) {
   421   SDL_free (h->level_file_offsets);
   422   SDL_free (h);
   423 }
   424 
   425 static xcf_hierarchy * read_xcf_hierarchy (SDL_RWops * src) {
   426   xcf_hierarchy * h;
   427   int i;
   428 
   429   h = (xcf_hierarchy *) SDL_malloc (sizeof (xcf_hierarchy));
   430   h->width  = SDL_ReadBE32 (src);
   431   h->height = SDL_ReadBE32 (src);
   432   h->bpp    = SDL_ReadBE32 (src);
   433 
   434   h->level_file_offsets = NULL;
   435   i = 0;
   436   do {
   437     h->level_file_offsets = (Uint32 *) SDL_realloc (h->level_file_offsets, sizeof (Uint32) * (i+1));
   438     h->level_file_offsets [i] = SDL_ReadBE32 (src);
   439   } while (h->level_file_offsets [i++]);
   440 
   441   return h;
   442 }
   443 
   444 static void free_xcf_level (xcf_level * l) {
   445   SDL_free (l->tile_file_offsets);
   446   SDL_free (l);
   447 }
   448 
   449 static xcf_level * read_xcf_level (SDL_RWops * src) {
   450   xcf_level * l;
   451   int i;
   452 
   453   l = (xcf_level *) SDL_malloc (sizeof (xcf_level));
   454   l->width  = SDL_ReadBE32 (src);
   455   l->height = SDL_ReadBE32 (src);
   456 
   457   l->tile_file_offsets = NULL;
   458   i = 0;
   459   do {
   460     l->tile_file_offsets = (Uint32 *) SDL_realloc (l->tile_file_offsets, sizeof (Uint32) * (i+1));
   461     l->tile_file_offsets [i] = SDL_ReadBE32 (src);
   462   } while (l->tile_file_offsets [i++]);
   463 
   464   return l;
   465 }
   466 
   467 static void free_xcf_tile (unsigned char * t) {
   468   SDL_free (t);
   469 }
   470 
   471 static unsigned char * load_xcf_tile_none (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
   472   unsigned char * load;
   473 
   474   load = (unsigned char *) SDL_malloc (len); // expect this is okay
   475   SDL_RWread (src, load, len, 1);
   476 
   477   return load;
   478 }
   479 
   480 static unsigned char * load_xcf_tile_rle (SDL_RWops * src, Uint32 len, int bpp, int x, int y) {
   481   unsigned char * load, * t, * data, * d;
   482   Uint32 reallen;
   483   int i, size, count, j, length;
   484   unsigned char val;
   485 
   486   if (len == 0) {  /* probably bogus data. */
   487     return NULL;
   488   }
   489 
   490   t = load = (unsigned char *) SDL_malloc (len);
   491   reallen = SDL_RWread (src, t, 1, len);
   492 
   493   data = (unsigned char *) SDL_calloc (1, x*y*bpp);
   494   for (i = 0; i < bpp; i++) {
   495     d    = data + i;
   496     size = x*y;
   497     count = 0;
   498 
   499     while (size > 0) {
   500       val = *t++;
   501 
   502       length = val;
   503       if (length >= 128) {
   504         length = 255 - (length - 1);
   505         if (length == 128) {
   506           length = (*t << 8) + t[1];
   507           t += 2;
   508         }
   509 
   510         if (((size_t) (t - load) + length) >= len) {
   511           break;  /* bogus data */
   512         } else if (length > size) {
   513           break;  /* bogus data */
   514         }
   515 
   516         count += length;
   517         size -= length;
   518 
   519         while (length-- > 0) {
   520           *d = *t++;
   521           d += bpp;
   522         }
   523       } else {
   524         length += 1;
   525         if (length == 128) {
   526           length = (*t << 8) + t[1];
   527           t += 2;
   528         }
   529 
   530         if (((size_t) (t - load)) >= len) {
   531           break;  /* bogus data */
   532         } else if (length > size) {
   533           break;  /* bogus data */
   534         }
   535 
   536         count += length;
   537         size -= length;
   538 
   539         val = *t++;
   540 
   541         for (j = 0; j < length; j++) {
   542           *d = val;
   543           d += bpp;
   544         }
   545       }
   546     }
   547 
   548     if (size > 0) {
   549       break;  /* just drop out, untouched data initialized to zero. */
   550     }
   551 
   552   }
   553 
   554   SDL_free (load);
   555   return (data);
   556 }
   557 
   558 static Uint32 rgb2grey (Uint32 a) {
   559   Uint8 l;
   560   l = (Uint8)(0.2990 * ((a & 0x00FF0000) >> 16)
   561     + 0.5870 * ((a & 0x0000FF00) >>  8)
   562     + 0.1140 * ((a & 0x000000FF)));
   563 
   564   return (l << 16) | (l << 8) | l;
   565 }
   566 
   567 static void create_channel_surface (SDL_Surface * surf, xcf_image_type itype, Uint32 color, Uint32 opacity) {
   568   Uint32 c = 0;
   569 
   570   switch (itype) {
   571   case IMAGE_RGB:
   572   case IMAGE_INDEXED:
   573     c = opacity | color;
   574     break;
   575   case IMAGE_GREYSCALE:
   576     c = opacity | rgb2grey (color);
   577     break;
   578   }
   579   SDL_FillRect (surf, NULL, c);
   580 }
   581 
   582 static int 
   583 do_layer_surface(SDL_Surface * surface, SDL_RWops * src, xcf_header * head, xcf_layer * layer, load_tile_type load_tile)
   584 {
   585     xcf_hierarchy  *hierarchy;
   586     xcf_level      *level;
   587     unsigned char  *tile;
   588     Uint8          *p8;
   589     Uint16         *p16;
   590     Uint32         *p;
   591     int            i, j;
   592     Uint32         x, y, tx, ty, ox, oy;
   593     Uint32         *row;
   594 
   595     SDL_RWseek(src, layer->hierarchy_file_offset, RW_SEEK_SET);
   596     hierarchy = read_xcf_hierarchy(src);
   597 
   598     if (hierarchy->bpp > 4) {  /* unsupported. */
   599         SDL_Log("Unknown Gimp image bpp (%u)\n", (unsigned int) hierarchy->bpp);
   600         free_xcf_hierarchy(hierarchy);
   601         return 1;
   602     }
   603 
   604     if ((hierarchy->width > 20000) || (hierarchy->height > 20000)) {  /* arbitrary limit to avoid integer overflow. */
   605         SDL_Log("Gimp image too large (%ux%u)\n", (unsigned int) hierarchy->width, (unsigned int) hierarchy->height);
   606         free_xcf_hierarchy(hierarchy);
   607         return 1;
   608     }
   609 
   610     level = NULL;
   611     for (i = 0; hierarchy->level_file_offsets[i]; i++) {
   612         SDL_RWseek(src, hierarchy->level_file_offsets[i], RW_SEEK_SET);
   613         level = read_xcf_level(src);
   614 
   615         ty = tx = 0;
   616         for (j = 0; level->tile_file_offsets[j]; j++) {
   617             SDL_RWseek(src, level->tile_file_offsets[j], RW_SEEK_SET);
   618             ox = tx + 64 > level->width ? level->width % 64 : 64;
   619             oy = ty + 64 > level->height ? level->height % 64 : 64;
   620 
   621             if (level->tile_file_offsets[j + 1]) {
   622                 tile = load_tile(src, level->tile_file_offsets[j + 1] - level->tile_file_offsets[j], hierarchy->bpp, ox, oy);
   623             } else {
   624                 tile = load_tile(src, ox * oy * 6, hierarchy->bpp, ox, oy);
   625             }
   626 
   627             if (!tile) {
   628                 if (hierarchy) {
   629                     free_xcf_hierarchy(hierarchy);
   630                 }
   631                 if (level) {
   632                     free_xcf_level(level);
   633                 }
   634                 return 1;
   635             }
   636 
   637             p8 = tile;
   638             p16 = (Uint16 *) p8;
   639             p = (Uint32 *) p8;
   640             for (y = ty; y < ty + oy; y++) {
   641                 row = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch + tx * 4);
   642                 switch (hierarchy->bpp) {
   643                 case 4:
   644                     for (x = tx; x < tx + ox; x++)
   645                         *row++ = Swap32(*p++);
   646                     break;
   647                 case 3:
   648                     for (x = tx; x < tx + ox; x++) {
   649                         *row = 0xFF000000;
   650                         *row |= ((Uint32)*p8++ << 16);
   651                         *row |= ((Uint32)*p8++ << 8);
   652                         *row |= ((Uint32)*p8++ << 0);
   653                         row++;
   654                     }
   655                     break;
   656                 case 2:
   657                     /* Indexed / Greyscale + Alpha */
   658                     switch (head->image_type) {
   659                     case IMAGE_INDEXED:
   660                         for (x = tx; x < tx + ox; x++) {
   661                             *row = ((Uint32)(head->cm_map[*p8 * 3]) << 16);
   662                             *row |= ((Uint32)(head->cm_map[*p8 * 3 + 1]) << 8);
   663                             *row |= ((Uint32)(head->cm_map[*p8++ * 3 + 2]) << 0);
   664                             *row |= ((Uint32)*p8++ << 24);
   665                             row++;
   666                         }
   667                         break;
   668                     case IMAGE_GREYSCALE:
   669                         for (x = tx; x < tx + ox; x++) {
   670                             *row = ((Uint32)*p8 << 16);
   671                             *row |= ((Uint32)*p8 << 8);
   672                             *row |= ((Uint32)*p8++ << 0);
   673                             *row |= ((Uint32)*p8++ << 24);
   674                             row++;
   675                         }
   676                         break;
   677                     default:
   678                         SDL_Log("Unknown Gimp image type (%d)\n", head->image_type);
   679                         if (hierarchy) {
   680                             free_xcf_hierarchy(hierarchy);
   681                         }
   682                         if (level)
   683                             free_xcf_level(level);
   684                         return 1;
   685                     }
   686                     break;
   687                 case 1:
   688                     /* Indexed / Greyscale */
   689                     switch (head->image_type) {
   690                     case IMAGE_INDEXED:
   691                         for (x = tx; x < tx + ox; x++) {
   692                             *row++ = 0xFF000000
   693                                 | ((Uint32)(head->cm_map[*p8 * 3]) << 16)
   694                                 | ((Uint32)(head->cm_map[*p8 * 3 + 1]) << 8)
   695                                 | ((Uint32)(head->cm_map[*p8 * 3 + 2]) << 0);
   696                             p8++;
   697                         }
   698                         break;
   699                     case IMAGE_GREYSCALE:
   700                         for (x = tx; x < tx + ox; x++) {
   701                             *row++ = 0xFF000000
   702                                 | (((Uint32)(*p8)) << 16)
   703                                 | (((Uint32)(*p8)) << 8)
   704                                 | (((Uint32)(*p8)) << 0);
   705                             ++p8;
   706                         }
   707                         break;
   708                     default:
   709                         SDL_Log("Unknown Gimp image type (%d)\n", head->image_type);
   710                         if (tile)
   711                             free_xcf_tile(tile);
   712                         if (level)
   713                             free_xcf_level(level);
   714                         if (hierarchy)
   715                             free_xcf_hierarchy(hierarchy);
   716                         return 1;
   717                     }
   718                     break;
   719                 }
   720             }
   721             free_xcf_tile(tile);
   722 
   723             tx += 64;
   724             if (tx >= level->width) {
   725                 tx = 0;
   726                 ty += 64;
   727             }
   728             if (ty >= level->height) {
   729                 break;
   730             }
   731         }
   732         free_xcf_level(level);
   733     }
   734 
   735     free_xcf_hierarchy(hierarchy);
   736 
   737     return 0;
   738 }
   739 
   740 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
   741 {
   742   Sint64 start;
   743   const char *error = NULL;
   744   SDL_Surface *surface, *lays;
   745   xcf_header * head;
   746   xcf_layer  * layer;
   747   xcf_channel ** channel;
   748   int chnls, i, offsets;
   749   Sint64 offset, fp;
   750 
   751   unsigned char * (* load_tile) (SDL_RWops *, Uint32, int, int, int);
   752 
   753   if (!src) {
   754     /* The error message has been set in SDL_RWFromFile */
   755     return NULL;
   756   }
   757   start = SDL_RWtell(src);
   758 
   759   /* Initialize the data we will clean up when we're done */
   760   surface = NULL;
   761 
   762   head = read_xcf_header(src);
   763   if (!head) {
   764     return NULL;
   765   }
   766 
   767   switch (head->compr) {
   768   case COMPR_NONE:
   769     load_tile = load_xcf_tile_none;
   770     break;
   771   case COMPR_RLE:
   772     load_tile = load_xcf_tile_rle;
   773     break;
   774   default:
   775     SDL_Log("Unsupported Compression.\n");
   776     free_xcf_header (head);
   777     return NULL;
   778   }
   779 
   780   /* Create the surface of the appropriate type */
   781   surface = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
   782                  0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   783 
   784   if ( surface == NULL ) {
   785     error = "Out of memory";
   786     goto done;
   787   }
   788 
   789   offsets = 0;
   790 
   791   while ((offset = SDL_ReadBE32 (src))) {
   792     head->layer_file_offsets = (Uint32 *) SDL_realloc (head->layer_file_offsets, sizeof (Uint32) * (offsets+1));
   793     head->layer_file_offsets [offsets] = (Uint32)offset;
   794     offsets++;
   795   }
   796   fp = SDL_RWtell (src);
   797 
   798   lays = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
   799               0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   800 
   801   if ( lays == NULL ) {
   802     error = "Out of memory";
   803     goto done;
   804   }
   805 
   806   // Blit layers backwards, because Gimp saves them highest first
   807   for (i = offsets; i > 0; i--) {
   808     SDL_Rect rs, rd;
   809     SDL_RWseek (src, head->layer_file_offsets [i-1], RW_SEEK_SET);
   810 
   811     layer = read_xcf_layer (src);
   812     do_layer_surface (lays, src, head, layer, load_tile);
   813     rs.x = 0;
   814     rs.y = 0;
   815     rs.w = layer->width;
   816     rs.h = layer->height;
   817     rd.x = layer->offset_x;
   818     rd.y = layer->offset_y;
   819     rd.w = layer->width;
   820     rd.h = layer->height;
   821 
   822     if (layer->visible)
   823       SDL_BlitSurface (lays, &rs, surface, &rd);
   824     free_xcf_layer (layer);
   825   }
   826 
   827   SDL_FreeSurface (lays);
   828 
   829   SDL_RWseek (src, fp, RW_SEEK_SET);
   830 
   831   // read channels
   832   channel = NULL;
   833   chnls   = 0;
   834   while ((offset = SDL_ReadBE32 (src))) {
   835     channel = (xcf_channel **) SDL_realloc (channel, sizeof (xcf_channel *) * (chnls+1));
   836     fp = SDL_RWtell (src);
   837     SDL_RWseek (src, offset, RW_SEEK_SET);
   838     channel [chnls++] = (read_xcf_channel (src));
   839     SDL_RWseek (src, fp, RW_SEEK_SET);
   840   }
   841 
   842   if (chnls) {
   843     SDL_Surface * chs;
   844 
   845     chs = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
   846                0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   847 
   848     if (chs == NULL) {
   849       error = "Out of memory";
   850       goto done;
   851     }
   852     for (i = 0; i < chnls; i++) {
   853       //      printf ("CNLBLT %i\n", i);
   854       if (!channel [i]->selection && channel [i]->visible) {
   855     create_channel_surface (chs, (xcf_image_type)head->image_type, channel [i]->color, channel [i]->opacity);
   856     SDL_BlitSurface (chs, NULL, surface, NULL);
   857       }
   858       free_xcf_channel (channel [i]);
   859     }
   860 
   861     SDL_FreeSurface (chs);
   862   }
   863 
   864 done:
   865   free_xcf_header (head);
   866   if ( error ) {
   867     SDL_RWseek(src, start, RW_SEEK_SET);
   868     if ( surface ) {
   869       SDL_FreeSurface(surface);
   870       surface = NULL;
   871     }
   872     IMG_SetError("%s", error);
   873   }
   874 
   875   return(surface);
   876 }
   877 
   878 #else
   879 
   880 /* See if an image is contained in a data source */
   881 int IMG_isXCF(SDL_RWops *src)
   882 {
   883   return(0);
   884 }
   885 
   886 /* Load a XCF type image from an SDL datasource */
   887 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
   888 {
   889   return(NULL);
   890 }
   891 
   892 #endif /* LOAD_XCF */