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