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