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