Dillo v3.1.1-119-g140d9ebd
Loading...
Searching...
No Matches
gif.c
Go to the documentation of this file.
1/*
2 * File: gif.c
3 *
4 * Copyright (C) 1997 Raph Levien <raph@acm.org>
5 * Copyright (C) 2000-2007 Jorge Arellano Cid <jcid@dillo.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 */
12
19/* Notes 13 Oct 1997 --RLL
20 *
21 * Today, just for the hell of it, I implemented a new decoder from
22 * scratch. It's oriented around pushing bytes, while the old decoder
23 * was based around reads which may suspend. There were basically
24 * three motivations.
25 *
26 * 1. To increase the speed.
27 *
28 * 2. To fix some bugs I had seen, most likely due to suspension.
29 *
30 * 3. To make sure that the code had no buffer overruns or the like.
31 *
32 * 4. So that the code could be released under a freer license.
33 *
34 * Let's see how we did on speed. I used a large image for testing
35 * (fvwm95-2.gif).
36 *
37 * The old decoder spent a total of about 1.04 seconds decoding the
38 * image. Another .58 seconds went into Image_line, almost
39 * entirely conversion from colormap to RGB.
40 *
41 * The new decoder spent a total of 0.46 seconds decoding the image.
42 * However, the time for Image_line went up to 1.01 seconds.
43 * Thus, even though the decoder seems to be about twice as fast,
44 * the net gain is pretty minimal. Could this be because of cache
45 * effects?
46 *
47 * Lessons learned: The first, which I keep learning over and over, is
48 * not to try to optimize too much. It doesn't work. Just keep things
49 * simple.
50 *
51 * Second, it seems that the colormap to RGB conversion is really a
52 * significant part of the overall time. It's possible that going
53 * directly to 16 bits would help, but that's optimization again :)
54 */
55
56
57/* TODO:
58 * + Make sure to handle error cases gracefully (including aborting the
59 * connection, if necessary).
60 */
61
62#include <config.h>
63#ifdef ENABLE_GIF
64
65#include <stdio.h> /* for sprintf */
66#include <string.h> /* for memcpy and memmove */
67
68#include "msg.h"
69#include "image.hh"
70#include "cache.h"
71#include "dicache.h"
72
73#define INTERLACE 0x40
74#define LOCALCOLORMAP 0x80
75
76#define LM_to_uint(a,b) ((((uchar_t)b)<<8)|((uchar_t)a))
77
78#define MAXCOLORMAPSIZE 256
79#define MAX_LWZ_BITS 12
80
81
82typedef struct {
83 DilloImage *Image;
84 DilloUrl *url;
85 int version;
86
87 int state;
88 size_t Start_Ofs;
89 uint_t Flags;
90
91 uchar_t input_code_size;
93 int pass;
94
95 uint_t y;
96
98 int code_size;
99
101 uint_t Width;
102 uint_t Height;
103 size_t ColorMap_ofs;
104 uint_t ColorResolution;
105 uint_t NumColors;
106 int Background;
107 uint_t spill_line_index;
108#if 0
109 uint_t AspectRatio; /* AspectRatio (not used) */
110#endif
111
113 int transparent;
114#if 0
115 /* None are used: */
116 int delayTime;
117 int inputFlag;
118 int disposal;
119#endif
120
121 /* state for the new push-oriented decoder */
122 int packet_size;
124 int bits_in_window;
125 uint_t last_code;
126 uint_t line_index;
127 uchar_t **spill_lines;
128 int num_spill_lines_max;
129 int length[(1 << MAX_LWZ_BITS) + 1];
130 int code_and_byte[(1 << MAX_LWZ_BITS) + 1];
131} DilloGif;
132
133/* Some invariants:
134 *
135 * last_code <= code_mask
136 *
137 * code_and_byte is stored packed: (code << 8) | byte
138 */
139
140
141/*
142 * Forward declarations
143 */
144static void Gif_write(DilloGif *gif, void *Buf, uint_t BufSize);
145static void Gif_close(DilloGif *gif, CacheClient_t *Client);
146static size_t Gif_process_bytes(DilloGif *gif, const uchar_t *buf,
147 int bufsize, void *Buf);
148
149
153void *a_Gif_new(DilloImage *Image, DilloUrl *url, int version)
154{
155 DilloGif *gif = dMalloc(sizeof(DilloGif));
156 _MSG("a_Gif_new: gif=%p\n", gif);
157
158 gif->Image = Image;
159 gif->url = url;
160 gif->version = version;
161
162 gif->Flags = 0;
163 gif->state = 0;
164 gif->Start_Ofs = 0;
165 gif->linebuf = NULL;
166 gif->Background = Image->bg_color;
167 gif->transparent = -1;
168 gif->num_spill_lines_max = 0;
169 gif->spill_lines = NULL;
170 gif->window = 0;
171 gif->packet_size = 0;
172 gif->ColorMap_ofs = 0;
173
174 return gif;
175}
176
180static void Gif_free(DilloGif *gif)
181{
182 int i;
183
184 _MSG("Gif_free: gif=%p\n", gif);
185
186 dFree(gif->linebuf);
187 if (gif->spill_lines != NULL) {
188 for (i = 0; i < gif->num_spill_lines_max; i++)
189 dFree(gif->spill_lines[i]);
190 dFree(gif->spill_lines);
191 }
192 dFree(gif);
193}
194
199void a_Gif_callback(int Op, void *data)
200{
201 if (Op == CA_Send) {
202 CacheClient_t *Client = data;
203 Gif_write(Client->CbData, Client->Buf, Client->BufSize);
204 } else if (Op == CA_Close) {
205 CacheClient_t *Client = data;
206 Gif_close(Client->CbData, Client);
207 } else if (Op == CA_Abort) {
208 Gif_free(data);
209 }
210}
211
215static void Gif_write(DilloGif *gif, void *Buf, uint_t BufSize)
216{
217 uchar_t *buf;
218 int bufsize, bytes_consumed;
219
220 /* Sanity checks */
221 if (!Buf || BufSize == 0)
222 return;
223
224 buf = ((uchar_t *) Buf) + gif->Start_Ofs;
225 bufsize = BufSize - gif->Start_Ofs;
226
227 _MSG("Gif_write: %u bytes\n", BufSize);
228
229 /* Process the bytes in the input buffer. */
230 bytes_consumed = Gif_process_bytes(gif, buf, bufsize, Buf);
231
232 if (bytes_consumed < 1)
233 return;
234 gif->Start_Ofs += bytes_consumed;
235
236 _MSG("exit Gif_write, bufsize=%ld\n", (long)bufsize);
237}
238
242static void Gif_close(DilloGif *gif, CacheClient_t *Client)
243{
244 _MSG("Gif_close: destroy gif %p\n", gif);
245 a_Dicache_close(gif->url, gif->version, Client);
246 Gif_free(gif);
247}
248
249
250/* --- GIF Extensions ----------------------------------------------------- */
251
260static inline size_t Gif_data_blocks(const uchar_t *Buf, size_t BSize)
261{
262 size_t Size = 0;
263
264 if (BSize < 1)
265 return 0;
266 while (Buf[0]) {
267 if (BSize <= (size_t)(Buf[0] + 1))
268 return 0;
269 Size += Buf[0] + 1;
270 BSize -= Buf[0] + 1;
271 Buf += Buf[0] + 1;
272 }
273 return Size + 1;
274}
275
284static inline size_t Gif_do_generic_ext(const uchar_t *Buf, size_t BSize)
285{
286
287 size_t Size = Buf[0] + 1, /* (uchar_t + 1) can't overflow size_t */
288 DSize;
289
290 /* The Block size (the first byte) is supposed to be a specific size
291 * for each extension... we don't check.
292 */
293
294 if (Size > BSize)
295 return 0;
296 DSize = Gif_data_blocks(Buf + Size, BSize - Size);
297 if (!DSize)
298 return 0;
299 Size += DSize;
300 return Size <= BSize ? Size : 0;
301}
302
303/*
304 * ?
305 */
306static inline size_t
307 Gif_do_gc_ext(DilloGif *gif, const uchar_t *Buf, size_t BSize)
308{
309 /* Graphic Control Extension */
310 size_t Size = Buf[0] + 2;
311 uint_t Flags;
312
313 if (BSize < 6 || Size > BSize)
314 return 0;
315 Buf++;
316 Flags = Buf[0];
317
318 /* The packed fields */
319#if 0
320 gif->disposal = (Buf[0] >> 2) & 0x7;
321 gif->inputFlag = (Buf[0] >> 1) & 0x1;
322
323 /* Delay time */
324 gif->delayTime = LM_to_uint(Buf[1], Buf[2]);
325#endif
326
327 /* Transparent color index, may not be valid (unless flag is set) */
328 if ((Flags & 0x1)) {
329 gif->transparent = Buf[3];
330 }
331 return Size;
332}
333
334#define App_Ext (0xff)
335#define Cmt_Ext (0xfe)
336#define GC_Ext (0xf9)
337#define Txt_Ext (0x01)
338
339/*
340 * ?
341 * Return value:
342 * TRUE when the extension is over
343 */
344static size_t Gif_do_extension(DilloGif *gif, uint_t Label,
345 const uchar_t *buf,
346 size_t BSize)
347{
348 switch (Label) {
349 case GC_Ext: /* Graphics extension */
350 return Gif_do_gc_ext(gif, buf, BSize);
351
352 case Cmt_Ext: /* Comment extension */
353 return Gif_data_blocks(buf, BSize);
354
355 case Txt_Ext: /* Plain text Extension */
356 case App_Ext: /* Application Extension */
357 default:
358 return Gif_do_generic_ext(buf, BSize); /*Ignore Extension */
359 }
360}
361
362/* --- General Image Decoder ----------------------------------------------- */
363/* Here begins the new push-oriented decoder. */
364
365/*
366 * ?
367 */
368static void Gif_lwz_init(DilloGif *gif)
369{
370 gif->num_spill_lines_max = 1;
371 gif->spill_lines = dMalloc(sizeof(uchar_t *) * gif->num_spill_lines_max);
372
373 gif->spill_lines[0] = dMalloc(gif->Width);
374 gif->bits_in_window = 0;
375
376 /* First code in table = clear_code +1
377 * Last code in table = first code in table
378 * clear_code = (1<< input code size)
379 */
380 gif->last_code = (1 << gif->input_code_size) + 1;
381 memset(gif->code_and_byte, 0,
382 (1 + gif->last_code) * sizeof(gif->code_and_byte[0]));
383 gif->code_size = gif->input_code_size + 1;
384 gif->line_index = 0;
385}
386
390static void Gif_emit_line(DilloGif *gif, const uchar_t *linebuf)
391{
392 a_Dicache_write(gif->url, gif->version, linebuf, gif->y);
393 if (gif->Flags & INTERLACE) {
394 switch (gif->pass) {
395 case 0:
396 case 1:
397 gif->y += 8;
398 break;
399 case 2:
400 gif->y += 4;
401 break;
402 case 3:
403 gif->y += 2;
404 break;
405 }
406 if (gif->y >= gif->Height) {
407 gif->pass++;
408 switch (gif->pass) {
409 case 1:
410 gif->y = 4;
411 break;
412 case 2:
413 gif->y = 2;
414 break;
415 case 3:
416 gif->y = 1;
417 break;
418 default:
419 /* arriving here is an error in the input image. */
420 gif->y = 0;
421 break;
422 }
423 }
424 } else {
425 if (gif->y < gif->Height)
426 gif->y++;
427 }
428}
429
433static void Gif_literal(DilloGif *gif, uint_t code)
434{
435 gif->linebuf[gif->line_index++] = code;
436 if (gif->line_index >= gif->Width) {
437 Gif_emit_line(gif, gif->linebuf);
438 gif->line_index = 0;
439 }
440 gif->length[gif->last_code + 1] = 2;
441 gif->code_and_byte[gif->last_code + 1] = (code << 8);
442 gif->code_and_byte[gif->last_code] |= code;
443}
444
445/*
446 * ?
447 */
448/* Profiling reveals over half the GIF time is spent here: */
449static void Gif_sequence(DilloGif *gif, uint_t code)
450{
451 uint_t o_index, o_size, orig_code;
452 uint_t sequence_length = gif->length[code];
453 uint_t line_index = gif->line_index;
454 int num_spill_lines;
455 int spill_line_index = gif->spill_line_index;
456 uchar_t *last_byte_ptr, *obuf;
457
458 gif->length[gif->last_code + 1] = sequence_length + 1;
459 gif->code_and_byte[gif->last_code + 1] = (code << 8);
460
461 /* We're going to traverse the sequence backwards. Thus,
462 * we need to allocate spill lines if the sequence won't
463 * fit entirely within the present scan line. */
464 if (line_index + sequence_length <= gif->Width) {
465 num_spill_lines = 0;
466 obuf = gif->linebuf;
467 o_index = line_index + sequence_length;
468 o_size = sequence_length - 1;
469 } else {
470 num_spill_lines = (line_index + sequence_length - 1) /
471 gif->Width;
472 o_index = (line_index + sequence_length - 1) % gif->Width + 1;
473 if (num_spill_lines > gif->num_spill_lines_max) {
474 /* Allocate more spill lines. */
475 spill_line_index = gif->num_spill_lines_max;
476 gif->num_spill_lines_max = num_spill_lines << 1;
477 gif->spill_lines = dRealloc(gif->spill_lines,
478 gif->num_spill_lines_max *
479 sizeof(uchar_t *));
480
481 for (; spill_line_index < gif->num_spill_lines_max;
482 spill_line_index++)
483 gif->spill_lines[spill_line_index] =
484 dMalloc(gif->Width);
485 }
486 spill_line_index = num_spill_lines - 1;
487 obuf = gif->spill_lines[spill_line_index];
488 o_size = o_index;
489 }
490 gif->line_index = o_index; /* for afterwards */
491
492 /* for fixing up later if last_code == code */
493 orig_code = code;
494 last_byte_ptr = obuf + o_index - 1;
495
496 /* spill lines are allocated, and we are clear to
497 * write. This loop does not write the first byte of
498 * the sequence, however (last byte traversed). */
499 while (sequence_length > 1) {
500 sequence_length -= o_size;
501 /* Write o_size bytes to
502 * obuf[o_index - o_size..o_index). */
503 for (; o_size > 0 && o_index > 0; o_size--) {
504 uint_t code_and_byte = gif->code_and_byte[code];
505
506 _MSG("%d ", gif->code_and_byte[code] & 255);
507
508 obuf[--o_index] = code_and_byte & 255;
509 code = code_and_byte >> 8;
510 }
511 /* Prepare for writing to next line. */
512 if (o_index == 0) {
513 if (spill_line_index > 0) {
514 spill_line_index--;
515 obuf = gif->spill_lines[spill_line_index];
516 o_size = gif->Width;
517 } else {
518 obuf = gif->linebuf;
519 o_size = sequence_length - 1;
520 }
521 o_index = gif->Width;
522 }
523 }
524 /* Ok, now we write the first byte of the sequence. */
525 /* We are sure that the code is literal. */
526 _MSG("%d", code);
527 obuf[--o_index] = code;
528 gif->code_and_byte[gif->last_code] |= code;
529
530 /* Fix up the output if the original code was last_code. */
531 if (orig_code == gif->last_code) {
532 *last_byte_ptr = code;
533 _MSG(" fixed (%d)!", code);
534 }
535 _MSG("\n");
536
537 /* Output any full lines. */
538 if (gif->line_index >= gif->Width) {
539 Gif_emit_line(gif, gif->linebuf);
540 gif->line_index = 0;
541 }
542 if (num_spill_lines) {
543 if (gif->line_index)
544 Gif_emit_line(gif, gif->linebuf);
545 for (spill_line_index = 0;
546 spill_line_index < num_spill_lines - (gif->line_index ? 1 : 0);
547 spill_line_index++)
548 Gif_emit_line(gif, gif->spill_lines[spill_line_index]);
549 }
550 if (num_spill_lines) {
551 /* Swap the last spill line with the gif line, using
552 * linebuf as the swap temporary. */
553 uchar_t *linebuf = gif->spill_lines[num_spill_lines - 1];
554
555 gif->spill_lines[num_spill_lines - 1] = gif->linebuf;
556 gif->linebuf = linebuf;
557 }
558 gif->spill_line_index = spill_line_index;
559}
560
571static int Gif_process_code(DilloGif *gif, uint_t code, uint_t clear_code)
572{
573
574 /* A short table describing what to do with the code:
575 * code < clear_code : This is uncompressed, raw data
576 * code== clear_code : Reset the decompression table
577 * code== clear_code+1: End of data stream
578 * code > clear_code+1: Compressed code; look up in table
579 */
580 if (code < clear_code) {
581 /* a literal code. */
582 _MSG("literal\n");
583 Gif_literal(gif, code);
584 return 1;
585 } else if (code >= clear_code + 2) {
586 /* a sequence code. */
587 if (code > gif->last_code)
588 return -1;
589 Gif_sequence(gif, code);
590 return 1;
591 } else if (code == clear_code) {
592 /* clear code. Resets the whole table */
593 _MSG("clear\n");
594 return 0;
595 } else {
596 /* end code. */
597 _MSG("end\n");
598 return 2;
599 }
600}
601
602/*
603 * ?
604 */
605static int Gif_decode(DilloGif *gif, const uchar_t *buf, size_t bsize)
606{
607 /*
608 * Data block processing. The image stuff is a series of data blocks.
609 * Each data block is 1 to 256 bytes long. The first byte is the length
610 * of the data block. 0 == the last data block.
611 */
612 size_t bufsize, packet_size;
613 uint_t clear_code;
615 int bits_in_window;
616 uint_t code;
617 int code_size;
618 uint_t code_mask;
619
620 bufsize = bsize;
621
622 /* Want to get all inner loop state into local variables. */
623 packet_size = gif->packet_size;
624 window = gif->window;
625 bits_in_window = gif->bits_in_window;
626 code_size = gif->code_size;
627 code_mask = (1 << code_size) - 1;
628 clear_code = 1 << gif->input_code_size;
629
630 /* If packet size == 0, we are at the start of a data block.
631 * The first byte of the data block indicates how big it is (0 == last
632 * datablock)
633 * packet size is set to this size; it indicates how much of the data block
634 * we have left to process.
635 */
636 while (bufsize > 0) {
637 /* lwz_bytes is the number of remaining lwz bytes in the packet. */
638 int lwz_bytes = MIN(packet_size, bufsize);
639
640 bufsize -= lwz_bytes;
641 packet_size -= lwz_bytes;
642 for (; lwz_bytes > 0; lwz_bytes--) {
643 /* printf ("%d ", *buf) would print the depacketized lwz stream. */
644
645 /* Push the byte onto the "end" of the window (MSB). The low order
646 * bits always come first in the LZW stream. */
647 window = (window >> 8) | (*buf++ << 24);
648 bits_in_window += 8;
649
650 while (bits_in_window >= code_size) {
651 /* Extract the code. The code is code_size (3 to 12) bits long,
652 * at the start of the window */
653 code = (window >> (32 - bits_in_window)) & code_mask;
654
655 _MSG("code = %d, ", code);
656
657 bits_in_window -= code_size;
658 switch (Gif_process_code(gif, code, clear_code)) {
659 case 1: /* Increment last code */
660 gif->last_code++;
661 /*gif->code_and_byte[gif->last_code+1]=0; */
662
663 if ((gif->last_code & code_mask) == 0) {
664 if (gif->last_code == (1 << MAX_LWZ_BITS))
665 gif->last_code--;
666 else {
667 code_size++;
668 code_mask = (1 << code_size) - 1;
669 }
670 }
671 break;
672
673 case 0: /* Reset codes size and mask */
674 gif->last_code = clear_code + 1;
675 code_size = gif->input_code_size + 1;
676 code_mask = (1 << code_size) - 1;
677 break;
678
679 case 2: /* End code... consume remaining data chunks..? */
680 goto error; /* Could clean up better? */
681 default:
682 MSG("Gif_decode: error!\n");
683 goto error;
684 }
685 }
686 }
687
688 /* We reach here if
689 * a) We have reached the end of the data block;
690 * b) we ran out of data before reaching the end of the data block
691 */
692 if (bufsize <= 0)
693 break; /* We are out of data; */
694
695 /* Start of new data block */
696 bufsize--;
697 if (!(packet_size = *buf++)) {
698 /* This is the "block terminator" -- the last data block */
699 gif->state = 999; /* BUG: should Go back to getting GIF blocks. */
700 break;
701 }
702 }
703
704 gif->packet_size = packet_size;
705 gif->window = window;
706 gif->bits_in_window = bits_in_window;
707 gif->code_size = code_size;
708 return bsize - bufsize;
709
710 error:
711 gif->state = 999;
712 return bsize - bufsize;
713}
714
715/*
716 * ?
717 */
718static int Gif_check_sig(DilloGif *gif, const uchar_t *ibuf, int ibsize)
719{
720 /* at beginning of file - read magic number */
721 if (ibsize < 6)
722 return 0;
723 if (memcmp(ibuf, "GIF87a", 6) != 0 &&
724 memcmp(ibuf, "GIF89a", 6) != 0) {
725 MSG_WARN("\"%s\" is not a GIF file.\n", URL_STR(gif->url));
726 gif->state = 999;
727 return 6;
728 }
729 gif->state = 1;
730 return 6;
731}
732
733/* Read the color map
734 *
735 * Implements, from the spec:
736 * Global Color Table
737 * Local Color Table
738 */
739static inline size_t
740 Gif_do_color_table(DilloGif *gif, void *Buf,
741 const uchar_t *buf, size_t bsize, size_t CT_Size)
742{
743 size_t Size = 3 * (1 << (1 + CT_Size));
744
745 if (Size > bsize)
746 return 0;
747
748 gif->ColorMap_ofs = (ulong_t) buf - (ulong_t) Buf;
749 gif->NumColors = (1 << (1 + CT_Size));
750 return Size;
751}
752
753/*
754 * This implements, from the spec:
755 * <Logical Screen> ::= Logical Screen Descriptor [Global Color Table]
756 */
757static size_t Gif_get_descriptor(DilloGif *gif, void *Buf,
758 const uchar_t *buf, int bsize)
759{
760
761 /* screen descriptor */
762 size_t Size = 7, /* Size of descriptor */
763 mysize; /* Size of color table */
764 uchar_t Flags;
765
766 if (bsize < 7)
767 return 0;
768 Flags = buf[4];
769
770 if (Flags & LOCALCOLORMAP) {
771 mysize = Gif_do_color_table(
772 gif, Buf, buf + 7, (size_t)bsize - 7, Flags & (size_t)0x7);
773 if (!mysize)
774 return 0;
775 Size += mysize; /* Size of the color table that follows */
776 /* gif->Background = buf[5]; */
777 }
778 /* gif->Width = LM_to_uint(buf[0], buf[1]);
779 gif->Height = LM_to_uint(buf[2], buf[3]); */
780 gif->ColorResolution = (((buf[4] & 0x70) >> 3) + 1);
781 /* gif->AspectRatio = buf[6]; */
782
783 return Size;
784}
785
786/*
787 * This implements, from the spec:
788 * <Table-Based Image> ::= Image Descriptor [Local Color Table] Image Data
789 *
790 * ('Buf' points to just after the Image separator)
791 * we should probably just check that the local stuff is consistent
792 * with the stuff at the header. For now, we punt...
793 */
794static size_t Gif_do_img_desc(DilloGif *gif, void *Buf,
795 const uchar_t *buf, size_t bsize)
796{
797 uchar_t Flags;
798 size_t Size = 9 + 1; /* image descriptor size + first byte of image data */
799
800 if (bsize < 10)
801 return 0;
802
803 gif->Width = LM_to_uint(buf[4], buf[5]);
804 gif->Height = LM_to_uint(buf[6], buf[7]);
805
806 /* check max image size */
807 if (gif->Width <= 0 || gif->Height <= 0 ||
808 gif->Width > IMAGE_MAX_AREA / gif->Height) {
809 MSG("Gif_do_img_desc: suspicious image size request %u x %u\n",
810 gif->Width, gif->Height);
811 gif->state = 999;
812 return 0;
813 }
814
816 a_Dicache_set_parms(gif->url, gif->version, gif->Image,
817 gif->Width, gif->Height, DILLO_IMG_TYPE_INDEXED,
818 1 / 2.2);
819 gif->Image = NULL; /* safeguard: hereafter it may be freed by its owner */
820
821 Flags = buf[8];
822
823 gif->Flags |= Flags & INTERLACE;
824 gif->pass = 0;
825 bsize -= 9;
826 buf += 9;
827 if (Flags & LOCALCOLORMAP) {
828 size_t LSize = Gif_do_color_table(
829 gif, Buf, buf, bsize, Flags & (size_t)0x7);
830
831 if (!LSize)
832 return 0;
833 Size += LSize;
834 buf += LSize;
835 bsize -= LSize;
836 }
837 /* Finally, get the first byte of the LZW image data */
838 if (bsize < 1)
839 return 0;
840 gif->input_code_size = *buf++;
841 if (gif->input_code_size > 8) {
842 gif->state = 999;
843 return Size;
844 }
845 gif->y = 0;
846 Gif_lwz_init(gif);
847 gif->spill_line_index = 0;
848 gif->linebuf = dMalloc(gif->Width);
849 gif->state = 3; /*Process the lzw data next */
850 if (gif->ColorMap_ofs) {
851 a_Dicache_set_cmap(gif->url, gif->version, gif->Background,
852 (uchar_t *) Buf + gif->ColorMap_ofs,
853 gif->NumColors, 256, gif->transparent);
854 }
855 return Size;
856}
857
858/* --- Top level data block processors ------------------------------------ */
859#define Img_Desc (0x2c)
860#define Trailer (0x3B)
861#define Ext_Id (0x21)
862
863/*
864 * This identifies which kind of GIF blocks are next, and processes them.
865 * It returns if there isn't enough data to process the next blocks, or if
866 * the next block is the lzw data (which is streamed differently)
867 *
868 * This implements, from the spec, <Data>* Trailer
869 * <Data> ::= <Graphic Block> | <Special-Purpose Block>
870 * <Special-Purpose Block> ::= Application Extension | Comment Extension
871 * <Graphic Block> ::= [Graphic Control Extension] <Graphic-Rendering Block>
872 * <Graphic-Rendering Block> ::= <Table-Based Image> | Plain Text Extension
873 *
874 * <Data>* --> GIF_Block
875 * <Data> --> while (...)
876 * <Special-Purpose Block> --> Gif_do_extension
877 * Graphic Control Extension --> Gif_do_extension
878 * Plain Text Extension --> Gif_do_extension
879 * <Table-Based Image> --> Gif_do_img_desc
880 *
881 * Return Value
882 * 0 if not enough data is present, otherwise the number of bytes
883 * "consumed"
884 */
885static size_t GIF_Block(DilloGif * gif, void *Buf,
886 const uchar_t *buf, size_t bsize)
887{
888 size_t Size = 0, mysize;
889 uchar_t C;
890
891 if (bsize < 1)
892 return 0;
893 while (gif->state == 2) {
894 if (bsize < 1)
895 return Size;
896 bsize--;
897 switch (*buf++) {
898 case Ext_Id:
899 /* get the extension type */
900 if (bsize < 2)
901 return Size;
902
903 /* Have the extension block intepreted. */
904 C = *buf++;
905 bsize--;
906 mysize = Gif_do_extension(gif, C, buf, bsize);
907
908 if (!mysize)
909 /* Not all of the extension is there.. quit until more data
910 * arrives */
911 return Size;
912
913 bsize -= mysize;
914 buf += mysize;
915
916 /* Increment the amount consumed by the extension introducer
917 * and id, and extension block size */
918 Size += mysize + 2;
919 /* Do more GIF Blocks */
920 continue;
921
922 case Img_Desc: /* Image descriptor */
923 mysize = Gif_do_img_desc(gif, Buf, buf, bsize);
924 if (!mysize)
925 return Size;
926
927 /* Increment the amount consumed by the Image Separator and the
928 * Resultant blocks */
929 Size += 1 + mysize;
930 return Size;
931
932 case Trailer:
933 gif->state = 999; /* BUG: should close the rest of the file */
934 return Size + 1;
935 break; /* GIF terminator */
936
937 default: /* Unknown */
938 /* gripe and complain */
939 MSG ("gif.c::GIF_Block: Error, 0x%x found\n", *(buf-1));
940 gif->state = 999;
941 return Size + 1;
942 }
943 }
944 return Size;
945}
946
947
948/*
949 * Process some bytes from the input gif stream. It's a state machine.
950 *
951 * From the GIF spec:
952 * <GIF Data Stream> ::= Header <Logical Screen> <Data>* Trailer
953 *
954 * <GIF Data Stream> --> Gif_process_bytes
955 * Header --> State 0
956 * <Logical Screen> --> State 1
957 * <Data>* --> State 2
958 * Trailer --> State > 3
959 *
960 * State == 3 is special... this is inside of <Data> but all of the stuff in
961 * there has been gotten and set up. So we stream it outside.
962 */
963static size_t Gif_process_bytes(DilloGif *gif, const uchar_t *ibuf,
964 int bufsize, void *Buf)
965{
966 int tmp_bufsize = bufsize;
967 size_t mysize;
968
969 switch (gif->state) {
970 case 0:
971 mysize = Gif_check_sig(gif, ibuf, tmp_bufsize);
972 if (!mysize)
973 break;
974 tmp_bufsize -= mysize;
975 ibuf += mysize;
976 if (gif->state != 1)
977 break;
978 /* fallthrough */
979 case 1:
980 mysize = Gif_get_descriptor(gif, Buf, ibuf, tmp_bufsize);
981 if (!mysize)
982 break;
983 tmp_bufsize -= mysize;
984 ibuf += mysize;
985 gif->state = 2;
986 /* fallthrough */
987 case 2:
988 /* Ok, this loop construction looks weird. It implements the <Data>* of
989 * the GIF grammar. All sorts of stuff is allocated to set up for the
990 * decode part (state ==2) and then there is the actual decode part (3)
991 */
992 mysize = GIF_Block(gif, Buf, ibuf, (size_t)tmp_bufsize);
993 if (!mysize)
994 break;
995 tmp_bufsize -= mysize;
996 ibuf += mysize;
997 if (gif->state != 3)
998 break;
999 /* fallthrough */
1000 case 3:
1001 /* get an image byte */
1002 /* The users sees all of this stuff */
1003 mysize = Gif_decode(gif, ibuf, (size_t)tmp_bufsize);
1004 if (mysize == 0)
1005 break;
1006 ibuf += mysize;
1007 tmp_bufsize -= mysize;
1008 /* fallthrough */
1009 default:
1010 /* error - just consume all input */
1011 tmp_bufsize = 0;
1012 break;
1013 }
1014
1015 _MSG("Gif_process_bytes: final state %d, %ld bytes consumed\n",
1016 gif->state, (long)(bufsize - tmp_bufsize));
1017
1018 return bufsize - tmp_bufsize;
1019}
1020
1021#else /* ENABLE_GIF */
1022
1023void *a_Gif_new() { return 0; }
1024void a_Gif_callback() { return; }
1025
1026#endif /* ENABLE_GIF */
#define _MSG(...)
Definition bookmarks.c:45
#define MSG(...)
Definition bookmarks.c:46
#define CA_Send
Definition cache.h:15
#define CA_Abort
Definition cache.h:17
#define CA_Close
Definition cache.h:16
unsigned char uchar_t
Definition d_size.h:17
unsigned int uint_t
Definition d_size.h:20
unsigned long ulong_t
Definition d_size.h:19
static const int bufsize
Definition decode.c:21
void a_Dicache_set_parms(DilloUrl *url, int version, DilloImage *Image, uint_t width, uint_t height, DilloImgType type, double gamma)
Set image's width, height & type.
Definition dicache.c:248
void a_Dicache_close(DilloUrl *url, int version, CacheClient_t *Client)
Implement the close method of the decoding process.
Definition dicache.c:349
void a_Dicache_write(DilloUrl *url, int version, const uchar_t *buf, uint_t Y)
Implement the write method (Write a scan line into the Dicache entry) buf: row buffer Y : row number.
Definition dicache.c:329
void a_Dicache_set_cmap(DilloUrl *url, int version, int bg_color, const uchar_t *cmap, uint_t num_colors, int num_colors_max, int bg_index)
Implement the set_cmap method for the Image.
Definition dicache.c:282
void dFree(void *mem)
Definition dlib.c:68
void * dMalloc(size_t size)
Definition dlib.c:45
void * dRealloc(void *mem, size_t size)
Definition dlib.c:53
#define MIN(a, b)
Definition dlib.h:30
static void error(char *msg)
Definition dpidc.c:39
static Fl_Window * window
#define IMAGE_MAX_AREA
Definition fltkimgbuf.cc:27
void a_Gif_callback()
Definition gif.c:1024
void * a_Gif_new()
Definition gif.c:1023
static uchar_t * linebuf
Definition imgbuf.cc:23
#define MSG_WARN(...)
Definition msg.h:26
@ DILLO_IMG_TYPE_INDEXED
Definition image.hh:43
Data structure for cache clients.
Definition cache.h:48
void * CbData
Client function data.
Definition cache.h:55
uint_t BufSize
Valid size of cache-data.
Definition cache.h:53
void * Buf
Pointer to cache-data.
Definition cache.h:52
Definition url.h:88
int32_t bg_color
Background color.
Definition image.hh:68
#define URL_STR(u)
Definition url.h:76