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