File: | xcursorgen.c |
Location: | line 443, column 3 |
Description: | Potential leak of memory pointed to by 'list' |
1 | /* | |||
2 | * xcursorgen.c | |||
3 | * | |||
4 | * Copyright (C) 2002 Manish Singh | |||
5 | * | |||
6 | * Permission to use, copy, modify, distribute, and sell this software and its | |||
7 | * documentation for any purpose is hereby granted without fee, provided that | |||
8 | * the above copyright notice appear in all copies and that both that | |||
9 | * copyright notice and this permission notice appear in supporting | |||
10 | * documentation, and that the name of Manish Singh not be used in | |||
11 | * advertising or publicity pertaining to distribution of the software without | |||
12 | * specific, written prior permission. Manish Singh makes no | |||
13 | * representations about the suitability of this software for any purpose. It | |||
14 | * is provided "as is" without express or implied warranty. | |||
15 | * | |||
16 | * MANISH SINGH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | |||
17 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | |||
18 | * EVENT SHALL MANISH SINGH BE LIABLE FOR ANY SPECIAL, INDIRECT OR | |||
19 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | |||
20 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | |||
21 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |||
22 | * PERFORMANCE OF THIS SOFTWARE. | |||
23 | */ | |||
24 | ||||
25 | #include "config.h" | |||
26 | ||||
27 | #include <stdio.h> | |||
28 | #include <stdlib.h> | |||
29 | #include <string.h> | |||
30 | #include <ctype.h> | |||
31 | ||||
32 | #include <X11/Xlib.h> | |||
33 | #include <X11/Xutil.h> | |||
34 | #include <X11/Xcursor/Xcursor.h> | |||
35 | ||||
36 | #include <png.h> | |||
37 | ||||
38 | struct flist | |||
39 | { | |||
40 | int size; | |||
41 | int xhot, yhot; | |||
42 | int delay; | |||
43 | char *pngfile; | |||
44 | struct flist *next; | |||
45 | }; | |||
46 | ||||
47 | static void | |||
48 | usage (const char *name) | |||
49 | { | |||
50 | fprintf (stderr__stderrp, | |||
51 | "usage: %s [-V] [--version] [-?] [--help] [-p <dir>] [--prefix <dir>] [CONFIG [OUT]]\n%s", | |||
52 | name, | |||
53 | "Generate an Xcursor file from a series of PNG images\n" | |||
54 | "\n" | |||
55 | " -V, --version display the version number and exit\n" | |||
56 | " -?, --help display this message and exit\n" | |||
57 | " -p, --prefix <dir> find cursor images in <dir>\n" | |||
58 | "\n" | |||
59 | "With no CONFIG, or when CONFIG is -, read standard input. " | |||
60 | "Same with OUT and\n" | |||
61 | "standard output.\n"); | |||
62 | } | |||
63 | ||||
64 | static int | |||
65 | read_config_file (const char *config, struct flist **list) | |||
66 | { | |||
67 | FILE *fp; | |||
68 | char line[4096], pngfile[4000]; | |||
69 | int size, xhot, yhot, delay; | |||
70 | struct flist *start = NULL((void*)0), *end = NULL((void*)0), *curr; | |||
71 | int count = 0; | |||
72 | ||||
73 | if (strcmp (config, "-") != 0) | |||
74 | { | |||
75 | fp = fopen (config, "r"); | |||
76 | if (!fp) | |||
77 | { | |||
78 | *list = NULL((void*)0); | |||
79 | return 0; | |||
80 | } | |||
81 | } | |||
82 | else | |||
83 | fp = stdin__stdinp; | |||
84 | ||||
85 | while (fgets (line, sizeof (line), fp) != NULL((void*)0)) | |||
86 | { | |||
87 | if (line[0] == '#') | |||
88 | continue; | |||
89 | ||||
90 | switch (sscanf (line, "%d %d %d %3999s %d", &size, &xhot, &yhot, pngfile, &delay)) | |||
91 | { | |||
92 | case 4: | |||
93 | delay = 50; | |||
94 | break; | |||
95 | case 5: | |||
96 | break; | |||
97 | default: | |||
98 | { | |||
99 | fprintf (stderr__stderrp, "Bad config file data!\n"); | |||
100 | fclose (fp); | |||
101 | return 0; | |||
102 | } | |||
103 | } | |||
104 | ||||
105 | curr = malloc (sizeof (struct flist)); | |||
106 | if (curr == NULL((void*)0)) | |||
107 | { | |||
108 | fprintf (stderr__stderrp, "malloc() failed\n"); | |||
109 | fclose (fp); | |||
110 | return 0; | |||
111 | } | |||
112 | ||||
113 | curr->size = size; | |||
114 | curr->xhot = xhot; | |||
115 | curr->yhot = yhot; | |||
116 | ||||
117 | curr->delay = delay; | |||
118 | ||||
119 | curr->pngfile = strdup (pngfile); | |||
120 | if (curr->pngfile == NULL((void*)0)) | |||
121 | { | |||
122 | fprintf (stderr__stderrp, "strdup() failed\n"); | |||
123 | fclose (fp); | |||
124 | free(curr); | |||
125 | return 0; | |||
126 | } | |||
127 | ||||
128 | curr->next = NULL((void*)0); | |||
129 | ||||
130 | if (start) | |||
131 | { | |||
132 | end->next = curr; | |||
133 | end = curr; | |||
134 | } | |||
135 | else | |||
136 | { | |||
137 | start = curr; | |||
138 | end = curr; | |||
139 | } | |||
140 | ||||
141 | count++; | |||
142 | } | |||
143 | ||||
144 | fclose (fp); | |||
145 | ||||
146 | *list = start; | |||
147 | return count; | |||
148 | } | |||
149 | ||||
150 | #define div_255(x)(((x) + 0x80 + (((x) + 0x80) >> 8)) >> 8) (((x) + 0x80 + (((x) + 0x80) >> 8)) >> 8) | |||
151 | ||||
152 | static void | |||
153 | premultiply_data (png_structp png, png_row_infop row_info, png_bytep data) | |||
154 | { | |||
155 | int i; | |||
156 | ||||
157 | for (i = 0; i < row_info->rowbytes; i += 4) | |||
158 | { | |||
159 | unsigned char *base = &data[i]; | |||
160 | unsigned char blue = base[0]; | |||
161 | unsigned char green = base[1]; | |||
162 | unsigned char red = base[2]; | |||
163 | unsigned char alpha = base[3]; | |||
164 | XcursorPixel p; | |||
165 | ||||
166 | red = div_255((unsigned)red * (unsigned)alpha)((((unsigned)red * (unsigned)alpha) + 0x80 + ((((unsigned)red * (unsigned)alpha) + 0x80) >> 8)) >> 8); | |||
167 | green = div_255((unsigned)green * (unsigned)alpha)((((unsigned)green * (unsigned)alpha) + 0x80 + ((((unsigned)green * (unsigned)alpha) + 0x80) >> 8)) >> 8); | |||
168 | blue = div_255((unsigned)blue * (unsigned)alpha)((((unsigned)blue * (unsigned)alpha) + 0x80 + ((((unsigned)blue * (unsigned)alpha) + 0x80) >> 8)) >> 8); | |||
169 | p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0); | |||
170 | memcpy (base, &p, sizeof (XcursorPixel))__builtin___memcpy_chk (base, &p, sizeof (XcursorPixel), __builtin_object_size (base, 0)); | |||
171 | } | |||
172 | } | |||
173 | ||||
174 | static XcursorImage * | |||
175 | load_image (struct flist *list, const char *prefix) | |||
176 | { | |||
177 | XcursorImage *image; | |||
178 | png_structp png; | |||
179 | png_infop info; | |||
180 | png_bytepp rows; | |||
181 | FILE *fp; | |||
182 | int i; | |||
183 | png_uint_32 width, height; | |||
184 | int depth, color, interlace; | |||
185 | char *file; | |||
186 | ||||
187 | png = png_create_read_struct (PNG_LIBPNG_VER_STRING"1.5.1", NULL((void*)0), NULL((void*)0), NULL((void*)0)); | |||
188 | if (png == NULL((void*)0)) | |||
189 | return NULL((void*)0); | |||
190 | ||||
191 | info = png_create_info_struct (png); | |||
192 | if (info == NULL((void*)0)) | |||
193 | { | |||
194 | png_destroy_read_struct (&png, NULL((void*)0), NULL((void*)0)); | |||
195 | return NULL((void*)0); | |||
196 | } | |||
197 | ||||
198 | if (setjmp (png_jmpbuf(png)(*png_set_longjmp_fn((png), longjmp, sizeof (jmp_buf))))) | |||
199 | { | |||
200 | png_destroy_read_struct (&png, &info, NULL((void*)0)); | |||
201 | return NULL((void*)0); | |||
202 | } | |||
203 | ||||
204 | if (prefix) | |||
205 | { | |||
206 | file = malloc (strlen (prefix) + 1 + strlen (list->pngfile) + 1); | |||
207 | if (file == NULL((void*)0)) | |||
208 | { | |||
209 | fprintf (stderr__stderrp, "malloc() failed\n"); | |||
210 | png_destroy_read_struct (&png, &info, NULL((void*)0)); | |||
211 | return NULL((void*)0); | |||
212 | } | |||
213 | strcpy (file, prefix)__builtin___strcpy_chk (file, prefix, __builtin_object_size ( file, 2 > 1 ? 1 : 0)); | |||
214 | strcat (file, "/")__builtin___strcat_chk (file, "/", __builtin_object_size (file , 2 > 1 ? 1 : 0)); | |||
215 | strcat (file, list->pngfile)__builtin___strcat_chk (file, list->pngfile, __builtin_object_size (file, 2 > 1 ? 1 : 0)); | |||
216 | } | |||
217 | else | |||
218 | file = list->pngfile; | |||
219 | fp = fopen (file, "rb"); | |||
220 | if (prefix) | |||
221 | free (file); | |||
222 | ||||
223 | if (fp == NULL((void*)0)) | |||
224 | { | |||
225 | png_destroy_read_struct (&png, &info, NULL((void*)0)); | |||
226 | return NULL((void*)0); | |||
227 | } | |||
228 | ||||
229 | png_init_io (png, fp); | |||
230 | png_read_info (png, info); | |||
231 | png_get_IHDR (png, info, &width, &height, &depth, &color, &interlace, | |||
232 | NULL((void*)0), NULL((void*)0)); | |||
233 | ||||
234 | /* TODO: More needs to be done here maybe */ | |||
235 | ||||
236 | if (color == PNG_COLOR_TYPE_PALETTE(2 | 1) && depth <= 8) | |||
237 | png_set_expand (png); | |||
238 | ||||
239 | if (color == PNG_COLOR_TYPE_GRAY0 && depth < 8) | |||
240 | png_set_expand (png); | |||
241 | ||||
242 | if (png_get_valid (png, info, PNG_INFO_tRNS0x0010)) | |||
243 | png_set_expand (png); | |||
244 | ||||
245 | if (depth == 16) | |||
246 | png_set_strip_16 (png); | |||
247 | ||||
248 | if (depth < 8) | |||
249 | png_set_packing (png); | |||
250 | ||||
251 | if (color == PNG_COLOR_TYPE_GRAY0 || color == PNG_COLOR_TYPE_GRAY_ALPHA(4)) | |||
252 | png_set_gray_to_rgb (png); | |||
253 | ||||
254 | if (interlace != PNG_INTERLACE_NONE0) | |||
255 | png_set_interlace_handling (png); | |||
256 | ||||
257 | png_set_bgr (png); | |||
258 | png_set_filler (png, 255, PNG_FILLER_AFTER1); | |||
259 | ||||
260 | png_set_read_user_transform_fn (png, premultiply_data); | |||
261 | ||||
262 | png_read_update_info (png, info); | |||
263 | ||||
264 | image = XcursorImageCreate (width, height); | |||
265 | ||||
266 | image->size = list->size; | |||
267 | image->xhot = list->xhot; | |||
268 | image->yhot = list->yhot; | |||
269 | image->delay = list->delay; | |||
270 | ||||
271 | rows = malloc (sizeof (png_bytep) * height); | |||
272 | if (rows == NULL((void*)0)) | |||
273 | { | |||
274 | fclose (fp); | |||
275 | png_destroy_read_struct (&png, &info, NULL((void*)0)); | |||
276 | return NULL((void*)0); | |||
277 | } | |||
278 | ||||
279 | for (i = 0; i < height; i++) | |||
280 | rows[i] = (png_bytep) (image->pixels + i * width); | |||
281 | ||||
282 | png_read_image (png, rows); | |||
283 | png_read_end (png, info); | |||
284 | ||||
285 | free (rows); | |||
286 | fclose (fp); | |||
287 | png_destroy_read_struct (&png, &info, NULL((void*)0)); | |||
288 | ||||
289 | return image; | |||
290 | } | |||
291 | ||||
292 | static int | |||
293 | write_cursors (int count, struct flist *list, | |||
294 | const char *filename, const char *prefix) | |||
295 | { | |||
296 | XcursorImages *cimages; | |||
297 | XcursorImage *image; | |||
298 | int i; | |||
299 | FILE *fp; | |||
300 | int ret; | |||
301 | ||||
302 | if (strcmp (filename, "-") != 0) | |||
303 | { | |||
304 | fp = fopen (filename, "wb"); | |||
305 | if (!fp) | |||
306 | return 1; | |||
307 | } | |||
308 | else | |||
309 | fp = stdout__stdoutp; | |||
310 | ||||
311 | cimages = XcursorImagesCreate (count); | |||
312 | ||||
313 | cimages->nimage = count; | |||
314 | ||||
315 | for (i = 0; i < count; i++, list = list->next) | |||
316 | { | |||
317 | image = load_image (list, prefix); | |||
318 | if (image == NULL((void*)0)) | |||
319 | { | |||
320 | fprintf (stderr__stderrp, "PNG error while reading %s!\n", list->pngfile); | |||
321 | fclose(fp); | |||
322 | return 1; | |||
323 | } | |||
324 | ||||
325 | cimages->images[i] = image; | |||
326 | } | |||
327 | ||||
328 | ret = XcursorFileSaveImages (fp, cimages); | |||
329 | ||||
330 | fclose (fp); | |||
331 | ||||
332 | return ret ? 0 : 1; | |||
333 | } | |||
334 | ||||
335 | static int | |||
336 | check_image (char *image) | |||
337 | { | |||
338 | unsigned int width, height; | |||
339 | unsigned char *data; | |||
340 | int x_hot, y_hot; | |||
341 | unsigned char hash[XCURSOR_BITMAP_HASH_SIZE16]; | |||
342 | int i; | |||
343 | ||||
344 | if (XReadBitmapFileData (image, &width, &height, &data, &x_hot, &y_hot) != BitmapSuccess0) | |||
345 | { | |||
346 | fprintf (stderr__stderrp, "Can't open bitmap file \"%s\"\n", image); | |||
347 | return 1; | |||
348 | } | |||
349 | else { | |||
350 | XImage ximage = { | |||
351 | .width = width, | |||
352 | .height = height, | |||
353 | .depth = 1, | |||
354 | .bits_per_pixel = 1, | |||
355 | .xoffset = 0, | |||
356 | .format = XYPixmap1, | |||
357 | .data = (char *)data, | |||
358 | .byte_order = LSBFirst0, | |||
359 | .bitmap_unit = 8, | |||
360 | .bitmap_bit_order = LSBFirst0, | |||
361 | .bitmap_pad = 8, | |||
362 | .bytes_per_line = (width+7)/8 | |||
363 | }; | |||
364 | XcursorImageHash (&ximage, hash); | |||
365 | } | |||
366 | printf ("%s: ", image); | |||
367 | for (i = 0; i < XCURSOR_BITMAP_HASH_SIZE16; i++) | |||
368 | printf ("%02x", hash[i]); | |||
369 | printf ("\n"); | |||
370 | return 0; | |||
371 | } | |||
372 | ||||
373 | int | |||
374 | main (int argc, char *argv[]) | |||
375 | { | |||
376 | struct flist *list; | |||
377 | int count; | |||
378 | const char *in = NULL((void*)0), *out = NULL((void*)0); | |||
379 | const char *prefix = NULL((void*)0); | |||
380 | int i; | |||
381 | ||||
382 | for (i = 1; i < argc; i++) | |||
| ||||
383 | { | |||
384 | if (strcmp (argv[i], "-V") == 0 || strcmp (argv[i], "--version") == 0) | |||
385 | { | |||
386 | printf ("xcursorgen version %s\n", PACKAGE_VERSION"1.0.6"); | |||
387 | return 0; | |||
388 | } | |||
389 | ||||
390 | if (strcmp (argv[i], "-?") == 0 || strcmp (argv[i], "--help") == 0) | |||
391 | { | |||
392 | usage (argv[0]); | |||
393 | return 0; | |||
394 | } | |||
395 | if (strcmp (argv[i], "-image") == 0) | |||
396 | { | |||
397 | int ret = 0; | |||
398 | while (argv[++i]) | |||
399 | { | |||
400 | if (check_image (argv[i])) | |||
401 | ret = i; | |||
402 | } | |||
403 | return ret; | |||
404 | } | |||
405 | if (strcmp (argv[i], "-p") == 0 || strcmp (argv[i], "--prefix") == 0) | |||
406 | { | |||
407 | i++; | |||
408 | if (argv[i] == NULL((void*)0)) | |||
409 | { | |||
410 | fprintf (stderr__stderrp, "%s: %s requires an argument\n", | |||
411 | argv[0], argv[i-1]); | |||
412 | usage (argv[0]); | |||
413 | return 1; | |||
414 | } | |||
415 | prefix = argv[i]; | |||
416 | continue; | |||
417 | } | |||
418 | ||||
419 | if (!in) | |||
420 | in = argv[i]; | |||
421 | else if (!out) | |||
422 | out = argv[i]; | |||
423 | else | |||
424 | { | |||
425 | fprintf (stderr__stderrp, "%s: unexpected argument '%s'\n", argv[0], argv[i]); | |||
426 | usage (argv[0]); | |||
427 | return 1; | |||
428 | } | |||
429 | } | |||
430 | ||||
431 | if (!in) | |||
432 | in = "-"; | |||
433 | if (!out) | |||
434 | out = "-"; | |||
435 | ||||
436 | count = read_config_file (in, &list); | |||
437 | if (count == 0) | |||
438 | { | |||
439 | fprintf (stderr__stderrp, "Error reading config file!\n"); | |||
440 | return 1; | |||
441 | } | |||
442 | ||||
443 | return write_cursors (count, list, out, prefix); | |||
| ||||
444 | } |