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