parse.c revision 97cf2ee2
1/*
2 * Copyright (C) 1989-95 GROUPE BULL
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
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
17 * GROUPE BULL 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 GROUPE BULL 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 GROUPE BULL.
24 */
25
26/*****************************************************************************\
27* parse.c:                                                                    *
28*                                                                             *
29*  XPM library                                                                *
30*  Parse an XPM file or array and store the found informations                *
31*  in the given XpmImage structure.                                           *
32*                                                                             *
33*  Developed by Arnaud Le Hors                                                *
34\*****************************************************************************/
35
36/*
37 * The code related to FOR_MSW has been added by
38 * HeDu (hedu@cul-ipn.uni-kiel.de) 4/94
39 */
40
41/* October 2004, source code review by Thomas Biege <thomas@suse.de> */
42
43#ifdef HAVE_CONFIG_H
44#include <config.h>
45#endif
46#include "XpmI.h"
47#include <ctype.h>
48#include <string.h>
49
50#if defined(HAS_STRLCAT) || defined(HAVE_STRLCAT)
51# define STRLCAT(dst, src, dstsize) do { \
52  	if (strlcat(dst, src, dstsize) >= (dstsize)) \
53	    return (XpmFileInvalid); } while(0)
54# define STRLCPY(dst, src, dstsize) do { \
55  	if (strlcpy(dst, src, dstsize) >= (dstsize)) \
56	    return (XpmFileInvalid); } while(0)
57#else
58# define STRLCAT(dst, src, dstsize) do { \
59	if ((strlen(dst) + strlen(src)) < (dstsize)) \
60 	    strcat(dst, src); \
61	else return (XpmFileInvalid); } while(0)
62# define STRLCPY(dst, src, dstsize) do { \
63	if (strlen(src) < (dstsize)) \
64 	    strcpy(dst, src); \
65	else return (XpmFileInvalid); } while(0)
66#endif
67
68LFUNC(ParsePixels, int, (xpmData *data, unsigned int width,
69			 unsigned int height, unsigned int ncolors,
70			 unsigned int cpp, XpmColor *colorTable,
71			 xpmHashTable *hashtable, unsigned int **pixels));
72
73const char *xpmColorKeys[] = {
74    "s",				/* key #1: symbol */
75    "m",				/* key #2: mono visual */
76    "g4",				/* key #3: 4 grays visual */
77    "g",				/* key #4: gray visual */
78    "c",				/* key #5: color visual */
79};
80
81int
82xpmParseValues(
83    xpmData		*data,
84    unsigned int	*width,
85    unsigned int	*height,
86    unsigned int	*ncolors,
87    unsigned int	*cpp,
88    unsigned int	*x_hotspot,
89    unsigned int	*y_hotspot,
90    unsigned int	*hotspot,
91    unsigned int	*extensions)
92{
93    unsigned int l;
94    char buf[BUFSIZ + 1];
95
96    if (!data->format) {		/* XPM 2 or 3 */
97
98	/*
99	 * read values: width, height, ncolors, chars_per_pixel
100	 */
101	if (!(xpmNextUI(data, width) && xpmNextUI(data, height)
102	      && xpmNextUI(data, ncolors) && xpmNextUI(data, cpp)))
103	    return (XpmFileInvalid);
104
105	/*
106	 * read optional information (hotspot and/or XPMEXT) if any
107	 */
108	l = xpmNextWord(data, buf, BUFSIZ);
109	if (l) {
110	    *extensions = (l == 6 && !strncmp("XPMEXT", buf, 6));
111	    if (*extensions)
112		*hotspot = (xpmNextUI(data, x_hotspot)
113			    && xpmNextUI(data, y_hotspot));
114	    else {
115		*hotspot = (xpmatoui(buf, l, x_hotspot)
116			    && xpmNextUI(data, y_hotspot));
117		l = xpmNextWord(data, buf, BUFSIZ);
118		*extensions = (l == 6 && !strncmp("XPMEXT", buf, 6));
119	    }
120	}
121    } else {
122
123	/*
124	 * XPM 1 file read values: width, height, ncolors, chars_per_pixel
125	 */
126	int i;
127	char *ptr;
128	Bool got_one, saw_width = False, saw_height = False;
129	Bool saw_ncolors = False, saw_chars_per_pixel = False;
130
131	for (i = 0; i < 4; i++) {
132	    l = xpmNextWord(data, buf, BUFSIZ);
133	    if (l != 7 || strncmp("#define", buf, 7))
134		return (XpmFileInvalid);
135	    l = xpmNextWord(data, buf, BUFSIZ);
136	    if (!l)
137		return (XpmFileInvalid);
138	    buf[l] = '\0';
139	    ptr = buf;
140	    got_one = False;
141	    while (!got_one) {
142		ptr = strchr(ptr, '_');
143		if (!ptr)
144		    return (XpmFileInvalid);
145		switch (l - (ptr - buf)) {
146		case 6:
147		    if (saw_width || strncmp("_width", ptr, 6)
148			|| !xpmNextUI(data, width))
149			return (XpmFileInvalid);
150		    else
151			saw_width = True;
152		    got_one = True;
153		    break;
154		case 7:
155		    if (saw_height || strncmp("_height", ptr, 7)
156			|| !xpmNextUI(data, height))
157			return (XpmFileInvalid);
158		    else
159			saw_height = True;
160		    got_one = True;
161		    break;
162		case 8:
163		    if (saw_ncolors || strncmp("_ncolors", ptr, 8)
164			|| !xpmNextUI(data, ncolors))
165			return (XpmFileInvalid);
166		    else
167			saw_ncolors = True;
168		    got_one = True;
169		    break;
170		case 16:
171		    if (saw_chars_per_pixel
172			|| strncmp("_chars_per_pixel", ptr, 16)
173			|| !xpmNextUI(data, cpp))
174			return (XpmFileInvalid);
175		    else
176			saw_chars_per_pixel = True;
177		    got_one = True;
178		    break;
179		default:
180		    ptr++;
181		}
182	    }
183	    /* skip the end of line */
184	    xpmNextString(data);
185	}
186	if (!saw_width || !saw_height || !saw_ncolors || !saw_chars_per_pixel)
187	  return (XpmFileInvalid);
188
189	*hotspot = 0;
190	*extensions = 0;
191    }
192    return (XpmSuccess);
193}
194
195int
196xpmParseColors(
197    xpmData		 *data,
198    unsigned int	  ncolors,
199    unsigned int	  cpp,
200    XpmColor		**colorTablePtr,
201    xpmHashTable	 *hashtable)
202{
203    unsigned int key = 0, l, a, b, len;
204    unsigned int curkey;		/* current color key */
205    unsigned int lastwaskey;		/* key read */
206    char buf[BUFSIZ+1];
207    char curbuf[BUFSIZ];		/* current buffer */
208    const char **sptr;
209    char *s;
210    XpmColor *color;
211    XpmColor *colorTable;
212    char **defaults;
213    int ErrorStatus;
214
215    if (ncolors >= UINT_MAX / sizeof(XpmColor))
216	return (XpmNoMemory);
217    colorTable = (XpmColor *) XpmCalloc(ncolors, sizeof(XpmColor));
218    if (!colorTable)
219	return (XpmNoMemory);
220
221    if (!data->format) {		/* XPM 2 or 3 */
222	for (a = 0, color = colorTable; a < ncolors; a++, color++) {
223	    xpmNextString(data);	/* skip the line */
224
225	    /*
226	     * read pixel value
227	     */
228	    if (cpp >= UINT_MAX - 1) {
229		xpmFreeColorTable(colorTable, ncolors);
230		return (XpmNoMemory);
231	    }
232	    color->string = (char *) XpmMalloc(cpp + 1);
233	    if (!color->string) {
234		xpmFreeColorTable(colorTable, ncolors);
235		return (XpmNoMemory);
236	    }
237	    for (b = 0, s = color->string; b < cpp; b++, s++)
238		*s = xpmGetC(data);
239	    *s = '\0';
240
241	    /*
242	     * store the string in the hashtable with its color index number
243	     */
244	    if (USE_HASHTABLE) {
245		ErrorStatus =
246		    xpmHashIntern(hashtable, color->string, HashAtomData(a));
247		if (ErrorStatus != XpmSuccess) {
248		    xpmFreeColorTable(colorTable, ncolors);
249		    return (ErrorStatus);
250		}
251	    }
252
253	    /*
254	     * read color keys and values
255	     */
256	    defaults = (char **) color;
257	    curkey = 0;
258	    lastwaskey = 0;
259	    *curbuf = '\0';		/* init curbuf */
260	    while ((l = xpmNextWord(data, buf, BUFSIZ))) {
261		if (!lastwaskey) {
262		    for (key = 0, sptr = xpmColorKeys; key < NKEYS; key++,
263			 sptr++)
264			if ((strlen(*sptr) == l) && (!strncmp(*sptr, buf, l)))
265			    break;
266		}
267		if (!lastwaskey && key < NKEYS) {	/* open new key */
268		    if (curkey) {	/* flush string */
269			len = strlen(curbuf) + 1;
270			s = (char *) XpmMalloc(len);
271			if (!s) {
272			    xpmFreeColorTable(colorTable, ncolors);
273			    return (XpmNoMemory);
274			}
275			defaults[curkey] = s;
276			memcpy(s, curbuf, len);
277		    }
278		    curkey = key + 1;	/* set new key  */
279		    *curbuf = '\0';	/* reset curbuf */
280		    lastwaskey = 1;
281		} else {
282		    if (!curkey) {	/* key without value */
283			xpmFreeColorTable(colorTable, ncolors);
284			return (XpmFileInvalid);
285		    }
286		    if (!lastwaskey)
287			STRLCAT(curbuf, " ", sizeof(curbuf));/* append space */
288		    buf[l] = '\0';
289		    STRLCAT(curbuf, buf, sizeof(curbuf)); /* append buf */
290		    lastwaskey = 0;
291		}
292	    }
293	    if (!curkey) {		/* key without value */
294		xpmFreeColorTable(colorTable, ncolors);
295		return (XpmFileInvalid);
296	    }
297	    len = strlen(curbuf) + 1; /* integer overflow just theoretically possible */
298	    s = defaults[curkey] = (char *) XpmMalloc(len);
299	    if (!s) {
300		xpmFreeColorTable(colorTable, ncolors);
301		return (XpmNoMemory);
302	    }
303	    memcpy(s, curbuf, len);
304	}
305    } else {				/* XPM 1 */
306	/* get to the beginning of the first string */
307	data->Bos = '"';
308	data->Eos = '\0';
309	xpmNextString(data);
310	data->Eos = '"';
311	for (a = 0, color = colorTable; a < ncolors; a++, color++) {
312
313	    /*
314	     * read pixel value
315	     */
316	    if (cpp >= UINT_MAX - 1) {
317		xpmFreeColorTable(colorTable, ncolors);
318		return (XpmNoMemory);
319	    }
320	    color->string = (char *) XpmMalloc(cpp + 1);
321	    if (!color->string) {
322		xpmFreeColorTable(colorTable, ncolors);
323		return (XpmNoMemory);
324	    }
325	    for (b = 0, s = color->string; b < cpp; b++, s++)
326		*s = xpmGetC(data);
327	    *s = '\0';
328
329	    /*
330	     * store the string in the hashtable with its color index number
331	     */
332	    if (USE_HASHTABLE) {
333		ErrorStatus =
334		    xpmHashIntern(hashtable, color->string, HashAtomData(a));
335		if (ErrorStatus != XpmSuccess) {
336		    xpmFreeColorTable(colorTable, ncolors);
337		    return (ErrorStatus);
338		}
339	    }
340
341	    /*
342	     * read color values
343	     */
344	    xpmNextString(data);	/* get to the next string */
345	    *curbuf = '\0';		/* init curbuf */
346	    while ((l = xpmNextWord(data, buf, BUFSIZ))) {
347		if (*curbuf != '\0')
348		    STRLCAT(curbuf, " ", sizeof(curbuf));/* append space */
349		buf[l] = '\0';
350		STRLCAT(curbuf, buf, sizeof(curbuf));	/* append buf */
351	    }
352	    len = strlen(curbuf) + 1;
353	    s = (char *) XpmMalloc(len);
354	    if (!s) {
355		xpmFreeColorTable(colorTable, ncolors);
356		return (XpmNoMemory);
357	    }
358	    memcpy(s, curbuf, len);
359	    color->c_color = s;
360	    *curbuf = '\0';		/* reset curbuf */
361	    if (a < ncolors - 1)	/* can we trust ncolors -> leave data's bounds */
362		xpmNextString(data);	/* get to the next string */
363	}
364    }
365    *colorTablePtr = colorTable;
366    return (XpmSuccess);
367}
368
369static int
370ParsePixels(
371    xpmData		 *data,
372    unsigned int	  width,
373    unsigned int	  height,
374    unsigned int	  ncolors,
375    unsigned int	  cpp,
376    XpmColor		 *colorTable,
377    xpmHashTable	 *hashtable,
378    unsigned int	**pixels)
379{
380    unsigned int *iptr, *iptr2 = NULL; /* found by Egbert Eich */
381    unsigned int a, x, y;
382
383    if ((height > 0 && width >= UINT_MAX / height) ||
384	width * height >= UINT_MAX / sizeof(unsigned int))
385	return XpmNoMemory;
386#ifndef FOR_MSW
387    iptr2 = (unsigned int *) XpmMalloc(sizeof(unsigned int) * width * height);
388#else
389
390    /*
391     * special treatment to trick DOS malloc(size_t) where size_t is 16 bit!!
392     * XpmMalloc is defined to longMalloc(long) and checks the 16 bit boundary
393     */
394    iptr2 = (unsigned int *)
395	XpmMalloc((long) sizeof(unsigned int) * (long) width * (long) height);
396#endif
397    if (!iptr2)
398	return (XpmNoMemory);
399
400    iptr = iptr2;
401
402    switch (cpp) {
403
404    case (1):				/* Optimize for single character
405					 * colors */
406	{
407	    unsigned short colidx[256];
408
409	    if (ncolors > 256) {
410		XpmFree(iptr2); /* found by Egbert Eich */
411		return (XpmFileInvalid);
412	    }
413
414	    bzero((char *)colidx, 256 * sizeof(short));
415	    for (a = 0; a < ncolors; a++)
416		colidx[(unsigned char)colorTable[a].string[0]] = a + 1;
417
418	    for (y = 0; y < height; y++) {
419		xpmNextString(data);
420		for (x = 0; x < width; x++, iptr++) {
421		    int c = xpmGetC(data);
422
423		    if (c > 0 && c < 256 && colidx[c] != 0)
424			*iptr = colidx[c] - 1;
425		    else {
426			XpmFree(iptr2);
427			return (XpmFileInvalid);
428		    }
429		}
430	    }
431	}
432	break;
433
434    case (2):				/* Optimize for double character
435					 * colors */
436	{
437
438/* free all allocated pointers at all exits */
439#define FREE_CIDX \
440do \
441{ \
442	int f; for (f = 0; f < 256; f++) \
443	if (cidx[f]) XpmFree(cidx[f]); \
444} while(0)
445
446	    /* array of pointers malloced by need */
447	    unsigned short *cidx[256];
448	    unsigned int char1;
449
450	    bzero((char *)cidx, 256 * sizeof(unsigned short *)); /* init */
451	    for (a = 0; a < ncolors; a++) {
452		char1 = (unsigned char) colorTable[a].string[0];
453		if (cidx[char1] == NULL) { /* get new memory */
454		    cidx[char1] = (unsigned short *)
455			XpmCalloc(256, sizeof(unsigned short));
456		    if (cidx[char1] == NULL) { /* new block failed */
457			FREE_CIDX;
458			XpmFree(iptr2);
459			return (XpmNoMemory);
460		    }
461		}
462		cidx[char1][(unsigned char)colorTable[a].string[1]] = a + 1;
463	    }
464
465	    for (y = 0; y < height; y++) {
466		xpmNextString(data);
467		for (x = 0; x < width; x++, iptr++) {
468		    int cc1 = xpmGetC(data);
469		    if (cc1 > 0 && cc1 < 256) {
470			int cc2 = xpmGetC(data);
471			if (cc2 > 0 && cc2 < 256 &&
472			    cidx[cc1] && cidx[cc1][cc2] != 0)
473			    *iptr = cidx[cc1][cc2] - 1;
474			else {
475			    FREE_CIDX;
476			    XpmFree(iptr2);
477			    return (XpmFileInvalid);
478			}
479		    } else {
480			FREE_CIDX;
481			XpmFree(iptr2);
482			return (XpmFileInvalid);
483		    }
484		}
485	    }
486	    FREE_CIDX;
487	}
488	break;
489
490    default:				/* Non-optimized case of long color
491					 * names */
492	{
493	    char *s;
494	    char buf[BUFSIZ];
495
496	    if (cpp >= sizeof(buf)) {
497		XpmFree(iptr2); /* found by Egbert Eich */
498		return (XpmFileInvalid);
499	    }
500
501	    buf[cpp] = '\0';
502	    if (USE_HASHTABLE) {
503		xpmHashAtom *slot;
504
505		for (y = 0; y < height; y++) {
506		    xpmNextString(data);
507		    for (x = 0; x < width; x++, iptr++) {
508			for (a = 0, s = buf; a < cpp; a++, s++)
509			    *s = xpmGetC(data); /* int assigned to char, not a problem here */
510			slot = xpmHashSlot(hashtable, buf);
511			if (!*slot) {	/* no color matches */
512			    XpmFree(iptr2);
513			    return (XpmFileInvalid);
514			}
515			*iptr = HashColorIndex(slot);
516		    }
517		}
518	    } else {
519		for (y = 0; y < height; y++) {
520		    xpmNextString(data);
521		    for (x = 0; x < width; x++, iptr++) {
522			for (a = 0, s = buf; a < cpp; a++, s++)
523			    *s = xpmGetC(data); /* int assigned to char, not a problem here */
524			for (a = 0; a < ncolors; a++)
525			    if (!strcmp(colorTable[a].string, buf))
526				break;
527			if (a == ncolors) {	/* no color matches */
528			    XpmFree(iptr2);
529			    return (XpmFileInvalid);
530			}
531			*iptr = a;
532		    }
533		}
534	    }
535	}
536	break;
537    }
538    *pixels = iptr2;
539    return (XpmSuccess);
540}
541
542int
543xpmParseExtensions(
544    xpmData		 *data,
545    XpmExtension	**extensions,
546    unsigned int	 *nextensions)
547{
548    XpmExtension *exts = NULL, *ext;
549    unsigned int num = 0;
550    unsigned int nlines, a, l, notstart, notend = 0;
551    int status;
552    char *string, *s, *s2, **sp;
553
554    xpmNextString(data);
555    exts = (XpmExtension *) XpmMalloc(sizeof(XpmExtension));
556    /* get the whole string */
557    status = xpmGetString(data, &string, &l);
558    if (status != XpmSuccess) {
559	XpmFree(exts);
560	return (status);
561    }
562    /* look for the key word XPMEXT, skip lines before this */
563    while ((notstart = strncmp("XPMEXT", string, 6))
564	   && (notend = strncmp("XPMENDEXT", string, 9))) {
565	XpmFree(string);
566	xpmNextString(data);
567	status = xpmGetString(data, &string, &l);
568	if (status != XpmSuccess) {
569	    XpmFree(exts);
570	    return (status);
571	}
572    }
573    if (!notstart)
574	notend = strncmp("XPMENDEXT", string, 9);
575    while (!notstart && notend) {
576	/* there starts an extension */
577	ext = (XpmExtension *)
578	    XpmRealloc(exts, (num + 1) * sizeof(XpmExtension)); /* can the loop be forced to iterate often enough to make "(num + 1) * sizeof(XpmExtension)" wrapping? */
579	if (!ext) {
580	    XpmFree(string);
581	    XpmFreeExtensions(exts, num);
582	    return (XpmNoMemory);
583	}
584	exts = ext;
585	ext += num;
586	/* skip whitespace and store its name */
587	s2 = s = string + 6;
588	while (isspace(*s2))
589	    s2++;
590	a = s2 - s;
591	ext->name = (char *) XpmMalloc(l - a - 6);
592	if (!ext->name) {
593	    XpmFree(string);
594	    ext->lines = NULL;
595	    ext->nlines = 0;
596	    XpmFreeExtensions(exts, num + 1);
597	    return (XpmNoMemory);
598	}
599	strncpy(ext->name, s + a, l - a - 6);
600	XpmFree(string);
601	/* now store the related lines */
602	xpmNextString(data);
603	status = xpmGetString(data, &string, &l);
604	if (status != XpmSuccess) {
605	    ext->lines = NULL;
606	    ext->nlines = 0;
607	    XpmFreeExtensions(exts, num + 1);
608	    return (status);
609	}
610	ext->lines = (char **) XpmMalloc(sizeof(char *));
611	nlines = 0;
612	while ((notstart = strncmp("XPMEXT", string, 6))
613	       && (notend = strncmp("XPMENDEXT", string, 9))) {
614	    sp = (char **)
615		XpmRealloc(ext->lines, (nlines + 1) * sizeof(char *)); /* can we iterate enough for a wrapping? */
616	    if (!sp) {
617		XpmFree(string);
618		ext->nlines = nlines;
619		XpmFreeExtensions(exts, num + 1);
620		return (XpmNoMemory);
621	    }
622	    ext->lines = sp;
623	    ext->lines[nlines] = string;
624	    nlines++;
625	    xpmNextString(data);
626	    status = xpmGetString(data, &string, &l);
627	    if (status != XpmSuccess) {
628		ext->nlines = nlines;
629		XpmFreeExtensions(exts, num + 1);
630		return (status);
631	    }
632	}
633	if (!nlines) {
634	    XpmFree(ext->lines);
635	    ext->lines = NULL;
636	}
637	ext->nlines = nlines;
638	num++;
639    }
640    if (!num) {
641	XpmFree(string);
642	XpmFree(exts);
643	exts = NULL;
644    } else if (!notend)
645	XpmFree(string);
646    *nextensions = num;
647    *extensions = exts;
648    return (XpmSuccess);
649}
650
651
652/* function call in case of error */
653#undef RETURN
654#define RETURN(status) \
655do { \
656      goto error; \
657} while(0)
658
659/*
660 * This function parses an Xpm file or data and store the found informations
661 * in an an XpmImage structure which is returned.
662 */
663int
664xpmParseData(
665    xpmData	*data,
666    XpmImage	*image,
667    XpmInfo	*info)
668{
669    /* variables to return */
670    unsigned int width, height, ncolors, cpp;
671    unsigned int x_hotspot, y_hotspot, hotspot = 0, extensions = 0;
672    XpmColor *colorTable = NULL;
673    unsigned int *pixelindex = NULL;
674    char *hints_cmt = NULL;
675    char *colors_cmt = NULL;
676    char *pixels_cmt = NULL;
677
678    unsigned int cmts;
679    int ErrorStatus;
680    xpmHashTable hashtable;
681
682    cmts = info && (info->valuemask & XpmReturnComments);
683
684    /*
685     * parse the header
686     */
687    ErrorStatus = xpmParseHeader(data);
688    if (ErrorStatus != XpmSuccess)
689	return (ErrorStatus);
690
691    /*
692     * read values
693     */
694    ErrorStatus = xpmParseValues(data, &width, &height, &ncolors, &cpp,
695				 &x_hotspot, &y_hotspot, &hotspot,
696				 &extensions);
697    if (ErrorStatus != XpmSuccess)
698	return (ErrorStatus);
699
700    /*
701     * store the hints comment line
702     */
703    if (cmts)
704	xpmGetCmt(data, &hints_cmt);
705
706    /*
707     * init the hashtable
708     */
709    if (USE_HASHTABLE) {
710	ErrorStatus = xpmHashTableInit(&hashtable);
711	if (ErrorStatus != XpmSuccess)
712	    RETURN(ErrorStatus);
713    }
714
715    /*
716     * read colors
717     */
718    ErrorStatus = xpmParseColors(data, ncolors, cpp, &colorTable, &hashtable);
719    if (ErrorStatus != XpmSuccess) {
720	if (USE_HASHTABLE)
721	    xpmHashTableFree(&hashtable);
722	RETURN(ErrorStatus);
723    }
724
725    /*
726     * store the colors comment line
727     */
728    if (cmts)
729	xpmGetCmt(data, &colors_cmt);
730
731    /*
732     * read pixels and index them on color number
733     */
734    ErrorStatus = ParsePixels(data, width, height, ncolors, cpp, colorTable,
735			      &hashtable, &pixelindex);
736
737    /*
738     * free the hastable
739     */
740    if (USE_HASHTABLE)
741	xpmHashTableFree(&hashtable);
742
743    if (ErrorStatus != XpmSuccess)
744	RETURN(ErrorStatus);
745
746    /*
747     * store the pixels comment line
748     */
749    if (cmts)
750	xpmGetCmt(data, &pixels_cmt);
751
752    /*
753     * parse extensions
754     */
755    if (info && (info->valuemask & XpmReturnExtensions)) {
756	if (extensions) {
757	    ErrorStatus = xpmParseExtensions(data, &info->extensions,
758					     &info->nextensions);
759	    if (ErrorStatus != XpmSuccess)
760		RETURN(ErrorStatus);
761	} else {
762	    info->extensions = NULL;
763	    info->nextensions = 0;
764	}
765    }
766
767    /*
768     * store found informations in the XpmImage structure
769     */
770    image->width = width;
771    image->height = height;
772    image->cpp = cpp;
773    image->ncolors = ncolors;
774    image->colorTable = colorTable;
775    image->data = pixelindex;
776
777    if (info) {
778	if (cmts) {
779	    info->hints_cmt = hints_cmt;
780	    info->colors_cmt = colors_cmt;
781	    info->pixels_cmt = pixels_cmt;
782	}
783	if (hotspot) {
784	    info->x_hotspot = x_hotspot;
785	    info->y_hotspot = y_hotspot;
786	    info->valuemask |= XpmHotspot;
787	}
788    }
789    return (XpmSuccess);
790
791/* exit point in case of error, free only locally allocated variables */
792error:
793    if (colorTable)
794	xpmFreeColorTable(colorTable, ncolors);
795    if (pixelindex)
796	XpmFree(pixelindex);
797    if (hints_cmt)
798	XpmFree(hints_cmt);
799    if (colors_cmt)
800	XpmFree(colors_cmt);
801    if (pixels_cmt)
802	XpmFree(pixels_cmt);
803
804    return(ErrorStatus);
805}
806