899113ba5791e57397c44d7aa7b5747d2786e988
[platform/upstream/libXmu.git] / src / RdBitF.c
1 /*
2
3 Copyright 1988, 1998  The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
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 THE
17 OPEN GROUP 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 The Open Group 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 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  */
66 static void initHexTable(void);
67 static int NextInt(FILE*);
68
69 /* shared data for the image read/parse logic */
70 static short hexTable[256];             /* conversion value */
71 static 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  */
78 static void
79 initHexTable(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  */
112 static int
113 NextInt(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  */
148 int
149 XmuReadBitmapData(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)
271 static int
272 access_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
287 static int
288 AccessFile(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
361 FILE *
362 fopen_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
384 int
385 XmuReadBitmapDataFromFile(_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 }