IMG_xpm.c
author Thomas Bernard <miniupnp@free.fr>
Fri, 30 Nov 2018 11:04:15 +0100
branchSDL-1.2
changeset 634 68f958f43339
parent 607 1a1189c2978f
permissions -rw-r--r--
IMG_xcf.c: Avoid infinite loop in read_xcf_header()
slouken@7
     1
/*
slouken@280
     2
  SDL_image:  An example image loading library for use with SDL
slouken@280
     3
  Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
slouken@7
     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@7
     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@7
    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@7
    20
*/
slouken@7
    21
slouken@35
    22
/*
slouken@35
    23
 * XPM (X PixMap) image loader:
slouken@35
    24
 *
slouken@35
    25
 * Supports the XPMv3 format, EXCEPT:
slouken@35
    26
 * - hotspot coordinates are ignored
slouken@35
    27
 * - only colour ('c') colour symbols are used
slouken@35
    28
 * - rgb.txt is not used (for portability), so only RGB colours
slouken@35
    29
 *   are recognized (#rrggbb etc) - only a few basic colour names are
slouken@35
    30
 *   handled
slouken@35
    31
 *
slouken@35
    32
 * The result is an 8bpp indexed surface if possible, otherwise 32bpp.
slouken@35
    33
 * The colourkey is correctly set if transparency is used.
slouken@35
    34
 * 
slouken@35
    35
 * Besides the standard API, also provides
slouken@35
    36
 *
slouken@35
    37
 *     SDL_Surface *IMG_ReadXPMFromArray(char **xpm)
slouken@35
    38
 *
slouken@35
    39
 * that reads the image data from an XPM file included in the C source.
slouken@35
    40
 *
slouken@35
    41
 * TODO: include rgb.txt here. The full table (from solaris 2.6) only
slouken@35
    42
 * requires about 13K in binary form.
slouken@35
    43
 */
slouken@7
    44
slouken@9
    45
#include <stdlib.h>
slouken@7
    46
#include <stdio.h>
slouken@7
    47
#include <string.h>
slouken@7
    48
#include <ctype.h>
slouken@7
    49
slouken@7
    50
#include "SDL_image.h"
slouken@7
    51
slouken@7
    52
#ifdef LOAD_XPM
slouken@7
    53
slouken@7
    54
/* See if an image is contained in a data source */
slouken@7
    55
int IMG_isXPM(SDL_RWops *src)
slouken@7
    56
{
slouken@117
    57
	int start;
slouken@117
    58
	int is_XPM;
slouken@35
    59
	char magic[9];
slouken@7
    60
icculus@154
    61
	if ( !src )
icculus@154
    62
		return 0;
slouken@117
    63
	start = SDL_RWtell(src);
slouken@117
    64
	is_XPM = 0;
slouken@117
    65
	if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
slouken@117
    66
		if ( memcmp(magic, "/* XPM */", sizeof(magic)) == 0 ) {
slouken@117
    67
			is_XPM = 1;
slouken@117
    68
		}
slouken@117
    69
	}
slouken@236
    70
	SDL_RWseek(src, start, RW_SEEK_SET);
slouken@117
    71
	return(is_XPM);
slouken@7
    72
}
slouken@7
    73
slouken@7
    74
/* Hash table to look up colors from pixel strings */
slouken@11
    75
#define STARTING_HASH_SIZE 256
slouken@11
    76
slouken@11
    77
struct hash_entry {
slouken@11
    78
	char *key;
slouken@11
    79
	Uint32 color;
slouken@11
    80
	struct hash_entry *next;
slouken@7
    81
};
slouken@7
    82
slouken@11
    83
struct color_hash {
slouken@11
    84
	struct hash_entry **table;
slouken@11
    85
	struct hash_entry *entries; /* array of all entries */
slouken@11
    86
	struct hash_entry *next_free;
slouken@11
    87
	int size;
slouken@11
    88
	int maxnum;
slouken@11
    89
};
slouken@11
    90
slouken@11
    91
static int hash_key(const char *key, int cpp, int size)
slouken@7
    92
{
slouken@7
    93
	int hash;
slouken@7
    94
slouken@7
    95
	hash = 0;
slouken@7
    96
	while ( cpp-- > 0 ) {
slouken@11
    97
		hash = hash * 33 + *key++;
slouken@7
    98
	}
slouken@11
    99
	return hash & (size - 1);
slouken@7
   100
}
slouken@7
   101
