RdBitF.c revision 9d0b5e55
1/*
2
3Copyright 1988, 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 in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25*/
26
27/*
28 * This file contains miscellaneous utility routines and is not part of the
29 * Xlib standard.
30 *
31 * Public entry points:
32 *
33 *     XmuReadBitmapData		read data from FILE descriptor
34 *     XmuReadBitmapDataFromFile	read X10 or X11 format bitmap files
35 *					and return data
36 *
37 * Note that this file and ../X/XRdBitF.c look very similar....  Keep them
38 * that way (but don't use common source code so that people can have one
39 * without the other).
40 */
41
42
43/*
44 * Based on an optimized version provided by Jim Becker, Auguest 5, 1988.
45 */
46
47#ifdef HAVE_CONFIG_H
48#include <config.h>
49#endif
50#include <X11/Xos.h>
51#include <X11/Xlib.h>
52#include <X11/Xutil.h>
53#include <X11/Xlibint.h>
54#include <stdio.h>
55#include <ctype.h>
56#include <X11/Xmu/Drawing.h>
57#ifdef WIN32
58#include <X11/Xwindows.h>
59#endif
60
61#define MAX_SIZE 255
62
63/*
64 * Prototypes
65 */
66static void initHexTable(void);
67static int NextInt(FILE*);
68
69/* shared data for the image read/parse logic */
70static short hexTable[256];		/* conversion value */
71static Bool initialized = False;	/* easier to fill in at run time */
72
73
74/*
75 *	Table index for the hex values. Initialized once, first time.
76 *	Used for translation value or delimiter significance lookup.
77 */
78static void
79initHexTable(void)
80{
81    /*
82     * We build the table at run time for several reasons:
83     *
84     *     1.  portable to non-ASCII machines.
85     *     2.  still reentrant since we set the init flag after setting table.
86     *     3.  easier to extend.
87     *     4.  less prone to bugs.
88     */
89    hexTable['0'] = 0;	hexTable['1'] = 1;
90    hexTable['2'] = 2;	hexTable['3'] = 3;
91    hexTable['4'] = 4;	hexTable['5'] = 5;
92    hexTable['6'] = 6;	hexTable['7'] = 7;
93    hexTable['8'] = 8;	hexTable['9'] = 9;
94    hexTable['A'] = 10;	hexTable['B'] = 11;
95    hexTable['C'] = 12;	hexTable['D'] = 13;
96    hexTable['E'] = 14;	hexTable['F'] = 15;
97    hexTable['a'] = 10;	hexTable['b'] = 11;
98    hexTable['c'] = 12;	hexTable['d'] = 13;
99    hexTable['e'] = 14;	hexTable['f'] = 15;
100
101    /* delimiters of significance are flagged w/ negative value */
102    hexTable[' '] = -1;	hexTable[','] = -1;
103    hexTable['}'] = -1;	hexTable['\n'] = -1;
104    hexTable['\t'] = -1;
105
106    initialized = True;
107}
108
109/*
110 *	read next hex value in the input stream, return -1 if EOF
111 */
112static int
113NextInt(FILE *fstream)
114{
115    int	ch;
116    int	value = 0;
117    int gotone = 0;
118    int done = 0;
119
120    /* loop, accumulate hex value until find delimiter  */
121    /* skip any initial delimiters found in read stream */
122
123    while (!done) {
124	ch = getc(fstream);
125	if (ch == EOF) {
126	    value	= -1;
127	    done++;
128	} else {
129	    /* trim high bits, check type and accumulate */
130	    ch &= 0xff;
131	    if (isascii(ch) && isxdigit(ch)) {
132		value = (value << 4) + hexTable[ch];
133		gotone++;
134	    } else if ((hexTable[ch]) < 0 && gotone)
135	      done++;
136	}
137    }
138    return value;
139}
140
141
142/*
143 * The data returned by the following routine is always in left-most byte
144 * first and left-most bit first.  If it doesn't return BitmapSuccess then
145 * its arguments won't have been touched.  This routine should look as much
146 * like the Xlib routine XReadBitmapfile as possible.
147 */
148int
149XmuReadBitmapData(FILE *fstream, unsigned int *width, unsigned int *height,
150		  unsigned char **datap, int *x_hot, int *y_hot)
151{
152    unsigned char *data = NULL;		/* working variable */
153    char line[MAX_SIZE];		/* input line from file */
154    int size;				/* number of bytes of data */
155    char name_and_type[MAX_SIZE];	/* an input line */
156    char *type;				/* for parsing */
157    int value;				/* from an input line */
158    int version10p;			/* boolean, old format */
159    int padding;			/* to handle alignment */
160    int bytes_per_line;			/* per scanline of data */
161    unsigned int ww = 0;		/* width */
162    unsigned int hh = 0;		/* height */
163    int hx = -1;			/* x hotspot */
164    int hy = -1;			/* y hotspot */
165
166#undef  Xmalloc /* see MALLOC_0_RETURNS_NULL in Xlibint.h */
167#define Xmalloc(size) malloc(size)
168
169    /* first time initialization */
170    if (initialized == False) initHexTable();
171
172    /* error cleanup and return macro	*/
173#define	RETURN(code) { if (data) free (data); return code; }
174
175    while (fgets(line, MAX_SIZE, fstream)) {
176	if (strlen(line) == MAX_SIZE-1) {
177	    RETURN (BitmapFileInvalid);
178	}
179	if (sscanf(line,"#define %s %d",name_and_type,&value) == 2) {
180	    if (!(type = strrchr(name_and_type, '_')))
181	      type = name_and_type;
182	    else
183	      type++;
184
185	    if (!strcmp("width", type))
186	      ww = (unsigned int) value;
187	    if (!strcmp("height", type))
188	      hh = (unsigned int) value;
189	    if (!strcmp("hot", type)) {
190		if (type-- == name_and_type || type-- == name_and_type)
191		  continue;
192		if (!strcmp("x_hot", type))
193		  hx = value;
194		if (!strcmp("y_hot", type))
195		  hy = value;
196	    }
197	    continue;
198	}
199
200	if (sscanf(line, "static short %s = {", name_and_type) == 1)
201	  version10p = 1;
202	else if (sscanf(line,"static unsigned char %s = {",name_and_type) == 1)
203	  version10p = 0;
204	else if (sscanf(line, "static char %s = {", name_and_type) == 1)
205	  version10p = 0;
206	else
207	  continue;
208
209	if (!(type = strrchr(name_and_type, '_')))
210	  type = name_and_type;
211	else
212	  type++;
213
214	if (strcmp("bits[]", type))
215	  continue;
216
217	if (!ww || !hh)
218	  RETURN (BitmapFileInvalid);
219
220	if ((ww % 16) && ((ww % 16) < 9) && version10p)
221	  padding = 1;
222	else
223	  padding = 0;
224
225	bytes_per_line = (ww+7)/8 + padding;
226
227	size = bytes_per_line * hh;
228	data = (unsigned char *) Xmalloc ((unsigned int) size);
229	if (!data)
230	  RETURN (BitmapNoMemory);
231
232	if (version10p) {
233	    unsigned char *ptr;
234	    int bytes;
235
236	    for (bytes=0, ptr=data; bytes<size; (bytes += 2)) {
237		if ((value = NextInt(fstream)) < 0)
238		  RETURN (BitmapFileInvalid);
239		*(ptr++) = value;
240		if (!padding || ((bytes+2) % bytes_per_line))
241		  *(ptr++) = value >> 8;
242	    }
243	} else {
244	    unsigned char *ptr;
245	    int bytes;
246
247	    for (bytes=0, ptr=data; bytes<size; bytes++, ptr++) {
248		if ((value = NextInt(fstream)) < 0)
249		  RETURN (BitmapFileInvalid);
250		*ptr=value;
251	    }
252	}
253	break;
254    }					/* end while */
255
256    if (data == NULL) {
257	RETURN (BitmapFileInvalid);
258    }
259
260    *datap = data;
261    data = NULL;
262    *width = ww;
263    *height = hh;
264    if (x_hot) *x_hot = hx;
265    if (y_hot) *y_hot = hy;
266
267    RETURN (BitmapSuccess);
268}
269
270#if defined(WIN32)
271static int
272access_file(char *path, char *pathbuf, int len_pathbuf, char **pathret)
273{
274    if (access (path, F_OK) == 0) {
275	if (strlen (path) < len_pathbuf)
276	    *pathret = pathbuf;
277	else
278	    *pathret = malloc (strlen (path) + 1);
279	if (*pathret) {
280	    strcpy (*pathret, path);
281	    return 1;
282	}
283    }
284    return 0;
285}
286
287static int
288AccessFile(char *path, char *pathbuf, int len_pathbuf, char **pathret)
289{
290#ifndef MAX_PATH
291#define MAX_PATH 512
292#endif
293
294    unsigned long drives;
295    int i, len;
296    char* drive;
297    char buf[MAX_PATH];
298    char* bufp;
299
300    /* just try the "raw" name first and see if it works */
301    if (access_file (path, pathbuf, len_pathbuf, pathret))
302	return 1;
303
304    /* try the places set in the environment */
305    drive = getenv ("_XBASEDRIVE");
306    if (!drive)
307	drive = "C:";
308    len = strlen (drive) + strlen (path);
309    if (len < MAX_PATH) bufp = buf;
310    else bufp = malloc (len + 1);
311    strcpy (bufp, drive);
312    strcat (bufp, path);
313    if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
314	if (bufp != buf) free (bufp);
315	return 1;
316    }
317
318    /* one last place to look */
319    drive = getenv ("HOMEDRIVE");
320    if (drive) {
321	len = strlen (drive) + strlen (path);
322	if (len < MAX_PATH) bufp = buf;
323	else bufp = malloc (len + 1);
324	strcpy (bufp, drive);
325	strcat (bufp, path);
326	if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
327	    if (bufp != buf) free (bufp);
328	    return 1;
329	}
330    }
331
332    /* does OS/2 (with or with gcc-emx) have getdrives? */
333    /* tried everywhere else, go fishing */
334#define C_DRIVE ('C' - 'A')
335#define Z_DRIVE ('Z' - 'A')
336    drives = _getdrives ();
337    for (i = C_DRIVE; i <= Z_DRIVE; i++) { /* don't check on A: or B: */
338	if ((1 << i) & drives) {
339	    len = 2 + strlen (path);
340	    if (len < MAX_PATH) bufp = buf;
341	    else bufp = malloc (len + 1);
342	    *bufp = 'A' + i;
343	    *(bufp + 1) = ':';
344	    *(bufp + 2) = '\0';
345	    strcat (bufp, path);
346	    if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
347		if (bufp != buf) free (bufp);
348		return 1;
349	    }
350	}
351    }
352    return 0;
353}
354
355FILE *
356fopen_file(char *path, char *mode)
357{
358    char buf[MAX_PATH];
359    char* bufp;
360    void* ret = NULL;
361    UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS);
362
363    if (AccessFile (path, buf, MAX_PATH, &bufp))
364	ret = fopen (bufp, mode);
365
366    (void) SetErrorMode (olderror);
367
368    if (bufp != buf) free (bufp);
369
370    return ret;
371}
372
373#else
374#define fopen_file fopen
375#endif
376
377
378int
379XmuReadBitmapDataFromFile(_Xconst char *filename, unsigned int *width,
380			       unsigned int *height, unsigned char **datap,
381			       int *x_hot, int *y_hot)
382{
383    FILE *fstream;
384    int status;
385
386    if ((fstream = fopen_file (filename, "r")) == NULL) {
387	return BitmapOpenFailed;
388    }
389    status = XmuReadBitmapData(fstream, width, height, datap, x_hot, y_hot);
390    fclose (fstream);
391    return status;
392}
393