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