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 *  WrFFrI.c:                                                                  *
28 *                                                                             *
29 *  XPM library                                                                *
30 *  Write an image and possibly its mask to an XPM file                        *
31 *                                                                             *
32 *  Developed by Arnaud Le Hors                                                *
33 \*****************************************************************************/
34 
35 /*
36  * The code related to AMIGA has been added by
37  * Lorens Younes (d93-hyo@nada.kth.se) 4/96
38  */
39 
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43 #include "XpmI.h"
44 
45 #ifndef NO_ZPIPE
46 #include "sys/wait.h"
47 #include "sys/types.h"
48 #include "unistd.h"
49 #include "errno.h"
50 #endif
51 
52 #include "fcntl.h"
53 
54 #ifdef FOR_MSW
55 #define O_WRONLY _O_WRONLY
56 #define O_CREAT  _O_CREAT
57 #define O_TRUNC  _O_TRUNC
58 #endif
59 
60 /* MS Windows define a function called WriteFile @#%#&!!! */
61 LFUNC(xpmWriteFile, int, (FILE *file, XpmImage *image, const char *name,
62 			  XpmInfo *info));
63 
64 LFUNC(WriteColors, void, (FILE *file, XpmColor *colors, unsigned int ncolors));
65 
66 LFUNC(WritePixels, int, (FILE *file, unsigned int width, unsigned int height,
67 			 unsigned int cpp, unsigned int *pixels,
68 			 XpmColor *colors));
69 
70 LFUNC(WriteExtensions, void, (FILE *file, XpmExtension *ext,
71 			      unsigned int num));
72 
73 LFUNC(OpenWriteFile, int, (const char *filename, xpmData *mdata));
74 LFUNC(xpmDataClose, void, (xpmData *mdata));
75 
76 int
XpmWriteFileFromImage(Display * display,const char * filename,XImage * image,XImage * shapeimage,XpmAttributes * attributes)77 XpmWriteFileFromImage(
78     Display		*display,
79     const char		*filename,
80     XImage		*image,
81     XImage		*shapeimage,
82     XpmAttributes	*attributes)
83 {
84     XpmImage xpmimage;
85     XpmInfo info;
86     int ErrorStatus;
87 
88     /* create an XpmImage from the image */
89     ErrorStatus = XpmCreateXpmImageFromImage(display, image, shapeimage,
90 					     &xpmimage, attributes);
91     if (ErrorStatus != XpmSuccess)
92 	return (ErrorStatus);
93 
94     /* write the file from the XpmImage */
95     if (attributes) {
96 	xpmSetInfo(&info, attributes);
97 	ErrorStatus = XpmWriteFileFromXpmImage(filename, &xpmimage, &info);
98     } else
99 	ErrorStatus = XpmWriteFileFromXpmImage(filename, &xpmimage, NULL);
100 
101     /* free the XpmImage */
102     XpmFreeXpmImage(&xpmimage);
103 
104     return (ErrorStatus);
105 }
106 
107 int
XpmWriteFileFromXpmImage(const char * filename,XpmImage * image,XpmInfo * info)108 XpmWriteFileFromXpmImage(
109     const char	*filename,
110     XpmImage	*image,
111     XpmInfo	*info)
112 {
113     xpmData mdata;
114     const char *name;
115     char *dot, *s, new_name[BUFSIZ] = {0};
116     int ErrorStatus;
117 
118     /* open file to write */
119     if ((ErrorStatus = OpenWriteFile(filename, &mdata)) != XpmSuccess)
120 	return (ErrorStatus);
121 
122     /* figure out a name */
123     if (filename) {
124 #ifdef VMS
125 	name = filename;
126 #else
127 	if (!(name = strrchr(filename, '/'))
128 #ifdef AMIGA
129 	    && !(name = strrchr(filename, ':'))
130 #endif
131      )
132 	    name = filename;
133 	else
134 	    name++;
135 #endif
136 	/* let's try to make a valid C syntax name */
137 	if (strchr(name, '.')) {
138 	    strncpy(new_name, name, sizeof(new_name));
139 	    new_name[sizeof(new_name)-1] = '\0';
140 	    /* change '.' to '_' */
141 	    name = s = new_name;
142 	    while ((dot = strchr(s, '.'))) {
143 		*dot = '_';
144 		s = dot;
145 	    }
146 	}
147 	if (strchr(name, '-')) {
148 	    if (name != new_name) {
149 		strncpy(new_name, name, sizeof(new_name));
150 		new_name[sizeof(new_name)-1] = '\0';
151 		name = new_name;
152 	    }
153 	    /* change '-' to '_' */
154 	    s = new_name;
155 	    while ((dot = strchr(s, '-'))) {
156 		*dot = '_';
157 		s = dot;
158 	    }
159 	}
160     } else
161 	name = "image_name";
162 
163     /* write the XpmData from the XpmImage */
164     if (ErrorStatus == XpmSuccess)
165 	ErrorStatus = xpmWriteFile(mdata.stream.file, image, name, info);
166 
167     xpmDataClose(&mdata);
168 
169     return (ErrorStatus);
170 }
171 
172 static int
xpmWriteFile(FILE * file,XpmImage * image,const char * name,XpmInfo * info)173 xpmWriteFile(
174     FILE	*file,
175     XpmImage	*image,
176     const char	*name,
177     XpmInfo	*info)
178 {
179     /* calculation variables */
180     unsigned int cmts, extensions;
181     int ErrorStatus;
182 
183     cmts = info && (info->valuemask & XpmComments);
184     extensions = info && (info->valuemask & XpmExtensions)
185 	&& info->nextensions;
186 
187     /* print the header line */
188     fprintf(file, "/* XPM */\nstatic char * %s[] = {\n", name);
189 
190     /* print the hints line */
191     if (cmts && info->hints_cmt)
192 	fprintf(file, "/*%s*/\n", info->hints_cmt);
193 
194     fprintf(file, "\"%d %d %d %d", image->width, image->height,
195 	    image->ncolors, image->cpp);
196 
197     if (info && (info->valuemask & XpmHotspot))
198 	fprintf(file, " %d %d", info->x_hotspot, info->y_hotspot);
199 
200     if (extensions)
201 	fprintf(file, " XPMEXT");
202 
203     fprintf(file, "\",\n");
204 
205     /* print colors */
206     if (cmts && info->colors_cmt)
207 	fprintf(file, "/*%s*/\n", info->colors_cmt);
208 
209     WriteColors(file, image->colorTable, image->ncolors);
210 
211     /* print pixels */
212     if (cmts && info->pixels_cmt)
213 	fprintf(file, "/*%s*/\n", info->pixels_cmt);
214 
215     ErrorStatus = WritePixels(file, image->width, image->height, image->cpp,
216 			      image->data, image->colorTable);
217     if (ErrorStatus != XpmSuccess)
218 	return (ErrorStatus);
219 
220     /* print extensions */
221     if (extensions)
222 	WriteExtensions(file, info->extensions, info->nextensions);
223 
224     /* close the array */
225     fprintf(file, "};\n");
226 
227     return (XpmSuccess);
228 }
229 
230 static void
WriteColors(FILE * file,XpmColor * colors,unsigned int ncolors)231 WriteColors(
232     FILE		*file,
233     XpmColor		*colors,
234     unsigned int	 ncolors)
235 {
236     unsigned int a, key;
237     char *s;
238     char **defaults;
239 
240     for (a = 0; a < ncolors; a++, colors++) {
241 
242 	defaults = (char **) colors;
243 	fprintf(file, "\"%s", *defaults++);
244 
245 	for (key = 1; key <= NKEYS; key++, defaults++) {
246 	    if ((s = *defaults))
247 		fprintf(file, "\t%s %s", xpmColorKeys[key - 1], s);
248 	}
249 	fprintf(file, "\",\n");
250     }
251 }
252 
253 
254 static int
WritePixels(FILE * file,unsigned int width,unsigned int height,unsigned int cpp,unsigned int * pixels,XpmColor * colors)255 WritePixels(
256     FILE		*file,
257     unsigned int	 width,
258     unsigned int	 height,
259     unsigned int	 cpp,
260     unsigned int	*pixels,
261     XpmColor		*colors)
262 {
263     char *s, *p, *buf;
264     unsigned int x, y, h;
265 
266     h = height - 1;
267     if (cpp != 0 && width >= (UINT_MAX - 3)/cpp)
268 	return XpmNoMemory;
269     p = buf = (char *) XpmMalloc(width * cpp + 3);
270     if (!buf)
271 	return (XpmNoMemory);
272     *buf = '"';
273     p++;
274     for (y = 0; y < h; y++) {
275 	s = p;
276 	for (x = 0; x < width; x++, pixels++) {
277 	    strncpy(s, colors[*pixels].string, cpp);
278 	    s += cpp;
279 	}
280 	*s++ = '"';
281 	*s = '\0';
282 	fprintf(file, "%s,\n", buf);
283     }
284     /* duplicate some code to avoid a test in the loop */
285     s = p;
286     for (x = 0; x < width; x++, pixels++) {
287 	strncpy(s, colors[*pixels].string, cpp);
288 	s += cpp;
289     }
290     *s++ = '"';
291     *s = '\0';
292     fprintf(file, "%s", buf);
293 
294     XpmFree(buf);
295     return (XpmSuccess);
296 }
297 
298 static void
WriteExtensions(FILE * file,XpmExtension * ext,unsigned int num)299 WriteExtensions(
300     FILE		*file,
301     XpmExtension	*ext,
302     unsigned int	 num)
303 {
304     unsigned int x, y, n;
305     char **line;
306 
307     for (x = 0; x < num; x++, ext++) {
308 	fprintf(file, ",\n\"XPMEXT %s\"", ext->name);
309 	n = ext->nlines;
310 	for (y = 0, line = ext->lines; y < n; y++, line++)
311 	    fprintf(file, ",\n\"%s\"", *line);
312     }
313     fprintf(file, ",\n\"XPMENDEXT\"");
314 }
315 
316 
317 #ifndef NO_ZPIPE
318 FUNC(xpmPipeThrough, FILE*, (int fd,
319 			     const char* cmd,
320 			     const char* arg1,
321 			     const char* mode));
322 #endif
323 
324 /*
325  * open the given file to be written as an xpmData which is returned
326  */
327 static int
OpenWriteFile(const char * filename,xpmData * mdata)328 OpenWriteFile(
329     const char	*filename,
330     xpmData	*mdata)
331 {
332     if (!filename) {
333 	mdata->stream.file = (stdout);
334 	mdata->type = XPMFILE;
335     } else {
336 #ifndef NO_ZPIPE
337 	size_t len;
338 #endif
339 	int fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644);
340 	if ( fd < 0 )
341 	    return(XpmOpenFailed);
342 #ifndef NO_ZPIPE
343 	len = strlen(filename);
344 	if (len > 2 && !strcmp(".Z", filename + (len - 2))) {
345 	    mdata->stream.file = xpmPipeThrough(fd, "compress", NULL, "w");
346 	    mdata->type = XPMPIPE;
347 	} else if (len > 3 && !strcmp(".gz", filename + (len - 3))) {
348 	    mdata->stream.file = xpmPipeThrough(fd, "gzip", "-q", "w");
349 	    mdata->type = XPMPIPE;
350 	} else
351 #endif
352 	{
353 	    mdata->stream.file = fdopen(fd, "w");
354 	    mdata->type = XPMFILE;
355 	}
356 	if (!mdata->stream.file) {
357 	    close(fd);
358 	    return (XpmOpenFailed);
359 	}
360     }
361     return (XpmSuccess);
362 }
363 
364 /*
365  * close the file related to the xpmData if any
366  */
367 static void
xpmDataClose(xpmData * mdata)368 xpmDataClose(xpmData *mdata)
369 {
370     if (mdata->stream.file != (stdout))
371 	fclose(mdata->stream.file);
372 }
373 
374