began for maemo
[xscreensaver] / xscreensaver / utils / minixpm.c
1 /* xscreensaver, Copyright (c) 2001-2006 Jamie Zawinski <jwz@jwz.org>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software and its
4  * documentation for any purpose is hereby granted without fee, provided that
5  * the above copyright notice appear in all copies and that both that
6  * copyright notice and this permission notice appear in supporting
7  * documentation.  No representations are made about the suitability of this
8  * software for any purpose.  It is provided "as is" without express or 
9  * implied warranty.
10  */
11
12 /* I implemented this subset of libXPM here because I don't want the
13    xscreensaver daemon to depend on libXPM for two reasons: first,
14    because I want the logo to show up even if libXPM is not installed
15    on the system; and second, I don't want to have to security-audit
16    libXPM.  The fewer libraries that are linked into the xscreensaver
17    daemon, the more likely to be secure it is.
18
19    Also, the Cocoa port uses this code since libXPM isn't available
20    by default on MacOS.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #ifdef HAVE_COCOA
32 # include "jwxyz.h"
33 #else  /* !HAVE_COCOA - real Xlib */
34 # include <X11/Xlib.h>
35 # include <X11/Xutil.h>
36 #endif /* !HAVE_COCOA */
37
38 #include "minixpm.h"
39
40 extern const char *progname;
41
42 static Bool
43 bigendian (void)
44 {
45   union { int i; char c[sizeof(int)]; } u;
46   u.i = 1;
47   return !u.c[0];
48 }
49
50 static const char hex[128] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
52                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
53                               0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
54                               0, 10,11,12,13,14,15,0, 0, 0, 0, 0, 0, 0, 0, 0,
55                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56                               0, 10,11,12,13,14,15,0, 0, 0, 0, 0, 0, 0, 0, 0,
57                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
58
59 XImage *
60 minixpm_to_ximage (Display *dpy, Visual *visual, Colormap colormap, int depth,
61                    unsigned long transparent_color,
62                    const char * const * data,
63                    int *width_ret, int *height_ret,
64                    unsigned long **pixels_ret, int *npixels_ret,
65                    unsigned char **mask_ret)
66 {
67   int w, w8, h, ncolors, nbytes;
68   char c;
69   int x, y, i, pixel_count;
70   struct {
71     char byte;
72     int cr; int cg; int cb;
73     int mr; int mg; int mb;
74   } cmap[256];
75   unsigned char rmap[256];
76
77   unsigned long *pixels;
78   XImage *ximage = 0;
79
80   if (4 != sscanf ((const char *) *data,
81                    "%d %d %d %d %c", &w, &h, &ncolors, &nbytes, &c)) {
82     fprintf (stderr, "%s: unparsable XPM header\n", progname);
83     abort();
84   }
85
86   if (ncolors < 1 || ncolors > 255) {
87     fprintf (stderr, "%s: XPM: ncolors is %d\n", progname, ncolors);
88     abort();
89   }
90   if (nbytes != 1) {
91     fprintf (stderr, "%s: %d-byte XPM files not supported\n",
92              progname, nbytes);
93     abort();
94   }
95   data++;
96
97   for (i = 0; i < ncolors; i++)
98     {
99       const char *line = *data;
100       cmap[i].byte = *line++;
101       while (*line)
102         {
103           int r, g, b;
104           char which;
105           while (*line == ' ' || *line == '\t')
106             line++;
107           which = *line;
108           if (!which) continue;  /* whitespace at end of line */
109           line++;
110           if (which != 'c' && which != 'm') {
111             fprintf (stderr, "%s: unknown XPM pixel type '%c' in \"%s\"\n",
112                      progname, which, *data);
113             abort();
114           }
115           while (*line == ' ' || *line == '\t')
116             line++;
117           if (!strncasecmp(line, "None", 4))
118             {
119               r = g = b = -1;
120               line += 4;
121             }
122           else
123             {
124               if (*line != '#') {
125                 fprintf (stderr, "%s: unparsable XPM color spec: \"%s\"\n",
126                          progname, line);
127                 abort();
128               }
129               if (*line == '#')
130                 line++;
131               r = (hex[(int) line[0]] << 4) | hex[(int) line[1]]; line += 2;
132               g = (hex[(int) line[0]] << 4) | hex[(int) line[1]]; line += 2;
133               b = (hex[(int) line[0]] << 4) | hex[(int) line[1]]; line += 2;
134             }
135
136           if (which == 'c')
137             {
138               cmap[i].cr = r;
139               cmap[i].cg = g;
140               cmap[i].cb = b;
141             }
142           else
143             {
144               cmap[i].mr = r;
145               cmap[i].mg = g;
146               cmap[i].mb = b;
147             }
148         }
149
150       data++;
151     }
152
153   if (depth == 1) transparent_color = 1;
154
155   pixels = (unsigned long *) calloc (ncolors+1, sizeof(*pixels));
156   pixel_count = 0;
157   for (i = 0; i < ncolors; i++)
158     {
159       if (cmap[i].cr == -1) /* transparent */
160         {
161           rmap[(int) cmap[i].byte] = 255;
162         }
163       else
164         {
165           XColor color;
166           color.flags = DoRed|DoGreen|DoBlue;
167           color.red   = (cmap[i].cr << 8) | cmap[i].cr;
168           color.green = (cmap[i].cg << 8) | cmap[i].cg;
169           color.blue  = (cmap[i].cb << 8) | cmap[i].cb;
170           if (depth == 1 ||
171               !XAllocColor (dpy, colormap, &color))
172             {
173               color.red   = (cmap[i].mr << 8) | cmap[i].mr;
174               color.green = (cmap[i].mg << 8) | cmap[i].mg;
175               color.blue  = (cmap[i].mb << 8) | cmap[i].mb;
176               if (!XAllocColor (dpy, colormap, &color)) {
177                 fprintf (stderr, "%s: unable to allocate XPM color\n",
178                          progname);
179                 abort();
180               }
181             }
182           pixels[pixel_count] = color.pixel;
183           rmap[(int) cmap[i].byte] = pixel_count;
184           pixel_count++;
185         }
186     }
187
188   ximage = XCreateImage (dpy, visual, depth,
189                          (depth == 1 ? XYBitmap : ZPixmap),
190                          0, 0, w, h, 8, 0);
191   if (! ximage) return 0;
192
193   ximage->bitmap_bit_order =
194     ximage->byte_order =
195     (bigendian() ? MSBFirst : LSBFirst);
196
197   ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
198   if (!ximage->data) {
199     XDestroyImage (ximage);
200     return 0;
201   }
202
203   w8 = (w + 7) / 8;
204   if (mask_ret)
205     {
206       int s = (w8 * h) + 1;
207       *mask_ret = (unsigned char *) malloc (s);
208       if (!*mask_ret)
209         mask_ret = 0;
210       else
211         memset (*mask_ret, 255, s);
212     }
213
214   for (y = 0; y < h; y++)
215     {
216       const char *line = *data++;
217       for (x = 0; x < w; x++)
218         {
219           int p = rmap[(int) *line];
220           line++;
221           XPutPixel (ximage, x, y, (p == 255 ? transparent_color : pixels[p]));
222
223           if (p == 255 && mask_ret)
224             (*mask_ret)[(y * w8) + (x >> 3)] &= (~(1 << (x & 7)));
225         }
226     }
227
228   *width_ret = w;
229   *height_ret = h;
230   *pixels_ret = pixels;
231   *npixels_ret = pixel_count;
232   return ximage;
233 }