slouken@11
   102
static struct color_hash *create_colorhash(int maxnum)
slouken@7
   103
{
slouken@11
   104
	int bytes, s;
slouken@7
   105
	struct color_hash *hash;
slouken@7
   106
slouken@11
   107
	/* we know how many entries we need, so we can allocate
slouken@11
   108
	   everything here */
sezeroz@607
   109
	hash = (struct color_hash *)malloc(sizeof *hash);
slouken@11
   110
	if(!hash)
slouken@11
   111
		return NULL;
slouken@11
   112
slouken@11
   113
	/* use power-of-2 sized hash table for decoding speed */
slouken@11
   114
	for(s = STARTING_HASH_SIZE; s < maxnum; s <<= 1)
slouken@11
   115
		;
slouken@11
   116
	hash->size = s;
slouken@11
   117
	hash->maxnum = maxnum;
slouken@11
   118
	bytes = hash->size * sizeof(struct hash_entry **);
slouken@11
   119
	hash->entries = NULL;	/* in case malloc fails */
sezeroz@607
   120
	hash->table = (struct hash_entry **)malloc(bytes);
sezeroz@607
   121
	if(!hash->table) {
sezeroz@607
   122
		free(hash);
slouken@11
   123
		return NULL;
sezeroz@607
   124
	}
slouken@11
   125
	memset(hash->table, 0, bytes);
sezeroz@607
   126
	hash->entries = (struct hash_entry *)malloc(maxnum * sizeof(struct hash_entry));
icculus@275
   127
	if(!hash->entries) {
icculus@275
   128
		free(hash->table);
sezeroz@607
   129
		free(hash);
slouken@11
   130
		return NULL;
icculus@275
   131
	}
slouken@11
   132
	hash->next_free = hash->entries;
slouken@11
   133
	return hash;
slouken@7
   134
}
slouken@7
   135
slouken@7
   136
static int add_colorhash(struct color_hash *hash,
slouken@11
   137
                         char *key, int cpp, Uint32 color)
slouken@7
   138
{
slouken@11
   139
	int index = hash_key(key, cpp, hash->size);
slouken@11
   140
	struct hash_entry *e = hash->next_free++;
slouken@11
   141
	e->color = color;
slouken@11
   142
	e->key = key;
slouken@11
   143
	e->next = hash->table[index];
slouken@11
   144
	hash->table[index] = e;
slouken@11
   145
	return 1;
slouken@7
   146
}
slouken@7
   147
slouken@11
   148
/* fast lookup that works if cpp == 1 */
slouken@22
   149
#define QUICK_COLORHASH(hash, key) ((hash)->table[*(Uint8 *)(key)]->color)
slouken@11
   150
slouken@11
   151
static Uint32 get_colorhash(struct color_hash *hash, const char *key, int cpp)
slouken@7
   152
{
slouken@11
   153
	struct hash_entry *entry = hash->table[hash_key(key, cpp, hash->size)];
slouken@11
   154
	while(entry) {
slouken@11
   155
		if(memcmp(key, entry->key, cpp) == 0)
slouken@11
   156
			return entry->color;
slouken@11
   157
		entry = entry->next;
slouken@7
   158
	}
slouken@11
   159
	return 0;		/* garbage in - garbage out */
slouken@7
   160
}
slouken@7
   161
slouken@7
   162
static void free_colorhash(struct color_hash *hash)
slouken@7
   163
{
sezeroz@607
   164
	if(hash) {
slouken@11
   165
		free(hash->table);
slouken@11
   166
		free(hash->entries);
slouken@11
   167
		free(hash);
slouken@7
   168
	}
slouken@7
   169
}
slouken@7
   170
slouken@35
   171
/* portable case-insensitive string comparison */
slouken@35
   172
static int string_equal(const char *a, const char *b, int n)
slouken@35
   173
{
slouken@35
   174
	while(*a && *b && n) {
slouken@35
   175
		if(toupper((unsigned char)*a) != toupper((unsigned char)*b))
slouken@35
   176
			return 0;
slouken@35
   177
		a++;
slouken@35
   178
		b++;
slouken@35
   179
		n--;
slouken@35
   180
	}
slouken@35
   181
	return *a == *b;
slouken@35
   182
}
slouken@35
   183
