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