1
/* $XdotOrg: xc/extras/Xpm/lib/parse.c,v 1.2.4.1 2004/09/15 15:47:39 daniel Exp $ */
3
* Copyright (C) 1989-95 GROUPE BULL
5
* Permission is hereby granted, free of charge, to any person obtaining a copy
6
* of this software and associated documentation files (the "Software"), to
7
* deal in the Software without restriction, including without limitation the
8
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9
* sell copies of the Software, and to permit persons to whom the Software is
10
* furnished to do so, subject to the following conditions:
12
* The above copyright notice and this permission notice shall be included in
13
* all copies or substantial portions of the Software.
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
* GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
* Except as contained in this notice, the name of GROUPE BULL shall not be
23
* used in advertising or otherwise to promote the sale, use or other dealings
24
* in this Software without prior written authorization from GROUPE BULL.
26
/* $XFree86: xc/extras/Xpm/lib/parse.c,v 1.2 2000/09/26 15:56:43 tsi Exp $ */
28
/*****************************************************************************\
32
* Parse an XPM file or array and store the found informations *
33
* in the given XpmImage structure. *
35
* Developed by Arnaud Le Hors *
36
\*****************************************************************************/
40
* The code related to FOR_MSW has been added by
41
* HeDu (hedu@cul-ipn.uni-kiel.de) 4/94
44
/* October 2004, source code review by Thomas Biege <thomas@suse.de> */
53
#if defined(HAS_STRLCAT) || defined(HAVE_STRLCAT)
54
# define STRLCAT(dst, src, dstsize) do { \
55
if (strlcat(dst, src, dstsize) >= (dstsize)) \
56
return (XpmFileInvalid); } while(0)
57
# define STRLCPY(dst, src, dstsize) do { \
58
if (strlcpy(dst, src, dstsize) >= (dstsize)) \
59
return (XpmFileInvalid); } while(0)
61
# define STRLCAT(dst, src, dstsize) do { \
62
if ((strlen(dst) + strlen(src)) < (dstsize)) \
64
else return (XpmFileInvalid); } while(0)
65
# define STRLCPY(dst, src, dstsize) do { \
66
if (strlen(src) < (dstsize)) \
68
else return (XpmFileInvalid); } while(0)
71
LFUNC(ParsePixels, int, (xpmData *data, unsigned int width,
72
unsigned int height, unsigned int ncolors,
73
unsigned int cpp, XpmColor *colorTable,
74
xpmHashTable *hashtable, unsigned int **pixels));
76
char *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 */
85
xpmParseValues(data, width, height, ncolors, cpp,
86
x_hotspot, y_hotspot, hotspot, extensions)
88
unsigned int *width, *height, *ncolors, *cpp;
89
unsigned int *x_hotspot, *y_hotspot, *hotspot;
90
unsigned int *extensions;
95
if (!data->format) { /* XPM 2 or 3 */
98
* read values: width, height, ncolors, chars_per_pixel
100
if (!(xpmNextUI(data, width) && xpmNextUI(data, height)
101
&& xpmNextUI(data, ncolors) && xpmNextUI(data, cpp)))
102
return (XpmFileInvalid);
105
* read optional information (hotspot and/or XPMEXT) if any
107
l = xpmNextWord(data, buf, BUFSIZ);
109
*extensions = (l == 6 && !strncmp("XPMEXT", buf, 6));
111
*hotspot = (xpmNextUI(data, x_hotspot)
112
&& xpmNextUI(data, y_hotspot));
114
*hotspot = (xpmatoui(buf, l, x_hotspot)
115
&& xpmNextUI(data, y_hotspot));
116
l = xpmNextWord(data, buf, BUFSIZ);
117
*extensions = (l == 6 && !strncmp("XPMEXT", buf, 6));
123
* XPM 1 file read values: width, height, ncolors, chars_per_pixel
127
Bool got_one, saw_width = False, saw_height = False;
128
Bool saw_ncolors = False, saw_chars_per_pixel = False;
130
for (i = 0; i < 4; i++) {
131
l = xpmNextWord(data, buf, BUFSIZ);
132
if (l != 7 || strncmp("#define", buf, 7))
133
return (XpmFileInvalid);
134
l = xpmNextWord(data, buf, BUFSIZ);
136
return (XpmFileInvalid);
141
ptr = index(ptr, '_');
143
return (XpmFileInvalid);
144
switch (l - (ptr - buf)) {
146
if (saw_width || strncmp("_width", ptr, 6)
147
|| !xpmNextUI(data, width))
148
return (XpmFileInvalid);
154
if (saw_height || strncmp("_height", ptr, 7)
155
|| !xpmNextUI(data, height))
156
return (XpmFileInvalid);
162
if (saw_ncolors || strncmp("_ncolors", ptr, 8)
163
|| !xpmNextUI(data, ncolors))
164
return (XpmFileInvalid);
170
if (saw_chars_per_pixel
171
|| strncmp("_chars_per_pixel", ptr, 16)
172
|| !xpmNextUI(data, cpp))
173
return (XpmFileInvalid);
175
saw_chars_per_pixel = True;
182
/* skip the end of line */
185
if (!saw_width || !saw_height || !saw_ncolors || !saw_chars_per_pixel)
186
return (XpmFileInvalid);
195
xpmParseColors(data, ncolors, cpp, colorTablePtr, hashtable)
197
unsigned int ncolors;
199
XpmColor **colorTablePtr;
200
xpmHashTable *hashtable;
202
unsigned int key = 0, l, a, b, len;
203
unsigned int curkey; /* current color key */
204
unsigned int lastwaskey; /* key read */
206
char curbuf[BUFSIZ]; /* current buffer */
209
XpmColor *colorTable;
213
if (ncolors >= UINT_MAX / sizeof(XpmColor))
214
return (XpmNoMemory);
215
colorTable = (XpmColor *) XpmCalloc(ncolors, sizeof(XpmColor));
217
return (XpmNoMemory);
219
if (!data->format) { /* XPM 2 or 3 */
220
for (a = 0, color = colorTable; a < ncolors; a++, color++) {
221
xpmNextString(data); /* skip the line */
226
if (cpp >= UINT_MAX - 1) {
227
xpmFreeColorTable(colorTable, ncolors);
228
return (XpmNoMemory);
230
color->string = (char *) XpmMalloc(cpp + 1);
231
if (!color->string) {
232
xpmFreeColorTable(colorTable, ncolors);
233
return (XpmNoMemory);
235
for (b = 0, s = color->string; b < cpp; b++, s++)
240
* store the string in the hashtable with its color index number
244
xpmHashIntern(hashtable, color->string, HashAtomData(a));
245
if (ErrorStatus != XpmSuccess) {
246
xpmFreeColorTable(colorTable, ncolors);
247
return (ErrorStatus);
252
* read color keys and values
254
defaults = (char **) color;
257
*curbuf = '\0'; /* init curbuf */
258
while ((l = xpmNextWord(data, buf, BUFSIZ))) {
260
for (key = 0, sptr = xpmColorKeys; key < NKEYS; key++,
262
if ((strlen(*sptr) == l) && (!strncmp(*sptr, buf, l)))
265
if (!lastwaskey && key < NKEYS) { /* open new key */
266
if (curkey) { /* flush string */
267
len = strlen(curbuf) + 1;
268
s = (char *) XpmMalloc(len);
270
xpmFreeColorTable(colorTable, ncolors);
271
return (XpmNoMemory);
273
defaults[curkey] = s;
274
memcpy(s, curbuf, len);
276
curkey = key + 1; /* set new key */
277
*curbuf = '\0'; /* reset curbuf */
280
if (!curkey) { /* key without value */
281
xpmFreeColorTable(colorTable, ncolors);
282
return (XpmFileInvalid);
285
STRLCAT(curbuf, " ", sizeof(curbuf));/* append space */
287
STRLCAT(curbuf, buf, sizeof(curbuf)); /* append buf */
291
if (!curkey) { /* key without value */
292
xpmFreeColorTable(colorTable, ncolors);
293
return (XpmFileInvalid);
295
len = strlen(curbuf) + 1; /* integer overflow just theoretically possible */
296
s = defaults[curkey] = (char *) XpmMalloc(len);
298
xpmFreeColorTable(colorTable, ncolors);
299
return (XpmNoMemory);
301
memcpy(s, curbuf, len);
304
/* get to the beginning of the first string */
309
for (a = 0, color = colorTable; a < ncolors; a++, color++) {
314
if (cpp >= UINT_MAX - 1) {
315
xpmFreeColorTable(colorTable, ncolors);
316
return (XpmNoMemory);
318
color->string = (char *) XpmMalloc(cpp + 1);
319
if (!color->string) {
320
xpmFreeColorTable(colorTable, ncolors);
321
return (XpmNoMemory);
323
for (b = 0, s = color->string; b < cpp; b++, s++)
328
* store the string in the hashtable with its color index number
332
xpmHashIntern(hashtable, color->string, HashAtomData(a));
333
if (ErrorStatus != XpmSuccess) {
334
xpmFreeColorTable(colorTable, ncolors);
335
return (ErrorStatus);
342
xpmNextString(data); /* get to the next string */
343
*curbuf = '\0'; /* init curbuf */
344
while ((l = xpmNextWord(data, buf, BUFSIZ))) {
346
STRLCAT(curbuf, " ", sizeof(curbuf));/* append space */
348
STRLCAT(curbuf, buf, sizeof(curbuf)); /* append buf */
350
len = strlen(curbuf) + 1;
351
s = (char *) XpmMalloc(len);
353
xpmFreeColorTable(colorTable, ncolors);
354
return (XpmNoMemory);
356
memcpy(s, curbuf, len);
358
*curbuf = '\0'; /* reset curbuf */
359
if (a < ncolors - 1) /* can we trust ncolors -> leave data's bounds */
360
xpmNextString(data); /* get to the next string */
363
*colorTablePtr = colorTable;
368
ParsePixels(data, width, height, ncolors, cpp, colorTable, hashtable, pixels)
372
unsigned int ncolors;
374
XpmColor *colorTable;
375
xpmHashTable *hashtable;
376
unsigned int **pixels;
378
unsigned int *iptr, *iptr2 = NULL; /* found by Egbert Eich */
379
unsigned int a, x, y;
381
if ((height > 0 && width >= UINT_MAX / height) ||
382
width * height >= UINT_MAX / sizeof(unsigned int))
385
iptr2 = (unsigned int *) XpmMalloc(sizeof(unsigned int) * width * height);
389
* special treatment to trick DOS malloc(size_t) where size_t is 16 bit!!
390
* XpmMalloc is defined to longMalloc(long) and checks the 16 bit boundary
392
iptr2 = (unsigned int *)
393
XpmMalloc((long) sizeof(unsigned int) * (long) width * (long) height);
396
return (XpmNoMemory);
402
case (1): /* Optimize for single character
405
unsigned short colidx[256];
408
XpmFree(iptr2); /* found by Egbert Eich */
409
return (XpmFileInvalid);
412
bzero((char *)colidx, 256 * sizeof(short));
413
for (a = 0; a < ncolors; a++)
414
colidx[(unsigned char)colorTable[a].string[0]] = a + 1;
416
for (y = 0; y < height; y++) {
418
for (x = 0; x < width; x++, iptr++) {
419
int c = xpmGetC(data);
421
if (c > 0 && c < 256 && colidx[c] != 0)
422
*iptr = colidx[c] - 1;
425
return (XpmFileInvalid);
432
case (2): /* Optimize for double character
436
/* free all allocated pointers at all exits */
440
int f; for (f = 0; f < 256; f++) \
441
if (cidx[f]) XpmFree(cidx[f]); \
444
/* array of pointers malloced by need */
445
unsigned short *cidx[256];
448
bzero((char *)cidx, 256 * sizeof(unsigned short *)); /* init */
449
for (a = 0; a < ncolors; a++) {
450
char1 = (unsigned char) colorTable[a].string[0];
451
if (cidx[char1] == NULL) { /* get new memory */
452
cidx[char1] = (unsigned short *)
453
XpmCalloc(256, sizeof(unsigned short));
454
if (cidx[char1] == NULL) { /* new block failed */
457
return (XpmNoMemory);
460
cidx[char1][(unsigned char)colorTable[a].string[1]] = a + 1;
463
for (y = 0; y < height; y++) {
465
for (x = 0; x < width; x++, iptr++) {
466
int cc1 = xpmGetC(data);
467
if (cc1 > 0 && cc1 < 256) {
468
int cc2 = xpmGetC(data);
469
if (cc2 > 0 && cc2 < 256 &&
470
cidx[cc1] && cidx[cc1][cc2] != 0)
471
*iptr = cidx[cc1][cc2] - 1;
475
return (XpmFileInvalid);
480
return (XpmFileInvalid);
488
default: /* Non-optimized case of long color
494
if (cpp >= sizeof(buf)) {
495
XpmFree(iptr2); /* found by Egbert Eich */
496
return (XpmFileInvalid);
503
for (y = 0; y < height; y++) {
505
for (x = 0; x < width; x++, iptr++) {
506
for (a = 0, s = buf; a < cpp; a++, s++)
507
*s = xpmGetC(data); /* int assigned to char, not a problem here */
508
slot = xpmHashSlot(hashtable, buf);
509
if (!*slot) { /* no color matches */
511
return (XpmFileInvalid);
513
*iptr = HashColorIndex(slot);
517
for (y = 0; y < height; y++) {
519
for (x = 0; x < width; x++, iptr++) {
520
for (a = 0, s = buf; a < cpp; a++, s++)
521
*s = xpmGetC(data); /* int assigned to char, not a problem here */
522
for (a = 0; a < ncolors; a++)
523
if (!strcmp(colorTable[a].string, buf))
525
if (a == ncolors) { /* no color matches */
527
return (XpmFileInvalid);
541
xpmParseExtensions(data, extensions, nextensions)
543
XpmExtension **extensions;
544
unsigned int *nextensions;
546
XpmExtension *exts = NULL, *ext;
547
unsigned int num = 0;
548
unsigned int nlines, a, l, notstart, notend = 0;
550
char *string, *s, *s2, **sp;
553
exts = (XpmExtension *) XpmMalloc(sizeof(XpmExtension));
554
/* get the whole string */
555
status = xpmGetString(data, &string, &l);
556
if (status != XpmSuccess) {
560
/* look for the key word XPMEXT, skip lines before this */
561
while ((notstart = strncmp("XPMEXT", string, 6))
562
&& (notend = strncmp("XPMENDEXT", string, 9))) {
565
status = xpmGetString(data, &string, &l);
566
if (status != XpmSuccess) {
572
notend = strncmp("XPMENDEXT", string, 9);
573
while (!notstart && notend) {
574
/* there starts an extension */
575
ext = (XpmExtension *)
576
XpmRealloc(exts, (num + 1) * sizeof(XpmExtension)); /* can the loop be forced to iterate often enough to make "(num + 1) * sizeof(XpmExtension)" wrapping? */
579
XpmFreeExtensions(exts, num);
580
return (XpmNoMemory);
584
/* skip whitespace and store its name */
589
ext->name = (char *) XpmMalloc(l - a - 6);
594
XpmFreeExtensions(exts, num + 1);
595
return (XpmNoMemory);
597
strncpy(ext->name, s + a, l - a - 6);
599
/* now store the related lines */
601
status = xpmGetString(data, &string, &l);
602
if (status != XpmSuccess) {
605
XpmFreeExtensions(exts, num + 1);
608
ext->lines = (char **) XpmMalloc(sizeof(char *));
610
while ((notstart = strncmp("XPMEXT", string, 6))
611
&& (notend = strncmp("XPMENDEXT", string, 9))) {
613
XpmRealloc(ext->lines, (nlines + 1) * sizeof(char *)); /* can we iterate enough for a wrapping? */
616
ext->nlines = nlines;
617
XpmFreeExtensions(exts, num + 1);
618
return (XpmNoMemory);
621
ext->lines[nlines] = string;
624
status = xpmGetString(data, &string, &l);
625
if (status != XpmSuccess) {
626
ext->nlines = nlines;
627
XpmFreeExtensions(exts, num + 1);
635
ext->nlines = nlines;
650
/* function call in case of error */
652
#define RETURN(status) \
658
* This function parses an Xpm file or data and store the found informations
659
* in an an XpmImage structure which is returned.
662
xpmParseData(data, image, info)
667
/* variables to return */
668
unsigned int width, height, ncolors, cpp;
669
unsigned int x_hotspot, y_hotspot, hotspot = 0, extensions = 0;
670
XpmColor *colorTable = NULL;
671
unsigned int *pixelindex = NULL;
672
char *hints_cmt = NULL;
673
char *colors_cmt = NULL;
674
char *pixels_cmt = NULL;
678
xpmHashTable hashtable;
680
cmts = info && (info->valuemask & XpmReturnComments);
685
ErrorStatus = xpmParseHeader(data);
686
if (ErrorStatus != XpmSuccess)
687
return (ErrorStatus);
692
ErrorStatus = xpmParseValues(data, &width, &height, &ncolors, &cpp,
693
&x_hotspot, &y_hotspot, &hotspot,
695
if (ErrorStatus != XpmSuccess)
696
return (ErrorStatus);
699
* store the hints comment line
702
xpmGetCmt(data, &hints_cmt);
708
ErrorStatus = xpmHashTableInit(&hashtable);
709
if (ErrorStatus != XpmSuccess)
710
return (ErrorStatus);
716
ErrorStatus = xpmParseColors(data, ncolors, cpp, &colorTable, &hashtable);
717
if (ErrorStatus != XpmSuccess) {
719
xpmHashTableFree(&hashtable);
724
* store the colors comment line
727
xpmGetCmt(data, &colors_cmt);
730
* read pixels and index them on color number
732
ErrorStatus = ParsePixels(data, width, height, ncolors, cpp, colorTable,
733
&hashtable, &pixelindex);
739
xpmHashTableFree(&hashtable);
741
if (ErrorStatus != XpmSuccess)
745
* store the pixels comment line
748
xpmGetCmt(data, &pixels_cmt);
753
if (info && (info->valuemask & XpmReturnExtensions)) {
755
ErrorStatus = xpmParseExtensions(data, &info->extensions,
757
if (ErrorStatus != XpmSuccess)
760
info->extensions = NULL;
761
info->nextensions = 0;
766
* store found informations in the XpmImage structure
768
image->width = width;
769
image->height = height;
771
image->ncolors = ncolors;
772
image->colorTable = colorTable;
773
image->data = pixelindex;
777
info->hints_cmt = hints_cmt;
778
info->colors_cmt = colors_cmt;
779
info->pixels_cmt = pixels_cmt;
782
info->x_hotspot = x_hotspot;
783
info->y_hotspot = y_hotspot;
784
info->valuemask |= XpmHotspot;
789
/* exit point in case of error, free only locally allocated variables */
792
xpmFreeColorTable(colorTable, ncolors);