IMG_xcf.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 27 Jul 2013 01:18:33 -0700
changeset 415 1700d607fce3
parent 368 8a61842d00ce
child 419 e108e1228d62
permissions -rw-r--r--
Fixed bug 1991 - XCF and LBM image loading might lead to random crashes

Marcus von Appen

The current XCF and LBM image loaders mix SDL's and the underlying C memory APIs to allocate, reallocate or compare memory, which can lead to random crashes on the target system.

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