113a45c1e625abc402c058549fb352edf7af3077
[framework/uifw/xorg/lib/libxpm.git] / src / CrBufFrI.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 *  CrBufFrI.c:                                                                *
28 *                                                                             *
29 *  XPM library                                                                *
30 *  Scan an image and possibly its mask and create an XPM buffer               *
31 *                                                                             *
32 *  Developed by Arnaud Le Hors                                                *
33 \*****************************************************************************/
34
35 /* October 2004, source code review by Thomas Biege <thomas@suse.de> */
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40 #include "XpmI.h"
41
42 LFUNC(WriteColors, int, (char **dataptr, unsigned int *data_size,
43                          unsigned int *used_size, XpmColor *colors,
44                          unsigned int ncolors, unsigned int cpp));
45
46 LFUNC(WritePixels, void, (char *dataptr, unsigned int data_size,
47                           unsigned int *used_size,
48                           unsigned int width, unsigned int height,
49                           unsigned int cpp, unsigned int *pixels,
50                           XpmColor *colors));
51
52 LFUNC(WriteExtensions, void, (char *dataptr, unsigned int data_size,
53                               unsigned int *used_size,
54                               XpmExtension *ext, unsigned int num));
55
56 LFUNC(ExtensionsSize, unsigned int, (XpmExtension *ext, unsigned int num));
57 LFUNC(CommentsSize, int, (XpmInfo *info));
58
59 int
60 XpmCreateBufferFromImage(
61     Display              *display,
62     char                **buffer_return,
63     XImage               *image,
64     XImage               *shapeimage,
65     XpmAttributes        *attributes)
66 {
67     XpmImage xpmimage;
68     XpmInfo info;
69     int ErrorStatus;
70
71     /* initialize return value */
72     if (buffer_return)
73         *buffer_return = NULL;
74
75     /* create an XpmImage from the image */
76     ErrorStatus = XpmCreateXpmImageFromImage(display, image, shapeimage,
77                                              &xpmimage, attributes);
78     if (ErrorStatus != XpmSuccess)
79         return (ErrorStatus);
80
81     /* create the buffer from the XpmImage */
82     if (attributes) {
83         xpmSetInfo(&info, attributes);
84         ErrorStatus =
85             XpmCreateBufferFromXpmImage(buffer_return, &xpmimage, &info);
86     } else
87         ErrorStatus =
88             XpmCreateBufferFromXpmImage(buffer_return, &xpmimage, NULL);
89
90     /* free the XpmImage */
91     XpmFreeXpmImage(&xpmimage);
92
93     return (ErrorStatus);
94 }
95
96
97 #undef RETURN
98 #define RETURN(status) \
99 do \
100 { \
101       ErrorStatus = status; \
102       goto error; \
103 }while(0)
104
105 int
106 XpmCreateBufferFromXpmImage(
107     char        **buffer_return,
108     XpmImage     *image,
109     XpmInfo      *info)
110 {
111     /* calculation variables */
112     int ErrorStatus;
113     char buf[BUFSIZ];
114     unsigned int cmts, extensions, ext_size = 0;
115     unsigned int l, cmt_size = 0;
116     char *ptr = NULL, *p;
117     unsigned int ptr_size, used_size, tmp;
118
119     *buffer_return = NULL;
120
121     cmts = info && (info->valuemask & XpmComments);
122     extensions = info && (info->valuemask & XpmExtensions)
123         && info->nextensions;
124
125     /* compute the extensions and comments size */
126     if (extensions)
127         ext_size = ExtensionsSize(info->extensions, info->nextensions);
128     if (cmts)
129         cmt_size = CommentsSize(info);
130
131     /* write the header line */
132 #ifndef VOID_SPRINTF
133     used_size =
134 #endif
135     sprintf(buf, "/* XPM */\nstatic char * image_name[] = {\n");
136 #ifdef VOID_SPRINTF
137     used_size = strlen(buf);
138 #endif
139     ptr_size = used_size + ext_size + cmt_size + 1; /* ptr_size can't be 0 */
140     if(ptr_size <= used_size ||
141        ptr_size <= ext_size  ||
142        ptr_size <= cmt_size)
143     {
144         return XpmNoMemory;
145     }
146     ptr = (char *) XpmMalloc(ptr_size);
147     if (!ptr)
148         return XpmNoMemory;
149     strcpy(ptr, buf);
150
151     /* write the values line */
152     if (cmts && info->hints_cmt) {
153 #ifndef VOID_SPRINTF
154         used_size +=
155 #endif
156         snprintf(ptr + used_size, ptr_size-used_size, "/*%s*/\n", info->hints_cmt);
157 #ifdef VOID_SPRINTF
158         used_size += strlen(info->hints_cmt) + 5;
159 #endif
160     }
161 #ifndef VOID_SPRINTF
162     l =
163 #endif
164     sprintf(buf, "\"%d %d %d %d", image->width, image->height,
165             image->ncolors, image->cpp);
166 #ifdef VOID_SPRINTF
167     l = strlen(buf);
168 #endif
169
170     if (info && (info->valuemask & XpmHotspot)) {
171 #ifndef VOID_SPRINTF
172         l +=
173 #endif
174         snprintf(buf + l, sizeof(buf)-l, " %d %d", info->x_hotspot, info->y_hotspot);
175 #ifdef VOID_SPRINTF
176         l = strlen(buf);
177 #endif
178     }
179     if (extensions) {
180 #ifndef VOID_SPRINTF
181         l +=
182 #endif
183         sprintf(buf + l, " XPMEXT");
184 #ifdef VOID_SPRINTF
185         l = strlen(buf);
186 #endif
187     }
188 #ifndef VOID_SPRINTF
189     l +=
190 #endif
191     sprintf(buf + l, "\",\n");
192 #ifdef VOID_SPRINTF
193     l = strlen(buf);
194 #endif
195     ptr_size += l;
196     if(ptr_size <= l)
197         RETURN(XpmNoMemory);
198     p = (char *) XpmRealloc(ptr, ptr_size);
199     if (!p)
200         RETURN(XpmNoMemory);
201     ptr = p;
202     strcpy(ptr + used_size, buf);
203     used_size += l;
204
205     /* write colors */
206     if (cmts && info->colors_cmt) {
207 #ifndef VOID_SPRINTF
208         used_size +=
209 #endif
210         snprintf(ptr + used_size, ptr_size-used_size, "/*%s*/\n", info->colors_cmt);
211 #ifdef VOID_SPRINTF
212         used_size += strlen(info->colors_cmt) + 5;
213 #endif
214     }
215     ErrorStatus = WriteColors(&ptr, &ptr_size, &used_size,
216                               image->colorTable, image->ncolors, image->cpp);
217  
218     if (ErrorStatus != XpmSuccess)
219         RETURN(ErrorStatus);
220
221     /*
222      * now we know the exact size we need, realloc the data
223      * 4 = 1 (for '"') + 3 (for '",\n')
224      * 1 = - 2 (because the last line does not end with ',\n') + 3 (for '};\n')
225      */
226      if(image->width  > UINT_MAX / image->cpp ||
227        (tmp = image->width * image->cpp + 4) <= 4 ||
228         image->height > UINT_MAX / tmp ||
229        (tmp = image->height * tmp + 1) <= 1 ||
230        (ptr_size += tmp) <= tmp)
231         RETURN(XpmNoMemory);
232
233     p = (char *) XpmRealloc(ptr, ptr_size);
234     if (!p)
235         RETURN(XpmNoMemory);
236     ptr = p;
237
238     /* print pixels */
239     if (cmts && info->pixels_cmt) {
240 #ifndef VOID_SPRINTF
241         used_size +=
242 #endif
243         snprintf(ptr + used_size, ptr_size-used_size, "/*%s*/\n", info->pixels_cmt);
244 #ifdef VOID_SPRINTF
245         used_size += strlen(info->pixels_cmt) + 5;
246 #endif
247     }
248     WritePixels(ptr + used_size, ptr_size - used_size, &used_size, image->width, image->height,
249                 image->cpp, image->data, image->colorTable);
250
251     /* print extensions */
252     if (extensions)
253         WriteExtensions(ptr + used_size, ptr_size-used_size, &used_size,
254                         info->extensions, info->nextensions);
255
256     /* close the array */
257     strcpy(ptr + used_size, "};\n");
258
259     *buffer_return = ptr;
260
261     return (XpmSuccess);
262
263 /* exit point in case of error, free only locally allocated variables */
264 error:
265     if (ptr)
266         XpmFree(ptr);
267     return (ErrorStatus);
268 }
269
270
271 static int
272 WriteColors(
273     char                **dataptr,
274     unsigned int         *data_size,
275     unsigned int         *used_size,
276     XpmColor             *colors,
277     unsigned int          ncolors,
278     unsigned int          cpp)
279 {
280     char buf[BUFSIZ] = {0};
281     unsigned int a, key, l;
282     char *s, *s2;
283     char **defaults;
284
285     *buf = '"';
286     for (a = 0; a < ncolors; a++, colors++) {
287
288         defaults = (char **) colors;
289         s = buf + 1;
290         if(cpp > (sizeof(buf) - (s-buf)))
291                 return(XpmNoMemory);
292         strncpy(s, *defaults++, cpp);
293         s += cpp;
294
295         for (key = 1; key <= NKEYS; key++, defaults++) {
296             if ((s2 = *defaults)) {
297 #ifndef VOID_SPRINTF
298                 s +=
299 #endif
300                 /* assume C99 compliance */
301                 snprintf(s, sizeof(buf) - (s-buf), "\t%s %s", xpmColorKeys[key - 1], s2);
302 #ifdef VOID_SPRINTF
303                 s += strlen(s);
304 #endif
305                 /* now let's check if s points out-of-bounds */
306                 if((s-buf) > sizeof(buf))
307                         return(XpmNoMemory);
308             }
309         }
310         if(sizeof(buf) - (s-buf) < 4)
311                 return(XpmNoMemory);
312         strcpy(s, "\",\n");
313         l = s + 3 - buf;
314         if( *data_size                   >= UINT_MAX-l ||
315             *data_size + l               <= *used_size ||
316            (*data_size + l - *used_size) <= sizeof(buf))
317                 return(XpmNoMemory);
318         s = (char *) XpmRealloc(*dataptr, *data_size + l);
319         if (!s)
320             return (XpmNoMemory);
321         *data_size += l;
322         strcpy(s + *used_size, buf);
323         *used_size += l;
324         *dataptr = s;
325     }
326     return (XpmSuccess);
327 }
328
329 static void
330 WritePixels(
331     char                *dataptr,
332     unsigned int         data_size,
333     unsigned int        *used_size,
334     unsigned int         width,
335     unsigned int         height,
336     unsigned int         cpp,
337     unsigned int        *pixels,
338     XpmColor            *colors)
339 {
340     char *s = dataptr;
341     unsigned int x, y, h;
342
343     if(height <= 1)
344         return;
345
346     h = height - 1;
347     for (y = 0; y < h; y++) {
348         *s++ = '"';
349         for (x = 0; x < width; x++, pixels++) {
350             if(cpp >= (data_size - (s-dataptr)))
351                 return;
352             strncpy(s, colors[*pixels].string, cpp); /* how can we trust *pixels? :-\ */
353             s += cpp;
354         }
355         if((data_size - (s-dataptr)) < 4)
356                 return;
357         strcpy(s, "\",\n");
358         s += 3;
359     }
360     /* duplicate some code to avoid a test in the loop */
361     *s++ = '"';
362     for (x = 0; x < width; x++, pixels++) {
363         if(cpp >= (data_size - (s-dataptr)))
364             return;
365         strncpy(s, colors[*pixels].string, cpp); /* how can we trust *pixels? */
366         s += cpp;
367     }
368     *s++ = '"';
369     *used_size += s - dataptr;
370 }
371
372 static unsigned int
373 ExtensionsSize(
374     XpmExtension        *ext,
375     unsigned int         num)
376 {
377     unsigned int x, y, a, size;
378     char **line;
379
380     size = 0;
381     if(num == 0)
382         return(0); /* ok? */
383     for (x = 0; x < num; x++, ext++) {
384         /* 11 = 10 (for ',\n"XPMEXT ') + 1 (for '"') */
385         size += strlen(ext->name) + 11;
386         a = ext->nlines; /* how can we trust ext->nlines to be not out-of-bounds? */
387         for (y = 0, line = ext->lines; y < a; y++, line++)
388             /* 4 = 3 (for ',\n"') + 1 (for '"') */
389             size += strlen(*line) + 4;
390     }
391     /* 13 is for ',\n"XPMENDEXT"' */
392     if(size > UINT_MAX - 13) /* unlikely */
393         return(0);
394     return size + 13;
395 }
396
397 static void
398 WriteExtensions(
399     char                *dataptr,
400     unsigned int         data_size,
401     unsigned int        *used_size,
402     XpmExtension        *ext,
403     unsigned int         num)
404 {
405     unsigned int x, y, a;
406     char **line;
407     char *s = dataptr;
408
409     for (x = 0; x < num; x++, ext++) {
410 #ifndef VOID_SPRINTF
411         s +=
412 #endif
413         snprintf(s, data_size - (s-dataptr), ",\n\"XPMEXT %s\"", ext->name);
414 #ifdef VOID_SPRINTF
415         s += strlen(ext->name) + 11;
416 #endif
417         a = ext->nlines;
418         for (y = 0, line = ext->lines; y < a; y++, line++) {
419 #ifndef VOID_SPRINTF
420             s +=
421 #endif
422             snprintf(s, data_size - (s-dataptr), ",\n\"%s\"", *line);
423 #ifdef VOID_SPRINTF
424             s += strlen(*line) + 4;
425 #endif
426         }
427     }
428     strncpy(s, ",\n\"XPMENDEXT\"", data_size - (s-dataptr)-1);
429     *used_size += s - dataptr + 13;
430 }
431
432 static int
433 CommentsSize(XpmInfo *info)
434 {
435     int size = 0;
436
437     /* 5 = 2 (for "/_*") + 3 (for "*_/\n") */
438     /* wrap possible but *very* unlikely */
439     if (info->hints_cmt)
440         size += 5 + strlen(info->hints_cmt);
441
442     if (info->colors_cmt)
443         size += 5 + strlen(info->colors_cmt);
444
445     if (info->pixels_cmt)
446         size += 5 + strlen(info->pixels_cmt);
447
448     return size;
449 }