IMG_xcf.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 26 Sep 2018 14:58:31 -0400
changeset 585 170d7d32e4a8
parent 575 36e9e2255178
child 590 8b4ee1d72a2a
permissions -rw-r--r--
xcf: Fix potential buffer overflow on corrupt or maliciously-crafted XCF file.
     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                 if ((ty >= surface->h) || ((tx+ox) > surface->w)) {
   642                     break;
   643                 }
   644                 row = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch + tx * 4);
   645                 switch (hierarchy->bpp) {
   646                 case 4:
   647                     for (x = tx; x < tx + ox; x++)
   648                         *row++ = Swap32(*p++);
   649                     break;
   650                 case 3:
   651                     for (x = tx; x < tx + ox; x++) {
   652                         *row = 0xFF000000;
   653                         *row |= ((Uint32)*p8++ << 16);
   654                         *row |= ((Uint32)*p8++ << 8);
   655                         *row |= ((Uint32)*p8++ << 0);
   656                         row++;
   657                     }
   658                     break;
   659                 case 2:
   660                     /* Indexed / Greyscale + Alpha */
   661                     switch (head->image_type) {
   662                     case IMAGE_INDEXED:
   663                         for (x = tx; x < tx + ox; x++) {
   664                             *row = ((Uint32)(head->cm_map[*p8 * 3]) << 16);
   665                             *row |= ((Uint32)(head->cm_map[*p8 * 3 + 1]) << 8);
   666                             *row |= ((Uint32)(head->cm_map[*p8++ * 3 + 2]) << 0);
   667                             *row |= ((Uint32)*p8++ << 24);
   668                             row++;
   669                         }
   670                         break;
   671                     case IMAGE_GREYSCALE:
   672                         for (x = tx; x < tx + ox; x++) {
   673                             *row = ((Uint32)*p8 << 16);
   674                             *row |= ((Uint32)*p8 << 8);
   675                             *row |= ((Uint32)*p8++ << 0);
   676                             *row |= ((Uint32)*p8++ << 24);
   677                             row++;
   678                         }
   679                         break;
   680                     default:
   681                         SDL_Log("Unknown Gimp image type (%d)\n", head->image_type);
   682                         if (hierarchy) {
   683                             free_xcf_hierarchy(hierarchy);
   684                         }
   685                         if (level)
   686                             free_xcf_level(level);
   687                         return 1;
   688                     }
   689                     break;
   690                 case 1:
   691                     /* Indexed / Greyscale */
   692                     switch (head->image_type) {
   693                     case IMAGE_INDEXED:
   694                         for (x = tx; x < tx + ox; x++) {
   695                             *row++ = 0xFF000000
   696                                 | ((Uint32)(head->cm_map[*p8 * 3]) << 16)
   697                                 | ((Uint32)(head->cm_map[*p8 * 3 + 1]) << 8)
   698                                 | ((Uint32)(head->cm_map[*p8 * 3 + 2]) << 0);
   699                             p8++;
   700                         }
   701                         break;
   702                     case IMAGE_GREYSCALE:
   703                         for (x = tx; x < tx + ox; x++) {
   704                             *row++ = 0xFF000000
   705                                 | (((Uint32)(*p8)) << 16)
   706                                 | (((Uint32)(*p8)) << 8)
   707                                 | (((Uint32)(*p8)) << 0);
   708                             ++p8;
   709                         }
   710                         break;
   711                     default:
   712                         SDL_Log("Unknown Gimp image type (%d)\n", head->image_type);
   713                         if (tile)
   714                             free_xcf_tile(tile);
   715                         if (level)
   716                             free_xcf_level(level);
   717                         if (hierarchy)
   718                             free_xcf_hierarchy(hierarchy);
   719                         return 1;
   720                     }
   721                     break;
   722                 }
   723             }
   724             free_xcf_tile(tile);
   725 
   726             tx += 64;
   727             if (tx >= level->width) {
   728                 tx = 0;
   729                 ty += 64;
   730             }
   731             if (ty >= level->height) {
   732                 break;
   733             }
   734         }
   735         free_xcf_level(level);
   736     }
   737 
   738     free_xcf_hierarchy(hierarchy);
   739 
   740     return 0;
   741 }
   742 
   743 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
   744 {
   745   Sint64 start;
   746   const char *error = NULL;
   747   SDL_Surface *surface, *lays;
   748   xcf_header * head;
   749   xcf_layer  * layer;
   750   xcf_channel ** channel;
   751   int chnls, i, offsets;
   752   Sint64 offset, fp;
   753 
   754   unsigned char * (* load_tile) (SDL_RWops *, Uint32, int, int, int);
   755 
   756   if (!src) {
   757     /* The error message has been set in SDL_RWFromFile */
   758     return NULL;
   759   }
   760   start = SDL_RWtell(src);
   761 
   762   /* Initialize the data we will clean up when we're done */
   763   surface = NULL;
   764 
   765   head = read_xcf_header(src);
   766   if (!head) {
   767     return NULL;
   768   }
   769 
   770   switch (head->compr) {
   771   case COMPR_NONE:
   772     load_tile = load_xcf_tile_none;
   773     break;
   774   case COMPR_RLE:
   775     load_tile = load_xcf_tile_rle;
   776     break;
   777   default:
   778     SDL_Log("Unsupported Compression.\n");
   779     free_xcf_header (head);
   780     return NULL;
   781   }
   782 
   783   /* Create the surface of the appropriate type */
   784   surface = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
   785                  0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   786 
   787   if ( surface == NULL ) {
   788     error = "Out of memory";
   789     goto done;
   790   }
   791 
   792   offsets = 0;
   793 
   794   while ((offset = SDL_ReadBE32 (src))) {
   795     head->layer_file_offsets = (Uint32 *) SDL_realloc (head->layer_file_offsets, sizeof (Uint32) * (offsets+1));
   796     head->layer_file_offsets [offsets] = (Uint32)offset;
   797     offsets++;
   798   }
   799   fp = SDL_RWtell (src);
   800 
   801   lays = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
   802               0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   803 
   804   if ( lays == NULL ) {
   805     error = "Out of memory";
   806     goto done;
   807   }
   808 
   809   // Blit layers backwards, because Gimp saves them highest first
   810   for (i = offsets; i > 0; i--) {
   811     SDL_Rect rs, rd;
   812     SDL_RWseek (src, head->layer_file_offsets [i-1], RW_SEEK_SET);
   813 
   814     layer = read_xcf_layer (src);
   815     do_layer_surface (lays, src, head, layer, load_tile);
   816     rs.x = 0;
   817     rs.y = 0;
   818     rs.w = layer->width;
   819     rs.h = layer->height;
   820     rd.x = layer->offset_x;
   821     rd.y = layer->offset_y;
   822     rd.w = layer->width;
   823     rd.h = layer->height;
   824 
   825     if (layer->visible)
   826       SDL_BlitSurface (lays, &rs, surface, &rd);
   827     free_xcf_layer (layer);
   828   }
   829 
   830   SDL_FreeSurface (lays);
   831 
   832   SDL_RWseek (src, fp, RW_SEEK_SET);
   833 
   834   // read channels
   835   channel = NULL;
   836   chnls   = 0;
   837   while ((offset = SDL_ReadBE32 (src))) {
   838     channel = (xcf_channel **) SDL_realloc (channel, sizeof (xcf_channel *) * (chnls+1));
   839     fp = SDL_RWtell (src);
   840     SDL_RWseek (src, offset, RW_SEEK_SET);
   841     channel [chnls++] = (read_xcf_channel (src));
   842     SDL_RWseek (src, fp, RW_SEEK_SET);
   843   }
   844 
   845   if (chnls) {
   846     SDL_Surface * chs;
   847 
   848     chs = SDL_CreateRGBSurface(SDL_SWSURFACE, head->width, head->height, 32,
   849                0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
   850 
   851     if (chs == NULL) {
   852       error = "Out of memory";
   853       goto done;
   854     }
   855     for (i = 0; i < chnls; i++) {
   856       //      printf ("CNLBLT %i\n", i);
   857       if (!channel [i]->selection && channel [i]->visible) {
   858     create_channel_surface (chs, (xcf_image_type)head->image_type, channel [i]->color, channel [i]->opacity);
   859     SDL_BlitSurface (chs, NULL, surface, NULL);
   860       }
   861       free_xcf_channel (channel [i]);
   862     }
   863 
   864     SDL_FreeSurface (chs);
   865   }
   866 
   867 done:
   868   free_xcf_header (head);
   869   if ( error ) {
   870     SDL_RWseek(src, start, RW_SEEK_SET);
   871     if ( surface ) {
   872       SDL_FreeSurface(surface);
   873       surface = NULL;
   874     }
   875     IMG_SetError("%s", error);
   876   }
   877 
   878   return(surface);
   879 }
   880 
   881 #else
   882 
   883 /* See if an image is contained in a data source */
   884 int IMG_isXCF(SDL_RWops *src)
   885 {
   886   return(0);
   887 }
   888 
   889 /* Load a XCF type image from an SDL datasource */
   890 SDL_Surface *IMG_LoadXCF_RW(SDL_RWops *src)
   891 {
   892   return(NULL);
   893 }
   894 
   895 #endif /* LOAD_XCF */