LCOV - code coverage report
Current view: top level - lib/libz - inffast.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 156 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 1 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13