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