parse.c revision 6e7d3316
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
73char *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    char **sptr, *s;
209    XpmColor *color;
210    XpmColor *colorTable;
211    char **defaults;
212    int ErrorStatus;
213
214    if (ncolors >= UINT_MAX / sizeof(XpmColor))
215	return (XpmNoMemory);
216    colorTable = (XpmColor *) XpmCalloc(ncolors, sizeof(XpmColor));
217    if (!colorTable)
218	return (XpmNoMemory);
219
220    if (!data->format) {		/* XPM 2 or 3 */
221	for (a = 0, color = colorTable; a < ncolors; a++, color++) {
222	    xpmNextString(data);	/* skip the line */
223
224	    /*
225	     * read pixel value
226	     */
227	    if (cpp >= UINT_MAX - 1) {
228		xpmFreeColorTable(colorTable, ncolors);
229		return (XpmNoMemory);
230	    }
231	    color->string = (char *) XpmMalloc(cpp + 1);
232	    if (!color->string) {
233		xpmFreeColorTable(colorTable, ncolors);
234		return (XpmNoMemory);
235	    }
236	    for (b = 0, s = color->string; b < cpp; b++, s++)
237		*s = xpmGetC(data);
238	    *s = '\0';
239
240	    /*
241	     * store the string in the hashtable with its color index number
242	     */
243	    if (USE_HASHTABLE) {
244		ErrorStatus =
245		    xpmHashIntern(hashtable, color->string, HashAtomData(a));
246		if (ErrorStatus != XpmSuccess) {
247		    xpmFreeColorTable(colorTable, ncolors);
248		    return (ErrorStatus);
249		}
250	    }
251
252	    /*
253	     * read color keys and values
254	     */
255	    defaults = (char **) color;
256	    curkey = 0;
257	    lastwaskey = 0;
258	    *curbuf = '\0';		/* init curbuf */
259	    while ((l = xpmNextWord(data, buf, BUFSIZ))) {
260		if (!lastwaskey) {
261		    for (key = 0, sptr = xpmColorKeys; key < NKEYS; key++,
262			 sptr++)
263			if ((strlen(*sptr) == l) && (!strncmp(*sptr, buf, l)))
264			    break;
265		}
266		if (!lastwaskey && key < NKEYS) {	/* open new key */
267		    if (curkey) {	/* flush string */
268			len = strlen(curbuf) + 1;
269			s = (char *) XpmMalloc(len);
270			if (!s) {
271			    xpmFreeColorTable(colorTable, ncolors);
272			    return (XpmNoMemory);
273			}
274			defaults[curkey] = s;
275			memcpy(s, curbuf, len);
276		    }
277		    curkey = key + 1;	/* set new key  */
278		    *curbuf = '\0';	/* reset curbuf */
279		    lastwaskey = 1;
280		} else {
281		    if (!curkey) {	/* key without value */
282			xpmFreeColorTable(colorTable, ncolors);
283			return (XpmFileInvalid);
284		    }
285		    if (!lastwaskey)
286			STRLCAT(curbuf, " ", sizeof(curbuf));/* append space */
287		    buf[l] = '\0';
288		    STRLCAT(curbuf, buf, sizeof(curbuf)); /* append buf */
289		    lastwaskey = 0;
290		}
291	    }
292	    if (!curkey) {		/* key without value */
293		xpmFreeColorTable(colorTable, ncolors);
294		return (XpmFileInvalid);
295	    }
296	    len = strlen(curbuf) + 1; /* integer overflow just theoretically possible */
297	    s = defaults[curkey] = (char *) XpmMalloc(len);
298	    if (!s) {
299		xpmFreeColorTable(colorTable, ncolors);
300		return (XpmNoMemory);
301	    }
302	    memcpy(s, curbuf, len);
303	}
304    } else {				/* XPM 1 */
305	/* get to the beginning of the first string */
306	data->Bos = '"';
307	data->Eos = '\0';
308	xpmNextString(data);
309	data->Eos = '"';
310	for (a = 0, color = colorTable; a < ncolors; a++, color++) {
311
312	    /*
313	     * read pixel value
314	     */
315	    if (cpp >= UINT_MAX - 1) {
316		xpmFreeColorTable(colorTable, ncolors);
317		return (XpmNoMemory);
318	    }
319	    color->string = (char *) XpmMalloc(cpp + 1);
320	    if (!color->string) {
321		xpmFreeColorTable(colorTable, ncolors);
322		return (XpmNoMemory);
323	    }
324	    for (b = 0, s = color->string; b < cpp; b++, s++)
325		*s = xpmGetC(data);
326	    *s = '\0';
327
328	    /*
329	     * store the string in the hashtable with its color index number
330	     */
331	    if (USE_HASHTABLE) {
332		ErrorStatus =
333		    xpmHashIntern(hashtable, color->string, HashAtomData(a));
334		if (ErrorStatus != XpmSuccess) {
335		    xpmFreeColorTable(colorTable, ncolors);
336		    return (ErrorStatus);
337		}
338	    }
339
340	    /*
341	     * read color values
342	     */
343	    xpmNextString(data);	/* get to the next string */
344	    *curbuf = '\0';		/* init curbuf */
345	    while ((l = xpmNextWord(data, buf, BUFSIZ))) {
346		if (*curbuf != '\0')
347		    STRLCAT(curbuf, " ", sizeof(curbuf));/* append space */
348		buf[l] = '\0';
349		STRLCAT(curbuf, buf, sizeof(curbuf));	/* append buf */
350	    }
351	    len = strlen(curbuf) + 1;
352	    s = (char *) XpmMalloc(len);
353	    if (!s) {
354		xpmFreeColorTable(colorTable, ncolors);
355		return (XpmNoMemory);
356	    }
357	    memcpy(s, curbuf, len);
358	    color->c_color = s;
359	    *curbuf = '\0';		/* reset curbuf */
360	    if (a < ncolors - 1)	/* can we trust ncolors -> leave data's bounds */
361		xpmNextString(data);	/* get to the next string */
362	}
363    }
364    *colorTablePtr = colorTable;
365    return (XpmSuccess);
366}
367
368static int
369ParsePixels(
370    xpmData		 *data,
371    unsigned int	  width,
372    unsigned int	  height,
373    unsigned int	  ncolors,
374    unsigned int	  cpp,
375    XpmColor		 *colorTable,
376    xpmHashTable	 *hashtable,
377    unsigned int	**pixels)
378{
379    unsigned int *iptr, *iptr2 = NULL; /* found by Egbert Eich */
380    unsigned int a, x, y;
381
382    if ((height > 0 && width >= UINT_MAX / height) ||
383	width * height >= UINT_MAX / sizeof(unsigned int))
384	return XpmNoMemory;
385#ifndef FOR_MSW
386    iptr2 = (unsigned int *) XpmMalloc(sizeof(unsigned int) * width * height);
387#else
388
389    /*
390     * special treatment to trick DOS malloc(size_t) where size_t is 16 bit!!
391     * XpmMalloc is defined to longMalloc(long) and checks the 16 bit boundary
392     */
393    iptr2 = (unsigned int *)
394	XpmMalloc((long) sizeof(unsigned int) * (long) width * (long) height);
395#endif
396    if (!iptr2)
397	return (XpmNoMemory);
398
399    iptr = iptr2;
400
401    switch (cpp) {
402
403    case (1):				/* Optimize for single character
404					 * colors */
405	{
406	    unsigned short colidx[256];
407
408	    if (ncolors > 256) {
409		XpmFree(iptr2); /* found by Egbert Eich */
410		return (XpmFileInvalid);
411	    }
412
413	    bzero((char *)colidx, 256 * sizeof(short));
414	    for (a = 0; a < ncolors; a++)
415		colidx[(unsigned char)colorTable[a].string[0]] = a + 1;
416
417	    for (y = 0; y < height; y++) {
418		xpmNextString(data);
419		for (x = 0; x < width; x++, iptr++) {
420		    int c = xpmGetC(data);
421
422		    if (c > 0 && c < 256 && colidx[c] != 0)
423			*iptr = colidx[c] - 1;
424		    else {
425			XpmFree(iptr2);
426			return (XpmFileInvalid);
427		    }
428		}
429	    }
430	}
431	break;
432
433    case (2):				/* Optimize for double character
434					 * colors */
435	{
436
437/* free all allocated pointers at all exits */
438#define FREE_CIDX \
439do \
440{ \
441	int f; for (f = 0; f < 256; f++) \
442	if (cidx[f]) XpmFree(cidx[f]); \
443} while(0)
444
445	    /* array of pointers malloced by need */
446	    unsigned short *cidx[256];
447	    unsigned int char1;
448
449	    bzero((char *)cidx, 256 * sizeof(unsigned short *)); /* init */
450	    for (a = 0; a < ncolors; a++) {
451		char1 = (unsigned char) colorTable[a].string[0];
452		if (cidx[char1] == NULL) { /* get new memory */
453		    cidx[char1] = (unsigned short *)
454			XpmCalloc(256, sizeof(unsigned short));
455		    if (cidx[char1] == NULL) { /* new block failed */
456			FREE_CIDX;
457			XpmFree(iptr2);
458			return (XpmNoMemory);
459		    }
460		}
461		cidx[char1][(unsigned char)colorTable[a].string[1]] = a + 1;
462	    }
463
464	    for (y = 0; y < height; y++) {
465		xpmNextString(data);
466		for (x = 0; x < width; x++, iptr++) {
467		    int cc1 = xpmGetC(data);
468		    if (cc1 > 0 && cc1 < 256) {
469			int cc2 = xpmGetC(data);
470			if (cc2 > 0 && cc2 < 256 &&
471			    cidx[cc1] && cidx[cc1][cc2] != 0)
472			    *iptr = cidx[cc1][cc2] - 1;
473			else {
474			    FREE_CIDX;
475			    XpmFree(iptr2);
476			    return (XpmFileInvalid);
477			}
478		    } else {
479			FREE_CIDX;
480			XpmFree(iptr2);
481			return (XpmFileInvalid);
482		    }
483		}
484	    }
485	    FREE_CIDX;
486	}
487	break;
488
489    default:				/* Non-optimized case of long color
490					 * names */
491	{
492	    char *s;
493	    char buf[BUFSIZ];
494
495	    if (cpp >= sizeof(buf)) {
496		XpmFree(iptr2); /* found by Egbert Eich */
497		return (XpmFileInvalid);
498	    }
499
500	    buf[cpp] = '\0';
501	    if (USE_HASHTABLE) {
502		xpmHashAtom *slot;
503
504		for (y = 0; y < height; y++) {
505		    xpmNextString(data);
506		    for (x = 0; x < width; x++, iptr++) {
507			for (a = 0, s = buf; a < cpp; a++, s++)
508			    *s = xpmGetC(data); /* int assigned to char, not a problem here */
509			slot = xpmHashSlot(hashtable, buf);
510			if (!*slot) {	/* no color matches */
511			    XpmFree(iptr2);
512			    return (XpmFileInvalid);
513			}
514			*iptr = HashColorIndex(slot);
515		    }
516		}
517	    } else {
518		for (y = 0; y < height; y++) {
519		    xpmNextString(data);
520		    for (x = 0; x < width; x++, iptr++) {
521			for (a = 0, s = buf; a < cpp; a++, s++)
522			    *s = xpmGetC(data); /* int assigned to char, not a problem here */
523			for (a = 0; a < ncolors; a++)
524			    if (!strcmp(colorTable[a].string, buf))
525				break;
526			if (a == ncolors) {	/* no color matches */
527			    XpmFree(iptr2);
528			    return (XpmFileInvalid);
529			}
530			*iptr = a;
531		    }
532		}
533	    }
534	}
535	break;
536    }
537    *pixels = iptr2;
538    return (XpmSuccess);
539}
540
541int
542xpmParseExtensions(
543    xpmData		 *data,
544    XpmExtension	**extensions,
545    unsigned int	 *nextensions)
546{
547    XpmExtension *exts = NULL, *ext;
548    unsigned int num = 0;
549    unsigned int nlines, a, l, notstart, notend = 0;
550    int status;
551    char *string, *s, *s2, **sp;
552
553    xpmNextString(data);
554    exts = (XpmExtension *) XpmMalloc(sizeof(XpmExtension));
555    /* get the whole string */
556    status = xpmGetString(data, &string, &l);
557    if (status != XpmSuccess) {
558	XpmFree(exts);
559	return (status);
560    }
561    /* look for the key word XPMEXT, skip lines before this */
562    while ((notstart = strncmp("XPMEXT", string, 6))
563	   && (notend = strncmp("XPMENDEXT", string, 9))) {
564	XpmFree(string);
565	xpmNextString(data);
566	status = xpmGetString(data, &string, &l);
567	if (status != XpmSuccess) {
568	    XpmFree(exts);
569	    return (status);
570	}
571    }
572    if (!notstart)
573	notend = strncmp("XPMENDEXT", string, 9);
574    while (!notstart && notend) {
575	/* there starts an extension */
576	ext = (XpmExtension *)
577	    XpmRealloc(exts, (num + 1) * sizeof(XpmExtension)); /* can the loop be forced to iterate often enough to make "(num + 1) * sizeof(XpmExtension)" wrapping? */
578	if (!ext) {
579	    XpmFree(string);
580	    XpmFreeExtensions(exts, num);
581	    return (XpmNoMemory);
582	}
583	exts = ext;
584	ext += num;
585	/* skip whitespace and store its name */
586	s2 = s = string + 6;
587	while (isspace(*s2))
588	    s2++;
589	a = s2 - s;
590	ext->name = (char *) XpmMalloc(l - a - 6);
591	if (!ext->name) {
592	    XpmFree(string);
593	    ext->lines = NULL;
594	    ext->nlines = 0;
595	    XpmFreeExtensions(exts, num + 1);
596	    return (XpmNoMemory);
597	}
598	strncpy(ext->name, s + a, l - a - 6);
599	XpmFree(string);
600	/* now store the related lines */
601	xpmNextString(data);
602	status = xpmGetString(data, &string, &l);
603	if (status != XpmSuccess) {
604	    ext->lines = NULL;
605	    ext->nlines = 0;
606	    XpmFreeExtensions(exts, num + 1);
607	    return (status);
608	}
609	ext->lines = (char **) XpmMalloc(sizeof(char *));
610	nlines = 0;
611	while ((notstart = strncmp("XPMEXT", string, 6))
612	       && (notend = strncmp("XPMENDEXT", string, 9))) {
613	    sp = (char **)
614		XpmRealloc(ext->lines, (nlines + 1) * sizeof(char *)); /* can we iterate enough for a wrapping? */
615	    if (!sp) {
616		XpmFree(string);
617		ext->nlines = nlines;
618		XpmFreeExtensions(exts, num + 1);
619		return (XpmNoMemory);
620	    }
621	    ext->lines = sp;
622	    ext->lines[nlines] = string;
623	    nlines++;
624	    xpmNextString(data);
625	    status = xpmGetString(data, &string, &l);
626	    if (status != XpmSuccess) {
627		ext->nlines = nlines;
628		XpmFreeExtensions(exts, num + 1);
629		return (status);
630	    }
631	}
632	if (!nlines) {
633	    XpmFree(ext->lines);
634	    ext->lines = NULL;
635	}
636	ext->nlines = nlines;
637	num++;
638    }
639    if (!num) {
640	XpmFree(string);
641	XpmFree(exts);
642	exts = NULL;
643    } else if (!notend)
644	XpmFree(string);
645    *nextensions = num;
646    *extensions = exts;
647    return (XpmSuccess);
648}
649
650
651/* function call in case of error */
652#undef RETURN
653#define RETURN(status) \
654do { \
655      goto error; \
656} while(0)
657
658/*
659 * This function parses an Xpm file or data and store the found informations
660 * in an an XpmImage structure which is returned.
661 */
662int
663xpmParseData(
664    xpmData	*data,
665    XpmImage	*image,
666    XpmInfo	*info)
667{
668    /* variables to return */
669    unsigned int width, height, ncolors, cpp;
670    unsigned int x_hotspot, y_hotspot, hotspot = 0, extensions = 0;
671    XpmColor *colorTable = NULL;
672    unsigned int *pixelindex = NULL;
673    char *hints_cmt = NULL;
674    char *colors_cmt = NULL;
675    char *pixels_cmt = NULL;
676
677    unsigned int cmts;
678    int ErrorStatus;
679    xpmHashTable hashtable;
680
681    cmts = info && (info->valuemask & XpmReturnComments);
682
683    /*
684     * parse the header
685     */
686    ErrorStatus = xpmParseHeader(data);
687    if (ErrorStatus != XpmSuccess)
688	return (ErrorStatus);
689
690    /*
691     * read values
692     */
693    ErrorStatus = xpmParseValues(data, &width, &height, &ncolors, &cpp,
694				 &x_hotspot, &y_hotspot, &hotspot,
695				 &extensions);
696    if (ErrorStatus != XpmSuccess)
697	return (ErrorStatus);
698
699    /*
700     * store the hints comment line
701     */
702    if (cmts)
703	xpmGetCmt(data, &hints_cmt);
704
705    /*
706     * init the hashtable
707     */
708    if (USE_HASHTABLE) {
709	ErrorStatus = xpmHashTableInit(&hashtable);
710	if (ErrorStatus != XpmSuccess)
711	    RETURN(ErrorStatus);
712    }
713
714    /*
715     * read colors
716     */
717    ErrorStatus = xpmParseColors(data, ncolors, cpp, &colorTable, &hashtable);
718    if (ErrorStatus != XpmSuccess) {
719	if (USE_HASHTABLE)
720	    xpmHashTableFree(&hashtable);
721	RETURN(ErrorStatus);
722    }
723
724    /*
725     * store the colors comment line
726     */
727    if (cmts)
728	xpmGetCmt(data, &colors_cmt);
729
730    /*
731     * read pixels and index them on color number
732     */
733    ErrorStatus = ParsePixels(data, width, height, ncolors, cpp, colorTable,
734			      &hashtable, &pixelindex);
735
736    /*
737     * free the hastable
738     */
739    if (USE_HASHTABLE)
740	xpmHashTableFree(&hashtable);
741
742    if (ErrorStatus != XpmSuccess)
743	RETURN(ErrorStatus);
744
745    /*
746     * store the pixels comment line
747     */
748    if (cmts)
749	xpmGetCmt(data, &pixels_cmt);
750
751    /*
752     * parse extensions
753     */
754    if (info && (info->valuemask & XpmReturnExtensions)) {
755	if (extensions) {
756	    ErrorStatus = xpmParseExtensions(data, &info->extensions,
757					     &info->nextensions);
758	    if (ErrorStatus != XpmSuccess)
759		RETURN(ErrorStatus);
760	} else {
761	    info->extensions = NULL;
762	    info->nextensions = 0;
763	}
764    }
765
766    /*
767     * store found informations in the XpmImage structure
768     */
769    image->width = width;
770    image->height = height;
771    image->cpp = cpp;
772    image->ncolors = ncolors;
773    image->colorTable = colorTable;
774    image->data = pixelindex;
775
776    if (info) {
777	if (cmts) {
778	    info->hints_cmt = hints_cmt;
779	    info->colors_cmt = colors_cmt;
780	    info->pixels_cmt = pixels_cmt;
781	}
782	if (hotspot) {
783	    info->x_hotspot = x_hotspot;
784	    info->y_hotspot = y_hotspot;
785	    info->valuemask |= XpmHotspot;
786	}
787    }
788    return (XpmSuccess);
789
790/* exit point in case of error, free only locally allocated variables */
791error:
792    if (colorTable)
793	xpmFreeColorTable(colorTable, ncolors);
794    if (pixelindex)
795	XpmFree(pixelindex);
796    if (hints_cmt)
797	XpmFree(hints_cmt);
798    if (colors_cmt)
799	XpmFree(colors_cmt);
800    if (pixels_cmt)
801	XpmFree(pixels_cmt);
802
803    return(ErrorStatus);
804}
805