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