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