[BACK]Return to inffast.c CVS log [TXT][DIR] Up to [local] / sys / lib / libz

Annotation of sys/lib/libz/inffast.c, Revision 1.1.1.1

1.1       nbrk        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: 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:     state = (struct inflate_state FAR *)strm->state;
                    100:     in = strm->next_in - OFF;
                    101:     last = in + (strm->avail_in - 5);
                    102:     out = strm->next_out - OFF;
                    103:     beg = out - (start - strm->avail_out);
                    104:     end = out + (strm->avail_out - 257);
                    105: #ifdef INFLATE_STRICT
                    106:     dmax = state->dmax;
                    107: #endif
                    108:     wsize = state->wsize;
                    109:     whave = state->whave;
                    110:     write = state->write;
                    111:     window = state->window;
                    112:     hold = state->hold;
                    113:     bits = state->bits;
                    114:     lcode = state->lencode;
                    115:     dcode = state->distcode;
                    116:     lmask = (1U << state->lenbits) - 1;
                    117:     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:     do {
                    122:         if (bits < 15) {
                    123:             hold += (unsigned long)(PUP(in)) << bits;
                    124:             bits += 8;
                    125:             hold += (unsigned long)(PUP(in)) << bits;
                    126:             bits += 8;
                    127:         }
                    128:         this = lcode[hold & lmask];
                    129:       dolen:
                    130:         op = (unsigned)(this.bits);
                    131:         hold >>= op;
                    132:         bits -= op;
                    133:         op = (unsigned)(this.op);
                    134:         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:             PUP(out) = (unsigned char)(this.val);
                    139:         }
                    140:         else if (op & 16) {                     /* length base */
                    141:             len = (unsigned)(this.val);
                    142:             op &= 15;                           /* number of extra bits */
                    143:             if (op) {
                    144:                 if (bits < op) {
                    145:                     hold += (unsigned long)(PUP(in)) << bits;
                    146:                     bits += 8;
                    147:                 }
                    148:                 len += (unsigned)hold & ((1U << op) - 1);
                    149:                 hold >>= op;
                    150:                 bits -= op;
                    151:             }
                    152:             Tracevv((stderr, "inflate:         length %u\n", len));
                    153:             if (bits < 15) {
                    154:                 hold += (unsigned long)(PUP(in)) << bits;
                    155:                 bits += 8;
                    156:                 hold += (unsigned long)(PUP(in)) << bits;
                    157:                 bits += 8;
                    158:             }
                    159:             this = dcode[hold & dmask];
                    160:           dodist:
                    161:             op = (unsigned)(this.bits);
                    162:             hold >>= op;
                    163:             bits -= op;
                    164:             op = (unsigned)(this.op);
                    165:             if (op & 16) {                      /* distance base */
                    166:                 dist = (unsigned)(this.val);
                    167:                 op &= 15;                       /* number of extra bits */
                    168:                 if (bits < op) {
                    169:                     hold += (unsigned long)(PUP(in)) << bits;
                    170:                     bits += 8;
                    171:                     if (bits < op) {
                    172:                         hold += (unsigned long)(PUP(in)) << bits;
                    173:                         bits += 8;
                    174:                     }
                    175:                 }
                    176:                 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:                 hold >>= op;
                    185:                 bits -= op;
                    186:                 Tracevv((stderr, "inflate:         distance %u\n", dist));
                    187:                 op = (unsigned)(out - beg);     /* max distance in output */
                    188:                 if (dist > op) {                /* see if copy from window */
                    189:                     op = dist - op;             /* distance back in window */
                    190:                     if (op > whave) {
                    191: #ifdef SMALL
                    192:                        strm->msg = "error";
                    193: #else
                    194:                         strm->msg = (char *)"invalid distance too far back";
                    195: #endif
                    196:                         state->mode = BAD;
                    197:                         break;
                    198:                     }
                    199:                     from = window - OFF;
                    200:                     if (write == 0) {           /* very common case */
                    201:                         from += wsize - op;
                    202:                         if (op < len) {         /* some from window */
                    203:                             len -= op;
                    204:                             do {
                    205:                                 PUP(out) = PUP(from);
                    206:                             } while (--op);
                    207:                             from = out - dist;  /* rest from output */
                    208:                         }
                    209:                     }
                    210:                     else if (write < op) {      /* wrap around window */
                    211:                         from += wsize + write - op;
                    212:                         op -= write;
                    213:                         if (op < len) {         /* some from end of window */
                    214:                             len -= op;
                    215:                             do {
                    216:                                 PUP(out) = PUP(from);
                    217:                             } while (--op);
                    218:                             from = window - OFF;
                    219:                             if (write < len) {  /* some from start of window */
                    220:                                 op = write;
                    221:                                 len -= op;
                    222:                                 do {
                    223:                                     PUP(out) = PUP(from);
                    224:                                 } while (--op);
                    225:                                 from = out - dist;      /* rest from output */
                    226:                             }
                    227:                         }
                    228:                     }
                    229:                     else {                      /* contiguous in window */
                    230:                         from += write - op;
                    231:                         if (op < len) {         /* some from window */
                    232:                             len -= op;
                    233:                             do {
                    234:                                 PUP(out) = PUP(from);
                    235:                             } while (--op);
                    236:                             from = out - dist;  /* rest from output */
                    237:                         }
                    238:                     }
                    239:                     while (len > 2) {
                    240:                         PUP(out) = PUP(from);
                    241:                         PUP(out) = PUP(from);
                    242:                         PUP(out) = PUP(from);
                    243:                         len -= 3;
                    244:                     }
                    245:                     if (len) {
                    246:                         PUP(out) = PUP(from);
                    247:                         if (len > 1)
                    248:                             PUP(out) = PUP(from);
                    249:                     }
                    250:                 }
                    251:                 else {
                    252:                     from = out - dist;          /* copy direct from output */
                    253:                     do {                        /* minimum length is three */
                    254:                         PUP(out) = PUP(from);
                    255:                         PUP(out) = PUP(from);
                    256:                         PUP(out) = PUP(from);
                    257:                         len -= 3;
                    258:                     } while (len > 2);
                    259:                     if (len) {
                    260:                         PUP(out) = PUP(from);
                    261:                         if (len > 1)
                    262:                             PUP(out) = PUP(from);
                    263:                     }
                    264:                 }
                    265:             }
                    266:             else if ((op & 64) == 0) {          /* 2nd level distance code */
                    267:                 this = dcode[this.val + (hold & ((1U << op) - 1))];
                    268:                 goto dodist;
                    269:             }
                    270:             else {
                    271: #ifdef SMALL
                    272:                strm->msg = "error";
                    273: #else
                    274:                 strm->msg = (char *)"invalid distance code";
                    275: #endif
                    276:                 state->mode = BAD;
                    277:                 break;
                    278:             }
                    279:         }
                    280:         else if ((op & 64) == 0) {              /* 2nd level length code */
                    281:             this = lcode[this.val + (hold & ((1U << op) - 1))];
                    282:             goto dolen;
                    283:         }
                    284:         else if (op & 32) {                     /* end-of-block */
                    285:             Tracevv((stderr, "inflate:         end of block\n"));
                    286:             state->mode = TYPE;
                    287:             break;
                    288:         }
                    289:         else {
                    290: #ifdef SMALL
                    291:            strm->msg = "error";
                    292: #else
                    293:             strm->msg = (char *)"invalid literal/length code";
                    294: #endif
                    295:             state->mode = BAD;
                    296:             break;
                    297:         }
                    298:     } while (in < last && out < end);
                    299:
                    300:     /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
                    301:     len = bits >> 3;
                    302:     in -= len;
                    303:     bits -= len << 3;
                    304:     hold &= (1U << bits) - 1;
                    305:
                    306:     /* update state and return */
                    307:     strm->next_in = in + OFF;
                    308:     strm->next_out = out + OFF;
                    309:     strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
                    310:     strm->avail_out = (unsigned)(out < end ?
                    311:                                  257 + (end - out) : 257 - (out - end));
                    312:     state->hold = hold;
                    313:     state->bits = bits;
                    314:     return;
                    315: }
                    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 */

CVSweb