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