brintos

brintos / linux-shallow public Read only

0
0
Text · 12.1 KiB · 2843f9b Raw
342 lines · c
1/* inffast.c -- fast decoding2 * Copyright (C) 1995-2004 Mark Adler3 * For conditions of distribution and use, see copyright notice in zlib.h4 */5 6#include <linux/zutil.h>7#include "inftrees.h"8#include "inflate.h"9#include "inffast.h"10 11#ifndef ASMINF12 13union uu {14	unsigned short us;15	unsigned char b[2];16};17 18/* Endian independent version */19static inline unsigned short20get_unaligned16(const unsigned short *p)21{22	union uu  mm;23	unsigned char *b = (unsigned char *)p;24 25	mm.b[0] = b[0];26	mm.b[1] = b[1];27	return mm.us;28}29 30/*31   Decode literal, length, and distance codes and write out the resulting32   literal and match bytes until either not enough input or output is33   available, an end-of-block is encountered, or a data error is encountered.34   When large enough input and output buffers are supplied to inflate(), for35   example, a 16K input buffer and a 64K output buffer, more than 95% of the36   inflate execution time is spent in this routine.37 38   Entry assumptions:39 40        state->mode == LEN41        strm->avail_in >= 642        strm->avail_out >= 25843        start >= strm->avail_out44        state->bits < 845 46   On return, state->mode is one of:47 48        LEN -- ran out of enough output space or enough available input49        TYPE -- reached end of block code, inflate() to interpret next block50        BAD -- error in block data51 52   Notes:53 54    - The maximum input bits used by a length/distance pair is 15 bits for the55      length code, 5 bits for the length extra, 15 bits for the distance code,56      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.57      Therefore if strm->avail_in >= 6, then there is enough input to avoid58      checking for available input while decoding.59 60    - The maximum bytes that a single length/distance pair can output is 25861      bytes, which is the maximum length that can be coded.  inflate_fast()62      requires strm->avail_out >= 258 for each loop to avoid checking for63      output space.64 65    - @start:	inflate()'s starting value for strm->avail_out66 */67void inflate_fast(z_streamp strm, unsigned start)68{69    struct inflate_state *state;70    const unsigned char *in;    /* local strm->next_in */71    const unsigned char *last;  /* while in < last, enough input available */72    unsigned char *out;         /* local strm->next_out */73    unsigned char *beg;         /* inflate()'s initial strm->next_out */74    unsigned char *end;         /* while out < end, enough space available */75#ifdef INFLATE_STRICT76    unsigned dmax;              /* maximum distance from zlib header */77#endif78    unsigned wsize;             /* window size or zero if not using window */79    unsigned whave;             /* valid bytes in the window */80    unsigned write;             /* window write index */81    unsigned char *window;      /* allocated sliding window, if wsize != 0 */82    unsigned long hold;         /* local strm->hold */83    unsigned bits;              /* local strm->bits */84    code const *lcode;          /* local strm->lencode */85    code const *dcode;          /* local strm->distcode */86    unsigned lmask;             /* mask for first level of length codes */87    unsigned dmask;             /* mask for first level of distance codes */88    code this;                  /* retrieved table entry */89    unsigned op;                /* code bits, operation, extra bits, or */90                                /*  window position, window bytes to copy */91    unsigned len;               /* match length, unused bytes */92    unsigned dist;              /* match distance */93    unsigned char *from;        /* where to copy match from */94 95    /* copy state to local variables */96    state = (struct inflate_state *)strm->state;97    in = strm->next_in;98    last = in + (strm->avail_in - 5);99    out = strm->next_out;100    beg = out - (start - strm->avail_out);101    end = out + (strm->avail_out - 257);102#ifdef INFLATE_STRICT103    dmax = state->dmax;104#endif105    wsize = state->wsize;106    whave = state->whave;107    write = state->write;108    window = state->window;109    hold = state->hold;110    bits = state->bits;111    lcode = state->lencode;112    dcode = state->distcode;113    lmask = (1U << state->lenbits) - 1;114    dmask = (1U << state->distbits) - 1;115 116    /* decode literals and length/distances until end-of-block or not enough117       input data or output space */118    do {119        if (bits < 15) {120            hold += (unsigned long)(*in++) << bits;121            bits += 8;122            hold += (unsigned long)(*in++) << bits;123            bits += 8;124        }125        this = lcode[hold & lmask];126      dolen:127        op = (unsigned)(this.bits);128        hold >>= op;129        bits -= op;130        op = (unsigned)(this.op);131        if (op == 0) {                          /* literal */132            *out++ = (unsigned char)(this.val);133        }134        else if (op & 16) {                     /* length base */135            len = (unsigned)(this.val);136            op &= 15;                           /* number of extra bits */137            if (op) {138                if (bits < op) {139                    hold += (unsigned long)(*in++) << bits;140                    bits += 8;141                }142                len += (unsigned)hold & ((1U << op) - 1);143                hold >>= op;144                bits -= op;145            }146            if (bits < 15) {147                hold += (unsigned long)(*in++) << bits;148                bits += 8;149                hold += (unsigned long)(*in++) << bits;150                bits += 8;151            }152            this = dcode[hold & dmask];153          dodist:154            op = (unsigned)(this.bits);155            hold >>= op;156            bits -= op;157            op = (unsigned)(this.op);158            if (op & 16) {                      /* distance base */159                dist = (unsigned)(this.val);160                op &= 15;                       /* number of extra bits */161                if (bits < op) {162                    hold += (unsigned long)(*in++) << bits;163                    bits += 8;164                    if (bits < op) {165                        hold += (unsigned long)(*in++) << bits;166                        bits += 8;167                    }168                }169                dist += (unsigned)hold & ((1U << op) - 1);170#ifdef INFLATE_STRICT171                if (dist > dmax) {172                    strm->msg = (char *)"invalid distance too far back";173                    state->mode = BAD;174                    break;175                }176#endif177                hold >>= op;178                bits -= op;179                op = (unsigned)(out - beg);     /* max distance in output */180                if (dist > op) {                /* see if copy from window */181                    op = dist - op;             /* distance back in window */182                    if (op > whave) {183                        strm->msg = (char *)"invalid distance too far back";184                        state->mode = BAD;185                        break;186                    }187                    from = window;188                    if (write == 0) {           /* very common case */189                        from += wsize - op;190                        if (op < len) {         /* some from window */191                            len -= op;192                            do {193                                *out++ = *from++;194                            } while (--op);195                            from = out - dist;  /* rest from output */196                        }197                    }198                    else if (write < op) {      /* wrap around window */199                        from += wsize + write - op;200                        op -= write;201                        if (op < len) {         /* some from end of window */202                            len -= op;203                            do {204                                *out++ = *from++;205                            } while (--op);206                            from = window;207                            if (write < len) {  /* some from start of window */208                                op = write;209                                len -= op;210                                do {211                                    *out++ = *from++;212                                } while (--op);213                                from = out - dist;      /* rest from output */214                            }215                        }216                    }217                    else {                      /* contiguous in window */218                        from += write - op;219                        if (op < len) {         /* some from window */220                            len -= op;221                            do {222                                *out++ = *from++;223                            } while (--op);224                            from = out - dist;  /* rest from output */225                        }226                    }227                    while (len > 2) {228                        *out++ = *from++;229                        *out++ = *from++;230                        *out++ = *from++;231                        len -= 3;232                    }233                    if (len) {234                        *out++ = *from++;235                        if (len > 1)236                            *out++ = *from++;237                    }238                }239                else {240		    unsigned short *sout;241		    unsigned long loops;242 243                    from = out - dist;          /* copy direct from output */244		    /* minimum length is three */245		    /* Align out addr */246		    if (!((long)(out - 1) & 1)) {247			*out++ = *from++;248			len--;249		    }250		    sout = (unsigned short *)(out);251		    if (dist > 2) {252			unsigned short *sfrom;253 254			sfrom = (unsigned short *)(from);255			loops = len >> 1;256			do {257			    if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))258				*sout++ = *sfrom++;259			    else260				*sout++ = get_unaligned16(sfrom++);261			} while (--loops);262			out = (unsigned char *)sout;263			from = (unsigned char *)sfrom;264		    } else { /* dist == 1 or dist == 2 */265			unsigned short pat16;266 267			pat16 = *(sout-1);268			if (dist == 1) {269				union uu mm;270				/* copy one char pattern to both bytes */271				mm.us = pat16;272				mm.b[0] = mm.b[1];273				pat16 = mm.us;274			}275			loops = len >> 1;276			do277			    *sout++ = pat16;278			while (--loops);279			out = (unsigned char *)sout;280		    }281		    if (len & 1)282			*out++ = *from++;283                }284            }285            else if ((op & 64) == 0) {          /* 2nd level distance code */286                this = dcode[this.val + (hold & ((1U << op) - 1))];287                goto dodist;288            }289            else {290                strm->msg = (char *)"invalid distance code";291                state->mode = BAD;292                break;293            }294        }295        else if ((op & 64) == 0) {              /* 2nd level length code */296            this = lcode[this.val + (hold & ((1U << op) - 1))];297            goto dolen;298        }299        else if (op & 32) {                     /* end-of-block */300            state->mode = TYPE;301            break;302        }303        else {304            strm->msg = (char *)"invalid literal/length code";305            state->mode = BAD;306            break;307        }308    } while (in < last && out < end);309 310    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */311    len = bits >> 3;312    in -= len;313    bits -= len << 3;314    hold &= (1U << bits) - 1;315 316    /* update state and return */317    strm->next_in = in;318    strm->next_out = out;319    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));320    strm->avail_out = (unsigned)(out < end ?321                                 257 + (end - out) : 257 - (out - end));322    state->hold = hold;323    state->bits = bits;324    return;325}326 327/*328   inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):329   - Using bit fields for code structure330   - Different op definition to avoid & for extra bits (do & for table bits)331   - Three separate decoding do-loops for direct, window, and write == 0332   - Special case for distance > 1 copies to do overlapped load and store copy333   - Explicit branch predictions (based on measured branch probabilities)334   - Deferring match copy and interspersed it with decoding subsequent codes335   - Swapping literal/length else336   - Swapping window/direct else337   - Larger unrolled copy loops (three is about right)338   - Moving len -= 3 statement into middle of loop339 */340 341#endif /* !ASMINF */342