1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2 /* GdkPixbuf library - GIF image loader
3  *
4  * Copyright (C) 1999 Mark Crichton
5  * Copyright (C) 1999 The Free Software Foundation
6  *
7  * Authors: Jonathan Blandford <jrb@redhat.com>
8  *          Adapted from the gimp gif filter written by Adam Moss <adam@gimp.org>
9  *          Gimp work based on earlier work.
10  *          Permission to relicense under the LGPL obtained.
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 /* This loader is very hairy code.
27  *
28  * The main loop was not designed for incremental loading, so when it was hacked
29  * in it got a bit messy.  Basically, every function is written to expect a failed
30  * read_gif, and lets you call it again assuming that the bytes are there.
31  *
32  * Return vals.
33  * Unless otherwise specified, these are the return vals for most functions:
34  *
35  *  0 -> success
36  * -1 -> more bytes needed.
37  * -2 -> failure; abort the load
38  * -3 -> control needs to be passed back to the main loop
39  *        \_ (most of the time returning 0 will get this, but not always)
40  *
41  * >1 -> for functions that get a guchar, the char will be returned.
42  *
43  * -jrb (11/03/1999)
44  */
45 
46 /*
47  * If you have any images that crash this code, please, please let me know and
48  * send them to me.
49  *                                            <jrb@redhat.com>
50  */
51 
52 
53 
54 #include "config.h"
55 #include <stdio.h>
56 #include <string.h>
57 #include <errno.h>
58 #include <glib/gi18n-lib.h>
59 #include "gdk-pixbuf-io.h"
60 #include "io-gif-animation.h"
61 
62 
63 
64 #undef DUMP_IMAGE_DETAILS
65 #undef IO_GIFDEBUG
66 
67 #define MAXCOLORMAPSIZE  256
68 
69 #define INTERLACE          0x40
70 #define LOCALCOLORMAP      0x80
71 #define BitSet(byte, bit)  (((byte) & (bit)) == (bit))
72 #define LM_to_uint(a,b)         (((b)<<8)|(a))
73 
74 
75 
76 typedef unsigned char CMap[3][MAXCOLORMAPSIZE];
77 
78 /* Possible states we can be in. */
79 enum {
80 	GIF_START,
81 	GIF_GET_COLORMAP,
82 	GIF_GET_NEXT_STEP,
83 	GIF_GET_FRAME_INFO,
84 	GIF_GET_EXTENSION,
85 	GIF_GET_COLORMAP2,
86 	GIF_PREPARE_LZW,
87 	GIF_GET_LZW,
88 	GIF_DONE
89 };
90 
91 
92 typedef struct _Gif89 Gif89;
93 struct _Gif89
94 {
95 	int transparent;
96 	int delay_time;
97 	int input_flag;
98 	int disposal;
99 };
100 
101 typedef struct _GifContext GifContext;
102 struct _GifContext
103 {
104 	int state; /* really only relevant for progressive loading */
105 	unsigned int width;
106 	unsigned int height;
107 
108         gboolean has_global_cmap;
109 
110         gint global_colormap_size;
111         unsigned int global_bit_pixel;
112 	unsigned int global_color_resolution;
113         unsigned int background_index;
114 
115         gboolean frame_cmap_active;
116         CMap frame_color_map;
117         gint frame_colormap_size;
118         unsigned int frame_bit_pixel;
119 
120 	unsigned int aspect_ratio;
121 	GdkPixbufGifAnim *animation;
122 	GdkPixbufFrame *frame;
123 	Gif89 gif89;
124 
125 	/* stuff per frame. */
126 	int frame_len;
127 	int frame_height;
128 	int frame_interlace;
129 	int x_offset;
130 	int y_offset;
131 
132 	/* Static read only */
133 	FILE *file;
134 
135 	/* progressive read, only. */
136 	GdkPixbufModuleSizeFunc size_func;
137 	GdkPixbufModulePreparedFunc prepare_func;
138 	GdkPixbufModuleUpdatedFunc update_func;
139 	gpointer user_data;
140         guchar *buf;
141 	gsize ptr;
142 	gsize size;
143 	gsize amount_needed;
144 
145 	/* extension context */
146 	guchar extension_label;
147 	guchar extension_flag;
148         gboolean in_loop_extension;
149 
150 	/* get block context */
151 	guchar block_count;
152 	guchar block_buf[280];
153 
154 	guchar lzw_set_code_size;
155 
156         /* error pointer */
157         GError **error;
158 };
159 
160 
161 
162 #ifdef IO_GIFDEBUG
163 static int count = 0;
164 #endif
165 
166 /* Returns TRUE if read is OK,
167  * FALSE if more memory is needed. */
168 static gboolean
gif_read(GifContext * context,guchar * buffer,size_t len)169 gif_read (GifContext *context, guchar *buffer, size_t len)
170 {
171 	gboolean retval;
172 #ifdef IO_GIFDEBUG
173 	gint i;
174 #endif
175 	if (context->file) {
176 #ifdef IO_GIFDEBUG
177 		count += len;
178 		g_print ("Fsize :%zi\tcount :%d\t", len, count);
179 #endif
180 		retval = (fread (buffer, 1, len, context->file) == len);
181 
182                 if (!retval && ferror (context->file)) {
183                         gint save_errno = errno;
184                         g_set_error (context->error,
185                                      G_FILE_ERROR,
186                                      g_file_error_from_errno (save_errno),
187                                      _("Failure reading GIF: %s"),
188                                      g_strerror (save_errno));
189                 }
190 
191 #ifdef IO_GIFDEBUG
192 		if (len < 100) {
193 			for (i = 0; i < len; i++)
194 				g_print ("%d ", buffer[i]);
195 		}
196 		g_print ("\n");
197 #endif
198 
199 		return retval;
200 	} else {
201 #ifdef IO_GIFDEBUG
202 /*  		g_print ("\tlooking for %d bytes.  size == %d, ptr == %d\n", len, context->size, context->ptr); */
203 #endif
204 		if ((context->size - context->ptr) >= len) {
205 #ifdef IO_GIFDEBUG
206 			count += len;
207 #endif
208 			memcpy (buffer, context->buf + context->ptr, len);
209 			context->ptr += len;
210 			context->amount_needed = 0;
211 #ifdef IO_GIFDEBUG
212 			g_print ("Psize :%zi\tcount :%d\t", len, count);
213 			if (len < 100) {
214 				for (i = 0; i < len; i++)
215 					g_print ("%d ", buffer[i]);
216 			}
217 			g_print ("\n");
218 #endif
219 			return TRUE;
220 		}
221 		context->amount_needed = len - (context->size - context->ptr);
222 	}
223 	return FALSE;
224 }
225 
226 /* Changes the stage to be GIF_GET_COLORMAP */
227 static void
gif_set_get_colormap(GifContext * context)228 gif_set_get_colormap (GifContext *context)
229 {
230 	context->global_colormap_size = 0;
231 	context->state = GIF_GET_COLORMAP;
232 }
233 
234 static void
gif_set_get_colormap2(GifContext * context)235 gif_set_get_colormap2 (GifContext *context)
236 {
237 	context->frame_colormap_size = 0;
238 	context->state = GIF_GET_COLORMAP2;
239 }
240 
241 static gint
gif_get_colormap(GifContext * context)242 gif_get_colormap (GifContext *context)
243 {
244 	unsigned char rgb[3];
245 
246 	while (context->global_colormap_size < context->global_bit_pixel) {
247 		if (!gif_read (context, rgb, sizeof (rgb))) {
248 			return -1;
249 		}
250 
251 		context->animation->color_map[context->global_colormap_size * 3 + 0] = rgb[0];
252 		context->animation->color_map[context->global_colormap_size * 3 + 1] = rgb[1];
253 		context->animation->color_map[context->global_colormap_size * 3 + 2] = rgb[2];
254 
255 		context->global_colormap_size ++;
256 	}
257 
258 	return 0;
259 }
260 
261 
262 static gint
gif_get_colormap2(GifContext * context)263 gif_get_colormap2 (GifContext *context)
264 {
265 	unsigned char rgb[3];
266 
267 	while (context->frame_colormap_size < context->frame_bit_pixel) {
268 		if (!gif_read (context, rgb, sizeof (rgb))) {
269 			return -1;
270 		}
271 
272 		context->frame_color_map[0][context->frame_colormap_size] = rgb[0];
273 		context->frame_color_map[1][context->frame_colormap_size] = rgb[1];
274 		context->frame_color_map[2][context->frame_colormap_size] = rgb[2];
275 
276 		context->frame_colormap_size ++;
277 	}
278 
279 	return 0;
280 }
281 
282 /*
283  * in order for this function to work, we need to perform some black magic.
284  * We want to return -1 to let the calling function know, as before, that it needs
285  * more bytes.  If we return 0, we were able to successfully read all block->count bytes.
286  * Problem is, we don't want to reread block_count every time, so we check to see if
287  * context->block_count is 0 before we read in the function.
288  *
289  * As a result, context->block_count MUST be 0 the first time the get_data_block is called
290  * within a context, and cannot be 0 the second time it's called.
291  */
292 
293 static int
get_data_block(GifContext * context,unsigned char * buf,gint * empty_block)294 get_data_block (GifContext *context,
295 		unsigned char *buf,
296 		gint *empty_block)
297 {
298 
299 	if (context->block_count == 0) {
300 		if (!gif_read (context, &context->block_count, 1)) {
301 			return -1;
302 		}
303 	}
304 
305 	if (context->block_count == 0)
306 		if (empty_block) {
307 			*empty_block = TRUE;
308 			return 0;
309 		}
310 
311 	if (!gif_read (context, buf, context->block_count)) {
312 		return -1;
313 	}
314 
315 	return 0;
316 }
317 
318 static void
gif_set_get_extension(GifContext * context)319 gif_set_get_extension (GifContext *context)
320 {
321 	context->state = GIF_GET_EXTENSION;
322 	context->extension_flag = TRUE;
323 	context->extension_label = 0;
324 	context->block_count = 0;
325 }
326 
327 static int
gif_get_extension(GifContext * context)328 gif_get_extension (GifContext *context)
329 {
330 	gint retval;
331 	gint empty_block = FALSE;
332 
333 	if (context->extension_flag) {
334 		if (context->extension_label == 0) {
335 			/* I guess bad things can happen if we have an extension of 0 )-: */
336 			/* I should look into this sometime */
337 			if (!gif_read (context, & context->extension_label , 1)) {
338 				return -1;
339 			}
340 		}
341 
342 		switch (context->extension_label) {
343                 case 0xf9:			/* Graphic Control Extension */
344                         retval = get_data_block (context, (unsigned char *) context->block_buf, NULL);
345 			if (retval != 0)
346 				return retval;
347 
348 			if (context->frame == NULL) {
349 				/* I only want to set the transparency if I haven't
350 				 * created the frame yet.
351                                  */
352 				context->gif89.disposal = (context->block_buf[0] >> 2) & 0x7;
353 				context->gif89.input_flag = (context->block_buf[0] >> 1) & 0x1;
354 				context->gif89.delay_time = LM_to_uint (context->block_buf[1], context->block_buf[2]);
355 
356 				if ((context->block_buf[0] & 0x1) != 0) {
357 					context->gif89.transparent = context->block_buf[3];
358 				} else {
359 					context->gif89.transparent = -1;
360 				}
361 			}
362 
363 			/* Now we've successfully loaded this one, we continue on our way */
364 			context->block_count = 0;
365 			context->extension_flag = FALSE;
366 			break;
367                 case 0xff: /* application extension */
368                         if (!context->in_loop_extension) {
369                                 retval = get_data_block (context, (unsigned char *) context->block_buf, NULL);
370                                 if (retval != 0)
371                                         return retval;
372                                 if (!strncmp ((gchar *)context->block_buf, "NETSCAPE2.0", 11) ||
373                                     !strncmp ((gchar *)context->block_buf, "ANIMEXTS1.0", 11)) {
374                                         context->in_loop_extension = TRUE;
375                                 }
376                                 context->block_count = 0;
377                         }
378                         if (context->in_loop_extension) {
379                                 do {
380                                         retval = get_data_block (context, (unsigned char *) context->block_buf, &empty_block);
381                                         if (retval != 0)
382                                                 return retval;
383                                         if (context->block_buf[0] == 0x01) {
384                                                 context->animation->loop = context->block_buf[1] + (context->block_buf[2] << 8);
385                                                 if (context->animation->loop != 0)
386                                                         context->animation->loop++;
387                                         }
388                                         context->block_count = 0;
389                                 }
390                                 while (!empty_block);
391                                 context->in_loop_extension = FALSE;
392                                 context->extension_flag = FALSE;
393                                 return 0;
394                         }
395 			break;
396 		default:
397 			/* Unhandled extension */
398 			break;
399 		}
400 	}
401 	/* read all blocks, until I get an empty block, in case there was an extension I didn't know about. */
402 	do {
403 		retval = get_data_block (context, (unsigned char *) context->block_buf, &empty_block);
404 		if (retval != 0)
405 			return retval;
406 		context->block_count = 0;
407 	} while (!empty_block);
408 
409 	return 0;
410 }
411 
412 static void
gif_set_get_lzw(GifContext * context)413 gif_set_get_lzw (GifContext *context)
414 {
415 	context->state = GIF_GET_LZW;
416 }
417 
418 static int
gif_get_lzw(GifContext * context)419 gif_get_lzw (GifContext *context)
420 {
421 	if (context->frame == NULL) {
422                 int rowstride;
423                 guint64 len;
424 
425                 rowstride = gdk_pixbuf_calculate_rowstride (GDK_COLORSPACE_RGB,
426                                                             TRUE,
427                                                             8,
428                                                             context->frame_len,
429                                                             context->frame_height);
430                 if (rowstride < 0 ||
431                     !g_uint64_checked_mul (&len, rowstride, context->frame_height) ||
432                     len >= G_MAXINT) {
433                         g_set_error_literal (context->error,
434                                              GDK_PIXBUF_ERROR,
435                                              GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
436                                              _("Not enough memory to load GIF file"));
437                         return -2;
438                 }
439 
440                 context->frame = g_new0 (GdkPixbufFrame, 1);
441 
442                 context->frame->lzw_data = g_byte_array_new ();
443                 context->frame->lzw_code_size = context->lzw_set_code_size;
444 
445                 context->frame->width = context->frame_len;
446                 context->frame->height = context->frame_height;
447                 context->frame->x_offset = context->x_offset;
448                 context->frame->y_offset = context->y_offset;
449                 context->frame->interlace = context->frame_interlace;
450 
451                 if (context->frame_colormap_size > 0) {
452                         int i;
453 
454                         context->frame->color_map = g_malloc (256 * 3);
455                         context->frame->color_map_allocated = TRUE;
456                         for (i = 0; i < 256; i++) {
457                                 context->frame->color_map[i * 3 + 0] = context->frame_color_map[0][i];
458                                 context->frame->color_map[i * 3 + 1] = context->frame_color_map[1][i];
459                                 context->frame->color_map[i * 3 + 2] = context->frame_color_map[2][i];
460                         }
461                 }
462                 else {
463                         context->frame->color_map = context->animation->color_map;
464                 }
465 
466                 context->frame->transparent_index = context->gif89.transparent;
467 
468                 /* GIF delay is in hundredths, we want thousandths */
469                 context->frame->delay_time = context->gif89.delay_time * 10;
470 
471                 /* GIFs with delay time 0 are mostly broken, but they
472                  * just want a default, "not that fast" delay.
473                  */
474                 if (context->frame->delay_time == 0)
475                         context->frame->delay_time = 100;
476 
477                 /* No GIFs gets to play faster than 50 fps. They just
478                  * lock up poor gtk.
479                  */
480                 if (context->frame->delay_time < 20)
481                         context->frame->delay_time = 20; /* 20 = "fast" */
482 
483                 context->frame->elapsed = context->animation->total_time;
484                 context->animation->total_time += context->frame->delay_time;
485 
486                 switch (context->gif89.disposal) {
487                 case 0:
488                 case 1:
489                         context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
490                         break;
491                 case 2:
492                         context->frame->action = GDK_PIXBUF_FRAME_DISPOSE;
493                         break;
494                 case 3:
495                         context->frame->action = GDK_PIXBUF_FRAME_REVERT;
496                         break;
497                 default:
498                         context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
499                         break;
500                 }
501 
502                 context->animation->frames = g_list_append (context->animation->frames, context->frame);
503 
504 		/* Notify when have first frame */
505 		if (context->animation->frames->next == NULL && context->prepare_func != NULL) {
506 			GdkPixbuf *pixbuf = gdk_pixbuf_animation_get_static_image (GDK_PIXBUF_ANIMATION (context->animation));
507 			if (pixbuf != NULL)
508 				(* context->prepare_func) (pixbuf,
509 				                           GDK_PIXBUF_ANIMATION (context->animation),
510 				                           context->user_data);
511 		}
512         }
513 
514 	/* read all blocks */
515 	while (TRUE) {
516 		gint retval, empty_block = FALSE;
517 
518 		retval = get_data_block (context, (unsigned char *) context->block_buf, &empty_block);
519 
520 		/* Notify frame update */
521 		if ((retval != 0 || empty_block) && context->animation->frames->next == NULL && context->update_func != NULL) {
522 			GdkPixbuf *pixbuf = gdk_pixbuf_animation_get_static_image (GDK_PIXBUF_ANIMATION (context->animation));
523 			if (pixbuf)
524 				(* context->update_func) (pixbuf,
525 				                          0, 0, context->frame->width, context->frame->height,
526 				                          context->user_data);
527 		}
528 
529 		if (retval != 0)
530 			return retval;
531 
532 		if (empty_block) {
533 			context->frame = NULL;
534 			context->state = GIF_GET_NEXT_STEP;
535 			return 0;
536 		}
537 
538 		g_byte_array_append (context->frame->lzw_data, context->block_buf, context->block_count);
539 		if (context->animation->last_frame == context->frame)
540 			context->animation->last_frame = NULL;
541 		context->block_count = 0;
542 	}
543 }
544 
545 static void
gif_set_prepare_lzw(GifContext * context)546 gif_set_prepare_lzw (GifContext *context)
547 {
548 	context->state = GIF_PREPARE_LZW;
549 }
550 static int
gif_prepare_lzw(GifContext * context)551 gif_prepare_lzw (GifContext *context)
552 {
553 	if (!gif_read (context, &(context->lzw_set_code_size), 1)) {
554 		/*g_message (_("GIF: EOF / read error on image data\n"));*/
555 		return -1;
556 	}
557 
558         if (context->lzw_set_code_size > 12) {
559                 g_set_error_literal (context->error,
560                                      GDK_PIXBUF_ERROR,
561                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
562                                      _("GIF image is corrupt (incorrect LZW compression)"));
563                 return -2;
564         }
565 
566 	gif_set_get_lzw (context);
567 
568 	return 0;
569 }
570 
571 /* needs 13 bytes to proceed. */
572 static gint
gif_init(GifContext * context)573 gif_init (GifContext *context)
574 {
575 	unsigned char buf[16];
576 	char version[4];
577 
578 	if (!gif_read (context, buf, 6)) {
579 		/* Unable to read magic number,
580                  * gif_read() should have set error
581                  */
582 		return -1;
583 	}
584 
585 	if (strncmp ((char *) buf, "GIF", 3) != 0) {
586 		/* Not a GIF file */
587                 g_set_error_literal (context->error,
588                                      GDK_PIXBUF_ERROR,
589                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
590                                      _("File does not appear to be a GIF file"));
591 		return -2;
592 	}
593 
594 	strncpy (version, (char *) buf + 3, 3);
595 	version[3] = '\0';
596 
597 	if ((strcmp (version, "87a") != 0) && (strcmp (version, "89a") != 0)) {
598 		gchar *escaped_version;
599 
600 		/* bad version number, not '87a' or '89a' */
601 		escaped_version = g_strescape (version, NULL);
602                 g_set_error (context->error,
603                              GDK_PIXBUF_ERROR,
604                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
605                              _("Version %s of the GIF file format is not supported"),
606                              escaped_version);
607 		g_free (escaped_version);
608 		return -2;
609 	}
610 
611 	/* read the screen descriptor */
612 	if (!gif_read (context, buf, 7)) {
613 		/* Failed to read screen descriptor, error set */
614 		return -1;
615 	}
616 
617 	context->width = LM_to_uint (buf[0], buf[1]);
618 	context->height = LM_to_uint (buf[2], buf[3]);
619         /* The 4th byte is
620          * high bit: whether to use the background index
621          * next 3:   color resolution
622          * next:     whether colormap is sorted by priority of allocation
623          * last 3:   size of colormap
624          */
625 	context->global_bit_pixel = 2 << (buf[4] & 0x07);
626 	context->global_color_resolution = (((buf[4] & 0x70) >> 3) + 1);
627         context->has_global_cmap = (buf[4] & 0x80) != 0;
628 	context->background_index = buf[5];
629 	context->aspect_ratio = buf[6];
630 
631         context->animation->width = context->width;
632         context->animation->height = context->height;
633 
634         if (context->size_func) {
635                 gint width, height;
636 
637                 width = context->width;
638                 height = context->height;
639 
640                 (*context->size_func) (&width, &height, context->user_data);
641 
642                 if (width == 0 || height == 0) {
643                         g_set_error_literal (context->error,
644                                              GDK_PIXBUF_ERROR,
645                                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
646                                              _("Resulting GIF image has zero size"));
647                         return -2;
648                 }
649         }
650 
651 	if (context->has_global_cmap) {
652 		gif_set_get_colormap (context);
653 	} else {
654 		context->state = GIF_GET_NEXT_STEP;
655 	}
656 
657 #ifdef DUMP_IMAGE_DETAILS
658         g_print (">Image width: %d height: %d global_cmap: %d background: %d\n",
659                  context->width, context->height, context->has_global_cmap, context->background_index);
660 #endif
661 
662 	return 0;
663 }
664 
665 static void
gif_set_get_frame_info(GifContext * context)666 gif_set_get_frame_info (GifContext *context)
667 {
668 	context->state = GIF_GET_FRAME_INFO;
669 }
670 
671 static gint
gif_get_frame_info(GifContext * context)672 gif_get_frame_info (GifContext *context)
673 {
674 	unsigned char buf[9];
675 
676 	if (!gif_read (context, buf, 9)) {
677 		return -1;
678 	}
679 
680 	/* Okay, we got all the info we need.  Lets record it */
681 	context->frame_len = LM_to_uint (buf[4], buf[5]);
682 	context->frame_height = LM_to_uint (buf[6], buf[7]);
683 	context->x_offset = LM_to_uint (buf[0], buf[1]);
684 	context->y_offset = LM_to_uint (buf[2], buf[3]);
685 
686 	if (context->animation->frames == NULL &&
687             context->gif89.disposal == 3) {
688                 /* First frame can't have "revert to previous" as its
689                  * dispose mode. Silently use "retain" instead.
690                  */
691                 context->gif89.disposal = 0;
692 	}
693 
694 	context->frame_interlace = BitSet (buf[8], INTERLACE);
695 
696 #ifdef DUMP_IMAGE_DETAILS
697         g_print (">width: %d height: %d xoffset: %d yoffset: %d disposal: %d delay: %d transparent: %d interlace: %d\n",
698                  context->frame_len, context->frame_height, context->x_offset, context->y_offset,
699                  context->gif89.disposal, context->gif89.delay_time, context->gif89.transparent, context->frame_interlace);
700 #endif
701 
702 	if (BitSet (buf[8], LOCALCOLORMAP)) {
703 
704 #ifdef DUMP_IMAGE_DETAILS
705                 g_print (">has local colormap\n");
706 #endif
707 
708 		/* Does this frame have it's own colormap. */
709 		/* really only relevant when looking at the first frame
710 		 * of an animated gif. */
711 		/* if it does, we need to re-read in the colormap,
712 		 * the gray_scale, and the bit_pixel */
713                 context->frame_cmap_active = TRUE;
714 		context->frame_bit_pixel = 1 << ((buf[8] & 0x07) + 1);
715 		gif_set_get_colormap2 (context);
716 		return 0;
717 	}
718 
719         if (!context->has_global_cmap) {
720                 context->state = GIF_DONE;
721 
722                 g_set_error_literal (context->error,
723                                      GDK_PIXBUF_ERROR,
724                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
725                                      _("GIF image has no global colormap, and a frame inside it has no local colormap."));
726 
727 		return -2;
728         }
729 
730 	gif_set_prepare_lzw (context);
731 	return 0;
732 
733 }
734 
735 static gint
gif_get_next_step(GifContext * context)736 gif_get_next_step (GifContext *context)
737 {
738 	unsigned char c;
739 	while (TRUE) {
740 		if (!gif_read (context, &c, 1)) {
741 			return -1;
742 		}
743 		if (c == ';') {
744 			/* GIF terminator */
745 			/* hmm.  Not 100% sure what to do about this.  Should
746 			 * i try to return a blank image instead? */
747 			context->state = GIF_DONE;
748 			return 0;
749 		}
750 
751 		if (c == '!') {
752 			/* Check the extension */
753 			gif_set_get_extension (context);
754 			return 0;
755 		}
756 
757 		/* look for frame */
758 		if (c != ',') {
759 			/* Not a valid start character */
760 			continue;
761 		}
762 		/* load the frame */
763 		gif_set_get_frame_info (context);
764 		return 0;
765 	}
766 }
767 
768 
769 #define LOG(x) /* g_print ("%s: %s\n", G_STRLOC, x); */
770 
771 static gint
gif_main_loop(GifContext * context)772 gif_main_loop (GifContext *context)
773 {
774 	gint retval = 0;
775 
776 	do {
777 		switch (context->state) {
778 		case GIF_START:
779                         LOG("start\n");
780 			retval = gif_init (context);
781 			break;
782 
783 		case GIF_GET_COLORMAP:
784                         LOG("get_colormap\n");
785 			retval = gif_get_colormap (context);
786 			if (retval == 0)
787 				context->state = GIF_GET_NEXT_STEP;
788 			break;
789 
790 		case GIF_GET_NEXT_STEP:
791                         LOG("next_step\n");
792 			retval = gif_get_next_step (context);
793 			break;
794 
795 		case GIF_GET_FRAME_INFO:
796                         LOG("frame_info\n");
797 			retval = gif_get_frame_info (context);
798 			break;
799 
800 		case GIF_GET_EXTENSION:
801                         LOG("get_extension\n");
802 			retval = gif_get_extension (context);
803 			if (retval == 0)
804 				context->state = GIF_GET_NEXT_STEP;
805 			break;
806 
807 		case GIF_GET_COLORMAP2:
808                         LOG("get_colormap2\n");
809 			retval = gif_get_colormap2 (context);
810 			if (retval == 0)
811 				gif_set_prepare_lzw (context);
812 			break;
813 
814 		case GIF_PREPARE_LZW:
815                         LOG("prepare_lzw\n");
816 			retval = gif_prepare_lzw (context);
817 			break;
818 
819 		case GIF_GET_LZW:
820                         LOG("get_lzw\n");
821 			retval = gif_get_lzw (context);
822 			break;
823 
824 		case GIF_DONE:
825                         LOG("done\n");
826                         /* fall through */
827 		default:
828 			retval = 0;
829 			goto done;
830 		};
831 	} while ((retval == 0) || (retval == -3));
832  done:
833 	return retval;
834 }
835 
836 static GifContext *
new_context(void)837 new_context (void)
838 {
839 	GifContext *context;
840 
841 	context = g_try_malloc (sizeof (GifContext));
842         if (context == NULL)
843                 return NULL;
844 
845         memset (context, 0, sizeof (GifContext));
846 
847         context->animation = g_object_new (GDK_TYPE_PIXBUF_GIF_ANIM, NULL);
848 	context->frame = NULL;
849 	context->file = NULL;
850 	context->state = GIF_START;
851 	context->size_func = NULL;
852 	context->prepare_func = NULL;
853 	context->update_func = NULL;
854 	context->user_data = NULL;
855 	context->buf = NULL;
856 	context->amount_needed = 13;
857 	context->buf = g_new (guchar, context->amount_needed);
858 	context->gif89.transparent = -1;
859 	context->gif89.delay_time = -1;
860 	context->gif89.input_flag = -1;
861 	context->gif89.disposal = -1;
862         context->animation->loop = 1;
863         context->in_loop_extension = FALSE;
864 
865 	return context;
866 }
867 /* Shared library entry point */
868 static GdkPixbuf *
gdk_pixbuf__gif_image_load(FILE * file,GError ** error)869 gdk_pixbuf__gif_image_load (FILE *file, GError **error)
870 {
871 	GifContext *context;
872 	GdkPixbuf *pixbuf;
873         gint retval;
874 
875 	g_return_val_if_fail (file != NULL, NULL);
876 
877 	context = new_context ();
878 
879         if (context == NULL) {
880                 g_set_error_literal (error,
881                                      GDK_PIXBUF_ERROR,
882                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
883                                      _("Not enough memory to load GIF file"));
884                 return NULL;
885         }
886 
887 	context->file = file;
888         context->error = error;
889 
890         retval = gif_main_loop (context);
891 	if (retval == -1 || context->animation->frames == NULL) {
892                 if (context->error && *(context->error) == NULL)
893                         g_set_error_literal (context->error,
894                                              GDK_PIXBUF_ERROR,
895                                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
896                                              _("GIF file was missing some data (perhaps it was truncated somehow?)"));
897         }
898         else if (retval == -2) {
899                 pixbuf = NULL;
900                 goto out;
901         }
902 
903         pixbuf = gdk_pixbuf_animation_get_static_image (GDK_PIXBUF_ANIMATION (context->animation));
904 
905         if (pixbuf)
906                 g_object_ref (pixbuf);
907 
908 out:
909         g_object_unref (context->animation);
910 
911         g_free (context->buf);
912 	g_free (context);
913 
914 	return pixbuf;
915 }
916 
917 static gpointer
gdk_pixbuf__gif_image_begin_load(GdkPixbufModuleSizeFunc size_func,GdkPixbufModulePreparedFunc prepare_func,GdkPixbufModuleUpdatedFunc update_func,gpointer user_data,GError ** error)918 gdk_pixbuf__gif_image_begin_load (GdkPixbufModuleSizeFunc size_func,
919                                   GdkPixbufModulePreparedFunc prepare_func,
920 				  GdkPixbufModuleUpdatedFunc update_func,
921 				  gpointer user_data,
922                                   GError **error)
923 {
924 	GifContext *context;
925 
926 #ifdef IO_GIFDEBUG
927 	count = 0;
928 #endif
929 	context = new_context ();
930 
931         if (context == NULL) {
932                 g_set_error_literal (error,
933                                      GDK_PIXBUF_ERROR,
934                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
935                                      _("Not enough memory to load GIF file"));
936                 return NULL;
937         }
938 
939         context->error = error;
940 	context->size_func = size_func;
941 	context->prepare_func = prepare_func;
942 	context->update_func = update_func;
943 	context->user_data = user_data;
944 
945 	return (gpointer) context;
946 }
947 
948 static gboolean
gdk_pixbuf__gif_image_stop_load(gpointer data,GError ** error)949 gdk_pixbuf__gif_image_stop_load (gpointer data, GError **error)
950 {
951 	GifContext *context = (GifContext *) data;
952         gboolean retval = TRUE;
953 
954         if (context->animation->frames == NULL) {
955                 g_set_error_literal (error,
956                                      GDK_PIXBUF_ERROR,
957                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
958                                      _("GIF image was truncated or incomplete."));
959 
960                 retval = FALSE;
961         } else if (context->state != GIF_DONE) {
962                 g_set_error_literal (error,
963                                      GDK_PIXBUF_ERROR,
964                                      GDK_PIXBUF_ERROR_INCOMPLETE_ANIMATION,
965                                      _("Not all frames of the GIF image were loaded."));
966 
967                 retval = FALSE;
968         }
969 
970         g_object_unref (context->animation);
971 
972   	g_free (context->buf);
973 	g_free (context);
974 
975         return retval;
976 }
977 
978 static gboolean
gdk_pixbuf__gif_image_load_increment(gpointer data,const guchar * buf,guint size,GError ** error)979 gdk_pixbuf__gif_image_load_increment (gpointer data,
980                                       const guchar *buf, guint size,
981                                       GError **error)
982 {
983 	gint retval;
984 	GifContext *context = (GifContext *) data;
985 
986         context->error = error;
987 
988 	if (context->amount_needed == 0) {
989 		/* we aren't looking for some bytes. */
990 		/* we can use buf now, but we don't want to keep it around at all.
991 		 * it will be gone by the end of the call. */
992 		context->buf = (guchar*) buf; /* very dubious const cast */
993 		context->ptr = 0;
994 		context->size = size;
995 	} else {
996 		/* we need some bytes */
997 		if (size < context->amount_needed) {
998 			context->amount_needed -= size;
999 			/* copy it over and return */
1000 			memcpy (context->buf + context->size, buf, size);
1001 			context->size += size;
1002 			return TRUE;
1003 		} else if (size == context->amount_needed) {
1004 			memcpy (context->buf + context->size, buf, size);
1005 			context->size += size;
1006 		} else {
1007 			context->buf = g_realloc (context->buf, context->size + size);
1008 			memcpy (context->buf + context->size, buf, size);
1009 			context->size += size;
1010 		}
1011 	}
1012 
1013 	retval = gif_main_loop (context);
1014 
1015 	if (retval == -2) {
1016 		if (context->buf == buf)
1017                         context->buf = NULL;
1018 		return FALSE;
1019         }
1020 	if (retval == -1) {
1021 		/* we didn't have enough memory */
1022 		/* prepare for the next image_load_increment */
1023 		if (context->buf == buf) {
1024 			g_assert (context->size == size);
1025 			context->buf = g_new (guchar, context->amount_needed + (context->size - context->ptr));
1026 			memcpy (context->buf, buf + context->ptr, context->size - context->ptr);
1027 		} else {
1028 			/* copy the left overs to the begining of the buffer */
1029 			/* and realloc the memory */
1030 			memmove (context->buf, context->buf + context->ptr, context->size - context->ptr);
1031 			context->buf = g_realloc (context->buf, context->amount_needed + (context->size - context->ptr));
1032 		}
1033 		context->size = context->size - context->ptr;
1034 		context->ptr = 0;
1035 	} else {
1036 		/* we are prolly all done */
1037 		if (context->buf == buf)
1038 			context->buf = NULL;
1039 	}
1040 	return TRUE;
1041 }
1042 
1043 static GdkPixbufAnimation *
gdk_pixbuf__gif_image_load_animation(FILE * file,GError ** error)1044 gdk_pixbuf__gif_image_load_animation (FILE *file,
1045                                       GError **error)
1046 {
1047 	GifContext *context;
1048 	GdkPixbufAnimation *animation;
1049 
1050 	g_return_val_if_fail (file != NULL, NULL);
1051 
1052 	context = new_context ();
1053 
1054         if (context == NULL) {
1055                 g_set_error_literal (error,
1056                                      GDK_PIXBUF_ERROR,
1057                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1058                                      _("Not enough memory to load GIF file"));
1059                 return NULL;
1060         }
1061 
1062         context->error = error;
1063 	context->file = file;
1064 
1065 	if (gif_main_loop (context) == -1 || context->animation->frames == NULL) {
1066                 if (context->error && *(context->error) == NULL)
1067                         g_set_error_literal (context->error,
1068                                              GDK_PIXBUF_ERROR,
1069                                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
1070                                              _("GIF file was missing some data (perhaps it was truncated somehow?)"));
1071 
1072                 g_object_unref (context->animation);
1073                 context->animation = NULL;
1074         }
1075 
1076         if (context->animation)
1077                 animation = GDK_PIXBUF_ANIMATION (context->animation);
1078         else
1079                 animation = NULL;
1080 
1081         if (context->error && *(context->error))
1082                 g_print ("%s\n", (*(context->error))->message);
1083 
1084         g_free (context->buf);
1085 	g_free (context);
1086 	return animation;
1087 }
1088 
1089 #ifndef INCLUDE_gif
1090 #define MODULE_ENTRY(function) G_MODULE_EXPORT void function
1091 #else
1092 #define MODULE_ENTRY(function) void _gdk_pixbuf__gif_ ## function
1093 #endif
1094 
MODULE_ENTRY(fill_vtable)1095 MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
1096 {
1097         module->load = gdk_pixbuf__gif_image_load;
1098         module->begin_load = gdk_pixbuf__gif_image_begin_load;
1099         module->stop_load = gdk_pixbuf__gif_image_stop_load;
1100         module->load_increment = gdk_pixbuf__gif_image_load_increment;
1101         module->load_animation = gdk_pixbuf__gif_image_load_animation;
1102 }
1103 
MODULE_ENTRY(fill_info)1104 MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
1105 {
1106         static const GdkPixbufModulePattern signature[] = {
1107                 { "GIF8", NULL, 100 },
1108                 { NULL, NULL, 0 }
1109         };
1110 	static const gchar *mime_types[] = {
1111 		"image/gif",
1112 		NULL
1113 	};
1114 	static const gchar *extensions[] = {
1115 		"gif",
1116 		NULL
1117 	};
1118 
1119 	info->name = "gif";
1120         info->signature = (GdkPixbufModulePattern *) signature;
1121 	info->description = NC_("image format", "GIF");
1122 	info->mime_types = (gchar **) mime_types;
1123 	info->extensions = (gchar **) extensions;
1124 	info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
1125 	info->license = "LGPL";
1126 }
1127