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