1/*
2
3Copyright 1987, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28
29/*
30 *	Code to read bitmaps from disk files. Interprets
31 *	data from X10 and X11 bitmap files and creates
32 *	Pixmap representations of files. Returns Pixmap
33 *	ID and specifics about image.
34 *
35 *	Modified for speedup by Jim Becker, changed image
36 *	data parsing logic (removed some fscanf()s).
37 *	Aug 5, 1988
38 *
39 * Note that this file and ../Xmu/RdBitF.c look very similar....  Keep them
40 * that way (but don't use common source code so that people can have one
41 * without the other).
42 */
43
44#ifdef HAVE_CONFIG_H
45#include <config.h>
46#endif
47#include "Xlibint.h"
48#include <X11/Xos.h>
49#include "Xutil.h"
50#include <stdio.h>
51#include <ctype.h>
52#include "reallocarray.h"
53
54#define MAX_SIZE 255
55
56/* shared data for the image read/parse logic */
57static const short hexTable[256] = {
58    ['0'] = 0,  ['1'] = 1,
59    ['2'] = 2,  ['3'] = 3,
60    ['4'] = 4,  ['5'] = 5,
61    ['6'] = 6,  ['7'] = 7,
62    ['8'] = 8,  ['9'] = 9,
63    ['A'] = 10, ['B'] = 11,
64    ['C'] = 12, ['D'] = 13,
65    ['E'] = 14, ['F'] = 15,
66    ['a'] = 10, ['b'] = 11,
67    ['c'] = 12, ['d'] = 13,
68    ['e'] = 14, ['f'] = 15,
69
70    [' '] = -1, [','] = -1,
71    ['}'] = -1, ['\n'] = -1,
72    ['\t'] = -1
73};
74
75/*
76 *	read next hex value in the input stream, return -1 if EOF
77 */
78static int
79NextInt (
80    FILE *fstream)
81{
82    int	ch;
83    int	value = 0;
84    int gotone = 0;
85    int done = 0;
86
87    /* loop, accumulate hex value until find delimiter  */
88    /* skip any initial delimiters found in read stream */
89
90    while (!done) {
91	ch = getc(fstream);
92	if (ch == EOF) {
93	    value	= -1;
94	    done++;
95	} else {
96	    /* trim high bits, check type and accumulate */
97	    ch &= 0xff;
98	    if (isascii(ch) && isxdigit(ch)) {
99		value = (value << 4) + hexTable[ch];
100		gotone++;
101	    } else if ((hexTable[ch]) < 0 && gotone)
102	      done++;
103	}
104    }
105    return value;
106}
107
108int
109XReadBitmapFileData (
110    _Xconst char *filename,
111    unsigned int *width,                /* RETURNED */
112    unsigned int *height,               /* RETURNED */
113    unsigned char **data,               /* RETURNED */
114    int *x_hot,                         /* RETURNED */
115    int *y_hot)                         /* RETURNED */
116{
117    FILE *fstream;			/* handle on file  */
118    unsigned char *bits = NULL;		/* working variable */
119    char line[MAX_SIZE];		/* input line from file */
120    int size;				/* number of bytes of data */
121    char name_and_type[MAX_SIZE];	/* an input line */
122    char *type;				/* for parsing */
123    int value;				/* from an input line */
124    int version10p;			/* boolean, old format */
125    int padding;			/* to handle alignment */
126    int bytes_per_line;			/* per scanline of data */
127    unsigned int ww = 0;		/* width */
128    unsigned int hh = 0;		/* height */
129    int hx = -1;			/* x hotspot */
130    int hy = -1;			/* y hotspot */
131
132    if (!(fstream = fopen(filename, "r")))
133	return BitmapOpenFailed;
134
135    /* error cleanup and return macro	*/
136#define	RETURN(code) \
137    do { Xfree (bits); fclose (fstream); return code; } while (0)
138
139    while (fgets(line, MAX_SIZE, fstream)) {
140	if (strlen(line) == MAX_SIZE-1)
141	    RETURN (BitmapFileInvalid);
142	if (sscanf(line,"#define %s %d",name_and_type,&value) == 2) {
143	    if (!(type = strrchr(name_and_type, '_')))
144	      type = name_and_type;
145	    else
146	      type++;
147
148	    if (!strcmp("width", type))
149	      ww = (unsigned int) value;
150	    if (!strcmp("height", type))
151	      hh = (unsigned int) value;
152	    if (!strcmp("hot", type)) {
153		if (type-- == name_and_type || type-- == name_and_type)
154		  continue;
155		if (!strcmp("x_hot", type))
156		  hx = value;
157		if (!strcmp("y_hot", type))
158		  hy = value;
159	    }
160	    continue;
161	}
162
163	if (sscanf(line, "static short %s = {", name_and_type) == 1)
164	  version10p = 1;
165	else if (sscanf(line,"static unsigned char %s = {",name_and_type) == 1)
166	  version10p = 0;
167	else if (sscanf(line, "static char %s = {", name_and_type) == 1)
168	  version10p = 0;
169	else
170	  continue;
171
172	if (!(type = strrchr(name_and_type, '_')))
173	  type = name_and_type;
174	else
175	  type++;
176
177	if (strcmp("bits[]", type))
178	  continue;
179
180	if (!ww || !hh)
181	  RETURN (BitmapFileInvalid);
182
183	if ((ww % 16) && ((ww % 16) < 9) && version10p)
184	  padding = 1;
185	else
186	  padding = 0;
187
188	bytes_per_line = (ww+7)/8 + padding;
189
190	bits = Xmallocarray (hh, bytes_per_line);
191	if (!bits)
192	  RETURN (BitmapNoMemory);
193	size = bytes_per_line * hh;
194
195	if (version10p) {
196	    unsigned char *ptr;
197	    int bytes;
198
199	    for (bytes=0, ptr=bits; bytes<size; (bytes += 2)) {
200		if ((value = NextInt(fstream)) < 0)
201		  RETURN (BitmapFileInvalid);
202		*(ptr++) = value;
203		if (!padding || ((bytes+2) % bytes_per_line))
204		  *(ptr++) = value >> 8;
205	    }
206	} else {
207	    unsigned char *ptr;
208	    int bytes;
209
210	    for (bytes=0, ptr=bits; bytes<size; bytes++, ptr++) {
211		if ((value = NextInt(fstream)) < 0)
212		  RETURN (BitmapFileInvalid);
213		*ptr=value;
214	    }
215	}
216
217	/* If we got to this point, we read a full bitmap file. Break so we don't
218	 * start reading another one from the same file and leak the memory
219	 * allocated for the previous one. */
220	break;
221    }					/* end while */
222
223    fclose(fstream);
224    if (!bits)
225	return (BitmapFileInvalid);
226
227    *data = bits;
228    *width = ww;
229    *height = hh;
230    if (x_hot) *x_hot = hx;
231    if (y_hot) *y_hot = hy;
232
233    return (BitmapSuccess);
234}
235
236int
237XReadBitmapFile (
238    Display *display,
239    Drawable d,
240    _Xconst char *filename,
241    unsigned int *width,                /* RETURNED */
242    unsigned int *height,               /* RETURNED */
243    Pixmap *pixmap,                     /* RETURNED */
244    int *x_hot,                         /* RETURNED */
245    int *y_hot)                         /* RETURNED */
246{
247    unsigned char *data;
248    int res;
249
250    res = XReadBitmapFileData(filename, width, height, &data, x_hot, y_hot);
251    if (res != BitmapSuccess)
252	return res;
253    *pixmap = XCreateBitmapFromData(display, d, (char *)data, *width, *height);
254    Xfree(data);
255    if (*pixmap == None)
256	return (BitmapNoMemory);
257    return (BitmapSuccess);
258}
259