Jon's multiple AF patch: Sweep now takes care of all AFs
[privoxy.git] / deanimate.c
1 const char deanimate_rcs[] = "$Id: deanimate.c,v 1.10 2002/03/24 13:25:43 swa Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/deanimate.c,v $
5  *
6  * Purpose     :  Declares functions to deanimate GIF images on the fly.
7  *                
8  *                Functions declared include: gif_deanimate, buf_free,
9  *                buf_copy,  buf_getbyte, gif_skip_data_block, and
10  *                gif_extract_image
11  *
12  * Copyright   :  Written by and Copyright (C) 2001 by the the SourceForge
13  *                Privoxy team. http://www.privoxy.org/
14  *
15  *                Based on the GIF file format specification (see
16  *                http://tronche.com/computer-graphics/gif/gif89a.html)
17  *                and ideas from the Image::DeAnim Perl module by
18  *                Ken MacFarlane, <ksm+cpan@universal.dca.net>
19  *
20  *                This program is free software; you can redistribute it 
21  *                and/or modify it under the terms of the GNU General
22  *                Public License as published by the Free Software
23  *                Foundation; either version 2 of the License, or (at
24  *                your option) any later version.
25  *
26  *                This program is distributed in the hope that it will
27  *                be useful, but WITHOUT ANY WARRANTY; without even the
28  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
29  *                PARTICULAR PURPOSE.  See the GNU General Public
30  *                License for more details.
31  *
32  *                The GNU General Public License should be included with
33  *                this file.  If not, you can view it at
34  *                http://www.gnu.org/copyleft/gpl.html
35  *                or write to the Free Software Foundation, Inc., 59
36  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
37  *
38  * Revisions   :
39  *    $Log: deanimate.c,v $
40  *    Revision 1.10  2002/03/24 13:25:43  swa
41  *    name change related issues
42  *
43  *    Revision 1.9  2002/03/13 00:27:04  jongfoster
44  *    Killing warnings
45  *
46  *    Revision 1.8  2002/03/09 19:42:47  jongfoster
47  *    Fixing more warnings
48  *
49  *    Revision 1.7  2002/03/08 17:46:04  jongfoster
50  *    Fixing int/size_t warnings
51  *
52  *    Revision 1.6  2002/03/07 03:46:17  oes
53  *    Fixed compiler warnings
54  *
55  *    Revision 1.5  2001/09/10 10:16:06  oes
56  *    Silenced compiler warnings
57  *
58  *    Revision 1.4  2001/07/18 12:28:49  oes
59  *    - Added feature for extracting the first frame
60  *      to gif_deanimate
61  *    - Separated image buffer extension into buf_extend
62  *    - Extended gif deanimation to GIF87a (untested!)
63  *    - Cosmetics
64  *
65  *    Revision 1.3  2001/07/15 13:57:50  jongfoster
66  *    Adding #includes string.h and miscutil.h
67  *
68  *    Revision 1.2  2001/07/13 13:46:20  oes
69  *    Introduced GIF deanimation feature
70  *
71  *
72  **********************************************************************/
73 \f
74
75 #include "config.h"
76
77 #include <string.h>
78 #include <fcntl.h>
79
80 #include "project.h"
81 #include "deanimate.h"
82 #include "miscutil.h"
83
84 const char deanimate_h_rcs[] = DEANIMATE_H_VERSION;
85
86 /*********************************************************************
87  * 
88  * Function    :  buf_free
89  *
90  * Description :  Safely frees a struct binbuffer
91  *
92  * Parameters  :
93  *          1  :  buf = Pointer to the binbuffer to be freed
94  *
95  * Returns     :  N/A
96  *
97  *********************************************************************/
98 void buf_free(struct binbuffer *buf)
99 {
100    if (buf == NULL) return;
101
102    if (buf->buffer != NULL)
103    {
104       free(buf->buffer);
105    }
106
107    free(buf);
108
109 }
110
111
112 /*********************************************************************
113  * 
114  * Function    :  buf_extend
115  *
116  * Description :  Ensure that a given binbuffer can hold a given amount
117  *                of bytes, by reallocating its buffer if necessary.
118  *                Allocate new mem in chunks of 1024 bytes, so we don't
119  *                have to realloc() too often.
120  *
121  * Parameters  :
122  *          1  :  buf = Pointer to the binbuffer
123  *          2  :  length = Desired minimum size
124  *                
125  *
126  * Returns     :  0 on success, 1 on failiure.
127  *
128  *********************************************************************/
129 int buf_extend(struct binbuffer *buf, size_t length)
130 {
131    char *newbuf;
132
133    if (buf->offset + length > buf->size)
134    {
135       buf->size = ((buf->size + length + (size_t)1023) & ~(size_t)1023);
136       newbuf = (char *)realloc(buf->buffer, buf->size);
137
138       if (newbuf == NULL)
139       {
140          freez(buf->buffer);
141          return 1;
142       }
143       else
144       {
145          buf->buffer = newbuf;
146          return 0;
147       }
148    }
149    return 0;
150
151 }
152
153
154 /*********************************************************************
155  * 
156  * Function    :  buf_copy
157  *
158  * Description :  Safely copies a given amount of bytes from one
159  *                struct binbuffer to another, advancing the
160  *                offsets appropriately.
161  *
162  * Parameters  :
163  *          1  :  src = Pointer to the source binbuffer
164  *          2  :  dst = Pointer to the destination binbuffer
165  *          3  :  length = Number of bytes to be copied
166  *
167  * Returns     :  0 on success, 1 on failiure.
168  *
169  *********************************************************************/
170 int buf_copy(struct binbuffer *src, struct binbuffer *dst, size_t length)
171 {
172
173    /*
174     * Sanity check: Can't copy more data than we have
175     */
176    if (src->offset + length > src->size) 
177    {
178       return 1;
179    }
180
181    /*
182     * Ensure that dst can hold the new data
183     */
184    if (buf_extend(dst, length)) 
185    {
186       return 1;
187    }
188
189    /*
190     * Now that it's safe, memcpy() the desired amount of
191     * data from src to dst and adjust the offsets
192     */
193    memcpy(dst->buffer + dst->offset, src->buffer + src->offset, length);
194    src->offset += length;
195    dst->offset += length;
196
197    return 0;
198
199 }
200
201
202 /*********************************************************************
203  * 
204  * Function    :  buf_getbyte
205  *
206  * Description :  Safely gets a byte from a given binbuffer at a
207  *                given offset
208  *
209  * Parameters  :
210  *          1  :  buf = Pointer to the source binbuffer
211  *          2  :  offset = Offset to the desired byte
212  *
213  * Returns     :  The byte on success, or 0 on failiure
214  *
215  *********************************************************************/
216 unsigned char buf_getbyte(struct binbuffer *src, size_t offset)
217 {
218    if (src->offset + offset < src->size)
219    {
220       return (unsigned char)*(src->buffer + src->offset + offset);
221    }
222    else
223    {
224       return '\0';
225    }
226
227 }
228
229
230 /*********************************************************************
231  * 
232  * Function    :  gif_skip_data_block
233  *
234  * Description :  Safely advances the offset of a given struct binbuffer
235  *                that contains a GIF image and whose offset is
236  *                positioned at the start of a data block, behind
237  *                that block.
238  *
239  * Parameters  :
240  *          1  :  buf = Pointer to the binbuffer
241  *
242  * Returns     :  0 on success, or 1 on failiure
243  *
244  *********************************************************************/
245 int gif_skip_data_block(struct binbuffer *buf)
246 {
247    unsigned char c;
248
249    /* 
250     * Data blocks are sequences of chunks, which are headed
251     * by a one-byte length field, with the last chunk having
252     * zero length.
253     */
254    while((c = buf_getbyte(buf, 0)) != '\0')
255    {
256       if ((buf->offset += c + 1) >= buf->size - 1)
257       {
258          return 1;
259       }
260    }
261    buf->offset++;
262
263    return 0;
264
265 }
266
267
268 /*********************************************************************
269  * 
270  * Function    :  gif_extract_image
271  *
272  * Description :  Safely extracts an image data block from a given
273  *                struct binbuffer that contains a GIF image and whose
274  *                offset is positioned at the start of a data block 
275  *                into a given destination binbuffer.
276  *
277  * Parameters  :
278  *          1  :  src = Pointer to the source binbuffer
279  *          2  :  dst = Pointer to the destination binbuffer
280  *
281  * Returns     :  0 on success, or 1 on failiure
282  *
283  *********************************************************************/
284 int gif_extract_image(struct binbuffer *src, struct binbuffer *dst)
285 {
286    unsigned char c;
287    
288    /*
289     * Remember the colormap flag and copy the image head
290     */
291    c = buf_getbyte(src, 9);
292    if (buf_copy(src, dst, 10))
293    {
294       return 1;
295    }
296
297    /*
298     * If the image has a local colormap, copy it.
299     */
300    if (c & 0x80)
301    {
302       if (buf_copy(src, dst, (size_t) 3 * (1 << ((c & 0x07) + 1))))
303       {
304          return 1;
305       }           
306    }
307    if (buf_copy(src, dst, 1)) return 1;
308
309    /*
310     * Copy the image chunk by chunk.
311     */
312    while((c = buf_getbyte(src, 0)) != '\0')
313    {
314       if (buf_copy(src, dst, 1 + (size_t) c)) return 1;
315    }
316    if (buf_copy(src, dst, 1)) return 1;
317
318    /*
319     * Trim and rewind the dst buffer
320     */
321    if (NULL == (dst->buffer = (char *)realloc(dst->buffer, dst->offset))) return 1;
322    dst->size = dst->offset;
323    dst->offset = 0;
324
325    return(0);
326
327 }
328
329 /*********************************************************************
330  * 
331  * Function    :  gif_deanimate
332  *
333  * Description :  Deanimate a given GIF image, i.e. given a GIF with
334  *                an (optional) image block and an arbitrary number
335  *                of image extension blocks, produce an output GIF with
336  *                only one image block that contains the last image
337  *                (extenstion) block of the original.
338  *                Also strip Comments, Application extenstions, etc.
339  *
340  * Parameters  :
341  *          1  :  src = Pointer to the source binbuffer
342  *          2  :  dst = Pointer to the destination binbuffer
343  *          3  :  get_first_image = Flag: If set, get the first image
344  *                                        If unset (default), get the last
345  *
346  * Returns     :  0 on success, or 1 on failiure
347  *
348  *********************************************************************/
349 int gif_deanimate(struct binbuffer *src, struct binbuffer *dst, int get_first_image)
350 {
351    unsigned char c;
352    struct binbuffer *image;
353
354    if (NULL == src || NULL == dst)
355    {
356       return 1;
357    }
358
359    c = buf_getbyte(src, 10);
360
361    /*
362     * Check & copy GIF header 
363     */
364    if (strncmp(src->buffer, "GIF89a", 6) && strncmp(src->buffer, "GIF87a", 6)) 
365    {
366       return 1;
367    }
368    else
369    {
370       if (buf_copy(src, dst, 13))
371       {
372          return 1;
373       }
374    }
375
376    /*
377     * Look for global colormap and  copy if found.
378     */
379    if(c & 0x80)
380    {
381       if (buf_copy(src, dst, (size_t) 3 * (1 << ((c & 0x07) + 1))))
382       {
383          return 1;
384       }
385    }
386
387    /*
388     * Reserve a buffer for the current image block
389     */
390    if (NULL == (image = (struct binbuffer *)zalloc(sizeof(*image))))
391    {
392       return 1;
393    }
394
395    /*
396     * Parse the GIF block by block and copy the relevant
397     * parts to dst
398     */
399    while(src->offset < src->size)
400    {
401       switch(buf_getbyte(src, 0))
402       {
403          /*
404           *  End-of-GIF Marker: Append current image and return
405           */
406       case 0x3b:
407          goto write;
408
409          /* 
410           * Image block: Extract to current image buffer.
411           */
412       case 0x2c:
413          image->offset = 0;
414          if (gif_extract_image(src, image)) goto failed;
415          if (get_first_image) goto write;
416          continue;
417
418          /*
419           * Extension block: Look at next byte and decide
420           */
421       case 0x21:
422          switch (buf_getbyte(src, 1))
423          {
424             /*
425              * Image extension: Copy extension  header and image
426              *                  to the current image buffer
427              */
428          case 0xf9:
429             image->offset = 0;
430             if (buf_copy(src, image, 8) || buf_getbyte(src, 0) != 0x2c) goto failed;
431             if (gif_extract_image(src, image)) goto failed;
432             if (get_first_image) goto write;
433             continue;
434
435             /*
436              * Application extension: Skip
437              */
438          case 0xff:
439             if ((src->offset += 14) >= src->size || gif_skip_data_block(src)) goto failed;
440             continue;
441
442             /*
443              * Comment extension: Skip
444              */
445          case 0xfe:
446             if ((src->offset += 2) >= src->size || gif_skip_data_block(src)) goto failed;
447             continue;
448
449             /*
450              * Plain text extension: Skip
451              */
452          case 0x01:
453             if ((src->offset += 15) >= src->size || gif_skip_data_block(src)) goto failed;
454             continue;
455
456             /*
457              * Ooops, what type of extension is that?
458              */
459          default:
460             goto failed;
461
462          }
463
464          /*
465           * Ooops, what type of block is that?
466           */
467       default:
468          goto failed;
469          
470       }
471    } /* -END- while src */
472
473    /*
474     * Either we got here by goto, or because the GIF is
475     * bogus and EOF was reached before an end-of-gif marker 
476     * was found.
477     */
478
479 failed:
480    buf_free(image);
481    return 1;
482
483    /*
484     * Append the current image to dst and return
485     */
486
487 write:
488    if (buf_copy(image, dst, image->size)) goto failed;
489    if (buf_extend(dst, 1)) goto failed;
490    *(dst->buffer + dst->offset++) = 0x3b;
491    buf_free(image);
492    return 0;
493
494 }
495
496
497 /*
498   Local Variables:
499   tab-width: 3
500   end:
501 */