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