Git init
[framework/uifw/xorg/lib/libxpm.git] / src / CrDatFrI.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 *  CrDataFI.c:                                                                *
28 *                                                                             *
29 *  XPM library                                                                *
30 *  Scan an image and possibly its mask and create an XPM array                *
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(CreateColors, int, (char **dataptr, unsigned int *data_size,
43                           XpmColor *colors, unsigned int ncolors,
44                           unsigned int cpp));
45
46 LFUNC(CreatePixels, void, (char **dataptr, unsigned int data_size,
47                            unsigned int width,
48                            unsigned int height, unsigned int cpp,
49                            unsigned int *pixels, XpmColor *colors));
50
51 LFUNC(CountExtensions, void, (XpmExtension *ext, unsigned int num,
52                               unsigned int *ext_size,
53                               unsigned int *ext_nlines));
54
55 LFUNC(CreateExtensions, void, (char **dataptr, unsigned int data_size,
56                                unsigned int offset,
57                                XpmExtension *ext, unsigned int num,
58                                unsigned int ext_nlines));
59
60 int
61 XpmCreateDataFromImage(
62     Display               *display,
63     char                ***data_return,
64     XImage                *image,
65     XImage                *shapeimage,
66     XpmAttributes         *attributes)
67 {
68     XpmImage xpmimage;
69     XpmInfo info;
70     int ErrorStatus;
71
72     /* initialize return value */
73     if (data_return)
74         *data_return = NULL;
75
76     /* create an XpmImage from the image */
77     ErrorStatus = XpmCreateXpmImageFromImage(display, image, shapeimage,
78                                              &xpmimage, attributes);
79     if (ErrorStatus != XpmSuccess)
80         return (ErrorStatus);
81
82     /* create the data from the XpmImage */
83     if (attributes) {
84         xpmSetInfo(&info, attributes);
85         ErrorStatus = XpmCreateDataFromXpmImage(data_return, &xpmimage, &info);
86     } else
87         ErrorStatus = XpmCreateDataFromXpmImage(data_return, &xpmimage, NULL);
88
89     /* free the XpmImage */
90     XpmFreeXpmImage(&xpmimage);
91
92     return (ErrorStatus);
93 }
94
95 #undef RETURN
96 #define RETURN(status) \
97 do \
98 { \
99       ErrorStatus = status; \
100       goto exit; \
101 } while(0)
102
103 int
104 XpmCreateDataFromXpmImage(
105     char        ***data_return,
106     XpmImage      *image,
107     XpmInfo       *info)
108 {
109     /* calculation variables */
110     int ErrorStatus;
111     char buf[BUFSIZ];
112     char **header = NULL, **data, **sptr, **sptr2, *s;
113     unsigned int header_size, header_nlines;
114     unsigned int data_size, data_nlines;
115     unsigned int extensions = 0, ext_size = 0, ext_nlines = 0;
116     unsigned int offset, l, n;
117
118     *data_return = NULL;
119
120     extensions = info && (info->valuemask & XpmExtensions)
121         && info->nextensions;
122
123     /* compute the number of extensions lines and size */
124     if (extensions)
125         CountExtensions(info->extensions, info->nextensions,
126                         &ext_size, &ext_nlines);
127
128     /*
129      * alloc a temporary array of char pointer for the header section which
130      * is the hints line + the color table lines
131      */
132     header_nlines = 1 + image->ncolors; /* this may wrap and/or become 0 */
133
134     /* 2nd check superfluous if we do not need header_nlines any further */
135     if(header_nlines <= image->ncolors ||
136        header_nlines >= UINT_MAX / sizeof(char *))
137         return(XpmNoMemory);
138
139     header_size = sizeof(char *) * header_nlines;
140     if (header_size >= UINT_MAX / sizeof(char *))
141         return (XpmNoMemory);
142     header = (char **) XpmCalloc(header_size, sizeof(char *)); /* can we trust image->ncolors */
143     if (!header)
144         return (XpmNoMemory);
145
146     /* print the hints line */
147     s = buf;
148 #ifndef VOID_SPRINTF
149     s +=
150 #endif
151     sprintf(s, "%d %d %d %d", image->width, image->height,
152             image->ncolors, image->cpp);
153 #ifdef VOID_SPRINTF
154     s += strlen(s);
155 #endif
156
157     if (info && (info->valuemask & XpmHotspot)) {
158 #ifndef VOID_SPRINTF
159         s +=
160 #endif
161         sprintf(s, " %d %d", info->x_hotspot, info->y_hotspot);
162 #ifdef VOID_SPRINTF
163         s += strlen(s);
164 #endif
165     }
166     if (extensions) {
167         strcpy(s, " XPMEXT");
168         s += 7;
169     }
170     l = s - buf + 1;
171     *header = (char *) XpmMalloc(l);
172     if (!*header)
173         RETURN(XpmNoMemory);
174     header_size += l;
175     strcpy(*header, buf);
176
177     /* print colors */
178     ErrorStatus = CreateColors(header + 1, &header_size,
179                                image->colorTable, image->ncolors, image->cpp);
180
181     if (ErrorStatus != XpmSuccess)
182         RETURN(ErrorStatus);
183
184     /* now we know the size needed, alloc the data and copy the header lines */
185     offset = image->width * image->cpp + 1;
186
187     if(offset <= image->width || offset <= image->cpp)
188         RETURN(XpmNoMemory);
189
190     if( (image->height + ext_nlines) >= UINT_MAX / sizeof(char *))
191         RETURN(XpmNoMemory);
192     data_size = (image->height + ext_nlines) * sizeof(char *);
193
194     if (image->height > UINT_MAX / offset ||
195         image->height * offset > UINT_MAX - data_size)
196         RETURN(XpmNoMemory);
197     data_size += image->height * offset;
198
199     if( (header_size + ext_size) >= (UINT_MAX - data_size) )
200         RETURN(XpmNoMemory);
201     data_size += header_size + ext_size;
202
203     data = (char **) XpmMalloc(data_size);
204     if (!data)
205         RETURN(XpmNoMemory);
206
207     data_nlines = header_nlines + image->height + ext_nlines;
208     *data = (char *) (data + data_nlines);
209
210     /* can header have less elements then n suggests? */
211     n = image->ncolors;
212     for (l = 0, sptr = data, sptr2 = header; l <= n && sptr && sptr2; l++, sptr++, sptr2++) {
213         strcpy(*sptr, *sptr2);
214         *(sptr + 1) = *sptr + strlen(*sptr2) + 1;
215     }
216
217     /* print pixels */
218     data[header_nlines] = (char *) data + header_size
219         + (image->height + ext_nlines) * sizeof(char *);
220
221     CreatePixels(data + header_nlines, data_size-header_nlines, image->width, image->height,
222                  image->cpp, image->data, image->colorTable);
223
224     /* print extensions */
225     if (extensions)
226         CreateExtensions(data + header_nlines + image->height - 1,
227                          data_size - header_nlines - image->height + 1, offset,
228                          info->extensions, info->nextensions,
229                          ext_nlines);
230
231     *data_return = data;
232     ErrorStatus = XpmSuccess;
233
234 /* exit point, free only locally allocated variables */
235 exit:
236     if (header) {
237         for (l = 0; l < header_nlines; l++)
238             if (header[l])
239                 XpmFree(header[l]);
240                 XpmFree(header);
241     }
242     return(ErrorStatus);
243 }
244
245 static int
246 CreateColors(
247     char                **dataptr,
248     unsigned int         *data_size,
249     XpmColor             *colors,
250     unsigned int          ncolors,
251     unsigned int          cpp)
252 {
253     char buf[BUFSIZ];
254     unsigned int a, key, l;
255     char *s, *s2;
256     char **defaults;
257
258     /* can ncolors be trusted here? */
259     for (a = 0; a < ncolors; a++, colors++, dataptr++) {
260
261         defaults = (char **) colors;
262         if(sizeof(buf) <= cpp)
263             return(XpmNoMemory);
264         strncpy(buf, *defaults++, cpp);
265         s = buf + cpp;
266
267         if(sizeof(buf) <= (s-buf))
268                 return XpmNoMemory;
269
270         for (key = 1; key <= NKEYS; key++, defaults++) {
271             if ((s2 = *defaults)) {
272 #ifndef VOID_SPRINTF
273                 s +=
274 #endif
275                 /* assume C99 compliance */
276                         snprintf(s, sizeof(buf)-(s-buf), "\t%s %s", xpmColorKeys[key - 1], s2);
277 #ifdef VOID_SPRINTF
278                 s += strlen(s);
279 #endif
280                 /* does s point out-of-bounds? */
281                 if(sizeof(buf) < (s-buf))
282                         return XpmNoMemory;
283             }
284         }
285         /* what about using strdup()? */
286         l = s - buf + 1;
287         s = (char *) XpmMalloc(l);
288         if (!s)
289             return (XpmNoMemory);
290         *data_size += l;
291         *dataptr = strcpy(s, buf);
292     }
293     return (XpmSuccess);
294 }
295
296 static void
297 CreatePixels(
298     char                **dataptr,
299     unsigned int          data_size,
300     unsigned int          width,
301     unsigned int          height,
302     unsigned int          cpp,
303     unsigned int         *pixels,
304     XpmColor             *colors)
305 {
306     char *s;
307     unsigned int x, y, h, offset;
308
309     if(height <= 1)
310         return;
311
312     h = height - 1;
313
314     offset = width * cpp + 1;
315
316     if(offset <= width || offset <= cpp)
317         return;
318
319     /* why trust h? */
320     for (y = 0; y < h; y++, dataptr++) {
321         s = *dataptr;
322         /* why trust width? */
323         for (x = 0; x < width; x++, pixels++) {
324             if(cpp > (data_size - (s - *dataptr)))
325                 return;
326             strncpy(s, colors[*pixels].string, cpp); /* why trust pixel? */
327             s += cpp;
328         }
329         *s = '\0';
330         if(offset > data_size)
331                 return;
332         *(dataptr + 1) = *dataptr + offset;
333     }
334     /* duplicate some code to avoid a test in the loop */
335     s = *dataptr;
336     /* why trust width? */
337     for (x = 0; x < width; x++, pixels++) {
338         if(cpp > data_size - (s - *dataptr))
339                 return;
340         strncpy(s, colors[*pixels].string, cpp); /* why should we trust *pixel? */
341         s += cpp;
342     }
343     *s = '\0';
344 }
345
346 static void
347 CountExtensions(
348     XpmExtension        *ext,
349     unsigned int         num,
350     unsigned int        *ext_size,
351     unsigned int        *ext_nlines)
352 {
353     unsigned int x, y, a, size, nlines;
354     char **line;
355
356     size = 0;
357     nlines = 0;
358     for (x = 0; x < num; x++, ext++) {
359         /* 1 for the name */
360         nlines += ext->nlines + 1;
361         /* 8 = 7 (for "XPMEXT ") + 1 (for 0) */
362         size += strlen(ext->name) + 8;
363         a = ext->nlines;
364         for (y = 0, line = ext->lines; y < a; y++, line++)
365             size += strlen(*line) + 1;
366     }
367     /* 10 and 1 are for the ending "XPMENDEXT" */
368     *ext_size = size + 10;
369     *ext_nlines = nlines + 1;
370 }
371
372 static void
373 CreateExtensions(
374     char                **dataptr,
375     unsigned int          data_size,
376     unsigned int          offset,
377     XpmExtension         *ext,
378     unsigned int          num,
379     unsigned int          ext_nlines)
380 {
381     unsigned int x, y, a, b;
382     char **line;
383
384     *(dataptr + 1) = *dataptr + offset;
385     dataptr++;
386     a = 0;
387     for (x = 0; x < num; x++, ext++) {
388         snprintf(*dataptr, data_size, "XPMEXT %s", ext->name);
389         a++;
390         if (a < ext_nlines)
391             *(dataptr + 1) = *dataptr + strlen(ext->name) + 8;
392         dataptr++;
393         b = ext->nlines; /* can we trust these values? */
394         for (y = 0, line = ext->lines; y < b; y++, line++) {
395             strcpy(*dataptr, *line);
396             a++;
397             if (a < ext_nlines)
398                 *(dataptr + 1) = *dataptr + strlen(*line) + 1;
399             dataptr++;
400         }
401     }
402     strcpy(*dataptr, "XPMENDEXT");
403 }