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