Edit

IABSD.fr/xenocara/lib/libXpm/src/parse.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2007-09-30 08:38:09
    Hash : 3fa7de0f
    Message : libXpm 3.5.7

  • lib/libXpm/src/parse.c
  • /* $XdotOrg: lib/Xpm/src/parse.c,v 1.6 2005/07/16 21:11:25 alanc Exp $ */
    /*
     * 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.
     */
    /* $XFree86: xc/extras/Xpm/lib/parse.c,v 1.2 2000/09/26 15:56:43 tsi Exp $ */
    
    /*****************************************************************************\
    * 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                                                *
    \*****************************************************************************/
    /* $XFree86$ */
    
    /*
     * The code related to FOR_MSW has been added by
     * HeDu (hedu@cul-ipn.uni-kiel.de) 4/94
     */
    
    /* October 2004, source code review by Thomas Biege <thomas@suse.de> */
    
    #ifdef HAVE_CONFIG_H
    #include <config.h>
    #endif
    #include "XpmI.h"
    #include <ctype.h>
    #include <string.h>
    
    #if defined(HAS_STRLCAT) || defined(HAVE_STRLCAT)
    # define STRLCAT(dst, src, dstsize) do { \
      	if (strlcat(dst, src, dstsize) >= (dstsize)) \
    	    return (XpmFileInvalid); } while(0)
    # define STRLCPY(dst, src, dstsize) do { \
      	if (strlcpy(dst, src, dstsize) >= (dstsize)) \
    	    return (XpmFileInvalid); } while(0)
    #else
    # define STRLCAT(dst, src, dstsize) do { \
    	if ((strlen(dst) + strlen(src)) < (dstsize)) \
     	    strcat(dst, src); \
    	else return (XpmFileInvalid); } while(0)
    # define STRLCPY(dst, src, dstsize) do { \
    	if (strlen(src) < (dstsize)) \
     	    strcpy(dst, src); \
    	else return (XpmFileInvalid); } while(0)
    #endif
    
    LFUNC(ParsePixels, int, (xpmData *data, unsigned int width,
    			 unsigned int height, unsigned int ncolors,
    			 unsigned int cpp, XpmColor *colorTable,
    			 xpmHashTable *hashtable, unsigned int **pixels));
    
    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 */
    };
    
    int
    xpmParseValues(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 + 1];
    
        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 = strchr(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);
    }
    
    int
    xpmParseColors(data, ncolors, cpp, colorTablePtr, hashtable)
        xpmData *data;
        unsigned int ncolors;
        unsigned int cpp;
        XpmColor **colorTablePtr;
        xpmHashTable *hashtable;
    {
        unsigned int key = 0, l, a, b, len;
        unsigned int curkey;		/* current color key */
        unsigned int lastwaskey;		/* key read */
        char buf[BUFSIZ+1];
        char curbuf[BUFSIZ];		/* current buffer */
        char **sptr, *s;
        XpmColor *color;
        XpmColor *colorTable;
        char **defaults;
        int ErrorStatus;
    
        if (ncolors >= UINT_MAX / sizeof(XpmColor))
    	return (XpmNoMemory);
        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
    	     */
    	    if (cpp >= UINT_MAX - 1) {
    		xpmFreeColorTable(colorTable, ncolors);
    		return (XpmNoMemory);
    	    }
    	    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 */
    			len = strlen(curbuf) + 1;
    			s = (char *) XpmMalloc(len);
    			if (!s) {
    			    xpmFreeColorTable(colorTable, ncolors);
    			    return (XpmNoMemory);
    			}
    			defaults[curkey] = s;
    			memcpy(s, curbuf, len);
    		    }
    		    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)
    			STRLCAT(curbuf, " ", sizeof(curbuf));/* append space */
    		    buf[l] = '\0';
    		    STRLCAT(curbuf, buf, sizeof(curbuf)); /* append buf */
    		    lastwaskey = 0;
    		}
    	    }
    	    if (!curkey) {		/* key without value */
    		xpmFreeColorTable(colorTable, ncolors);
    		return (XpmFileInvalid);
    	    }
    	    len = strlen(curbuf) + 1; /* integer overflow just theoretically possible */
    	    s = defaults[curkey] = (char *) XpmMalloc(len);
    	    if (!s) {
    		xpmFreeColorTable(colorTable, ncolors);
    		return (XpmNoMemory);
    	    }
    	    memcpy(s, curbuf, len);
    	}
        } 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
    	     */
    	    if (cpp >= UINT_MAX - 1) {
    		xpmFreeColorTable(colorTable, ncolors);
    		return (XpmNoMemory);
    	    }
    	    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')
    		    STRLCAT(curbuf, " ", sizeof(curbuf));/* append space */
    		buf[l] = '\0';
    		STRLCAT(curbuf, buf, sizeof(curbuf));	/* append buf */
    	    }
    	    len = strlen(curbuf) + 1;
    	    s = (char *) XpmMalloc(len);
    	    if (!s) {
    		xpmFreeColorTable(colorTable, ncolors);
    		return (XpmNoMemory);
    	    }
    	    memcpy(s, curbuf, len);
    	    color->c_color = s;
    	    *curbuf = '\0';		/* reset curbuf */
    	    if (a < ncolors - 1)	/* can we trust ncolors -> leave data's bounds */
    		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 = NULL; /* found by Egbert Eich */
        unsigned int a, x, y;
    
        if ((height > 0 && width >= UINT_MAX / height) ||
    	width * height >= UINT_MAX / sizeof(unsigned int)) 
    	return XpmNoMemory;
    #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];
    
    	    if (ncolors > 256) {
    		XpmFree(iptr2); /* found by Egbert Eich */
    		return (XpmFileInvalid);
    	    }
    
    	    bzero((char *)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 \
    do \
    { \
    	int f; for (f = 0; f < 256; f++) \
    	if (cidx[f]) XpmFree(cidx[f]); \
    } while(0)
    
    	    /* array of pointers malloced by need */
    	    unsigned short *cidx[256];
    	    unsigned int char1;
    
    	    bzero((char *)cidx, 256 * sizeof(unsigned short *)); /* init */
    	    for (a = 0; a < ncolors; a++) {
    		char1 = (unsigned char) 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] && 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];
    
    	    if (cpp >= sizeof(buf)) {
    		XpmFree(iptr2); /* found by Egbert Eich */
    		return (XpmFileInvalid);
    	    }
    
    	    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); /* int assigned to char, not a problem here */
    			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); /* int assigned to char, not a problem here */
    			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);
    }
    
    int
    xpmParseExtensions(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)); /* can the loop be forced to iterate often enough to make "(num + 1) * sizeof(XpmExtension)" wrapping? */
    	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 *)); /* can we iterate enough for a wrapping? */
    	    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);
    }
    
    
    /* function call in case of error */
    #undef RETURN
    #define RETURN(status) \
    do { \
          goto error; \
    } while(0)
    
    /*
     * 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 = xpmParseValues(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 hashtable
         */
        if (USE_HASHTABLE) {
    	ErrorStatus = xpmHashTableInit(&hashtable);
    	if (ErrorStatus != XpmSuccess)
    	    RETURN(ErrorStatus);
        }
    
        /*
         * read colors
         */
        ErrorStatus = xpmParseColors(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 = xpmParseExtensions(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);
    
    /* exit point in case of error, free only locally allocated variables */
    error:
        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(ErrorStatus);
    }