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