CrDatFrI.c revision a966c04f
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/* $XFree86$ */
35
36/* October 2004, source code review by Thomas Biege <thomas@suse.de> */
37
38#ifdef HAVE_CONFIG_H
39#include <config.h>
40#endif
41#include "XpmI.h"
42
43LFUNC(CreateColors, int, (char **dataptr, unsigned int *data_size,
44			  XpmColor *colors, unsigned int ncolors,
45			  unsigned int cpp));
46
47LFUNC(CreatePixels, void, (char **dataptr, unsigned int data_size,
48			   unsigned int width,
49			   unsigned int height, unsigned int cpp,
50			   unsigned int *pixels, XpmColor *colors));
51
52LFUNC(CountExtensions, void, (XpmExtension *ext, unsigned int num,
53			      unsigned int *ext_size,
54			      unsigned int *ext_nlines));
55
56LFUNC(CreateExtensions, void, (char **dataptr, unsigned int data_size,
57			       unsigned int offset,
58			       XpmExtension *ext, unsigned int num,
59			       unsigned int ext_nlines));
60
61int
62XpmCreateDataFromImage(display, data_return, image, shapeimage, attributes)
63    Display *display;
64    char ***data_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 (data_return)
75	*data_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 data from the XpmImage */
84    if (attributes) {
85	xpmSetInfo(&info, attributes);
86	ErrorStatus = XpmCreateDataFromXpmImage(data_return, &xpmimage, &info);
87    } else
88	ErrorStatus = XpmCreateDataFromXpmImage(data_return, &xpmimage, NULL);
89
90    /* free the XpmImage */
91    XpmFreeXpmImage(&xpmimage);
92
93    return (ErrorStatus);
94}
95
96#undef RETURN
97#define RETURN(status) \
98do \
99{ \
100      ErrorStatus = status; \
101      goto exit; \
102} while(0)
103
104int
105XpmCreateDataFromXpmImage(data_return, image, info)
106    char ***data_return;
107    XpmImage *image;
108    XpmInfo *info;
109{
110    /* calculation variables */
111    int ErrorStatus;
112    char buf[BUFSIZ];
113    char **header = NULL, **data, **sptr, **sptr2, *s;
114    unsigned int header_size, header_nlines;
115    unsigned int data_size, data_nlines;
116    unsigned int extensions = 0, ext_size = 0, ext_nlines = 0;
117    unsigned int offset, l, n;
118
119    *data_return = NULL;
120
121    extensions = info && (info->valuemask & XpmExtensions)
122	&& info->nextensions;
123
124    /* compute the number of extensions lines and size */
125    if (extensions)
126	CountExtensions(info->extensions, info->nextensions,
127			&ext_size, &ext_nlines);
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 + ext_nlines) >= UINT_MAX / sizeof(char *))
192	RETURN(XpmNoMemory);
193    data_size = (image->height + ext_nlines) * sizeof(char *);
194
195    if (image->height > UINT_MAX / offset ||
196        image->height * offset > UINT_MAX - data_size)
197	RETURN(XpmNoMemory);
198    data_size += image->height * offset;
199
200    if( (header_size + ext_size) >= (UINT_MAX - data_size) )
201	RETURN(XpmNoMemory);
202    data_size += header_size + ext_size;
203
204    data = (char **) XpmMalloc(data_size);
205    if (!data)
206	RETURN(XpmNoMemory);
207
208    data_nlines = header_nlines + image->height + ext_nlines;
209    *data = (char *) (data + data_nlines);
210
211    /* can header have less elements then n suggests? */
212    n = image->ncolors;
213    for (l = 0, sptr = data, sptr2 = header; l <= n && sptr && sptr2; l++, sptr++, sptr2++) {
214	strcpy(*sptr, *sptr2);
215	*(sptr + 1) = *sptr + strlen(*sptr2) + 1;
216    }
217
218    /* print pixels */
219    data[header_nlines] = (char *) data + header_size
220	+ (image->height + ext_nlines) * sizeof(char *);
221
222    CreatePixels(data + header_nlines, data_size-header_nlines, image->width, image->height,
223		 image->cpp, image->data, image->colorTable);
224
225    /* print extensions */
226    if (extensions)
227	CreateExtensions(data + header_nlines + image->height - 1,
228			 data_size - header_nlines - image->height + 1, offset,
229			 info->extensions, info->nextensions,
230			 ext_nlines);
231
232    *data_return = data;
233    ErrorStatus = XpmSuccess;
234
235/* exit point, free only locally allocated variables */
236exit:
237    if (header) {
238	for (l = 0; l < header_nlines; l++)
239	    if (header[l])
240		XpmFree(header[l]);
241		XpmFree(header);
242    }
243    return(ErrorStatus);
244}
245
246static int
247CreateColors(dataptr, data_size, colors, ncolors, cpp)
248    char **dataptr;
249    unsigned int *data_size;
250    XpmColor *colors;
251    unsigned int ncolors;
252    unsigned int cpp;
253{
254    char buf[BUFSIZ];
255    unsigned int a, key, l;
256    char *s, *s2;
257    char **defaults;
258
259    /* can ncolors be trusted here? */
260    for (a = 0; a < ncolors; a++, colors++, dataptr++) {
261
262	defaults = (char **) colors;
263	if(sizeof(buf) <= cpp)
264	    return(XpmNoMemory);
265	strncpy(buf, *defaults++, cpp);
266	s = buf + cpp;
267
268	if(sizeof(buf) <= (s-buf))
269		return XpmNoMemory;
270
271	for (key = 1; key <= NKEYS; key++, defaults++) {
272	    if ((s2 = *defaults)) {
273#ifndef VOID_SPRINTF
274		s +=
275#endif
276		/* assume C99 compliance */
277			snprintf(s, sizeof(buf)-(s-buf), "\t%s %s", xpmColorKeys[key - 1], s2);
278#ifdef VOID_SPRINTF
279		s += strlen(s);
280#endif
281		/* does s point out-of-bounds? */
282		if(sizeof(buf) < (s-buf))
283			return XpmNoMemory;
284	    }
285	}
286	/* what about using strdup()? */
287	l = s - buf + 1;
288	s = (char *) XpmMalloc(l);
289	if (!s)
290	    return (XpmNoMemory);
291	*data_size += l;
292	*dataptr = strcpy(s, buf);
293    }
294    return (XpmSuccess);
295}
296
297static void
298CreatePixels(dataptr, data_size, width, height, cpp, pixels, colors)
299    char **dataptr;
300    unsigned int data_size;
301    unsigned int width;
302    unsigned int height;
303    unsigned int cpp;
304    unsigned int *pixels;
305    XpmColor *colors;
306{
307    char *s;
308    unsigned int x, y, h, offset;
309
310    if(height <= 1)
311    	return;
312
313    h = height - 1;
314
315    offset = width * cpp + 1;
316
317    if(offset <= width || offset <= cpp)
318    	return;
319
320    /* why trust h? */
321    for (y = 0; y < h; y++, dataptr++) {
322	s = *dataptr;
323	/* why trust width? */
324	for (x = 0; x < width; x++, pixels++) {
325	    if(cpp > (data_size - (s - *dataptr)))
326	    	return;
327	    strncpy(s, colors[*pixels].string, cpp); /* why trust pixel? */
328	    s += cpp;
329	}
330	*s = '\0';
331	if(offset > data_size)
332		return;
333	*(dataptr + 1) = *dataptr + offset;
334    }
335    /* duplicate some code to avoid a test in the loop */
336    s = *dataptr;
337    /* why trust width? */
338    for (x = 0; x < width; x++, pixels++) {
339	if(cpp > data_size - (s - *dataptr))
340	    	return;
341	strncpy(s, colors[*pixels].string, cpp); /* why should we trust *pixel? */
342	s += cpp;
343    }
344    *s = '\0';
345}
346
347static void
348CountExtensions(ext, num, ext_size, ext_nlines)
349    XpmExtension *ext;
350    unsigned int num;
351    unsigned int *ext_size;
352    unsigned int *ext_nlines;
353{
354    unsigned int x, y, a, size, nlines;
355    char **line;
356
357    size = 0;
358    nlines = 0;
359    for (x = 0; x < num; x++, ext++) {
360	/* 1 for the name */
361	nlines += ext->nlines + 1;
362	/* 8 = 7 (for "XPMEXT ") + 1 (for 0) */
363	size += strlen(ext->name) + 8;
364	a = ext->nlines;
365	for (y = 0, line = ext->lines; y < a; y++, line++)
366	    size += strlen(*line) + 1;
367    }
368    /* 10 and 1 are for the ending "XPMENDEXT" */
369    *ext_size = size + 10;
370    *ext_nlines = nlines + 1;
371}
372
373static void
374CreateExtensions(dataptr, data_size, offset, ext, num, ext_nlines)
375    char **dataptr;
376    unsigned int data_size;
377    unsigned int offset;
378    XpmExtension *ext;
379    unsigned int num;
380    unsigned int ext_nlines;
381{
382    unsigned int x, y, a, b;
383    char **line;
384
385    *(dataptr + 1) = *dataptr + offset;
386    dataptr++;
387    a = 0;
388    for (x = 0; x < num; x++, ext++) {
389	snprintf(*dataptr, data_size, "XPMEXT %s", ext->name);
390	a++;
391	if (a < ext_nlines)
392	    *(dataptr + 1) = *dataptr + strlen(ext->name) + 8;
393	dataptr++;
394	b = ext->nlines; /* can we trust these values? */
395	for (y = 0, line = ext->lines; y < b; y++, line++) {
396	    strcpy(*dataptr, *line);
397	    a++;
398	    if (a < ext_nlines)
399		*(dataptr + 1) = *dataptr + strlen(*line) + 1;
400	    dataptr++;
401	}
402    }
403    strcpy(*dataptr, "XPMENDEXT");
404}
405