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