RdBitF.c revision e120bd27
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#ifdef __UNIXOS2__
307    if (!drive)
308	drive = getenv ("X11ROOT");
309#endif
310    if (!drive)
311	drive = "C:";
312    len = strlen (drive) + strlen (path);
313    if (len < MAX_PATH) bufp = buf;
314    else bufp = malloc (len + 1);
315    strcpy (bufp, drive);
316    strcat (bufp, path);
317    if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
318	if (bufp != buf) free (bufp);
319	return 1;
320    }
321
322#ifndef __UNIXOS2__
323    /* one last place to look */
324    drive = getenv ("HOMEDRIVE");
325    if (drive) {
326	len = strlen (drive) + strlen (path);
327	if (len < MAX_PATH) bufp = buf;
328	else bufp = malloc (len + 1);
329	strcpy (bufp, drive);
330	strcat (bufp, path);
331	if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
332	    if (bufp != buf) free (bufp);
333	    return 1;
334	}
335    }
336
337    /* does OS/2 (with or with gcc-emx) have getdrives? */
338    /* tried everywhere else, go fishing */
339#define C_DRIVE ('C' - 'A')
340#define Z_DRIVE ('Z' - 'A')
341    drives = _getdrives ();
342    for (i = C_DRIVE; i <= Z_DRIVE; i++) { /* don't check on A: or B: */
343	if ((1 << i) & drives) {
344	    len = 2 + strlen (path);
345	    if (len < MAX_PATH) bufp = buf;
346	    else bufp = malloc (len + 1);
347	    *bufp = 'A' + i;
348	    *(bufp + 1) = ':';
349	    *(bufp + 2) = '\0';
350	    strcat (bufp, path);
351	    if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
352		if (bufp != buf) free (bufp);
353		return 1;
354	    }
355	}
356    }
357#endif
358    return 0;
359}
360
361FILE *
362fopen_file(char *path, char *mode)
363{
364    char buf[MAX_PATH];
365    char* bufp;
366    void* ret = NULL;
367    UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS);
368
369    if (AccessFile (path, buf, MAX_PATH, &bufp))
370	ret = fopen (bufp, mode);
371
372    (void) SetErrorMode (olderror);
373
374    if (bufp != buf) free (bufp);
375
376    return ret;
377}
378
379#else
380#define fopen_file fopen
381#endif
382
383
384int
385XmuReadBitmapDataFromFile(_Xconst char *filename, unsigned int *width,
386			       unsigned int *height, unsigned char **datap,
387			       int *x_hot, int *y_hot)
388{
389    FILE *fstream;
390    int status;
391
392#ifdef __UNIXOS2__
393    filename = __XOS2RedirRoot(filename);
394#endif
395    if ((fstream = fopen_file (filename, "r")) == NULL) {
396	return BitmapOpenFailed;
397    }
398    status = XmuReadBitmapData(fstream, width, height, datap, x_hot, y_hot);
399    fclose (fstream);
400    return status;
401}
402