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