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