slouken@11
   184
#define ARRAYSIZE(a) (int)(sizeof(a) / sizeof((a)[0]))
slouken@11
   185
slouken@11
   186
/*
slouken@11
   187
 * convert colour spec to RGB (in 0xrrggbb format).
slouken@35
   188
 * return 1 if successful.
slouken@11
   189
 */
slouken@35
   190
static int color_to_rgb(char *spec, int speclen, Uint32 *rgb)
slouken@7
   191
{
slouken@11
   192
	/* poor man's rgb.txt */
slouken@11
   193
	static struct { char *name; Uint32 rgb; } known[] = {
slouken@11
   194
		{"none",  0xffffffff},
slouken@11
   195
		{"black", 0x00000000},
slouken@11
   196
		{"white", 0x00ffffff},
slouken@11
   197
		{"red",   0x00ff0000},
slouken@11
   198
		{"green", 0x0000ff00},
slouken@11
   199
		{"blue",  0x000000ff}
slouken@11
   200
	};
slouken@7
   201
slouken@11
   202
	if(spec[0] == '#') {
slouken@11
   203
		char buf[7];
slouken@35
   204
		switch(speclen) {
slouken@35
   205
		case 4:
slouken@35
   206
			buf[0] = buf[1] = spec[1];
slouken@35
   207
			buf[2] = buf[3] = spec[2];
slouken@35
   208
			buf[4] = buf[5] = spec[3];
slouken@7
   209
			break;
slouken@35
   210
		case 7:
slouken@35
   211
			memcpy(buf, spec + 1, 6);
slouken@7
   212
			break;
slouken@35
   213
		case 13:
slouken@35
   214
			buf[0] = spec[1];
slouken@35
   215
			buf[1] = spec[2];
slouken@35
   216
			buf[2] = spec[5];
slouken@35
   217
			buf[3] = spec[6];
slouken@35
   218
			buf[4] = spec[9];
slouken@35
   219
			buf[5] = spec[10];
slouken@7
   220
			break;
slouken@11
   221
		}
slouken@11
   222
		buf[6] = '\0';
slouken@11
   223
		*rgb = strtol(buf, NULL, 16);
slouken@11
   224
		return 1;
slouken@11
   225
	} else {
slouken@11
   226
		int i;
slouken@11
   227
		for(i = 0; i < ARRAYSIZE(known); i++)
slouken@35
   228
			if(string_equal(known[i].name, spec, speclen)) {
slouken@11
   229
				*rgb = known[i].rgb;
slouken@11
   230
				return 1;
slouken@11
   231
			}
slouken@11
   232
		return 0;
slouken@7
   233
	}
slouken@7
   234
}
slouken@7
   235
slouken@11
   236
#ifndef MAX
slouken@11
   237
#define MAX(a, b) ((a) > (b) ? (a) : (b))
slouken@11
   238
#endif
slouken@11
   239
slouken@35
   240
static char *linebuf;
slouken@35
   241
static int buflen;
slouken@35
   242
static char *error;
slouken@35
   243
slouken@35
   244
/*
slouken@35
   245
 * Read next line from the source.
slouken@35
   246
 * If len > 0, it's assumed to be at least len chars (for efficiency).
slouken@35
   247
 * Return NULL and set error upon EOF or parse error.
slouken@35
   248
 */
slouken@36
   249
