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
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
));
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 */
58 /* Visual Age cannot deal with old, non-ansi, code */
62 , unsigned int* height
63 , unsigned int* ncolors
65 , unsigned int* x_hotspot
66 , unsigned int* y_hotspot
67 , unsigned int* hotspot
68 , unsigned int* extensions
72 xpmParseValues(data
, width
, height
, ncolors
, cpp
,
73 x_hotspot
, y_hotspot
, hotspot
, extensions
)
75 unsigned int *width
, *height
, *ncolors
, *cpp
;
76 unsigned int *x_hotspot
, *y_hotspot
, *hotspot
;
77 unsigned int *extensions
;
83 if (!data
->format
) { /* XPM 2 or 3 */
86 * read values: width, height, ncolors, chars_per_pixel
88 if (!(xpmNextUI(data
, width
) && xpmNextUI(data
, height
)
89 && xpmNextUI(data
, ncolors
) && xpmNextUI(data
, cpp
)))
90 return (XpmFileInvalid
);
93 * read optional information (hotspot and/or XPMEXT) if any
95 l
= xpmNextWord(data
, buf
, BUFSIZ
);
97 *extensions
= (l
== 6 && !strncmp("XPMEXT", buf
, 6));
99 *hotspot
= (xpmNextUI(data
, x_hotspot
)
100 && xpmNextUI(data
, y_hotspot
));
102 *hotspot
= (xpmatoui(buf
, l
, x_hotspot
)
103 && xpmNextUI(data
, y_hotspot
));
104 l
= xpmNextWord(data
, buf
, BUFSIZ
);
105 *extensions
= (l
== 6 && !strncmp("XPMEXT", buf
, 6));
111 * XPM 1 file read values: width, height, ncolors, chars_per_pixel
115 Bool got_one
, saw_width
= False
, saw_height
= False
;
116 Bool saw_ncolors
= False
, saw_chars_per_pixel
= False
;
118 for (i
= 0; i
< 4; i
++) {
119 l
= xpmNextWord(data
, buf
, BUFSIZ
);
120 if (l
!= 7 || strncmp("#define", buf
, 7))
121 return (XpmFileInvalid
);
122 l
= xpmNextWord(data
, buf
, BUFSIZ
);
124 return (XpmFileInvalid
);
129 ptr
= index(ptr
, '_');
131 return (XpmFileInvalid
);
132 switch (l
- (ptr
- buf
)) {
134 if (saw_width
|| strncmp("_width", ptr
, 6)
135 || !xpmNextUI(data
, width
))
136 return (XpmFileInvalid
);
142 if (saw_height
|| strncmp("_height", ptr
, 7)
143 || !xpmNextUI(data
, height
))
144 return (XpmFileInvalid
);
150 if (saw_ncolors
|| strncmp("_ncolors", ptr
, 8)
151 || !xpmNextUI(data
, ncolors
))
152 return (XpmFileInvalid
);
158 if (saw_chars_per_pixel
159 || strncmp("_chars_per_pixel", ptr
, 16)
160 || !xpmNextUI(data
, cpp
))
161 return (XpmFileInvalid
);
163 saw_chars_per_pixel
= True
;
170 /* skip the end of line */
173 if (!saw_width
|| !saw_height
|| !saw_ncolors
|| !saw_chars_per_pixel
)
174 return (XpmFileInvalid
);
183 /* Visual Age cannot deal with old, non-ansi, code */
186 , unsigned int ncolors
188 , XpmColor
** colorTablePtr
189 , xpmHashTable
* hashtable
193 xpmParseColors(data
, ncolors
, cpp
, colorTablePtr
, hashtable
)
195 unsigned int ncolors
;
197 XpmColor
**colorTablePtr
;
198 xpmHashTable
*hashtable
;
201 unsigned int key
, l
, a
, b
;
202 unsigned int curkey
; /* current color key */
203 unsigned int lastwaskey
; /* key read */
205 char curbuf
[BUFSIZ
]; /* current buffer */
208 XpmColor
*colorTable
;
212 colorTable
= (XpmColor
*) XpmCalloc(ncolors
, sizeof(XpmColor
));
214 return (XpmNoMemory
);
216 if (!data
->format
) { /* XPM 2 or 3 */
217 for (a
= 0, color
= colorTable
; a
< ncolors
; a
++, color
++) {
218 xpmNextString(data
); /* skip the line */
223 color
->string
= (char *) XpmMalloc(cpp
+ 1);
224 if (!color
->string
) {
225 xpmFreeColorTable(colorTable
, ncolors
);
226 return (XpmNoMemory
);
228 for (b
= 0, s
= color
->string
; b
< cpp
; b
++, s
++)
233 * store the string in the hashtable with its color index number
237 xpmHashIntern(hashtable
, color
->string
, HashAtomData(a
));
238 if (ErrorStatus
!= XpmSuccess
) {
239 xpmFreeColorTable(colorTable
, ncolors
);
240 return (ErrorStatus
);
245 * read color keys and values
247 defaults
= (char **) color
;
250 *curbuf
= '\0'; /* init curbuf */
251 while (l
= xpmNextWord(data
, buf
, BUFSIZ
)) {
253 for (key
= 0, sptr
= xpmColorKeys
; key
< NKEYS
; key
++,
255 if ((strlen(*sptr
) == l
) && (!strncmp(*sptr
, buf
, l
)))
258 if (!lastwaskey
&& key
< NKEYS
) { /* open new key */
259 if (curkey
) { /* flush string */
260 s
= (char *) XpmMalloc(strlen(curbuf
) + 1);
262 xpmFreeColorTable(colorTable
, ncolors
);
263 return (XpmNoMemory
);
265 defaults
[curkey
] = s
;
268 curkey
= key
+ 1; /* set new key */
269 *curbuf
= '\0'; /* reset curbuf */
272 if (!curkey
) { /* key without value */
273 xpmFreeColorTable(colorTable
, ncolors
);
274 return (XpmFileInvalid
);
277 strcat(curbuf
, " "); /* append space */
279 strcat(curbuf
, buf
);/* append buf */
283 if (!curkey
) { /* key without value */
284 xpmFreeColorTable(colorTable
, ncolors
);
285 return (XpmFileInvalid
);
287 s
= defaults
[curkey
] = (char *) XpmMalloc(strlen(curbuf
) + 1);
289 xpmFreeColorTable(colorTable
, ncolors
);
290 return (XpmNoMemory
);
295 /* get to the beginning of the first string */
300 for (a
= 0, color
= colorTable
; a
< ncolors
; a
++, color
++) {
305 color
->string
= (char *) XpmMalloc(cpp
+ 1);
306 if (!color
->string
) {
307 xpmFreeColorTable(colorTable
, ncolors
);
308 return (XpmNoMemory
);
310 for (b
= 0, s
= color
->string
; b
< cpp
; b
++, s
++)
315 * store the string in the hashtable with its color index number
319 xpmHashIntern(hashtable
, color
->string
, HashAtomData(a
));
320 if (ErrorStatus
!= XpmSuccess
) {
321 xpmFreeColorTable(colorTable
, ncolors
);
322 return (ErrorStatus
);
329 xpmNextString(data
); /* get to the next string */
330 *curbuf
= '\0'; /* init curbuf */
331 while (l
= xpmNextWord(data
, buf
, BUFSIZ
)) {
333 strcat(curbuf
, " ");/* append space */
335 strcat(curbuf
, buf
); /* append buf */
337 s
= (char *) XpmMalloc(strlen(curbuf
) + 1);
339 xpmFreeColorTable(colorTable
, ncolors
);
340 return (XpmNoMemory
);
344 *curbuf
= '\0'; /* reset curbuf */
346 xpmNextString(data
); /* get to the next string */
349 *colorTablePtr
= colorTable
;
354 /* Visual Age cannot deal with old, non-ansi, code */
359 , unsigned int height
360 , unsigned int ncolors
362 , XpmColor
* colorTable
363 , xpmHashTable
* hashtable
364 , unsigned int** pixels
368 ParsePixels(data
, width
, height
, ncolors
, cpp
, colorTable
, hashtable
, pixels
)
372 unsigned int ncolors
;
374 XpmColor
*colorTable
;
375 xpmHashTable
*hashtable
;
376 unsigned int **pixels
;
379 unsigned int *iptr
, *iptr2
;
380 unsigned int a
, x
, y
;
383 iptr2
= (unsigned int *) XpmMalloc(sizeof(unsigned int) * width
* height
);
387 * special treatment to trick DOS malloc(size_t) where size_t is 16 bit!!
388 * XpmMalloc is defined to longMalloc(long) and checks the 16 bit boundary
390 iptr2
= (unsigned int *)
391 XpmMalloc((long) sizeof(unsigned int) * (long) width
* (long) height
);
394 return (XpmNoMemory
);
400 case (1): /* Optimize for single character
403 unsigned short colidx
[256];
405 bzero((char *)colidx
, 256 * sizeof(short));
406 for (a
= 0; a
< ncolors
; a
++)
407 colidx
[(unsigned char)colorTable
[a
].string
[0]] = a
+ 1;
409 for (y
= 0; y
< height
; y
++) {
411 for (x
= 0; x
< width
; x
++, iptr
++) {
412 int c
= xpmGetC(data
);
414 if (c
> 0 && c
< 256 && colidx
[c
] != 0)
415 *iptr
= colidx
[c
] - 1;
418 return (XpmFileInvalid
);
425 case (2): /* Optimize for double character
429 /* free all allocated pointers at all exits */
430 #define FREE_CIDX {int f; for (f = 0; f < 256; f++) \
431 if (cidx[f]) XpmFree(cidx[f]);}
433 /* array of pointers malloced by need */
434 unsigned short *cidx
[256];
437 bzero((char *)cidx
, 256 * sizeof(unsigned short *)); /* init */
438 for (a
= 0; a
< ncolors
; a
++) {
439 char1
= colorTable
[a
].string
[0];
440 if (cidx
[char1
] == NULL
) { /* get new memory */
441 cidx
[char1
] = (unsigned short *)
442 XpmCalloc(256, sizeof(unsigned short));
443 if (cidx
[char1
] == NULL
) { /* new block failed */
446 return (XpmNoMemory
);
449 cidx
[char1
][(unsigned char)colorTable
[a
].string
[1]] = a
+ 1;
452 for (y
= 0; y
< height
; y
++) {
454 for (x
= 0; x
< width
; x
++, iptr
++) {
455 int cc1
= xpmGetC(data
);
456 if (cc1
> 0 && cc1
< 256) {
457 int cc2
= xpmGetC(data
);
458 if (cc2
> 0 && cc2
< 256 &&
459 cidx
[cc1
] && cidx
[cc1
][cc2
] != 0)
460 *iptr
= cidx
[cc1
][cc2
] - 1;
464 return (XpmFileInvalid
);
469 return (XpmFileInvalid
);
477 default: /* Non-optimized case of long color
487 for (y
= 0; y
< height
; y
++) {
489 for (x
= 0; x
< width
; x
++, iptr
++) {
490 for (a
= 0, s
= buf
; a
< cpp
; a
++, s
++)
492 slot
= xpmHashSlot(hashtable
, buf
);
493 if (!*slot
) { /* no color matches */
495 return (XpmFileInvalid
);
497 *iptr
= HashColorIndex(slot
);
501 for (y
= 0; y
< height
; y
++) {
503 for (x
= 0; x
< width
; x
++, iptr
++) {
504 for (a
= 0, s
= buf
; a
< cpp
; a
++, s
++)
506 for (a
= 0; a
< ncolors
; a
++)
507 if (!strcmp(colorTable
[a
].string
, buf
))
509 if (a
== ncolors
) { /* no color matches */
511 return (XpmFileInvalid
);
525 /* Visual Age cannot deal with old, non-ansi, code */
526 int xpmParseExtensions(
528 , XpmExtension
** extensions
529 , unsigned int* nextensions
533 xpmParseExtensions(data
, extensions
, nextensions
)
535 XpmExtension
**extensions
;
536 unsigned int *nextensions
;
539 XpmExtension
*exts
= NULL
, *ext
;
540 unsigned int num
= 0;
541 unsigned int nlines
, a
, l
, notstart
, notend
= 0;
543 char *string
, *s
, *s2
, **sp
;
546 exts
= (XpmExtension
*) XpmMalloc(sizeof(XpmExtension
));
547 /* get the whole string */
548 status
= xpmGetString(data
, &string
, &l
);
549 if (status
!= XpmSuccess
) {
553 /* look for the key word XPMEXT, skip lines before this */
554 while ((notstart
= strncmp("XPMEXT", string
, 6))
555 && (notend
= strncmp("XPMENDEXT", string
, 9))) {
558 status
= xpmGetString(data
, &string
, &l
);
559 if (status
!= XpmSuccess
) {
565 notend
= strncmp("XPMENDEXT", string
, 9);
566 while (!notstart
&& notend
) {
567 /* there starts an extension */
568 ext
= (XpmExtension
*)
569 XpmRealloc(exts
, (num
+ 1) * sizeof(XpmExtension
));
572 XpmFreeExtensions(exts
, num
);
573 return (XpmNoMemory
);
577 /* skip whitespace and store its name */
582 ext
->name
= (char *) XpmMalloc(l
- a
- 6);
587 XpmFreeExtensions(exts
, num
+ 1);
588 return (XpmNoMemory
);
590 strncpy(ext
->name
, s
+ a
, l
- a
- 6);
592 /* now store the related lines */
594 status
= xpmGetString(data
, &string
, &l
);
595 if (status
!= XpmSuccess
) {
598 XpmFreeExtensions(exts
, num
+ 1);
601 ext
->lines
= (char **) XpmMalloc(sizeof(char *));
603 while ((notstart
= strncmp("XPMEXT", string
, 6))
604 && (notend
= strncmp("XPMENDEXT", string
, 9))) {
606 XpmRealloc(ext
->lines
, (nlines
+ 1) * sizeof(char *));
609 ext
->nlines
= nlines
;
610 XpmFreeExtensions(exts
, num
+ 1);
611 return (XpmNoMemory
);
614 ext
->lines
[nlines
] = string
;
617 status
= xpmGetString(data
, &string
, &l
);
618 if (status
!= XpmSuccess
) {
619 ext
->nlines
= nlines
;
620 XpmFreeExtensions(exts
, num
+ 1);
628 ext
->nlines
= nlines
;
643 /* function call in case of error */
645 #define RETURN(status) \
651 * This function parses an Xpm file or data and store the found informations
652 * in an an XpmImage structure which is returned.
655 /* Visual Age cannot deal with old, non-ansi, code */
663 xpmParseData(data
, image
, info
)
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
)
712 return (ErrorStatus
);
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;
767 * store found informations in the XpmImage structure
769 image
->width
= width
;
770 image
->height
= height
;
772 image
->ncolors
= ncolors
;
773 image
->colorTable
= colorTable
;
774 image
->data
= pixelindex
;
778 info
->hints_cmt
= hints_cmt
;
779 info
->colors_cmt
= colors_cmt
;
780 info
->pixels_cmt
= pixels_cmt
;
783 info
->x_hotspot
= x_hotspot
;
784 info
->y_hotspot
= y_hotspot
;
785 info
->valuemask
|= XpmHotspot
;
790 /* exit point in case of error, free only locally allocated variables */
793 xpmFreeColorTable(colorTable
, ncolors
);