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