1// Copyright 1998-2006 by Bill Spitzak and others.
2//
3// This library is free software; you can redistribute it and/or
4// modify it under the terms of the GNU Library General Public
5// License as published by the Free Software Foundation; either
6// version 2 of the License, or (at your option) any later version.
7//
8// This library is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11// Library General Public License for more details.
12//
13// You should have received a copy of the GNU Library General Public
14// License along with this library; if not, write to the Free Software
15// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
16// USA.
17//
18
19#include "config.h"
20
21#include <ctype.h>
22#include <stdint.h>
23#include <string.h>
24#include <stdio.h>
25#include <stdlib.h>
26
27#define NUM_BASE 95
28#define FIRSTCHAR 32
29
30void set_pixels(uint8_t *image, int w, int x, int y, uint32_t c) {
31 int offs = y * w * 4 + x * 4;
32 image[offs + 3] = (c) & 0xff;
33#if defined(_SDL)
34 image[offs + 2] = (c >> 24) & 0xff;
35 image[offs + 1] = (c >> 16) & 0xff;
36 image[offs + 0] = (c >> 8) & 0xff;
37#else
38 image[offs + 2] = (c >> 8) & 0xff;
39 image[offs + 1] = (c >> 16) & 0xff;
40 image[offs + 0] = (c >> 24) & 0xff;
41#endif
42}
43
44int xpm_decode32(uint8_t **image, unsigned *width, unsigned *height, const char *const *xpm) {
45 int ncolors, chars_per_pixel;
46 int next_line = 0;
47
48 if (xpm[0][0] == '/' && xpm[0][1] == '*') {
49 // skip
50 // /* XPM */
51 // static char * img_xpm[] = {
52 next_line = 2;
53 }
54
55 int n = sscanf(xpm[next_line], "%d %d %d %d", width, height, &ncolors, &chars_per_pixel);
56 if (n < 4 || (chars_per_pixel != 1 && chars_per_pixel != 2)) {
57 return 1;
58 }
59 if (*width <= 0 || *height <= 0) {
60 return 1;
61 }
62
63 int maxColors = chars_per_pixel == 1 ? NUM_BASE : (NUM_BASE * NUM_BASE);
64 if (ncolors >= maxColors) {
65 return 1;
66 }
67
68 // note that this array is unsigned char and skips the first line:
69 const uint8_t *const* data = (const uint8_t*const*)(xpm + next_line + 1);
70 uint32_t colors[maxColors];
71
72 for (int i = 0; i < ncolors; i++) {
73 const uint8_t *p = *data++;
74 int index = (*p++) - FIRSTCHAR;
75 if (chars_per_pixel == 2) {
76 int next = (*p++) - FIRSTCHAR;
77 index = index * NUM_BASE + next;
78 }
79 // where to store color
80 uint32_t *c = &colors[index];
81
82 // look for "c word", or last word if none:
83 while (*p && isspace(*p)) {
84 p++;
85 }
86 if (*p++ == 'c') {
87 while (*p && isspace(*p)) {
88 p++;
89 }
90 }
91
92 if (*p == '#') {
93 uint32_t C = strtol((const char *)p + 1, NULL, 16);
94 *c = 0x000000ff | C << 8; // convert color to RGBA
95 } else {
96 // assume "None" or "#transparent" for any errors
97 *c = 0;
98 }
99 }
100
101 *image = malloc((*width) * (*height) * sizeof(uint32_t));
102
103 if (chars_per_pixel == 1) {
104 for (int y = 0; y <* height; y++) {
105 const uint8_t *p = data[y];
106 for (int x = 0; x < *width; x++) {
107 int index = *(p++) - FIRSTCHAR;
108 set_pixels(*image, *width, x, y, colors[index]);
109 }
110 }
111 } else {
112 for (int y = 0; y < *height; y++) {
113 const uint8_t *p = data[y];
114 for (int x = 0; x < *width && *p; x++) {
115 int index = (*p++) - FIRSTCHAR;
116 int next = (*p++) - FIRSTCHAR;
117 index = index * NUM_BASE + next;
118 set_pixels(*image, *width, x, y, colors[index]);
119 }
120 }
121 }
122 return 0;
123}
124