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