]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-ico.c
Add a (#ifdef 0'ed) test provoking a segfault in TIFFReadDirectory().
[~andy/gtk] / gdk-pixbuf / io-ico.c
1 /* GdkPixbuf library - Windows Icon/Cursor image loader
2  *
3  * Copyright (C) 1999 The Free Software Foundation
4  *
5  * Authors: Arjan van de Ven <arjan@fenrus.demon.nl>
6  *          Federico Mena-Quintero <federico@gimp.org>
7  *
8  * Based on io-bmp.c
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  */
25
26 #undef DUMPBIH
27 /*
28
29 Icons are just like BMP's, except for the header.
30  
31 Known bugs:
32         * bi-tonal files aren't tested 
33
34 */
35
36 #include <config.h>
37 #include <stdio.h>
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41 #include <string.h>
42 #include "gdk-pixbuf-private.h"
43 #include "gdk-pixbuf-io.h"
44 #include <errno.h>
45
46 \f
47
48 /* 
49
50 These structures are actually dummies. These are according to
51 the "Windows API reference guide volume II" as written by 
52 Borland International, but GCC fiddles with the alignment of
53 the internal members.
54
55 */
56
57 struct BitmapFileHeader {
58         gushort bfType;
59         guint bfSize;
60         guint reserverd;
61         guint bfOffbits;
62 };
63
64 struct BitmapInfoHeader {
65         guint biSize;
66         guint biWidth;
67         guint biHeight;
68         gushort biPlanes;
69         gushort biBitCount;
70         guint biCompression;
71         guint biSizeImage;
72         guint biXPelsPerMeter;
73         guint biYPelsPerMeter;
74         guint biClrUsed;
75         guint biClrImportant;
76 };
77
78 #ifdef DUMPBIH
79 /* 
80
81 DumpBIH printf's the values in a BitmapInfoHeader to the screen, for 
82 debugging purposes.
83
84 */
85 static void DumpBIH(unsigned char *BIH)
86 {                               
87         printf("biSize      = %i \n",
88                (int)(BIH[3] << 24) + (BIH[2] << 16) + (BIH[1] << 8) + (BIH[0]));
89         printf("biWidth     = %i \n",
90                (int)(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]));
91         printf("biHeight    = %i \n",
92                (int)(BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) +
93                (BIH[8]));
94         printf("biPlanes    = %i \n", (int)(BIH[13] << 8) + (BIH[12]));
95         printf("biBitCount  = %i \n", (int)(BIH[15] << 8) + (BIH[14]));
96         printf("biCompress  = %i \n",
97                (int)(BIH[19] << 24) + (BIH[18] << 16) + (BIH[17] << 8) +
98                (BIH[16]));
99         printf("biSizeImage = %i \n",
100                (int)(BIH[23] << 24) + (BIH[22] << 16) + (BIH[21] << 8) +
101                (BIH[20]));
102         printf("biXPels     = %i \n",
103                (int)(BIH[27] << 24) + (BIH[26] << 16) + (BIH[25] << 8) +
104                (BIH[24]));
105         printf("biYPels     = %i \n",
106                (int)(BIH[31] << 24) + (BIH[30] << 16) + (BIH[29] << 8) +
107                (BIH[28]));
108         printf("biClrUsed   = %i \n",
109                (int)(BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) +
110                (BIH[32]));
111         printf("biClrImprtnt= %i \n",
112                (int)(BIH[39] << 24) + (BIH[38] << 16) + (BIH[37] << 8) +
113                (BIH[36]));
114 }
115 #endif
116
117 /* Progressive loading */
118 struct headerpair {
119         gint width;
120         gint height;
121         guint depth;
122         guint Negative;         /* Negative = 1 -> top down BMP,  
123                                    Negative = 0 -> bottom up BMP */
124 };
125
126 struct ico_progressive_state {
127         ModulePreparedNotifyFunc prepared_func;
128         ModuleUpdatedNotifyFunc updated_func;
129         gpointer user_data;
130
131         gint HeaderSize;        /* The size of the header-part (incl colormap) */
132         guchar *HeaderBuf;      /* The buffer for the header (incl colormap) */
133         gint BytesInHeaderBuf;  /* The size of the allocated HeaderBuf */
134         gint HeaderDone;        /* The nr of bytes actually in HeaderBuf */
135
136         gint LineWidth;         /* The width of a line in bytes */
137         guchar *LineBuf;        /* Buffer for 1 line */
138         gint LineDone;          /* # of bytes in LineBuf */
139         gint Lines;             /* # of finished lines */
140
141         gint Type;              /*  
142                                    32 = RGBA
143                                    24 = RGB
144                                    16 = 555 RGB
145                                    8 = 8 bit colormapped
146                                    4 = 4 bpp colormapped
147                                    1  = 1 bit bitonal 
148                                  */
149
150
151         struct headerpair Header;       /* Decoded (BE->CPU) header */
152         
153         gint                    DIBoffset;
154         gint                    ImageScore;
155
156
157         GdkPixbuf *pixbuf;      /* Our "target" */
158 };
159
160 static gpointer
161 gdk_pixbuf__ico_image_begin_load(ModulePreparedNotifyFunc prepared_func,
162                                  ModuleUpdatedNotifyFunc updated_func,
163                                  gpointer user_data,
164                                  GError **error);
165 static gboolean gdk_pixbuf__ico_image_stop_load(gpointer data, GError **error);
166 static gboolean gdk_pixbuf__ico_image_load_increment(gpointer data,
167                                                      const guchar * buf, guint size,
168                                                      GError **error);
169
170 static void 
171 context_free (struct ico_progressive_state *context)
172 {
173         if (context->LineBuf != NULL)
174                 g_free (context->LineBuf);
175         context->LineBuf = NULL;
176         if (context->HeaderBuf != NULL)
177                 g_free (context->HeaderBuf);
178
179         if (context->pixbuf)
180                 g_object_unref (context->pixbuf);
181
182         g_free (context);
183 }
184                                 
185 /* Shared library entry point --> Can go when generic_image_load
186    enters gdk-pixbuf-io */
187 static GdkPixbuf *
188 gdk_pixbuf__ico_image_load(FILE * f, GError **error)
189 {
190         guchar membuf [4096];
191         size_t length;
192         struct ico_progressive_state *State;
193
194         GdkPixbuf *pb;
195
196         State = gdk_pixbuf__ico_image_begin_load(NULL, NULL, NULL, error);
197
198         if (State == NULL)
199                 return NULL;
200         
201         while (!feof(f)) {
202                 length = fread(membuf, 1, 4096, f);
203                 if (ferror (f)) {
204                         g_set_error (error,
205                                      G_FILE_ERROR,
206                                      g_file_error_from_errno (errno),
207                                      _("Failure reading ICO: %s"), g_strerror (errno));
208                         context_free (State);
209                         return NULL;
210                 }
211                 if (length > 0)
212                         if (!gdk_pixbuf__ico_image_load_increment(State, membuf, length,
213                                                                   error)) {
214                                 context_free (State);
215                                 return NULL;
216                         }
217         }
218         if (State->pixbuf != NULL)
219                 g_object_ref (State->pixbuf);
220         else {
221                 g_set_error (error,
222                              GDK_PIXBUF_ERROR,
223                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
224                              _("ICO file was missing some data (perhaps it was truncated somehow?)"));
225                 context_free (State);
226                 return NULL;
227         }
228
229         pb = State->pixbuf;
230
231         gdk_pixbuf__ico_image_stop_load(State, NULL);
232         return pb;
233 }
234
235 static void DecodeHeader(guchar *Data, gint Bytes,
236                          struct ico_progressive_state *State,
237                          GError **error)
238 {
239 /* For ICO's we have to be very clever. There are multiple images possible
240    in an .ICO. For now, we select (in order of priority):
241      1) The one with the highest number of colors
242      2) The largest one
243  */   
244  
245         gint IconCount = 0; /* The number of icon-versions in the file */
246         guchar *BIH; /* The DIB for the used icon */
247         guchar *Ptr;
248         gint I;
249  
250         /* Step 1: The ICO header */
251  
252         IconCount = (Data[5] << 8) + (Data[4]);
253         
254         State->HeaderSize = 6 + IconCount*16;
255
256         if (State->HeaderSize>State->BytesInHeaderBuf) {
257                 State->HeaderBuf=g_try_realloc(State->HeaderBuf,State->HeaderSize);
258                 if (!State->HeaderBuf) {
259                         g_set_error (error,
260                                      GDK_PIXBUF_ERROR,
261                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
262                                      _("Not enough memory to load icon"));
263                         return;
264                 }
265                 State->BytesInHeaderBuf = State->HeaderSize;
266         }
267         if (Bytes < State->HeaderSize)
268                 return;
269         
270         /* We now have all the "short-specs" of the versions 
271            So we iterate through them and select the best one */
272            
273         State->ImageScore = 0;
274         State->DIBoffset  = 0;
275         Ptr = Data + 6;
276         for (I=0;I<IconCount;I++) {
277                 int ThisWidth, ThisHeight,ThisColors;
278                 int ThisScore;
279                 
280                 ThisWidth = Ptr[0];
281                 ThisHeight = Ptr[1];
282                 ThisColors = (Ptr[2]);
283                 if (ThisColors==0) 
284                         ThisColors=256; /* Yes, this is in the spec, ugh */
285                 
286                 ThisScore = ThisColors*1024+ThisWidth*ThisHeight; 
287
288                 if (ThisScore>State->ImageScore) {
289                         State->ImageScore = ThisScore;
290                         State->DIBoffset = (Ptr[15]<<24)+(Ptr[14]<<16)+
291                                            (Ptr[13]<<8) + (Ptr[12]);
292                                                                  
293                 }
294                 
295                 
296                 Ptr += 16;      
297         } 
298
299         if (State->DIBoffset < 0) {
300                 g_set_error (error,
301                              GDK_PIXBUF_ERROR,
302                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
303                              _("Invalid header in icon"));
304                 return;
305         }
306
307         /* We now have a winner, pointed to in State->DIBoffset,
308            so we know how many bytes are in the "header" part. */
309               
310         State->HeaderSize = State->DIBoffset + 40; /* 40 = sizeof(InfoHeader) */
311         
312         if (State->HeaderSize>State->BytesInHeaderBuf) {
313                 State->HeaderBuf=g_try_realloc(State->HeaderBuf,State->HeaderSize);
314                 if (!State->HeaderBuf) {
315                         g_set_error (error,
316                                      GDK_PIXBUF_ERROR,
317                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
318                                      _("Not enough memory to load icon"));
319                         return;
320                 }
321                 State->BytesInHeaderBuf = State->HeaderSize;
322         }
323         if (Bytes<State->HeaderSize) 
324                 return;   
325         
326         BIH = Data+State->DIBoffset;
327
328 #ifdef DUMPBIH
329         DumpBIH(BIH);
330 #endif  
331         
332         /* Add the palette to the headersize */
333                 
334         State->Header.width =
335             (int)(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]);
336         if (State->Header.width == 0) {
337                 g_set_error (error,
338                              GDK_PIXBUF_ERROR,
339                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
340                              _("Icon has zero width"));
341                 return;
342         }
343         State->Header.height =
344             (int)(BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) + (BIH[8])/2;
345             /* /2 because the BIH height includes the transparency mask */
346         if (State->Header.height == 0) {
347                 g_set_error (error,
348                              GDK_PIXBUF_ERROR,
349                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
350                              _("Icon has zero height"));
351                 return;
352         }
353         State->Header.depth = (BIH[15] << 8) + (BIH[14]);;
354
355         State->Type = State->Header.depth;      
356         if (State->Lines>=State->Header.height)
357                 State->Type = 1; /* The transparency mask is 1 bpp */
358         
359         
360         
361         /* Determine the  palette size. If the header indicates 0, it
362            is actually the maximum for the bpp. You have to love the
363            guys who made the spec. */
364         I = (int)(BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) + (BIH[32]);
365         I = I*4;
366         if ((I==0)&&(State->Type==1))
367                 I = 2*4;
368         if ((I==0)&&(State->Type==4))
369                 I = 16*4;
370         if ((I==0)&&(State->Type==8))
371                 I = 256*4;
372         
373         State->HeaderSize+=I;
374         
375         if (State->HeaderSize>State->BytesInHeaderBuf) {
376                 State->HeaderBuf=g_try_realloc(State->HeaderBuf,State->HeaderSize);
377                 if (!State->HeaderBuf) {
378                         g_set_error (error,
379                                      GDK_PIXBUF_ERROR,
380                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
381                                      _("Not enough memory to load icon"));
382                         return;
383                 }
384                 State->BytesInHeaderBuf = State->HeaderSize;
385         }
386         if (Bytes < State->HeaderSize)
387                 return;
388
389         if ((BIH[16] != 0) || (BIH[17] != 0) || (BIH[18] != 0)
390             || (BIH[19] != 0)) {
391                 /* FIXME: is this the correct message? */
392                 g_set_error (error,
393                              GDK_PIXBUF_ERROR,
394                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
395                              _("Compressed icons are not supported"));
396                 return;
397         }
398
399         /* Negative heights mean top-down pixel-order */
400         if (State->Header.height < 0) {
401                 State->Header.height = -State->Header.height;
402                 State->Header.Negative = 1;
403         }
404         if (State->Header.width < 0) {
405                 State->Header.width = -State->Header.width;
406         }
407         g_assert (State->Header.width > 0);
408         g_assert (State->Header.height > 0);
409
410         if (State->Type == 32)
411                 State->LineWidth = State->Header.width * 4;
412         else if (State->Type == 24)
413                 State->LineWidth = State->Header.width * 3;
414         else if (State->Type == 16)
415                 State->LineWidth = State->Header.height * 2;
416         else if (State->Type == 8)
417                 State->LineWidth = State->Header.width * 1;
418         else if (State->Type == 4)
419                 State->LineWidth = (State->Header.width+1)/2;
420         else if (State->Type == 1) {
421                 State->LineWidth = State->Header.width / 8;
422                 if ((State->Header.width & 7) != 0)
423                         State->LineWidth++;
424         } else {
425           g_set_error (error,
426                        GDK_PIXBUF_ERROR,
427                        GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
428                        _("Unsupported icon type"));
429           return;
430         }
431
432         /* Pad to a 32 bit boundary */
433         if (((State->LineWidth % 4) > 0))
434                 State->LineWidth = (State->LineWidth / 4) * 4 + 4;
435
436
437         if (State->LineBuf == NULL) {
438                 State->LineBuf = g_try_malloc(State->LineWidth);
439                 if (!State->LineBuf) {
440                         g_set_error (error,
441                                      GDK_PIXBUF_ERROR,
442                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
443                                      _("Not enough memory to load icon"));
444                         return;
445                 }
446         }
447
448         g_assert(State->LineBuf != NULL);
449
450
451         if (State->pixbuf == NULL) {
452                 State->pixbuf =
453                     gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
454                                    State->Header.width,
455                                    State->Header.height);
456                 if (!State->pixbuf) {
457                         g_set_error (error,
458                                      GDK_PIXBUF_ERROR,
459                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
460                                      _("Not enough memory to load icon"));
461                         return;
462                 }
463
464                 if (State->prepared_func != NULL)
465                         /* Notify the client that we are ready to go */
466                         (*State->prepared_func) (State->pixbuf,
467                                                  NULL,
468                                                  State->user_data);
469
470         }
471
472 }
473
474 /* 
475  * func - called when we have pixmap created (but no image data)
476  * user_data - passed as arg 1 to func
477  * return context (opaque to user)
478  */
479
480 static gpointer
481 gdk_pixbuf__ico_image_begin_load(ModulePreparedNotifyFunc prepared_func,
482                                  ModuleUpdatedNotifyFunc updated_func,
483                                  gpointer user_data,
484                                  GError **error)
485 {
486         struct ico_progressive_state *context;
487
488         context = g_new0(struct ico_progressive_state, 1);
489         context->prepared_func = prepared_func;
490         context->updated_func = updated_func;
491         context->user_data = user_data;
492
493         context->HeaderSize = 54;
494         context->HeaderBuf = g_try_malloc(14 + 40 + 4*256 + 512);
495         if (!context->HeaderBuf) {
496                 g_set_error (error,
497                              GDK_PIXBUF_ERROR,
498                              GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
499                              _("Not enough memory to load ICO file"));
500                 return NULL;
501         }
502         /* 4*256 for the colormap */
503         context->BytesInHeaderBuf = 14 + 40 + 4*256 + 512 ;
504         context->HeaderDone = 0;
505
506         context->LineWidth = 0;
507         context->LineBuf = NULL;
508         context->LineDone = 0;
509         context->Lines = 0;
510
511         context->Type = 0;
512
513         memset(&context->Header, 0, sizeof(struct headerpair));
514
515
516         context->pixbuf = NULL;
517
518
519         return (gpointer) context;
520 }
521
522 /*
523  * context - returned from image_begin_load
524  *
525  * free context, unref gdk_pixbuf
526  */
527 gboolean gdk_pixbuf__ico_image_stop_load(gpointer data,
528                                          GError **error)
529 {
530         struct ico_progressive_state *context =
531             (struct ico_progressive_state *) data;
532
533         /* FIXME this thing needs to report errors if
534          * we have unused image data
535          */
536
537         g_return_val_if_fail(context != NULL, TRUE);
538         
539         context_free (context);
540         return TRUE;
541 }
542
543 static void
544 OneLine32 (struct ico_progressive_state *context)
545 {
546         gint X;
547         guchar *Pixels;
548
549         X = 0;
550         if (context->Header.Negative == 0)
551                 Pixels = (context->pixbuf->pixels +
552                           context->pixbuf->rowstride *
553                           (context->Header.height - context->Lines - 1));
554         else
555                 Pixels = (context->pixbuf->pixels +
556                           context->pixbuf->rowstride *
557                           context->Lines);
558         while (X < context->Header.width) {
559                 Pixels[X * 4 + 0] = context->LineBuf[X * 4 + 2];
560                 Pixels[X * 4 + 1] = context->LineBuf[X * 4 + 1];
561                 Pixels[X * 4 + 2] = context->LineBuf[X * 4 + 0];
562                 Pixels[X * 4 + 3] = context->LineBuf[X * 4 + 3];
563                 X++;
564         }
565 }
566
567 static void OneLine24(struct ico_progressive_state *context)
568 {
569         gint X;
570         guchar *Pixels;
571
572         X = 0;
573         if (context->Header.Negative == 0)
574                 Pixels = (context->pixbuf->pixels +
575                           context->pixbuf->rowstride *
576                           (context->Header.height - context->Lines - 1));
577         else
578                 Pixels = (context->pixbuf->pixels +
579                           context->pixbuf->rowstride *
580                           context->Lines);
581         while (X < context->Header.width) {
582                 Pixels[X * 4 + 0] = context->LineBuf[X * 3 + 2];
583                 Pixels[X * 4 + 1] = context->LineBuf[X * 3 + 1];
584                 Pixels[X * 4 + 2] = context->LineBuf[X * 3 + 0];
585                 X++;
586         }
587
588 }
589
590 static void
591 OneLine16 (struct ico_progressive_state *context)
592 {
593         int i;
594         guchar *pixels;
595         guchar *src;
596
597         if (context->Header.Negative == 0)
598                 pixels = (context->pixbuf->pixels +
599                           context->pixbuf->rowstride * (context->Header.height - context->Lines - 1));
600         else
601                 pixels = (context->pixbuf->pixels +
602                           context->pixbuf->rowstride * context->Lines);
603
604         src = context->LineBuf;
605
606         for (i = 0; i < context->Header.width; i++) {
607                 int v, r, g, b;
608
609                 v = (int) src[0] | ((int) src[1] << 8);
610                 src += 2;
611
612                 /* Extract 5-bit RGB values */
613
614                 r = (v >> 10) & 0x1f;
615                 g = (v >> 5) & 0x1f;
616                 b = v & 0x1f;
617
618                 /* Fill the rightmost bits to form 8-bit values */
619
620                 *pixels++ = (r << 3) | (r >> 2);
621                 *pixels++ = (g << 3) | (g >> 2);
622                 *pixels++ = (b << 3) | (b >> 2);
623                 pixels++; /* skip alpha channel */
624         }
625 }
626
627
628 static void OneLine8(struct ico_progressive_state *context)
629 {
630         gint X;
631         guchar *Pixels;
632
633         X = 0;
634         if (context->Header.Negative == 0)
635                 Pixels = (context->pixbuf->pixels +
636                           context->pixbuf->rowstride *
637                           (context->Header.height - context->Lines - 1));
638         else
639                 Pixels = (context->pixbuf->pixels +
640                           context->pixbuf->rowstride *
641                           context->Lines);
642         while (X < context->Header.width) {
643                 /* The joys of having a BGR byteorder */
644                 Pixels[X * 4 + 0] =
645                     context->HeaderBuf[4 * context->LineBuf[X] + 42+context->DIBoffset];
646                 Pixels[X * 4 + 1] =
647                     context->HeaderBuf[4 * context->LineBuf[X] + 41+context->DIBoffset];
648                 Pixels[X * 4 + 2] =
649                     context->HeaderBuf[4 * context->LineBuf[X] + 40+context->DIBoffset];
650                 X++;
651         }
652 }
653 static void OneLine4(struct ico_progressive_state *context)
654 {
655         gint X;
656         guchar *Pixels;
657
658         X = 0;
659         if (context->Header.Negative == 0)
660                 Pixels = (context->pixbuf->pixels +
661                           context->pixbuf->rowstride *
662                           (context->Header.height - context->Lines - 1));
663         else
664                 Pixels = (context->pixbuf->pixels +
665                           context->pixbuf->rowstride *
666                           context->Lines);
667         
668         while (X < context->Header.width) {
669                 guchar Pix;
670                 
671                 Pix = context->LineBuf[X/2];
672
673                 Pixels[X * 4 + 0] =
674                     context->HeaderBuf[4 * (Pix>>4) + 42+context->DIBoffset];
675                 Pixels[X * 4 + 1] =
676                     context->HeaderBuf[4 * (Pix>>4) + 41+context->DIBoffset];
677                 Pixels[X * 4 + 2] =
678                     context->HeaderBuf[4 * (Pix>>4) + 40+context->DIBoffset];
679                 X++;
680                 if (X<context->Header.width) { 
681                         /* Handle the other 4 bit pixel only when there is one */
682                         Pixels[X * 4 + 0] =
683                             context->HeaderBuf[4 * (Pix&15) + 42+context->DIBoffset];
684                         Pixels[X * 4 + 1] =
685                             context->HeaderBuf[4 * (Pix&15) + 41+context->DIBoffset];
686                         Pixels[X * 4 + 2] =
687                             context->HeaderBuf[4 * (Pix&15) + 40+context->DIBoffset];
688                         X++;
689                 }
690         }
691         
692 }
693
694 static void OneLine1(struct ico_progressive_state *context)
695 {
696         gint X;
697         guchar *Pixels;
698
699         X = 0;
700         if (context->Header.Negative == 0)
701                 Pixels = (context->pixbuf->pixels +
702                           context->pixbuf->rowstride *
703                           (context->Header.height - context->Lines - 1));
704         else
705                 Pixels = (context->pixbuf->pixels +
706                           context->pixbuf->rowstride *
707                           context->Lines);
708         while (X < context->Header.width) {
709                 int Bit;
710
711                 Bit = (context->LineBuf[X / 8]) >> (7 - (X & 7));
712                 Bit = Bit & 1;
713                 /* The joys of having a BGR byteorder */
714                 Pixels[X * 4 + 0] = Bit*255;
715                 Pixels[X * 4 + 1] = Bit*255;
716                 Pixels[X * 4 + 2] = Bit*255;
717                 X++;
718         }
719 }
720
721 static void OneLineTransp(struct ico_progressive_state *context)
722 {
723         gint X;
724         guchar *Pixels;
725
726         X = 0;
727         if (context->Header.Negative == 0)
728                 Pixels = (context->pixbuf->pixels +
729                           context->pixbuf->rowstride *
730                           (2*context->Header.height - context->Lines - 1));
731         else
732                 Pixels = (context->pixbuf->pixels +
733                           context->pixbuf->rowstride *
734                           (context->Lines-context->Header.height));
735         while (X < context->Header.width) {
736                 int Bit;
737
738                 Bit = (context->LineBuf[X / 8]) >> (7 - (X & 7));
739                 Bit = Bit & 1;
740                 /* The joys of having a BGR byteorder */
741                 Pixels[X * 4 + 3] = 255-Bit*255;
742 #if 0           
743                 if (Bit){
744                   Pixels[X*4+0] = 255;
745                   Pixels[X*4+1] = 255;
746                 } else {
747                   Pixels[X*4+0] = 0;
748                   Pixels[X*4+1] = 0;
749                 }
750 #endif          
751                 X++;
752         }
753 }
754
755
756 static void OneLine(struct ico_progressive_state *context)
757 {
758         context->LineDone = 0;
759         
760         if (context->Lines >= context->Header.height*2) {
761                 return;
762         }
763                 
764         if (context->Lines <context->Header.height) {           
765                 if (context->Type == 32)
766                         OneLine32 (context);
767                 else if (context->Type == 24)
768                         OneLine24(context);
769                 else if (context->Type == 16)
770                         OneLine16 (context);
771                 else if (context->Type == 8)
772                         OneLine8(context);
773                 else if (context->Type == 4)
774                         OneLine4(context);
775                 else if (context->Type == 1)
776                         OneLine1(context);
777                 else 
778                         g_assert_not_reached ();
779         } else
780                 OneLineTransp(context);
781         
782         context->Lines++;
783         if (context->Lines>=context->Header.height) {
784                 context->Type = 1;
785                 context->LineWidth = context->Header.width / 8;
786                 if ((context->Header.width & 7) != 0)
787                         context->LineWidth++;
788                 /* Pad to a 32 bit boundary */
789                 if (((context->LineWidth % 4) > 0))
790                         context->LineWidth = (context->LineWidth / 4) * 4 + 4;
791                         
792         }
793           
794
795         if (context->updated_func != NULL) {
796                 (*context->updated_func) (context->pixbuf,
797                                           0,
798                                           context->Lines,
799                                           context->Header.width,
800                                           context->Header.height,
801                                           context->user_data);
802
803         }
804 }
805
806 /*
807  * context - from image_begin_load
808  * buf - new image data
809  * size - length of new image data
810  *
811  * append image data onto inrecrementally built output image
812  */
813 static gboolean
814 gdk_pixbuf__ico_image_load_increment(gpointer data,
815                                      const guchar * buf,
816                                      guint size,
817                                      GError **error)
818 {
819         struct ico_progressive_state *context =
820             (struct ico_progressive_state *) data;
821
822         gint BytesToCopy;
823
824         while (size > 0) {
825                 g_assert(context->LineDone >= 0);
826                 if (context->HeaderDone < context->HeaderSize) {        /* We still 
827                                                                            have headerbytes to do */
828                         BytesToCopy =
829                             context->HeaderSize - context->HeaderDone;
830                         if (BytesToCopy > size)
831                                 BytesToCopy = size;
832
833                         memmove(context->HeaderBuf + context->HeaderDone,
834                                buf, BytesToCopy);
835
836                         size -= BytesToCopy;
837                         buf += BytesToCopy;
838                         context->HeaderDone += BytesToCopy;
839                 } 
840                 else {
841                         BytesToCopy =
842                             context->LineWidth - context->LineDone;
843                         if (BytesToCopy > size)
844                                 BytesToCopy = size;
845
846                         if (BytesToCopy > 0) {
847                                 memmove(context->LineBuf +
848                                        context->LineDone, buf,
849                                        BytesToCopy);
850
851                                 size -= BytesToCopy;
852                                 buf += BytesToCopy;
853                                 context->LineDone += BytesToCopy;
854                         }
855                         if ((context->LineDone >= context->LineWidth) &&
856                             (context->LineWidth > 0))
857                                 OneLine(context);
858
859
860                 }
861
862                 if (context->HeaderDone >= 6) {
863                         GError *decode_err = NULL;
864                         DecodeHeader(context->HeaderBuf,
865                                      context->HeaderDone, context, &decode_err);
866                         if (decode_err) {
867                                 g_propagate_error (error, decode_err);
868                                 return FALSE;
869                         }
870                 }
871         }
872
873         return TRUE;
874 }
875
876 void
877 gdk_pixbuf__ico_fill_vtable (GdkPixbufModule *module)
878 {
879   module->load = gdk_pixbuf__ico_image_load;
880   module->begin_load = gdk_pixbuf__ico_image_begin_load;
881   module->stop_load = gdk_pixbuf__ico_image_stop_load;
882   module->load_increment = gdk_pixbuf__ico_image_load_increment;
883 }