LCOV - code coverage report
Current view: top level - fuzz - deanimate.c (source / functions) Hit Total Coverage
Test: trace.lcov_info_final Lines: 105 114 92.1 %
Date: 2021-02-22 04:51:02 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*********************************************************************
       2             :  *
       3             :  * File        :  $Source: /cvsroot/ijbswa/current/deanimate.c,v $
       4             :  *
       5             :  * Purpose     :  Declares functions to manipulate binary images on the
       6             :  *                fly.  High-level functions include:
       7             :  *                  - Deanimation of GIF images
       8             :  *
       9             :  * Copyright   :  Written by and Copyright (C) 2001 - 2004, 2006 by the
      10             :  *                Privoxy team. https://www.privoxy.org/
      11             :  *
      12             :  *                Based on the GIF file format specification (see
      13             :  *                http://tronche.com/computer-graphics/gif/gif89a.html)
      14             :  *                and ideas from the Image::DeAnim Perl module by
      15             :  *                Ken MacFarlane, <ksm+cpan@universal.dca.net>
      16             :  *
      17             :  *                This program is free software; you can redistribute it
      18             :  *                and/or modify it under the terms of the GNU General
      19             :  *                Public License as published by the Free Software
      20             :  *                Foundation; either version 2 of the License, or (at
      21             :  *                your option) any later version.
      22             :  *
      23             :  *                This program is distributed in the hope that it will
      24             :  *                be useful, but WITHOUT ANY WARRANTY; without even the
      25             :  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
      26             :  *                PARTICULAR PURPOSE.  See the GNU General Public
      27             :  *                License for more details.
      28             :  *
      29             :  *                The GNU General Public License should be included with
      30             :  *                this file.  If not, you can view it at
      31             :  *                http://www.gnu.org/copyleft/gpl.html
      32             :  *                or write to the Free Software Foundation, Inc., 59
      33             :  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
      34             :  *
      35             :  **********************************************************************/
      36             : 
      37             : 
      38             : #include "config.h"
      39             : 
      40             : #include <string.h>
      41             : #include <fcntl.h>
      42             : 
      43             : #include "project.h"
      44             : #include "errlog.h"
      45             : #include "deanimate.h"
      46             : #include "miscutil.h"
      47             : 
      48             : /*********************************************************************
      49             :  *
      50             :  * Function    :  buf_free
      51             :  *
      52             :  * Description :  Safely frees a struct binbuffer
      53             :  *
      54             :  * Parameters  :
      55             :  *          1  :  buf = Pointer to the binbuffer to be freed
      56             :  *
      57             :  * Returns     :  N/A
      58             :  *
      59             :  *********************************************************************/
      60         990 : void buf_free(struct binbuffer *buf)
      61             : {
      62         990 :    if (buf == NULL) return;
      63             : 
      64         990 :    if (buf->buffer != NULL)
      65             :    {
      66         590 :       free(buf->buffer);
      67             :    }
      68             : 
      69         990 :    free(buf);
      70             : 
      71             : }
      72             : 
      73             : 
      74             : /*********************************************************************
      75             :  *
      76             :  * Function    :  buf_extend
      77             :  *
      78             :  * Description :  Ensure that a given binbuffer can hold a given amount
      79             :  *                of bytes, by reallocating its buffer if necessary.
      80             :  *                Allocate new mem in chunks of 1024 bytes, so we don't
      81             :  *                have to realloc() too often.
      82             :  *
      83             :  * Parameters  :
      84             :  *          1  :  buf = Pointer to the binbuffer
      85             :  *          2  :  length = Desired minimum size
      86             :  *
      87             :  *
      88             :  * Returns     :  0 on success, 1 on failure.
      89             :  *
      90             :  *********************************************************************/
      91        9279 : static int buf_extend(struct binbuffer *buf, size_t length)
      92             : {
      93             :    char *newbuf;
      94             : 
      95        9279 :    if (buf->offset + length > buf->size)
      96             :    {
      97        1005 :       buf->size = ((buf->size + length + (size_t)1023) & ~(size_t)1023);
      98        1005 :       newbuf = (char *)realloc(buf->buffer, buf->size);
      99             : 
     100        1005 :       if (newbuf == NULL)
     101             :       {
     102           0 :          freez(buf->buffer);
     103           0 :          return 1;
     104             :       }
     105             :       else
     106             :       {
     107        1005 :          buf->buffer = newbuf;
     108        1005 :          return 0;
     109             :       }
     110             :    }
     111        8274 :    return 0;
     112             : 
     113             : }
     114             : 
     115             : 
     116             : /*********************************************************************
     117             :  *
     118             :  * Function    :  buf_copy
     119             :  *
     120             :  * Description :  Safely copies a given amount of bytes from one
     121             :  *                struct binbuffer to another, advancing the
     122             :  *                offsets appropriately.
     123             :  *
     124             :  * Parameters  :
     125             :  *          1  :  src = Pointer to the source binbuffer
     126             :  *          2  :  dst = Pointer to the destination binbuffer
     127             :  *          3  :  length = Number of bytes to be copied
     128             :  *
     129             :  * Returns     :  0 on success, 1 on failure.
     130             :  *
     131             :  *********************************************************************/
     132        9420 : static int buf_copy(struct binbuffer *src, struct binbuffer *dst, size_t length)
     133             : {
     134             :    /*
     135             :     * Sanity check: Make sure the source buffer contains
     136             :     * data and there's work to be done.
     137             :     */
     138        9420 :    if (src->buffer == NULL || src->size == 0 || length == 0)
     139             :    {
     140           0 :       return 1;
     141             :    }
     142             : 
     143             :    /*
     144             :     * Sanity check: Can't copy more data than we have
     145             :     */
     146        9420 :    if ((src->offset + length) > src->size)
     147             :    {
     148         143 :       return 1;
     149             :    }
     150             : 
     151             :    /*
     152             :     * Ensure that dst can hold the new data
     153             :     */
     154        9277 :    if (buf_extend(dst, length))
     155             :    {
     156           0 :       return 1;
     157             :    }
     158             : 
     159             :    /*
     160             :     * Now that it's safe, memcpy() the desired amount of
     161             :     * data from src to dst and adjust the offsets
     162             :     */
     163        9277 :    memcpy(dst->buffer + dst->offset, src->buffer + src->offset, length);
     164        9277 :    src->offset += length;
     165        9277 :    dst->offset += length;
     166             : 
     167        9277 :    return 0;
     168             : 
     169             : }
     170             : 
     171             : 
     172             : /*********************************************************************
     173             :  *
     174             :  * Function    :  buf_getbyte
     175             :  *
     176             :  * Description :  Safely gets a byte from a given binbuffer at a
     177             :  *                given offset
     178             :  *
     179             :  * Parameters  :
     180             :  *          1  :  src = Pointer to the source binbuffer
     181             :  *          2  :  offset = Offset to the desired byte
     182             :  *
     183             :  * Returns     :  The byte on success, or 0 on failure
     184             :  *
     185             :  *********************************************************************/
     186       12090 : static unsigned char buf_getbyte(const struct binbuffer *src, size_t offset)
     187             : {
     188       12090 :    if (src->offset + offset < src->size)
     189             :    {
     190       12060 :       return (unsigned char)*(src->buffer + src->offset + offset);
     191             :    }
     192             :    else
     193             :    {
     194          30 :       return '\0';
     195             :    }
     196             : 
     197             : }
     198             : 
     199             : 
     200             : /*********************************************************************
     201             :  *
     202             :  * Function    :  gif_skip_data_block
     203             :  *
     204             :  * Description :  Safely advances the offset of a given struct binbuffer
     205             :  *                that contains a GIF image and whose offset is
     206             :  *                positioned at the start of a data block, behind
     207             :  *                that block.
     208             :  *
     209             :  * Parameters  :
     210             :  *          1  :  buf = Pointer to the binbuffer
     211             :  *
     212             :  * Returns     :  0 on success, or 1 on failure
     213             :  *
     214             :  *********************************************************************/
     215         245 : static int gif_skip_data_block(struct binbuffer *buf)
     216             : {
     217             :    unsigned char c;
     218             : 
     219             :    /*
     220             :     * Data blocks are sequences of chunks, which are headed
     221             :     * by a one-byte length field, with the last chunk having
     222             :     * zero length.
     223             :     */
     224        1925 :    while((c = buf_getbyte(buf, 0)) != '\0')
     225             :    {
     226        1825 :       buf->offset += (size_t)c + 1;
     227        1825 :       if (buf->offset >= buf->size - 1)
     228             :       {
     229         145 :          return 1;
     230             :       }
     231             :    }
     232         100 :    buf->offset++;
     233             : 
     234         100 :    return 0;
     235             : 
     236             : }
     237             : 
     238             : 
     239             : /*********************************************************************
     240             :  *
     241             :  * Function    :  gif_extract_image
     242             :  *
     243             :  * Description :  Safely extracts an image data block from a given
     244             :  *                struct binbuffer that contains a GIF image and whose
     245             :  *                offset is positioned at the start of a data block
     246             :  *                into a given destination binbuffer.
     247             :  *
     248             :  * Parameters  :
     249             :  *          1  :  src = Pointer to the source binbuffer
     250             :  *          2  :  dst = Pointer to the destination binbuffer
     251             :  *
     252             :  * Returns     :  0 on success, or 1 on failure
     253             :  *
     254             :  *********************************************************************/
     255         414 : static int gif_extract_image(struct binbuffer *src, struct binbuffer *dst)
     256             : {
     257             :    unsigned char c;
     258             : 
     259             :    /*
     260             :     * Remember the colormap flag and copy the image head
     261             :     */
     262         414 :    c = buf_getbyte(src, 9);
     263         414 :    if (buf_copy(src, dst, 10))
     264             :    {
     265           1 :       return 1;
     266             :    }
     267             : 
     268             :    /*
     269             :     * If the image has a local colormap, copy it.
     270             :     */
     271         413 :    if (c & 0x80)
     272             :    {
     273         103 :       int map_length = 3 * (1 << ((c & 0x07) + 1));
     274         103 :       if (map_length <= 0)
     275             :       {
     276           0 :          log_error(LOG_LEVEL_DEANIMATE,
     277             :             "colormap length = %d (%c)?", map_length, c);
     278           0 :          return 1;
     279             :       }
     280         103 :       if (buf_copy(src, dst, (size_t)map_length))
     281             :       {
     282           1 :          return 1;
     283             :       }
     284             :    }
     285         412 :    if (buf_copy(src, dst, 1)) return 1;
     286             : 
     287             :    /*
     288             :     * Copy the image chunk by chunk.
     289             :     */
     290        7317 :    while((c = buf_getbyte(src, 0)) != '\0')
     291             :    {
     292        6951 :       if (buf_copy(src, dst, 1 + (size_t) c)) return 1;
     293             :    }
     294         366 :    if (buf_copy(src, dst, 1)) return 1;
     295             : 
     296             :    /*
     297             :     * Trim and rewind the dst buffer
     298             :     */
     299         339 :    if (NULL == (dst->buffer = (char *)realloc(dst->buffer, dst->offset))) return 1;
     300         339 :    dst->size = dst->offset;
     301         339 :    dst->offset = 0;
     302             : 
     303         339 :    return(0);
     304             : 
     305             : }
     306             : 
     307             : /*********************************************************************
     308             :  *
     309             :  * Function    :  gif_deanimate
     310             :  *
     311             :  * Description :  Deanimate a given GIF image, i.e. given a GIF with
     312             :  *                an (optional) image block and an arbitrary number
     313             :  *                of image extension blocks, produce an output GIF with
     314             :  *                only one image block that contains the last image
     315             :  *                (extension) block of the original.
     316             :  *                Also strip Comments, Application extensions, etc.
     317             :  *
     318             :  * Parameters  :
     319             :  *          1  :  src = Pointer to the source binbuffer
     320             :  *          2  :  dst = Pointer to the destination binbuffer
     321             :  *          3  :  get_first_image = Flag: If set, get the first image
     322             :  *                                        If unset (default), get the last
     323             :  *
     324             :  * Returns     :  0 on success, or 1 on failure
     325             :  *
     326             :  *********************************************************************/
     327         566 : int gif_deanimate(struct binbuffer *src, struct binbuffer *dst, int get_first_image)
     328             : {
     329             :    unsigned char c;
     330             :    struct binbuffer *image;
     331             : 
     332         566 :    if (NULL == src || NULL == dst)
     333             :    {
     334           0 :       return 1;
     335             :    }
     336         566 :    if (src->size <= 10)
     337             :    {
     338           1 :       return 1;
     339             :    }
     340             : 
     341         565 :    c = buf_getbyte(src, 10);
     342             : 
     343             :    /*
     344             :     * Check & copy GIF header
     345             :     */
     346         565 :    if (strncmp(src->buffer, "GIF89a", 6) && strncmp(src->buffer, "GIF87a", 6))
     347             :    {
     348          72 :       return 1;
     349             :    }
     350             :    else
     351             :    {
     352         493 :       if (buf_copy(src, dst, 13))
     353             :       {
     354           1 :          return 1;
     355             :       }
     356             :    }
     357             : 
     358             :    /*
     359             :     * Look for global colormap and  copy if found.
     360             :     */
     361         492 :    if (c & 0x80)
     362             :    {
     363         306 :       int map_length = 3 * (1 << ((c & 0x07) + 1));
     364         306 :       if (map_length <= 0)
     365             :       {
     366           0 :          log_error(LOG_LEVEL_DEANIMATE,
     367             :             "colormap length = %d (%c)?", map_length, c);
     368           0 :          return 1;
     369             :       }
     370         306 :       if (buf_copy(src, dst, (size_t)map_length))
     371             :       {
     372          66 :          return 1;
     373             :       }
     374             :    }
     375             : 
     376             :    /*
     377             :     * Reserve a buffer for the current image block
     378             :     */
     379         426 :    image = zalloc_or_die(sizeof(*image));
     380             : 
     381             :    /*
     382             :     * Parse the GIF block by block and copy the relevant
     383             :     * parts to dst
     384             :     */
     385         865 :    while(src->offset < src->size)
     386             :    {
     387         863 :       switch(buf_getbyte(src, 0))
     388             :       {
     389             :          /*
     390             :           * End-of-GIF Marker: Append current image if we got
     391             :           * one and return.
     392             :           */
     393          12 :       case 0x3b:
     394          12 :          if (image->size == 0) goto failed;
     395           2 :          goto write;
     396             : 
     397             :          /*
     398             :           * Image block: Extract to current image buffer.
     399             :           */
     400          63 :       case 0x2c:
     401          63 :          image->offset = 0;
     402          63 :          if (gif_extract_image(src, image)) goto failed;
     403          11 :          if (get_first_image) goto write;
     404          11 :          continue;
     405             : 
     406             :          /*
     407             :           * Extension block: Look at next byte and decide
     408             :           */
     409         634 :       case 0x21:
     410         634 :          switch (buf_getbyte(src, 1))
     411             :          {
     412             :             /*
     413             :              * Image extension: Copy extension  header and image
     414             :              *                  to the current image buffer
     415             :              */
     416         373 :          case 0xf9:
     417         373 :             image->offset = 0;
     418         373 :             if (buf_copy(src, image, 8) || buf_getbyte(src, 0) != 0x2c) goto failed;
     419         351 :             if (gif_extract_image(src, image)) goto failed;
     420         328 :             if (get_first_image) goto write;
     421         328 :             continue;
     422             : 
     423             :             /*
     424             :              * Application extension: Skip
     425             :              */
     426          67 :          case 0xff:
     427          67 :             if ((src->offset += 14) >= src->size || gif_skip_data_block(src)) goto failed;
     428          55 :             continue;
     429             : 
     430             :             /*
     431             :              * Comment extension: Skip
     432             :              */
     433         150 :          case 0xfe:
     434         150 :             if ((src->offset += 2) >= src->size || gif_skip_data_block(src)) goto failed;
     435          24 :             continue;
     436             : 
     437             :             /*
     438             :              * Plain text extension: Skip
     439             :              */
     440          32 :          case 0x01:
     441          32 :             if ((src->offset += 15) >= src->size || gif_skip_data_block(src)) goto failed;
     442          21 :             continue;
     443             : 
     444             :             /*
     445             :              * Ooops, what type of extension is that?
     446             :              */
     447          12 :          default:
     448          12 :             goto failed;
     449             : 
     450             :          }
     451             : 
     452             :          /*
     453             :           * Ooops, what type of block is that?
     454             :           */
     455         154 :       default:
     456         154 :          goto failed;
     457             : 
     458             :       }
     459             :    } /* -END- while src */
     460             : 
     461             :    /*
     462             :     * Either we got here by goto, or because the GIF is
     463             :     * bogus and EOF was reached before an end-of-gif marker
     464             :     * was found.
     465             :     */
     466             : 
     467         424 : failed:
     468         424 :    buf_free(image);
     469         424 :    return 1;
     470             : 
     471             :    /*
     472             :     * Append the current image to dst and return
     473             :     */
     474             : 
     475           2 : write:
     476           2 :    if (buf_copy(image, dst, image->size)) goto failed;
     477           2 :    if (buf_extend(dst, 1)) goto failed;
     478           2 :    *(dst->buffer + dst->offset++) = 0x3b;
     479           2 :    buf_free(image);
     480           2 :    return 0;
     481             : 
     482             : }
     483             : 
     484             : 
     485             : /*
     486             :   Local Variables:
     487             :   tab-width: 3
     488             :   end:
     489             : */

Generated by: LCOV version 1.14