1 /* ico2png.c - Create icon and cursor files from PNG images
2  *
3  * minimalistic version extracted from package 'icoutil'
4  * 'icoutil' is copyrighted as follows :
5  *
6  * Copyright (C) 1998-2005 Oskar Liljeblad
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21  */
22 
23 #ifndef _GNU_SOURCE
24 # define _GNU_SOURCE 1
25 #endif
26 
27 #include <stdint.h>		/* POSIX/Gnulib */
28 #include <stdio.h>		/* C89 */
29 #include <stdbool.h>		/* POSIX/Gnulib */
30 #include <stdlib.h>		/* C89 */
31 #include <stdarg.h>		/* C89 */
32 #include <stddef.h>
33 #include <dirent.h>
34 #include <ctype.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #ifdef HAVE_ERROR_H
38 #include <error.h>
39 #endif
40 #include <errno.h>
41 #include <getopt.h>
42 
43 #include <png.h>
44 
45 #include <X11/Intrinsic.h>
46 #include <X11/xpm.h>
47 
48 #include "xpaint.h"
49 #include "image.h"
50 #include "libpnmrw.h"
51 
52 extern int file_numpages;
53 extern int file_isSpecialImage;
54 static int silent;
55 
56 extern Image * readMagic(char *file);
57 extern Image * ReadPNG(char *file);
58 extern int WritePNGn(char *file, Image *image);
59 extern FILE * openTempFile(char **np);
60 extern void removeTempFile(void);
61 extern void AlphaWarning(char *format, int mode);
62 extern void * xmalloc(size_t n);
63 
64 /* Version number of program/package */
65 #define PROGRAM "ico2png"
66 
67 # ifndef __attribute__
68 #  if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__
69 #   define __attribute__(x)
70 #  endif
71 # endif
72 #define PACKED __attribute__ ((packed))
73 
74 struct MessageHeader {
75 	struct MessageHeader *old;
76 	char *message;
77 };
78 
79 #define memclear(m, s)		memset((m), 0, (s))
80 
81 #define xrealloc realloc
82 #define xcalloc(s) calloc(1, ((s)))
83 #define xstrdup strdup
84 
85 typedef void (*IteratorFunc)(void *);
86 
87 typedef struct _IteratorClass IteratorClass;
88 typedef struct _Iterator Iterator;
89 
90 struct _IteratorClass {
91 	bool (*has_next)(Iterator *it);
92 	void *(*next)(Iterator *it);
93 	void (*remove)(Iterator *it);
94 	void (*free)(Iterator *it);
95 	void (*restart)(Iterator *it);
96 	void *(*previous)(Iterator *it);
97 	void (*add)(Iterator *it, void *value);
98 };
99 
100 struct _Iterator {
101 	IteratorClass *class;
102 };
103 
104 static bool
iterator_has_next(Iterator * it)105 iterator_has_next(Iterator *it)
106 {
107 	return it->class->has_next(it);
108 }
109 
110 static void *
iterator_next(Iterator * it)111 iterator_next(Iterator *it)
112 {
113 	return it->class->next(it);
114 }
115 
116 static void
iterator_free(Iterator * it)117 iterator_free(Iterator *it)
118 {
119 	if (it->class->free == NULL)
120 		free(it);
121 	else
122 		it->class->free(it);
123 }
124 
125 static void
v_warn(const char * msg,va_list ap)126 v_warn(const char *msg, va_list ap)
127 {
128 	fprintf(stderr, "%s: ", PROGRAM);
129 	if (msg != NULL)
130 		vfprintf(stderr, msg, ap);
131 	fprintf(stderr, "\n");
132 }
133 
134 static void
warn(const char * msg,...)135 warn(const char *msg, ...)
136 {
137 	va_list ap;
138 
139         if (silent) return;
140 	va_start(ap, msg);
141 	v_warn(msg, ap);
142 	va_end(ap);
143 }
144 
145 static void
v_warn_errno(const char * msg,va_list ap)146 v_warn_errno(const char *msg, va_list ap)
147 {
148 	fprintf(stderr, "%s: ", PROGRAM);
149 	if (msg != NULL) {
150 		vfprintf(stderr, msg, ap);
151 		fprintf(stderr, ": ");
152 	}
153 	fprintf(stderr, "%s\n", strerror(errno));
154 }
155 
156 static void
warn_errno(const char * msg,...)157 warn_errno(const char *msg, ...)
158 {
159 	va_list ap;
160 
161 	va_start(ap, msg);
162 	v_warn_errno(msg, ap);
163 	va_end(ap);
164 }
165 
166 typedef struct _Entry Entry;
167 
168 struct _Entry {
169 	void *key;
170 	void *value;
171 	Entry *next;
172 };
173 
174 typedef uint32_t (*HashFunc)(const void *);
175 typedef int32_t (*CompareFunc)(const void *, const void *);
176 
177 typedef struct _HMap HMap;
178 
179 struct _HMap {
180 	Entry **buckets;
181 	uint32_t buckets_length;
182 	uint32_t threshold;
183 	float load_factor;
184 	uint32_t size;
185 
186 	HashFunc hash_key;
187 	CompareFunc compare_keys;
188 };
189 
190 static uint32_t
string_hash(const char * key)191 string_hash(const char *key)
192 {
193 	uint32_t hash = 0;
194 
195 	for (; *key != '\0'; key++)
196 		hash = (hash << 5) - hash + *key;
197 
198 	return hash;
199 }
200 
201 static HMap *
hmap_new_specific(uint32_t initial_capacity,float load_factor)202 hmap_new_specific(uint32_t initial_capacity, float load_factor)
203 {
204 	HMap *map = xmalloc(sizeof(HMap));
205 
206 	map->buckets = xmalloc(initial_capacity * sizeof(Entry *));
207 	memclear(map->buckets, initial_capacity * sizeof(Entry *));
208 
209 	map->buckets_length = initial_capacity;
210 	map->threshold = (uint32_t) (initial_capacity * load_factor);
211 	map->load_factor = load_factor;
212 	map->size = 0;
213 
214 	map->hash_key = (HashFunc) string_hash;
215 	map->compare_keys = (CompareFunc) strcmp;
216 
217 	return map;
218 }
219 
220 #define DEFAULT_CAPACITY 16
221 #define DEFAULT_LOAD_FACTOR           0.75F
222 
223 static HMap *
hmap_new(void)224 hmap_new(void)
225 {
226 	return hmap_new_specific(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR);
227 }
228 
229 static void
hmap_set_hash_function(HMap * map,HashFunc hash_key)230 hmap_set_hash_function(HMap *map, HashFunc hash_key)
231 {
232 	map->hash_key = hash_key;
233 }
234 
235 static void
hmap_set_compare_function(HMap * map,CompareFunc compare_keys)236 hmap_set_compare_function(HMap *map, CompareFunc compare_keys)
237 {
238 	map->compare_keys = compare_keys;
239 }
240 
241 static void
hmap_iterate_values(HMap * map,IteratorFunc iterator_func)242 hmap_iterate_values(HMap *map, IteratorFunc iterator_func)
243 {
244 	uint32_t i;
245 
246     for (i = 0; i < map->buckets_length; i++) {
247 		Entry *entry;
248 		for (entry = map->buckets[i]; entry != NULL; entry = entry->next)
249 			iterator_func(entry->value);
250 	}
251 }
252 
253 static void
hmap_clear(HMap * map)254 hmap_clear(HMap *map)
255 {
256 	uint32_t i;
257 
258     for (i = 0; i < map->buckets_length; i++) {
259 		Entry *entry = map->buckets[i];
260 		while (entry != NULL) {
261 			Entry *next = entry->next;
262 			free(entry);
263 			entry = next;
264 		}
265 		map->buckets[i] = NULL;
266 	}
267 
268 	map->size = 0;
269 }
270 
271 static void
hmap_free(HMap * map)272 hmap_free(HMap *map)
273 {
274 	hmap_clear(map);
275 	free(map->buckets);
276 	free(map);
277 }
278 
279 static inline uint32_t
hmap_hash(HMap * map,const void * key)280 hmap_hash(HMap *map, const void *key)
281 {
282 //	printf("hash %s into -> %d pos %d (%d)\n", key, map->hash_key(key), map->hash_key(key) % map->buckets_length, map->buckets_length);
283 	return (key == NULL ? 0 : (map->hash_key(key) % map->buckets_length));
284 }
285 
286 static bool
hmap_contains_key(HMap * map,const void * key)287 hmap_contains_key(HMap *map, const void *key)
288 {
289 	if (key == NULL) {
290 		Entry *entry = map->buckets[0];
291 		for (; entry != NULL; entry = entry->next) {
292 			if (entry->key == NULL)
293 				return true;
294 		}
295 	} else {
296 		Entry *entry = map->buckets[hmap_hash(map, key)];
297 		for (; entry != NULL; entry = entry->next) {
298 //			printf("compare %s vs %s -> %d\n",key,entry->key,map->compare_keys(key, entry->key));
299 			if (map->compare_keys(key, entry->key) == 0)
300 				return true;
301 		}
302 	}
303 
304 	return false;
305 }
306 
307 static inline void
hmap_rehash(HMap * map)308 hmap_rehash(HMap *map)
309 {
310 	Entry **old_buckets = map->buckets;
311 	uint32_t old_capacity = map->buckets_length;
312 	uint32_t i;
313 
314 	map->buckets_length = (map->buckets_length * 2) + 1;
315 	map->threshold = (uint32_t) (map->buckets_length * map->load_factor);
316 	map->buckets = xmalloc(map->buckets_length * sizeof(Entry *));
317 	memclear(map->buckets, map->buckets_length * sizeof(Entry *));
318 
319 	for (i = 0; i < old_capacity; i++) {
320 		Entry *entry = old_buckets[i];
321 		while (entry != NULL) {
322 			uint32_t index = hmap_hash(map, entry->key);
323 			Entry *dest = map->buckets[index];
324 			Entry *next;
325 
326 			if (dest != NULL) {
327 				while (dest->next != NULL)
328 					dest = dest->next;
329 				dest->next = entry;
330 			} else {
331 				map->buckets[index] = entry;
332 			}
333 
334 			next = entry->next;
335 			entry->next = NULL;
336 			entry = next;
337 		}
338 	}
339 
340 	free(old_buckets);
341 }
342 
343 static uint32_t
hmap_size(HMap * map)344 hmap_size(HMap *map)
345 {
346 	return map->size;
347 }
348 
349 static void *
hmap_get(HMap * map,const void * key)350 hmap_get(HMap *map, const void *key)
351 {
352 	if (key == NULL) {
353 		Entry *entry = map->buckets[0];
354 		for (; entry != NULL; entry = entry->next) {
355 			if (entry->key == NULL)
356 				return entry->value;
357 		}
358 	} else {
359 		Entry *entry = map->buckets[hmap_hash(map, key)];
360 		for (; entry != NULL; entry = entry->next) {
361 			if (map->compare_keys(key, entry->key) == 0)
362 				return entry->value;
363 		}
364 	}
365 
366 	return NULL;
367 }
368 
369 static void *
hmap_put(HMap * map,void * key,void * value)370 hmap_put(HMap *map, void *key, void *value)
371 {
372 	Entry *entry;
373 	uint32_t index;
374 
375 	if (key == NULL) {
376 		for (entry = map->buckets[0]; entry != NULL; entry = entry->next) {
377 			if (entry->key == NULL) {
378 				void *old_value = entry->value;
379 				entry->value = value;
380 				return old_value;
381 			}
382 		}
383 		index = 0;
384 	} else {
385 		index = hmap_hash(map, key);
386 		for (entry = map->buckets[index]; entry != NULL; entry = entry->next) {
387 			if (map->compare_keys(key, entry->key) == 0) {
388 				void *old_value = entry->value;
389 				entry->value = value;
390 				return old_value;
391 			}
392 		}
393 	}
394 
395 	map->size++;
396 	if (map->size > map->threshold) {
397 		hmap_rehash(map);
398 		index = hmap_hash(map, key);
399 	}
400 
401 	entry = xmalloc(sizeof(Entry));
402 	entry->key = key;
403 	entry->value = value;
404 	entry->next = map->buckets[index];
405 	map->buckets[index] = entry;
406 
407 	return NULL;
408 }
409 
410 static void *
hmap_remove(HMap * map,const void * key)411 hmap_remove(HMap *map, const void *key)
412 {
413 	Entry *entry;
414 	Entry *last = NULL;
415 
416 	if (key == NULL) {
417 		for (entry = map->buckets[0]; entry != NULL; entry = entry->next) {
418 			if (entry->key == NULL) {
419 				void *value = entry->value;
420 				if (last == NULL)
421 					map->buckets[0] = entry->next;
422 				else
423 					last->next = entry->next;
424 				map->size--;
425 				free(entry);
426 				return value;
427 			}
428 			last = entry;
429 		}
430 	} else {
431 		uint32_t index = hmap_hash(map, key);
432 		for (entry = map->buckets[index]; entry != NULL; entry = entry->next) {
433 			if (map->compare_keys(key, entry->key) == 0) {
434 				void *value = entry->value;
435 				if (last == NULL)
436 					map->buckets[index] = entry->next;
437 				else
438 					last->next = entry->next;
439 				map->size--;
440 				free(entry);
441 				return value;
442 			}
443 			last = entry;
444 		}
445 	}
446 
447 	return NULL;
448 }
449 
450 typedef struct _HMapIterator HMapIterator;
451 
452 struct _HMapIterator {
453 	Iterator iterator;
454 	HMap *map;
455 	uint32_t index;
456 	Entry *entry;
457 	Entry *previous_entry;
458 };
459 
460 static bool hmap_iterator_has_next(Iterator *it);
461 static void *hmap_iterator_next(Iterator *it);
462 static void hmap_iterator_remove(Iterator *it);
463 static void hmap_iterator_restart(Iterator *iterator);
464 
465 static IteratorClass hmap_iterator_class = {
466 	hmap_iterator_has_next,
467 	hmap_iterator_next,
468 	hmap_iterator_remove,
469 	NULL,
470 	hmap_iterator_restart,
471 	NULL,
472 	NULL,
473 };
474 
475 static bool
hmap_iterator_has_next(Iterator * it)476 hmap_iterator_has_next(Iterator *it)
477 {
478 	return ((HMapIterator *) it)->entry != NULL;
479 }
480 
481 static void *
hmap_iterator_next(Iterator * iterator)482 hmap_iterator_next(Iterator *iterator)
483 {
484 	HMapIterator *it = (HMapIterator *) iterator;
485 	HMap *map = it->map;
486 	void *data;
487 
488 	if (it->entry == NULL)
489 		return NULL;
490 
491 	data = it->entry->value;
492 	it->previous_entry = it->entry;
493 
494 	it->entry = it->entry->next;
495 	if (it->entry == NULL) {
496 		uint32_t i = it->index + 1;
497 		for (; i < map->buckets_length && map->buckets[i] == NULL; i++);
498 		it->index = i;
499 		it->entry = (i < map->buckets_length ? map->buckets[i] : NULL);
500 	}
501 
502 	return data;
503 }
504 
505 static void
hmap_iterator_remove(Iterator * iterator)506 hmap_iterator_remove(Iterator *iterator)
507 {
508 	HMapIterator *it = (HMapIterator *) iterator;
509 	if (it->previous_entry != NULL) {
510 		hmap_remove(it->map, it->previous_entry->key);
511 		it->previous_entry = NULL;
512 	}
513 }
514 
515 static void
hmap_iterator_restart(Iterator * iterator)516 hmap_iterator_restart(Iterator *iterator)
517 {
518 	HMapIterator *it = (HMapIterator *) iterator;
519 	uint32_t i;
520 
521 	for (i = 0; i < it->map->buckets_length && it->map->buckets[i] == NULL; i++);
522 	it->index = i;
523 	it->entry = (i < it->map->buckets_length ? it->map->buckets[i] : NULL);
524 	it->previous_entry = NULL;
525 }
526 
527 Iterator *
hmap_value_iterator(HMap * map)528 hmap_value_iterator(HMap *map)
529 {
530 	HMapIterator *it = xmalloc(sizeof(HMapIterator));
531 	it->iterator.class = &hmap_iterator_class;
532 	it->map = map;
533 	hmap_iterator_restart(&it->iterator);
534 	return &it->iterator;
535 }
536 
537 /* Main Windows BMP data structures */
538 
539 typedef struct {
540     uint8_t width;
541     uint8_t height;
542     uint8_t color_count;
543     uint8_t reserved;
544 } Win32IconResDir;
545 
546 typedef struct {
547     uint16_t width;
548     uint16_t height;
549 } Win32CursorDir;
550 
551 typedef struct {
552     union {
553 		Win32IconResDir icon;
554 		Win32CursorDir cursor;
555     } res_info;
556     uint16_t plane_count;
557     uint16_t bpp;
558     uint32_t bytes_in_res;
559     uint16_t res_id;
560 } Win32CursorIconDirEntry;
561 
562 typedef struct {
563     uint16_t reserved;
564     uint16_t type;
565     uint16_t count;
566     Win32CursorIconDirEntry entries[0] PACKED;
567 } Win32CursorIconDir;
568 
569 typedef struct {
570     uint8_t width;
571     uint8_t height;
572     uint8_t color_count;
573     uint8_t reserved;
574     uint16_t hotspot_x;		/* sometimes planes... */
575     uint16_t hotspot_y;		/* sometimes bpp... */
576     uint32_t dib_size;
577     uint32_t dib_offset;
578 } Win32CursorIconFileDirEntry;
579 
580 typedef struct {
581     uint16_t reserved;
582     uint16_t type;
583     uint16_t count;
584     Win32CursorIconFileDirEntry entries[0] PACKED;
585 } Win32CursorIconFileDir;
586 
587 typedef struct {
588     uint32_t size;
589     int32_t width;
590     int32_t height;
591     uint16_t planes;
592     uint16_t bpp;
593     uint32_t compression;
594     uint32_t size_image;
595     int32_t x_res;
596     int32_t y_res;
597     uint32_t clr_used;
598     uint32_t clr_important;
599 } Win32BitmapInfoHeader;
600 
601 typedef struct {
602     uint8_t blue;
603     uint8_t green;
604     uint8_t red;
605     uint8_t reserved;
606 } Win32RGBQuad;
607 
608 #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
609 #define IMAGE_SIZEOF_SHORT_NAME 8
610 
611 #define	IMAGE_RESOURCE_NAME_IS_STRING		0x80000000
612 #define	IMAGE_RESOURCE_DATA_IS_DIRECTORY	0x80000000
613 
614 #define PE_HEADER(module) \
615     ((Win32ImageNTHeaders*)((uint8_t *)(module) + \
616     	(((DOSImageHeader*)(module))->lfanew)))
617 
618 #define PE_SECTIONS(module) \
619     ((Win32ImageSectionHeader *)((uint8_t *) &PE_HEADER(module)->optional_header + \
620                            PE_HEADER(module)->file_header.size_of_optional_header))
621 
622 #define IMAGE_DOS_SIGNATURE    0x5A4D     /* MZ */
623 #define IMAGE_OS2_SIGNATURE    0x454E     /* NE */
624 #define IMAGE_OS2_SIGNATURE_LE 0x454C     /* LE */
625 #define IMAGE_OS2_SIGNATURE_LX 0x584C     /* LX */
626 #define IMAGE_VXD_SIGNATURE    0x454C     /* LE */
627 #define IMAGE_NT_SIGNATURE     0x00004550 /* PE00 */
628 
629 #define IMAGE_SCN_CNT_CODE			0x00000020
630 #define IMAGE_SCN_CNT_INITIALIZED_DATA		0x00000040
631 #define IMAGE_SCN_CNT_UNINITIALIZED_DATA	0x00000080
632 
633 #define	IMAGE_DIRECTORY_ENTRY_EXPORT		0
634 #define	IMAGE_DIRECTORY_ENTRY_IMPORT		1
635 #define	IMAGE_DIRECTORY_ENTRY_RESOURCE		2
636 #define	IMAGE_DIRECTORY_ENTRY_EXCEPTION		3
637 #define	IMAGE_DIRECTORY_ENTRY_SECURITY		4
638 #define	IMAGE_DIRECTORY_ENTRY_BASERELOC		5
639 #define	IMAGE_DIRECTORY_ENTRY_DEBUG		6
640 #define	IMAGE_DIRECTORY_ENTRY_COPYRIGHT		7
641 #define	IMAGE_DIRECTORY_ENTRY_GLOBALPTR		8   /* (MIPS GP) */
642 #define	IMAGE_DIRECTORY_ENTRY_TLS		9
643 #define	IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG	10
644 #define	IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT	11
645 #define	IMAGE_DIRECTORY_ENTRY_IAT		12  /* Import Address Table */
646 #define	IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT	13
647 #define	IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR	14
648 
649 #define RT_CURSOR        1
650 #define RT_BITMAP        2
651 #define RT_ICON          3
652 #define RT_MENU          4
653 #define RT_DIALOG        5
654 #define RT_STRING        6
655 #define RT_FONTDIR       7
656 #define RT_FONT          8
657 #define RT_ACCELERATOR   9
658 #define RT_RCDATA        10
659 #define RT_MESSAGELIST   11
660 #define RT_GROUP_CURSOR  12
661 #define RT_GROUP_ICON    14
662 
663 typedef struct {
664     union {
665     	struct {
666     	    #if BITFIELDS_BIGENDIAN
667     	    unsigned name_is_string:1;
668     	    unsigned name_offset:31;
669     	    #else
670     	    unsigned name_offset:31;
671     	    unsigned name_is_string:1;
672     	    #endif
673     	} s1;
674     	uint32_t name;
675     	struct {
676     	    #if WORDS_BIGENDIAN
677     	    uint16_t __pad;
678     	    uint16_t id;
679     	    #else
680     	    uint16_t id;
681     	    uint16_t __pad;
682     	    #endif
683     	} s2;
684     } u1;
685     union {
686     	uint32_t offset_to_data;
687     	struct {
688     	    #if BITFIELDS_BIGENDIAN
689     	    unsigned data_is_directory:1;
690     	    unsigned offset_to_directory:31;
691     	    #else
692     	    unsigned offset_to_directory:31;
693     	    unsigned data_is_directory:1;
694     	    #endif
695     	} s;
696     } u2;
697 } Win32ImageResourceDirectoryEntry;
698 
699 typedef struct {
700     uint16_t type_id;
701     uint16_t count;
702     uint32_t reserved;
703 } Win16NETypeInfo;
704 
705 typedef struct {
706     uint16_t offset;
707     uint16_t length;
708     uint16_t flags;
709     uint16_t id;
710     uint16_t handle;
711     uint16_t usage;
712 } Win16NENameInfo;
713 
714 typedef struct {
715     uint16_t magic;
716     uint8_t ver;
717     uint8_t rev;
718     uint16_t enttab;
719     uint16_t cbenttab;
720     int32_t crc;
721     uint16_t flags;
722     uint16_t autodata;
723     uint16_t heap;
724     uint16_t stack;
725     uint32_t csip;
726     uint32_t sssp;
727     uint16_t cseg;
728     uint16_t cmod;
729     uint16_t cbnrestab;
730     uint16_t segtab;
731     uint16_t rsrctab;
732     uint16_t restab;
733     uint16_t modtab;
734     uint16_t imptab;
735     uint32_t nrestab;
736     uint16_t cmovent;
737     uint16_t align;
738     uint16_t cres;
739     uint8_t exetyp;
740     uint8_t flagsothers;
741     uint16_t fastload_offset;
742     uint16_t fastload_length;
743     uint16_t swaparea;
744     uint16_t expver;
745 } OS2ImageHeader;
746 
747 typedef struct {
748     uint16_t magic;
749     uint16_t cblp;
750     uint16_t cp;
751     uint16_t crlc;
752     uint16_t cparhdr;
753     uint16_t minalloc;
754     uint16_t maxalloc;
755     uint16_t ss;
756     uint16_t sp;
757     uint16_t csum;
758     uint16_t ip;
759     uint16_t cs;
760     uint16_t lfarlc;
761     uint16_t ovno;
762     uint16_t res[4];
763     uint16_t oemid;
764     uint16_t oeminfo;
765     uint16_t res2[10];
766     uint32_t lfanew;
767 } DOSImageHeader;
768 
769 typedef struct {
770     uint16_t machine;
771     uint16_t number_of_sections;
772     uint32_t time_date_stamp;
773     uint32_t pointer_to_symbol_table;
774     uint32_t number_of_symbols;
775     uint16_t size_of_optional_header;
776     uint16_t characteristics;
777 } Win32ImageFileHeader;
778 
779 typedef struct {
780     uint32_t virtual_address;
781     uint32_t size;
782 } Win32ImageDataDirectory;
783 
784 typedef struct {
785     uint16_t magic;
786     uint8_t major_linker_version;
787     uint8_t minor_linker_version;
788     uint32_t size_of_code;
789     uint32_t size_of_initialized_data;
790     uint32_t size_of_uninitialized_data;
791     uint32_t address_of_entry_point;
792     uint32_t base_of_code;
793     uint32_t base_of_data;
794     uint32_t image_base;
795     uint32_t section_alignment;
796     uint32_t file_alignment;
797     uint16_t  major_operating_system_version;
798     uint16_t  minor_operating_system_version;
799     uint16_t  major_image_version;
800     uint16_t  minor_image_version;
801     uint16_t  major_subsystem_version;
802     uint16_t  minor_subsystem_version;
803     uint32_t win32_version_value;
804     uint32_t size_of_image;
805     uint32_t size_of_headers;
806     uint32_t checksum;
807     uint16_t subsystem;
808     uint16_t dll_characteristics;
809     uint32_t size_of_stack_reserve;
810     uint32_t size_of_stack_commit;
811     uint32_t size_of_heap_reserve;
812     uint32_t size_of_heap_commit;
813     uint32_t loader_flags;
814     uint32_t number_of_rva_and_sizes;
815     Win32ImageDataDirectory data_directory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
816 } Win32ImageOptionalHeader;
817 
818 typedef struct {
819     uint32_t signature;
820     Win32ImageFileHeader file_header;
821     Win32ImageOptionalHeader optional_header;
822 } Win32ImageNTHeaders;
823 
824 typedef struct  {
825     uint8_t name[IMAGE_SIZEOF_SHORT_NAME];
826     union {
827 	uint32_t physical_address;
828 	uint32_t virtual_size;
829     } misc;
830     uint32_t virtual_address;
831     uint32_t size_of_raw_data;
832     uint32_t pointer_to_raw_data;
833     uint32_t pointer_to_relocations;
834     uint32_t pointer_to_linenumbers;
835     uint16_t number_of_relocations;
836     uint16_t number_of_linenumbers;
837     uint32_t characteristics;
838 } Win32ImageSectionHeader;
839 
840 typedef struct {
841     uint32_t offset_to_data;
842     uint32_t size;
843     uint32_t code_page;
844     uint32_t resource_handle;
845 } Win32ImageResourceDataEntry;
846 
847 typedef struct {
848     uint32_t characteristics;
849     uint32_t time_date_stamp;
850     uint16_t major_version;
851     uint16_t minor_version;
852     uint16_t number_of_named_entries;
853     uint16_t number_of_id_entries;
854 } Win32ImageResourceDirectory;
855 
856 #if WORDS_BIGENDIAN
857 
858 static void fix_win32_cursor_icon_file_dir_endian(Win32CursorIconFileDir *obj);
859 static void fix_win32_bitmap_info_header_endian(Win32BitmapInfoHeader *obj);
860 static void fix_win32_cursor_icon_file_dir_entry_endian(Win32CursorIconFileDirEntry *obj);
861 static void fix_win32_image_data_directory(Win32ImageDataDirectory *obj);
862 static void fix_os2_image_header_endian(OS2ImageHeader *obj);
863 static void fix_win32_image_section_header(Win32ImageSectionHeader *obj);
864 static void fix_win32_image_header_endian(Win32ImageNTHeaders *obj);
865 
866 #else
867 
868 #define fix_win32_bitmap_info_header_endian(x)
869 #define fix_win32_cursor_icon_file_dir_endian(x)
870 #define fix_win32_cursor_icon_file_dir_entry_endian(x)
871 #define fix_win32_image_data_directory(x)
872 #define fix_os2_image_header_endian(x)
873 #define fix_win32_image_section_header(x)
874 #define fix_win32_image_header_endian(x)
875 
876 #endif /* WORDS_BIGENDIAN */
877 
878 #define ROW_BYTES(bits) ((((bits) + 31) >> 5) << 2)
879 
880 typedef struct _Palette {
881 	HMap *map;
882 	Iterator *it;
883 } Palette;
884 
885 typedef struct {
886 	uint8_t red;
887 	uint8_t green;
888 	uint8_t blue;
889 	uint32_t index;
890 } PaletteColor;
891 
892 static uint32_t
color_hash(PaletteColor * color)893 color_hash(PaletteColor *color)
894 {
895 	return (color->red << 16) | (color->green << 8) | color->blue;
896 }
897 
898 static int32_t
color_compare(PaletteColor * c1,PaletteColor * c2)899 color_compare(PaletteColor *c1, PaletteColor *c2)
900 {
901 	if (c1->red != c2->red)
902 		return c1->red - c2->red;
903 	if (c1->green != c2->green)
904 		return c1->green - c2->green;
905 	if (c1->blue != c2->blue)
906 		return c1->blue - c2->blue;
907 	return 0;
908 }
909 
910 static Palette *
palette_new(void)911 palette_new(void)
912 {
913 	Palette *palette = xmalloc(sizeof(Palette));
914 	palette->map = hmap_new();
915 	palette->it = NULL;
916 	hmap_set_hash_function(palette->map, (HashFunc) color_hash);
917 	hmap_set_compare_function(palette->map, (CompareFunc) color_compare);
918 	return palette;
919 }
920 
921 static void
palette_free(Palette * palette)922 palette_free(Palette *palette)
923 {
924 	if (palette->it != NULL)
925 		iterator_free(palette->it);
926 	hmap_iterate_values(palette->map, free);
927 	hmap_free(palette->map);
928 	free(palette);
929 }
930 
931 static void
palette_add(Palette * palette,uint8_t r,uint8_t g,uint8_t b)932 palette_add(Palette *palette, uint8_t r, uint8_t g, uint8_t b)
933 {
934 	PaletteColor color = { r, g, b, 0 };
935 
936 	if (!hmap_contains_key(palette->map, &color)) {
937 		PaletteColor *new_color = xmalloc(sizeof(PaletteColor));
938 		new_color->red = r;
939 		new_color->green = g;
940 		new_color->blue = b;
941 		new_color->index = 0;
942 		hmap_put(palette->map, new_color, new_color);
943 	}
944 }
945 
946 static bool
palette_next(Palette * palette,uint8_t * r,uint8_t * g,uint8_t * b)947 palette_next(Palette *palette, uint8_t *r, uint8_t *g, uint8_t *b)
948 {
949 	if (palette->it == NULL)
950 		palette->it = hmap_value_iterator(palette->map);
951 	if (iterator_has_next(palette->it)) {
952 		PaletteColor *color = iterator_next(palette->it);
953 		*r = color->red;
954 		*g = color->green;
955 		*b = color->blue;
956 		return true;
957 	}
958 	iterator_free(palette->it);
959 	palette->it = NULL;
960 	return false;
961 }
962 
963 static void
palette_assign_indices(Palette * palette)964 palette_assign_indices(Palette *palette)
965 {
966 	Iterator *it = hmap_value_iterator(palette->map);
967 	uint32_t c;
968 
969 	for (c = 0; iterator_has_next(it); c++) {
970 		PaletteColor *color = iterator_next(it);
971 		color->index = c;
972 	}
973 }
974 
975 static uint32_t
palette_lookup(Palette * palette,uint8_t r,uint8_t g,uint8_t b)976 palette_lookup(Palette *palette, uint8_t r, uint8_t g, uint8_t b)
977 {
978 	PaletteColor color = { r, g, b, 0 };
979 	PaletteColor *real_color = hmap_get(palette->map, &color);
980 	return (real_color != NULL ? real_color->index : -1);
981 }
982 
983 static uint32_t
palette_count(Palette * palette)984 palette_count(Palette *palette)
985 {
986 	return hmap_size(palette->map);
987 }
988 
989 static void
simple_setvec(uint8_t * data,uint32_t ofs,uint8_t size,uint32_t value)990 simple_setvec(uint8_t *data, uint32_t ofs, uint8_t size, uint32_t value)
991 {
992 	switch (size) {
993 	case 1:
994 		data[ofs/8] |= (value & 1) << (7 - ofs%8);
995 		break;
996 	case 2:
997 		data[ofs/4] |= (value & 3) << ((3 - ofs%4) << 1);
998 		break;
999 	case 4:
1000 		data[ofs/2] |= (value & 15) << ((1 - ofs%2) << 2);
1001 		break;
1002 	case 8:
1003 		data[ofs] = value;
1004 		break;
1005 	case 16:
1006 		data[2*ofs] = value;
1007 		data[2*ofs+1] = (value >> 8);
1008 		break;
1009 	case 24:
1010 		data[3*ofs] = value;
1011 		data[3*ofs+1] = (value >> 8);
1012 		data[3*ofs+2] = (value >> 16);
1013 		break;
1014 	case 32:
1015 		data[4*ofs] = value;
1016 		data[4*ofs+1] = (value >> 8);
1017 		data[4*ofs+2] = (value >> 16);
1018 		data[4*ofs+3] = (value >> 24);
1019 		break;
1020 	}
1021 }
1022 
1023 static uint32_t
simple_vec(uint8_t * data,uint32_t ofs,uint8_t size)1024 simple_vec(uint8_t *data, uint32_t ofs, uint8_t size)
1025 {
1026 	switch (size) {
1027 	case 1:
1028 		return (data[ofs/8] >> (7 - ofs%8)) & 1;
1029 	case 2:
1030 		return (data[ofs/4] >> ((3 - ofs%4) << 1)) & 3;
1031 	case 4:
1032 		return (data[ofs/2] >> ((1 - ofs%2) << 2)) & 15;
1033 	case 8:
1034 		return data[ofs];
1035 	case 16:
1036 		return data[2*ofs] | data[2*ofs+1] << 8;
1037 	case 24:
1038 		return data[3*ofs] | data[3*ofs+1] << 8 | data[3*ofs+2] << 16;
1039 	case 32:
1040 		return data[4*ofs] | data[4*ofs+1] << 8 | data[4*ofs+2] << 16 | data[4*ofs+3] << 24;
1041 	}
1042 
1043 	return 0;
1044 }
1045 
1046 static bool
xfread(void * ptr,size_t size,FILE * stream)1047 xfread(void *ptr, size_t size, FILE *stream)
1048 {
1049 	if (fread(ptr, size, 1, stream) < 1) {
1050 		if (ferror(stream))
1051 			warn_errno("cannot read file");
1052 		else
1053 			warn("premature end");
1054 		return false;
1055 	}
1056 	return true;
1057 }
1058 
1059 typedef struct {
1060 	uint32_t capacity;
1061 	uint32_t count;
1062 	char value[0];
1063 } StringBuffer;
1064 
1065 static inline StringBuffer *
get_string_buffer(char ** buf)1066 get_string_buffer(char **buf)
1067 {
1068 	return (StringBuffer *) (*buf - sizeof(StringBuffer));
1069 }
1070 
1071 static inline char *
new_strbuf(uint32_t capacity,uint32_t count)1072 new_strbuf(uint32_t capacity, uint32_t count)
1073 {
1074 	StringBuffer *strbuf;
1075 	strbuf = xmalloc(sizeof(StringBuffer) + sizeof(char)*capacity);
1076 	strbuf->capacity = capacity;
1077 	strbuf->count = count;
1078 	return strbuf->value;
1079 }
1080 
1081 static inline void
ensure_capacity(char ** buf,StringBuffer ** strbuf,uint32_t min_capacity)1082 ensure_capacity(char **buf, StringBuffer **strbuf, uint32_t min_capacity)
1083 {
1084 	if (min_capacity > (*strbuf)->capacity) {
1085 		uint32_t max = (min_capacity > (*strbuf)->count ? (*strbuf)->count*2+2 : (*strbuf)->count);
1086 		min_capacity = MAX(min_capacity, max);
1087 
1088 		*strbuf = xrealloc(*strbuf, sizeof(StringBuffer) + sizeof(char) * min_capacity);
1089 		(*strbuf)->capacity = min_capacity;
1090 		*buf = (*strbuf)->value;
1091 	}
1092 }
1093 
1094 /**
1095  * Read and discard some number of bytes from a stream.
1096  */
1097 static int
fskip(FILE * file,uint32_t bytes)1098 fskip(FILE *file, uint32_t bytes)
1099 {
1100 	for (; bytes > 0; bytes--) {
1101 		if (fgetc(file) == EOF)
1102 			return -1;
1103 	}
1104 	return 0;
1105 }
1106 
1107 /**
1108  * Write a number of bytes of the same value to a stream.
1109  */
1110 static int
fpad(FILE * file,char byte,uint32_t bytes)1111 fpad(FILE *file, char byte, uint32_t bytes)
1112 {
1113 	for (; bytes > 0; bytes--) {
1114 		if (fwrite(&byte, 1, 1, file) != 1)
1115 			return -1;
1116 	}
1117 	return 0;
1118 }
1119 
1120 static bool
create_icon(int filec,char ** filev,char * outname,bool icon_mode,int32_t hotspot_x,int32_t hotspot_y,int32_t alpha_threshold,int32_t bpp)1121 create_icon(int filec, char **filev, char *outname, bool icon_mode, int32_t hotspot_x, int32_t hotspot_y, int32_t alpha_threshold, int32_t bpp)
1122 {
1123 	struct {
1124 		FILE *in;
1125 		png_structp png_ptr;
1126 		png_infop info_ptr;
1127 		uint32_t bpp;
1128 		uint32_t palette_count;
1129 		uint32_t image_size;
1130 		uint32_t mask_size;
1131 		uint32_t width;
1132 		uint32_t height;
1133 		uint8_t *image_data;
1134 		uint8_t **row_datas;
1135 		Palette *palette;
1136 	} *img;
1137 
1138 	Win32CursorIconFileDir dir;
1139 	FILE *out = NULL;
1140 	uint32_t c, d, x;
1141 	uint32_t dib_start;
1142 	png_byte ct;
1143 
1144 	img = xcalloc(filec * sizeof(*img));
1145 
1146 	for (c = 0; c < filec; c++) {
1147 		char header[8];
1148 		uint32_t row_bytes;
1149 		uint8_t transparency[256];
1150 		uint16_t transparency_count;
1151 		bool need_transparency;
1152 
1153 		img[c].in = fopen(filev[c], "r");
1154     	if (img[c].in == NULL) {
1155 	    warn_errno("(#%d) cannot open file", c);
1156 			goto cleanup;
1157 		}
1158     	if (!xfread(header, 8, img[c].in))
1159 			goto cleanup;
1160     	if (png_sig_cmp((png_bytep)header, 0, 8)) {
1161 
1162 	    warn("(#%d) not a png file", c);
1163 			goto cleanup;
1164 		}
1165 
1166 		img[c].png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL /*user_error_fn, user_warning_fn*/);
1167 		if (img[c].png_ptr == NULL) {
1168 			warn("cannot initialize PNG library");
1169 			goto cleanup;
1170 		}
1171 		img[c].info_ptr = png_create_info_struct(img[c].png_ptr);
1172 		if (img[c].info_ptr == NULL) {
1173 			warn("cannot create PNG info structure - out of memory");
1174 			goto cleanup;
1175 		}
1176 
1177 		png_init_io(img[c].png_ptr, img[c].in);
1178 		png_set_sig_bytes(img[c].png_ptr, 8);
1179 		png_set_strip_16(img[c].png_ptr);
1180 		png_set_expand(img[c].png_ptr);
1181 		png_set_gray_to_rgb(img[c].png_ptr);
1182 		png_set_interlace_handling(img[c].png_ptr);
1183 		png_set_filler(img[c].png_ptr, 0xFF, PNG_FILLER_AFTER);
1184 		png_read_info(img[c].png_ptr, img[c].info_ptr);
1185 		png_read_update_info(img[c].png_ptr, img[c].info_ptr);
1186 
1187 		img[c].width = png_get_image_width(img[c].png_ptr, img[c].info_ptr);
1188 		/*if (img[c].width > 255) {
1189 			warn("image too wide (max 255, was %d pixels)", img[c].width);
1190 			goto cleanup;
1191 		}*/
1192 		img[c].height = png_get_image_height(img[c].png_ptr, img[c].info_ptr);
1193 		/*if (img[c].height > 255) {
1194 			warn("image too tall (max 255, was %d pixels)", img[c].height);
1195 			goto cleanup;
1196 		}*/
1197 
1198 		row_bytes = png_get_rowbytes(img[c].png_ptr, img[c].info_ptr);
1199 		img[c].row_datas = xmalloc(img[c].height * sizeof(png_bytep *));
1200 		img[c].row_datas[0] = xmalloc(img[c].height * row_bytes);
1201 		for (d = 1; d < img[c].height; d++)
1202 			img[c].row_datas[d] = img[c].row_datas[d-1] + row_bytes;
1203 		png_read_rows(img[c].png_ptr, img[c].row_datas, NULL, img[c].height);
1204 
1205 		ct = png_get_color_type(img[c].png_ptr, img[c].info_ptr);
1206 		img[c].palette = palette_new();
1207 
1208 
1209 		/* Count number of necessary colors in palette and number of transparencies */
1210 		memset(transparency, 0, 256);
1211 		for (d = 0; d < img[c].height; d++) {
1212 			png_bytep row = img[c].row_datas[d];
1213 			for (x = 0; x < img[c].width; x++) {
1214 				if (palette_count(img[c].palette) <= (1 << 8))
1215 				    palette_add(img[c].palette, row[4*x+0], row[4*x+1], row[4*x+2]);
1216 				if (ct & PNG_COLOR_MASK_ALPHA)
1217 				    transparency[row[4*x+3]] = 1;
1218 			}
1219 		}
1220 		transparency_count = 0;
1221 		for (d = 0; d < 256; d++)
1222 		    transparency_count += transparency[d];
1223 
1224 		/* If there are more than two steps of transparency, or if the
1225 		 * two steps are NOT either entirely off (0) and entirely on (255),
1226 		 * then we will lose transparency information if bpp is not 32.
1227 		 */
1228 		need_transparency =
1229 		    transparency_count > 2
1230 		    ||
1231 		    (transparency_count == 2 && (transparency[0] == 0 || transparency[255] == 0));
1232 
1233 		/* Can we keep all colors in a palette? */
1234 		if (need_transparency) {
1235 			if (bpp != -1) {
1236 			    if (bpp != 32)
1237 				warn("decreasing bit depth will discard variable transparency", transparency_count);
1238 			    /* Why 24 and not bpp? Otherwise we might decrease below what's possible
1239 			           * due to number of colors in image. The real decrease happens below. */
1240 			    img[c].bpp = 24;
1241 			} else {
1242 			    img[c].bpp = 32;
1243 			}
1244 			img[c].palette_count = 0;
1245 		}
1246 		else if (palette_count(img[c].palette) <= 256) {
1247 			for (d = 1; palette_count(img[c].palette) > 1 << d; d <<= 1);
1248 			if (d == 2)	/* four colors (two bits) are not supported */
1249 				d = 4;
1250 			img[c].bpp = d;
1251 			img[c].palette_count = 1 << d;
1252 		}
1253 		else {
1254 			img[c].bpp = 24;
1255 			img[c].palette_count = 0;
1256 		}
1257 
1258 		/* Does the user want to change number of bits per pixel? */
1259 		if (bpp != -1) {
1260 			if (img[c].bpp == bpp) {
1261 				/* No operation */
1262 			} else if (img[c].bpp < bpp) {
1263 				img[c].bpp = bpp;
1264 				img[c].palette_count = (bpp > 16 ? 0 : 1 << bpp);
1265 			} else {
1266 				warn("cannot decrease bit depth from %d to %d, bit depth not changed", img[c].bpp, bpp);
1267 			}
1268 		}
1269 
1270 		img[c].image_size = img[c].height * ROW_BYTES(img[c].width * img[c].bpp);
1271 		img[c].mask_size = img[c].height * ROW_BYTES(img[c].width);
1272 
1273 	}
1274 
1275         out = fopen(outname, "w");
1276 	if (out == NULL) {
1277 		warn_errno("cannot create file");
1278 		goto cleanup;
1279 	}
1280 
1281 	dir.reserved = 0;
1282 	dir.type = (icon_mode ? 1 : 2);
1283 	dir.count = filec;
1284 	fix_win32_cursor_icon_file_dir_endian(&dir);
1285 	if (fwrite(&dir, sizeof(Win32CursorIconFileDir), 1, out) != 1) {
1286 		warn_errno("cannot write to file");
1287 		goto cleanup;
1288 	}
1289 
1290 	dib_start = sizeof(Win32CursorIconFileDir) + filec * sizeof(Win32CursorIconFileDirEntry);
1291 	for (c = 0; c < filec; c++) {
1292 		Win32CursorIconFileDirEntry entry;
1293 
1294 		entry.width = MIN(255, img[c].width);
1295 		entry.height = MIN(255, img[c].height);
1296 		entry.reserved = 0;
1297 		if (icon_mode) {
1298 			entry.hotspot_x = 0;	 /* some mistake this for planes (XXX) */
1299 			entry.hotspot_y = 0;	 /* some mistake this for bpp (XXX) */
1300 		} else {
1301 			entry.hotspot_x = hotspot_x;	 /* some mistake this for planes (XXX) */
1302 			entry.hotspot_y = hotspot_y;	 /* some mistake this for bpp (XXX) */
1303 		}
1304 		entry.dib_offset = dib_start;
1305 		entry.color_count = (img[c].bpp >= 8 ? 0 : 1 << img[c].bpp);
1306 		entry.dib_size = img[c].palette_count * sizeof(Win32RGBQuad)
1307 				+ sizeof(Win32BitmapInfoHeader)
1308 				+ img[c].image_size
1309 				+ img[c].mask_size;
1310 
1311 		dib_start += entry.dib_size;
1312 
1313 		fix_win32_cursor_icon_file_dir_entry_endian(&entry);
1314 		if (fwrite(&entry, sizeof(Win32CursorIconFileDirEntry), 1, out) != 1) {
1315 			warn_errno("cannot write to file");
1316 			goto cleanup;
1317 		}
1318 
1319 	}
1320 
1321 	for (c = 0; c < filec; c++) {
1322 		Win32BitmapInfoHeader bitmap;
1323 
1324 		bitmap.size = sizeof(Win32BitmapInfoHeader);
1325 		bitmap.width = png_get_image_width(img[c].png_ptr, img[c].info_ptr);
1326 		bitmap.height = png_get_image_height(img[c].png_ptr, img[c].info_ptr) * 2;
1327 		bitmap.planes = 1;							// appears to be 1 always (XXX)
1328 		bitmap.bpp = img[c].bpp;
1329 		bitmap.compression = 0;
1330 		bitmap.x_res = 0;				// should be 0 always
1331 		bitmap.y_res = 0;				// should be 0 always
1332 		bitmap.clr_important = 0;					// should be 0 always
1333 		bitmap.clr_used = img[c].palette_count;
1334 		bitmap.size_image = img[c].image_size;		// appears to be ok here (may be image_size+mask_size or 0, XXX)
1335 
1336 		fix_win32_bitmap_info_header_endian(&bitmap);
1337 		if (fwrite(&bitmap, sizeof(Win32BitmapInfoHeader), 1, out) != 1) {
1338 			warn_errno("cannot write to file");
1339 			goto cleanup;
1340 		}
1341 
1342 		if (img[c].bpp <= 16) {
1343 			Win32RGBQuad color;
1344 
1345 			palette_assign_indices(img[c].palette);
1346 			color.reserved = 0;
1347 			while (palette_next(img[c].palette, &color.red, &color.green, &color.blue))
1348 				fwrite(&color, sizeof(Win32RGBQuad), 1, out);
1349 
1350 			/* Pad with empty colors. The reason we do this is because we
1351 			 * specify bitmap.clr_used as a base of 2. The latter is probably
1352 			 * not necessary according to the original specs, but many
1353 			 * programs that read icons assume it. Especially gdk-pixbuf.
1354 			 */
1355 		    	memclear(&color, sizeof(Win32RGBQuad));
1356 			for (d = palette_count(img[c].palette); d < 1 << img[c].bpp; d++)
1357 				fwrite(&color, sizeof(Win32RGBQuad), 1, out);
1358 		}
1359 
1360 		img[c].image_data = xcalloc(img[c].image_size);
1361 
1362 		for (d = 0; d < img[c].height; d++) {
1363 			png_bytep row = img[c].row_datas[img[c].height - d - 1];
1364 			if (img[c].bpp < 24) {
1365 				uint32_t imod = d * (img[c].image_size/img[c].height) * 8 / img[c].bpp;
1366 				for (x = 0; x < img[c].width; x++) {
1367 					uint32_t color;
1368 					color = palette_lookup(img[c].palette, row[4*x+0], row[4*x+1], row[4*x+2]);
1369 					simple_setvec(img[c].image_data, x+imod, img[c].bpp, color);
1370 				}
1371 			} else if (img[c].bpp == 24) {
1372 				uint32_t irow = d * (img[c].image_size/img[c].height);
1373 				for (x = 0; x < img[c].width; x++) {
1374 					img[c].image_data[3*x+0 + irow] = row[4*x+2];
1375 					img[c].image_data[3*x+1 + irow] = row[4*x+1];
1376 					img[c].image_data[3*x+2 + irow] = row[4*x+0];
1377 				}
1378 			} else if (img[c].bpp == 32) {
1379 				uint32_t irow = d * (img[c].image_size/img[c].height);
1380 				for (x = 0; x < img[c].width; x++) {
1381 					img[c].image_data[4*x+0 + irow] = row[4*x+2];
1382 					img[c].image_data[4*x+1 + irow] = row[4*x+1];
1383 					img[c].image_data[4*x+2 + irow] = row[4*x+0];
1384 					img[c].image_data[4*x+3 + irow] = row[4*x+3];
1385 				}
1386 			}
1387 		}
1388 
1389 		if (fwrite(img[c].image_data, img[c].image_size, 1, out) != 1) {
1390 			warn_errno("cannot write to file");
1391 			goto cleanup;
1392 		}
1393 
1394 		for (d = 0; d < img[c].height; d++) {
1395 			png_bytep row = img[c].row_datas[img[c].height - d - 1];
1396 
1397 			for (x = 0; x < img[c].width; x += 8) {
1398 				uint8_t mask = 0;
1399 				mask |= (row[4*(x+0)+3] <= alpha_threshold ? 1 << 7 : 0);
1400 				mask |= (row[4*(x+1)+3] <= alpha_threshold ? 1 << 6 : 0);
1401 				mask |= (row[4*(x+2)+3] <= alpha_threshold ? 1 << 5 : 0);
1402 				mask |= (row[4*(x+3)+3] <= alpha_threshold ? 1 << 4 : 0);
1403 				mask |= (row[4*(x+4)+3] <= alpha_threshold ? 1 << 3 : 0);
1404 				mask |= (row[4*(x+5)+3] <= alpha_threshold ? 1 << 2 : 0);
1405 				mask |= (row[4*(x+6)+3] <= alpha_threshold ? 1 << 1 : 0);
1406 				mask |= (row[4*(x+7)+3] <= alpha_threshold ? 1 << 0 : 0);
1407 				fputc(mask, out);
1408 			}
1409 
1410 			fpad(out, 0, img[c].mask_size/img[c].height - x/8);
1411 		}
1412 
1413 		free(img[c].image_data);
1414 		palette_free(img[c].palette);
1415 		free(img[c].row_datas[0]);
1416 		free(img[c].row_datas);
1417 		png_read_end(img[c].png_ptr, img[c].info_ptr);
1418 		png_destroy_read_struct(&img[c].png_ptr, &img[c].info_ptr, NULL);
1419 		fclose(img[c].in);
1420 		memclear(&img[c], sizeof(*img));
1421 	}
1422 
1423 	free(img);
1424         if (out) fclose(out);
1425 	return true;
1426 
1427 cleanup:
1428 
1429 	for (c = 0; c < filec; c++) {
1430 		if (img[c].image_data != NULL)
1431 			free(img[c].image_data);
1432 		if (img[c].palette != NULL)
1433 			palette_free(img[c].palette);
1434 		if (img[c].row_datas != NULL && img[c].row_datas[0] != NULL) {
1435 			free(img[c].row_datas[0]);
1436 			free(img[c].row_datas);
1437 		}
1438 		if (img[c].png_ptr != NULL)
1439 			png_destroy_read_struct(&img[c].png_ptr, &img[c].info_ptr, NULL);
1440 		if (img[c].in != NULL)
1441 			fclose(img[c].in);
1442 	}
1443 	free(img);
1444         if (out) fclose(out);
1445 	return false;
1446 }
1447 
1448 static int32_t image_index;
1449 static int32_t width = -1;
1450 static int32_t height = -1;
1451 static int32_t bitdepth = -1;
1452 static int32_t palettesize = -1;
1453 static int32_t hotspot_x = 0;
1454 static int32_t hotspot_y = 0;
1455 static bool hotspot_x_set = false;
1456 static bool hotspot_y_set = false;
1457 static int32_t alpha_threshold = 127;
1458 static bool icon_only = false;
1459 static bool cursor_only = false;
1460 
1461 static bool
filter(int i,int w,int h,int bd,int ps,bool icon,int hx,int hy)1462 filter(int i, int w, int h, int bd, int ps, bool icon, int hx, int hy)
1463 {
1464     if (image_index != -1 && i != image_index)
1465 	return false;
1466     if (width != -1 && w != width)
1467 	return false;
1468     if (height != -1 && h != height)
1469 	return false;
1470     if (bitdepth != -1 && bd != bitdepth)
1471 	return false;
1472     if (palettesize != -1 && ps != palettesize)
1473 	return false;
1474     if ((icon_only && !icon) || (cursor_only && icon))
1475 	return false;
1476     if (hotspot_x_set && hx != hotspot_x)
1477 	return false;
1478     if (hotspot_y_set && hy != hotspot_y)
1479 	return false;
1480     return true;
1481 }
1482 
1483 static int
extract_icons(FILE * in,Image ** out_image,bool extractmode)1484 extract_icons(FILE *in, Image **out_image, bool extractmode)
1485 {
1486 	Win32CursorIconFileDir dir;
1487 	Win32CursorIconFileDirEntry *entries = NULL;
1488 	uint32_t offset;
1489 	uint32_t c, d;
1490 	int completed;
1491 	int matched = 0;
1492         Image *out = NULL;
1493 
1494 	if (!xfread(&dir, sizeof(Win32CursorIconFileDir), in))
1495 		goto cleanup;
1496 	fix_win32_cursor_icon_file_dir_endian(&dir);
1497 
1498 	if (dir.reserved != 0) {
1499 		warn("not an icon or cursor file (reserved non-zero)");
1500 		goto cleanup;
1501 	}
1502 	if (dir.type != 1 && dir.type != 2) {
1503 		warn("not an icon or cursor file (wrong type)");
1504 		goto cleanup;
1505 	}
1506 
1507 	entries = xmalloc(dir.count * sizeof(Win32CursorIconFileDirEntry));
1508 	for (c = 0; c < dir.count; c++) {
1509 		if (!xfread(&entries[c], sizeof(Win32CursorIconFileDirEntry), in))
1510 			goto cleanup;
1511 		fix_win32_cursor_icon_file_dir_entry_endian(&entries[c]);
1512 		if (entries[c].reserved != 0)
1513 		    warn("(#%d) reserved is not zero", c+1);
1514 	}
1515 	offset = sizeof(Win32CursorIconFileDir) + dir.count * sizeof(Win32CursorIconFileDirEntry);
1516 
1517         warn("number of image entries :%d", dir.count);
1518 
1519 	for (completed = 0; completed < dir.count; ) {
1520 		uint32_t min_offset = UINT32_MAX;
1521 		int previous = completed;
1522 
1523 		for (c = 0; c < dir.count; c++) {
1524                         int number = c;
1525 			if (entries[c].dib_offset == offset) {
1526 				Win32BitmapInfoHeader bitmap;
1527 				Win32RGBQuad *palette = NULL;
1528 				uint32_t palette_count = 0;
1529 				uint32_t image_size, mask_size;
1530 				uint32_t width = 0, height = 0;
1531 				uint8_t *image_data = NULL, *mask_data = NULL;
1532 				unsigned char *row;
1533 				unsigned char *alpha;
1534 
1535 				if (!xfread(&bitmap, sizeof(Win32BitmapInfoHeader), in))
1536 					goto local_cleanup;
1537 
1538 				fix_win32_bitmap_info_header_endian(&bitmap);
1539 				if (bitmap.size < sizeof(Win32BitmapInfoHeader)) {
1540 				        warn("(#%d) bitmap header is too short", number);
1541 					goto local_cleanup;
1542 				}
1543 				if (bitmap.compression != 0) {
1544 				        warn("(#%d) compressed image found", number);
1545                                         fseek(in, offset, SEEK_SET);
1546                                         mask_size = 0;
1547                                         image_size = bitmap.size_image;
1548                                         goto direct;
1549 				}
1550 				if (bitmap.x_res != 0)
1551 					warn("(#%d) x_res field in bitmap should be zero", number);
1552 				if (bitmap.y_res != 0)
1553 					warn("(#%d) y_res field in bitmap should be zero", number);
1554 				if (bitmap.clr_important != 0)
1555 					warn("(#%d) clr_important field in bitmap should be zero", number);
1556 				if (bitmap.planes != 1)
1557 					warn("(#%d) planes field in bitmap should be one", number);
1558 				if (bitmap.size != sizeof(Win32BitmapInfoHeader)) {
1559 					uint32_t skip = bitmap.size - sizeof(Win32BitmapInfoHeader);
1560 					warn("(#%d) skipping %d bytes of extended bitmap header", number, skip);
1561 					fskip(in, skip);
1562 				}
1563 				offset += bitmap.size;
1564 
1565 				if (bitmap.clr_used != 0 || bitmap.bpp < 24) {
1566 					palette_count = (bitmap.clr_used != 0 ? bitmap.clr_used : 1 << bitmap.bpp);
1567 					palette = xmalloc(sizeof(Win32RGBQuad) * palette_count);
1568 					if (!xfread(palette, sizeof(Win32RGBQuad) * palette_count, in))
1569 						goto local_cleanup;
1570 					offset += sizeof(Win32RGBQuad) * palette_count;
1571 				}
1572 
1573 				width = bitmap.width;
1574 				height = abs(bitmap.height)/2;
1575 
1576 				image_size = height * ROW_BYTES(width * bitmap.bpp);
1577 				mask_size = height * ROW_BYTES(width);
1578 
1579 				if (entries[c].dib_size	!= bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad))
1580 					warn("(#%d) incorrect total size of bitmap (%d specified; %d real)",
1581 					    c, entries[c].dib_size,
1582 					    bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad)
1583 					);
1584 
1585 			direct:
1586 				image_data = xmalloc(image_size);
1587 				if (!xfread(image_data, image_size, in))
1588 					goto local_cleanup;
1589 
1590                                 if (mask_size) {
1591 				    mask_data = xmalloc(mask_size);
1592 				    if (!xfread(mask_data, mask_size, in))
1593 					goto local_cleanup;
1594 				}
1595 
1596 				offset += image_size;
1597 				offset += mask_size;
1598 				completed++;
1599 
1600 				if (!filter(completed, width, height, bitmap.bpp, palette_count, dir.type == 1,
1601 						(dir.type == 1 ? 0 : entries[c].hotspot_x),
1602 					        (dir.type == 1 ? 0 : entries[c].hotspot_y))) {
1603                                         if (bitmap.compression != 0) goto local_cleanup;
1604 					goto done;
1605 				}
1606 				matched++;
1607 
1608 				if (extractmode) {
1609 				        if (bitmap.compression) {
1610                                         /* Just hope it's an otherwise
1611                                            readable image ... */
1612 					    char *tmp;
1613 					    FILE * fp;
1614                                             int num = file_numpages;
1615                                             fp = openTempFile(&tmp);
1616 					    if (fp) {
1617                                                 fwrite(image_data, 1, image_size, fp);
1618                                                 fclose(fp);
1619 					    }
1620                                             if (fp) out = readMagic(tmp);
1621                                             file_numpages = num;
1622                                             if (num>1)  file_isSpecialImage = 1;
1623                                             removeTempFile();
1624 					    goto local_cleanup;
1625 					}
1626 					out = ImageNew(width, height);
1627                                         if (out)
1628                                             out->alpha = (unsigned char *)
1629 					         xmalloc(width * height);
1630 
1631 					if (!out || !out->alpha) {
1632 						warn_errno("(#%d) cannot create file", number);
1633                                                 if (out) free(out->alpha);
1634                                                 free(out);
1635                                                 out = NULL;
1636 						goto local_cleanup;
1637 					}
1638 				}
1639 				if (bitmap.compression) goto local_cleanup;
1640 
1641                                 if (out)
1642 				for (d = 0; d < height; d++) {
1643 				        uint32_t x;
1644 					uint32_t y = (bitmap.height < 0) ? d : height - d - 1;
1645 					uint32_t imod = y * (image_size / height) * 8 / bitmap.bpp;
1646 					uint32_t mmod = y * (mask_size / height) * 8;
1647 				        row = out->data + 3 * d * width;
1648                                         alpha = out->alpha + d * width;
1649 
1650 					for (x = 0; x < width; x++) {
1651 						uint32_t color = simple_vec(image_data, x + imod, bitmap.bpp);
1652 
1653 						if (bitmap.bpp <= 16) {
1654 							if (color >= palette_count) {
1655 								warn("(#%d) color out of range in image data", number);
1656 								goto local_cleanup;
1657 							}
1658 							row[3*x]   = palette[color].red;
1659 							row[3*x+1] = palette[color].green;
1660 							row[3*x+2] = palette[color].blue;
1661 						} else {
1662 							row[3*x]  = (color >> 16) & 0xFF;
1663 							row[3*x+1] = (color >>  8) & 0xFF;
1664 							row[3*x+2] = (color >>  0) & 0xFF;
1665 						}
1666 						if (bitmap.bpp == 32)
1667 						    alpha[x] = (color >> 24) & 0xFF;
1668 						else
1669 						    alpha[x] = simple_vec(mask_data, x + mmod, 1) ? 0 : 0xFF;
1670 					}
1671 				}
1672 
1673 			done:
1674 
1675 				if (palette != NULL)
1676 					free(palette);
1677 				if (image_data != NULL) {
1678 					free(image_data);
1679 					free(mask_data);
1680 				}
1681 				continue;
1682 
1683 			local_cleanup:
1684 
1685 				if (palette != NULL)
1686 					free(palette);
1687 				if (image_data != NULL) {
1688 					free(image_data);
1689 					free(mask_data);
1690 				}
1691 				goto cleanup;
1692 			} else {
1693 				if (entries[c].dib_offset > offset)
1694 						min_offset = MIN(min_offset, entries[c].dib_offset);
1695 			}
1696 		}
1697 
1698 		if (previous == completed) {
1699 			if (min_offset < offset) {
1700 				warn("offset of bitmap header incorrect (too low)");
1701 				goto cleanup;
1702 			}
1703 			warn("skipping %d bytes of garbage at %d", min_offset-offset, offset);
1704 			fskip(in, min_offset - offset);
1705 			offset = min_offset;
1706 		}
1707 	}
1708 
1709 cleanup:
1710         *out_image = out;
1711 	free(entries);
1712 	return matched;
1713 }
1714 
1715 static char ico_magic_number[4] = {0, 0, 1, 0};
1716 
1717 int
TestICO(char * file)1718 TestICO(char *file)
1719 {
1720     FILE *ico_stream;
1721 /* Values read from icon file */
1722     char iconheader[8];
1723 
1724     if ((ico_stream = fopen (file, "r")) == NULL)
1725         return false;
1726 
1727     if (fread (iconheader, 1, 6, ico_stream)<6 ||
1728         memcmp(iconheader, ico_magic_number, sizeof(ico_magic_number))) {
1729         fclose (ico_stream);
1730         return false;
1731     }
1732     fclose (ico_stream);
1733     return true;
1734 }
1735 
1736 Image *
ReadICO(char * file)1737 ReadICO (char *file)
1738 {
1739     Image *image = NULL;
1740     FILE *fp;
1741     static char *prevfile = NULL;
1742 
1743     fp = fopen(file, "r");
1744     if (!fp) return NULL;
1745 
1746     if (prevfile && !strcmp(file, prevfile)) {
1747         silent = 1;
1748     } else {
1749         free(prevfile);
1750         silent = 0;
1751         prevfile = xstrdup(file);
1752     }
1753     prevfile = file;
1754 
1755     image_index = -1;
1756     file_numpages = extract_icons(fp, &image, false);
1757     if (!silent)
1758         warn("number of images : %d\n", file_numpages);
1759     if (file_numpages == 0) goto failure;
1760     if (file_numpages > 1) file_isSpecialImage = 1;
1761 
1762     fp = fopen(file, "r");
1763     if (!fp) return NULL;
1764     image_index = Global.numpage;
1765     silent = 1;
1766     extract_icons(fp, &image, true);
1767  failure:
1768     return image;
1769 }
1770 
1771 int
WriteICO(char * file,Image * image)1772 WriteICO(char *file, Image * image)
1773 {
1774     int res;
1775     char *tmp;
1776     FILE *fp;
1777 
1778     if (image->alpha) AlphaWarning("ICO", 1);
1779 
1780     fp = openTempFile(&tmp);
1781     if (!fp) return 1;
1782     fclose(fp);
1783 
1784     res = WritePNGn(tmp, image);
1785     if (res) return res;
1786     silent = 0;
1787     res = create_icon(1, &tmp, file, 1, hotspot_x, hotspot_y, alpha_threshold, bitdepth);
1788     removeTempFile();
1789 
1790     return !res;
1791 }
1792