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