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