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