1 /*
2 * Copyright (C) 1989-95 GROUPE BULL
3 * Copyright � 2005, The LessTif developers.
4 *
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:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
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.
21 *
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.
25 */
26
27 /*****************************************************************************\
28 * data.c: *
29 * *
30 * XPM library *
31 * IO utilities *
32 * *
33 * Developed by Arnaud Le Hors *
34 \*****************************************************************************/
35 /* $XFree86: xc/extras/Xpm/lib/data.c,v 1.3 2001/10/28 03:32:10 tsi Exp $ */
36 /* $Header: /cvsroot/lesstif/lesstif/lib/Xm-2.1/Xpmdata.c,v 1.2 2005/04/13 18:03:26 dannybackx Exp $ */
37 #include <LTconfig.h>
38
39 /* amai: we can't include DebugUtil.h before system headers.
40 So we assume that system headers are idempotent, #include
41 all of those used below here and then try with our
42 DebugUtil.h! */
43 #include <stdio.h>
44 #include <string.h>
45
46 #include <ctype.h>
47 #ifdef HAVE_SYS_TYPES_H
48 #include <sys/types.h>
49 #endif
50 #ifdef HAVE_SYS_STAT_H
51 #include <sys/stat.h>
52 #endif
53 #ifdef HAVE_UNISTD_H
54 #include <unistd.h>
55 #endif
56 #ifdef HAVE_FCNTL_H
57 #include <fcntl.h>
58 #endif
59 #if defined(FOR_MSW) || defined(WIN32)
60 #include <io.h>
61 #endif
62
63 #include <X11/Intrinsic.h> /* Avoid re-definition of Pixel-type */
64
65 #include <Xm/XpmP.h>
66 #include <XmI/XpmI.h>
67
68 /* #if !defined(WITH_DBMALLOC) && !defined(WITH_DMALLOC) */
69 #include <XmI/DebugUtil.h>
70
71 #ifdef HAVE_STRLCAT
72 # define STRLCAT(dst, src, dstsize) { \
73 if (strlcat(dst, src, dstsize) >= (dstsize)) \
74 return (XpmFileInvalid); }
75 # define STRLCPY(dst, src, dstsize) { \
76 if (strlcpy(dst, src, dstsize) >= (dstsize)) \
77 return (XpmFileInvalid); }
78 #else
79 # define STRLCAT(dst, src, dstsize) { \
80 if ((strlen(dst) + strlen(src)) < (dstsize)) \
81 strcat(dst, src); \
82 else return (XpmFileInvalid); }
83 # define STRLCPY(dst, src, dstsize) { \
84 if (strlen(src) < (dstsize)) \
85 strcpy(dst, src); \
86 else return (XpmFileInvalid); }
87 #endif
88
89 /* October 2004, source code review by Thomas Biege <thomas@suse.de> */
90
91 #ifndef CXPMPROG
92 #include "XmI/XpmI.h"
93 #endif
94 #include <ctype.h>
95
96 #ifndef CXPMPROG
97 #define Getc(data, file) getc(file)
98 #define Ungetc(data, c, file) ungetc(c, file)
99 #endif
100
101 static int
ParseComment(xpmData * data)102 ParseComment(xpmData *data)
103 {
104 if (data->type == XPMBUFFER) {
105 register char c;
106 register unsigned int n = 0;
107 unsigned int notend;
108 char *s, *s2;
109
110 s = data->Comment;
111 *s = data->Bcmt[0];
112
113 /* skip the string beginning comment */
114 s2 = data->Bcmt;
115 do {
116 c = *data->cptr++;
117 *++s = c;
118 n++;
119 s2++;
120 } while (c == *s2 && *s2 != '\0' && c);
121
122 if (*s2 != '\0') {
123 /* this wasn't the beginning of a comment */
124 data->cptr -= n;
125 return 0;
126 }
127 /* store comment */
128 data->Comment[0] = *s;
129 s = data->Comment;
130 notend = 1;
131 n = 0;
132 while (notend) {
133 s2 = data->Ecmt;
134 while (*s != *s2 && c) {
135 c = *data->cptr++;
136 if (n == XPMMAXCMTLEN - 1) { /* forget it */
137 s = data->Comment;
138 n = 0;
139 }
140 *++s = c;
141 n++;
142 }
143 data->CommentLength = n;
144 do {
145 c = *data->cptr++;
146 if (n == XPMMAXCMTLEN - 1) { /* forget it */
147 s = data->Comment;
148 n = 0;
149 }
150 *++s = c;
151 n++;
152 s2++;
153 } while (c == *s2 && *s2 != '\0' && c);
154 if (*s2 == '\0') {
155 /* this is the end of the comment */
156 notend = 0;
157 data->cptr--;
158 }
159 }
160 return 0;
161 } else {
162 FILE *file = data->stream.file;
163 register int c;
164 register unsigned int n = 0, a;
165 unsigned int notend;
166 char *s, *s2;
167
168 s = data->Comment;
169 *s = data->Bcmt[0];
170
171 /* skip the string beginning comment */
172 s2 = data->Bcmt;
173 do {
174 c = Getc(data, file);
175 *++s = c;
176 n++;
177 s2++;
178 } while (c == *s2 && *s2 != '\0' && c != EOF);
179
180 if (*s2 != '\0') {
181 /* this wasn't the beginning of a comment */
182 /* put characters back in the order that we got them */
183 for (a = n; a > 0; a--, s--)
184 Ungetc(data, *s, file);
185 return 0;
186 }
187 /* store comment */
188 data->Comment[0] = *s;
189 s = data->Comment;
190 notend = 1;
191 n = 0;
192 while (notend) {
193 s2 = data->Ecmt;
194 while (*s != *s2 && c != EOF) {
195 c = Getc(data, file);
196 if (n == XPMMAXCMTLEN - 1) { /* forget it */
197 s = data->Comment;
198 n = 0;
199 }
200 *++s = c;
201 n++;
202 }
203 data->CommentLength = n;
204 do {
205 c = Getc(data, file);
206 if (n == XPMMAXCMTLEN - 1) { /* forget it */
207 s = data->Comment;
208 n = 0;
209 }
210 *++s = c;
211 n++;
212 s2++;
213 } while (c == *s2 && *s2 != '\0' && c != EOF);
214 if (*s2 == '\0') {
215 /* this is the end of the comment */
216 notend = 0;
217 Ungetc(data, *s, file);
218 }
219 }
220 return 0;
221 }
222 }
223
224 /*
225 * skip to the end of the current string and the beginning of the next one
226 */
227 int
xpmNextString(data)228 xpmNextString(data)
229 xpmData *data;
230 {
231 if (!data->type)
232 data->cptr = (data->stream.data)[++data->line];
233 else if (data->type == XPMBUFFER) {
234 register char c;
235
236 /* get to the end of the current string */
237 if (data->Eos)
238 while ((c = *data->cptr++) && c != data->Eos);
239
240 /*
241 * then get to the beginning of the next string looking for possible
242 * comment
243 */
244 if (data->Bos) {
245 while ((c = *data->cptr++) && c != data->Bos)
246 if (data->Bcmt && c == data->Bcmt[0])
247 ParseComment(data);
248 } else if (data->Bcmt) { /* XPM2 natural */
249 while ((c = *data->cptr++) == data->Bcmt[0])
250 ParseComment(data);
251 data->cptr--;
252 }
253 } else {
254 register int c;
255 FILE *file = data->stream.file;
256
257 /* get to the end of the current string */
258 if (data->Eos)
259 while ((c = Getc(data, file)) != data->Eos && c != EOF);
260
261 /*
262 * then get to the beginning of the next string looking for possible
263 * comment
264 */
265 if (data->Bos) {
266 while ((c = Getc(data, file)) != data->Bos && c != EOF)
267 if (data->Bcmt && c == data->Bcmt[0])
268 ParseComment(data);
269
270 } else if (data->Bcmt) { /* XPM2 natural */
271 while ((c = Getc(data, file)) == data->Bcmt[0])
272 ParseComment(data);
273 Ungetc(data, c, file);
274 }
275 }
276 return 0;
277 }
278
279
280 /*
281 * skip whitespace and return the following word
282 */
283 unsigned int
xpmNextWord(data,buf,buflen)284 xpmNextWord(data, buf, buflen)
285 xpmData *data;
286 char *buf;
287 unsigned int buflen;
288 {
289 register unsigned int n = 0;
290 int c;
291
292 if (!data->type || data->type == XPMBUFFER) {
293 while (isspace(c = *data->cptr) && c != data->Eos)
294 data->cptr++;
295 do {
296 c = *data->cptr++;
297 *buf++ = c;
298 n++;
299 } while (!isspace(c) && c != data->Eos && n < buflen);
300 n--;
301 data->cptr--;
302 } else {
303 FILE *file = data->stream.file;
304
305 while ((c = Getc(data, file)) != EOF && isspace(c) && c != data->Eos);
306 while (!isspace(c) && c != data->Eos && c != EOF && n < buflen) {
307 *buf++ = c;
308 n++;
309 c = Getc(data, file);
310 }
311 Ungetc(data, c, file);
312 }
313 return (n); /* this returns bytes read + 1 */
314 }
315
316 /*
317 * skip whitespace and compute the following unsigned int,
318 * returns 1 if one is found and 0 if not
319 */
320 int
xpmNextUI(data,ui_return)321 xpmNextUI(data, ui_return)
322 xpmData *data;
323 unsigned int *ui_return;
324 {
325 char buf[BUFSIZ];
326 int l;
327
328 l = xpmNextWord(data, buf, BUFSIZ);
329 return xpmatoui(buf, l, ui_return);
330 }
331
332 /*
333 * return end of string - WARNING: malloc!
334 */
335 int
xpmGetString(data,sptr,l)336 xpmGetString(data, sptr, l)
337 xpmData *data;
338 char **sptr;
339 unsigned int *l;
340 {
341 unsigned int i, n = 0;
342 int c;
343 char *p = NULL, *q, buf[BUFSIZ];
344
345 if (!data->type || data->type == XPMBUFFER) {
346 if (data->cptr) {
347 char *start = data->cptr;
348 while ((c = *data->cptr) && c != data->Eos)
349 data->cptr++;
350 n = data->cptr - start + 1;
351 p = (char *) XpmMalloc(n);
352 if (!p)
353 return (XpmNoMemory);
354 strncpy(p, start, n);
355 if (data->type) /* XPMBUFFER */
356 p[n - 1] = '\0';
357 }
358 } else {
359 FILE *file = data->stream.file;
360
361 if ((c = Getc(data, file)) == EOF)
362 return (XpmFileInvalid);
363
364 i = 0;
365 q = buf;
366 p = (char *) XpmMalloc(1);
367 while (c != data->Eos && c != EOF) {
368 if (i == BUFSIZ) {
369 /* get to the end of the buffer */
370 /* malloc needed memory */
371 q = (char *) XpmRealloc(p, n + i);
372 if (!q) {
373 XpmFree(p);
374 return (XpmNoMemory);
375 }
376 p = q;
377 q += n;
378 /* and copy what we already have */
379 strncpy(q, buf, i);
380 n += i;
381 i = 0;
382 q = buf;
383 }
384 *q++ = c;
385 i++;
386 c = Getc(data, file);
387 }
388 if (c == EOF) {
389 XpmFree(p);
390 return (XpmFileInvalid);
391 }
392 if (n + i != 0) {
393 /* malloc needed memory */
394 q = (char *) XpmRealloc(p, n + i + 1);
395 if (!q) {
396 XpmFree(p);
397 return (XpmNoMemory);
398 }
399 p = q;
400 q += n;
401 /* and copy the buffer */
402 strncpy(q, buf, i);
403 n += i;
404 p[n++] = '\0';
405 } else {
406 *p = '\0';
407 n = 1;
408 }
409 Ungetc(data, c, file);
410 }
411 *sptr = p;
412 *l = n;
413 return (XpmSuccess);
414 }
415
416 /*
417 * get the current comment line
418 */
419 int
xpmGetCmt(data,cmt)420 xpmGetCmt(data, cmt)
421 xpmData *data;
422 char **cmt;
423 {
424 if (!data->type)
425 *cmt = NULL;
426 else if (data->CommentLength != 0 && data->CommentLength < UINT_MAX - 1) {
427 if( (*cmt = (char *) XpmMalloc(data->CommentLength + 1)) == NULL)
428 return XpmNoMemory;
429 strncpy(*cmt, data->Comment, data->CommentLength);
430 (*cmt)[data->CommentLength] = '\0';
431 data->CommentLength = 0;
432 } else
433 *cmt = NULL;
434 return 0;
435 }
436
437 xpmDataType xpmDataTypes[] =
438 {
439 {"", "!", "\n", '\0', '\n', "", "", "", ""}, /* Natural type */
440 {"C", "/*", "*/", '"', '"', ",\n", "static char *", "[] = {\n", "};\n"},
441 {"Lisp", ";", "\n", '"', '"', "\n", "(setq ", " '(\n", "))\n"},
442 {NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL}
443 };
444
445 /*
446 * parse xpm header
447 */
448 int
xpmParseHeader(data)449 xpmParseHeader(data)
450 xpmData *data;
451 {
452 char buf[BUFSIZ+1] = {0};
453 int l, n = 0;
454
455 if (data->type) {
456 data->Bos = '\0';
457 data->Eos = '\n';
458 data->Bcmt = data->Ecmt = NULL;
459 l = xpmNextWord(data, buf, BUFSIZ);
460 if (l == 7 && !strncmp("#define", buf, 7)) {
461 /* this maybe an XPM 1 file */
462 char *ptr;
463
464 l = xpmNextWord(data, buf, BUFSIZ);
465 if (!l)
466 return (XpmFileInvalid);
467 buf[l] = '\0';
468 ptr = strrchr(buf, '_');
469 if (!ptr || strncmp("_format", ptr, l - (ptr - buf)))
470 return XpmFileInvalid;
471 /* this is definitely an XPM 1 file */
472 data->format = 1;
473 n = 1; /* handle XPM1 as mainly XPM2 C */
474 } else {
475
476 /*
477 * skip the first word, get the second one, and see if this is
478 * XPM 2 or 3
479 */
480 l = xpmNextWord(data, buf, BUFSIZ);
481 if ((l == 3 && !strncmp("XPM", buf, 3)) ||
482 (l == 4 && !strncmp("XPM2", buf, 4))) {
483 if (l == 3)
484 n = 1; /* handle XPM as XPM2 C */
485 else {
486 /* get the type key word */
487 l = xpmNextWord(data, buf, BUFSIZ);
488
489 /*
490 * get infos about this type
491 */
492 while (xpmDataTypes[n].type
493 && strncmp(xpmDataTypes[n].type, buf, l))
494 n++;
495 }
496 data->format = 0;
497 } else
498 /* nope this is not an XPM file */
499 return XpmFileInvalid;
500 }
501 if (xpmDataTypes[n].type) {
502 if (n == 0) { /* natural type */
503 data->Bcmt = xpmDataTypes[n].Bcmt;
504 data->Ecmt = xpmDataTypes[n].Ecmt;
505 xpmNextString(data); /* skip the end of the headerline */
506 data->Bos = xpmDataTypes[n].Bos;
507 data->Eos = xpmDataTypes[n].Eos;
508 } else {
509 data->Bcmt = xpmDataTypes[n].Bcmt;
510 data->Ecmt = xpmDataTypes[n].Ecmt;
511 if (!data->format) { /* XPM 2 or 3 */
512 data->Bos = xpmDataTypes[n].Bos;
513 data->Eos = '\0';
514 /* get to the beginning of the first string */
515 xpmNextString(data);
516 data->Eos = xpmDataTypes[n].Eos;
517 } else /* XPM 1 skip end of line */
518 xpmNextString(data);
519 }
520 } else
521 /* we don't know about that type of XPM file... */
522 return XpmFileInvalid;
523 }
524 return XpmSuccess;
525 }
526