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