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