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