Drop the 'Functions declared include:' comment sections
[privoxy.git] / deanimate.c
1 const char deanimate_rcs[] = "$Id: deanimate.c,v 1.21 2011/09/04 11:10:56 fabiankeil Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/deanimate.c,v $
5  *
6  * Purpose     :  Declares functions to manipulate binary images on the
7  *                fly.  High-level functions include:
8  *                  - Deanimation of GIF images
9  *
10  * Copyright   :  Written by and Copyright (C) 2001 - 2004, 2006 by the
11  *                SourceForge Privoxy team. http://www.privoxy.org/
12  *
13  *                Based on the GIF file format specification (see
14  *                http://tronche.com/computer-graphics/gif/gif89a.html)
15  *                and ideas from the Image::DeAnim Perl module by
16  *                Ken MacFarlane, <ksm+cpan@universal.dca.net>
17  *
18  *                This program is free software; you can redistribute it
19  *                and/or modify it under the terms of the GNU General
20  *                Public License as published by the Free Software
21  *                Foundation; either version 2 of the License, or (at
22  *                your option) any later version.
23  *
24  *                This program is distributed in the hope that it will
25  *                be useful, but WITHOUT ANY WARRANTY; without even the
26  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
27  *                PARTICULAR PURPOSE.  See the GNU General Public
28  *                License for more details.
29  *
30  *                The GNU General Public License should be included with
31  *                this file.  If not, you can view it at
32  *                http://www.gnu.org/copyleft/gpl.html
33  *                or write to the Free Software Foundation, Inc., 59
34  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
35  *
36  **********************************************************************/
37
38
39 #include "config.h"
40
41 #include <string.h>
42 #include <fcntl.h>
43
44 #include "errlog.h"
45 #include "project.h"
46 #include "deanimate.h"
47 #include "miscutil.h"
48
49 const char deanimate_h_rcs[] = DEANIMATE_H_VERSION;
50
51 /*********************************************************************
52  *
53  * Function    :  buf_free
54  *
55  * Description :  Safely frees a struct binbuffer
56  *
57  * Parameters  :
58  *          1  :  buf = Pointer to the binbuffer to be freed
59  *
60  * Returns     :  N/A
61  *
62  *********************************************************************/
63 void buf_free(struct binbuffer *buf)
64 {
65    if (buf == NULL) return;
66
67    if (buf->buffer != NULL)
68    {
69       free(buf->buffer);
70    }
71
72    free(buf);
73
74 }
75
76
77 /*********************************************************************
78  *
79  * Function    :  buf_extend
80  *
81  * Description :  Ensure that a given binbuffer can hold a given amount
82  *                of bytes, by reallocating its buffer if necessary.
83  *                Allocate new mem in chunks of 1024 bytes, so we don't
84  *                have to realloc() too often.
85  *
86  * Parameters  :
87  *          1  :  buf = Pointer to the binbuffer
88  *          2  :  length = Desired minimum size
89  *
90  *
91  * Returns     :  0 on success, 1 on failure.
92  *
93  *********************************************************************/
94 static int buf_extend(struct binbuffer *buf, size_t length)
95 {
96    char *newbuf;
97
98    if (buf->offset + length > buf->size)
99    {
100       buf->size = ((buf->size + length + (size_t)1023) & ~(size_t)1023);
101       newbuf = (char *)realloc(buf->buffer, buf->size);
102
103       if (newbuf == NULL)
104       {
105          freez(buf->buffer);
106          return 1;
107       }
108       else
109       {
110          buf->buffer = newbuf;
111          return 0;
112       }
113    }
114    return 0;
115
116 }
117
118
119 /*********************************************************************
120  *
121  * Function    :  buf_copy
122  *
123  * Description :  Safely copies a given amount of bytes from one
124  *                struct binbuffer to another, advancing the
125  *                offsets appropriately.
126  *
127  * Parameters  :
128  *          1  :  src = Pointer to the source binbuffer
129  *          2  :  dst = Pointer to the destination binbuffer
130  *          3  :  length = Number of bytes to be copied
131  *
132  * Returns     :  0 on success, 1 on failure.
133  *
134  *********************************************************************/
135 static int buf_copy(struct binbuffer *src, struct binbuffer *dst, size_t length)
136 {
137
138    /*
139     * Sanity check: Can't copy more data than we have
140     */
141    if (src->offset + length > src->size)
142    {
143       return 1;
144    }
145
146    /*
147     * Ensure that dst can hold the new data
148     */
149    if (buf_extend(dst, length))
150    {
151       return 1;
152    }
153
154    /*
155     * Now that it's safe, memcpy() the desired amount of
156     * data from src to dst and adjust the offsets
157     */
158    memcpy(dst->buffer + dst->offset, src->buffer + src->offset, length);
159    src->offset += length;
160    dst->offset += length;
161
162    return 0;
163
164 }
165
166
167 /*********************************************************************
168  *
169  * Function    :  buf_getbyte
170  *
171  * Description :  Safely gets a byte from a given binbuffer at a
172  *                given offset
173  *
174  * Parameters  :
175  *          1  :  src = Pointer to the source binbuffer
176  *          2  :  offset = Offset to the desired byte
177  *
178  * Returns     :  The byte on success, or 0 on failure
179  *
180  *********************************************************************/
181 static unsigned char buf_getbyte(const struct binbuffer *src, size_t offset)
182 {
183    if (src->offset + offset < src->size)
184    {
185       return (unsigned char)*(src->buffer + src->offset + offset);
186    }
187    else
188    {
189       return '\0';
190    }
191
192 }
193
194
195 /*********************************************************************
196  *
197  * Function    :  gif_skip_data_block
198  *
199  * Description :  Safely advances the offset of a given struct binbuffer
200  *                that contains a GIF image and whose offset is
201  *                positioned at the start of a data block, behind
202  *                that block.
203  *
204  * Parameters  :
205  *          1  :  buf = Pointer to the binbuffer
206  *
207  * Returns     :  0 on success, or 1 on failure
208  *
209  *********************************************************************/
210 static int gif_skip_data_block(struct binbuffer *buf)
211 {
212    unsigned char c;
213
214    /*
215     * Data blocks are sequences of chunks, which are headed
216     * by a one-byte length field, with the last chunk having
217     * zero length.
218     */
219    while((c = buf_getbyte(buf, 0)) != '\0')
220    {
221       buf->offset += (size_t)c + 1;
222       if (buf->offset >= buf->size - 1)
223       {
224          return 1;
225       }
226    }
227    buf->offset++;
228
229    return 0;
230
231 }
232
233
234 /*********************************************************************
235  *
236  * Function    :  gif_extract_image
237  *
238  * Description :  Safely extracts an image data block from a given
239  *                struct binbuffer that contains a GIF image and whose
240  *                offset is positioned at the start of a data block
241  *                into a given destination binbuffer.
242  *
243  * Parameters  :
244  *          1  :  src = Pointer to the source binbuffer
245  *          2  :  dst = Pointer to the destination binbuffer
246  *
247  * Returns     :  0 on success, or 1 on failure
248  *
249  *********************************************************************/
250 static int gif_extract_image(struct binbuffer *src, struct binbuffer *dst)
251 {
252    unsigned char c;
253
254    /*
255     * Remember the colormap flag and copy the image head
256     */
257    c = buf_getbyte(src, 9);
258    if (buf_copy(src, dst, 10))
259    {
260       return 1;
261    }
262
263    /*
264     * If the image has a local colormap, copy it.
265     */
266    if (c & 0x80)
267    {
268       int map_length = 3 * (1 << ((c & 0x07) + 1));
269       if (map_length <= 0)
270       {
271          log_error(LOG_LEVEL_DEANIMATE,
272             "colormap length = %d (%c)?", map_length, c);
273          return 1;
274       }
275       if (buf_copy(src, dst, (size_t)map_length))
276       {
277          return 1;
278       }
279    }
280    if (buf_copy(src, dst, 1)) return 1;
281
282    /*
283     * Copy the image chunk by chunk.
284     */
285    while((c = buf_getbyte(src, 0)) != '\0')
286    {
287       if (buf_copy(src, dst, 1 + (size_t) c)) return 1;
288    }
289    if (buf_copy(src, dst, 1)) return 1;
290
291    /*
292     * Trim and rewind the dst buffer
293     */
294    if (NULL == (dst->buffer = (char *)realloc(dst->buffer, dst->offset))) return 1;
295    dst->size = dst->offset;
296    dst->offset = 0;
297
298    return(0);
299
300 }
301
302 /*********************************************************************
303  *
304  * Function    :  gif_deanimate
305  *
306  * Description :  Deanimate a given GIF image, i.e. given a GIF with
307  *                an (optional) image block and an arbitrary number
308  *                of image extension blocks, produce an output GIF with
309  *                only one image block that contains the last image
310  *                (extenstion) block of the original.
311  *                Also strip Comments, Application extenstions, etc.
312  *
313  * Parameters  :
314  *          1  :  src = Pointer to the source binbuffer
315  *          2  :  dst = Pointer to the destination binbuffer
316  *          3  :  get_first_image = Flag: If set, get the first image
317  *                                        If unset (default), get the last
318  *
319  * Returns     :  0 on success, or 1 on failure
320  *
321  *********************************************************************/
322 int gif_deanimate(struct binbuffer *src, struct binbuffer *dst, int get_first_image)
323 {
324    unsigned char c;
325    struct binbuffer *image;
326
327    if (NULL == src || NULL == dst)
328    {
329       return 1;
330    }
331
332    c = buf_getbyte(src, 10);
333
334    /*
335     * Check & copy GIF header
336     */
337    if (strncmp(src->buffer, "GIF89a", 6) && strncmp(src->buffer, "GIF87a", 6))
338    {
339       return 1;
340    }
341    else
342    {
343       if (buf_copy(src, dst, 13))
344       {
345          return 1;
346       }
347    }
348
349    /*
350     * Look for global colormap and  copy if found.
351     */
352    if(c & 0x80)
353    {
354       int map_length = 3 * (1 << ((c & 0x07) + 1));
355       if (map_length <= 0)
356       {
357          log_error(LOG_LEVEL_DEANIMATE,
358             "colormap length = %d (%c)?", map_length, c);
359          return 1;
360       }
361       if (buf_copy(src, dst, (size_t)map_length))
362       {
363          return 1;
364       }
365    }
366
367    /*
368     * Reserve a buffer for the current image block
369     */
370    if (NULL == (image = (struct binbuffer *)zalloc(sizeof(*image))))
371    {
372       return 1;
373    }
374
375    /*
376     * Parse the GIF block by block and copy the relevant
377     * parts to dst
378     */
379    while(src->offset < src->size)
380    {
381       switch(buf_getbyte(src, 0))
382       {
383          /*
384           *  End-of-GIF Marker: Append current image and return
385           */
386       case 0x3b:
387          goto write;
388
389          /*
390           * Image block: Extract to current image buffer.
391           */
392       case 0x2c:
393          image->offset = 0;
394          if (gif_extract_image(src, image)) goto failed;
395          if (get_first_image) goto write;
396          continue;
397
398          /*
399           * Extension block: Look at next byte and decide
400           */
401       case 0x21:
402          switch (buf_getbyte(src, 1))
403          {
404             /*
405              * Image extension: Copy extension  header and image
406              *                  to the current image buffer
407              */
408          case 0xf9:
409             image->offset = 0;
410             if (buf_copy(src, image, 8) || buf_getbyte(src, 0) != 0x2c) goto failed;
411             if (gif_extract_image(src, image)) goto failed;
412             if (get_first_image) goto write;
413             continue;
414
415             /*
416              * Application extension: Skip
417              */
418          case 0xff:
419             if ((src->offset += 14) >= src->size || gif_skip_data_block(src)) goto failed;
420             continue;
421
422             /*
423              * Comment extension: Skip
424              */
425          case 0xfe:
426             if ((src->offset += 2) >= src->size || gif_skip_data_block(src)) goto failed;
427             continue;
428
429             /*
430              * Plain text extension: Skip
431              */
432          case 0x01:
433             if ((src->offset += 15) >= src->size || gif_skip_data_block(src)) goto failed;
434             continue;
435
436             /*
437              * Ooops, what type of extension is that?
438              */
439          default:
440             goto failed;
441
442          }
443
444          /*
445           * Ooops, what type of block is that?
446           */
447       default:
448          goto failed;
449
450       }
451    } /* -END- while src */
452
453    /*
454     * Either we got here by goto, or because the GIF is
455     * bogus and EOF was reached before an end-of-gif marker
456     * was found.
457     */
458
459 failed:
460    buf_free(image);
461    return 1;
462
463    /*
464     * Append the current image to dst and return
465     */
466
467 write:
468    if (buf_copy(image, dst, image->size)) goto failed;
469    if (buf_extend(dst, 1)) goto failed;
470    *(dst->buffer + dst->offset++) = 0x3b;
471    buf_free(image);
472    return 0;
473
474 }
475
476
477 /*
478   Local Variables:
479   tab-width: 3
480   end:
481 */