static char *get_next_line(char ***lines, SDL_RWops *src, int len)
slouken@7
   250
{
slouken@288
   251
	char *linebufnew;
slouken@288
   252
slouken@35
   253
	if(lines) {
slouken@35
   254
		return *(*lines)++;
slouken@35
   255
	} else {
slouken@35
   256
		char c;
slouken@35
   257
		int n;
slouken@35
   258
		do {
slouken@35
   259
			if(SDL_RWread(src, &c, 1, 1) <= 0) {
slouken@35
   260
				error = "Premature end of data";
slouken@35
   261
				return NULL;
slouken@35
   262
			}
slouken@35
   263
		} while(c != '"');
slouken@35
   264
		if(len) {
slouken@35
   265
			len += 4;	/* "\",\n\0" */
slouken@35
   266
			if(len > buflen){
slouken@35
   267
				buflen = len;
sezeroz@607
   268
				linebufnew = (char *)realloc(linebuf, buflen);
icculus@275
   269
				if(!linebufnew) {
icculus@275
   270
					free(linebuf);
slouken@35
   271
					error = "Out of memory";
slouken@35
   272
					return NULL;
slouken@35
   273
				}
icculus@275
   274
				linebuf = linebufnew;
slouken@35
   275
			}
slouken@35
   276
			if(SDL_RWread(src, linebuf, len - 1, 1) <= 0) {
slouken@35
   277
				error = "Premature end of data";
slouken@35
   278
				return NULL;
slouken@35
   279
			}
slouken@35
   280
			n = len - 2;
slouken@35
   281
		} else {
slouken@35
   282
			n = 0;
slouken@35
   283
			do {
slouken@35
   284
				if(n >= buflen - 1) {
slouken@35
   285
					if(buflen == 0)
slouken@35
   286
						buflen = 16;
slouken@35
   287
					buflen *= 2;
sezeroz@607
   288
					linebufnew = (char *)realloc(linebuf, buflen);
icculus@275
   289
					if(!linebufnew) {
icculus@275
   290
						free(linebuf);
slouken@35
   291
						error = "Out of memory";
slouken@35
   292
						return NULL;
slouken@35
   293
					}
icculus@275
   294
					linebuf = linebufnew;
slouken@35
   295
				}
slouken@35
   296
				if(SDL_RWread(src, linebuf + n, 1, 1) <= 0) {
slouken@35
   297
					error = "Premature end of data";
slouken@35
   298
					return NULL;
slouken@35
   299
				}
slouken@35
   300
			} while(linebuf[n++] != '"');
slouken@35
   301
			n--;
slouken@35
   302
		}
slouken@35
   303
		linebuf[n] = '\0';
slouken@35
   304
		return linebuf;
slouken@35
   305
	}
slouken@35
   306
}
slouken@35
   307
slouken@35
   308
#define SKIPSPACE(p)				\
slouken@35
   309
do {						\
slouken@35
   310
	while(isspace((unsigned char)*(p)))	\
slouken@35
   311
	      ++(p);				\
slouken@35
   312
} while(0)
slouken@35
   313
slouken@35
   314
#define SKIPNONSPACE(p)					\
slouken@35
   315
do {							\
slouken@35
   316
	while(!isspace((unsigned char)*(p)) && *p)	\
slouken@35
   317
	      ++(p);					\
slouken@35
   318
} while(0)
slouken@35
   319
slouken@35
   320
/* read XPM from either array or RWops */
slouken@35
   321
