]> git.imager.perl.org - imager.git/blob - ICO/msicon.c
don't define mm_log() with IMAGER_NO_CONTEXT
[imager.git] / ICO / msicon.c
1 #include "imext.h"
2 #include "msicon.h"
3 #include <string.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <stdarg.h>
7 #include <assert.h>
8
9 static
10 int read_packed(io_glue *ig, const char *format, ...);
11 static int 
12 read_palette(ico_reader_t *file, ico_image_t *image, int *error);
13 static int 
14 read_24bit_data(ico_reader_t *file, ico_image_t *image, int *error);
15 static int 
16 read_32bit_data(ico_reader_t *file, ico_image_t *image, int *error);
17 static int 
18 read_8bit_data(ico_reader_t *file, ico_image_t *image, int *error);
19 static int 
20 read_4bit_data(ico_reader_t *file, ico_image_t *image, int *error);
21 static int 
22 read_1bit_data(ico_reader_t *file, ico_image_t *image, int *error);
23 static int 
24 read_mask(ico_reader_t *file, ico_image_t *image, int *error);
25 static int
26 ico_write_validate(ico_image_t const *images, int image_count, int *error);
27 static int
28 ico_image_size(ico_image_t const *image, int *bits, int *colors);
29 static int
30 write_packed(i_io_glue_t *ig, char const *format, ...);
31 static int
32 write_palette(i_io_glue_t *ig, ico_image_t const *image, int *error);
33 static int
34 write_32_bit(i_io_glue_t *ig, ico_image_t const *image, int *error);
35 static int
36 write_8_bit(i_io_glue_t *ig, ico_image_t const *image, int *error);
37 static int
38 write_4_bit(i_io_glue_t *ig, ico_image_t const *image, int *error);
39 static int
40 write_1_bit(i_io_glue_t *ig, ico_image_t const *image, int *error);
41 static int
42 write_mask(i_io_glue_t *ig, ico_image_t const *image, int *error);
43
44 typedef struct {
45   int width;
46   int height;
47   long offset;
48   long size;
49   int hotspot_x, hotspot_y;
50 } ico_reader_image_entry;
51
52 /* this was previously declared, now define it */
53 struct ico_reader_tag {
54   /* the file we're dealing with */
55   i_io_glue_t *ig;
56
57   /* number of images in the file */
58   int count;
59
60   /* type of resource - 1=icon, 2=cursor */
61   int type;
62
63   /* image information from the header */
64   ico_reader_image_entry *images;
65 };
66
67 /*
68 =head1 NAME 
69
70 msicon.c - functions for working with .ICO files.
71
72 =head1 SYNOPSIS
73
74   // reading
75   int error;
76   ico_reader_t *file = ico_reader_open(ig, &error);
77   if (!file) {
78     char buffer[100];
79     ico_error_message(error, buffer, sizeof(buffer));
80     fputs(buffer, stderr);
81     exit(1);
82   }
83   int count = ico_image_count(file);
84   for (i = 0; i < count; ++i) {
85     ico_image_t *im = ico_image_read(file, index);
86     printf("%d x %d image %d\n", im->width, im->height, 
87            im->direct ? "direct" : "paletted");
88     ico_image_release(im);
89   }
90   ico_reader_close(file);
91
92 =head1 DESCRIPTION
93
94 This is intended as a general interface to reading MS Icon files, and
95 is written to be independent of Imager, even though it is part of
96 Imager.  You just need to supply something that acts like Imager's
97 io_glue.
98
99 It relies on icon images being generally small, and reads the entire
100 image into memory when reading.
101
102 =head1 READING ICON FILES
103
104 =over
105
106 =item ico_reader_open(ig, &error)
107
108 Parameters:
109
110 =over
111
112 =item *
113
114 io_glue *ig - an Imager IO object.  This must be seekable.
115
116 =item *
117
118 int *error - pointer to an integer which an error code will be
119 returned in on failure.
120
121 =back
122
123 =cut
124 */
125
126 ico_reader_t *
127 ico_reader_open(i_io_glue_t *ig, int *error) {
128   long res1, type, count;
129   ico_reader_t *file = NULL;
130   int i;
131
132   if (!read_packed(ig, "www", &res1, &type, &count)) {
133     *error = ICOERR_Short_File;
134     return NULL;
135   }
136   if (res1 != 0 || (type != 1 && type != 2) || count == 0) {
137     *error = ICOERR_Invalid_File;
138     return NULL;
139   }
140
141   file = malloc(sizeof(ico_reader_t));
142   if (!file) {
143     *error = ICOERR_Out_Of_Memory;
144     return NULL;
145   }
146   file->count = count;
147   file->type = type;
148   file->ig = ig;
149   file->images = malloc(sizeof(ico_reader_image_entry) * count);
150   if (file->images == NULL) {
151     *error = ICOERR_Out_Of_Memory;
152     free(file);
153     return NULL;
154   }
155
156   for (i = 0; i < count; ++i) {
157     long width, height, bytes_in_res, image_offset;
158
159     ico_reader_image_entry *image = file->images + i;
160     if (type == ICON_ICON) {
161       if (!read_packed(ig, "bb xxxxxx dd", &width, &height, &bytes_in_res, 
162                        &image_offset)) {
163         free(file->images);
164         free(file);
165         *error = ICOERR_Short_File;
166         return NULL;
167       }
168       image->hotspot_x = image->hotspot_y = 0;
169     }
170     else {
171       long hotspot_x, hotspot_y;
172
173       if (!read_packed(ig, "bb xx ww dd", &width, &height, 
174                        &hotspot_x, &hotspot_y, &bytes_in_res, 
175                        &image_offset)) {
176         free(file->images);
177         free(file);
178         *error = ICOERR_Short_File;
179         return NULL;
180       }
181       image->hotspot_x = hotspot_x;
182       image->hotspot_y = hotspot_y;
183     }
184
185     /* a width or height of zero here indicates a width/height of 256 */
186     image->width = width ? width : 256;
187     image->height = height ? height : 256;
188     image->offset = image_offset;
189     image->size = bytes_in_res;
190   }
191
192   return file;
193 }
194
195 /*
196 =item ico_image_count
197
198   // number of images in the file
199   count = ico_image_count(file);
200
201 =cut
202 */
203
204 int
205 ico_image_count(ico_reader_t *file) {
206   return file->count;
207 }
208
209 /*
210 =item ico_type
211
212   // type of file - ICON_ICON for icon, ICON_CURSOR for cursor
213   type = ico_type(file);
214
215 =cut
216 */
217
218 int
219 ico_type(ico_reader_t *file) {
220   return file->type;
221 }
222
223 /*
224 =item ico_image_read
225
226 Read an image from the file given it's index.
227
228 =cut
229 */
230
231 ico_image_t *
232 ico_image_read(ico_reader_t *file, int index, int *error) {
233   io_glue *ig = file->ig;
234   ico_reader_image_entry *im;
235   long bi_size, width, height, planes, bit_count;
236   ico_image_t *result;
237
238   if (index < 0 || index >= file->count) {
239     *error = ICOERR_Bad_Image_Index;
240     return NULL;
241   }
242
243   im = file->images + index;
244   if (i_io_seek(ig, im->offset, SEEK_SET) != im->offset) {
245     *error = ICOERR_File_Error;
246     return NULL;
247   }
248
249   if (!read_packed(ig, "dddww xxxx xxxx xxxx xxxx xxxx xxxx", &bi_size, 
250                    &width, &height, &planes, &bit_count)) {
251     *error = ICOERR_Short_File;
252     return NULL;
253   }
254
255   /* the bitmapinfoheader height includes the height of 
256      the and and xor masks */
257   if (bi_size != 40 || width != im->width || height != im->height * 2
258       || planes != 1) { /* don't know how to handle planes != 1 */
259     *error = ICOERR_Invalid_File;
260     return NULL;
261   }
262
263   if (bit_count != 1 && bit_count != 4 && bit_count != 8
264       && bit_count != 24 && bit_count != 32) {
265     *error = ICOERR_Unknown_Bits;
266     return 0;
267   }
268
269   result = malloc(sizeof(ico_image_t));
270   if (!result) {
271     *error = ICOERR_Out_Of_Memory;
272     return NULL;
273   }
274   result->width = width;
275   result->height = im->height;
276   result->direct = bit_count > 8;
277   result->bit_count = bit_count;
278   result->palette = NULL;
279   result->image_data = NULL;
280   result->mask_data = NULL;
281   result->hotspot_x = im->hotspot_x;
282   result->hotspot_y = im->hotspot_y;
283     
284   if (bit_count == 32) {
285     result->palette_size = 0;
286
287     result->image_data = malloc(result->width * result->height * sizeof(ico_color_t));
288     if (!result->image_data) {
289       free(result);
290       *error = ICOERR_Out_Of_Memory;
291       return NULL;
292     }
293     if (!read_32bit_data(file, result, error)) {
294       free(result->image_data);
295       free(result);
296       return NULL;
297     }
298   }
299   else if (bit_count == 24) {
300     result->palette_size = 0;
301
302     result->image_data = malloc(result->width * result->height * sizeof(ico_color_t));
303     if (!result->image_data) {
304       free(result);
305       *error = ICOERR_Out_Of_Memory;
306       return NULL;
307     }
308     if (!read_24bit_data(file, result, error)) {
309       free(result->image_data);
310       free(result);
311       return NULL;
312     }
313   }
314   else {
315     int read_result;
316
317     result->palette_size = 1 << bit_count;
318     result->palette = malloc(sizeof(ico_color_t) * result->palette_size);
319     if (!result->palette) {
320       free(result);
321       *error = ICOERR_Out_Of_Memory;
322       return NULL;
323     }
324
325     result->image_data = malloc(result->width * result->height);
326     if (!result->image_data) {
327       *error = ICOERR_Out_Of_Memory;
328       free(result->palette);
329       free(result);
330       return 0;
331     }      
332     
333     if (!read_palette(file, result, error)) {
334       free(result->palette);
335       free(result->image_data);
336       free(result);
337       return 0;
338     }
339
340     switch (bit_count) {
341     case 1:
342       read_result = read_1bit_data(file, result, error);
343       break;
344
345     case 4:
346       read_result = read_4bit_data(file, result, error);
347       break;
348       
349     case 8:
350       read_result = read_8bit_data(file, result, error);
351       break;
352
353     default:
354       assert(0); /* this can't happen in theory */
355       read_result = 0;
356       break;
357     }
358
359     if (!read_result) {
360       free(result->palette);
361       free(result->image_data);
362       free(result);
363       return 0;
364     }
365   }
366
367   result->mask_data = malloc(result->width * result->height);
368   if (!result->mask_data) {
369     *error = ICOERR_Out_Of_Memory;
370     free(result->palette);
371     free(result->image_data);
372     free(result);
373     return 0;
374   }
375
376   if (!read_mask(file, result, error)) {
377     free(result->mask_data);
378     free(result->palette);
379     free(result->image_data);
380     free(result);
381     return 0;
382   }
383
384   return result;
385 }
386
387 /*
388 =item ico_image_release
389
390 Release an image structure returned by ico_image_read.
391
392 =cut
393 */
394
395 void
396 ico_image_release(ico_image_t *image) {
397   free(image->mask_data);
398   free(image->palette);
399   free(image->image_data);
400   free(image);
401 }
402
403 /*
404 =item ico_reader_close
405
406 Releases the read file structure.
407
408 =cut
409 */
410
411 void
412 ico_reader_close(ico_reader_t *file) {
413   i_io_close(file->ig);
414   free(file->images);
415   free(file);
416 }
417
418 /*
419 =back
420
421 =head1 WRITING ICON FILES
422
423 =over
424
425 =item ico_write(ig, images, image_count, type, &error)
426
427 Parameters:
428
429 =over
430
431 =item *
432
433 io_glue *ig - an Imager IO object.  This only needs to implement
434 writing for ico_write()
435
436 =item *
437
438 ico_image_t *images - array of images to be written.
439
440 =item *
441
442 int image_count - number of images
443
444 =item *
445
446 int type - must be ICON_ICON or ICON_CURSOR
447
448 =item *
449
450 int *error - set to an error code on failure.
451
452 =back
453
454 Returns non-zero on success.
455
456 =cut
457 */
458
459 int
460 ico_write(i_io_glue_t *ig, ico_image_t const *images, int image_count,
461           int type, int *error) {
462   int i;
463   int start_offset = 6 + 16 * image_count;
464   int current_offset = start_offset;
465
466   if (type != ICON_ICON && type != ICON_CURSOR) {
467     *error = ICOERR_Bad_File_Type;
468     return 0;
469   }
470
471   /* validate the images */
472   if (!ico_write_validate(images, image_count, error))
473     return 0;
474
475   /* write the header */
476   if (!write_packed(ig, "www", 0, type, image_count)) {
477     *error = ICOERR_Write_Failure;
478     return 0;
479   }
480
481   /* work out the offsets of each image */
482   for (i = 0; i < image_count; ++i) {
483     ico_image_t const *image = images + i;
484     int bits, colors;
485     int size = ico_image_size(image, &bits, &colors);
486     int width_byte = image->width == 256 ? 0 : image->width;
487     int height_byte = image->height == 256 ? 0 : image->height;
488
489     if (type == ICON_ICON) {
490       if (!write_packed(ig, "bbbbwwdd", width_byte, height_byte,
491                         colors, 0, 1, bits, (unsigned long)size, 
492                         (unsigned long)current_offset)) {
493         *error = ICOERR_Write_Failure;
494         return 0;
495       }
496     }
497     else {
498       int hotspot_x = image->hotspot_x;
499       int hotspot_y = image->hotspot_y;
500
501       if (hotspot_x < 0)
502         hotspot_x = 0;
503       else if (hotspot_x >= image->width)
504         hotspot_x = image->width - 1;
505       if (hotspot_y < 0)
506         hotspot_y = 0;
507       else if (hotspot_y >= image->height)
508         hotspot_y = image->height - 1;
509
510       if (!write_packed(ig, "bbbbwwdd", width_byte, height_byte,
511                         colors, 0, hotspot_x, hotspot_y, (unsigned long)size, 
512                         (unsigned long)current_offset)) {
513         *error = ICOERR_Write_Failure;
514         return 0;
515       }
516     }
517     current_offset += size;
518   }
519   
520   /* write out each image */
521   for (i = 0; i < image_count; ++i) {
522     ico_image_t const *image = images + i;
523
524     if (image->direct) {
525       if (!write_32_bit(ig, image, error))
526         return 0;
527     }
528     else {
529       if (image->palette_size <= 2) {
530         if (!write_1_bit(ig, image, error))
531           return 0;
532       }
533       else if (image->palette_size <= 16) {
534         if (!write_4_bit(ig, image, error))
535           return 0;
536       }
537       else {
538         if (!write_8_bit(ig, image, error))
539           return 0;
540       }
541     }
542     if (!write_mask(ig, image, error))
543       return 0;
544   }
545
546   return 1;
547 }
548
549 /*
550 =back
551
552 =head1 ERROR MESSAGES
553
554 =over
555
556 =item ico_error_message
557
558 Converts an error code into an error message.
559
560 =cut
561 */
562
563 size_t
564 ico_error_message(int error, char *buffer, size_t buffer_size) {
565   char const *msg;
566   size_t size;
567
568   switch (error) {
569   case ICOERR_Short_File:
570     msg = "Short read";
571     break;
572
573   case ICOERR_File_Error:
574     msg = "I/O error";
575     break;
576
577   case ICOERR_Write_Failure:
578     msg = "Write failure";
579     break;
580
581   case ICOERR_Invalid_File:
582     msg = "Not an icon file";
583     break;
584
585   case ICOERR_Unknown_Bits:
586     msg = "Unknown value for bits/pixel";
587     break;
588
589   case ICOERR_Bad_Image_Index:
590     msg = "Image index out of range";
591     break;
592
593   case ICOERR_Bad_File_Type:
594     msg = "Bad file type parameter";
595     break;
596
597   case ICOERR_Invalid_Width:
598     msg = "Invalid image width";
599     break;
600
601   case ICOERR_Invalid_Height:
602     msg = "Invalid image height";
603     break;
604     
605   case ICOERR_Invalid_Palette:
606     msg = "Invalid Palette";
607     break;
608
609   case ICOERR_No_Data:
610     msg = "No image data in image supplied to ico_write";
611     break;
612
613   case ICOERR_Out_Of_Memory:
614     msg = "Out of memory";
615     break;
616
617   default:
618     msg = "Unknown error code";
619     break;
620   }
621
622   size = strlen(msg) + 1;
623   if (size > buffer_size)
624     size = buffer_size;
625   memcpy(buffer, msg, size);
626   buffer[size-1] = '\0';
627
628   return size;
629 }
630
631 /*
632 =back
633
634 =head1 PRIVATE FUNCTIONS
635
636 =over
637
638 =item read_packed
639
640 Reads packed data from a stream, unpacking it.
641
642 =cut
643 */
644
645 static
646 int read_packed(io_glue *ig, const char *format, ...) {
647   unsigned char buffer[100];
648   va_list ap;
649   long *p;
650   int size;
651   const char *formatp;
652   unsigned char *bufp;
653
654   /* read efficiently, work out the size of the buffer */
655   size = 0;
656   formatp = format;
657   while (*formatp) {
658     switch (*formatp++) {
659     case 'b': 
660     case 'x': size += 1; break;
661     case 'w': size += 2; break;
662     case 'd': size += 4; break;
663     case ' ': break; /* space to separate components */
664     default:
665       fprintf(stderr, "invalid unpack char in %s\n", format);
666       exit(1);
667     }
668   }
669
670   if (size > sizeof(buffer)) {
671     /* catch if we need a bigger buffer, but 100 is plenty */
672     fprintf(stderr, "format %s too long for buffer\n", format);
673     exit(1);
674   }
675
676   if (i_io_read(ig, buffer, size) != size) {
677     return 0;
678   }
679
680   va_start(ap, format);
681
682   bufp = buffer;
683   while (*format) {
684
685     switch (*format) {
686     case 'b':
687       p = va_arg(ap, long *);
688       *p = *bufp++;
689       break;
690
691     case 'w':
692       p = va_arg(ap, long *);
693       *p = bufp[0] + (bufp[1] << 8);
694       bufp += 2;
695       break;
696
697     case 'd':
698       p = va_arg(ap, long *);
699       *p = bufp[0] + (bufp[1] << 8) + (bufp[2] << 16) + (bufp[3] << 24);
700       bufp += 4;
701       break;
702
703     case 'x':
704       ++bufp; /* skip a byte */
705       break;
706
707     case ' ':
708       /* nothing to do */
709       break;
710     }
711     ++format;
712   }
713   return 1;
714 }
715
716 /*
717 =item read_palette
718
719 Reads the palette data for an icon image.
720
721 =cut
722 */
723
724 static
725 int
726 read_palette(ico_reader_t *file, ico_image_t *image, int *error) {
727   int palette_bytes = image->palette_size * 4;
728   unsigned char *read_buffer = malloc(palette_bytes);
729   unsigned char *inp;
730   ico_color_t *outp;
731   int i;
732
733   if (!read_buffer) {
734     *error = ICOERR_Out_Of_Memory;
735     return 0;
736   }
737
738   if (i_io_read(file->ig, read_buffer, palette_bytes) != palette_bytes) {
739     *error = ICOERR_Short_File;
740     free(read_buffer);
741     return 0;
742   }
743
744   inp = read_buffer;
745   outp = image->palette;
746   for (i = 0; i < image->palette_size; ++i) {
747     outp->b = *inp++;
748     outp->g = *inp++;
749     outp->r = *inp++;
750     outp->a = 255;
751     ++inp;
752     ++outp;
753   }
754   free(read_buffer);
755
756   return 1;
757 }
758
759 /*
760 =item read_32bit_data
761
762 Reads 32 bit image data.
763
764 =cut
765 */
766
767 static
768 int
769 read_32bit_data(ico_reader_t *file, ico_image_t *image, int *error) {
770   int line_bytes = image->width * 4;
771   unsigned char *buffer = malloc(line_bytes);
772   int y;
773   int x;
774   unsigned char *inp;
775   ico_color_t *outp;
776
777   if (!buffer) {
778     *error = ICOERR_Out_Of_Memory;
779     return 0;
780   }
781
782   for (y = image->height - 1; y >= 0; --y) {
783     if (i_io_read(file->ig, buffer, line_bytes) != line_bytes) {
784       free(buffer);
785       *error = ICOERR_Short_File;
786       return 0;
787     }
788     outp = image->image_data;
789     outp += y * image->width;
790     inp = buffer;
791     for (x = 0; x < image->width; ++x) {
792       outp->b = inp[0];
793       outp->g = inp[1];
794       outp->r = inp[2];
795       outp->a = inp[3];
796       ++outp;
797       inp += 4;
798     }
799   }
800   free(buffer);
801
802   return 1;
803 }
804
805 /*
806 =item read_24bit_data
807
808 Reads 24 bit image data.
809
810 =cut
811 */
812
813 static
814 int
815 read_24bit_data(ico_reader_t *file, ico_image_t *image, int *error) {
816   int line_bytes = image->width * 3;
817   unsigned char *buffer;
818   int y;
819   int x;
820   unsigned char *inp;
821   ico_color_t *outp;
822
823   line_bytes = (line_bytes + 3) / 4 * 4;
824
825   buffer = malloc(line_bytes);
826
827   if (!buffer) {
828     *error = ICOERR_Out_Of_Memory;
829     return 0;
830   }
831
832   for (y = image->height - 1; y >= 0; --y) {
833     if (i_io_read(file->ig, buffer, line_bytes) != line_bytes) {
834       free(buffer);
835       *error = ICOERR_Short_File;
836       return 0;
837     }
838     outp = image->image_data;
839     outp += y * image->width;
840     inp = buffer;
841     for (x = 0; x < image->width; ++x) {
842       outp->b = inp[0];
843       outp->g = inp[1];
844       outp->r = inp[2];
845       outp->a = 255;
846       ++outp;
847       inp += 3;
848     }
849   }
850   free(buffer);
851
852   return 1;
853 }
854
855 /*
856 =item read_8bit_data
857
858 Reads 8 bit image data.
859
860 =cut
861 */
862
863 static
864 int
865 read_8bit_data(ico_reader_t *file, ico_image_t *image, int *error) {
866   int line_bytes = (image->width + 3) / 4 * 4;
867   unsigned char *buffer = malloc(line_bytes);
868   int y;
869   int x;
870   unsigned char *inp, *outp;
871
872   if (!buffer) {
873     *error = ICOERR_Out_Of_Memory;
874     return 0;
875   }
876
877   for (y = image->height - 1; y >= 0; --y) {
878     outp = image->image_data;
879     outp += y * image->width;
880     if (i_io_read(file->ig, buffer, line_bytes) != line_bytes) {
881       free(buffer);
882       *error = ICOERR_Short_File;
883       return 0;
884     }
885     for (x = 0, inp = buffer; x < image->width; ++x) {
886       *outp++ = *inp++;
887     }
888   }
889   free(buffer);
890
891   return 1;
892 }
893
894 /*
895 =item read_4bit_data
896
897 Reads 4 bit image data.
898
899 =cut
900 */
901
902 static
903 int
904 read_4bit_data(ico_reader_t *file, ico_image_t *image, int *error) {
905   /* 2 pixels per byte, rounded up to the nearest dword */
906   int line_bytes = ((image->width + 1) / 2 + 3) / 4 * 4;
907   unsigned char *read_buffer = malloc(line_bytes);
908   int y;
909   int x;
910   unsigned char *inp, *outp;
911
912   if (!read_buffer) {
913     *error = ICOERR_Out_Of_Memory;
914     return 0;
915   }
916
917   for (y = image->height - 1; y >= 0; --y) {
918     if (i_io_read(file->ig, read_buffer, line_bytes) != line_bytes) {
919       free(read_buffer);
920       *error = ICOERR_Short_File;
921       return 0;
922     }
923     
924     outp = image->image_data;
925     outp += y * image->width;
926     inp = read_buffer;
927     for (x = 0; x < image->width; ++x) {
928       /* yes, this is kind of ugly */
929       if (x & 1) {
930         *outp++ = *inp++ & 0x0F;
931       }
932       else {
933         *outp++ = *inp >> 4;
934       }
935     }
936   }
937   free(read_buffer);
938
939   return 1;
940 }
941
942 /*
943 =item read_1bit_data
944
945 Reads 1 bit image data.
946
947 =cut
948 */
949
950 static
951 int
952 read_1bit_data(ico_reader_t *file, ico_image_t *image, int *error) {
953   /* 8 pixels per byte, rounded up to the nearest dword */
954   int line_bytes = ((image->width + 7) / 8 + 3) / 4 * 4;
955   unsigned char *read_buffer = malloc(line_bytes);
956   int y;
957   int x;
958   unsigned char *inp, *outp;
959
960   if (!read_buffer) {
961     *error = ICOERR_Out_Of_Memory;
962     return 0;
963   }
964
965   for (y = image->height - 1; y >= 0; --y) {
966     if (i_io_read(file->ig, read_buffer, line_bytes) != line_bytes) {
967       free(read_buffer);
968       *error = ICOERR_Short_File;
969       return 0;
970     }
971     
972     outp = image->image_data;
973     outp += y * image->width;
974     inp = read_buffer;
975     for (x = 0; x < image->width; ++x) {
976       *outp++ = (*inp >> (7 - (x & 7))) & 1;
977       if ((x & 7) == 7)
978         ++inp;
979     }
980   }
981   free(read_buffer);
982
983   return 1;
984 }
985
986 /* this is very similar to the 1 bit reader <sigh> */
987 /*
988 =item read_mask
989
990 Reads the AND mask from an icon image.
991
992 =cut
993 */
994
995 static
996 int
997 read_mask(ico_reader_t *file, ico_image_t *image, int *error) {
998   /* 8 pixels per byte, rounded up to the nearest dword */
999   int line_bytes = ((image->width + 7) / 8 + 3) / 4 * 4;
1000   unsigned char *read_buffer = malloc(line_bytes);
1001   int y;
1002   int x;
1003   int mask;
1004   unsigned char *inp, *outp;
1005
1006   if (!read_buffer) {
1007     *error = ICOERR_Out_Of_Memory;
1008     return 0;
1009   }
1010
1011   for (y = image->height - 1; y >= 0; --y) {
1012     if (i_io_read(file->ig, read_buffer, line_bytes) != line_bytes) {
1013       free(read_buffer);
1014       *error = ICOERR_Short_File;
1015       return 0;
1016     }
1017     
1018     outp = image->mask_data + y * image->width;
1019     inp = read_buffer;
1020     mask = 0x80;
1021     for (x = 0; x < image->width; ++x) {
1022       *outp++ = (*inp & mask) ? 1 : 0;
1023       mask >>= 1;
1024       if (!mask) {
1025         mask = 0x80;
1026         ++inp;
1027       }
1028     }
1029   }
1030   free(read_buffer);
1031
1032   return 1;
1033 }
1034
1035 /*
1036 =item ico_write_validate
1037
1038 Check each image to make sure it can go into an icon file.
1039
1040 =cut
1041 */
1042
1043 static int
1044 ico_write_validate(ico_image_t const *images, int image_count, int *error) {
1045   int i;
1046
1047   for (i = 0; i < image_count; ++i) {
1048     ico_image_t const *image = images + i;
1049
1050     if (image->width < 1 || image->width > 256) {
1051       *error = ICOERR_Invalid_Width;
1052       return 0;
1053     }
1054     if (image->height < 1 || image->height > 256) {
1055       *error = ICOERR_Invalid_Height;
1056       return 0;
1057     }
1058     if (!image->image_data) {
1059       *error = ICOERR_No_Data;
1060       return 0;
1061     }
1062     if (!image->direct) {
1063       if (image->palette_size < 0 || image->palette_size > 256 
1064           || !image->palette) {
1065         *error = ICOERR_Invalid_Palette;
1066         return 0;
1067       }
1068     }
1069   }
1070
1071   return 1;
1072 }
1073
1074 /*
1075 =item ico_image_size
1076
1077 Calculate how much space the icon takes up in the file.
1078
1079 =cut
1080 */
1081
1082 static int
1083 ico_image_size(ico_image_t const *image, int *bits, int *colors) {
1084   int size = 40; /* start with the BITMAPINFOHEADER */
1085
1086   /* add in the image area */
1087   if (image->direct) {
1088     *bits = 32;
1089     *colors = 0;
1090     size += image->width * 4 * image->height;
1091   }
1092   else {
1093     if (image->palette_size <= 2) {
1094       *bits = 1;
1095       *colors = 2;
1096     }
1097     else if (image->palette_size <= 16) {
1098       *bits = 4;
1099       *colors = 16;
1100     }
1101     else {
1102       *bits = 8;
1103       *colors = 0;
1104     }
1105
1106     /* palette size */
1107     size += *colors * 4;
1108
1109     /* image data size */
1110     size += (image->width * *bits + 31) / 32 * 4 * image->height;
1111   }
1112
1113   /* add in the mask */
1114   size += (image->width + 31) / 32 * 4 * image->height;
1115
1116   return size;
1117 }
1118
1119 /*
1120 =item write_packed
1121
1122 Pack numbers given a format to a stream.
1123
1124 =cut
1125 */
1126
1127 static int 
1128 write_packed(i_io_glue_t *ig, char const *format, ...) {
1129   unsigned char buffer[100];
1130   va_list ap;
1131   unsigned long p;
1132   int size;
1133   const char *formatp;
1134   unsigned char *bufp;
1135
1136   /* write efficiently, work out the size of the buffer */
1137   size = 0;
1138   formatp = format;
1139   while (*formatp) {
1140     switch (*formatp++) {
1141     case 'b': size++; break;
1142     case 'w': size += 2; break;
1143     case 'd': size += 4; break;
1144     case ' ': break; /* space to separate components */
1145     default:
1146       fprintf(stderr, "invalid unpack char in %s\n", format);
1147       exit(1);
1148     }
1149   }
1150
1151   if (size > sizeof(buffer)) {
1152     /* catch if we need a bigger buffer, but 100 is plenty */
1153     fprintf(stderr, "format %s too long for buffer\n", format);
1154     exit(1);
1155   }
1156
1157   va_start(ap, format);
1158
1159   bufp = buffer;
1160   while (*format) {
1161
1162     switch (*format) {
1163     case 'b':
1164       p = va_arg(ap, int);
1165       *bufp++ = p;
1166       break;
1167
1168     case 'w':
1169       p = va_arg(ap, int);
1170       *bufp++ = p & 0xFF;
1171       *bufp++  = (p >> 8) & 0xFF;
1172       break;
1173
1174     case 'd':
1175       p = va_arg(ap, unsigned long);
1176       *bufp++ = p & 0xFF;
1177       *bufp++ = (p >> 8) & 0xFF;
1178       *bufp++ = (p >> 16) & 0xFF;
1179       *bufp++ = (p >> 24) & 0xFF;
1180       break;
1181
1182     case ' ':
1183       /* nothing to do */
1184       break;
1185     }
1186     ++format;
1187   }
1188
1189   if (i_io_write(ig, buffer, size) != size)
1190     return 0;
1191   
1192   return 1;
1193 }
1194
1195 /*
1196 =item write_palette
1197
1198 Write the palette for an icon.
1199
1200 =cut
1201 */
1202
1203 static int
1204 write_palette(i_io_glue_t *ig, ico_image_t const *image, int *error) {
1205   int full_size = image->palette_size;
1206   unsigned char *writebuf, *outp;
1207   ico_color_t *colorp;
1208   int i;
1209
1210   if (image->palette_size <= 2)
1211     full_size = 2;
1212   else if (image->palette_size <= 16)
1213     full_size = 16;
1214   else
1215     full_size = 256;
1216
1217   writebuf = calloc(full_size, 4);
1218   if (!writebuf) {
1219     *error = ICOERR_Out_Of_Memory;
1220     return 0;
1221   }
1222   outp = writebuf;
1223   colorp = image->palette;
1224   for (i = 0; i < image->palette_size; ++i) {
1225     *outp++ = colorp->b;
1226     *outp++ = colorp->g;
1227     *outp++ = colorp->r;
1228     *outp++ = 0xFF;
1229     ++colorp;
1230   }
1231   for (; i < full_size; ++i) {
1232     *outp++ = 0;
1233     *outp++ = 0;
1234     *outp++ = 0;
1235     *outp++ = 0;
1236   }
1237
1238   if (i_io_write(ig, writebuf, full_size * 4) != full_size * 4) {
1239     *error = ICOERR_Write_Failure;
1240     free(writebuf);
1241     return 0;
1242   }
1243
1244   free(writebuf);
1245
1246   return 1;
1247 }
1248
1249 /*
1250 =item write_bitmapinfoheader
1251
1252 Write the BITMAPINFOHEADER for an icon image.
1253
1254 =cut
1255 */
1256
1257 static int
1258 write_bitmapinfoheader(i_io_glue_t *ig, ico_image_t const *image, int *error,
1259                         int bit_count, int clr_used) {
1260   if (!write_packed(ig, "d dd w w d d dd dd", 
1261                     40UL, /* biSize */
1262                     (unsigned long)image->width, 
1263                     (unsigned long)2 * image->height, /* biWidth/biHeight */
1264                     1, bit_count, /* biPlanes, biBitCount */
1265                     0UL, 0UL, /* biCompression, biSizeImage */
1266                     0UL, 0UL, /* bi(X|Y)PetsPerMeter */
1267                     (unsigned long)clr_used, /* biClrUsed */
1268                     0UL)) { /* biClrImportant */
1269     *error = ICOERR_Write_Failure;
1270     return 0;
1271   }
1272
1273   return 1;
1274 }
1275
1276 /*
1277 =item write_32_bit
1278
1279 Write 32-bit image data to the icon.
1280
1281 =cut
1282 */
1283
1284 static int
1285 write_32_bit(i_io_glue_t *ig, ico_image_t const *image, int *error) {
1286   unsigned char *writebuf;
1287   ico_color_t *data = image->image_data, *colorp;
1288   unsigned char *writep;
1289   int x, y;
1290
1291   if (!write_bitmapinfoheader(ig, image, error, 32, 0)) {
1292     return 0;
1293   }
1294
1295   writebuf = malloc(image->width * 4);
1296   if (!writebuf) {
1297     *error = ICOERR_Out_Of_Memory;
1298     return 0;
1299   }
1300
1301   for (y = image->height-1; y >= 0; --y) {
1302     writep = writebuf;
1303     colorp = data + y * image->width;
1304     for (x = 0; x < image->width; ++x) {
1305       *writep++ = colorp->b;
1306       *writep++ = colorp->g;
1307       *writep++ = colorp->r;
1308       *writep++ = colorp->a;
1309       ++colorp;
1310     }
1311     if (i_io_write(ig, writebuf, image->width * 4) != image->width * 4) {
1312       *error = ICOERR_Write_Failure;
1313       free(writebuf);
1314       return 0;
1315     }
1316   }
1317
1318   free(writebuf);
1319
1320   return 1;
1321 }
1322
1323 /*
1324 =item write_8_bit
1325
1326 Write 8 bit image data.
1327
1328 =cut
1329 */
1330
1331 static int
1332 write_8_bit(i_io_glue_t *ig, ico_image_t const *image, int *error) {
1333   static const unsigned char zeros[3] = { '\0' };
1334   int y;
1335   const unsigned char *data = image->image_data;
1336   int zero_count = (0U - (unsigned)image->width) & 3;
1337
1338   if (!write_bitmapinfoheader(ig, image, error, 8, 256)) {
1339     return 0;
1340   }
1341
1342   if (!write_palette(ig, image, error))
1343     return 0;
1344
1345   for (y = image->height-1; y >= 0; --y) {
1346     if (i_io_write(ig, data + y * image->width, 
1347                    image->width) != image->width) {
1348       *error = ICOERR_Write_Failure;
1349       return 0;
1350     }
1351     if (zero_count) {
1352       if (i_io_write(ig, zeros, zero_count) != zero_count) {
1353         *error = ICOERR_Write_Failure;
1354         return 0;
1355       }
1356     }
1357   }
1358
1359   return 1;
1360 }
1361
1362 /*
1363 =item write_4_bit
1364
1365 Write 4 bit image data.
1366
1367 =cut
1368 */
1369
1370 static int
1371 write_4_bit(i_io_glue_t *ig, ico_image_t const *image, int *error) {
1372   int line_size = ((image->width + 1) / 2 + 3) / 4 * 4;
1373   unsigned char *writebuf, *outp;
1374   int x, y;
1375   unsigned char const *data = image->image_data;
1376   unsigned char const *pixelp;
1377   
1378   if (!write_bitmapinfoheader(ig, image, error, 4, 16)) {
1379     return 0;
1380   }
1381
1382   if (!write_palette(ig, image, error))
1383     return 0;
1384
1385   writebuf = malloc(line_size);
1386   if (!writebuf) {
1387     *error = ICOERR_Out_Of_Memory;
1388     return 0;
1389   }
1390
1391   for (y = image->height-1; y >= 0; --y) {
1392     pixelp = data + y * image->width;
1393     outp = writebuf;
1394     memset(writebuf, 0, line_size);
1395     for (x = 0; x < image->width; ++x) {
1396       if (x & 1) {
1397         *outp |= *pixelp++ & 0x0F;
1398         ++outp;
1399       }
1400       else {
1401         *outp |= *pixelp++ << 4;
1402       }
1403     }
1404
1405     if (i_io_write(ig, writebuf, line_size) != line_size) {
1406       *error = ICOERR_Write_Failure;
1407       free(writebuf);
1408       return 0;
1409     }
1410   }
1411
1412   free(writebuf);
1413
1414   return 1;
1415 }
1416
1417 /*
1418 =item write_1_bit
1419
1420 Write 1 bit image data.
1421
1422 =cut
1423 */
1424
1425 static int
1426 write_1_bit(i_io_glue_t *ig, ico_image_t const *image, int *error) {
1427   int line_size = (image->width + 31) / 32 * 4;
1428   unsigned char *writebuf = malloc(line_size);
1429   unsigned char *outp;
1430   unsigned char const *data, *pixelp;
1431   int x,y;
1432   unsigned mask;
1433
1434   if (!write_bitmapinfoheader(ig, image, error, 1, 2)) {
1435     return 0;
1436   }
1437
1438   if (!write_palette(ig, image, error))
1439     return 0;
1440
1441   if (!writebuf) {
1442     *error = ICOERR_Out_Of_Memory;
1443     return 0;
1444   }
1445   
1446   data = image->image_data;
1447   for (y = image->height-1; y >= 0; --y) {
1448     memset(writebuf, 0, line_size);
1449     pixelp = data + y * image->width;
1450     outp = writebuf;
1451     mask = 0x80;
1452     for (x = 0; x < image->width; ++x) {
1453       if (*pixelp)
1454         *outp |= mask;
1455       mask >>= 1;
1456       if (!mask) {
1457         mask = 0x80;
1458         outp++;
1459       }
1460     }
1461     if (i_io_write(ig, writebuf, line_size) != line_size) {
1462       *error = ICOERR_Write_Failure;
1463       free(writebuf);
1464       return 0;
1465     }
1466   }
1467
1468   free(writebuf);
1469
1470   return 1;
1471 }
1472
1473 /*
1474 =item write_mask
1475
1476 Write the AND mask.
1477
1478 =cut
1479 */
1480
1481 static int
1482 write_mask(i_io_glue_t *ig, ico_image_t const *image, int *error) {
1483   int line_size = (image->width + 31) / 32 * 4;
1484   unsigned char *writebuf = malloc(line_size);
1485   unsigned char *outp;
1486   unsigned char const *data, *pixelp;
1487   int x,y;
1488   unsigned mask;
1489
1490   if (!writebuf) {
1491     *error = ICOERR_Out_Of_Memory;
1492     return 0;
1493   }
1494   
1495   data = image->mask_data;
1496   if (data) {
1497     for (y = image->height-1; y >= 0; --y) {
1498       memset(writebuf, 0, line_size);
1499       pixelp = data + y * image->width;
1500       outp = writebuf;
1501       mask = 0x80;
1502       for (x = 0; x < image->width; ++x) {
1503         if (*pixelp)
1504           *outp |= mask;
1505         mask >>= 1;
1506         if (!mask) {
1507           mask = 0x80;
1508           outp++;
1509         }
1510         ++pixelp;
1511       }
1512       if (i_io_write(ig, writebuf, line_size) != line_size) {
1513         *error = ICOERR_Write_Failure;
1514         free(writebuf);
1515         return 0;
1516       }
1517     }
1518   }
1519   else {
1520     memset(writebuf, 0, line_size);
1521     for (y = image->height-1; y >= 0; --y) {
1522       if (i_io_write(ig, writebuf, line_size) != line_size) {
1523         *error = ICOERR_Write_Failure;
1524         free(writebuf);
1525         return 0;
1526       }
1527     }
1528   }
1529
1530   free(writebuf);
1531
1532   return 1;
1533 }
1534
1535 /*
1536 =back
1537
1538 =head1 AUTHOR
1539
1540 Tony Cook <tonyc@cpan.org>
1541
1542 =head1 REVISION
1543
1544 $Revision$
1545
1546 =cut
1547 */