#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xlibint.h>
#include <stdio.h>
#include <ctype.h>
#include <X11/Xmu/Drawing.h>
#define MAX_SIZE 255
static void initHexTable(void);
static int NextInt(FILE*);
static short hexTable[256];
static Bool initialized = False;
static void
initHexTable(void)
{
hexTable['0'] = 0; hexTable['1'] = 1;
hexTable['2'] = 2; hexTable['3'] = 3;
hexTable['4'] = 4; hexTable['5'] = 5;
hexTable['6'] = 6; hexTable['7'] = 7;
hexTable['8'] = 8; hexTable['9'] = 9;
hexTable['A'] = 10; hexTable['B'] = 11;
hexTable['C'] = 12; hexTable['D'] = 13;
hexTable['E'] = 14; hexTable['F'] = 15;
hexTable['a'] = 10; hexTable['b'] = 11;
hexTable['c'] = 12; hexTable['d'] = 13;
hexTable['e'] = 14; hexTable['f'] = 15;
hexTable[' '] = -1; hexTable[','] = -1;
hexTable['}'] = -1; hexTable['\n'] = -1;
hexTable['\t'] = -1;
initialized = True;
}
static int
NextInt(FILE *fstream)
{
int ch;
int value = 0;
int gotone = 0;
int done = 0;
while (!done) {
ch = getc(fstream);
if (ch == EOF) {
value = -1;
done++;
} else {
ch &= 0xff;
if (isascii(ch) && isxdigit(ch)) {
value = (value << 4) + hexTable[ch];
gotone++;
} else if ((hexTable[ch]) < 0 && gotone)
done++;
}
}
return value;
}
int
XmuReadBitmapData(FILE *fstream, unsigned int *width, unsigned int *height,
unsigned char **datap, int *x_hot, int *y_hot)
{
unsigned char *data = NULL;
char line[MAX_SIZE];
int size;
char name_and_type[MAX_SIZE];
char *type;
int value;
int version10p;
int padding;
int bytes_per_line;
unsigned int ww = 0;
unsigned int hh = 0;
int hx = -1;
int hy = -1;
#undef Xmalloc
#define Xmalloc(size) malloc(size)
if (initialized == False) initHexTable();
#define RETURN(code) { if (data) free (data); return code; }
while (fgets(line, MAX_SIZE, fstream)) {
if (strlen(line) == MAX_SIZE-1) {
RETURN (BitmapFileInvalid);
}
if (sscanf(line,"#define %s %d",name_and_type,&value) == 2) {
if (!(type = strrchr(name_and_type, '_')))
type = name_and_type;
else
type++;
if (!strcmp("width", type))
ww = (unsigned int) value;
if (!strcmp("height", type))
hh = (unsigned int) value;
if (!strcmp("hot", type)) {
if (type-- == name_and_type || type-- == name_and_type)
continue;
if (!strcmp("x_hot", type))
hx = value;
if (!strcmp("y_hot", type))
hy = value;
}
continue;
}
if (sscanf(line, "static short %s = {", name_and_type) == 1)
version10p = 1;
else if (sscanf(line,"static unsigned char %s = {",name_and_type) == 1)
version10p = 0;
else if (sscanf(line, "static char %s = {", name_and_type) == 1)
version10p = 0;
else
continue;
if (!(type = strrchr(name_and_type, '_')))
type = name_and_type;
else
type++;
if (strcmp("bits[]", type))
continue;
if (!ww || !hh)
RETURN (BitmapFileInvalid);
if ((ww % 16) && ((ww % 16) < 9) && version10p)
padding = 1;
else
padding = 0;
bytes_per_line = (ww+7)/8 + padding;
size = bytes_per_line * hh;
data = (unsigned char *) Xmalloc ((unsigned int) size);
if (!data)
RETURN (BitmapNoMemory);
if (version10p) {
unsigned char *ptr;
int bytes;
for (bytes=0, ptr=data; bytes<size; (bytes += 2)) {
if ((value = NextInt(fstream)) < 0)
RETURN (BitmapFileInvalid);
*(ptr++) = value;
if (!padding || ((bytes+2) % bytes_per_line))
*(ptr++) = value >> 8;
}
} else {
unsigned char *ptr;
int bytes;
for (bytes=0, ptr=data; bytes<size; bytes++, ptr++) {
if ((value = NextInt(fstream)) < 0)
RETURN (BitmapFileInvalid);
*ptr=value;
}
}
break;
}
if (data == NULL) {
RETURN (BitmapFileInvalid);
}
*datap = data;
data = NULL;
*width = ww;
*height = hh;
if (x_hot) *x_hot = hx;
if (y_hot) *y_hot = hy;
RETURN (BitmapSuccess);
}
#if defined(WIN32)
static int
access_file(char *path, char *pathbuf, int len_pathbuf, char **pathret)
{
if (access (path, F_OK) == 0) {
if (strlen (path) < len_pathbuf)
*pathret = pathbuf;
else
*pathret = malloc (strlen (path) + 1);
if (*pathret) {
strcpy (*pathret, path);
return 1;
}
}
return 0;
}
static int
AccessFile(char *path, char *pathbuf, int len_pathbuf, char **pathret)
{
#ifndef MAX_PATH
#define MAX_PATH 512
#endif
unsigned long drives;
int i, len;
char* drive;
char buf[MAX_PATH];
char* bufp;
if (access_file (path, pathbuf, len_pathbuf, pathret))
return 1;
drive = getenv ("_XBASEDRIVE");
#ifdef __UNIXOS2__
if (!drive)
drive = getenv ("X11ROOT");
#endif
if (!drive)
drive = "C:";
len = strlen (drive) + strlen (path);
if (len < MAX_PATH) bufp = buf;
else bufp = malloc (len + 1);
strcpy (bufp, drive);
strcat (bufp, path);
if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
if (bufp != buf) free (bufp);
return 1;
}
#ifndef __UNIXOS2__
drive = getenv ("HOMEDRIVE");
if (drive) {
len = strlen (drive) + strlen (path);
if (len < MAX_PATH) bufp = buf;
else bufp = malloc (len + 1);
strcpy (bufp, drive);
strcat (bufp, path);
if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
if (bufp != buf) free (bufp);
return 1;
}
}
#define C_DRIVE ('C' - 'A')
#define Z_DRIVE ('Z' - 'A')
drives = _getdrives ();
for (i = C_DRIVE; i <= Z_DRIVE; i++) {
if ((1 << i) & drives) {
len = 2 + strlen (path);
if (len < MAX_PATH) bufp = buf;
else bufp = malloc (len + 1);
*bufp = 'A' + i;
*(bufp + 1) = ':';
*(bufp + 2) = '\0';
strcat (bufp, path);
if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
if (bufp != buf) free (bufp);
return 1;
}
}
}
#endif
return 0;
}
FILE *
fopen_file(char *path, char *mode)
{
char buf[MAX_PATH];
char* bufp;
void* ret = NULL;
UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS);
if (AccessFile (path, buf, MAX_PATH, &bufp))
ret = fopen (bufp, mode);
(void) SetErrorMode (olderror);
if (bufp != buf) free (bufp);
return ret;
}
#else
#define fopen_file fopen
#endif
int
XmuReadBitmapDataFromFile(_Xconst char *filename, unsigned int *width,
unsigned int *height, unsigned char **datap,
int *x_hot, int *y_hot)
{
FILE *fstream;
int status;
#ifdef __UNIXOS2__
filename = __XOS2RedirRoot(filename);
#endif
if ((fstream = fopen_file (filename, "r")) == NULL) {
return BitmapOpenFailed;
}
status = XmuReadBitmapData(fstream, width, height, datap, x_hot, y_hot);
fclose (fstream);
return status;
}