static SDL_Surface *load_xpm(char **xpm, SDL_RWops *src)
slouken@35
   322
{
slouken@176
   323
	int start = 0;
slouken@35
   324
	SDL_Surface *image = NULL;
slouken@7
   325
	int index;
slouken@11
   326
	int x, y;
slouken@7
   327
	int w, h, ncolors, cpp;
slouken@7
   328
	int indexed;
slouken@7
   329
	Uint8 *dst;
slouken@35
   330
	struct color_hash *colors = NULL;
slouken@11
   331
	SDL_Color *im_colors = NULL;
slouken@35
   332
	char *keystrings = NULL, *nextkey;
slouken@35
   333
	char *line;
slouken@35
   334
	char ***xpmlines = NULL;
slouken@35
   335
	int pixels_len;
slouken@7
   336
slouken@38
   337
	error = NULL;
slouken@38
   338
	linebuf = NULL;
slouken@38
   339
	buflen = 0;
slouken@38
   340
icculus@475
   341
	if ( src ) 
icculus@154
   342
		start = SDL_RWtell(src);
slouken@118
   343
slouken@35
   344
	if(xpm)
slouken@35
   345
		xpmlines = &xpm;
slouken@35
   346
slouken@35
   347
	line = get_next_line(xpmlines, src, 0);
slouken@35
   348
	if(!line)
slouken@35
   349
		goto done;
slouken@11
   350
	/*
slouken@11
   351
	 * The header string of an XPMv3 image has the format
slouken@11
   352
	 *
slouken@11
   353
	 * <width> <height> <ncolors> <cpp> [ <hotspot_x> <hotspot_y> ]
slouken@11
   354
	 *
slouken@11
   355
	 * where the hotspot coords are intended for mouse cursors.
slouken@11
   356
	 * Right now we don't use the hotspots but it should be handled
slouken@11
   357
	 * one day.
slouken@11
   358
	 */
slouken@35
   359
	if(sscanf(line, "%d %d %d %d", &w, &h, &ncolors, &cpp) != 4
slouken@11
   360
	   || w <= 0 || h <= 0 || ncolors <= 0 || cpp <= 0) {
slouken@35
   361
		error = "Invalid format description";
slouken@35
   362
		goto done;
slouken@11
   363
	}
slouken@7
   364
sezeroz@607
   365
	keystrings = (char *)malloc(ncolors * cpp);
slouken@11
   366
	if(!keystrings) {
slouken@35
   367
		error = "Out of memory";
slouken@35
   368
		goto done;
slouken@11
   369
	}
slouken@11
   370
	nextkey = keystrings;
slouken@7
   371
slouken@11
   372
	/* Create the new surface */
slouken@11
   373
	if(ncolors <= 256) {
slouken@11
   374
		indexed = 1;
slouken@11
   375
		image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8,
slouken@11
   376
					     0, 0, 0, 0);
slouken@11
   377
		im_colors = image->format->palette->colors;
slouken@11
   378
		image->format->palette->ncolors = ncolors;
slouken@11
   379
	} else {
slouken@11
   380
		indexed = 0;
slouken@11
   381
		image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
slouken@11
   382
					     0xff0000, 0x00ff00, 0x0000ff, 0);
slouken@11
   383
	}
slouken@11
   384
	if(!image) {
slouken@11
   385
		/* Hmm, some SDL error (out of memory?) */
slouken@35
   386
		goto done;
slouken@11
   387
	}
slouken@7
   388
slouken@7
   389
	/* Read the colors */
slouken@11
   390
	colors = create_colorhash(ncolors);
slouken@35
   391
	if (!colors) {
slouken@11
   392
		error = "Out of memory";
slouken@11
   393
		goto done;
slouken@7
   394
	}
slouken@11
   395
	for(index = 0; index < ncolors; ++index ) {
slouken@35
   396
		char *p;
slouken@35
   397
		line = get_next_line(xpmlines, src, 0);
slouken@35
   398
		if(!line)
slouken@35
   399
			goto done;
slouken@11
   400
slouken@35
   401
		p = line + cpp + 1;
slouken@11
   402
slouken@11
   403
		/* parse a colour definition */
slouken@11
   404
		for(;;) {
slouken@11
   405
			char nametype;
slouken@11
   406
			char *colname;
slouken@35
   407
			Uint32 rgb, pixel;
slouken@11
   408
slouken@35
   409
			SKIPSPACE(p);
slouken@35
   410
			if(!*p) {
slouken@35
   411
				error = "colour parse error";
slouken@11
   412
				goto done;
slouken@7
   413
			}
slouken@35
   414
			nametype = *p;
slouken@35
   415
			SKIPNONSPACE(p);
slouken@35
   416
			SKIPSPACE(p);
slouken@35
   417
			colname = p;
slouken@35
   418
			SKIPNONSPACE(p);
slouken@11
   419
			if(nametype == 's')
slouken@11
   420
				continue;      /* skip symbolic colour names */
slouken@11
   421
slouken@35
   422
			if(!color_to_rgb(colname, p - colname, &rgb))
slouken@11
   423
				continue;
slouken@11
   424
slouken@35
   425
			memcpy(nextkey, line, cpp);
slouken@11
   426
			if(indexed) {
slouken@11
   427
				SDL_Color *c = im_colors + index;
slouken@139
   428
				c->r = (Uint8)(rgb >> 16);
slouken@139
   429
				c->g = (Uint8)(rgb >> 8);
slouken@139
   430
				c->b = (Uint8)(rgb);
slouken@35
   431
				pixel = index;
slouken@11
   432
			} else
slouken@35
   433
				pixel = rgb;
slouken@35
   434
			add_colorhash(colors, nextkey, cpp, pixel);
slouken@11
   435
			nextkey += cpp;
slouken@11
   436
			if(rgb == 0xffffffff)
slouken@35
   437
				SDL_SetColorKey(image, SDL_SRCCOLORKEY, pixel);
slouken@11
   438
			break;
slouken@7
   439
		}
slouken@7
   440
	}
