New comit of SDL2
[supertux.git] / src / SDL2 / IMG_xpm.c
1 /*
2   SDL_image:  An example image loading library for use with SDL
3   Copyright (C) 1997-2013 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 /*
23  * XPM (X PixMap) image loader:
24  *
25  * Supports the XPMv3 format, EXCEPT:
26  * - hotspot coordinates are ignored
27  * - only colour ('c') colour symbols are used
28  * - rgb.txt is not used (for portability), so only RGB colours
29  *   are recognized (#rrggbb etc) - only a few basic colour names are
30  *   handled
31  *
32  * The result is an 8bpp indexed surface if possible, otherwise 32bpp.
33  * The colourkey is correctly set if transparency is used.
34  *
35  * Besides the standard API, also provides
36  *
37  *     SDL_Surface *IMG_ReadXPMFromArray(char **xpm)
38  *
39  * that reads the image data from an XPM file included in the C source.
40  *
41  * TODO: include rgb.txt here. The full table (from solaris 2.6) only
42  * requires about 13K in binary form.
43  */
44
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include <ctype.h>
49
50 #include "SDL_image.h"
51
52 #ifdef LOAD_XPM
53
54 /* See if an image is contained in a data source */
55 int IMG_isXPM(SDL_RWops *src)
56 {
57     Sint64 start;
58     int is_XPM;
59     char magic[9];
60
61     if ( !src )
62         return 0;
63     start = SDL_RWtell(src);
64     is_XPM = 0;
65     if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
66         if ( SDL_memcmp(magic, "/* XPM */", sizeof(magic)) == 0 ) {
67             is_XPM = 1;
68         }
69     }
70     SDL_RWseek(src, start, RW_SEEK_SET);
71     return(is_XPM);
72 }
73
74 /* Hash table to look up colors from pixel strings */
75 #define STARTING_HASH_SIZE 256
76
77 struct hash_entry {
78     char *key;
79     Uint32 color;
80     struct hash_entry *next;
81 };
82
83 struct color_hash {
84     struct hash_entry **table;
85     struct hash_entry *entries; /* array of all entries */
86     struct hash_entry *next_free;
87     int size;
88     int maxnum;
89 };
90
91 static int hash_key(const char *key, int cpp, int size)
92 {
93     int hash;
94
95     hash = 0;
96     while ( cpp-- > 0 ) {
97         hash = hash * 33 + *key++;
98     }
99     return hash & (size - 1);
100 }
101
102 static struct color_hash *create_colorhash(int maxnum)
103 {
104     int bytes, s;
105     struct color_hash *hash;
106
107     /* we know how many entries we need, so we can allocate
108        everything here */
109     hash = (struct color_hash *)SDL_malloc(sizeof *hash);
110     if(!hash)
111         return NULL;
112
113     /* use power-of-2 sized hash table for decoding speed */
114     for(s = STARTING_HASH_SIZE; s < maxnum; s <<= 1)
115         ;
116     hash->size = s;
117     hash->maxnum = maxnum;
118     bytes = hash->size * sizeof(struct hash_entry **);
119     hash->entries = NULL;   /* in case malloc fails */
120     hash->table = (struct hash_entry **)SDL_malloc(bytes);
121     if(!hash->table) {
122         SDL_free(hash);
123         return NULL;
124     }
125     memset(hash->table, 0, bytes);
126     hash->entries = (struct hash_entry *)SDL_malloc(maxnum * sizeof(struct hash_entry));
127     if(!hash->entries) {
128         SDL_free(hash->table);
129         SDL_free(hash);
130         return NULL;
131     }
132     hash->next_free = hash->entries;
133     return hash;
134 }
135
136 static int add_colorhash(struct color_hash *hash,
137                          char *key, int cpp, Uint32 color)
138 {
139     int index = hash_key(key, cpp, hash->size);
140     struct hash_entry *e = hash->next_free++;
141     e->color = color;
142     e->key = key;
143     e->next = hash->table[index];
144     hash->table[index] = e;
145     return 1;
146 }
147
148 /* fast lookup that works if cpp == 1 */
149 #define QUICK_COLORHASH(hash, key) ((hash)->table[*(Uint8 *)(key)]->color)
150
151 static Uint32 get_colorhash(struct color_hash *hash, const char *key, int cpp)
152 {
153     struct hash_entry *entry = hash->table[hash_key(key, cpp, hash->size)];
154     while(entry) {
155         if(SDL_memcmp(key, entry->key, cpp) == 0)
156             return entry->color;
157         entry = entry->next;
158     }
159     return 0;       /* garbage in - garbage out */
160 }
161
162 static void free_colorhash(struct color_hash *hash)
163 {
164     if(hash) {
165         if(hash->table)
166             SDL_free(hash->table);
167         if(hash->entries)
168             SDL_free(hash->entries);
169         SDL_free(hash);
170     }
171 }
172
173 /*
174  * convert colour spec to RGB (in 0xrrggbb format).
175  * return 1 if successful.
176  */
177 static int color_to_rgb(char *spec, int speclen, Uint32 *rgb)
178 {
179     /* poor man's rgb.txt */
180     static struct { char *name; Uint32 rgb; } known[] = {
181         { "none",                 0xFFFFFF },
182         { "black",                0x000000 },
183         { "white",                0xFFFFFF },
184         { "red",                  0xFF0000 },
185         { "green",                0x00FF00 },
186         { "blue",                 0x0000FF },
187 /* This table increases the size of the library by 40K, so it's disabled by default */
188 #ifdef EXTENDED_XPM_COLORS
189         { "aliceblue",            0xf0f8ff },
190         { "antiquewhite",         0xfaebd7 },
191         { "antiquewhite1",        0xffefdb },
192         { "antiquewhite2",        0xeedfcc },
193         { "antiquewhite3",        0xcdc0b0 },
194         { "antiquewhite4",        0x8b8378 },
195         { "aqua",                 0x00ffff },
196         { "aquamarine",           0x7fffd4 },
197         { "aquamarine1",          0x7fffd4 },
198         { "aquamarine2",          0x76eec6 },
199         { "aquamarine3",          0x66cdaa },
200         { "aquamarine4",          0x458b74 },
201         { "azure",                0xf0ffff },
202         { "azure1",               0xf0ffff },
203         { "azure2",               0xe0eeee },
204         { "azure3",               0xc1cdcd },
205         { "azure4",               0x838b8b },
206         { "beige",                0xf5f5dc },
207         { "bisque",               0xffe4c4 },
208         { "bisque1",              0xffe4c4 },
209         { "bisque2",              0xeed5b7 },
210         { "bisque3",              0xcdb79e },
211         { "bisque4",              0x8b7d6b },
212         { "black",                0x000000 },
213         { "blanchedalmond",       0xffebcd },
214         { "blue",                 0x0000ff },
215         { "blue1",                0x0000ff },
216         { "blue2",                0x0000ee },
217         { "blue3",                0x0000cd },
218         { "blue4",                0x00008B },
219         { "blueviolet",           0x8a2be2 },
220         { "brown",                0xA52A2A },
221         { "brown1",               0xFF4040 },
222         { "brown2",               0xEE3B3B },
223         { "brown3",               0xCD3333 },
224         { "brown4",               0x8B2323 },
225         { "burlywood",            0xDEB887 },
226         { "burlywood1",           0xFFD39B },
227         { "burlywood2",           0xEEC591 },
228         { "burlywood3",           0xCDAA7D },
229         { "burlywood4",           0x8B7355 },
230         { "cadetblue",            0x5F9EA0 },
231         { "cadetblue",            0x5f9ea0 },
232         { "cadetblue1",           0x98f5ff },
233         { "cadetblue2",           0x8ee5ee },
234         { "cadetblue3",           0x7ac5cd },
235         { "cadetblue4",           0x53868b },
236         { "chartreuse",           0x7FFF00 },
237         { "chartreuse1",          0x7FFF00 },
238         { "chartreuse2",          0x76EE00 },
239         { "chartreuse3",          0x66CD00 },
240         { "chartreuse4",          0x458B00 },
241         { "chocolate",            0xD2691E },
242         { "chocolate1",           0xFF7F24 },
243         { "chocolate2",           0xEE7621 },
244         { "chocolate3",           0xCD661D },
245         { "chocolate4",           0x8B4513 },
246         { "coral",                0xFF7F50 },
247         { "coral1",               0xFF7256 },
248         { "coral2",               0xEE6A50 },
249         { "coral3",               0xCD5B45 },
250         { "coral4",               0x8B3E2F },
251         { "cornflowerblue",       0x6495ed },
252         { "cornsilk",             0xFFF8DC },
253         { "cornsilk1",            0xFFF8DC },
254         { "cornsilk2",            0xEEE8CD },
255         { "cornsilk3",            0xCDC8B1 },
256         { "cornsilk4",            0x8B8878 },
257         { "crimson",              0xDC143C },
258         { "cyan",                 0x00FFFF },
259         { "cyan1",                0x00FFFF },
260         { "cyan2",                0x00EEEE },
261         { "cyan3",                0x00CDCD },
262         { "cyan4",                0x008B8B },
263         { "darkblue",             0x00008b },
264         { "darkcyan",             0x008b8b },
265         { "darkgoldenrod",        0xb8860b },
266         { "darkgoldenrod1",       0xffb90f },
267         { "darkgoldenrod2",       0xeead0e },
268         { "darkgoldenrod3",       0xcd950c },
269         { "darkgoldenrod4",       0x8b6508 },
270         { "darkgray",             0xa9a9a9 },
271         { "darkgreen",            0x006400 },
272         { "darkgrey",             0xa9a9a9 },
273         { "darkkhaki",            0xbdb76b },
274         { "darkmagenta",          0x8b008b },
275         { "darkolivegreen",       0x556b2f },
276         { "darkolivegreen1",      0xcaff70 },
277         { "darkolivegreen2",      0xbcee68 },
278         { "darkolivegreen3",      0xa2cd5a },
279         { "darkolivegreen4",      0x6e8b3d },
280         { "darkorange",           0xff8c00 },
281         { "darkorange1",          0xff7f00 },
282         { "darkorange2",          0xee7600 },
283         { "darkorange3",          0xcd6600 },
284         { "darkorange4",          0x8b4500 },
285         { "darkorchid",           0x9932cc },
286         { "darkorchid1",          0xbf3eff },
287         { "darkorchid2",          0xb23aee },
288         { "darkorchid3",          0x9a32cd },
289         { "darkorchid4",          0x68228b },
290         { "darkred",              0x8b0000 },
291         { "darksalmon",           0xe9967a },
292         { "darkseagreen",         0x8fbc8f },
293         { "darkseagreen1",        0xc1ffc1 },
294         { "darkseagreen2",        0xb4eeb4 },
295         { "darkseagreen3",        0x9bcd9b },
296         { "darkseagreen4",        0x698b69 },
297         { "darkslateblue",        0x483d8b },
298         { "darkslategray",        0x2f4f4f },
299         { "darkslategray1",       0x97ffff },
300         { "darkslategray2",       0x8deeee },
301         { "darkslategray3",       0x79cdcd },
302         { "darkslategray4",       0x528b8b },
303         { "darkslategrey",        0x2f4f4f },
304         { "darkturquoise",        0x00ced1 },
305         { "darkviolet",           0x9400D3 },
306         { "darkviolet",           0x9400d3 },
307         { "deeppink",             0xff1493 },
308         { "deeppink1",            0xff1493 },
309         { "deeppink2",            0xee1289 },
310         { "deeppink3",            0xcd1076 },
311         { "deeppink4",            0x8b0a50 },
312         { "deepskyblue",          0x00bfff },
313         { "deepskyblue1",         0x00bfff },
314         { "deepskyblue2",         0x00b2ee },
315         { "deepskyblue3",         0x009acd },
316         { "deepskyblue4",         0x00688b },
317         { "dimgray",              0x696969 },
318         { "dimgrey",              0x696969 },
319         { "dodgerblue",           0x1e90ff },
320         { "dodgerblue1",          0x1e90ff },
321         { "dodgerblue2",          0x1c86ee },
322         { "dodgerblue3",          0x1874cd },
323         { "dodgerblue4",          0x104e8b },
324         { "firebrick",            0xB22222 },
325         { "firebrick1",           0xFF3030 },
326         { "firebrick2",           0xEE2C2C },
327         { "firebrick3",           0xCD2626 },
328         { "firebrick4",           0x8B1A1A },
329         { "floralwhite",          0xfffaf0 },
330         { "forestgreen",          0x228b22 },
331         { "fractal",              0x808080 },
332         { "fuchsia",              0xFF00FF },
333         { "gainsboro",            0xDCDCDC },
334         { "ghostwhite",           0xf8f8ff },
335         { "gold",                 0xFFD700 },
336         { "gold1",                0xFFD700 },
337         { "gold2",                0xEEC900 },
338         { "gold3",                0xCDAD00 },
339         { "gold4",                0x8B7500 },
340         { "goldenrod",            0xDAA520 },
341         { "goldenrod1",           0xFFC125 },
342         { "goldenrod2",           0xEEB422 },
343         { "goldenrod3",           0xCD9B1D },
344         { "goldenrod4",           0x8B6914 },
345         { "gray",                 0x7E7E7E },
346         { "gray",                 0xBEBEBE },
347         { "gray0",                0x000000 },
348         { "gray1",                0x030303 },
349         { "gray10",               0x1A1A1A },
350         { "gray100",              0xFFFFFF },
351         { "gray11",               0x1C1C1C },
352         { "gray12",               0x1F1F1F },
353         { "gray13",               0x212121 },
354         { "gray14",               0x242424 },
355         { "gray15",               0x262626 },
356         { "gray16",               0x292929 },
357         { "gray17",               0x2B2B2B },
358         { "gray18",               0x2E2E2E },
359         { "gray19",               0x303030 },
360         { "gray2",                0x050505 },
361         { "gray20",               0x333333 },
362         { "gray21",               0x363636 },
363         { "gray22",               0x383838 },
364         { "gray23",               0x3B3B3B },
365         { "gray24",               0x3D3D3D },
366         { "gray25",               0x404040 },
367         { "gray26",               0x424242 },
368         { "gray27",               0x454545 },
369         { "gray28",               0x474747 },
370         { "gray29",               0x4A4A4A },
371         { "gray3",                0x080808 },
372         { "gray30",               0x4D4D4D },
373         { "gray31",               0x4F4F4F },
374         { "gray32",               0x525252 },
375         { "gray33",               0x545454 },
376         { "gray34",               0x575757 },
377         { "gray35",               0x595959 },
378         { "gray36",               0x5C5C5C },
379         { "gray37",               0x5E5E5E },
380         { "gray38",               0x616161 },
381         { "gray39",               0x636363 },
382         { "gray4",                0x0A0A0A },
383         { "gray40",               0x666666 },
384         { "gray41",               0x696969 },
385         { "gray42",               0x6B6B6B },
386         { "gray43",               0x6E6E6E },
387         { "gray44",               0x707070 },
388         { "gray45",               0x737373 },
389         { "gray46",               0x757575 },
390         { "gray47",               0x787878 },
391         { "gray48",               0x7A7A7A },
392         { "gray49",               0x7D7D7D },
393         { "gray5",                0x0D0D0D },
394         { "gray50",               0x7F7F7F },
395         { "gray51",               0x828282 },
396         { "gray52",               0x858585 },
397         { "gray53",               0x878787 },
398         { "gray54",               0x8A8A8A },
399         { "gray55",               0x8C8C8C },
400         { "gray56",               0x8F8F8F },
401         { "gray57",               0x919191 },
402         { "gray58",               0x949494 },
403         { "gray59",               0x969696 },
404         { "gray6",                0x0F0F0F },
405         { "gray60",               0x999999 },
406         { "gray61",               0x9C9C9C },
407         { "gray62",               0x9E9E9E },
408         { "gray63",               0xA1A1A1 },
409         { "gray64",               0xA3A3A3 },
410         { "gray65",               0xA6A6A6 },
411         { "gray66",               0xA8A8A8 },
412         { "gray67",               0xABABAB },
413         { "gray68",               0xADADAD },
414         { "gray69",               0xB0B0B0 },
415         { "gray7",                0x121212 },
416         { "gray70",               0xB3B3B3 },
417         { "gray71",               0xB5B5B5 },
418         { "gray72",               0xB8B8B8 },
419         { "gray73",               0xBABABA },
420         { "gray74",               0xBDBDBD },
421         { "gray75",               0xBFBFBF },
422         { "gray76",               0xC2C2C2 },
423         { "gray77",               0xC4C4C4 },
424         { "gray78",               0xC7C7C7 },
425         { "gray79",               0xC9C9C9 },
426         { "gray8",                0x141414 },
427         { "gray80",               0xCCCCCC },
428         { "gray81",               0xCFCFCF },
429         { "gray82",               0xD1D1D1 },
430         { "gray83",               0xD4D4D4 },
431         { "gray84",               0xD6D6D6 },
432         { "gray85",               0xD9D9D9 },
433         { "gray86",               0xDBDBDB },
434         { "gray87",               0xDEDEDE },
435         { "gray88",               0xE0E0E0 },
436         { "gray89",               0xE3E3E3 },
437         { "gray9",                0x171717 },
438         { "gray90",               0xE5E5E5 },
439         { "gray91",               0xE8E8E8 },
440         { "gray92",               0xEBEBEB },
441         { "gray93",               0xEDEDED },
442         { "gray94",               0xF0F0F0 },
443         { "gray95",               0xF2F2F2 },
444         { "gray96",               0xF5F5F5 },
445         { "gray97",               0xF7F7F7 },
446         { "gray98",               0xFAFAFA },
447         { "gray99",               0xFCFCFC },
448         { "green",                0x008000 },
449         { "green",                0x00FF00 },
450         { "green1",               0x00FF00 },
451         { "green2",               0x00EE00 },
452         { "green3",               0x00CD00 },
453         { "green4",               0x008B00 },
454         { "greenyellow",          0xadff2f },
455         { "grey",                 0xBEBEBE },
456         { "grey0",                0x000000 },
457         { "grey1",                0x030303 },
458         { "grey10",               0x1A1A1A },
459         { "grey100",              0xFFFFFF },
460         { "grey11",               0x1C1C1C },
461         { "grey12",               0x1F1F1F },
462         { "grey13",               0x212121 },
463         { "grey14",               0x242424 },
464         { "grey15",               0x262626 },
465         { "grey16",               0x292929 },
466         { "grey17",               0x2B2B2B },
467         { "grey18",               0x2E2E2E },
468         { "grey19",               0x303030 },
469         { "grey2",                0x050505 },
470         { "grey20",               0x333333 },
471         { "grey21",               0x363636 },
472         { "grey22",               0x383838 },
473         { "grey23",               0x3B3B3B },
474         { "grey24",               0x3D3D3D },
475         { "grey25",               0x404040 },
476         { "grey26",               0x424242 },
477         { "grey27",               0x454545 },
478         { "grey28",               0x474747 },
479         { "grey29",               0x4A4A4A },
480         { "grey3",                0x080808 },
481         { "grey30",               0x4D4D4D },
482         { "grey31",               0x4F4F4F },
483         { "grey32",               0x525252 },
484         { "grey33",               0x545454 },
485         { "grey34",               0x575757 },
486         { "grey35",               0x595959 },
487         { "grey36",               0x5C5C5C },
488         { "grey37",               0x5E5E5E },
489         { "grey38",               0x616161 },
490         { "grey39",               0x636363 },
491         { "grey4",                0x0A0A0A },
492         { "grey40",               0x666666 },
493         { "grey41",               0x696969 },
494         { "grey42",               0x6B6B6B },
495         { "grey43",               0x6E6E6E },
496         { "grey44",               0x707070 },
497         { "grey45",               0x737373 },
498         { "grey46",               0x757575 },
499         { "grey47",               0x787878 },
500         { "grey48",               0x7A7A7A },
501         { "grey49",               0x7D7D7D },
502         { "grey5",                0x0D0D0D },
503         { "grey50",               0x7F7F7F },
504         { "grey51",               0x828282 },
505         { "grey52",               0x858585 },
506         { "grey53",               0x878787 },
507         { "grey54",               0x8A8A8A },
508         { "grey55",               0x8C8C8C },
509         { "grey56",               0x8F8F8F },
510         { "grey57",               0x919191 },
511         { "grey58",               0x949494 },
512         { "grey59",               0x969696 },
513         { "grey6",                0x0F0F0F },
514         { "grey60",               0x999999 },
515         { "grey61",               0x9C9C9C },
516         { "grey62",               0x9E9E9E },
517         { "grey63",               0xA1A1A1 },
518         { "grey64",               0xA3A3A3 },
519         { "grey65",               0xA6A6A6 },
520         { "grey66",               0xA8A8A8 },
521         { "grey67",               0xABABAB },
522         { "grey68",               0xADADAD },
523         { "grey69",               0xB0B0B0 },
524         { "grey7",                0x121212 },
525         { "grey70",               0xB3B3B3 },
526         { "grey71",               0xB5B5B5 },
527         { "grey72",               0xB8B8B8 },
528         { "grey73",               0xBABABA },
529         { "grey74",               0xBDBDBD },
530         { "grey75",               0xBFBFBF },
531         { "grey76",               0xC2C2C2 },
532         { "grey77",               0xC4C4C4 },
533         { "grey78",               0xC7C7C7 },
534         { "grey79",               0xC9C9C9 },
535         { "grey8",                0x141414 },
536         { "grey80",               0xCCCCCC },
537         { "grey81",               0xCFCFCF },
538         { "grey82",               0xD1D1D1 },
539         { "grey83",               0xD4D4D4 },
540         { "grey84",               0xD6D6D6 },
541         { "grey85",               0xD9D9D9 },
542         { "grey86",               0xDBDBDB },
543         { "grey87",               0xDEDEDE },
544         { "grey88",               0xE0E0E0 },
545         { "grey89",               0xE3E3E3 },
546         { "grey9",                0x171717 },
547         { "grey90",               0xE5E5E5 },
548         { "grey91",               0xE8E8E8 },
549         { "grey92",               0xEBEBEB },
550         { "grey93",               0xEDEDED },
551         { "grey94",               0xF0F0F0 },
552         { "grey95",               0xF2F2F2 },
553         { "grey96",               0xF5F5F5 },
554         { "grey97",               0xF7F7F7 },
555         { "grey98",               0xFAFAFA },
556         { "grey99",               0xFCFCFC },
557         { "honeydew",             0xF0FFF0 },
558         { "honeydew1",            0xF0FFF0 },
559         { "honeydew2",            0xE0EEE0 },
560         { "honeydew3",            0xC1CDC1 },
561         { "honeydew4",            0x838B83 },
562         { "hotpink",              0xff69b4 },
563         { "hotpink1",             0xff6eb4 },
564         { "hotpink2",             0xee6aa7 },
565         { "hotpink3",             0xcd6090 },
566         { "hotpink4",             0x8b3a62 },
567         { "indianred",            0xcd5c5c },
568         { "indianred1",           0xff6a6a },
569         { "indianred2",           0xee6363 },
570         { "indianred3",           0xcd5555 },
571         { "indianred4",           0x8b3a3a },
572         { "indigo",               0x4B0082 },
573         { "ivory",                0xFFFFF0 },
574         { "ivory1",               0xFFFFF0 },
575         { "ivory2",               0xEEEEE0 },
576         { "ivory3",               0xCDCDC1 },
577         { "ivory4",               0x8B8B83 },
578         { "khaki",                0xF0E68C },
579         { "khaki1",               0xFFF68F },
580         { "khaki2",               0xEEE685 },
581         { "khaki3",               0xCDC673 },
582         { "khaki4",               0x8B864E },
583         { "lavender",             0xE6E6FA },
584         { "lavenderblush",        0xfff0f5 },
585         { "lavenderblush1",       0xfff0f5 },
586         { "lavenderblush2",       0xeee0e5 },
587         { "lavenderblush3",       0xcdc1c5 },
588         { "lavenderblush4",       0x8b8386 },
589         { "lawngreen",            0x7cfc00 },
590         { "lemonchiffon",         0xfffacd },
591         { "lemonchiffon1",        0xfffacd },
592         { "lemonchiffon2",        0xeee9bf },
593         { "lemonchiffon3",        0xcdc9a5 },
594         { "lemonchiffon4",        0x8b8970 },
595         { "lightblue",            0xadd8e6 },
596         { "lightblue1",           0xbfefff },
597         { "lightblue2",           0xb2dfee },
598         { "lightblue3",           0x9ac0cd },
599         { "lightblue4",           0x68838b },
600         { "lightcoral",           0xf08080 },
601         { "lightcyan",            0xe0ffff },
602         { "lightcyan1",           0xe0ffff },
603         { "lightcyan2",           0xd1eeee },
604         { "lightcyan3",           0xb4cdcd },
605         { "lightcyan4",           0x7a8b8b },
606         { "lightgoldenrod",       0xeedd82 },
607         { "lightgoldenrod1",      0xffec8b },
608         { "lightgoldenrod2",      0xeedc82 },
609         { "lightgoldenrod3",      0xcdbe70 },
610         { "lightgoldenrod4",      0x8b814c },
611         { "lightgoldenrodyellow", 0xfafad2 },
612         { "lightgray",            0xd3d3d3 },
613         { "lightgreen",           0x90ee90 },
614         { "lightgrey",            0xd3d3d3 },
615         { "lightpink",            0xffb6c1 },
616         { "lightpink1",           0xffaeb9 },
617         { "lightpink2",           0xeea2ad },
618         { "lightpink3",           0xcd8c95 },
619         { "lightpink4",           0x8b5f65 },
620         { "lightsalmon",          0xffa07a },
621         { "lightsalmon1",         0xffa07a },
622         { "lightsalmon2",         0xee9572 },
623         { "lightsalmon3",         0xcd8162 },
624         { "lightsalmon4",         0x8b5742 },
625         { "lightseagreen",        0x20b2aa },
626         { "lightskyblue",         0x87cefa },
627         { "lightskyblue1",        0xb0e2ff },
628         { "lightskyblue2",        0xa4d3ee },
629         { "lightskyblue3",        0x8db6cd },
630         { "lightskyblue4",        0x607b8b },
631         { "lightslateblue",       0x8470ff },
632         { "lightslategray",       0x778899 },
633         { "lightslategrey",       0x778899 },
634         { "lightsteelblue",       0xb0c4de },
635         { "lightsteelblue1",      0xcae1ff },
636         { "lightsteelblue2",      0xbcd2ee },
637         { "lightsteelblue3",      0xa2b5cd },
638         { "lightsteelblue4",      0x6e7b8b },
639         { "lightyellow",          0xffffe0 },
640         { "lightyellow1",         0xffffe0 },
641         { "lightyellow2",         0xeeeed1 },
642         { "lightyellow3",         0xcdcdb4 },
643         { "lightyellow4",         0x8b8b7a },
644         { "lime",                 0x00FF00 },
645         { "limegreen",            0x32cd32 },
646         { "linen",                0xFAF0E6 },
647         { "magenta",              0xFF00FF },
648         { "magenta1",             0xFF00FF },
649         { "magenta2",             0xEE00EE },
650         { "magenta3",             0xCD00CD },
651         { "magenta4",             0x8B008B },
652         { "maroon",               0x800000 },
653         { "maroon",               0xB03060 },
654         { "maroon1",              0xFF34B3 },
655         { "maroon2",              0xEE30A7 },
656         { "maroon3",              0xCD2990 },
657         { "maroon4",              0x8B1C62 },
658         { "mediumaquamarine",     0x66cdaa },
659         { "mediumblue",           0x0000cd },
660         { "mediumforestgreen",    0x32814b },
661         { "mediumgoldenrod",      0xd1c166 },
662         { "mediumorchid",         0xba55d3 },
663         { "mediumorchid1",        0xe066ff },
664         { "mediumorchid2",        0xd15fee },
665         { "mediumorchid3",        0xb452cd },
666         { "mediumorchid4",        0x7a378b },
667         { "mediumpurple",         0x9370db },
668         { "mediumpurple1",        0xab82ff },
669         { "mediumpurple2",        0x9f79ee },
670         { "mediumpurple3",        0x8968cd },
671         { "mediumpurple4",        0x5d478b },
672         { "mediumseagreen",       0x3cb371 },
673         { "mediumslateblue",      0x7b68ee },
674         { "mediumspringgreen",    0x00fa9a },
675         { "mediumturquoise",      0x48d1cc },
676         { "mediumvioletred",      0xc71585 },
677         { "midnightblue",         0x191970 },
678         { "mintcream",            0xf5fffa },
679         { "mistyrose",            0xffe4e1 },
680         { "mistyrose1",           0xffe4e1 },
681         { "mistyrose2",           0xeed5d2 },
682         { "mistyrose3",           0xcdb7b5 },
683         { "mistyrose4",           0x8b7d7b },
684         { "moccasin",             0xFFE4B5 },
685         { "navajowhite",          0xffdead },
686         { "navajowhite1",         0xffdead },
687         { "navajowhite2",         0xeecfa1 },
688         { "navajowhite3",         0xcdb38b },
689         { "navajowhite4",         0x8b795e },
690         { "navy",                 0x000080 },
691         { "navyblue",             0x000080 },
692         { "none",                 0x0000FF },
693         { "oldlace",              0xfdf5e6 },
694         { "olive",                0x808000 },
695         { "olivedrab",            0x6b8e23 },
696         { "olivedrab1",           0xc0ff3e },
697         { "olivedrab2",           0xb3ee3a },
698         { "olivedrab3",           0x9acd32 },
699         { "olivedrab4",           0x698b22 },
700         { "opaque",               0x000000 },
701         { "orange",               0xFFA500 },
702         { "orange1",              0xFFA500 },
703         { "orange2",              0xEE9A00 },
704         { "orange3",              0xCD8500 },
705         { "orange4",              0x8B5A00 },
706         { "orangered",            0xff4500 },
707         { "orangered1",           0xff4500 },
708         { "orangered2",           0xee4000 },
709         { "orangered3",           0xcd3700 },
710         { "orangered4",           0x8b2500 },
711         { "orchid",               0xDA70D6 },
712         { "orchid1",              0xFF83FA },
713         { "orchid2",              0xEE7AE9 },
714         { "orchid3",              0xCD69C9 },
715         { "orchid4",              0x8B4789 },
716         { "palegoldenrod",        0xeee8aa },
717         { "palegreen",            0x98fb98 },
718         { "palegreen1",           0x9aff9a },
719         { "palegreen2",           0x90ee90 },
720         { "palegreen3",           0x7ccd7c },
721         { "palegreen4",           0x548b54 },
722         { "paleturquoise",        0xafeeee },
723         { "paleturquoise1",       0xbbffff },
724         { "paleturquoise2",       0xaeeeee },
725         { "paleturquoise3",       0x96cdcd },
726         { "paleturquoise4",       0x668b8b },
727         { "palevioletred",        0xdb7093 },
728         { "palevioletred1",       0xff82ab },
729         { "palevioletred2",       0xee799f },
730         { "palevioletred3",       0xcd6889 },
731         { "palevioletred4",       0x8b475d },
732         { "papayawhip",           0xffefd5 },
733         { "peachpuff",            0xffdab9 },
734         { "peachpuff1",           0xffdab9 },
735         { "peachpuff2",           0xeecbad },
736         { "peachpuff3",           0xcdaf95 },
737         { "peachpuff4",           0x8b7765 },
738         { "peru",                 0xCD853F },
739         { "pink",                 0xFFC0CB },
740         { "pink1",                0xFFB5C5 },
741         { "pink2",                0xEEA9B8 },
742         { "pink3",                0xCD919E },
743         { "pink4",                0x8B636C },
744         { "plum",                 0xDDA0DD },
745         { "plum1",                0xFFBBFF },
746         { "plum2",                0xEEAEEE },
747         { "plum3",                0xCD96CD },
748         { "plum4",                0x8B668B },
749         { "powderblue",           0xb0e0e6 },
750         { "purple",               0x800080 },
751         { "purple",               0xA020F0 },
752         { "purple1",              0x9B30FF },
753         { "purple2",              0x912CEE },
754         { "purple3",              0x7D26CD },
755         { "purple4",              0x551A8B },
756         { "red",                  0xFF0000 },
757         { "red1",                 0xFF0000 },
758         { "red2",                 0xEE0000 },
759         { "red3",                 0xCD0000 },
760         { "red4",                 0x8B0000 },
761         { "rosybrown",            0xbc8f8f },
762         { "rosybrown1",           0xffc1c1 },
763         { "rosybrown2",           0xeeb4b4 },
764         { "rosybrown3",           0xcd9b9b },
765         { "rosybrown4",           0x8b6969 },
766         { "royalblue",            0x4169e1 },
767         { "royalblue1",           0x4876ff },
768         { "royalblue2",           0x436eee },
769         { "royalblue3",           0x3a5fcd },
770         { "royalblue4",           0x27408b },
771         { "saddlebrown",          0x8b4513 },
772         { "salmon",               0xFA8072 },
773         { "salmon1",              0xFF8C69 },
774         { "salmon2",              0xEE8262 },
775         { "salmon3",              0xCD7054 },
776         { "salmon4",              0x8B4C39 },
777         { "sandybrown",           0xf4a460 },
778         { "seagreen",             0x2e8b57 },
779         { "seagreen1",            0x54ff9f },
780         { "seagreen2",            0x4eee94 },
781         { "seagreen3",            0x43cd80 },
782         { "seagreen4",            0x2e8b57 },
783         { "seashell",             0xFFF5EE },
784         { "seashell1",            0xFFF5EE },
785         { "seashell2",            0xEEE5DE },
786         { "seashell3",            0xCDC5BF },
787         { "seashell4",            0x8B8682 },
788         { "sienna",               0xA0522D },
789         { "sienna1",              0xFF8247 },
790         { "sienna2",              0xEE7942 },
791         { "sienna3",              0xCD6839 },
792         { "sienna4",              0x8B4726 },
793         { "silver",               0xC0C0C0 },
794         { "skyblue",              0x87ceeb },
795         { "skyblue1",             0x87ceff },
796         { "skyblue2",             0x7ec0ee },
797         { "skyblue3",             0x6ca6cd },
798         { "skyblue4",             0x4a708b },
799         { "slateblue",            0x6a5acd },
800         { "slateblue1",           0x836fff },
801         { "slateblue2",           0x7a67ee },
802         { "slateblue3",           0x6959cd },
803         { "slateblue4",           0x473c8b },
804         { "slategray",            0x708090 },
805         { "slategray1",           0xc6e2ff },
806         { "slategray2",           0xb9d3ee },
807         { "slategray3",           0x9fb6cd },
808         { "slategray4",           0x6c7b8b },
809         { "slategrey",            0x708090 },
810         { "snow",                 0xFFFAFA },
811         { "snow1",                0xFFFAFA },
812         { "snow2",                0xEEE9E9 },
813         { "snow3",                0xCDC9C9 },
814         { "snow4",                0x8B8989 },
815         { "springgreen",          0x00ff7f },
816         { "springgreen1",         0x00ff7f },
817         { "springgreen2",         0x00ee76 },
818         { "springgreen3",         0x00cd66 },
819         { "springgreen4",         0x008b45 },
820         { "steelblue",            0x4682b4 },
821         { "steelblue1",           0x63b8ff },
822         { "steelblue2",           0x5cacee },
823         { "steelblue3",           0x4f94cd },
824         { "steelblue4",           0x36648b },
825         { "tan",                  0xD2B48C },
826         { "tan1",                 0xFFA54F },
827         { "tan2",                 0xEE9A49 },
828         { "tan3",                 0xCD853F },
829         { "tan4",                 0x8B5A2B },
830         { "teal",                 0x008080 },
831         { "thistle",              0xD8BFD8 },
832         { "thistle1",             0xFFE1FF },
833         { "thistle2",             0xEED2EE },
834         { "thistle3",             0xCDB5CD },
835         { "thistle4",             0x8B7B8B },
836         { "tomato",               0xFF6347 },
837         { "tomato1",              0xFF6347 },
838         { "tomato2",              0xEE5C42 },
839         { "tomato3",              0xCD4F39 },
840         { "tomato4",              0x8B3626 },
841         { "transparent",          0x0000FF },
842         { "turquoise",            0x40E0D0 },
843         { "turquoise1",           0x00F5FF },
844         { "turquoise2",           0x00E5EE },
845         { "turquoise3",           0x00C5CD },
846         { "turquoise4",           0x00868B },
847         { "violet",               0xEE82EE },
848         { "violetred",            0xd02090 },
849         { "violetred1",           0xff3e96 },
850         { "violetred2",           0xee3a8c },
851         { "violetred3",           0xcd3278 },
852         { "violetred4",           0x8b2252 },
853         { "wheat",                0xF5DEB3 },
854         { "wheat1",               0xFFE7BA },
855         { "wheat2",               0xEED8AE },
856         { "wheat3",               0xCDBA96 },
857         { "wheat4",               0x8B7E66 },
858         { "white",                0xFFFFFF },
859         { "whitesmoke",           0xf5f5f5 },
860         { "yellow",               0xFFFF00 },
861         { "yellow1",              0xFFFF00 },
862         { "yellow2",              0xEEEE00 },
863         { "yellow3",              0xCDCD00 },
864         { "yellow4",              0x8B8B00 },
865         { "yellowgreen",          0x9acd32 },
866 #endif /* EXTENDED_XPM_COLORS */
867         {"none",                  0xFFFFFF}
868     };
869
870     if(spec[0] == '#') {
871         char buf[7];
872         switch(speclen) {
873         case 4:
874             buf[0] = buf[1] = spec[1];
875             buf[2] = buf[3] = spec[2];
876             buf[4] = buf[5] = spec[3];
877             break;
878         case 7:
879             SDL_memcpy(buf, spec + 1, 6);
880             break;
881         case 13:
882             buf[0] = spec[1];
883             buf[1] = spec[2];
884             buf[2] = spec[5];
885             buf[3] = spec[6];
886             buf[4] = spec[9];
887             buf[5] = spec[10];
888             break;
889         }
890         buf[6] = '\0';
891         *rgb = strtol(buf, NULL, 16);
892         return 1;
893     } else {
894         int i;
895         for(i = 0; i < SDL_arraysize(known); i++)
896             if(SDL_strncasecmp(known[i].name, spec, speclen) == 0) {
897                 *rgb = known[i].rgb;
898                 return 1;
899             }
900         return 0;
901     }
902 }
903
904 #ifndef MAX
905 #define MAX(a, b) ((a) > (b) ? (a) : (b))
906 #endif
907
908 static char *linebuf;
909 static int buflen;
910 static char *error;
911
912 /*
913  * Read next line from the source.
914  * If len > 0, it's assumed to be at least len chars (for efficiency).
915  * Return NULL and set error upon EOF or parse error.
916  */
917 static char *get_next_line(char ***lines, SDL_RWops *src, int len)
918 {
919     char *linebufnew;
920
921     if(lines) {
922         return *(*lines)++;
923     } else {
924         char c;
925         int n;
926         do {
927             if(SDL_RWread(src, &c, 1, 1) <= 0) {
928                 error = "Premature end of data";
929                 return NULL;
930             }
931         } while(c != '"');
932         if(len) {
933             len += 4;   /* "\",\n\0" */
934             if(len > buflen){
935                 buflen = len;
936                 linebufnew = (char *)SDL_realloc(linebuf, buflen);
937                 if(!linebufnew) {
938                     SDL_free(linebuf);
939                     error = "Out of memory";
940                     return NULL;
941                 }
942                 linebuf = linebufnew;
943             }
944             if(SDL_RWread(src, linebuf, len - 1, 1) <= 0) {
945                 error = "Premature end of data";
946                 return NULL;
947             }
948             n = len - 2;
949         } else {
950             n = 0;
951             do {
952                 if(n >= buflen - 1) {
953                     if(buflen == 0)
954                         buflen = 16;
955                     buflen *= 2;
956                     linebufnew = (char *)SDL_realloc(linebuf, buflen);
957                     if(!linebufnew) {
958                         SDL_free(linebuf);
959                         error = "Out of memory";
960                         return NULL;
961                     }
962                     linebuf = linebufnew;
963                 }
964                 if(SDL_RWread(src, linebuf + n, 1, 1) <= 0) {
965                     error = "Premature end of data";
966                     return NULL;
967                 }
968             } while(linebuf[n++] != '"');
969             n--;
970         }
971         linebuf[n] = '\0';
972         return linebuf;
973     }
974 }
975
976 #define SKIPSPACE(p)                \
977 do {                        \
978     while(SDL_isspace((unsigned char)*(p))) \
979           ++(p);                \
980 } while(0)
981
982 #define SKIPNONSPACE(p)                 \
983 do {                            \
984     while(!SDL_isspace((unsigned char)*(p)) && *p)  \
985           ++(p);                    \
986 } while(0)
987
988 /* read XPM from either array or RWops */
989 static SDL_Surface *load_xpm(char **xpm, SDL_RWops *src)
990 {
991     Sint64 start = 0;
992     SDL_Surface *image = NULL;
993     int index;
994     int x, y;
995     int w, h, ncolors, cpp;
996     int indexed;
997     Uint8 *dst;
998     struct color_hash *colors = NULL;
999     SDL_Color *im_colors = NULL;
1000     char *keystrings = NULL, *nextkey;
1001     char *line;
1002     char ***xpmlines = NULL;
1003     int pixels_len;
1004
1005     error = NULL;
1006     linebuf = NULL;
1007     buflen = 0;
1008
1009     if ( src )
1010         start = SDL_RWtell(src);
1011
1012     if(xpm)
1013         xpmlines = &xpm;
1014
1015     line = get_next_line(xpmlines, src, 0);
1016     if(!line)
1017         goto done;
1018     /*
1019      * The header string of an XPMv3 image has the format
1020      *
1021      * <width> <height> <ncolors> <cpp> [ <hotspot_x> <hotspot_y> ]
1022      *
1023      * where the hotspot coords are intended for mouse cursors.
1024      * Right now we don't use the hotspots but it should be handled
1025      * one day.
1026      */
1027     if(SDL_sscanf(line, "%d %d %d %d", &w, &h, &ncolors, &cpp) != 4
1028        || w <= 0 || h <= 0 || ncolors <= 0 || cpp <= 0) {
1029         error = "Invalid format description";
1030         goto done;
1031     }
1032
1033     keystrings = (char *)SDL_malloc(ncolors * cpp);
1034     if(!keystrings) {
1035         error = "Out of memory";
1036         goto done;
1037     }
1038     nextkey = keystrings;
1039
1040     /* Create the new surface */
1041     if(ncolors <= 256) {
1042         indexed = 1;
1043         image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8,
1044                          0, 0, 0, 0);
1045         im_colors = image->format->palette->colors;
1046         image->format->palette->ncolors = ncolors;
1047     } else {
1048         indexed = 0;
1049         image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
1050                          0xff0000, 0x00ff00, 0x0000ff, 0);
1051     }
1052     if(!image) {
1053         /* Hmm, some SDL error (out of memory?) */
1054         goto done;
1055     }
1056
1057     /* Read the colors */
1058     colors = create_colorhash(ncolors);
1059     if (!colors) {
1060         error = "Out of memory";
1061         goto done;
1062     }
1063     for(index = 0; index < ncolors; ++index ) {
1064         char *p;
1065         line = get_next_line(xpmlines, src, 0);
1066         if(!line)
1067             goto done;
1068
1069         p = line + cpp + 1;
1070
1071         /* parse a colour definition */
1072         for(;;) {
1073             char nametype;
1074             char *colname;
1075             Uint32 rgb, pixel;
1076
1077             SKIPSPACE(p);
1078             if(!*p) {
1079                 error = "colour parse error";
1080                 goto done;
1081             }
1082             nametype = *p;
1083             SKIPNONSPACE(p);
1084             SKIPSPACE(p);
1085             colname = p;
1086             SKIPNONSPACE(p);
1087             if(nametype == 's')
1088                 continue;      /* skip symbolic colour names */
1089
1090             if(!color_to_rgb(colname, p - colname, &rgb))
1091                 continue;
1092
1093             SDL_memcpy(nextkey, line, cpp);
1094             if(indexed) {
1095                 SDL_Color *c = im_colors + index;
1096                 c->r = (Uint8)(rgb >> 16);
1097                 c->g = (Uint8)(rgb >> 8);
1098                 c->b = (Uint8)(rgb);
1099                 pixel = index;
1100             } else
1101                 pixel = rgb;
1102             add_colorhash(colors, nextkey, cpp, pixel);
1103             nextkey += cpp;
1104             if(rgb == 0xffffffff)
1105                 SDL_SetColorKey(image, SDL_TRUE, pixel);
1106             break;
1107         }
1108     }
1109
1110     /* Read the pixels */
1111     pixels_len = w * cpp;
1112     dst = (Uint8 *)image->pixels;
1113     for(y = 0; y < h; y++) {
1114         line = get_next_line(xpmlines, src, pixels_len);
1115         if(indexed) {
1116             /* optimization for some common cases */
1117             if(cpp == 1)
1118                 for(x = 0; x < w; x++)
1119                     dst[x] = (Uint8)QUICK_COLORHASH(colors,
1120                                  line + x);
1121             else
1122                 for(x = 0; x < w; x++)
1123                     dst[x] = (Uint8)get_colorhash(colors,
1124                                    line + x * cpp,
1125                                    cpp);
1126         } else {
1127             for (x = 0; x < w; x++)
1128                 ((Uint32*)dst)[x] = get_colorhash(colors,
1129                                 line + x * cpp,
1130                                   cpp);
1131         }
1132         dst += image->pitch;
1133     }
1134
1135 done:
1136     if(error) {
1137         if ( src )
1138             SDL_RWseek(src, start, RW_SEEK_SET);
1139         if ( image ) {
1140             SDL_FreeSurface(image);
1141             image = NULL;
1142         }
1143         IMG_SetError(error);
1144     }
1145     if (keystrings)
1146         SDL_free(keystrings);
1147     free_colorhash(colors);
1148     if (linebuf)
1149         SDL_free(linebuf);
1150     return(image);
1151 }
1152
1153 /* Load a XPM type image from an RWops datasource */
1154 SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src)
1155 {
1156     if ( !src ) {
1157         /* The error message has been set in SDL_RWFromFile */
1158         return NULL;
1159     }
1160     return load_xpm(NULL, src);
1161 }
1162
1163 SDL_Surface *IMG_ReadXPMFromArray(char **xpm)
1164 {
1165     return load_xpm(xpm, NULL);
1166 }
1167
1168 #else  /* not LOAD_XPM */
1169
1170 /* See if an image is contained in a data source */
1171 int IMG_isXPM(SDL_RWops *src)
1172 {
1173     return(0);
1174 }
1175
1176
1177 /* Load a XPM type image from an SDL datasource */
1178 SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src)
1179 {
1180     return(NULL);
1181 }
1182
1183 SDL_Surface *IMG_ReadXPMFromArray(char **xpm)
1184 {
1185     return NULL;
1186 }
1187 #endif /* not LOAD_XPM */