"Fossies" - the Fresh Open Source Software Archive

Member "clamav-0.102.3/libclamav/adc.c" (12 May 2020, 10478 Bytes) of package /linux/misc/clamav-0.102.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "adc.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.102.1_vs_0.102.2.

    1 /*
    2  *  Copyright (C) 2013-2020 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
    3  *  Copyright (C) 2013 Sourcefire, Inc.
    4  *
    5  *  Authors: David Raynor <draynor@sourcefire.com>
    6  *
    7  *  This program is free software; you can redistribute it and/or modify
    8  *  it under the terms of the GNU General Public License version 2 as
    9  *  published by the Free Software Foundation.
   10  *
   11  *  This program is distributed in the hope that it will be useful,
   12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14  *  GNU General Public License for more details.
   15  *
   16  *  You should have received a copy of the GNU General Public License
   17  *  along with this program; if not, write to the Free Software
   18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
   19  *  MA 02110-1301, USA.
   20  */
   21 
   22 #if HAVE_CONFIG_H
   23 #include "clamav-config.h"
   24 #endif
   25 
   26 #include <stdio.h>
   27 #include <errno.h>
   28 #if HAVE_STRING_H
   29 #include <string.h>
   30 #endif
   31 
   32 #include "clamav.h"
   33 #include "others.h"
   34 #include "adc.h"
   35 
   36 /* #define DEBUG_ADC */
   37 
   38 #ifdef DEBUG_ADC
   39 #define adc_dbgmsg(...) cli_dbgmsg(__VA_ARGS__)
   40 #else
   41 #define adc_dbgmsg(...) ;
   42 #endif
   43 
   44 /* Initialize values and collect buffer
   45  * NOTE: buffer size must be larger than largest lookback offset */
   46 int adc_decompressInit(adc_stream *strm)
   47 {
   48     if (strm == NULL) {
   49         return ADC_IO_ERROR;
   50     }
   51     if (strm->state != ADC_STATE_UNINIT) {
   52         return ADC_DATA_ERROR;
   53     }
   54 
   55     /* Have to buffer maximum backward lookup */
   56     strm->buffer = (uint8_t *)calloc(ADC_BUFF_SIZE, 1);
   57     if (strm->buffer == NULL) {
   58         return ADC_MEM_ERROR;
   59     }
   60     strm->buffered = 0;
   61     strm->state    = ADC_STATE_GETTYPE;
   62     strm->length   = 0;
   63     strm->offset   = 0;
   64     strm->curr     = strm->buffer;
   65 
   66     return ADC_OK;
   67 }
   68 
   69 /* Decompress routine
   70  * NOTE: Reaching end of input buffer does not mean end of output.
   71  * It may fill the output buffer but have more to output.
   72  * It will only return ADC_STREAM_END if output buffer is not full.
   73  * It will return ADC_DATA_ERROR if it ends in the middle of a phrase
   74  * (i.e. in the middle of a lookback code or data run)
   75  */
   76 int adc_decompress(adc_stream *strm)
   77 {
   78     uint8_t bData;
   79     uint8_t didNothing = 1;
   80 
   81     /* first, the error returns based on strm */
   82     if ((strm == NULL) || (strm->next_in == NULL) || (strm->next_out == NULL)) {
   83         return ADC_IO_ERROR;
   84     }
   85     if (strm->state == ADC_STATE_UNINIT) {
   86         return ADC_DATA_ERROR;
   87     }
   88 
   89     cli_dbgmsg("adc_decompress: avail_in %llu avail_out %llu state %u\n",
   90                (long long unsigned)strm->avail_in, (long long unsigned)strm->avail_out, strm->state);
   91 
   92     while (strm->avail_out) {
   93         /* Exit if needs more in bytes and none available */
   94         int needsInput;
   95         switch (strm->state) {
   96             case ADC_STATE_SHORTLOOK:
   97             case ADC_STATE_LONGLOOK:
   98                 needsInput = 0;
   99                 break;
  100             default:
  101                 needsInput = 1;
  102                 break;
  103         }
  104         if (needsInput && (strm->avail_in == 0)) {
  105             break;
  106         } else {
  107             didNothing = 0;
  108         }
  109 
  110         /* Find or execute statecode */
  111         switch (strm->state) {
  112             case ADC_STATE_GETTYPE: {
  113                 /* Grab action code */
  114                 bData = *(strm->next_in);
  115                 strm->next_in++;
  116                 strm->avail_in--;
  117                 if (bData & 0x80) {
  118                     strm->state  = ADC_STATE_RAWDATA;
  119                     strm->offset = 0;
  120                     strm->length = (bData & 0x7F) + 1;
  121                 } else if (bData & 0x40) {
  122                     strm->state  = ADC_STATE_LONGOP2;
  123                     strm->offset = 0;
  124                     strm->length = (bData & 0x3F) + 4;
  125                 } else {
  126                     strm->state  = ADC_STATE_SHORTOP;
  127                     strm->offset = (bData & 0x3) * 0x100;
  128                     strm->length = ((bData & 0x3C) >> 2) + 3;
  129                 }
  130                 adc_dbgmsg("adc_decompress: GETTYPE bData %x state %u offset %u length %u\n",
  131                            bData, strm->state, strm->offset, strm->length);
  132                 break;
  133             }
  134             case ADC_STATE_LONGOP2: {
  135                 /* Grab first offset byte */
  136                 bData = *(strm->next_in);
  137                 strm->next_in++;
  138                 strm->avail_in--;
  139                 strm->offset = bData * 0x100;
  140                 strm->state  = ADC_STATE_LONGOP1;
  141                 adc_dbgmsg("adc_decompress: LONGOP2 bData %x state %u offset %u length %u\n",
  142                            bData, strm->state, strm->offset, strm->length);
  143                 break;
  144             }
  145             case ADC_STATE_LONGOP1: {
  146                 /* Grab second offset byte */
  147                 bData = *(strm->next_in);
  148                 strm->next_in++;
  149                 strm->avail_in--;
  150                 strm->offset += bData + 1;
  151                 strm->state = ADC_STATE_LONGLOOK;
  152                 adc_dbgmsg("adc_decompress: LONGOP1 bData %x state %u offset %u length %u\n",
  153                            bData, strm->state, strm->offset, strm->length);
  154                 break;
  155             }
  156             case ADC_STATE_SHORTOP: {
  157                 /* Grab offset byte */
  158                 bData = *(strm->next_in);
  159                 strm->next_in++;
  160                 strm->avail_in--;
  161                 strm->offset += bData + 1;
  162                 strm->state = ADC_STATE_SHORTLOOK;
  163                 adc_dbgmsg("adc_decompress: SHORTOP bData %x state %u offset %u length %u\n",
  164                            bData, strm->state, strm->offset, strm->length);
  165                 break;
  166             }
  167 
  168             case ADC_STATE_RAWDATA: {
  169                 /* Grab data */
  170                 adc_dbgmsg("adc_decompress: RAWDATA offset %u length %u\n", strm->offset, strm->length);
  171                 while ((strm->avail_in > 0) && (strm->avail_out > 0) && (strm->length > 0)) {
  172                     bData = *(strm->next_in);
  173                     strm->next_in++;
  174                     strm->avail_in--;
  175                     /* store to output */
  176                     *(strm->next_out) = bData;
  177                     strm->next_out++;
  178                     strm->avail_out--;
  179                     /* store to buffer */
  180                     if (strm->curr >= (strm->buffer + ADC_BUFF_SIZE)) {
  181                         strm->curr = strm->buffer;
  182                     }
  183                     *(strm->curr) = bData;
  184                     strm->curr++;
  185                     if (strm->buffered < ADC_BUFF_SIZE) {
  186                         strm->buffered++;
  187                     }
  188                     strm->length--;
  189                 }
  190                 if (strm->length == 0) {
  191                     /* adc_dbgmsg("adc_decompress: RAWDATADONE buffered %u avail_in %u avail_out %u \n",
  192                         strm->buffered, strm->avail_in, strm->avail_out); */
  193                     strm->state = ADC_STATE_GETTYPE;
  194                 }
  195                 break;
  196             }
  197 
  198             case ADC_STATE_SHORTLOOK:
  199             case ADC_STATE_LONGLOOK: {
  200                 /* Copy data */
  201                 adc_dbgmsg("adc_decompress: LOOKBACK offset %u length %u avail_in %u avail_out %u\n",
  202                            strm->offset, strm->length, strm->avail_in, strm->avail_out);
  203                 while ((strm->avail_out > 0) && (strm->length > 0)) {
  204                     /* state validation first */
  205                     if (strm->offset > 0x10000) {
  206                         cli_dbgmsg("adc_decompress: bad LOOKBACK offset %u\n", strm->offset);
  207                         return ADC_DATA_ERROR;
  208                     } else if ((strm->state == ADC_STATE_SHORTLOOK) && (strm->offset > 0x400)) {
  209                         cli_dbgmsg("adc_decompress: bad LOOKBACK offset %u\n", strm->offset);
  210                         return ADC_DATA_ERROR;
  211                     }
  212                     if (strm->offset > strm->buffered) {
  213                         cli_dbgmsg("adc_decompress: too large LOOKBACK offset %u\n", strm->offset);
  214                         return ADC_DATA_ERROR;
  215                     }
  216                     /* retrieve byte */
  217                     if (strm->curr >= (strm->buffer + ADC_BUFF_SIZE)) {
  218                         strm->curr = strm->buffer;
  219                     }
  220                     if (strm->curr >= (strm->buffer + strm->offset)) {
  221                         bData = *(uint8_t *)(strm->curr - strm->offset);
  222                     } else {
  223                         bData = *(uint8_t *)(strm->curr + ADC_BUFF_SIZE - strm->offset);
  224                     }
  225                     /* store to output */
  226                     *(strm->next_out) = bData;
  227                     strm->next_out++;
  228                     strm->avail_out--;
  229                     /* store to buffer */
  230                     *(strm->curr) = bData;
  231                     strm->curr++;
  232                     if (strm->buffered < ADC_BUFF_SIZE) {
  233                         strm->buffered++;
  234                     }
  235                     strm->length--;
  236                 }
  237                 if (strm->length == 0) {
  238                     strm->state = ADC_STATE_GETTYPE;
  239                     /* adc_dbgmsg("adc_decompress: LOOKBACKDONE buffered %u avail_in %u avail_out %u \n",
  240                         strm->buffered, strm->avail_in, strm->avail_out); */
  241                 }
  242                 break;
  243             }
  244 
  245             default: {
  246                 /* bad state */
  247                 cli_errmsg("adc_decompress: invalid state %u\n", strm->state);
  248                 return ADC_DATA_ERROR;
  249             }
  250         } /* end switch */
  251     }     /* end while */
  252 
  253     /* There really isn't a terminator, just end of data */
  254     if (didNothing && strm->avail_out) {
  255         if (strm->state == ADC_STATE_GETTYPE) {
  256             /* Nothing left to do */
  257             return ADC_STREAM_END;
  258         } else {
  259             /* Ended mid phrase */
  260             cli_dbgmsg("adc_decompress: stream ended mid-phrase, state %u\n", strm->state);
  261             return ADC_DATA_ERROR;
  262         }
  263     }
  264     return ADC_OK;
  265 }
  266 
  267 /* Cleanup routine, frees buffer */
  268 int adc_decompressEnd(adc_stream *strm)
  269 {
  270     if (strm == NULL) {
  271         return ADC_IO_ERROR;
  272     }
  273     if (strm->state == ADC_STATE_UNINIT) {
  274         return ADC_DATA_ERROR;
  275     }
  276 
  277     if (strm->buffer != NULL) {
  278         free(strm->buffer);
  279     }
  280     strm->buffered = 0;
  281     strm->state    = ADC_STATE_UNINIT;
  282     strm->length   = 0;
  283     strm->offset   = 0;
  284 
  285     return ADC_OK;
  286 }