slouken@7
   441
slouken@7
   442
	/* Read the pixels */
slouken@11
   443
	pixels_len = w * cpp;
sezeroz@607
   444
	dst = (Uint8 *)image->pixels;
slouken@35
   445
	for(y = 0; y < h; y++) {
slouken@35
   446
		line = get_next_line(xpmlines, src, pixels_len);
sezeroz@607
   447
		if (!line)
sezeroz@607
   448
			goto done;
slouken@11
   449
		if(indexed) {
slouken@11
   450
			/* optimization for some common cases */
slouken@11
   451
			if(cpp == 1)
slouken@11
   452
				for(x = 0; x < w; x++)
slouken@139
   453
					dst[x] = (Uint8)QUICK_COLORHASH(colors,
slouken@35
   454
								 line + x);
slouken@11
   455
			else
slouken@11
   456
				for(x = 0; x < w; x++)
slouken@139
   457
					dst[x] = (Uint8)get_colorhash(colors,
slouken@35
   458
							       line + x * cpp,
slouken@11
   459
							       cpp);
slouken@11
   460
		} else {
slouken@11
   461
			for (x = 0; x < w; x++)
slouken@11
   462
				((Uint32*)dst)[x] = get_colorhash(colors,
slouken@35
   463
								line + x * cpp,
slouken@11
   464
								  cpp);
slouken@7
   465
		}
slouken@11
   466
		dst += image->pitch;
slouken@7
   467
	}
slouken@11
   468
slouken@11
   469
done:
slouken@11
   470
	if(error) {
icculus@154
   471
		if ( src )
slouken@236
   472
			SDL_RWseek(src, start, RW_SEEK_SET);
slouken@118
   473
		if ( image ) {
slouken@118
   474
			SDL_FreeSurface(image);
slouken@118
   475
			image = NULL;
slouken@118
   476
		}
slouken@11
   477
		IMG_SetError(error);
slouken@7
   478
	}
slouken@11
   479
	free(keystrings);
slouken@7
   480
	free_colorhash(colors);
slouken@35
   481
	free(linebuf);
slouken@7
   482
	return(image);
slouken@7
   483
}
slouken@7
   484
slouken@35
   485
/* Load a XPM type image from an RWops datasource */
slouken@35
   486
SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src)
slouken@35
   487
{
slouken@98
   488
	if ( !src ) {
slouken@98
   489
		/* The error message has been set in SDL_RWFromFile */
slouken@98
   490
		return NULL;
slouken@98
   491
	}
slouken@35
   492
	return load_xpm(NULL, src);
slouken@35
   493
}
slouken@35
   494
slouken@35
   495
SDL_Surface *IMG_ReadXPMFromArray(char **xpm)
slouken@35
   496
{
sezeroz@607
   497
	if ( !xpm ) {
sezeroz@607
   498
		IMG_SetError("array is NULL");
sezeroz@607
   499
		return NULL;
sezeroz@607
   500
	}
slouken@35
   501
	return load_xpm(xpm, NULL);
slouken@35
   502
}
slouken@35
   503
slouken@35
   504
#else  /* not LOAD_XPM */
slouken@7
   505
slouken@7
   506
/* See if an image is contained in a data source */
slouken@7
   507
int IMG_isXPM(SDL_RWops *src)
slouken@7
   508
{
slouken@7
   509
	return(0);
slouken@7
   510
}
slouken@7
   511
slouken@35
   512
slouken@7
   513
/* Load a XPM type image from an SDL datasource */
slouken@7
   514
SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src)
slouken@7
   515
{
slouken@7
   516
	return(NULL);
slouken@7
   517
}
slouken@7
   518
slouken@35
   519
SDL_Surface *IMG_ReadXPMFromArray(char **xpm)
slouken@35
   520
{
slouken@35
   521
    return NULL;
slouken@35
   522
}
slouken@35
   523
#endif /* not LOAD_XPM */