Mattias Engdeg�rd - Wed Dec 6 10:00:07 PST 2000
authorSam Lantinga <slouken@lokigames.com>
Wed, 06 Dec 2000 18:00:38 +0000
changeset 11b3d1b573a542
parent 10 d61ec057aee0
child 12 94f2a42b2df8
Mattias Engdeg�rd - Wed Dec 6 10:00:07 PST 2000
* Improved the XPM loading code
CHANGES
IMG.c
IMG_xpm.c
SDL_image.h
     1.1 --- a/CHANGES	Thu Nov 30 04:04:21 2000 +0000
     1.2 +++ b/CHANGES	Wed Dec 06 18:00:38 2000 +0000
     1.3 @@ -1,3 +1,7 @@
     1.4 +
     1.5 +1.1.1:
     1.6 +Mattias Engdegrd - Wed Dec  6 10:00:07 PST 2000
     1.7 + * Improved the XPM loading code
     1.8  
     1.9  1.1.0:
    1.10  Sam Lantinga - Wed Nov 29 00:46:27 PST 2000
     2.1 --- a/IMG.c	Thu Nov 30 04:04:21 2000 +0000
     2.2 +++ b/IMG.c	Wed Dec 06 18:00:38 2000 +0000
     2.3 @@ -67,7 +67,7 @@
     2.4  }
     2.5  
     2.6  /* Portable case-insensitive string compare function */
     2.7 -static int string_equals(const char *str1, const char *str2)
     2.8 +int IMG_string_equals(const char *str1, const char *str2)
     2.9  {
    2.10  	while ( *str1 && *str2 ) {
    2.11  		if ( toupper((unsigned char)*str1) !=
    2.12 @@ -99,11 +99,11 @@
    2.13  	/* Detect the type of image being loaded */
    2.14  	start = SDL_RWtell(src);
    2.15  	image = NULL;
    2.16 -	for ( i=0; i < ARRAYSIZE(supported) && !image; ++i ) {
    2.17 +	for ( i=0; i < ARRAYSIZE(supported); ++i ) {
    2.18  	        if( (supported[i].is
    2.19  		     && (SDL_RWseek(src, start, SEEK_SET),
    2.20  			 supported[i].is(src)))
    2.21 -		    || (type && string_equals(type, supported[i].type))) {
    2.22 +		    || (type && IMG_string_equals(type, supported[i].type))) {
    2.23  #ifdef DEBUG_IMGLIB
    2.24  			fprintf(stderr, "IMGLIB: Loading image as %s\n",
    2.25  							supported[i].type);
    2.26 @@ -118,7 +118,7 @@
    2.27  	if ( freesrc ) {
    2.28  		SDL_RWclose(src);
    2.29  	}
    2.30 -	if ( image == NULL ) {
    2.31 +	if ( i == ARRAYSIZE(supported) ) {
    2.32  		IMG_SetError("Unsupported image format");
    2.33  	}
    2.34  	return(image);
     3.1 --- a/IMG_xpm.c	Thu Nov 30 04:04:21 2000 +0000
     3.2 +++ b/IMG_xpm.c	Wed Dec 06 18:00:38 2000 +0000
     3.3 @@ -41,41 +41,13 @@
     3.4  
     3.5  	is_XPM = 0;
     3.6  	if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
     3.7 -		if ( strncmp(magic, "/* XPM */", 9) == 0 ) {
     3.8 +		if(memcmp(magic, "/* XPM */", 9) == 0) {
     3.9  			is_XPM = 1;
    3.10  		}
    3.11  	}
    3.12  	return(is_XPM);
    3.13  }
    3.14  
    3.15 -static char *my_strdup(const char *string)
    3.16 -{
    3.17 -	char *newstring;
    3.18 -
    3.19 -	newstring = (char *)malloc(strlen(string)+1);
    3.20 -	if ( newstring ) {
    3.21 -		strcpy(newstring, string);
    3.22 -	}
    3.23 -	return(newstring);
    3.24 -}
    3.25 -
    3.26 -/* Not exactly the same semantics as strncasecmp(), but portable */
    3.27 -static int my_strncasecmp(const char *str1, const char *str2, int len)
    3.28 -{
    3.29 -	if ( len == 0 ) {
    3.30 -		len = strlen(str2);
    3.31 -		if ( len != strlen(str1) ) {
    3.32 -			return(-1);
    3.33 -		}
    3.34 -	}
    3.35 -	while ( len-- > 0 ) {
    3.36 -		if ( tolower(*str1++) != tolower(*str2++) ) {
    3.37 -			return(-1);
    3.38 -		}
    3.39 -	}
    3.40 -	return(0);
    3.41 -}
    3.42 -
    3.43  static char *SDL_RWgets(char *string, int maxlen, SDL_RWops *src)
    3.44  {
    3.45  	int i;
    3.46 @@ -85,7 +57,7 @@
    3.47  			/* EOF or error */
    3.48  			if ( i == 0 ) {
    3.49  				/* Hmm, EOF on initial read, return NULL */
    3.50 -				string = NULL;
    3.51 +				return NULL;
    3.52  			}
    3.53  			break;
    3.54  		}
    3.55 @@ -93,392 +65,383 @@
    3.56  		   as line separators because blank lines are just
    3.57  		   ignored by the XPM format.
    3.58  		*/
    3.59 -		if ( (string[i] == '\r') || (string[i] == '\n') ) {
    3.60 +		if ( (string[i] == '\n') || (string[i] == '\r') ) {
    3.61  			break;
    3.62  		}
    3.63  	}
    3.64 -	if ( string ) {
    3.65 -		string[i] = '\0';
    3.66 -	}
    3.67 +	string[i] = '\0';
    3.68  	return(string);
    3.69  }
    3.70  
    3.71  /* Hash table to look up colors from pixel strings */
    3.72 -#define HASH_SIZE	256
    3.73 -struct color_hash {
    3.74 -	struct hash_entry {
    3.75 -		int keylen;
    3.76 -		char *key;
    3.77 -		Uint32 color;
    3.78 -		struct hash_entry *next;
    3.79 -	} *entries[HASH_SIZE];
    3.80 +#define STARTING_HASH_SIZE 256
    3.81 +
    3.82 +struct hash_entry {
    3.83 +	char *key;
    3.84 +	Uint32 color;
    3.85 +	struct hash_entry *next;
    3.86  };
    3.87  
    3.88 -static int hash_key(const char *key, int cpp)
    3.89 +struct color_hash {
    3.90 +	struct hash_entry **table;
    3.91 +	struct hash_entry *entries; /* array of all entries */
    3.92 +	struct hash_entry *next_free;
    3.93 +	int size;
    3.94 +	int maxnum;
    3.95 +};
    3.96 +
    3.97 +static int hash_key(const char *key, int cpp, int size)
    3.98  {
    3.99  	int hash;
   3.100  
   3.101  	hash = 0;
   3.102  	while ( cpp-- > 0 ) {
   3.103 -		hash += *key++;
   3.104 +		hash = hash * 33 + *key++;
   3.105  	}
   3.106 -	return(hash%HASH_SIZE);
   3.107 +	return hash & (size - 1);
   3.108  }
   3.109  
   3.110 -static struct color_hash *create_colorhash(void)
   3.111 +static struct color_hash *create_colorhash(int maxnum)
   3.112  {
   3.113 +	int bytes, s;
   3.114  	struct color_hash *hash;
   3.115  
   3.116 -	hash = (struct color_hash *)malloc(sizeof *hash);
   3.117 -	if ( hash ) {
   3.118 -		memset(hash, 0, (sizeof *hash));
   3.119 -	}
   3.120 -	return(hash);
   3.121 +	/* we know how many entries we need, so we can allocate
   3.122 +	   everything here */
   3.123 +	hash = malloc(sizeof *hash);
   3.124 +	if(!hash)
   3.125 +		return NULL;
   3.126 +
   3.127 +	/* use power-of-2 sized hash table for decoding speed */
   3.128 +	for(s = STARTING_HASH_SIZE; s < maxnum; s <<= 1)
   3.129 +		;
   3.130 +	hash->size = s;
   3.131 +	hash->maxnum = maxnum;
   3.132 +	bytes = hash->size * sizeof(struct hash_entry **);
   3.133 +	hash->entries = NULL;	/* in case malloc fails */
   3.134 +	hash->table = malloc(bytes);
   3.135 +	if(!hash->table)
   3.136 +		return NULL;
   3.137 +	memset(hash->table, 0, bytes);
   3.138 +	hash->entries = malloc(maxnum * sizeof(struct hash_entry));
   3.139 +	if(!hash->entries)
   3.140 +		return NULL;
   3.141 +	hash->next_free = hash->entries;
   3.142 +	return hash;
   3.143  }
   3.144  
   3.145  static int add_colorhash(struct color_hash *hash,
   3.146 -                         const char *key, int cpp, Uint32 color)
   3.147 +                         char *key, int cpp, Uint32 color)
   3.148  {
   3.149 -	int hash_index;
   3.150 -	struct hash_entry *prev, *entry;
   3.151 -
   3.152 -	/* Create the hash entry */
   3.153 -	entry = (struct hash_entry *)malloc(sizeof *entry);
   3.154 -	if ( ! entry ) {
   3.155 -		return(0);
   3.156 -	}
   3.157 -	entry->keylen = cpp;
   3.158 -	entry->key = my_strdup(key);
   3.159 -	if ( ! entry->key ) {
   3.160 -		free(entry);
   3.161 -		return(0);
   3.162 -	}
   3.163 -	entry->color = color;
   3.164 -	entry->next = NULL;
   3.165 -
   3.166 -	/* Add it to the hash table */
   3.167 -	hash_index = hash_key(key, cpp);
   3.168 -	for ( prev = hash->entries[hash_index];
   3.169 -	      prev && prev->next; prev = prev->next ) {
   3.170 -		/* Go to the end of the list */ ;
   3.171 -	}
   3.172 -	if ( prev ) {
   3.173 -		prev->next = entry;
   3.174 -	} else {
   3.175 -		hash->entries[hash_index] = entry;
   3.176 -	}
   3.177 -	return(1);
   3.178 +	int index = hash_key(key, cpp, hash->size);
   3.179 +	struct hash_entry *e = hash->next_free++;
   3.180 +	e->color = color;
   3.181 +	e->key = key;
   3.182 +	e->next = hash->table[index];
   3.183 +	hash->table[index] = e;
   3.184 +	return 1;
   3.185  }
   3.186  
   3.187 -static int get_colorhash(struct color_hash *hash,
   3.188 -                         const char *key, int cpp, Uint32 *color)
   3.189 +/* fast lookup that works if cpp == 1 */
   3.190 +#define QUICK_COLORHASH(hash, key) ((hash)->table[*(key)]->color)
   3.191 +
   3.192 +static Uint32 get_colorhash(struct color_hash *hash, const char *key, int cpp)
   3.193  {
   3.194 -	int hash_index;
   3.195 -	struct hash_entry *entry;
   3.196 -
   3.197 -	hash_index = hash_key(key, cpp);
   3.198 -	for ( entry = hash->entries[hash_index]; entry; entry = entry->next ) {
   3.199 -		if ( strncmp(key, entry->key, entry->keylen) == 0 ) {
   3.200 -			*color = entry->color;
   3.201 -			return(1);
   3.202 -		}
   3.203 +	struct hash_entry *entry = hash->table[hash_key(key, cpp, hash->size)];
   3.204 +	while(entry) {
   3.205 +		if(memcmp(key, entry->key, cpp) == 0)
   3.206 +			return entry->color;
   3.207 +		entry = entry->next;
   3.208  	}
   3.209 -	return(0);
   3.210 +	return 0;		/* garbage in - garbage out */
   3.211  }
   3.212  
   3.213  static void free_colorhash(struct color_hash *hash)
   3.214  {
   3.215 -	int i;
   3.216 -	struct hash_entry *entry, *freeable;
   3.217 -
   3.218 -	for ( i=0; i<HASH_SIZE; ++i ) {
   3.219 -		entry = hash->entries[i];
   3.220 -		while ( entry ) {
   3.221 -			freeable = entry;
   3.222 -			entry = entry->next;
   3.223 -			free(freeable->key);
   3.224 -			free(freeable);
   3.225 -		}
   3.226 +	if(hash && hash->table) {
   3.227 +		free(hash->table);
   3.228 +		free(hash->entries);
   3.229 +		free(hash);
   3.230  	}
   3.231 -	free(hash);
   3.232  }
   3.233  
   3.234 -static int color_to_rgb(const char *colorspec, int *r, int *g, int *b)
   3.235 +#define ARRAYSIZE(a) (int)(sizeof(a) / sizeof((a)[0]))
   3.236 +
   3.237 +/*
   3.238 + * convert colour spec to RGB (in 0xrrggbb format).
   3.239 + * return 1 if successful. may scribble on the colorspec buffer.
   3.240 + */
   3.241 +static int color_to_rgb(char *spec, Uint32 *rgb)
   3.242  {
   3.243 -	char rbuf[3];
   3.244 -	char gbuf[3];
   3.245 -	char bbuf[3];
   3.246 +	/* poor man's rgb.txt */
   3.247 +	static struct { char *name; Uint32 rgb; } known[] = {
   3.248 +		{"none",  0xffffffff},
   3.249 +		{"black", 0x00000000},
   3.250 +		{"white", 0x00ffffff},
   3.251 +		{"red",   0x00ff0000},
   3.252 +		{"green", 0x0000ff00},
   3.253 +		{"blue",  0x000000ff}
   3.254 +	};
   3.255  
   3.256 -	/* Handle monochrome black and white */
   3.257 -	if ( my_strncasecmp(colorspec, "black", 0) == 0 ) {
   3.258 -		*r = 0;
   3.259 -		*g = 0;
   3.260 -		*b = 0;
   3.261 -		return(1);
   3.262 -	}
   3.263 -	if ( my_strncasecmp(colorspec, "white", 0) == 0 ) {
   3.264 -		*r = 255;
   3.265 -		*g = 255;
   3.266 -		*b = 255;
   3.267 -		return(1);
   3.268 -	}
   3.269 -
   3.270 -	/* Normal hexidecimal color */
   3.271 -	switch (strlen(colorspec)) {
   3.272 +	if(spec[0] == '#') {
   3.273 +		char buf[7];
   3.274 +		++spec;
   3.275 +		switch(strlen(spec)) {
   3.276  		case 3:
   3.277 -			rbuf[0] = colorspec[0];
   3.278 -			rbuf[1] = colorspec[0];
   3.279 -			gbuf[0] = colorspec[1];
   3.280 -			gbuf[1] = colorspec[1];
   3.281 -			bbuf[0] = colorspec[2];
   3.282 -			bbuf[1] = colorspec[2];
   3.283 +			buf[0] = buf[1] = spec[0];
   3.284 +			buf[2] = buf[3] = spec[1];
   3.285 +			buf[4] = buf[5] = spec[2];
   3.286  			break;
   3.287  		case 6:
   3.288 -			rbuf[0] = colorspec[0];
   3.289 -			rbuf[1] = colorspec[1];
   3.290 -			gbuf[0] = colorspec[2];
   3.291 -			gbuf[1] = colorspec[3];
   3.292 -			bbuf[0] = colorspec[4];
   3.293 -			bbuf[1] = colorspec[5];
   3.294 +			memcpy(buf, spec, 6);
   3.295  			break;
   3.296  		case 12:
   3.297 -			rbuf[0] = colorspec[0];
   3.298 -			rbuf[1] = colorspec[1];
   3.299 -			gbuf[0] = colorspec[4];
   3.300 -			gbuf[1] = colorspec[5];
   3.301 -			bbuf[0] = colorspec[8];
   3.302 -			bbuf[1] = colorspec[9];
   3.303 +			buf[0] = spec[0];
   3.304 +			buf[1] = spec[1];
   3.305 +			buf[2] = spec[4];
   3.306 +			buf[3] = spec[5];
   3.307 +			buf[4] = spec[8];
   3.308 +			buf[5] = spec[9];
   3.309  			break;
   3.310 -		default:
   3.311 -			return(0);
   3.312 +		}
   3.313 +		buf[6] = '\0';
   3.314 +		*rgb = strtol(buf, NULL, 16);
   3.315 +		return 1;
   3.316 +	} else {
   3.317 +		int i;
   3.318 +		for(i = 0; i < ARRAYSIZE(known); i++)
   3.319 +			if(IMG_string_equals(known[i].name, spec)) {
   3.320 +				*rgb = known[i].rgb;
   3.321 +				return 1;
   3.322 +			}
   3.323 +		return 0;
   3.324  	}
   3.325 -	rbuf[2] = '\0';
   3.326 -	*r = (int)strtol(rbuf, NULL, 16);
   3.327 -	gbuf[2] = '\0';
   3.328 -	*g = (int)strtol(gbuf, NULL, 16);
   3.329 -	bbuf[2] = '\0';
   3.330 -	*b = (int)strtol(bbuf, NULL, 16);
   3.331 -	return(1);
   3.332  }
   3.333  
   3.334 +static char *skipspace(char *p)
   3.335 +{
   3.336 +	while(isspace((unsigned char)*p))
   3.337 +	      ++p;
   3.338 +	return p;
   3.339 +}
   3.340 +
   3.341 +static char *skipnonspace(char *p)
   3.342 +{
   3.343 +	while(!isspace((unsigned char)*p) && *p)
   3.344 +		++p;
   3.345 +	return p;
   3.346 +}
   3.347 +
   3.348 +#ifndef MAX
   3.349 +#define MAX(a, b) ((a) > (b) ? (a) : (b))
   3.350 +#endif
   3.351 +
   3.352  /* Load a XPM type image from an SDL datasource */
   3.353  SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src)
   3.354  {
   3.355  	SDL_Surface *image;
   3.356  	char line[1024];
   3.357 -	char *here, *stop;
   3.358 +	char *here;
   3.359  	int index;
   3.360 -	int i, x, y;
   3.361 +	int x, y;
   3.362  	int w, h, ncolors, cpp;
   3.363 -	int found;
   3.364 -	int r, g, b;
   3.365 -	Uint32 colorkey;
   3.366 -	char *colorkey_string;
   3.367  	int pixels_len;
   3.368 -	char *pixels;
   3.369 +	char *pixels = NULL;
   3.370  	int indexed;
   3.371  	Uint8 *dst;
   3.372 -	Uint32 pixel;
   3.373  	struct color_hash *colors;
   3.374 +	SDL_Color *im_colors = NULL;
   3.375 +	char *keystrings, *nextkey;
   3.376 +	char *error = NULL;
   3.377  
   3.378  	/* Skip to the first string, which describes the image */
   3.379 -	image = NULL;
   3.380  	do {
   3.381 -		here = SDL_RWgets(line, sizeof(line), src);
   3.382 -		if ( ! here ) {
   3.383 +	        here = SDL_RWgets(line, sizeof(line), src);
   3.384 +		if ( !here ) {
   3.385  			IMG_SetError("Premature end of data");
   3.386  			return(NULL);
   3.387  		}
   3.388 -		if ( *here == '"' ) {
   3.389 -			++here;
   3.390 -			/* Skip to width */
   3.391 -			while ( isspace(*here) ) ++here;
   3.392 -			w = atoi(here);
   3.393 -			while ( ! isspace(*here) ) ++here;
   3.394 -			/* Skip to height */
   3.395 -			while ( isspace(*here) ) ++here;
   3.396 -			h = atoi(here);
   3.397 -			while ( ! isspace(*here) ) ++here;
   3.398 -			/* Skip to number of colors */
   3.399 -			while ( isspace(*here) ) ++here;
   3.400 -			ncolors = atoi(here);
   3.401 -			while ( ! isspace(*here) ) ++here;
   3.402 -			/* Skip to characters per pixel */
   3.403 -			while ( isspace(*here) ) ++here;
   3.404 -			cpp = atoi(here);
   3.405 -			while ( ! isspace(*here) ) ++here;
   3.406 +		here = skipspace(here);
   3.407 +	} while(*here != '"');
   3.408 +	/*
   3.409 +	 * The header string of an XPMv3 image has the format
   3.410 +	 *
   3.411 +	 * <width> <height> <ncolors> <cpp> [ <hotspot_x> <hotspot_y> ]
   3.412 +	 *
   3.413 +	 * where the hotspot coords are intended for mouse cursors.
   3.414 +	 * Right now we don't use the hotspots but it should be handled
   3.415 +	 * one day.
   3.416 +	 */
   3.417 +	if(sscanf(here + 1, "%d %d %d %d", &w, &h, &ncolors, &cpp) != 4
   3.418 +	   || w <= 0 || h <= 0 || ncolors <= 0 || cpp <= 0) {
   3.419 +		IMG_SetError("Invalid format description");
   3.420 +		return(NULL);
   3.421 +	}
   3.422  
   3.423 -			/* Verify the parameters */
   3.424 -			if ( !w || !h || !ncolors || !cpp ) {
   3.425 -				IMG_SetError("Invalid format description");
   3.426 -				return(NULL);
   3.427 -			}
   3.428 -			pixels_len = 1+w*cpp+1+1;
   3.429 -			pixels = (char *)malloc(pixels_len);
   3.430 -			if ( ! pixels ) {
   3.431 -				IMG_SetError("Out of memory");
   3.432 -				return(NULL);
   3.433 -			}
   3.434 +	keystrings = malloc(ncolors * cpp);
   3.435 +	if(!keystrings) {
   3.436 +		IMG_SetError("Out of memory");
   3.437 +		free(pixels);
   3.438 +		return NULL;
   3.439 +	}
   3.440 +	nextkey = keystrings;
   3.441  
   3.442 -			/* Create the new surface */
   3.443 -			if ( ncolors <= 256 ) {
   3.444 -				indexed = 1;
   3.445 -				image = SDL_CreateRGBSurface(SDL_SWSURFACE,
   3.446 -							w, h, 8, 0, 0, 0, 0);
   3.447 -			} else {
   3.448 -				int rmask, gmask, bmask;
   3.449 -				indexed = 0;
   3.450 -				if ( SDL_BYTEORDER == SDL_BIG_ENDIAN ) {
   3.451 -					rmask = 0x000000ff;
   3.452 -					gmask = 0x0000ff00;
   3.453 -					bmask = 0x00ff0000;
   3.454 -				} else {
   3.455 -					rmask = 0x00ff0000;
   3.456 -					gmask = 0x0000ff00;
   3.457 -					bmask = 0x000000ff;
   3.458 -				}
   3.459 -				image = SDL_CreateRGBSurface(SDL_SWSURFACE,
   3.460 -							w, h, 32,
   3.461 -							rmask, gmask, bmask, 0);
   3.462 -			}
   3.463 -			if ( ! image ) {
   3.464 -				/* Hmm, some SDL error (out of memory?) */
   3.465 -				free(pixels);
   3.466 -				return(NULL);
   3.467 -			}
   3.468 -		}
   3.469 -	} while ( ! image );
   3.470 +	/* Create the new surface */
   3.471 +	if(ncolors <= 256) {
   3.472 +		indexed = 1;
   3.473 +		image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8,
   3.474 +					     0, 0, 0, 0);
   3.475 +		im_colors = image->format->palette->colors;
   3.476 +		image->format->palette->ncolors = ncolors;
   3.477 +	} else {
   3.478 +		indexed = 0;
   3.479 +		image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
   3.480 +					     0xff0000, 0x00ff00, 0x0000ff, 0);
   3.481 +	}
   3.482 +	if(!image) {
   3.483 +		/* Hmm, some SDL error (out of memory?) */
   3.484 +		free(pixels);
   3.485 +		return(NULL);
   3.486 +	}
   3.487  
   3.488  	/* Read the colors */
   3.489 -	colors = create_colorhash();
   3.490 +	colors = create_colorhash(ncolors);
   3.491  	if ( ! colors ) {
   3.492 -		SDL_FreeSurface(image);
   3.493 -		free(pixels);
   3.494 -		IMG_SetError("Out of memory");
   3.495 -		return(NULL);
   3.496 +		error = "Out of memory";
   3.497 +		goto done;
   3.498  	}
   3.499 -	colorkey_string = NULL;
   3.500 -	for ( index=0; index < ncolors; ++index ) {
   3.501 -		here = SDL_RWgets(line, sizeof(line), src);
   3.502 -		if ( ! here ) {
   3.503 -			SDL_FreeSurface(image);
   3.504 -			image = NULL;
   3.505 -			IMG_SetError("Premature end of data");
   3.506 -			goto done;
   3.507 -		}
   3.508 -		if ( *here == '"' ) {
   3.509 -			const char *key;
   3.510 -			++here;
   3.511 -			/* Grab the pixel key */
   3.512 -			key = here;
   3.513 -			for ( i=0; i<cpp; ++i ) {
   3.514 -				if ( ! *here++ ) {
   3.515 -					/* Parse error */
   3.516 -					continue;
   3.517 -				}
   3.518 +	for(index = 0; index < ncolors; ++index ) {
   3.519 +		char *key;
   3.520 +		int len;
   3.521 +
   3.522 +		do {
   3.523 +			here = SDL_RWgets(line, sizeof(line), src);
   3.524 +			if(!here) {
   3.525 +				error = "Premature end of data";
   3.526 +				goto done;
   3.527  			}
   3.528 -			if ( *here ) {
   3.529 -				*here++ = '\0';
   3.530 +			here = skipspace(here);
   3.531 +		} while(*here != '"');
   3.532 +
   3.533 +		++here;
   3.534 +		len = strlen(here);
   3.535 +		if(len < cpp + 7)
   3.536 +			continue;	/* cannot be a valid line */
   3.537 +
   3.538 +		key = here;
   3.539 +		key[cpp] = '\0';
   3.540 +		here += cpp + 1;
   3.541 +
   3.542 +		/* parse a colour definition */
   3.543 +		for(;;) {
   3.544 +			char nametype;
   3.545 +			char *colname;
   3.546 +			char delim;
   3.547 +			Uint32 rgb;
   3.548 +
   3.549 +			here = skipspace(here);
   3.550 +			nametype = *here;
   3.551 +			here = skipnonspace(here);
   3.552 +			here = skipspace(here);
   3.553 +			colname = here;
   3.554 +			while(*here && !isspace((unsigned char)*here)
   3.555 +			      && *here != '"')
   3.556 +				here++;
   3.557 +			if(!*here) {
   3.558 +				error = "color parse error";
   3.559 +				goto done;
   3.560  			}
   3.561 -			/* Find the color identifier */
   3.562 -			found = 0;
   3.563 -			while ( *here && ! found ) {
   3.564 -				while ( isspace(*here) ) ++here;
   3.565 -				if ( (*here != 'c') &&
   3.566 -				     (*here != 'g') &&
   3.567 -				     (*here != 'm') ) {
   3.568 -					/* Skip color type */
   3.569 -					while ( *here && !isspace(*here) )
   3.570 -						++here;
   3.571 -					/* Skip color name */
   3.572 -					while ( isspace(*here) ) ++here;
   3.573 -					while ( *here && !isspace(*here) )
   3.574 -						++here;
   3.575 -					continue;
   3.576 -				}
   3.577 -				++here;
   3.578 -				while ( isspace(*here) ) ++here;
   3.579 -				if ( my_strncasecmp(here, "None", 4) == 0 ) {
   3.580 -					colorkey_string = my_strdup(key);
   3.581 -					if ( indexed ) {
   3.582 -						colorkey = (Uint32)index;
   3.583 -					} else {
   3.584 -						colorkey = 0xFFFFFFFF;
   3.585 -					}
   3.586 -					found = 1;
   3.587 -					continue;
   3.588 -				}
   3.589 -				if ( *here == '#' ) {
   3.590 -					++here;
   3.591 -				}
   3.592 -				while ( isspace(*here) ) ++here;
   3.593 -				for ( stop=here; isalnum(*stop); ++stop ) {
   3.594 -					/* Skip the pixel color */;
   3.595 -				}
   3.596 -				*stop++ = '\0';
   3.597 -				found = color_to_rgb(here, &r, &g, &b);
   3.598 -				if ( found ) {
   3.599 -					if ( indexed ) {
   3.600 -						SDL_Color *color;
   3.601 -						color = &image->format->palette->colors[index];
   3.602 -						color->r = (Uint8)r;
   3.603 -						color->g = (Uint8)g;
   3.604 -						color->b = (Uint8)b;
   3.605 -						pixel = index;
   3.606 -					} else {
   3.607 -						pixel = (r<<16)|(g<<8)|b;
   3.608 -					}
   3.609 -					add_colorhash(colors, key, cpp, pixel);
   3.610 -				}
   3.611 -				*here = '\0';
   3.612 -			}
   3.613 -			if ( ! found ) {
   3.614 -				/* Hum, couldn't parse a color.. */;
   3.615 -			}
   3.616 +			if(nametype == 's')
   3.617 +				continue;      /* skip symbolic colour names */
   3.618 +
   3.619 +			delim = *here;
   3.620 +			*here = '\0';
   3.621 +			if(delim)
   3.622 +			    here++;
   3.623 +
   3.624 +			if(!color_to_rgb(colname, &rgb))
   3.625 +				continue;
   3.626 +
   3.627 +			memcpy(nextkey, key, cpp);
   3.628 +			if(indexed) {
   3.629 +				SDL_Color *c = im_colors + index;
   3.630 +				c->r = rgb >> 16;
   3.631 +				c->g = rgb >> 8;
   3.632 +				c->b = rgb;
   3.633 +				add_colorhash(colors, nextkey, cpp, index);
   3.634 +			} else
   3.635 +				add_colorhash(colors, nextkey, cpp, rgb);
   3.636 +			nextkey += cpp;
   3.637 +			if(rgb == 0xffffffff)
   3.638 +				SDL_SetColorKey(image, SDL_SRCCOLORKEY,
   3.639 +						indexed ? index : rgb);
   3.640 +			break;
   3.641  		}
   3.642  	}
   3.643  
   3.644  	/* Read the pixels */
   3.645 -	for ( y=0; y < h; ) {
   3.646 -		here = SDL_RWgets(pixels, pixels_len, src);
   3.647 -		if ( ! here ) {
   3.648 -			SDL_FreeSurface(image);
   3.649 -			image = NULL;
   3.650 -			IMG_SetError("Premature end of data");
   3.651 +	pixels_len = w * cpp;
   3.652 +	pixels = malloc(MAX(pixels_len + 5, 20));
   3.653 +	if(!pixels) {
   3.654 +		error = "Out of memory";
   3.655 +		goto done;
   3.656 +	}
   3.657 +	dst = image->pixels;
   3.658 +	for (y = 0; y < h; ) {
   3.659 +		Uint8 *s;
   3.660 +		char c;
   3.661 +		do {
   3.662 +			if(SDL_RWread(src, &c, 1, 1) <= 0) {
   3.663 +				error = "Premature end of data";
   3.664 +				goto done;
   3.665 +			}
   3.666 +		} while(c == ' ');
   3.667 +		if(c != '"') {
   3.668 +			/* comment or empty line, skip it */
   3.669 +			while(c != '\n' && c != '\r') {
   3.670 +				if(SDL_RWread(src, &c, 1, 1) <= 0) {
   3.671 +					error = "Premature end of data";
   3.672 +					goto done;
   3.673 +				}
   3.674 +			}
   3.675 +			continue;
   3.676 +		}
   3.677 +		if(SDL_RWread(src, pixels, pixels_len + 3, 1) <= 0) {
   3.678 +			error = "Premature end of data";
   3.679  			goto done;
   3.680  		}
   3.681 -		if ( *here == '"' ) {
   3.682 -			++here;
   3.683 -			dst = (Uint8 *)image->pixels + y*image->pitch;
   3.684 -			for ( x=0; x<w; ++x ) {
   3.685 -				pixel = 0;
   3.686 -				if ( colorkey_string &&
   3.687 -				     (strncmp(here,colorkey_string,cpp)==0) ) {
   3.688 -					pixel = colorkey;
   3.689 -				} else {
   3.690 -					get_colorhash(colors, here,cpp, &pixel);
   3.691 -				}
   3.692 -				if ( indexed ) {
   3.693 -					*dst++ = pixel;
   3.694 -				} else {
   3.695 -					*((Uint32 *)dst)++ = pixel;
   3.696 -				}
   3.697 -				for ( i=0; *here && i<cpp; ++i ) {
   3.698 -					++here;
   3.699 -				}
   3.700 -			}
   3.701 -			++y;
   3.702 +		s = pixels;
   3.703 +		if(indexed) {
   3.704 +			/* optimization for some common cases */
   3.705 +			if(cpp == 1)
   3.706 +				for(x = 0; x < w; x++)
   3.707 +					dst[x] = QUICK_COLORHASH(colors,
   3.708 +								 s + x);
   3.709 +			else
   3.710 +				for(x = 0; x < w; x++)
   3.711 +					dst[x] = get_colorhash(colors,
   3.712 +							       s + x * cpp,
   3.713 +							       cpp);
   3.714 +		} else {
   3.715 +			for (x = 0; x < w; x++)
   3.716 +				((Uint32*)dst)[x] = get_colorhash(colors,
   3.717 +								  s + x * cpp,
   3.718 +								  cpp);
   3.719  		}
   3.720 +		dst += image->pitch;
   3.721 +		y++;
   3.722  	}
   3.723 -	if ( colorkey_string ) {
   3.724 -        	SDL_SetColorKey(image, SDL_SRCCOLORKEY, colorkey);
   3.725 +
   3.726 +done:
   3.727 +	if(error) {
   3.728 +		if(image)
   3.729 +			SDL_FreeSurface(image);
   3.730 +		image = NULL;
   3.731 +		IMG_SetError(error);
   3.732  	}
   3.733 -done:
   3.734  	free(pixels);
   3.735 +	free(keystrings);
   3.736  	free_colorhash(colors);
   3.737 -	if ( colorkey_string ) {
   3.738 -		free(colorkey_string);
   3.739 -	}
   3.740  	return(image);
   3.741  }
   3.742  
     4.1 --- a/SDL_image.h	Thu Nov 30 04:04:21 2000 +0000
     4.2 +++ b/SDL_image.h	Wed Dec 06 18:00:38 2000 +0000
     4.3 @@ -79,6 +79,9 @@
     4.4  #define IMG_SetError	SDL_SetError
     4.5  #define IMG_GetError	SDL_GetError
     4.6  
     4.7 +/* used internally, NOT an exported function */
     4.8 +extern DECLSPEC int IMG_string_equals(const char *str1, const char *str2);
     4.9 +
    4.10  /* Ends C function definitions when using C++ */
    4.11  #ifdef __cplusplus
    4.12  };