-const char deanimate_rcs[] = "$Id: deanimate.c,v 1.19 2008/05/21 15:29:35 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/deanimate.c,v $
* Purpose : Declares functions to manipulate binary images on the
* fly. High-level functions include:
* - Deanimation of GIF images
- *
- * Functions declared include: gif_deanimate, buf_free,
- * buf_copy, buf_getbyte, gif_skip_data_block
- * and gif_extract_image
*
- * Copyright : Written by and Copyright (C) 2001 - 2004, 2006 by the
- * SourceForge Privoxy team. http://www.privoxy.org/
+ * Copyright : Written by and Copyright (C) 2001-2021 by the
+ * Privoxy team. https://www.privoxy.org/
*
* Based on the GIF file format specification (see
- * http://tronche.com/computer-graphics/gif/gif89a.html)
+ * https://tronche.com/computer-graphics/gif/gif89a.html)
* and ideas from the Image::DeAnim Perl module by
* Ken MacFarlane, <ksm+cpan@universal.dca.net>
*
- * This program is free software; you can redistribute it
+ * This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at
#include <string.h>
#include <fcntl.h>
-#include "errlog.h"
#include "project.h"
+#include "errlog.h"
#include "deanimate.h"
#include "miscutil.h"
-const char deanimate_h_rcs[] = DEANIMATE_H_VERSION;
-
/*********************************************************************
- *
+ *
* Function : buf_free
*
* Description : Safely frees a struct binbuffer
/*********************************************************************
- *
+ *
* Function : buf_extend
*
* Description : Ensure that a given binbuffer can hold a given amount
* Parameters :
* 1 : buf = Pointer to the binbuffer
* 2 : length = Desired minimum size
- *
+ *
*
* Returns : 0 on success, 1 on failure.
*
/*********************************************************************
- *
+ *
* Function : buf_copy
*
* Description : Safely copies a given amount of bytes from one
*********************************************************************/
static int buf_copy(struct binbuffer *src, struct binbuffer *dst, size_t length)
{
+ /*
+ * Sanity check: Make sure the source buffer contains
+ * data and there's work to be done.
+ */
+ if (src->buffer == NULL || src->size == 0 || length == 0)
+ {
+ return 1;
+ }
/*
* Sanity check: Can't copy more data than we have
*/
- if (src->offset + length > src->size)
+ if (src->offset + length > src->size)
{
return 1;
}
/*
* Ensure that dst can hold the new data
*/
- if (buf_extend(dst, length))
+ if (buf_extend(dst, length))
{
return 1;
}
/*********************************************************************
- *
+ *
* Function : buf_getbyte
*
* Description : Safely gets a byte from a given binbuffer at a
/*********************************************************************
- *
+ *
* Function : gif_skip_data_block
*
* Description : Safely advances the offset of a given struct binbuffer
{
unsigned char c;
- /*
+ /*
* Data blocks are sequences of chunks, which are headed
* by a one-byte length field, with the last chunk having
* zero length.
/*********************************************************************
- *
+ *
* Function : gif_extract_image
*
* Description : Safely extracts an image data block from a given
* struct binbuffer that contains a GIF image and whose
- * offset is positioned at the start of a data block
+ * offset is positioned at the start of a data block
* into a given destination binbuffer.
*
* Parameters :
if (buf_copy(src, dst, (size_t)map_length))
{
return 1;
- }
+ }
}
if (buf_copy(src, dst, 1)) return 1;
}
/*********************************************************************
- *
+ *
* Function : gif_deanimate
*
* Description : Deanimate a given GIF image, i.e. given a GIF with
* an (optional) image block and an arbitrary number
* of image extension blocks, produce an output GIF with
* only one image block that contains the last image
- * (extenstion) block of the original.
- * Also strip Comments, Application extenstions, etc.
+ * (extension) block of the original.
+ * Also strip Comments, Application extensions, etc.
*
* Parameters :
* 1 : src = Pointer to the source binbuffer
{
unsigned char c;
struct binbuffer *image;
+ int image_buffered = 0;
if (NULL == src || NULL == dst)
{
return 1;
}
+ if (src->size <= 10)
+ {
+ return 1;
+ }
c = buf_getbyte(src, 10);
/*
- * Check & copy GIF header
+ * Check & copy GIF header
*/
- if (strncmp(src->buffer, "GIF89a", 6) && strncmp(src->buffer, "GIF87a", 6))
+ if (strncmp(src->buffer, "GIF89a", 6) && strncmp(src->buffer, "GIF87a", 6))
{
return 1;
}
/*
* Look for global colormap and copy if found.
*/
- if(c & 0x80)
+ if (c & 0x80)
{
int map_length = 3 * (1 << ((c & 0x07) + 1));
if (map_length <= 0)
/*
* Reserve a buffer for the current image block
*/
- if (NULL == (image = (struct binbuffer *)zalloc(sizeof(*image))))
- {
- return 1;
- }
+ image = zalloc_or_die(sizeof(*image));
/*
* Parse the GIF block by block and copy the relevant
* parts to dst
*/
- while(src->offset < src->size)
+ while (src->offset < src->size)
{
- switch(buf_getbyte(src, 0))
+ switch (buf_getbyte(src, 0))
{
/*
- * End-of-GIF Marker: Append current image and return
+ * End-of-GIF Marker: Append current image if we got
+ * one and return.
*/
case 0x3b:
+ if (image->size == 0) goto failed;
goto write;
- /*
+ /*
* Image block: Extract to current image buffer.
*/
case 0x2c:
- image->offset = 0;
+ if (image_buffered == 1)
+ {
+ /* Discard previous image. */
+ image->offset = 0;
+ image_buffered = 0;
+ }
if (gif_extract_image(src, image)) goto failed;
+ image_buffered = 1;
if (get_first_image) goto write;
continue;
switch (buf_getbyte(src, 1))
{
/*
- * Image extension: Copy extension header and image
- * to the current image buffer
+ * Image extension: Copy extension header
+ * and continue looking for new blocks.
*/
case 0xf9:
- image->offset = 0;
- if (buf_copy(src, image, 8) || buf_getbyte(src, 0) != 0x2c) goto failed;
- if (gif_extract_image(src, image)) goto failed;
- if (get_first_image) goto write;
+ if (image_buffered == 1)
+ {
+ image->offset = 0;
+ image_buffered = 0;
+ }
+ if (buf_copy(src, image, 8)) goto failed;
continue;
/*
*/
default:
goto failed;
-
+
}
} /* -END- while src */
/*
* Either we got here by goto, or because the GIF is
- * bogus and EOF was reached before an end-of-gif marker
+ * bogus and EOF was reached before an end-of-gif marker
* was found.
*/