// Decode PKWare Compression Library stream. public static byte[] Decompress(byte[] src) { var br = new BitReader(src); // Are literals coded? var coded = br.ReadBits(8); if (coded < 0 || coded > 1) { throw new NotImplementedException("Invalid data stream"); } var encodedLiterals = coded == 1; // log2(dictionary size) - 6 var dict = br.ReadBits(8); if (dict < 4 || dict > 6) { throw new InvalidDataException("Invalid dictionary size"); } // output state ushort next = 0; // index of next write location in out[] var first = true; // true to check distances (for first 4K) var outBuffer = new byte[MAXWIN]; // output buffer and sliding window var ms = new MemoryStream(); // decode literals and length/distance pairs do { // length/distance pair if (br.ReadBits(1) == 1) { // Length var symbol = Decode(lencode, br); var len = lengthbase[symbol] + br.ReadBits(extra[symbol]); // Magic number for "done" if (len == 519) { for (var i = 0; i < next; i++) { ms.WriteByte(outBuffer[i]); } break; } // Distance symbol = len == 2 ? 2 : dict; var dist = Decode(distcode, br) << symbol; dist += br.ReadBits(symbol); dist++; if (first && dist > next) { throw new InvalidDataException("Attempt to jump before data"); } // copy length bytes from distance bytes back do { var dest = next; var source = dest - dist; var copy = MAXWIN; if (next < dist) { source += copy; copy = dist; } copy -= next; if (copy > len) { copy = len; } len -= copy; next += (ushort)copy; // copy with old-fashioned memcpy semantics // in case of overlapping ranges. this is NOT // the same as Array.Copy() while (copy-- > 0) { outBuffer[dest++] = outBuffer[source++]; } // Flush window to outstream if (next == MAXWIN) { for (var i = 0; i < next; i++) { ms.WriteByte(outBuffer[i]); } next = 0; first = false; } } while (len != 0); } else { // literal value var symbol = encodedLiterals ? Decode(litcode, br) : br.ReadBits(8); outBuffer[next++] = (byte)symbol; if (next == MAXWIN) { for (var i = 0; i < next; i++) { ms.WriteByte(outBuffer[i]); } next = 0; first = false; } } } while (true); return(ms.ToArray()); }