LCOV - code coverage report
Current view: directory - modules/zlib/src - inffast.c (source / functions) Found Hit Coverage
Test: app.info Lines: 143 106 74.1 %
Date: 2012-06-02 Functions: 1 1 100.0 %

       1                 : /* inffast.c -- fast decoding
       2                 :  * Copyright (C) 1995-2008, 2010 Mark Adler
       3                 :  * For conditions of distribution and use, see copyright notice in zlib.h
       4                 :  */
       5                 : 
       6                 : #include "zutil.h"
       7                 : #include "inftrees.h"
       8                 : #include "inflate.h"
       9                 : #include "inffast.h"
      10                 : 
      11                 : #ifndef ASMINF
      12                 : 
      13                 : /* Allow machine dependent optimization for post-increment or pre-increment.
      14                 :    Based on testing to date,
      15                 :    Pre-increment preferred for:
      16                 :    - PowerPC G3 (Adler)
      17                 :    - MIPS R5000 (Randers-Pehrson)
      18                 :    Post-increment preferred for:
      19                 :    - none
      20                 :    No measurable difference:
      21                 :    - Pentium III (Anderson)
      22                 :    - M68060 (Nikl)
      23                 :  */
      24                 : #ifdef POSTINC
      25                 : #  define OFF 0
      26                 : #  define PUP(a) *(a)++
      27                 : #else
      28                 : #  define OFF 1
      29                 : #  define PUP(a) *++(a)
      30                 : #endif
      31                 : 
      32                 : /*
      33                 :    Decode literal, length, and distance codes and write out the resulting
      34                 :    literal and match bytes until either not enough input or output is
      35                 :    available, an end-of-block is encountered, or a data error is encountered.
      36                 :    When large enough input and output buffers are supplied to inflate(), for
      37                 :    example, a 16K input buffer and a 64K output buffer, more than 95% of the
      38                 :    inflate execution time is spent in this routine.
      39                 : 
      40                 :    Entry assumptions:
      41                 : 
      42                 :         state->mode == LEN
      43                 :         strm->avail_in >= 6
      44                 :         strm->avail_out >= 258
      45                 :         start >= strm->avail_out
      46                 :         state->bits < 8
      47                 : 
      48                 :    On return, state->mode is one of:
      49                 : 
      50                 :         LEN -- ran out of enough output space or enough available input
      51                 :         TYPE -- reached end of block code, inflate() to interpret next block
      52                 :         BAD -- error in block data
      53                 : 
      54                 :    Notes:
      55                 : 
      56                 :     - The maximum input bits used by a length/distance pair is 15 bits for the
      57                 :       length code, 5 bits for the length extra, 15 bits for the distance code,
      58                 :       and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
      59                 :       Therefore if strm->avail_in >= 6, then there is enough input to avoid
      60                 :       checking for available input while decoding.
      61                 : 
      62                 :     - The maximum bytes that a single length/distance pair can output is 258
      63                 :       bytes, which is the maximum length that can be coded.  inflate_fast()
      64                 :       requires strm->avail_out >= 258 for each loop to avoid checking for
      65                 :       output space.
      66                 :  */
      67            1671 : void ZLIB_INTERNAL inflate_fast(strm, start)
      68                 : z_streamp strm;
      69                 : unsigned start;         /* inflate()'s starting value for strm->avail_out */
      70                 : {
      71                 :     struct inflate_state FAR *state;
      72                 :     unsigned char FAR *in;      /* local strm->next_in */
      73                 :     unsigned char FAR *last;    /* while in < last, enough input available */
      74                 :     unsigned char FAR *out;     /* local strm->next_out */
      75                 :     unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
      76                 :     unsigned char FAR *end;     /* while out < end, enough space available */
      77                 : #ifdef INFLATE_STRICT
      78                 :     unsigned dmax;              /* maximum distance from zlib header */
      79                 : #endif
      80                 :     unsigned wsize;             /* window size or zero if not using window */
      81                 :     unsigned whave;             /* valid bytes in the window */
      82                 :     unsigned wnext;             /* window write index */
      83                 :     unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
      84                 :     unsigned long hold;         /* local strm->hold */
      85                 :     unsigned bits;              /* local strm->bits */
      86                 :     code const FAR *lcode;      /* local strm->lencode */
      87                 :     code const FAR *dcode;      /* local strm->distcode */
      88                 :     unsigned lmask;             /* mask for first level of length codes */
      89                 :     unsigned dmask;             /* mask for first level of distance codes */
      90                 :     code here;                  /* retrieved table entry */
      91                 :     unsigned op;                /* code bits, operation, extra bits, or */
      92                 :                                 /*  window position, window bytes to copy */
      93                 :     unsigned len;               /* match length, unused bytes */
      94                 :     unsigned dist;              /* match distance */
      95                 :     unsigned char FAR *from;    /* where to copy match from */
      96                 : 
      97                 :     /* copy state to local variables */
      98            1671 :     state = (struct inflate_state FAR *)strm->state;
      99            1671 :     in = strm->next_in - OFF;
     100            1671 :     last = in + (strm->avail_in - 5);
     101            1671 :     out = strm->next_out - OFF;
     102            1671 :     beg = out - (start - strm->avail_out);
     103            1671 :     end = out + (strm->avail_out - 257);
     104                 : #ifdef INFLATE_STRICT
     105                 :     dmax = state->dmax;
     106                 : #endif
     107            1671 :     wsize = state->wsize;
     108            1671 :     whave = state->whave;
     109            1671 :     wnext = state->wnext;
     110            1671 :     window = state->window;
     111            1671 :     hold = state->hold;
     112            1671 :     bits = state->bits;
     113            1671 :     lcode = state->lencode;
     114            1671 :     dcode = state->distcode;
     115            1671 :     lmask = (1U << state->lenbits) - 1;
     116            1671 :     dmask = (1U << state->distbits) - 1;
     117                 : 
     118                 :     /* decode literals and length/distances until end-of-block or not enough
     119                 :        input data or output space */
     120                 :     do {
     121          300213 :         if (bits < 15) {
     122          114635 :             hold += (unsigned long)(PUP(in)) << bits;
     123          114635 :             bits += 8;
     124          114635 :             hold += (unsigned long)(PUP(in)) << bits;
     125          114635 :             bits += 8;
     126                 :         }
     127          300213 :         here = lcode[hold & lmask];
     128                 :       dolen:
     129          300243 :         op = (unsigned)(here.bits);
     130          300243 :         hold >>= op;
     131          300243 :         bits -= op;
     132          300243 :         op = (unsigned)(here.op);
     133          300243 :         if (op == 0) {                          /* literal */
     134                 :             Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
     135                 :                     "inflate:         literal '%c'\n" :
     136                 :                     "inflate:         literal 0x%02x\n", here.val));
     137          256332 :             PUP(out) = (unsigned char)(here.val);
     138                 :         }
     139           43911 :         else if (op & 16) {                     /* length base */
     140           43879 :             len = (unsigned)(here.val);
     141           43879 :             op &= 15;                           /* number of extra bits */
     142           43879 :             if (op) {
     143            7922 :                 if (bits < op) {
     144               0 :                     hold += (unsigned long)(PUP(in)) << bits;
     145               0 :                     bits += 8;
     146                 :                 }
     147            7922 :                 len += (unsigned)hold & ((1U << op) - 1);
     148            7922 :                 hold >>= op;
     149            7922 :                 bits -= op;
     150                 :             }
     151                 :             Tracevv((stderr, "inflate:         length %u\n", len));
     152           43879 :             if (bits < 15) {
     153           17296 :                 hold += (unsigned long)(PUP(in)) << bits;
     154           17296 :                 bits += 8;
     155           17296 :                 hold += (unsigned long)(PUP(in)) << bits;
     156           17296 :                 bits += 8;
     157                 :             }
     158           43879 :             here = dcode[hold & dmask];
     159                 :           dodist:
     160           43910 :             op = (unsigned)(here.bits);
     161           43910 :             hold >>= op;
     162           43910 :             bits -= op;
     163           43910 :             op = (unsigned)(here.op);
     164           43910 :             if (op & 16) {                      /* distance base */
     165           43879 :                 dist = (unsigned)(here.val);
     166           43879 :                 op &= 15;                       /* number of extra bits */
     167           43879 :                 if (bits < op) {
     168               1 :                     hold += (unsigned long)(PUP(in)) << bits;
     169               1 :                     bits += 8;
     170               1 :                     if (bits < op) {
     171               0 :                         hold += (unsigned long)(PUP(in)) << bits;
     172               0 :                         bits += 8;
     173                 :                     }
     174                 :                 }
     175           43879 :                 dist += (unsigned)hold & ((1U << op) - 1);
     176                 : #ifdef INFLATE_STRICT
     177                 :                 if (dist > dmax) {
     178                 :                     strm->msg = (char *)"invalid distance too far back";
     179                 :                     state->mode = BAD;
     180                 :                     break;
     181                 :                 }
     182                 : #endif
     183           43879 :                 hold >>= op;
     184           43879 :                 bits -= op;
     185                 :                 Tracevv((stderr, "inflate:         distance %u\n", dist));
     186           43879 :                 op = (unsigned)(out - beg);     /* max distance in output */
     187           43879 :                 if (dist > op) {                /* see if copy from window */
     188              57 :                     op = dist - op;             /* distance back in window */
     189              57 :                     if (op > whave) {
     190               0 :                         if (state->sane) {
     191               0 :                             strm->msg =
     192                 :                                 (char *)"invalid distance too far back";
     193               0 :                             state->mode = BAD;
     194               0 :                             break;
     195                 :                         }
     196                 : #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
     197                 :                         if (len <= op - whave) {
     198                 :                             do {
     199                 :                                 PUP(out) = 0;
     200                 :                             } while (--len);
     201                 :                             continue;
     202                 :                         }
     203                 :                         len -= op - whave;
     204                 :                         do {
     205                 :                             PUP(out) = 0;
     206                 :                         } while (--op > whave);
     207                 :                         if (op == 0) {
     208                 :                             from = out - dist;
     209                 :                             do {
     210                 :                                 PUP(out) = PUP(from);
     211                 :                             } while (--len);
     212                 :                             continue;
     213                 :                         }
     214                 : #endif
     215                 :                     }
     216              57 :                     from = window - OFF;
     217              57 :                     if (wnext == 0) {           /* very common case */
     218               0 :                         from += wsize - op;
     219               0 :                         if (op < len) {         /* some from window */
     220               0 :                             len -= op;
     221                 :                             do {
     222               0 :                                 PUP(out) = PUP(from);
     223               0 :                             } while (--op);
     224               0 :                             from = out - dist;  /* rest from output */
     225                 :                         }
     226                 :                     }
     227              57 :                     else if (wnext < op) {      /* wrap around window */
     228               0 :                         from += wsize + wnext - op;
     229               0 :                         op -= wnext;
     230               0 :                         if (op < len) {         /* some from end of window */
     231               0 :                             len -= op;
     232                 :                             do {
     233               0 :                                 PUP(out) = PUP(from);
     234               0 :                             } while (--op);
     235               0 :                             from = window - OFF;
     236               0 :                             if (wnext < len) {  /* some from start of window */
     237               0 :                                 op = wnext;
     238               0 :                                 len -= op;
     239                 :                                 do {
     240               0 :                                     PUP(out) = PUP(from);
     241               0 :                                 } while (--op);
     242               0 :                                 from = out - dist;      /* rest from output */
     243                 :                             }
     244                 :                         }
     245                 :                     }
     246                 :                     else {                      /* contiguous in window */
     247              57 :                         from += wnext - op;
     248              57 :                         if (op < len) {         /* some from window */
     249               0 :                             len -= op;
     250                 :                             do {
     251               0 :                                 PUP(out) = PUP(from);
     252               0 :                             } while (--op);
     253               0 :                             from = out - dist;  /* rest from output */
     254                 :                         }
     255                 :                     }
     256             426 :                     while (len > 2) {
     257             312 :                         PUP(out) = PUP(from);
     258             312 :                         PUP(out) = PUP(from);
     259             312 :                         PUP(out) = PUP(from);
     260             312 :                         len -= 3;
     261                 :                     }
     262              57 :                     if (len) {
     263              31 :                         PUP(out) = PUP(from);
     264              31 :                         if (len > 1)
     265               8 :                             PUP(out) = PUP(from);
     266                 :                     }
     267                 :                 }
     268                 :                 else {
     269           43822 :                     from = out - dist;          /* copy direct from output */
     270                 :                     do {                        /* minimum length is three */
     271          108377 :                         PUP(out) = PUP(from);
     272          108377 :                         PUP(out) = PUP(from);
     273          108377 :                         PUP(out) = PUP(from);
     274          108377 :                         len -= 3;
     275          108377 :                     } while (len > 2);
     276           43822 :                     if (len) {
     277           26545 :                         PUP(out) = PUP(from);
     278           26545 :                         if (len > 1)
     279           13886 :                             PUP(out) = PUP(from);
     280                 :                     }
     281                 :                 }
     282                 :             }
     283              31 :             else if ((op & 64) == 0) {          /* 2nd level distance code */
     284              31 :                 here = dcode[here.val + (hold & ((1U << op) - 1))];
     285              31 :                 goto dodist;
     286                 :             }
     287                 :             else {
     288               0 :                 strm->msg = (char *)"invalid distance code";
     289               0 :                 state->mode = BAD;
     290               0 :                 break;
     291                 :             }
     292                 :         }
     293              32 :         else if ((op & 64) == 0) {              /* 2nd level length code */
     294              30 :             here = lcode[here.val + (hold & ((1U << op) - 1))];
     295              30 :             goto dolen;
     296                 :         }
     297               2 :         else if (op & 32) {                     /* end-of-block */
     298                 :             Tracevv((stderr, "inflate:         end of block\n"));
     299               2 :             state->mode = TYPE;
     300               2 :             break;
     301                 :         }
     302                 :         else {
     303               0 :             strm->msg = (char *)"invalid literal/length code";
     304               0 :             state->mode = BAD;
     305               0 :             break;
     306                 :         }
     307          300211 :     } while (in < last && out < end);
     308                 : 
     309                 :     /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
     310            1671 :     len = bits >> 3;
     311            1671 :     in -= len;
     312            1671 :     bits -= len << 3;
     313            1671 :     hold &= (1U << bits) - 1;
     314                 : 
     315                 :     /* update state and return */
     316            1671 :     strm->next_in = in + OFF;
     317            1671 :     strm->next_out = out + OFF;
     318            1671 :     strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
     319            3342 :     strm->avail_out = (unsigned)(out < end ?
     320            1671 :                                  257 + (end - out) : 257 - (out - end));
     321            1671 :     state->hold = hold;
     322            1671 :     state->bits = bits;
     323                 :     return;
     324                 : }
     325                 : 
     326                 : /*
     327                 :    inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
     328                 :    - Using bit fields for code structure
     329                 :    - Different op definition to avoid & for extra bits (do & for table bits)
     330                 :    - Three separate decoding do-loops for direct, window, and wnext == 0
     331                 :    - Special case for distance > 1 copies to do overlapped load and store copy
     332                 :    - Explicit branch predictions (based on measured branch probabilities)
     333                 :    - Deferring match copy and interspersed it with decoding subsequent codes
     334                 :    - Swapping literal/length else
     335                 :    - Swapping window/direct else
     336                 :    - Larger unrolled copy loops (three is about right)
     337                 :    - Moving len -= 3 statement into middle of loop
     338                 :  */
     339                 : 
     340                 : #endif /* !ASMINF */

Generated by: LCOV version 1.7