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