2 * Copyright (C) 1989-95 GROUPE BULL
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
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.
26 /*****************************************************************************\
30 * Parse an XPM file or array and store the found informations *
31 * in the given XpmImage structure. *
33 * Developed by Arnaud Le Hors *
34 \*****************************************************************************/
37 * The code related to FOR_MSW has been added by
38 * HeDu (hedu@cul-ipn.uni-kiel.de) 4/94
41 /* October 2004, source code review by Thomas Biege <thomas@suse.de> */
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)
58 # define STRLCAT(dst, src, dstsize) do { \
59 if ((strlen(dst) + strlen(src)) < (dstsize)) \
61 else return (XpmFileInvalid); } while(0)
62 # define STRLCPY(dst, src, dstsize) do { \
63 if (strlen(src) < (dstsize)) \
65 else return (XpmFileInvalid); } while(0)
68 LFUNC(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));
73 const 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 */
86 unsigned int *ncolors,
88 unsigned int *x_hotspot,
89 unsigned int *y_hotspot,
90 unsigned int *hotspot,
91 unsigned int *extensions)
96 if (!data->format) { /* XPM 2 or 3 */
99 * read values: width, height, ncolors, chars_per_pixel
101 if (!(xpmNextUI(data, width) && xpmNextUI(data, height)
102 && xpmNextUI(data, ncolors) && xpmNextUI(data, cpp)))
103 return (XpmFileInvalid);
106 * read optional information (hotspot and/or XPMEXT) if any
108 l = xpmNextWord(data, buf, BUFSIZ);
110 *extensions = (l == 6 && !strncmp("XPMEXT", buf, 6));
112 *hotspot = (xpmNextUI(data, x_hotspot)
113 && xpmNextUI(data, y_hotspot));
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));
124 * XPM 1 file read values: width, height, ncolors, chars_per_pixel
128 Bool got_one, saw_width = False, saw_height = False;
129 Bool saw_ncolors = False, saw_chars_per_pixel = False;
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);
137 return (XpmFileInvalid);
142 ptr = strchr(ptr, '_');
144 return (XpmFileInvalid);
145 switch (l - (ptr - buf)) {
147 if (saw_width || strncmp("_width", ptr, 6)
148 || !xpmNextUI(data, width))
149 return (XpmFileInvalid);
155 if (saw_height || strncmp("_height", ptr, 7)
156 || !xpmNextUI(data, height))
157 return (XpmFileInvalid);
163 if (saw_ncolors || strncmp("_ncolors", ptr, 8)
164 || !xpmNextUI(data, ncolors))
165 return (XpmFileInvalid);
171 if (saw_chars_per_pixel
172 || strncmp("_chars_per_pixel", ptr, 16)
173 || !xpmNextUI(data, cpp))
174 return (XpmFileInvalid);
176 saw_chars_per_pixel = True;
183 /* skip the end of line */
186 if (!saw_width || !saw_height || !saw_ncolors || !saw_chars_per_pixel)
187 return (XpmFileInvalid);
198 unsigned int ncolors,
200 XpmColor **colorTablePtr,
201 xpmHashTable *hashtable)
203 unsigned int key = 0, l, a, b, len;
204 unsigned int curkey; /* current color key */
205 unsigned int lastwaskey; /* key read */
207 char curbuf[BUFSIZ]; /* current buffer */
211 XpmColor *colorTable;
215 if (ncolors >= UINT_MAX / sizeof(XpmColor))
216 return (XpmNoMemory);
217 colorTable = (XpmColor *) XpmCalloc(ncolors, sizeof(XpmColor));
219 return (XpmNoMemory);
221 if (!data->format) { /* XPM 2 or 3 */
222 for (a = 0, color = colorTable; a < ncolors; a++, color++) {
223 xpmNextString(data); /* skip the line */
228 if (cpp >= UINT_MAX - 1) {
229 xpmFreeColorTable(colorTable, ncolors);
230 return (XpmNoMemory);
232 color->string = (char *) XpmMalloc(cpp + 1);
233 if (!color->string) {
234 xpmFreeColorTable(colorTable, ncolors);
235 return (XpmNoMemory);
237 for (b = 0, s = color->string; b < cpp; b++, s++)
242 * store the string in the hashtable with its color index number
246 xpmHashIntern(hashtable, color->string, HashAtomData(a));
247 if (ErrorStatus != XpmSuccess) {
248 xpmFreeColorTable(colorTable, ncolors);
249 return (ErrorStatus);
254 * read color keys and values
256 defaults = (char **) color;
259 *curbuf = '\0'; /* init curbuf */
260 while ((l = xpmNextWord(data, buf, BUFSIZ))) {
262 for (key = 0, sptr = xpmColorKeys; key < NKEYS; key++,
264 if ((strlen(*sptr) == l) && (!strncmp(*sptr, buf, l)))
267 if (!lastwaskey && key < NKEYS) { /* open new key */
268 if (curkey) { /* flush string */
269 len = strlen(curbuf) + 1;
270 s = (char *) XpmMalloc(len);
272 xpmFreeColorTable(colorTable, ncolors);
273 return (XpmNoMemory);
275 defaults[curkey] = s;
276 memcpy(s, curbuf, len);
278 curkey = key + 1; /* set new key */
279 *curbuf = '\0'; /* reset curbuf */
282 if (!curkey) { /* key without value */
283 xpmFreeColorTable(colorTable, ncolors);
284 return (XpmFileInvalid);
287 STRLCAT(curbuf, " ", sizeof(curbuf));/* append space */
289 STRLCAT(curbuf, buf, sizeof(curbuf)); /* append buf */
293 if (!curkey) { /* key without value */
294 xpmFreeColorTable(colorTable, ncolors);
295 return (XpmFileInvalid);
297 len = strlen(curbuf) + 1; /* integer overflow just theoretically possible */
298 s = defaults[curkey] = (char *) XpmMalloc(len);
300 xpmFreeColorTable(colorTable, ncolors);
301 return (XpmNoMemory);
303 memcpy(s, curbuf, len);
306 /* get to the beginning of the first string */
311 for (a = 0, color = colorTable; a < ncolors; a++, color++) {
316 if (cpp >= UINT_MAX - 1) {
317 xpmFreeColorTable(colorTable, ncolors);
318 return (XpmNoMemory);
320 color->string = (char *) XpmMalloc(cpp + 1);
321 if (!color->string) {
322 xpmFreeColorTable(colorTable, ncolors);
323 return (XpmNoMemory);
325 for (b = 0, s = color->string; b < cpp; b++, s++)
330 * store the string in the hashtable with its color index number
334 xpmHashIntern(hashtable, color->string, HashAtomData(a));
335 if (ErrorStatus != XpmSuccess) {
336 xpmFreeColorTable(colorTable, ncolors);
337 return (ErrorStatus);
344 xpmNextString(data); /* get to the next string */
345 *curbuf = '\0'; /* init curbuf */
346 while ((l = xpmNextWord(data, buf, BUFSIZ))) {
348 STRLCAT(curbuf, " ", sizeof(curbuf));/* append space */
350 STRLCAT(curbuf, buf, sizeof(curbuf)); /* append buf */
352 len = strlen(curbuf) + 1;
353 s = (char *) XpmMalloc(len);
355 xpmFreeColorTable(colorTable, ncolors);
356 return (XpmNoMemory);
358 memcpy(s, curbuf, len);
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 */
365 *colorTablePtr = colorTable;
374 unsigned int ncolors,
376 XpmColor *colorTable,
377 xpmHashTable *hashtable,
378 unsigned int **pixels)
380 unsigned int *iptr, *iptr2 = NULL; /* found by Egbert Eich */
381 unsigned int a, x, y;
383 if ((height > 0 && width >= UINT_MAX / height) ||
384 width * height >= UINT_MAX / sizeof(unsigned int))
387 iptr2 = (unsigned int *) XpmMalloc(sizeof(unsigned int) * width * height);
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
394 iptr2 = (unsigned int *)
395 XpmMalloc((long) sizeof(unsigned int) * (long) width * (long) height);
398 return (XpmNoMemory);
404 case (1): /* Optimize for single character
407 unsigned short colidx[256];
410 XpmFree(iptr2); /* found by Egbert Eich */
411 return (XpmFileInvalid);
414 bzero((char *)colidx, 256 * sizeof(short));
415 for (a = 0; a < ncolors; a++)
416 colidx[(unsigned char)colorTable[a].string[0]] = a + 1;
418 for (y = 0; y < height; y++) {
420 for (x = 0; x < width; x++, iptr++) {
421 int c = xpmGetC(data);
423 if (c > 0 && c < 256 && colidx[c] != 0)
424 *iptr = colidx[c] - 1;
427 return (XpmFileInvalid);
434 case (2): /* Optimize for double character
438 /* free all allocated pointers at all exits */
442 int f; for (f = 0; f < 256; f++) \
443 if (cidx[f]) XpmFree(cidx[f]); \
446 /* array of pointers malloced by need */
447 unsigned short *cidx[256];
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 */
459 return (XpmNoMemory);
462 cidx[char1][(unsigned char)colorTable[a].string[1]] = a + 1;
465 for (y = 0; y < height; y++) {
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;
477 return (XpmFileInvalid);
482 return (XpmFileInvalid);
490 default: /* Non-optimized case of long color
496 if (cpp >= sizeof(buf)) {
497 XpmFree(iptr2); /* found by Egbert Eich */
498 return (XpmFileInvalid);
505 for (y = 0; y < height; y++) {
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 */
513 return (XpmFileInvalid);
515 *iptr = HashColorIndex(slot);
519 for (y = 0; y < height; y++) {
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))
527 if (a == ncolors) { /* no color matches */
529 return (XpmFileInvalid);
545 XpmExtension **extensions,
546 unsigned int *nextensions)
548 XpmExtension *exts = NULL, *ext;
549 unsigned int num = 0;
550 unsigned int nlines, a, l, notstart, notend = 0;
552 char *string, *s, *s2, **sp;
555 exts = (XpmExtension *) XpmMalloc(sizeof(XpmExtension));
556 /* get the whole string */
557 status = xpmGetString(data, &string, &l);
558 if (status != XpmSuccess) {
562 /* look for the key word XPMEXT, skip lines before this */
563 while ((notstart = strncmp("XPMEXT", string, 6))
564 && (notend = strncmp("XPMENDEXT", string, 9))) {
567 status = xpmGetString(data, &string, &l);
568 if (status != XpmSuccess) {
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? */
581 XpmFreeExtensions(exts, num);
582 return (XpmNoMemory);
586 /* skip whitespace and store its name */
591 ext->name = (char *) XpmMalloc(l - a - 6);
596 XpmFreeExtensions(exts, num + 1);
597 return (XpmNoMemory);
599 strncpy(ext->name, s + a, l - a - 6);
601 /* now store the related lines */
603 status = xpmGetString(data, &string, &l);
604 if (status != XpmSuccess) {
607 XpmFreeExtensions(exts, num + 1);
610 ext->lines = (char **) XpmMalloc(sizeof(char *));
612 while ((notstart = strncmp("XPMEXT", string, 6))
613 && (notend = strncmp("XPMENDEXT", string, 9))) {
615 XpmRealloc(ext->lines, (nlines + 1) * sizeof(char *)); /* can we iterate enough for a wrapping? */
618 ext->nlines = nlines;
619 XpmFreeExtensions(exts, num + 1);
620 return (XpmNoMemory);
623 ext->lines[nlines] = string;
626 status = xpmGetString(data, &string, &l);
627 if (status != XpmSuccess) {
628 ext->nlines = nlines;
629 XpmFreeExtensions(exts, num + 1);
637 ext->nlines = nlines;
652 /* function call in case of error */
654 #define RETURN(status) \
660 * This function parses an Xpm file or data and store the found informations
661 * in an an XpmImage structure which is returned.
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;
680 xpmHashTable hashtable;
682 cmts = info && (info->valuemask & XpmReturnComments);
687 ErrorStatus = xpmParseHeader(data);
688 if (ErrorStatus != XpmSuccess)
689 return (ErrorStatus);
694 ErrorStatus = xpmParseValues(data, &width, &height, &ncolors, &cpp,
695 &x_hotspot, &y_hotspot, &hotspot,
697 if (ErrorStatus != XpmSuccess)
698 return (ErrorStatus);
701 * store the hints comment line
704 xpmGetCmt(data, &hints_cmt);
710 ErrorStatus = xpmHashTableInit(&hashtable);
711 if (ErrorStatus != XpmSuccess)
718 ErrorStatus = xpmParseColors(data, ncolors, cpp, &colorTable, &hashtable);
719 if (ErrorStatus != XpmSuccess) {
721 xpmHashTableFree(&hashtable);
726 * store the colors comment line
729 xpmGetCmt(data, &colors_cmt);
732 * read pixels and index them on color number
734 ErrorStatus = ParsePixels(data, width, height, ncolors, cpp, colorTable,
735 &hashtable, &pixelindex);
741 xpmHashTableFree(&hashtable);
743 if (ErrorStatus != XpmSuccess)
747 * store the pixels comment line
750 xpmGetCmt(data, &pixels_cmt);
755 if (info && (info->valuemask & XpmReturnExtensions)) {
757 ErrorStatus = xpmParseExtensions(data, &info->extensions,
759 if (ErrorStatus != XpmSuccess)
762 info->extensions = NULL;
763 info->nextensions = 0;
768 * store found informations in the XpmImage structure
770 image->width = width;
771 image->height = height;
773 image->ncolors = ncolors;
774 image->colorTable = colorTable;
775 image->data = pixelindex;
779 info->hints_cmt = hints_cmt;
780 info->colors_cmt = colors_cmt;
781 info->pixels_cmt = pixels_cmt;
784 info->x_hotspot = x_hotspot;
785 info->y_hotspot = y_hotspot;
786 info->valuemask |= XpmHotspot;
791 /* exit point in case of error, free only locally allocated variables */
794 xpmFreeColorTable(colorTable, ncolors);