]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-gif.c
Properly handle gc->clip_region == NULL>
[~andy/gtk] / gdk-pixbuf / io-gif.c
1 /* GdkPixbuf library - GIF image loader
2  *
3  * Copyright (C) 1999 Mark Crichton
4  * Copyright (C) 1999 The Free Software Foundation
5  *
6  * Authors: Jonathan Blandford <jrb@redhat.com>
7  *          Adapted from the gimp gif filter written by Adam Moss <adam@gimp.org>
8  *          Gimp work based on earlier work.
9  *          Permission to relicense under the LGPL obtained.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the
23  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24  * Boston, MA 02111-1307, USA.
25  */
26
27 /* This loader is very hairy code.
28  *
29  * The main loop was not designed for incremental loading, so when it was hacked
30  * in it got a bit messy.  Basicly, every function is written to expect a failed
31  * read_gif, and lets you call it again assuming that the bytes are there.
32  *
33  * A note on Animations:
34  * Currently, it doesn't correctly read the different colormap per frame.  This
35  * needs implementing sometime.
36  *
37  * Return vals.
38  * Unless otherwise specified, these are the return vals for most functions:
39  *
40  *  0 -> success
41  * -1 -> more bytes needed.
42  * -2 -> failure; abort the load
43  * -3 -> control needs to be passed back to the main loop
44  *        \_ (most of the time returning 0 will get this, but not always)
45  *
46  * >1 -> for functions that get a guchar, the char will be returned.
47  *
48  * -jrb (11/03/1999)
49  */
50
51 /*
52  * If you have any images that crash this code, please, please let me know and
53  * send them to me.
54  *                                            <jrb@redhat.com>
55  */
56
57 \f
58
59 #include <config.h>
60 #include <stdio.h>
61 #include <string.h>
62 #include "gdk-pixbuf-private.h"
63 #include "gdk-pixbuf-io.h"
64
65 \f
66
67 #define MAXCOLORMAPSIZE  256
68 #define MAX_LZW_BITS     12
69
70 #define INTERLACE          0x40
71 #define LOCALCOLORMAP      0x80
72 #define BitSet(byte, bit)  (((byte) & (bit)) == (bit))
73 #define LM_to_uint(a,b)         (((b)<<8)|(a))
74
75 \f
76
77 typedef unsigned char CMap[3][MAXCOLORMAPSIZE];
78
79 /* Possible states we can be in. */
80 enum {
81         GIF_START,
82         GIF_GET_COLORMAP,
83         GIF_GET_NEXT_STEP,
84         GIF_GET_FRAME_INFO,
85         GIF_GET_EXTENTION,
86         GIF_GET_COLORMAP2,
87         GIF_PREPARE_LZW,
88         GIF_LZW_FILL_BUFFER,
89         GIF_LZW_CLEAR_CODE,
90         GIF_GET_LZW,
91         GIF_DONE,
92 };
93
94
95 typedef struct _Gif89 Gif89;
96 struct _Gif89
97 {
98         int transparent;
99         int delay_time;
100         int input_flag;
101         int disposal;
102 };
103
104 typedef struct _GifContext GifContext;
105 struct _GifContext
106 {
107         int state; /* really only relevant for progressive loading */
108         unsigned int width;
109         unsigned int height;
110         CMap color_map;
111         CMap frame_color_map;
112         unsigned int bit_pixel;
113         unsigned int color_resolution;
114         unsigned int background;
115         unsigned int aspect_ratio;
116         GdkPixbuf *pixbuf;
117         GdkPixbufAnimation *animation;
118         GdkPixbufFrame *frame;
119         Gif89 gif89;
120
121         /* stuff per frame.  As we only support the first one, not so
122          * relevant.  But still needed */
123         int frame_len;
124         int frame_height;
125         int frame_interlace;
126         int x_offset;
127         int y_offset;
128
129         /* Static read only */
130         FILE *file;
131
132         /* progressive read, only. */
133         ModulePreparedNotifyFunc prepare_func;
134         ModuleUpdatedNotifyFunc update_func;
135         ModuleFrameDoneNotifyFunc frame_done_func;
136         ModuleAnimationDoneNotifyFunc anim_done_func;
137         gpointer user_data;
138         guchar *buf;
139         guint ptr;
140         guint size;
141         guint amount_needed;
142
143         /* colormap context */
144         gint colormap_index;
145         gint colormap_flag;
146
147         /* extension context */
148         guchar extension_label;
149         guchar extension_flag;
150
151         /* get block context */
152         guchar block_count;
153         guchar block_buf[280];
154         gint block_ptr;
155
156         int old_state; /* used by lzw_fill buffer */
157         /* get_code context */
158         int code_curbit;
159         int code_lastbit;
160         int code_done;
161         int code_last_byte;
162         int lzw_code_pending;
163
164         /* lzw context */
165         gint lzw_fresh;
166         gint lzw_code_size;
167         guchar lzw_set_code_size;
168         gint lzw_max_code;
169         gint lzw_max_code_size;
170         gint lzw_firstcode;
171         gint lzw_oldcode;
172         gint lzw_clear_code;
173         gint lzw_end_code;
174         gint *lzw_sp;
175
176         gint lzw_table[2][(1 << MAX_LZW_BITS)];
177         gint lzw_stack[(1 << (MAX_LZW_BITS)) * 2 + 1];
178
179         /* painting context */
180         gint draw_xpos;
181         gint draw_ypos;
182         gint draw_pass;
183
184         /* error pointer */
185         GError **error;
186 };
187
188 static int GetDataBlock (GifContext *, unsigned char *);
189
190 \f
191
192 #ifdef IO_GIFDEBUG
193 static int count = 0;
194 #endif
195
196 /* Returns TRUE if read is OK,
197  * FALSE if more memory is needed. */
198 static int
199 gif_read (GifContext *context, guchar *buffer, size_t len)
200 {
201         gint retval;
202 #ifdef IO_GIFDEBUG
203         gint i;
204 #endif
205         if (context->file) {
206 #ifdef IO_GIFDEBUG
207                 count += len;
208                 g_print ("Fsize :%d\tcount :%d\t", len, count);
209 #endif
210                 retval = (fread(buffer, len, 1, context->file) != 0);                
211 #ifdef IO_GIFDEBUG
212                 if (len < 100) {
213                         for (i = 0; i < len; i++)
214                                 g_print ("%d ", buffer[i]);
215                 }
216                 g_print ("\n");
217 #endif
218                 
219                 return retval;
220         } else {
221 #ifdef IO_GIFDEBUG
222 /*              g_print ("\tlooking for %d bytes.  size == %d, ptr == %d\n", len, context->size, context->ptr); */
223 #endif
224                 if ((context->size - context->ptr) >= len) {
225 #ifdef IO_GIFDEBUG
226                         count += len;
227 #endif
228                         memcpy (buffer, context->buf + context->ptr, len);
229                         context->ptr += len;
230                         context->amount_needed = 0;
231 #ifdef IO_GIFDEBUG
232                         g_print ("Psize :%d\tcount :%d\t", len, count);
233                         if (len < 100) {
234                                 for (i = 0; i < len; i++)
235                                         g_print ("%d ", buffer[i]);
236                         }
237                         g_print ("\n");
238 #endif
239                         return TRUE;
240                 }
241                 context->amount_needed = len - (context->size - context->ptr);
242         }
243         return 0;
244 }
245
246 /* Changes the stage to be GIF_GET_COLORMAP */
247 static void
248 gif_set_get_colormap (GifContext *context)
249 {
250         context->colormap_flag = TRUE;
251         context->colormap_index = 0;
252         context->state = GIF_GET_COLORMAP;
253 }
254
255 static void
256 gif_set_get_colormap2 (GifContext *context)
257 {
258         context->colormap_flag = TRUE;
259         context->colormap_index = 0;
260         context->state = GIF_GET_COLORMAP2;
261 }
262
263 static gint
264 gif_get_colormap (GifContext *context)
265 {
266         unsigned char rgb[3];
267
268         while (context->colormap_index < context->bit_pixel) {
269                 if (!gif_read (context, rgb, sizeof (rgb))) {
270                         /*g_message (_("GIF: bad colormap\n"));*/
271                         return -1;
272                 }
273
274                 context->color_map[0][context->colormap_index] = rgb[0];
275                 context->color_map[1][context->colormap_index] = rgb[1];
276                 context->color_map[2][context->colormap_index] = rgb[2];
277
278                 context->colormap_flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]);
279                 context->colormap_index ++;
280         }
281
282         return 0;
283 }
284
285 /*
286  * in order for this function to work, we need to perform some black magic.
287  * We want to return -1 to let the calling function know, as before, that it needs
288  * more bytes.  If we return 0, we were able to successfully read all block->count bytes.
289  * Problem is, we don't want to reread block_count every time, so we check to see if
290  * context->block_count is 0 before we read in the function.
291  *
292  * As a result, context->block_count MUST be 0 the first time the get_data_block is called
293  * within a context, and cannot be 0 the second time it's called.
294  */
295
296 static int
297 get_data_block (GifContext *context,
298                 unsigned char *buf,
299                 gint *empty_block)
300 {
301
302         if (context->block_count == 0) {
303                 if (!gif_read (context, &context->block_count, 1)) {
304                         return -1;
305                 }
306         }
307
308         if (context->block_count == 0)
309                 if (empty_block) {
310                         *empty_block = TRUE;
311                         return 0;
312                 }
313
314         if (!gif_read (context, buf, context->block_count)) {
315                 return -1;
316         }
317
318         return 0;
319 }
320
321 static void
322 gif_set_get_extension (GifContext *context)
323 {
324         context->state = GIF_GET_EXTENTION;
325         context->extension_flag = TRUE;
326         context->extension_label = 0;
327         context->block_count = 0;
328         context->block_ptr = 0;
329 }
330
331 static int
332 gif_get_extension (GifContext *context)
333 {
334         gint retval;
335         gint empty_block = FALSE;
336
337         if (context->extension_flag) {
338                 if (context->extension_label == 0) {
339                         /* I guess bad things can happen if we have an extension of 0 )-: */
340                         /* I should look into this sometime */
341                         if (!gif_read (context, & context->extension_label , 1)) {
342                                 return -1;
343                         }
344                 }
345
346                 switch (context->extension_label) {
347                 case 0xf9:                      /* Graphic Control Extension */
348                         retval = get_data_block (context, (unsigned char *) context->block_buf, NULL);
349                         if (retval != 0)
350                                 return retval;
351                         if (context->pixbuf == NULL) {
352                                 /* I only want to set the transparency if I haven't
353                                  * created the pixbuf yet. */
354                                 context->gif89.disposal = (context->block_buf[0] >> 2) & 0x7;
355                                 context->gif89.input_flag = (context->block_buf[0] >> 1) & 0x1;
356                                 context->gif89.delay_time = LM_to_uint (context->block_buf[1], context->block_buf[2]);
357                                 
358                                 if ((context->block_buf[0] & 0x1) != 0) {
359                                         context->gif89.transparent = context->block_buf[3];
360                                 } else {
361                                         context->gif89.transparent = -1;
362                                 }
363                         }
364
365                         /* Now we've successfully loaded this one, we continue on our way */
366                         context->block_count = 0;
367                         context->extension_flag = FALSE;
368                 default:
369                         /* Unhandled extension */
370                         break;
371                 }
372         }
373         /* read all blocks, until I get an empty block, in case there was an extension I didn't know about. */
374         do {
375                 retval = get_data_block (context, (unsigned char *) context->block_buf, &empty_block);
376                 if (retval != 0)
377                         return retval;
378                 context->block_count = 0;
379         } while (!empty_block);
380
381         return 0;
382 }
383
384 static int ZeroDataBlock = FALSE;
385
386 static int
387 GetDataBlock (GifContext *context,
388               unsigned char *buf)
389 {
390 /*      unsigned char count; */
391
392         if (!gif_read (context, &context->block_count, 1)) {
393                 /*g_message (_("GIF: error in getting DataBlock size\n"));*/
394                 return -1;
395         }
396
397         ZeroDataBlock = context->block_count == 0;
398
399         if ((context->block_count != 0) && (!gif_read (context, buf, context->block_count))) {
400                 /*g_message (_("GIF: error in reading DataBlock\n"));*/
401                 return -1;
402         }
403
404         return context->block_count;
405 }
406
407
408 static void
409 gif_set_lzw_fill_buffer (GifContext *context)
410 {
411         context->block_count = 0;
412         context->old_state = context->state;
413         context->state = GIF_LZW_FILL_BUFFER;
414 }
415
416 static int
417 gif_lzw_fill_buffer (GifContext *context)
418 {
419         gint retval;
420
421         if (context->code_done) {
422                 if (context->code_curbit >= context->code_lastbit) {
423                         g_set_error (context->error,
424                                      GDK_PIXBUF_ERROR,
425                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
426                                      _("GIF file was missing some data (perhaps it was truncated somehow?)"));
427
428                         return -2;
429                 }
430                 /* Is this supposed to be an error or what? */
431                 /* g_message ("trying to read more data after we've done stuff\n"); */
432                 g_set_error (context->error,
433                              GDK_PIXBUF_ERROR,
434                              GDK_PIXBUF_ERROR_FAILED,
435                              _("Internal error in the GIF loader (%s)"),
436                              G_STRLOC);
437                 
438                 return -2;
439         }
440
441         context->block_buf[0] = context->block_buf[context->code_last_byte - 2];
442         context->block_buf[1] = context->block_buf[context->code_last_byte - 1];
443
444         retval = get_data_block (context, &context->block_buf[2], NULL);
445
446         if (retval == -1)
447                 return -1;
448
449         if (context->block_count == 0)
450                 context->code_done = TRUE;
451
452         context->code_last_byte = 2 + context->block_count;
453         context->code_curbit = (context->code_curbit - context->code_lastbit) + 16;
454         context->code_lastbit = (2 + context->block_count) * 8;
455
456         context->state = context->old_state;
457         return 0;
458 }
459
460 static int
461 get_code (GifContext *context,
462           int   code_size)
463 {
464         int i, j, ret;
465
466         if ((context->code_curbit + code_size) >= context->code_lastbit){
467                 gif_set_lzw_fill_buffer (context);
468                 return -3;
469         }
470
471         ret = 0;
472         for (i = context->code_curbit, j = 0; j < code_size; ++i, ++j)
473                 ret |= ((context->block_buf[i / 8] & (1 << (i % 8))) != 0) << j;
474
475         context->code_curbit += code_size;
476
477         return ret;
478 }
479
480
481 static void
482 set_gif_lzw_clear_code (GifContext *context)
483 {
484         context->state = GIF_LZW_CLEAR_CODE;
485         context->lzw_code_pending = -1;
486 }
487
488 static int
489 gif_lzw_clear_code (GifContext *context)
490 {
491         gint code;
492
493         code = get_code (context, context->lzw_code_size);
494         if (code == -3)
495                 return -0;
496
497         context->lzw_firstcode = context->lzw_oldcode = code;
498         context->lzw_code_pending = code;
499         context->state = GIF_GET_LZW;
500         return 0;
501 }
502
503 static int
504 lzw_read_byte (GifContext *context)
505 {
506         int code, incode;
507         gint retval;
508         gint my_retval;
509         register int i;
510
511         if (context->lzw_code_pending != -1) {
512                 retval = context->lzw_code_pending;
513                 context->lzw_code_pending = -1;
514                 return retval;
515         }
516
517         if (context->lzw_fresh) {
518                 context->lzw_fresh = FALSE;
519                 do {
520                         retval = get_code (context, context->lzw_code_size);
521                         if (retval < 0) {
522                                 return retval;
523                         }
524
525                         context->lzw_firstcode = context->lzw_oldcode = retval;
526                 } while (context->lzw_firstcode == context->lzw_clear_code);
527                 return context->lzw_firstcode;
528         }
529
530         if (context->lzw_sp > context->lzw_stack) {
531                 my_retval = *--(context->lzw_sp);
532                 return my_retval;
533         }
534
535         while ((code = get_code (context, context->lzw_code_size)) >= 0) {
536                 if (code == context->lzw_clear_code) {
537                         for (i = 0; i < context->lzw_clear_code; ++i) {
538                                 context->lzw_table[0][i] = 0;
539                                 context->lzw_table[1][i] = i;
540                         }
541                         for (; i < (1 << MAX_LZW_BITS); ++i)
542                                 context->lzw_table[0][i] = context->lzw_table[1][i] = 0;
543                         context->lzw_code_size = context->lzw_set_code_size + 1;
544                         context->lzw_max_code_size = 2 * context->lzw_clear_code;
545                         context->lzw_max_code = context->lzw_clear_code + 2;
546                         context->lzw_sp = context->lzw_stack;
547
548                         set_gif_lzw_clear_code (context);
549                         return -3;
550                 } else if (code == context->lzw_end_code) {
551                         int count;
552                         unsigned char buf[260];
553
554                         /*g_error (" DID WE EVER EVER GET HERE\n");*/
555                         g_warning ("Unhandled Case.  If you have an image that causes this, let me <jrb@redhat.com> know.\n");
556
557                         if (ZeroDataBlock) {
558                                 return -2;
559                         }
560
561                         while ((count = GetDataBlock (context, buf)) > 0)
562                                 ;
563
564                         if (count != 0) {
565                                 /*g_print (_("GIF: missing EOD in data stream (common occurence)"));*/
566                                 return -2;
567                         }
568                 }
569
570                 incode = code;
571
572                 if (code >= context->lzw_max_code) {
573                         *(context->lzw_sp)++ = context->lzw_firstcode;
574                         code = context->lzw_oldcode;
575                 }
576
577                 while (code >= context->lzw_clear_code) {
578                         *(context->lzw_sp)++ = context->lzw_table[1][code];
579
580                         if (code == context->lzw_table[0][code]) {
581                                 g_set_error (context->error,
582                                              GDK_PIXBUF_ERROR,
583                                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
584                                              _("Circular table entry in GIF file"));
585                                 return -2;
586                         }
587                         code = context->lzw_table[0][code];
588                 }
589
590                 *(context->lzw_sp)++ = context->lzw_firstcode = context->lzw_table[1][code];
591
592                 if ((code = context->lzw_max_code) < (1 << MAX_LZW_BITS)) {
593                         context->lzw_table[0][code] = context->lzw_oldcode;
594                         context->lzw_table[1][code] = context->lzw_firstcode;
595                         ++context->lzw_max_code;
596                         if ((context->lzw_max_code >= context->lzw_max_code_size) &&
597                             (context->lzw_max_code_size < (1 << MAX_LZW_BITS))) {
598                                 context->lzw_max_code_size *= 2;
599                                 ++context->lzw_code_size;
600                         }
601                 }
602
603                 context->lzw_oldcode = incode;
604
605                 if (context->lzw_sp > context->lzw_stack) {
606                         my_retval = *--(context->lzw_sp);
607                         return my_retval;
608                 }
609         }
610         return code;
611 }
612
613 static void
614 gif_set_get_lzw (GifContext *context)
615 {
616         context->state = GIF_GET_LZW;
617         context->draw_xpos = 0;
618         context->draw_ypos = 0;
619         context->draw_pass = 0;
620 }
621
622 static void
623 gif_fill_in_pixels (GifContext *context, guchar *dest, gint offset, guchar v)
624 {
625         guchar *pixel = NULL;
626
627         if (context->gif89.transparent != -1) {
628                 pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 4;
629                 *pixel = context->color_map [0][(guchar) v];
630                 *(pixel+1) = context->color_map [1][(guchar) v];
631                 *(pixel+2) = context->color_map [2][(guchar) v];
632                 *(pixel+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 65535);
633         } else {
634                 pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 3;
635                 *pixel = context->color_map [0][(guchar) v];
636                 *(pixel+1) = context->color_map [1][(guchar) v];
637                 *(pixel+2) = context->color_map [2][(guchar) v];
638         }
639 }
640
641
642 /* only called if progressive and interlaced */
643 static void
644 gif_fill_in_lines (GifContext *context, guchar *dest, guchar v)
645 {
646         switch (context->draw_pass) {
647         case 0:
648                 if (context->draw_ypos > 4) {
649                         gif_fill_in_pixels (context, dest, -4, v);
650                         gif_fill_in_pixels (context, dest, -3, v);
651                 }
652                 if (context->draw_ypos < (context->frame_height - 4)) {
653                         gif_fill_in_pixels (context, dest, 3, v);
654                         gif_fill_in_pixels (context, dest, 4, v);
655                 }
656                 /* we don't need a break here.  We draw the outer pixels first, then the
657                  * inner ones, then the innermost ones.  case 0 needs to draw all 3 bands.
658                  * case 1, just the last two, and case 2 just draws the last one*/
659         case 1:
660                 if (context->draw_ypos > 2)
661                         gif_fill_in_pixels (context, dest, -2, v);
662                 if (context->draw_ypos < (context->frame_height - 2))
663                         gif_fill_in_pixels (context, dest, 2, v);
664                 /* no break as above. */
665         case 2:
666                 if (context->draw_ypos > 1)
667                         gif_fill_in_pixels (context, dest, -1, v);
668                 if (context->draw_ypos < (context->frame_height - 1))
669                         gif_fill_in_pixels (context, dest, 1, v);
670         case 3:
671         default:
672                 break;
673         }
674 }
675
676 static int
677 gif_get_lzw (GifContext *context)
678 {
679         guchar *dest, *temp;
680         gint lower_bound, upper_bound; /* bounds for emitting the area_updated signal */
681         gboolean bound_flag;
682         gint first_pass; /* bounds for emitting the area_updated signal */
683         gint v;
684
685         if (context->pixbuf == NULL) {
686                 context->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
687                                                   context->gif89.transparent != -1,
688                                                   8,
689                                                   context->frame_len,
690                                                   context->frame_height);
691
692                 if (context->prepare_func)
693                         (* context->prepare_func) (context->pixbuf, context->user_data);
694                 if (context->animation || context->frame_done_func || context->anim_done_func) {
695                         context->frame = g_new (GdkPixbufFrame, 1);
696                         context->frame->x_offset = context->x_offset;
697                         context->frame->y_offset = context->y_offset;;
698                         context->frame->delay_time = context->gif89.delay_time;
699                         switch (context->gif89.disposal) {
700                         case 0:
701                         case 1:
702                                 context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
703                                 break;
704                         case 2:
705                                 context->frame->action = GDK_PIXBUF_FRAME_DISPOSE;
706                                 break;
707                         case 3:
708                                 context->frame->action = GDK_PIXBUF_FRAME_REVERT;
709                                 break;
710                         default:
711                                 context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
712                                 break;
713                         }
714                         context->frame->pixbuf = context->pixbuf;
715                         if (context->animation) {
716                                 int w,h;
717                                 context->animation->n_frames ++;
718                                 context->animation->frames = g_list_append (context->animation->frames, context->frame);
719                                 w = gdk_pixbuf_get_width (context->pixbuf);
720                                 h = gdk_pixbuf_get_height (context->pixbuf);
721                                 if (w > context->animation->width)
722                                         context->animation->width = w;
723                                 if (h > context->animation->height)
724                                         context->animation->height = h;
725                         }
726                 }
727         }
728         dest = gdk_pixbuf_get_pixels (context->pixbuf);
729
730         bound_flag = FALSE;
731         lower_bound = upper_bound = context->draw_ypos;
732         first_pass = context->draw_pass;
733
734         while (TRUE) {
735                 v = lzw_read_byte (context);
736                 if (v < 0) {
737                         goto finished_data;
738                 }
739                 bound_flag = TRUE;
740
741                 if (context->gif89.transparent != -1) {
742                         temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 4;
743                         *temp = context->color_map [0][(guchar) v];
744                         *(temp+1) = context->color_map [1][(guchar) v];
745                         *(temp+2) = context->color_map [2][(guchar) v];
746                         *(temp+3) = (guchar) ((v == context->gif89.transparent) ? 0 : -1);
747                 } else {
748                         temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 3;
749                         *temp = context->color_map [0][(guchar) v];
750                         *(temp+1) = context->color_map [1][(guchar) v];
751                         *(temp+2) = context->color_map [2][(guchar) v];
752                 }
753
754                 if (context->prepare_func && context->frame_interlace)
755                         gif_fill_in_lines (context, dest, v);
756
757                 context->draw_xpos++;
758
759                 if (context->draw_xpos == context->frame_len) {
760                         context->draw_xpos = 0;
761                         if (context->frame_interlace) {
762                                 switch (context->draw_pass) {
763                                 case 0:
764                                 case 1:
765                                         context->draw_ypos += 8;
766                                         break;
767                                 case 2:
768                                         context->draw_ypos += 4;
769                                         break;
770                                 case 3:
771                                         context->draw_ypos += 2;
772                                         break;
773                                 }
774
775                                 if (context->draw_ypos >= context->frame_height) {
776                                         context->draw_pass++;
777                                         switch (context->draw_pass) {
778                                         case 1:
779                                                 context->draw_ypos = 4;
780                                                 break;
781                                         case 2:
782                                                 context->draw_ypos = 2;
783                                                 break;
784                                         case 3:
785                                                 context->draw_ypos = 1;
786                                                 break;
787                                         default:
788                                                 goto done;
789                                         }
790                                 }
791                         } else {
792                                 context->draw_ypos++;
793                         }
794                         if (context->draw_pass != first_pass) {
795                                 if (context->draw_ypos > lower_bound) {
796                                         lower_bound = 0;
797                                         upper_bound = context->frame_height;
798                                 } else {
799
800                                 }
801                         } else
802                                 upper_bound = context->draw_ypos;
803                 }
804                 if (context->draw_ypos >= context->frame_height)
805                         break;
806         }
807  done:
808         /* we got enough data. there may be more (ie, newer layers) but we can quit now */
809         if (context->animation || context->frame_done_func || context->anim_done_func) {
810                 context->state = GIF_GET_NEXT_STEP;
811         } else
812                 context->state = GIF_DONE;
813         v = 0;
814  finished_data:
815         if (bound_flag && context->update_func) {
816                 if (lower_bound <= upper_bound && first_pass == context->draw_pass) {
817                         (* context->update_func)
818                                 (context->pixbuf,
819                                  0, lower_bound,
820                                  gdk_pixbuf_get_width (context->pixbuf),
821                                  upper_bound - lower_bound,
822                                  context->user_data);
823                 } else {
824                         if (lower_bound <= upper_bound) {
825                                 (* context->update_func)
826                                         (context->pixbuf,
827                                          0, 0,
828                                          gdk_pixbuf_get_width (context->pixbuf),
829                                          gdk_pixbuf_get_height (context->pixbuf),
830                                          context->user_data);
831                         } else {
832                                 (* context->update_func)
833                                         (context->pixbuf,
834                                          0, 0,
835                                          gdk_pixbuf_get_width (context->pixbuf),
836                                          upper_bound,
837                                          context->user_data);
838                                 (* context->update_func)
839                                         (context->pixbuf,
840                                          0, lower_bound,
841                                          gdk_pixbuf_get_width (context->pixbuf),
842                                          gdk_pixbuf_get_height (context->pixbuf),
843                                          context->user_data);
844                         }
845                 }
846         }
847
848         if ((context->animation || context->frame_done_func || context->anim_done_func)
849             && context->state == GIF_GET_NEXT_STEP) {
850                 if (context->frame_done_func)
851                         (* context->frame_done_func) (context->frame,
852                                                       context->user_data);
853                 if (context->frame_done_func)
854                         gdk_pixbuf_unref (context->pixbuf);
855                 context->pixbuf = NULL;
856                 context->frame = NULL;
857         }
858         
859         return v;
860 }
861
862 static void
863 gif_set_prepare_lzw (GifContext *context)
864 {
865         context->state = GIF_PREPARE_LZW;
866         context->lzw_code_pending = -1;
867 }
868 static int
869 gif_prepare_lzw (GifContext *context)
870 {
871         gint i;
872
873         if (!gif_read (context, &(context->lzw_set_code_size), 1)) {
874                 /*g_message (_("GIF: EOF / read error on image data\n"));*/
875                 return -1;
876         }
877
878         context->lzw_code_size = context->lzw_set_code_size + 1;
879         context->lzw_clear_code = 1 << context->lzw_set_code_size;
880         context->lzw_end_code = context->lzw_clear_code + 1;
881         context->lzw_max_code_size = 2 * context->lzw_clear_code;
882         context->lzw_max_code = context->lzw_clear_code + 2;
883         context->lzw_fresh = TRUE;
884         context->code_curbit = 0;
885         context->code_lastbit = 0;
886         context->code_last_byte = 0;
887         context->code_done = FALSE;
888
889         for (i = 0; i < context->lzw_clear_code; ++i) {
890                 context->lzw_table[0][i] = 0;
891                 context->lzw_table[1][i] = i;
892         }
893         for (; i < (1 << MAX_LZW_BITS); ++i)
894                 context->lzw_table[0][i] = context->lzw_table[1][0] = 0;
895
896         context->lzw_sp = context->lzw_stack;
897         gif_set_get_lzw (context);
898
899         return 0;
900 }
901
902 /* needs 13 bytes to proceed. */
903 static gint
904 gif_init (GifContext *context)
905 {
906         unsigned char buf[16];
907         char version[4];
908
909         if (!gif_read (context, buf, 6)) {
910                 /* Unable to read magic number,
911                  * gif_read() should have set error
912                  */
913                 return -1;
914         }
915
916         if (strncmp ((char *) buf, "GIF", 3) != 0) {
917                 /* Not a GIF file */
918                 g_set_error (context->error,
919                              GDK_PIXBUF_ERROR,
920                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
921                              _("File does not appear to be a GIF file"));
922                 return -1;
923         }
924
925         strncpy (version, (char *) buf + 3, 3);
926         version[3] = '\0';
927
928         if ((strcmp (version, "87a") != 0) && (strcmp (version, "89a") != 0)) {
929                 /* bad version number, not '87a' or '89a' */
930                 g_set_error (context->error,
931                              GDK_PIXBUF_ERROR,
932                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
933                              _("Version %s of the GIF file format is not supported"),
934                              version);
935                 return -1;
936         }
937
938         /* read the screen descriptor */
939         if (!gif_read (context, buf, 7)) {
940                 /* Failed to read screen descriptor, error set */
941                 return -1;
942         }
943
944         context->width = LM_to_uint (buf[0], buf[1]);
945         context->height = LM_to_uint (buf[2], buf[3]);
946         context->bit_pixel = 2 << (buf[4] & 0x07);
947         context->color_resolution = (((buf[4] & 0x70) >> 3) + 1);
948         context->background = buf[5];
949         context->aspect_ratio = buf[6];
950
951         if (BitSet (buf[4], LOCALCOLORMAP)) {
952                 gif_set_get_colormap (context);
953         } else {
954                 context->state = GIF_GET_NEXT_STEP;
955         }
956         return 0;
957 }
958
959 static void
960 gif_set_get_frame_info (GifContext *context)
961 {
962         context->state = GIF_GET_FRAME_INFO;
963 }
964
965 static gint
966 gif_get_frame_info (GifContext *context)
967 {
968         unsigned char buf[9];
969         if (!gif_read (context, buf, 9)) {
970                 return -1;
971         }
972         /* Okay, we got all the info we need.  Lets record it */
973         context->frame_len = LM_to_uint (buf[4], buf[5]);
974         context->frame_height = LM_to_uint (buf[6], buf[7]);
975         context->x_offset = LM_to_uint (buf[0], buf[1]);
976         context->y_offset = LM_to_uint (buf[2], buf[3]);
977
978         if (context->frame_height > context->height) {
979                 /* we don't want to resize things.  So we exit */
980                 context->state = GIF_DONE;
981
982                 g_set_error (context->error,
983                              GDK_PIXBUF_ERROR,
984                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
985                              _("GIF animation contained a frame with an incorrect size"));
986                 
987                 return -2;
988         }
989
990         context->frame_interlace = BitSet (buf[8], INTERLACE);
991         if (BitSet (buf[8], LOCALCOLORMAP)) {
992                 /* Does this frame have it's own colormap. */
993                 /* really only relevant when looking at the first frame
994                  * of an animated gif. */
995                 /* if it does, we need to re-read in the colormap,
996                  * the gray_scale, and the bit_pixel */
997                 context->bit_pixel = 1 << ((buf[8] & 0x07) + 1);
998                 gif_set_get_colormap2 (context);
999                 return 0;
1000         }
1001         gif_set_prepare_lzw (context);
1002         return 0;
1003
1004 }
1005
1006 static gint
1007 gif_get_next_step (GifContext *context)
1008 {
1009         unsigned char c;
1010         while (TRUE) {
1011                 if (!gif_read (context, &c, 1)) {
1012                         return -1;
1013                 }
1014                 if (c == ';') {
1015                         /* GIF terminator */
1016                         /* hmm.  Not 100% sure what to do about this.  Should
1017                          * i try to return a blank image instead? */
1018                         context->state = GIF_DONE;
1019                         return 0;
1020                 }
1021
1022                 if (c == '!') {
1023                         /* Check the extention */
1024                         gif_set_get_extension (context);
1025                         return 0;
1026                 }
1027
1028                 /* look for frame */
1029                 if (c != ',') {
1030                         /* Not a valid start character */
1031                         continue;
1032                 }
1033                 /* load the frame */
1034                 gif_set_get_frame_info (context);
1035                 return 0;
1036         }
1037 }
1038
1039
1040 static gint
1041 gif_main_loop (GifContext *context)
1042 {
1043         gint retval = 0;
1044
1045         do {
1046                 switch (context->state) {
1047                 case GIF_START:
1048                         retval = gif_init (context);
1049                         break;
1050
1051                 case GIF_GET_COLORMAP:
1052                         retval = gif_get_colormap (context);
1053                         if (retval == 0)
1054                                 context->state = GIF_GET_NEXT_STEP;
1055                         break;
1056
1057                 case GIF_GET_NEXT_STEP:
1058                         retval = gif_get_next_step (context);
1059                         break;
1060
1061                 case GIF_GET_FRAME_INFO:
1062                         retval = gif_get_frame_info (context);
1063                         break;
1064
1065                 case GIF_GET_EXTENTION:
1066                         retval = gif_get_extension (context);
1067                         if (retval == 0)
1068                                 context->state = GIF_GET_NEXT_STEP;
1069                         break;
1070
1071                 case GIF_GET_COLORMAP2:
1072                         retval = gif_get_colormap (context);
1073                         if (retval == 0)
1074                                 gif_set_prepare_lzw (context);
1075                         break;
1076
1077                 case GIF_PREPARE_LZW:
1078                         retval = gif_prepare_lzw (context);
1079                         break;
1080
1081                 case GIF_LZW_FILL_BUFFER:
1082                         retval = gif_lzw_fill_buffer (context);
1083                         break;
1084
1085                 case GIF_LZW_CLEAR_CODE:
1086                         retval = gif_lzw_clear_code (context);
1087                         break;
1088
1089                 case GIF_GET_LZW:
1090                         retval = gif_get_lzw (context);
1091                         break;
1092
1093                 case GIF_DONE:
1094                 default:
1095                         retval = 0;
1096                         goto done;
1097                 };
1098         } while ((retval == 0) || (retval == -3));
1099  done:
1100         return retval;
1101 }
1102
1103 static GifContext *
1104 new_context (void)
1105 {
1106         GifContext *context;
1107
1108         context = g_new0 (GifContext, 1);
1109
1110         context->pixbuf = NULL;
1111         context->file = NULL;
1112         context->state = GIF_START;
1113         context->prepare_func = NULL;
1114         context->update_func = NULL;
1115         context->frame_done_func = NULL;
1116         context->anim_done_func = NULL;
1117         context->user_data = NULL;
1118         context->buf = NULL;
1119         context->amount_needed = 0;
1120         context->gif89.transparent = -1;
1121         context->gif89.delay_time = -1;
1122         context->gif89.input_flag = -1;
1123         context->gif89.disposal = -1;
1124
1125         return context;
1126 }
1127 /* Shared library entry point */
1128 GdkPixbuf *
1129 gdk_pixbuf__gif_image_load (FILE *file, GError **error)
1130 {
1131         GifContext *context;
1132         GdkPixbuf *pixbuf;
1133
1134         g_return_val_if_fail (file != NULL, NULL);
1135
1136         context = new_context ();
1137         context->file = file;
1138         context->error = error;
1139         
1140         gif_main_loop (context);
1141
1142         pixbuf = context->pixbuf;
1143         g_free (context);
1144  
1145         return pixbuf;
1146 }
1147
1148 gpointer
1149 gdk_pixbuf__gif_image_begin_load (ModulePreparedNotifyFunc prepare_func,
1150                                   ModuleUpdatedNotifyFunc update_func,
1151                                   ModuleFrameDoneNotifyFunc frame_done_func,
1152                                   ModuleAnimationDoneNotifyFunc anim_done_func,
1153                                   gpointer user_data,
1154                                   GError **error)
1155 {
1156         GifContext *context;
1157
1158 #ifdef IO_GIFDEBUG
1159         count = 0;
1160 #endif
1161         context = new_context ();
1162         context->error = error;
1163         context->prepare_func = prepare_func;
1164         context->update_func = update_func;
1165         context->frame_done_func = frame_done_func;
1166         context->anim_done_func = anim_done_func;
1167         context->user_data = user_data;
1168
1169         return (gpointer) context;
1170 }
1171
1172 void
1173 gdk_pixbuf__gif_image_stop_load (gpointer data)
1174 {
1175         GifContext *context = (GifContext *) data;
1176
1177         /* FIXME: free the animation data */
1178
1179         if (context->pixbuf)
1180                 gdk_pixbuf_unref (context->pixbuf);
1181         if (context->animation)
1182                 gdk_pixbuf_animation_unref (context->animation);
1183 /*      g_free (context->buf);*/
1184         g_free (context);
1185 }
1186
1187 gboolean
1188 gdk_pixbuf__gif_image_load_increment (gpointer data, guchar *buf, guint size,
1189                                       GError **error)
1190 {
1191         gint retval;
1192         GifContext *context = (GifContext *) data;
1193
1194         context->error = error;
1195         
1196         if (context->amount_needed == 0) {
1197                 /* we aren't looking for some bytes. */
1198                 /* we can use buf now, but we don't want to keep it around at all.
1199                  * it will be gone by the end of the call. */
1200                 context->buf = buf;
1201                 context->ptr = 0;
1202                 context->size = size;
1203         } else {
1204                 /* we need some bytes */
1205                 if (size < context->amount_needed) {
1206                         context->amount_needed -= size;
1207                         /* copy it over and return */
1208                         memcpy (context->buf + context->size, buf, size);
1209                         context->size += size;
1210                         return TRUE;
1211                 } else if (size == context->amount_needed) {
1212                         memcpy (context->buf + context->size, buf, size);
1213                         context->size += size;
1214                 } else {
1215                         context->buf = g_realloc (context->buf, context->size + size);
1216                         memcpy (context->buf + context->size, buf, size);
1217                         context->size += size;
1218                 }
1219         }
1220
1221         retval = gif_main_loop (context);
1222
1223         if (retval == -2)
1224                 return FALSE;
1225         if (retval == -1) {
1226                 /* we didn't have enough memory */
1227                 /* prepare for the next image_load_increment */
1228                 if (context->buf == buf) {
1229                         g_assert (context->size == size);
1230                         context->buf = (guchar *)g_new (guchar, context->amount_needed + (context->size - context->ptr));
1231                         memcpy (context->buf, buf + context->ptr, context->size - context->ptr);
1232                 } else {
1233                         /* copy the left overs to the begining of the buffer */
1234                         /* and realloc the memory */
1235                         memmove (context->buf, context->buf + context->ptr, context->size - context->ptr);
1236                         context->buf = g_realloc (context->buf, context->amount_needed + (context->size - context->ptr));
1237                 }
1238                 context->size = context->size - context->ptr;
1239                 context->ptr = 0;
1240         } else {
1241                 /* we are prolly all done */
1242                 if (context->buf == buf)
1243                         context->buf = NULL;
1244         }
1245         return TRUE;
1246 }
1247
1248 GdkPixbufAnimation *
1249 gdk_pixbuf__gif_image_load_animation (FILE *file,
1250                                       GError **error)
1251 {
1252         GifContext *context;
1253         GdkPixbufAnimation *animation;
1254
1255         g_return_val_if_fail (file != NULL, NULL);
1256
1257         context = new_context ();
1258
1259         context->error = error;
1260         
1261         context->animation = g_object_new (GDK_TYPE_PIXBUF_ANIMATION, NULL);
1262
1263         context->animation->n_frames = 0;
1264         context->animation->frames = NULL;
1265         context->animation->width = 0;
1266         context->animation->height = 0;
1267         context->file = file;
1268
1269         gif_main_loop (context);
1270
1271         animation = context->animation;
1272         g_free (context);
1273         return animation;
1274 }