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, August 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 #include <direct.h> /* for _getdrives() */ 60 #endif 61 62 #ifdef O_CLOEXEC 63 #define FOPEN_CLOEXEC "e" 64 #else 65 #define FOPEN_CLOEXEC "" 66 #endif 67 68 #define MAX_SIZE 255 69 70 /* 71 * Prototypes 72 */ 73 static void initHexTable(void); 74 static int NextInt(FILE*); 75 76 /* shared data for the image read/parse logic */ 77 static short hexTable[256]; /* conversion value */ 78 static Bool initialized = False; /* easier to fill in at run time */ 79 80 81 /* 82 * Table index for the hex values. Initialized once, first time. 83 * Used for translation value or delimiter significance lookup. 84 */ 85 static void 86 initHexTable(void) 87 { 88 /* 89 * We build the table at run time for several reasons: 90 * 91 * 1. portable to non-ASCII machines. 92 * 2. still reentrant since we set the init flag after setting table. 93 * 3. easier to extend. 94 * 4. less prone to bugs. 95 */ 96 hexTable['0'] = 0; hexTable['1'] = 1; 97 hexTable['2'] = 2; hexTable['3'] = 3; 98 hexTable['4'] = 4; hexTable['5'] = 5; 99 hexTable['6'] = 6; hexTable['7'] = 7; 100 hexTable['8'] = 8; hexTable['9'] = 9; 101 hexTable['A'] = 10; hexTable['B'] = 11; 102 hexTable['C'] = 12; hexTable['D'] = 13; 103 hexTable['E'] = 14; hexTable['F'] = 15; 104 hexTable['a'] = 10; hexTable['b'] = 11; 105 hexTable['c'] = 12; hexTable['d'] = 13; 106 hexTable['e'] = 14; hexTable['f'] = 15; 107 108 /* delimiters of significance are flagged w/ negative value */ 109 hexTable[' '] = -1; hexTable[','] = -1; 110 hexTable['}'] = -1; hexTable['\n'] = -1; 111 hexTable['\t'] = -1; 112 113 initialized = True; 114 } 115 116 /* 117 * read next hex value in the input stream, return -1 if EOF 118 */ 119 static int 120 NextInt(FILE *fstream) 121 { 122 int ch; 123 int value = 0; 124 int gotone = 0; 125 int done = 0; 126 127 /* loop, accumulate hex value until find delimiter */ 128 /* skip any initial delimiters found in read stream */ 129 130 while (!done) { 131 ch = getc(fstream); 132 if (ch == EOF) { 133 value = -1; 134 done++; 135 } else { 136 /* trim high bits, check type and accumulate */ 137 ch &= 0xff; 138 if (isascii(ch) && isxdigit(ch)) { 139 value = (value << 4) + hexTable[ch]; 140 gotone++; 141 } else if ((hexTable[ch]) < 0 && gotone) 142 done++; 143 } 144 } 145 return value; 146 } 147 148 149 /* 150 * The data returned by the following routine is always in left-most byte 151 * first and left-most bit first. If it doesn't return BitmapSuccess then 152 * its arguments won't have been touched. This routine should look as much 153 * like the Xlib routine XReadBitmapFile as possible. 154 */ 155 int 156 XmuReadBitmapData(FILE *fstream, unsigned int *width, unsigned int *height, 157 unsigned char **datap, int *x_hot, int *y_hot) 158 { 159 unsigned char *data = NULL; /* working variable */ 160 char line[MAX_SIZE]; /* input line from file */ 161 int size; /* number of bytes of data */ 162 char name_and_type[MAX_SIZE]; /* an input line */ 163 char *type; /* for parsing */ 164 int value; /* from an input line */ 165 int version10p; /* boolean, old format */ 166 int padding; /* to handle alignment */ 167 int bytes_per_line; /* per scanline of data */ 168 unsigned int ww = 0; /* width */ 169 unsigned int hh = 0; /* height */ 170 int hx = -1; /* x hotspot */ 171 int hy = -1; /* y hotspot */ 172 173 #undef Xmalloc /* see MALLOC_0_RETURNS_NULL in Xlibint.h */ 174 #define Xmalloc(size) malloc(size) 175 176 /* first time initialization */ 177 if (initialized == False) initHexTable(); 178 179 /* error cleanup and return macro */ 180 #define RETURN(code) { if (data) free (data); return code; } 181 182 while (fgets(line, MAX_SIZE, fstream)) { 183 if (strlen(line) == MAX_SIZE-1) { 184 RETURN (BitmapFileInvalid); 185 } 186 if (sscanf(line,"#define %s %d",name_and_type,&value) == 2) { 187 if (!(type = strrchr(name_and_type, '_'))) 188 type = name_and_type; 189 else 190 type++; 191 192 if (!strcmp("width", type)) 193 ww = (unsigned int) value; 194 if (!strcmp("height", type)) 195 hh = (unsigned int) value; 196 if (!strcmp("hot", type)) { 197 if (type-- == name_and_type || type-- == name_and_type) 198 continue; 199 if (!strcmp("x_hot", type)) 200 hx = value; 201 if (!strcmp("y_hot", type)) 202 hy = value; 203 } 204 continue; 205 } 206 207 if (sscanf(line, "static short %s = {", name_and_type) == 1) 208 version10p = 1; 209 else if (sscanf(line,"static unsigned char %s = {",name_and_type) == 1) 210 version10p = 0; 211 else if (sscanf(line, "static char %s = {", name_and_type) == 1) 212 version10p = 0; 213 else 214 continue; 215 216 if (!(type = strrchr(name_and_type, '_'))) 217 type = name_and_type; 218 else 219 type++; 220 221 if (strcmp("bits[]", type)) 222 continue; 223 224 if (!ww || !hh) 225 RETURN (BitmapFileInvalid); 226 227 if ((ww % 16) && ((ww % 16) < 9) && version10p) 228 padding = 1; 229 else 230 padding = 0; 231 232 bytes_per_line = (ww+7)/8 + padding; 233 234 size = bytes_per_line * hh; 235 data = Xmalloc ((unsigned int) size); 236 if (!data) 237 RETURN (BitmapNoMemory); 238 239 if (version10p) { 240 unsigned char *ptr; 241 int bytes; 242 243 for (bytes=0, ptr=data; bytes<size; (bytes += 2)) { 244 if ((value = NextInt(fstream)) < 0) 245 RETURN (BitmapFileInvalid); 246 *(ptr++) = value; 247 if (!padding || ((bytes+2) % bytes_per_line)) 248 *(ptr++) = value >> 8; 249 } 250 } else { 251 unsigned char *ptr; 252 int bytes; 253 254 for (bytes=0, ptr=data; bytes<size; bytes++, ptr++) { 255 if ((value = NextInt(fstream)) < 0) 256 RETURN (BitmapFileInvalid); 257 *ptr=value; 258 } 259 } 260 break; 261 } /* end while */ 262 263 if (data == NULL) { 264 RETURN (BitmapFileInvalid); 265 } 266 267 *datap = data; 268 data = NULL; 269 *width = ww; 270 *height = hh; 271 if (x_hot) *x_hot = hx; 272 if (y_hot) *y_hot = hy; 273 274 RETURN (BitmapSuccess); 275 } 276 277 #if defined(WIN32) 278 static int 279 access_file(char *path, char *pathbuf, int len_pathbuf, char **pathret) 280 { 281 if (access (path, F_OK) == 0) { 282 if (strlen (path) < len_pathbuf) 283 *pathret = pathbuf; 284 else 285 *pathret = malloc (strlen (path) + 1); 286 if (*pathret) { 287 strcpy (*pathret, path); 288 return 1; 289 } 290 } 291 return 0; 292 } 293 294 static int 295 AccessFile(char *path, char *pathbuf, int len_pathbuf, char **pathret) 296 { 297 #ifndef MAX_PATH 298 #define MAX_PATH 512 299 #endif 300 301 unsigned long drives; 302 int i, len; 303 char* drive; 304 char buf[MAX_PATH]; 305 char* bufp; 306 307 /* just try the "raw" name first and see if it works */ 308 if (access_file (path, pathbuf, len_pathbuf, pathret)) 309 return 1; 310 311 /* try the places set in the environment */ 312 drive = getenv ("_XBASEDRIVE"); 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 /* one last place to look */ 326 drive = getenv ("HOMEDRIVE"); 327 if (drive) { 328 len = strlen (drive) + strlen (path); 329 if (len < MAX_PATH) bufp = buf; 330 else bufp = malloc (len + 1); 331 strcpy (bufp, drive); 332 strcat (bufp, path); 333 if (access_file (bufp, pathbuf, len_pathbuf, pathret)) { 334 if (bufp != buf) free (bufp); 335 return 1; 336 } 337 } 338 339 /* does OS/2 (with or with gcc-emx) have getdrives? */ 340 /* tried everywhere else, go fishing */ 341 #define C_DRIVE ('C' - 'A') 342 #define Z_DRIVE ('Z' - 'A') 343 drives = _getdrives (); 344 for (i = C_DRIVE; i <= Z_DRIVE; i++) { /* don't check on A: or B: */ 345 if ((1 << i) & drives) { 346 len = 2 + strlen (path); 347 if (len < MAX_PATH) bufp = buf; 348 else bufp = malloc (len + 1); 349 *bufp = 'A' + i; 350 *(bufp + 1) = ':'; 351 *(bufp + 2) = '\0'; 352 strcat (bufp, path); 353 if (access_file (bufp, pathbuf, len_pathbuf, pathret)) { 354 if (bufp != buf) free (bufp); 355 return 1; 356 } 357 } 358 } 359 return 0; 360 } 361 362 FILE * 363 fopen_file(char *path, char *mode) 364 { 365 char buf[MAX_PATH]; 366 char* bufp; 367 void* ret = NULL; 368 UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS); 369 370 if (AccessFile (path, buf, MAX_PATH, &bufp)) 371 ret = fopen (bufp, mode); 372 373 (void) SetErrorMode (olderror); 374 375 if (bufp != buf) free (bufp); 376 377 return ret; 378 } 379 380 #else 381 #define fopen_file fopen 382 #endif 383 384 385 int 386 XmuReadBitmapDataFromFile(_Xconst char *filename, unsigned int *width, 387 unsigned int *height, unsigned char **datap, 388 int *x_hot, int *y_hot) 389 { 390 FILE *fstream; 391 int status; 392 393 if ((fstream = fopen_file (filename, "r" FOPEN_CLOEXEC)) == NULL) { 394 return BitmapOpenFailed; 395 } 396 status = XmuReadBitmapData(fstream, width, height, datap, x_hot, y_hot); 397 fclose (fstream); 398 return status; 399 } 400