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