create-package-feed.pl: Only generate checksums for files that make it into the feed
[privoxy.git] / deanimate.c
1 const char deanimate_rcs[] = "$Id: deanimate.c,v 1.23 2012/03/09 16:24:36 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    image = zalloc_or_die(sizeof(*image));
371
372    /*
373     * Parse the GIF block by block and copy the relevant
374     * parts to dst
375     */
376    while(src->offset < src->size)
377    {
378       switch(buf_getbyte(src, 0))
379       {
380          /*
381           *  End-of-GIF Marker: Append current image and return
382           */
383       case 0x3b:
384          goto write;
385
386          /*
387           * Image block: Extract to current image buffer.
388           */
389       case 0x2c:
390          image->offset = 0;
391          if (gif_extract_image(src, image)) goto failed;
392          if (get_first_image) goto write;
393          continue;
394
395          /*
396           * Extension block: Look at next byte and decide
397           */
398       case 0x21:
399          switch (buf_getbyte(src, 1))
400          {
401             /*
402              * Image extension: Copy extension  header and image
403              *                  to the current image buffer
404              */
405          case 0xf9:
406             image->offset = 0;
407             if (buf_copy(src, image, 8) || buf_getbyte(src, 0) != 0x2c) goto failed;
408             if (gif_extract_image(src, image)) goto failed;
409             if (get_first_image) goto write;
410             continue;
411
412             /*
413              * Application extension: Skip
414              */
415          case 0xff:
416             if ((src->offset += 14) >= src->size || gif_skip_data_block(src)) goto failed;
417             continue;
418
419             /*
420              * Comment extension: Skip
421              */
422          case 0xfe:
423             if ((src->offset += 2) >= src->size || gif_skip_data_block(src)) goto failed;
424             continue;
425
426             /*
427              * Plain text extension: Skip
428              */
429          case 0x01:
430             if ((src->offset += 15) >= src->size || gif_skip_data_block(src)) goto failed;
431             continue;
432
433             /*
434              * Ooops, what type of extension is that?
435              */
436          default:
437             goto failed;
438
439          }
440
441          /*
442           * Ooops, what type of block is that?
443           */
444       default:
445          goto failed;
446
447       }
448    } /* -END- while src */
449
450    /*
451     * Either we got here by goto, or because the GIF is
452     * bogus and EOF was reached before an end-of-gif marker
453     * was found.
454     */
455
456 failed:
457    buf_free(image);
458    return 1;
459
460    /*
461     * Append the current image to dst and return
462     */
463
464 write:
465    if (buf_copy(image, dst, image->size)) goto failed;
466    if (buf_extend(dst, 1)) goto failed;
467    *(dst->buffer + dst->offset++) = 0x3b;
468    buf_free(image);
469    return 0;
470
471 }
472
473
474 /*
475   Local Variables:
476   tab-width: 3
477   end:
478 */