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