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