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