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