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