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