summaryrefslogtreecommitdiffstats
path: root/utils/minixpm.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/minixpm.c')
-rw-r--r--utils/minixpm.c251
1 files changed, 251 insertions, 0 deletions
diff --git a/utils/minixpm.c b/utils/minixpm.c
new file mode 100644
index 0000000..997e628
--- /dev/null
+++ b/utils/minixpm.c
@@ -0,0 +1,251 @@
+/* xscreensaver, Copyright (c) 2001-2014 Jamie Zawinski <jwz@jwz.org>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. No representations are made about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ */
+
+/* I implemented this subset of libXPM here because I don't want the
+ xscreensaver daemon to depend on libXPM for two reasons: first,
+ because I want the logo to show up even if libXPM is not installed
+ on the system; and second, I don't want to have to security-audit
+ libXPM. The fewer libraries that are linked into the xscreensaver
+ daemon, the more likely to be secure it is.
+
+ Also, the Cocoa port uses this code since libXPM isn't available
+ by default on MacOS.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_JWXYZ
+# include "jwxyz.h"
+#else /* real Xlib */
+# include <X11/Xlib.h>
+# include <X11/Xutil.h>
+#endif /* !HAVE_JWXYZ */
+
+#include "minixpm.h"
+
+extern const char *progname;
+
+static Bool
+bigendian (void)
+{
+ union { int i; char c[sizeof(int)]; } u;
+ u.i = 1;
+ return !u.c[0];
+}
+
+static const char hex[128] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
+ 0, 10,11,12,13,14,15,0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 10,11,12,13,14,15,0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+XImage *
+minixpm_to_ximage (Display *dpy, Visual *visual, Colormap colormap, int depth,
+ unsigned long transparent_color,
+ const char * const * data,
+ int *width_ret, int *height_ret,
+ unsigned long **pixels_ret, int *npixels_ret,
+ unsigned char **mask_ret)
+{
+ int w, w8, h, ncolors, nbytes;
+ char c;
+ int x, y, i, pixel_count;
+ struct {
+ char byte;
+ int cr; int cg; int cb;
+ int mr; int mg; int mb;
+ } cmap[256];
+ unsigned char rmap[256];
+
+ unsigned long *pixels;
+ XImage *ximage = 0;
+
+ memset (cmap, 0, sizeof(cmap)); /* avoid warnings */
+
+ if (4 != sscanf ((const char *) *data,
+ "%d %d %d %d %c", &w, &h, &ncolors, &nbytes, &c)) {
+ fprintf (stderr, "%s: unparsable XPM header\n", progname);
+ abort();
+ }
+
+ if (ncolors < 1 || ncolors > 255) {
+ fprintf (stderr, "%s: XPM: ncolors is %d\n", progname, ncolors);
+ abort();
+ }
+ if (nbytes != 1) {
+ fprintf (stderr, "%s: %d-byte XPM files not supported\n",
+ progname, nbytes);
+ abort();
+ }
+ data++;
+
+ for (i = 0; i < ncolors; i++)
+ {
+ const char *line = *data;
+ cmap[i].byte = *line++;
+ while (*line)
+ {
+ int r, g, b;
+ char which;
+ while (*line == ' ' || *line == '\t')
+ line++;
+ which = *line;
+ if (!which) continue; /* whitespace at end of line */
+ line++;
+ if (which != 'c' && which != 'm') {
+ fprintf (stderr, "%s: unknown XPM pixel type '%c' in \"%s\"\n",
+ progname, which, *data);
+ abort();
+ }
+ while (*line == ' ' || *line == '\t')
+ line++;
+ if (!strncasecmp(line, "None", 4))
+ {
+ r = g = b = -1;
+ line += 4;
+ }
+ else if (!strncasecmp(line, "white", 5))
+ {
+ r = g = b = 255;
+ line += 5;
+ }
+ else if (!strncasecmp(line, "black", 5))
+ {
+ r = g = b = 0;
+ line += 5;
+ }
+ else
+ {
+ if (*line != '#') {
+ fprintf (stderr, "%s: unparsable XPM color spec: \"%s\"\n",
+ progname, line);
+ abort();
+ }
+ if (*line == '#')
+ line++;
+ r = (hex[(int) line[0]] << 4) | hex[(int) line[1]]; line += 2;
+ g = (hex[(int) line[0]] << 4) | hex[(int) line[1]]; line += 2;
+ b = (hex[(int) line[0]] << 4) | hex[(int) line[1]]; line += 2;
+ }
+
+ if (which == 'c')
+ {
+ cmap[i].cr = r;
+ cmap[i].cg = g;
+ cmap[i].cb = b;
+ }
+ else
+ {
+ cmap[i].mr = r;
+ cmap[i].mg = g;
+ cmap[i].mb = b;
+ }
+ }
+
+ data++;
+ }
+
+ if (depth == 1) transparent_color = 1;
+
+ pixels = (unsigned long *) calloc (ncolors+1, sizeof(*pixels));
+ pixel_count = 0;
+ for (i = 0; i < ncolors; i++)
+ {
+ if (cmap[i].cr == -1) /* transparent */
+ {
+ rmap[(int) cmap[i].byte] = 255;
+ }
+ else
+ {
+ XColor color;
+ color.flags = DoRed|DoGreen|DoBlue;
+ color.red = (cmap[i].cr << 8) | cmap[i].cr;
+ color.green = (cmap[i].cg << 8) | cmap[i].cg;
+ color.blue = (cmap[i].cb << 8) | cmap[i].cb;
+ if (depth == 1 ||
+ !XAllocColor (dpy, colormap, &color))
+ {
+ color.red = (cmap[i].mr << 8) | cmap[i].mr;
+ color.green = (cmap[i].mg << 8) | cmap[i].mg;
+ color.blue = (cmap[i].mb << 8) | cmap[i].mb;
+ if (!XAllocColor (dpy, colormap, &color)) {
+ fprintf (stderr, "%s: unable to allocate XPM color\n",
+ progname);
+ abort();
+ }
+ }
+ pixels[pixel_count] = color.pixel;
+ rmap[(int) cmap[i].byte] = pixel_count;
+ pixel_count++;
+ }
+ }
+
+ ximage = XCreateImage (dpy, visual, depth,
+ (depth == 1 ? XYBitmap : ZPixmap),
+ 0, 0, w, h, 8, 0);
+ if (! ximage)
+ {
+ if (pixels) free (pixels);
+ return 0;
+ }
+
+ ximage->bitmap_bit_order =
+ ximage->byte_order =
+ (bigendian() ? MSBFirst : LSBFirst);
+
+ ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
+ if (!ximage->data)
+ {
+ XDestroyImage (ximage);
+ if (pixels) free (pixels);
+ return 0;
+ }
+
+ w8 = (w + 7) / 8;
+ if (mask_ret)
+ {
+ int s = (w8 * h) + 1;
+ *mask_ret = (unsigned char *) malloc (s);
+ if (!*mask_ret)
+ mask_ret = 0;
+ else
+ memset (*mask_ret, 255, s);
+ }
+
+ for (y = 0; y < h; y++)
+ {
+ const char *line = *data++;
+ for (x = 0; x < w; x++)
+ {
+ int p = rmap[(int) *line];
+ line++;
+ XPutPixel (ximage, x, y, (p == 255 ? transparent_color : pixels[p]));
+
+ if (p == 255 && mask_ret)
+ (*mask_ret)[(y * w8) + (x >> 3)] &= (~(1 << (x & 7)));
+ }
+ }
+
+ *width_ret = w;
+ *height_ret = h;
+ *pixels_ret = pixels;
+ *npixels_ret = pixel_count;
+ return ximage;
+}