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