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