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