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