1 /*
2  * Copyright (C) 1989-95 GROUPE BULL
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17  * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20  *
21  * Except as contained in this notice, the name of GROUPE BULL shall not be
22  * used in advertising or otherwise to promote the sale, use or other dealings
23  * in this Software without prior written authorization from GROUPE BULL.
24  */
25 
26 /*****************************************************************************\
27 * scan.c:                                                                     *
28 *                                                                             *
29 *  XPM library                                                                *
30 *  Scanning utility for XPM file format                                       *
31 *                                                                             *
32 *  Developed by Arnaud Le Hors                                                *
33 \*****************************************************************************/
34 
35 /*
36  * The code related to FOR_MSW has been added by
37  * HeDu (hedu@cul-ipn.uni-kiel.de) 4/94
38  */
39 
40 /*
41  * The code related to AMIGA has been added by
42  * Lorens Younes (d93-hyo@nada.kth.se) 4/96
43  */
44 
45 /* October 2004, source code review by Thomas Biege <thomas@suse.de> */
46 
47 #ifdef HAVE_CONFIG_H
48 #include <config.h>
49 #endif
50 #include "XpmI.h"
51 
52 #define MAXPRINTABLE 92			/* number of printable ascii chars
53 					 * minus \ and " for string compat
54 					 * and ? to avoid ANSI trigraphs. */
55 
56 static const char *printable =
57 " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjklzxcvbnmMNBVCZ\
58 ASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
59 
60 /*
61  * printable begin with a space, so in most case, due to my algorithm, when
62  * the number of different colors is less than MAXPRINTABLE, it will give a
63  * char follow by "nothing" (a space) in the readable xpm file
64  */
65 
66 
67 typedef struct {
68     Pixel *pixels;
69     unsigned int *pixelindex;
70     unsigned int size;
71     unsigned int ncolors;
72     unsigned int mask_pixel;		/* whether there is or not */
73 }      PixelsMap;
74 
75 LFUNC(storePixel, int, (Pixel pixel, PixelsMap *pmap,
76 			unsigned int *index_return));
77 
78 LFUNC(storeMaskPixel, int, (Pixel pixel, PixelsMap *pmap,
79 			    unsigned int *index_return));
80 
81 typedef int (*storeFuncPtr)(Pixel pixel, PixelsMap *pmap,
82 			    unsigned int *index_return);
83 
84 #ifndef FOR_MSW
85 # ifndef AMIGA
86 LFUNC(GetImagePixels, int, (XImage *image, unsigned int width,
87 			    unsigned int height, PixelsMap *pmap));
88 
89 LFUNC(GetImagePixels32, int, (XImage *image, unsigned int width,
90 			      unsigned int height, PixelsMap *pmap));
91 
92 LFUNC(GetImagePixels16, int, (XImage *image, unsigned int width,
93 			      unsigned int height, PixelsMap *pmap));
94 
95 LFUNC(GetImagePixels8, int, (XImage *image, unsigned int width,
96 			     unsigned int height, PixelsMap *pmap));
97 
98 LFUNC(GetImagePixels1, int, (XImage *image, unsigned int width,
99 			     unsigned int height, PixelsMap *pmap,
100 			     storeFuncPtr storeFunc));
101 # else /* AMIGA */
102 LFUNC(AGetImagePixels, int, (XImage *image, unsigned int width,
103 			     unsigned int height, PixelsMap *pmap,
104 			     storeFuncPtr storeFunc));
105 # endif/* AMIGA */
106 #else  /* ndef FOR_MSW */
107 LFUNC(MSWGetImagePixels, int, (Display *d, XImage *image, unsigned int width,
108 			       unsigned int height, PixelsMap *pmap,
109 			       storeFuncPtr storeFunc));
110 #endif
111 LFUNC(ScanTransparentColor, int, (XpmColor *color, unsigned int cpp,
112 				  XpmAttributes *attributes));
113 
114 LFUNC(ScanOtherColors, int, (Display *display, XpmColor *colors,
115 			     unsigned int ncolors,
116 			     Pixel *pixels, unsigned int mask,
117 			     unsigned int cpp, XpmAttributes *attributes));
118 
119 /*
120  * This function stores the given pixel in the given arrays which are grown
121  * if not large enough.
122  */
123 static int
storePixel(Pixel pixel,PixelsMap * pmap,unsigned int * index_return)124 storePixel(
125     Pixel		 pixel,
126     PixelsMap		*pmap,
127     unsigned int	*index_return)
128 {
129     unsigned int i;
130     Pixel *p;
131     unsigned int ncolors;
132 
133     if (*index_return) {		/* this is a transparent pixel! */
134 	*index_return = 0;
135 	return 0;
136     }
137     ncolors = pmap->ncolors;
138     p = pmap->pixels + pmap->mask_pixel;
139     for (i = pmap->mask_pixel; i < ncolors; i++, p++)
140 	if (*p == pixel)
141 	    break;
142     if (i == ncolors) {
143 	if (ncolors >= pmap->size) {
144 	    pmap->size *= 2;
145 	    p = (Pixel *) XpmRealloc(pmap->pixels, sizeof(Pixel) * pmap->size);
146 	    if (!p)
147 		return (1);
148 	    pmap->pixels = p;
149 
150 	}
151 	(pmap->pixels)[ncolors] = pixel;
152 	pmap->ncolors++;
153     }
154     *index_return = i;
155     return 0;
156 }
157 
158 static int
storeMaskPixel(Pixel pixel,PixelsMap * pmap,unsigned int * index_return)159 storeMaskPixel(
160     Pixel		 pixel,
161     PixelsMap		*pmap,
162     unsigned int	*index_return)
163 {
164     if (!pixel) {
165 	if (!pmap->ncolors) {
166 	    pmap->ncolors = 1;
167 	    (pmap->pixels)[0] = 0;
168 	    pmap->mask_pixel = 1;
169 	}
170 	*index_return = 1;
171     } else
172 	*index_return = 0;
173     return 0;
174 }
175 
176 /* function call in case of error */
177 #undef RETURN
178 #define RETURN(status) \
179 do { \
180       ErrorStatus = status; \
181       goto error; \
182 } while(0)
183 
184 /*
185  * This function scans the given image and stores the found informations in
186  * the given XpmImage structure.
187  */
188 int
XpmCreateXpmImageFromImage(Display * display,XImage * image,XImage * shapeimage,XpmImage * xpmimage,XpmAttributes * attributes)189 XpmCreateXpmImageFromImage(
190     Display		*display,
191     XImage		*image,
192     XImage		*shapeimage,
193     XpmImage		*xpmimage,
194     XpmAttributes	*attributes)
195 {
196     /* variables stored in the XpmAttributes structure */
197     unsigned int cpp;
198 
199     /* variables to return */
200     PixelsMap pmap;
201     XpmColor *colorTable = NULL;
202     int ErrorStatus = 0;
203 
204     /* calculation variables */
205     unsigned int width = 0;
206     unsigned int height = 0;
207     unsigned int cppm;			/* minimum chars per pixel */
208     unsigned int c;
209 
210     /* initialize pmap */
211     pmap.pixels = NULL;
212     pmap.pixelindex = NULL;
213     pmap.size = 256;			/* should be enough most of the time */
214     pmap.ncolors = 0;
215     pmap.mask_pixel = 0;
216 
217     /*
218      * get geometry
219      */
220     if (image) {
221 	width = image->width;
222 	height = image->height;
223     } else if (shapeimage) {
224 	width = shapeimage->width;
225 	height = shapeimage->height;
226     }
227 
228     /*
229      * retrieve information from the XpmAttributes
230      */
231     if (attributes && (attributes->valuemask & XpmCharsPerPixel
232 /* 3.2 backward compatibility code */
233 		       || attributes->valuemask & XpmInfos))
234 /* end 3.2 bc */
235 	cpp = attributes->cpp;
236     else
237 	cpp = 0;
238 
239     if ((height > 0 && width >= UINT_MAX / height) ||
240 	width * height >= UINT_MAX / sizeof(unsigned int))
241 	RETURN(XpmNoMemory);
242     pmap.pixelindex =
243 	(unsigned int *) XpmCalloc(width * height, sizeof(unsigned int));
244     if (!pmap.pixelindex)
245 	RETURN(XpmNoMemory);
246 
247     if (pmap.size >= UINT_MAX / sizeof(Pixel))
248 	RETURN(XpmNoMemory);
249 
250     pmap.pixels = (Pixel *) XpmMalloc(sizeof(Pixel) * pmap.size);
251     if (!pmap.pixels)
252 	RETURN(XpmNoMemory);
253 
254     /*
255      * scan shape mask if any
256      */
257     if (shapeimage) {
258 #ifndef FOR_MSW
259 # ifndef AMIGA
260 	ErrorStatus = GetImagePixels1(shapeimage, width, height, &pmap,
261 				      storeMaskPixel);
262 # else
263 	ErrorStatus = AGetImagePixels(shapeimage, width, height, &pmap,
264 				      storeMaskPixel);
265 # endif
266 #else
267 	ErrorStatus = MSWGetImagePixels(display, shapeimage, width, height,
268 					&pmap, storeMaskPixel);
269 #endif
270 	if (ErrorStatus != XpmSuccess)
271 	    RETURN(ErrorStatus);
272     }
273 
274     /*
275      * scan the image data
276      *
277      * In case depth is 1 or bits_per_pixel is 4, 6, 8, 24 or 32 use optimized
278      * functions, otherwise use slower but sure general one.
279      *
280      */
281 
282     if (image) {
283 #ifndef FOR_MSW
284 # ifndef AMIGA
285 	if (((image->bits_per_pixel | image->depth) == 1)  &&
286 	    (image->byte_order == image->bitmap_bit_order))
287 	    ErrorStatus = GetImagePixels1(image, width, height, &pmap,
288 					  storePixel);
289 	else if (image->format == ZPixmap) {
290 	    if (image->bits_per_pixel == 8)
291 		ErrorStatus = GetImagePixels8(image, width, height, &pmap);
292 	    else if (image->bits_per_pixel == 16)
293 		ErrorStatus = GetImagePixels16(image, width, height, &pmap);
294 	    else if (image->bits_per_pixel == 32)
295 		ErrorStatus = GetImagePixels32(image, width, height, &pmap);
296 	} else
297 	    ErrorStatus = GetImagePixels(image, width, height, &pmap);
298 # else
299 	ErrorStatus = AGetImagePixels(image, width, height, &pmap,
300 				      storePixel);
301 # endif
302 #else
303 	ErrorStatus = MSWGetImagePixels(display, image, width, height, &pmap,
304 					storePixel);
305 #endif
306 	if (ErrorStatus != XpmSuccess)
307 	    RETURN(ErrorStatus);
308     }
309 
310     /*
311      * get rgb values and a string of char, and possibly a name for each
312      * color
313      */
314     if (pmap.ncolors >= UINT_MAX / sizeof(XpmColor))
315 	RETURN(XpmNoMemory);
316     colorTable = (XpmColor *) XpmCalloc(pmap.ncolors, sizeof(XpmColor));
317     if (!colorTable)
318 	RETURN(XpmNoMemory);
319 
320     /* compute the minimal cpp */
321     for (cppm = 1, c = MAXPRINTABLE; pmap.ncolors > c; cppm++)
322 	c *= MAXPRINTABLE;
323     if (cpp < cppm)
324 	cpp = cppm;
325 
326     if (pmap.mask_pixel) {
327 	ErrorStatus = ScanTransparentColor(colorTable, cpp, attributes);
328 	if (ErrorStatus != XpmSuccess)
329 	    RETURN(ErrorStatus);
330     }
331 
332     ErrorStatus = ScanOtherColors(display, colorTable, pmap.ncolors,
333 				  pmap.pixels, pmap.mask_pixel, cpp,
334 				  attributes);
335     if (ErrorStatus != XpmSuccess)
336 	RETURN(ErrorStatus);
337 
338     /*
339      * store found informations in the XpmImage structure
340      */
341     xpmimage->width = width;
342     xpmimage->height = height;
343     xpmimage->cpp = cpp;
344     xpmimage->ncolors = pmap.ncolors;
345     xpmimage->colorTable = colorTable;
346     xpmimage->data = pmap.pixelindex;
347 
348     XpmFree(pmap.pixels);
349     return (XpmSuccess);
350 
351 /* exit point in case of error, free only locally allocated variables */
352 error:
353     if (pmap.pixelindex)
354 	XpmFree(pmap.pixelindex);
355     if (pmap.pixels)
356 	XpmFree(pmap.pixels);
357     if (colorTable)
358 	xpmFreeColorTable(colorTable, pmap.ncolors);
359 
360     return (ErrorStatus);
361 }
362 
363 static int
ScanTransparentColor(XpmColor * color,unsigned int cpp,XpmAttributes * attributes)364 ScanTransparentColor(
365     XpmColor		*color,
366     unsigned int	 cpp,
367     XpmAttributes	*attributes)
368 {
369     char *s;
370     unsigned int a, b, c;
371 
372     /* first get a character string */
373     a = 0;
374     if (cpp >= UINT_MAX - 1)
375 	return (XpmNoMemory);
376     if (!(s = color->string = (char *) XpmMalloc(cpp + 1)))
377 	return (XpmNoMemory);
378     *s++ = printable[c = a % MAXPRINTABLE];
379     for (b = 1; b < cpp; b++, s++)
380 	*s = printable[c = ((a - c) / MAXPRINTABLE) % MAXPRINTABLE];
381     *s = '\0';
382 
383     /* then retreive related info from the attributes if any */
384     if (attributes && (attributes->valuemask & XpmColorTable
385 /* 3.2 backward compatibility code */
386 		       || attributes->valuemask & XpmInfos)
387 /* end 3.2 bc */
388 	&& attributes->mask_pixel != XpmUndefPixel) {
389 
390 	unsigned int key;
391 	char **defaults = (char **) color;
392 	char **mask_defaults;
393 
394 /* 3.2 backward compatibility code */
395 	if (attributes->valuemask & XpmColorTable)
396 /* end 3.2 bc */
397 	    mask_defaults = (char **) (
398 		attributes->colorTable + attributes->mask_pixel);
399 /* 3.2 backward compatibility code */
400 	else
401 	    mask_defaults = (char **)
402 		((XpmColor **) attributes->colorTable)[attributes->mask_pixel];
403 /* end 3.2 bc */
404 	for (key = 1; key <= NKEYS; key++) {
405 	    if ((s = mask_defaults[key])) {
406 		defaults[key] = (char *) xpmstrdup(s);
407 		if (!defaults[key])
408 		    return (XpmNoMemory);
409 	    }
410 	}
411     } else {
412 	color->c_color = (char *) xpmstrdup(TRANSPARENT_COLOR);
413 	if (!color->c_color)
414 	    return (XpmNoMemory);
415     }
416     return (XpmSuccess);
417 }
418 
419 static int
ScanOtherColors(Display * display,XpmColor * colors,unsigned int ncolors,Pixel * pixels,unsigned int mask,unsigned int cpp,XpmAttributes * attributes)420 ScanOtherColors(
421     Display		*display,
422     XpmColor		*colors,
423     unsigned int	 ncolors,
424     Pixel		*pixels,
425     unsigned int	 mask,
426     unsigned int	 cpp,
427     XpmAttributes	*attributes)
428 {
429     /* variables stored in the XpmAttributes structure */
430     Colormap colormap;
431     char *rgb_fname;
432 
433 #ifndef FOR_MSW
434     xpmRgbName rgbn[MAX_RGBNAMES];
435 #else
436     xpmRgbName *rgbn = NULL;
437 #endif
438     int rgbn_max = 0;
439     unsigned int i, j, c, i2;
440     XpmColor *color;
441     XColor *xcolors = NULL, *xcolor;
442     char *colorname, *s;
443     XpmColor *colorTable = NULL, **oldColorTable = NULL;
444     unsigned int ancolors = 0;
445     Pixel *apixels = NULL;
446     unsigned int mask_pixel = 0;
447     Bool found;
448 
449     /* retrieve information from the XpmAttributes */
450     if (attributes && (attributes->valuemask & XpmColormap))
451 	colormap = attributes->colormap;
452     else
453 	colormap = XDefaultColormap(display, XDefaultScreen(display));
454     if (attributes && (attributes->valuemask & XpmRgbFilename))
455 	rgb_fname = attributes->rgb_fname;
456     else
457 	rgb_fname = NULL;
458 
459     /* start from the right element */
460     if (mask) {
461 	colors++;
462 	ncolors--;
463 	pixels++;
464     }
465 
466     /* first get character strings and rgb values */
467     if (ncolors >= UINT_MAX / sizeof(XColor) || cpp >= UINT_MAX - 1)
468 	return (XpmNoMemory);
469     xcolors = (XColor *) XpmMalloc(sizeof(XColor) * ncolors);
470     if (!xcolors)
471 	return (XpmNoMemory);
472 
473     for (i = 0, i2 = mask, color = colors, xcolor = xcolors;
474 	 i < ncolors; i++, i2++, color++, xcolor++, pixels++) {
475 
476 	if (!(s = color->string = (char *) XpmMalloc(cpp + 1))) {
477 	    XpmFree(xcolors);
478 	    return (XpmNoMemory);
479 	}
480 	*s++ = printable[c = i2 % MAXPRINTABLE];
481 	for (j = 1; j < cpp; j++, s++)
482 	    *s = printable[c = ((i2 - c) / MAXPRINTABLE) % MAXPRINTABLE];
483 	*s = '\0';
484 
485 	xcolor->pixel = *pixels;
486     }
487     XQueryColors(display, colormap, xcolors, ncolors);
488 
489 #ifndef FOR_MSW
490     /* read the rgb file if any was specified */
491     if (rgb_fname)
492 	rgbn_max = xpmReadRgbNames(attributes->rgb_fname, rgbn);
493 #else
494     /* FOR_MSW: rgb names and values are hardcoded in rgbtab.h */
495     rgbn_max = xpmReadRgbNames(NULL, NULL);
496 #endif
497 
498     if (attributes && attributes->valuemask & XpmColorTable) {
499 	colorTable = attributes->colorTable;
500 	ancolors = attributes->ncolors;
501 	apixels = attributes->pixels;
502 	mask_pixel = attributes->mask_pixel;
503     }
504 /* 3.2 backward compatibility code */
505     else if (attributes && attributes->valuemask & XpmInfos) {
506 	oldColorTable = (XpmColor **) attributes->colorTable;
507 	ancolors = attributes->ncolors;
508 	apixels = attributes->pixels;
509 	mask_pixel = attributes->mask_pixel;
510     }
511 /* end 3.2 bc */
512 
513     for (i = 0, color = colors, xcolor = xcolors; i < ncolors;
514 						  i++, color++, xcolor++) {
515 
516 	/* look for related info from the attributes if any */
517 	found = False;
518 	if (ancolors) {
519 	    unsigned int offset = 0;
520 
521 	    for (j = 0; j < ancolors; j++) {
522 		if (j == mask_pixel) {
523 		    offset = 1;
524 		    continue;
525 		}
526 		if (apixels[j - offset] == xcolor->pixel)
527 		    break;
528 	    }
529 	    if (j != ancolors) {
530 		unsigned int key;
531 		char **defaults = (char **) color;
532 		char **adefaults;
533 
534 /* 3.2 backward compatibility code */
535 		if (oldColorTable)
536 		    adefaults = (char **) oldColorTable[j];
537 		else
538 /* end 3.2 bc */
539 		    adefaults = (char **) (colorTable + j);
540 
541 		found = True;
542 		for (key = 1; key <= NKEYS; key++) {
543 		    if ((s = adefaults[key]))
544 			defaults[key] = (char *) xpmstrdup(s);
545 		}
546 	    }
547 	}
548 	if (!found) {
549 	    /* if nothing found look for a color name */
550 	    colorname = NULL;
551 	    if (rgbn_max)
552 		colorname = xpmGetRgbName(rgbn, rgbn_max, xcolor->red,
553 					  xcolor->green, xcolor->blue);
554 	    if (colorname)
555 		color->c_color = (char *) xpmstrdup(colorname);
556 	    else {
557 		/* at last store the rgb value */
558 		char buf[BUFSIZ];
559 #ifndef FOR_MSW
560 		sprintf(buf, "#%04X%04X%04X",
561 			xcolor->red, xcolor->green, xcolor->blue);
562 #else
563 		sprintf(buf, "#%02x%02x%02x",
564 			xcolor->red, xcolor->green, xcolor->blue);
565 #endif
566 		color->c_color = (char *) xpmstrdup(buf);
567 	    }
568 	    if (!color->c_color) {
569 		XpmFree(xcolors);
570 		xpmFreeRgbNames(rgbn, rgbn_max);
571 		return (XpmNoMemory);
572 	    }
573 	}
574     }
575 
576     XpmFree(xcolors);
577     xpmFreeRgbNames(rgbn, rgbn_max);
578     return (XpmSuccess);
579 }
580 
581 #ifndef FOR_MSW
582 # ifndef AMIGA
583 /*
584  * The functions below are written from X11R5 MIT's code (XImUtil.c)
585  *
586  * The idea is to have faster functions than the standard XGetPixel function
587  * to scan the image data. Indeed we can speed up things by suppressing tests
588  * performed for each pixel. We do exactly the same tests but at the image
589  * level.
590  */
591 
592 static unsigned long const low_bits_table[] = {
593     0x00000000, 0x00000001, 0x00000003, 0x00000007,
594     0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
595     0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
596     0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
597     0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
598     0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
599     0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
600     0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
601     0xffffffff
602 };
603 
604 /*
605  * Default method to scan pixels of an image data structure.
606  * The algorithm used is:
607  *
608  *	copy the source bitmap_unit or Zpixel into temp
609  *	normalize temp if needed
610  *	extract the pixel bits into return value
611  *
612  */
613 
614 static int
GetImagePixels(XImage * image,unsigned int width,unsigned int height,PixelsMap * pmap)615 GetImagePixels(
616     XImage		*image,
617     unsigned int	 width,
618     unsigned int	 height,
619     PixelsMap		*pmap)
620 {
621     char *src;
622     char *dst;
623     unsigned int *iptr;
624     char *data;
625     unsigned int x, y;
626     int bits, depth, ibu, ibpp, offset, i;
627     unsigned long lbt;
628     Pixel pixel, px;
629 
630     data = image->data;
631     iptr = pmap->pixelindex;
632     depth = image->depth;
633     lbt = low_bits_table[depth];
634     ibpp = image->bits_per_pixel;
635     offset = image->xoffset;
636 
637     if (image->bitmap_unit < 0)
638 	    return (XpmNoMemory);
639 
640     if ((image->bits_per_pixel | image->depth) == 1) {
641 	ibu = image->bitmap_unit;
642 	for (y = 0; y < height; y++)
643 	    for (x = 0; x < width; x++, iptr++) {
644 		src = &data[XYINDEX(x, y, image)];
645 		dst = (char *) &pixel;
646 		pixel = 0;
647 		for (i = ibu >> 3; --i >= 0;)
648 		    *dst++ = *src++;
649 		XYNORMALIZE(&pixel, image);
650 		bits = (x + offset) % ibu;
651 		pixel = ((((char *) &pixel)[bits >> 3]) >> (bits & 7)) & 1;
652 		if (ibpp != depth)
653 		    pixel &= lbt;
654 		if (storePixel(pixel, pmap, iptr))
655 		    return (XpmNoMemory);
656 	    }
657     } else if (image->format == XYPixmap) {
658 	int nbytes, bpl, j;
659 	long plane = 0;
660 	ibu = image->bitmap_unit;
661 	nbytes = ibu >> 3;
662 	bpl = image->bytes_per_line;
663 	for (y = 0; y < height; y++)
664 	    for (x = 0; x < width; x++, iptr++) {
665 		pixel = 0;
666 		plane = 0;
667 		for (i = depth; --i >= 0;) {
668 		    src = &data[XYINDEX(x, y, image) + plane];
669 		    dst = (char *) &px;
670 		    px = 0;
671 		    for (j = nbytes; --j >= 0;)
672 			*dst++ = *src++;
673 		    XYNORMALIZE(&px, image);
674 		    bits = (x + offset) % ibu;
675 		    pixel = (pixel << 1) |
676 			    (((((char *) &px)[bits >> 3]) >> (bits & 7)) & 1);
677 		    plane = plane + (bpl * height);
678 		}
679 		if (ibpp != depth)
680 		    pixel &= lbt;
681 		if (storePixel(pixel, pmap, iptr))
682 		    return (XpmNoMemory);
683 	    }
684     } else if (image->format == ZPixmap) {
685 	for (y = 0; y < height; y++)
686 	    for (x = 0; x < width; x++, iptr++) {
687 		src = &data[ZINDEX(x, y, image)];
688 		dst = (char *) &px;
689 		px = 0;
690 		for (i = (ibpp + 7) >> 3; --i >= 0;)
691 		    *dst++ = *src++;
692 		ZNORMALIZE(&px, image);
693 		pixel = 0;
694 		for (i = sizeof(unsigned long); --i >= 0;)
695 		    pixel = (pixel << 8) | ((unsigned char *) &px)[i];
696 		if (ibpp == 4) {
697 		    if (x & 1)
698 			pixel >>= 4;
699 		    else
700 			pixel &= 0xf;
701 		}
702 		if (ibpp != depth)
703 		    pixel &= lbt;
704 		if (storePixel(pixel, pmap, iptr))
705 		    return (XpmNoMemory);
706 	    }
707     } else
708 	return (XpmColorError); /* actually a bad image */
709     return (XpmSuccess);
710 }
711 
712 /*
713  * scan pixels of a 32-bits Z image data structure
714  */
715 
716 #if !defined(WORD64) && !defined(LONG64)
717 static unsigned long byteorderpixel = MSBFirst << 24;
718 #endif
719 
720 static int
GetImagePixels32(XImage * image,unsigned int width,unsigned int height,PixelsMap * pmap)721 GetImagePixels32(
722     XImage		 *image,
723     unsigned int	 width,
724     unsigned int	 height,
725     PixelsMap		*pmap)
726 {
727     unsigned char *addr;
728     unsigned char *data;
729     unsigned int *iptr;
730     unsigned int x, y;
731     unsigned long lbt;
732     Pixel pixel;
733     int depth;
734 
735     data = (unsigned char *) image->data;
736     iptr = pmap->pixelindex;
737     depth = image->depth;
738     lbt = low_bits_table[depth];
739 #if !defined(WORD64) && !defined(LONG64)
740     if (*((char *) &byteorderpixel) == image->byte_order) {
741 	for (y = 0; y < height; y++)
742 	    for (x = 0; x < width; x++, iptr++) {
743 		addr = &data[ZINDEX32(x, y, image)];
744 		pixel = *((unsigned long *) addr);
745 		if (depth != 32)
746 		    pixel &= lbt;
747 		if (storePixel(pixel, pmap, iptr))
748 		    return (XpmNoMemory);
749 	    }
750     } else
751 #endif
752     if (image->byte_order == MSBFirst)
753 	for (y = 0; y < height; y++)
754 	    for (x = 0; x < width; x++, iptr++) {
755 		addr = &data[ZINDEX32(x, y, image)];
756 		pixel = ((unsigned long) addr[0] << 24 |
757 			 (unsigned long) addr[1] << 16 |
758 			 (unsigned long) addr[2] << 8 |
759 			 addr[3]);
760 		if (depth != 32)
761 		    pixel &= lbt;
762 		if (storePixel(pixel, pmap, iptr))
763 		    return (XpmNoMemory);
764 	    }
765     else
766 	for (y = 0; y < height; y++)
767 	    for (x = 0; x < width; x++, iptr++) {
768 		addr = &data[ZINDEX32(x, y, image)];
769 		pixel = (addr[0] |
770 			 (unsigned long) addr[1] << 8 |
771 			 (unsigned long) addr[2] << 16 |
772 			 (unsigned long) addr[3] << 24);
773 		if (depth != 32)
774 		    pixel &= lbt;
775 		if (storePixel(pixel, pmap, iptr))
776 		    return (XpmNoMemory);
777 	    }
778     return (XpmSuccess);
779 }
780 
781 /*
782  * scan pixels of a 16-bits Z image data structure
783  */
784 
785 static int
GetImagePixels16(XImage * image,unsigned int width,unsigned int height,PixelsMap * pmap)786 GetImagePixels16(
787     XImage		*image,
788     unsigned int	 width,
789     unsigned int	 height,
790     PixelsMap		*pmap)
791 {
792     unsigned char *addr;
793     unsigned char *data;
794     unsigned int *iptr;
795     unsigned int x, y;
796     unsigned long lbt;
797     Pixel pixel;
798     int depth;
799 
800     data = (unsigned char *) image->data;
801     iptr = pmap->pixelindex;
802     depth = image->depth;
803     lbt = low_bits_table[depth];
804     if (image->byte_order == MSBFirst)
805 	for (y = 0; y < height; y++)
806 	    for (x = 0; x < width; x++, iptr++) {
807 		addr = &data[ZINDEX16(x, y, image)];
808 		pixel = addr[0] << 8 | addr[1];
809 		if (depth != 16)
810 		    pixel &= lbt;
811 		if (storePixel(pixel, pmap, iptr))
812 		    return (XpmNoMemory);
813 	    }
814     else
815 	for (y = 0; y < height; y++)
816 	    for (x = 0; x < width; x++, iptr++) {
817 		addr = &data[ZINDEX16(x, y, image)];
818 		pixel = addr[0] | addr[1] << 8;
819 		if (depth != 16)
820 		    pixel &= lbt;
821 		if (storePixel(pixel, pmap, iptr))
822 		    return (XpmNoMemory);
823 	    }
824     return (XpmSuccess);
825 }
826 
827 /*
828  * scan pixels of a 8-bits Z image data structure
829  */
830 
831 static int
GetImagePixels8(XImage * image,unsigned int width,unsigned int height,PixelsMap * pmap)832 GetImagePixels8(
833     XImage		*image,
834     unsigned int	 width,
835     unsigned int	 height,
836     PixelsMap		*pmap)
837 {
838     unsigned int *iptr;
839     unsigned char *data;
840     unsigned int x, y;
841     unsigned long lbt;
842     Pixel pixel;
843     int depth;
844 
845     data = (unsigned char *) image->data;
846     iptr = pmap->pixelindex;
847     depth = image->depth;
848     lbt = low_bits_table[depth];
849     for (y = 0; y < height; y++)
850 	for (x = 0; x < width; x++, iptr++) {
851 	    pixel = data[ZINDEX8(x, y, image)];
852 	    if (depth != 8)
853 		pixel &= lbt;
854 	    if (storePixel(pixel, pmap, iptr))
855 		return (XpmNoMemory);
856 	}
857     return (XpmSuccess);
858 }
859 
860 /*
861  * scan pixels of a 1-bit depth Z image data structure
862  */
863 
864 static int
GetImagePixels1(XImage * image,unsigned int width,unsigned int height,PixelsMap * pmap,storeFuncPtr storeFunc)865 GetImagePixels1(
866     XImage		*image,
867     unsigned int	 width,
868     unsigned int	 height,
869     PixelsMap		 *pmap,
870     storeFuncPtr	 storeFunc)
871 {
872     unsigned int *iptr;
873     unsigned int x, y;
874     char *data;
875     Pixel pixel;
876     int xoff, yoff, offset, bpl;
877 
878     data = image->data;
879     iptr = pmap->pixelindex;
880     offset = image->xoffset;
881     bpl = image->bytes_per_line;
882 
883     if (image->bitmap_bit_order == MSBFirst)
884 	for (y = 0; y < height; y++)
885 	    for (x = 0; x < width; x++, iptr++) {
886 		xoff = x + offset;
887 		yoff = y * bpl + (xoff >> 3);
888 		xoff &= 7;
889 		pixel = (data[yoff] & (0x80 >> xoff)) ? 1 : 0;
890 		if ((*storeFunc) (pixel, pmap, iptr))
891 		    return (XpmNoMemory);
892 	    }
893     else
894 	for (y = 0; y < height; y++)
895 	    for (x = 0; x < width; x++, iptr++) {
896 		xoff = x + offset;
897 		yoff = y * bpl + (xoff >> 3);
898 		xoff &= 7;
899 		pixel = (data[yoff] & (1 << xoff)) ? 1 : 0;
900 		if ((*storeFunc) (pixel, pmap, iptr))
901 		    return (XpmNoMemory);
902 	    }
903     return (XpmSuccess);
904 }
905 
906 # else /* AMIGA */
907 
908 #define CLEAN_UP(status) \
909 do {\
910     if (pixels) XpmFree (pixels);\
911     if (tmp_img) FreeXImage (tmp_img);\
912     return (status);\
913 } while(0)
914 
915 static int
AGetImagePixels(XImage * image,unsigned int width,unsigned int height,PixelsMap * pmap,int (* storeFunc)(Pixel,PixelsMap *,unsigned int *))916 AGetImagePixels (
917     XImage        *image,
918     unsigned int   width,
919     unsigned int   height,
920     PixelsMap     *pmap,
921     int          (*storeFunc) (Pixel, PixelsMap *, unsigned int *))
922 {
923     unsigned int   *iptr;
924     unsigned int    x, y;
925     unsigned char  *pixels;
926     XImage         *tmp_img;
927 
928     pixels = XpmMalloc ((((width+15)>>4)<<4)*sizeof (*pixels));
929     if (pixels == NULL)
930 	return XpmNoMemory;
931 
932     tmp_img = AllocXImage ((((width+15)>>4)<<4), 1, image->rp->BitMap->Depth);
933     if (tmp_img == NULL)
934 	CLEAN_UP (XpmNoMemory);
935 
936     iptr = pmap->pixelindex;
937     for (y = 0; y < height; ++y)
938     {
939 	ReadPixelLine8 (image->rp, 0, y, width, pixels, tmp_img->rp);
940 	for (x = 0; x < width; ++x, ++iptr)
941 	{
942 	    if ((*storeFunc) (pixels[x], pmap, iptr))
943 		CLEAN_UP (XpmNoMemory);
944 	}
945     }
946 
947     CLEAN_UP (XpmSuccess);
948 }
949 
950 #undef CLEAN_UP
951 
952 # endif/* AMIGA */
953 #else  /* ndef FOR_MSW */
954 static int
MSWGetImagePixels(Display * display,XImage * image,unsigned int width,unsigned int height,PixelsMap * pmap,int (* storeFunc)(Pixel,PixelsMap *,unsigned int *))955 MSWGetImagePixels(
956     Display	 *display,
957     XImage	 *image,
958     unsigned int  width,
959     unsigned int  height,
960     PixelsMap	 *pmap,
961     int		(*storeFunc) (Pixel, PixelsMap*, unsigned int *))
962 {
963     unsigned int *iptr;
964     unsigned int x, y;
965     Pixel pixel;
966 
967     iptr = pmap->pixelindex;
968 
969     SelectObject(*display, image->bitmap);
970     for (y = 0; y < height; y++) {
971 	for (x = 0; x < width; x++, iptr++) {
972 	    pixel = GetPixel(*display, x, y);
973 	    if ((*storeFunc) (pixel, pmap, iptr))
974 		return (XpmNoMemory);
975 	}
976     }
977     return (XpmSuccess);
978 }
979 
980 #endif
981 
982 #ifndef FOR_MSW
983 # ifndef AMIGA
984 int
XpmCreateXpmImageFromPixmap(Display * display,Pixmap pixmap,Pixmap shapemask,XpmImage * xpmimage,XpmAttributes * attributes)985 XpmCreateXpmImageFromPixmap(
986     Display		*display,
987     Pixmap		 pixmap,
988     Pixmap		 shapemask,
989     XpmImage		*xpmimage,
990     XpmAttributes	*attributes)
991 {
992     XImage *ximage = NULL;
993     XImage *shapeimage = NULL;
994     unsigned int width = 0;
995     unsigned int height = 0;
996     int ErrorStatus;
997 
998     /* get geometry */
999     if (attributes && attributes->valuemask & XpmSize) {
1000 	width = attributes->width;
1001 	height = attributes->height;
1002     }
1003     /* get the ximages */
1004     if (pixmap)
1005 	xpmCreateImageFromPixmap(display, pixmap, &ximage, &width, &height);
1006     if (shapemask)
1007 	xpmCreateImageFromPixmap(display, shapemask, &shapeimage,
1008 				 &width, &height);
1009 
1010     /* create the related XpmImage */
1011     ErrorStatus = XpmCreateXpmImageFromImage(display, ximage, shapeimage,
1012 					     xpmimage, attributes);
1013 
1014     /* destroy the ximages */
1015     if (ximage)
1016 	XDestroyImage(ximage);
1017     if (shapeimage)
1018 	XDestroyImage(shapeimage);
1019 
1020     return (ErrorStatus);
1021 }
1022 
1023 # endif/* not AMIGA */
1024 #endif /* ndef FOR_MSW */
1025