IMG_xcf.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 25 Apr 2013 00:22:51 -0700
changeset 367 b2aa197f6774
parent 365 ce8091caddf3
child 368 8a61842d00ce
permissions -rw-r--r--
Fixed bug 1821 - IMG_LoadLBM/PNM/XCF_RW() crash with a heap corruption on loading LBM, PNM or XCF images

Marcus von Appen

Trying to load a LBM image via any of the IMG_* functions will lead to a heap corruption on Windows 7, causing the application to crash.

The problem is caused by the usage of SDL_malloc on Win32, which by default uses dlmalloc, which in turn redefines malloc and free within the SDL address space.

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