/*
* Copyright (C) 1989-95 GROUPE BULL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of GROUPE BULL shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from GROUPE BULL.
*/
/*****************************************************************************\
* parse.c: *
* *
* XPM library *
* Parse an XPM file or array and store the found informations *
* in the given XpmImage structure. *
* *
* Developed by Arnaud Le Hors *
\*****************************************************************************/
/*
* The code related to FOR_MSW has been added by HeDu
* (hedu@cul-ipn.uni-kiel.de) 4/94
*/
#include "xpmP.h"
#include <ctype.h>
LFUNC(ParseValues, int, (xpmData * data, unsigned int *width,
unsigned int *height, unsigned int *ncolors,
unsigned int *cpp, unsigned int *x_hotspot,
unsigned int *y_hotspot, unsigned int *hotspot,
unsigned int *extensions));
LFUNC(ParseColors, int, (xpmData * data, unsigned int ncolors, unsigned int cpp,
XpmColor ** colorTablePtr, xpmHashTable * hashtable));
LFUNC(ParsePixels, int, (xpmData * data, unsigned int width,
unsigned int height, unsigned int ncolors,
unsigned int cpp, XpmColor * colorTable,
xpmHashTable * hashtable, unsigned int **pixels));
LFUNC(ParseExtensions, int, (xpmData * data, XpmExtension ** extensions,
unsigned int *nextensions));
char *xpmColorKeys[] = {
"s", /* key #1: symbol */
"m", /* key #2: mono visual */
"g4", /* key #3: 4 grays visual */
"g", /* key #4: gray visual */
"c", /* key #5: color visual */
};
/* function call in case of error, frees only locally allocated variables */
#undef RETURN
#define RETURN(status) \
{ \
if (colorTable) xpmFreeColorTable(colorTable, ncolors); \
if (pixelindex) XpmFree(pixelindex); \
if (hints_cmt) XpmFree(hints_cmt); \
if (colors_cmt) XpmFree(colors_cmt); \
if (pixels_cmt) XpmFree(pixels_cmt); \
return(status); \
}
/*
* This function parses an Xpm file or data and store the found informations
* in an an XpmImage structure which is returned.
*/
int
xpmParseData(data, image, info)
xpmData *data;
XpmImage *image;
XpmInfo *info;
{
/* variables to return */
unsigned int width, height, ncolors, cpp;
unsigned int x_hotspot, y_hotspot, hotspot = 0, extensions = 0;
XpmColor *colorTable = NULL;
unsigned int *pixelindex = NULL;
char *hints_cmt = NULL;
char *colors_cmt = NULL;
char *pixels_cmt = NULL;
unsigned int cmts;
int ErrorStatus;
xpmHashTable hashtable;
cmts = info && (info->valuemask & XpmReturnComments);
/*
* parse the header
*/
ErrorStatus = xpmParseHeader(data);
if (ErrorStatus != XpmSuccess)
return (ErrorStatus);
/*
* read values
*/
ErrorStatus = ParseValues(data, &width, &height, &ncolors, &cpp,
&x_hotspot, &y_hotspot, &hotspot, &extensions);
if (ErrorStatus != XpmSuccess)
return (ErrorStatus);
/*
* store the hints comment line
*/
if (cmts)
xpmGetCmt(data, &hints_cmt);
/*
* init the hastable
*/
if (USE_HASHTABLE)
{
ErrorStatus = xpmHashTableInit(&hashtable);
if (ErrorStatus != XpmSuccess)
return (ErrorStatus);
}
/*
* read colors
*/
ErrorStatus = ParseColors(data, ncolors, cpp, &colorTable, &hashtable);
if (ErrorStatus != XpmSuccess)
{
if (USE_HASHTABLE)
xpmHashTableFree(&hashtable);
RETURN(ErrorStatus);
}
/*
* store the colors comment line
*/
if (cmts)
xpmGetCmt(data, &colors_cmt);
/*
* read pixels and index them on color number
*/
ErrorStatus = ParsePixels(data, width, height, ncolors, cpp, colorTable,
&hashtable, &pixelindex);
/*
* free the hastable
*/
if (USE_HASHTABLE)
xpmHashTableFree(&hashtable);
if (ErrorStatus != XpmSuccess)
RETURN(ErrorStatus);
/*
* store the pixels comment line
*/
if (cmts)
xpmGetCmt(data, &pixels_cmt);
/*
* parse extensions
*/
if (info && (info->valuemask & XpmReturnExtensions))
if (extensions)
{
ErrorStatus = ParseExtensions(data, &info->extensions,
&info->nextensions);
if (ErrorStatus != XpmSuccess)
RETURN(ErrorStatus);
} else
{
info->extensions = NULL;
info->nextensions = 0;
}
/*
* store found informations in the XpmImage structure
*/
image->width = width;
image->height = height;
image->cpp = cpp;
image->ncolors = ncolors;
image->colorTable = colorTable;
image->data = pixelindex;
if (info)
{
if (cmts)
{
info->hints_cmt = hints_cmt;
info->colors_cmt = colors_cmt;
info->pixels_cmt = pixels_cmt;
}
if (hotspot)
{
info->x_hotspot = x_hotspot;
info->y_hotspot = y_hotspot;
info->valuemask |= XpmHotspot;
}
}
return (XpmSuccess);
}
static int
ParseValues(data, width, height, ncolors, cpp,
x_hotspot, y_hotspot, hotspot, extensions)
xpmData *data;
unsigned int *width, *height, *ncolors, *cpp;
unsigned int *x_hotspot, *y_hotspot, *hotspot;
unsigned int *extensions;
{
unsigned int l;
char buf[BUFSIZ];
if (!data->format)
{ /* XPM 2 or 3 */
/*
* read values: width, height, ncolors, chars_per_pixel
*/
if (!(xpmNextUI(data, width) && xpmNextUI(data, height)
&& xpmNextUI(data, ncolors) && xpmNextUI(data, cpp)))
return (XpmFileInvalid);
/*
* read optional information (hotspot and/or XPMEXT) if any
*/
l = xpmNextWord(data, buf, BUFSIZ);
if (l)
{
*extensions = (l == 6 && !strncmp("XPMEXT", buf, 6));
if (*extensions)
*hotspot = (xpmNextUI(data, x_hotspot)
&& xpmNextUI(data, y_hotspot));
else
{
*hotspot = (xpmatoui(buf, l, x_hotspot)
&& xpmNextUI(data, y_hotspot));
l = xpmNextWord(data, buf, BUFSIZ);
*extensions = (l == 6 && !strncmp("XPMEXT", buf, 6));
}
}
} else
{
/*
* XPM 1 file read values: width, height, ncolors, chars_per_pixel
*/
int i;
char *ptr;
Bool got_one, saw_width = False, saw_height = False;
Bool saw_ncolors = False, saw_chars_per_pixel = False;
for (i = 0; i < 4; i++)
{
l = xpmNextWord(data, buf, BUFSIZ);
if (l != 7 || strncmp("#define", buf, 7))
return (XpmFileInvalid);
l = xpmNextWord(data, buf, BUFSIZ);
if (!l)
return (XpmFileInvalid);
buf[l] = '\0';
ptr = buf;
got_one = False;
while (!got_one)
{
ptr = index(ptr, '_');
if (!ptr)
return (XpmFileInvalid);
switch (l - (ptr - buf))
{
case 6:
if (saw_width || strncmp("_width", ptr, 6)
|| !xpmNextUI(data, width))
return (XpmFileInvalid);
else
saw_width = True;
got_one = True;
break;
case 7:
if (saw_height || strncmp("_height", ptr, 7)
|| !xpmNextUI(data, height))
return (XpmFileInvalid);
else
saw_height = True;
got_one = True;
break;
case 8:
if (saw_ncolors || strncmp("_ncolors", ptr, 8)
|| !xpmNextUI(data, ncolors))
return (XpmFileInvalid);
else
saw_ncolors = True;
got_one = True;
break;
case 16:
if (saw_chars_per_pixel
|| strncmp("_chars_per_pixel", ptr, 16)
|| !xpmNextUI(data, cpp))
return (XpmFileInvalid);
else
saw_chars_per_pixel = True;
got_one = True;
break;
default:
ptr++;
}
}
/* skip the end of line */
xpmNextString(data);
}
if (!saw_width || !saw_height || !saw_ncolors || !saw_chars_per_pixel)
return (XpmFileInvalid);
*hotspot = 0;
*extensions = 0;
}
return (XpmSuccess);
}
static int
ParseColors(data, ncolors, cpp, colorTablePtr, hashtable)
xpmData *data;
unsigned int ncolors;
unsigned int cpp;
XpmColor **colorTablePtr;
xpmHashTable *hashtable;
{
unsigned int key, l, a, b;
unsigned int curkey; /* current color key */
unsigned int lastwaskey; /* key read */
char buf[BUFSIZ];
char curbuf[BUFSIZ]; /* current buffer */
char **sptr, *s;
XpmColor *color;
XpmColor *colorTable;
char **defaults;
int ErrorStatus;
colorTable = (XpmColor *) XpmCalloc(ncolors, sizeof(XpmColor));
if (!colorTable)
return (XpmNoMemory);
if (!data->format)
{ /* XPM 2 or 3 */
for (a = 0, color = colorTable; a < ncolors; a++, color++)
{
xpmNextString(data); /* skip the line */
/*
* read pixel value
*/
color->string = (char *) XpmMalloc(cpp + 1);
if (!color->string)
{
xpmFreeColorTable(colorTable, ncolors);
return (XpmNoMemory);
}
for (b = 0, s = color->string; b < cpp; b++, s++)
*s = xpmGetC(data);
*s = '\0';
/*
* store the string in the hashtable with its color index number
*/
if (USE_HASHTABLE)
{
ErrorStatus =
xpmHashIntern(hashtable, color->string, HashAtomData(a));
if (ErrorStatus != XpmSuccess)
{
xpmFreeColorTable(colorTable, ncolors);
return (ErrorStatus);
}
}
/*
* read color keys and values
*/
defaults = (char **) color;
curkey = 0;
lastwaskey = 0;
*curbuf = '\0'; /* init curbuf */
while (l = xpmNextWord(data, buf, BUFSIZ))
{
if (!lastwaskey)
{
for (key = 0, sptr = xpmColorKeys; key < NKEYS; key++,
sptr++)
if ((strlen(*sptr) == l) && (!strncmp(*sptr, buf, l)))
break;
}
if (!lastwaskey && key < NKEYS)
{ /* open new key */
if (curkey)
{ /* flush string */
s = (char *) XpmMalloc(strlen(curbuf) + 1);
if (!s)
{
xpmFreeColorTable(colorTable, ncolors);
return (XpmNoMemory);
}
defaults[curkey] = s;
strcpy(s, curbuf);
}
curkey = key + 1; /* set new key */
*curbuf = '\0'; /* reset curbuf */
lastwaskey = 1;
} else
{
if (!curkey)
{ /* key without value */
xpmFreeColorTable(colorTable, ncolors);
return (XpmFileInvalid);
}
if (!lastwaskey)
strcat(curbuf, " "); /* append space */
buf[l] = '\0';
strcat(curbuf, buf); /* append buf */
lastwaskey = 0;
}
}
if (!curkey)
{ /* key without value */
xpmFreeColorTable(colorTable, ncolors);
return (XpmFileInvalid);
}
s = defaults[curkey] = (char *) XpmMalloc(strlen(curbuf) + 1);
if (!s)
{
xpmFreeColorTable(colorTable, ncolors);
return (XpmNoMemory);
}
strcpy(s, curbuf);
}
} else
{ /* XPM 1 */
/* get to the beginning of the first string */
data->Bos = '"';
data->Eos = '\0';
xpmNextString(data);
data->Eos = '"';
for (a = 0, color = colorTable; a < ncolors; a++, color++)
{
/*
* read pixel value
*/
color->string = (char *) XpmMalloc(cpp + 1);
if (!color->string)
{
xpmFreeColorTable(colorTable, ncolors);
return (XpmNoMemory);
}
for (b = 0, s = color->string; b < cpp; b++, s++)
*s = xpmGetC(data);
*s = '\0';
/*
* store the string in the hashtable with its color index number
*/
if (USE_HASHTABLE)
{
ErrorStatus =
xpmHashIntern(hashtable, color->string, HashAtomData(a));
if (ErrorStatus != XpmSuccess)
{
xpmFreeColorTable(colorTable, ncolors);
return (ErrorStatus);
}
}
/*
* read color values
*/
xpmNextString(data); /* get to the next string */
*curbuf = '\0'; /* init curbuf */
while (l = xpmNextWord(data, buf, BUFSIZ))
{
if (*curbuf != '\0')
strcat(curbuf, " "); /* append space */
buf[l] = '\0';
strcat(curbuf, buf); /* append buf */
}
s = (char *) XpmMalloc(strlen(curbuf) + 1);
if (!s)
{
xpmFreeColorTable(colorTable, ncolors);
return (XpmNoMemory);
}
strcpy(s, curbuf);
color->c_color = s;
*curbuf = '\0'; /* reset curbuf */
if (a < ncolors - 1)
xpmNextString(data); /* get to the next string */
}
}
*colorTablePtr = colorTable;
return (XpmSuccess);
}
static int
ParsePixels(data, width, height, ncolors, cpp, colorTable, hashtable, pixels)
xpmData *data;
unsigned int width;
unsigned int height;
unsigned int ncolors;
unsigned int cpp;
XpmColor *colorTable;
xpmHashTable *hashtable;
unsigned int **pixels;
{
unsigned int *iptr, *iptr2;
unsigned int a, x, y;
#ifndef FOR_MSW
iptr2 = (unsigned int *) XpmMalloc(sizeof(unsigned int) * width * height);
#else
/*
* special treatment to trick DOS malloc(size_t) where size_t is 16 bit!!
* XpmMalloc is defined to longMalloc(long) and checks the 16 bit boundary
*/
iptr2 = (unsigned int *)
XpmMalloc((long) sizeof(unsigned int) * (long) width * (long) height);
#endif
if (!iptr2)
return (XpmNoMemory);
iptr = iptr2;
switch (cpp)
{
case (1): /* Optimize for single character colors */
{
unsigned short colidx[256];
bzero(colidx, 256 * sizeof(short));
for (a = 0; a < ncolors; a++)
colidx[(unsigned char) colorTable[a].string[0]] = a + 1;
for (y = 0; y < height; y++)
{
xpmNextString(data);
for (x = 0; x < width; x++, iptr++)
{
int c = xpmGetC(data);
if (c > 0 && c < 256 && colidx[c] != 0)
*iptr = colidx[c] - 1;
else
{
XpmFree(iptr2);
return (XpmFileInvalid);
}
}
}
}
break;
case (2): /* Optimize for double character colors */
{
/* free all allocated pointers at all exits */
#define FREE_CIDX {int f; for (f = 0; f < 256; f++) \
if (cidx[f]) XpmFree(cidx[f]);}
/* array of pointers malloced by need */
unsigned short *cidx[256];
int char1;
bzero(cidx, 256 * sizeof(unsigned short *)); /* init */
for (a = 0; a < ncolors; a++)
{
char1 = colorTable[a].string[0];
if (cidx[char1] == NULL)
{ /* get new memory */
cidx[char1] = (unsigned short *)
XpmCalloc(256, sizeof(unsigned short));
if (cidx[char1] == NULL)
{ /* new block failed */
FREE_CIDX;
XpmFree(iptr2);
return (XpmNoMemory);
}
}
cidx[char1][(unsigned char) colorTable[a].string[1]] = a + 1;
}
for (y = 0; y < height; y++)
{
xpmNextString(data);
for (x = 0; x < width; x++, iptr++)
{
int cc1 = xpmGetC(data);
if (cc1 > 0 && cc1 < 256)
{
int cc2 = xpmGetC(data);
if (cc2 > 0 && cc2 < 256 && cidx[cc1][cc2] != 0)
*iptr = cidx[cc1][cc2] - 1;
else
{
FREE_CIDX;
XpmFree(iptr2);
return (XpmFileInvalid);
}
} else
{
FREE_CIDX;
XpmFree(iptr2);
return (XpmFileInvalid);
}
}
}
FREE_CIDX;
}
break;
default: /* Non-optimized case of long color names */
{
char *s;
char buf[BUFSIZ];
buf[cpp] = '\0';
if (USE_HASHTABLE)
{
xpmHashAtom *slot;
for (y = 0; y < height; y++)
{
xpmNextString(data);
for (x = 0; x < width; x++, iptr++)
{
for (a = 0, s = buf; a < cpp; a++, s++)
*s = xpmGetC(data);
slot = xpmHashSlot(hashtable, buf);
if (!*slot)
{ /* no color matches */
XpmFree(iptr2);
return (XpmFileInvalid);
}
*iptr = HashColorIndex(slot);
}
}
} else
{
for (y = 0; y < height; y++)
{
xpmNextString(data);
for (x = 0; x < width; x++, iptr++)
{
for (a = 0, s = buf; a < cpp; a++, s++)
*s = xpmGetC(data);
for (a = 0; a < ncolors; a++)
if (!strcmp(colorTable[a].string, buf))
break;
if (a == ncolors)
{ /* no color matches */
XpmFree(iptr2);
return (XpmFileInvalid);
}
*iptr = a;
}
}
}
}
break;
}
*pixels = iptr2;
return (XpmSuccess);
}
static int
ParseExtensions(data, extensions, nextensions)
xpmData *data;
XpmExtension **extensions;
unsigned int *nextensions;
{
XpmExtension *exts = NULL, *ext;
unsigned int num = 0;
unsigned int nlines, a, l, notstart, notend = 0;
int status;
char *string, *s, *s2, **sp;
xpmNextString(data);
exts = (XpmExtension *) XpmMalloc(sizeof(XpmExtension));
/* get the whole string */
status = xpmGetString(data, &string, &l);
if (status != XpmSuccess)
{
XpmFree(exts);
return (status);
}
/* look for the key word XPMEXT, skip lines before this */
while ((notstart = strncmp("XPMEXT", string, 6))
&& (notend = strncmp("XPMENDEXT", string, 9)))
{
XpmFree(string);
xpmNextString(data);
status = xpmGetString(data, &string, &l);
if (status != XpmSuccess)
{
XpmFree(exts);
return (status);
}
}
if (!notstart)
notend = strncmp("XPMENDEXT", string, 9);
while (!notstart && notend)
{
/* there starts an extension */
ext = (XpmExtension *)
XpmRealloc(exts, (num + 1) * sizeof(XpmExtension));
if (!ext)
{
XpmFree(string);
XpmFreeExtensions(exts, num);
return (XpmNoMemory);
}
exts = ext;
ext += num;
/* skip whitespace and store its name */
s2 = s = string + 6;
while (isspace(*s2))
s2++;
a = s2 - s;
ext->name = (char *) XpmMalloc(l - a - 6);
if (!ext->name)
{
XpmFree(string);
ext->lines = NULL;
ext->nlines = 0;
XpmFreeExtensions(exts, num + 1);
return (XpmNoMemory);
}
strncpy(ext->name, s + a, l - a - 6);
XpmFree(string);
/* now store the related lines */
xpmNextString(data);
status = xpmGetString(data, &string, &l);
if (status != XpmSuccess)
{
ext->lines = NULL;
ext->nlines = 0;
XpmFreeExtensions(exts, num + 1);
return (status);
}
ext->lines = (char **) XpmMalloc(sizeof(char *));
nlines = 0;
while ((notstart = strncmp("XPMEXT", string, 6))
&& (notend = strncmp("XPMENDEXT", string, 9)))
{
sp = (char **)
XpmRealloc(ext->lines, (nlines + 1) * sizeof(char *));
if (!sp)
{
XpmFree(string);
ext->nlines = nlines;
XpmFreeExtensions(exts, num + 1);
return (XpmNoMemory);
}
ext->lines = sp;
ext->lines[nlines] = string;
nlines++;
xpmNextString(data);
status = xpmGetString(data, &string, &l);
if (status != XpmSuccess)
{
ext->nlines = nlines;
XpmFreeExtensions(exts, num + 1);
return (status);
}
}
if (!nlines)
{
XpmFree(ext->lines);
ext->lines = NULL;
}
ext->nlines = nlines;
num++;
}
if (!num)
{
XpmFree(string);
XpmFree(exts);
exts = NULL;
} else
if (!notend)
XpmFree(string);
*nextensions = num;
*extensions = exts;
return (XpmSuccess);
}
syntax highlighted by Code2HTML, v. 0.9.1