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