// Decode a code using huffman table h. static int Decode(Huffman h, BitReader br) { int code = 0; // len bits being decoded int first = 0; // first code of length len int index = 0; // index of first code of length len in symbol table short next = 1; while (true) { code |= br.ReadBits(1) ^ 1; // invert code int count = h.Count[next++]; if (code < first + count) { return(h.Symbol[index + (code - first)]); } index += count; first += count; first <<= 1; code <<= 1; } }
// Decode PKWare Compression Library stream. public static byte[] Decompress(byte[] src) { BitReader br = new BitReader(src); // Are literals coded? int coded = br.ReadBits(8); if (coded < 0 || coded > 1) { throw new NotImplementedException("Invalid datastream"); } bool EncodedLiterals = (coded == 1); // log2(dictionary size) - 6 int 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[] bool first = true; // true to check distances (for first 4K) byte[] 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 int symbol = Decode(lencode, br); int len = lengthbase[symbol] + br.ReadBits(extra[symbol]); if (len == 519) // Magic number for "done" { for (int i = 0; i < next; i++) { ms.WriteByte(outBuffer[i]); } break; } // Distance symbol = len == 2 ? 2 : dict; int 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 { int dest = next; int source = dest - dist; int 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 (int i = 0; i < next; i++) { ms.WriteByte(outBuffer[i]); } next = 0; first = false; } } while (len != 0); } else // literal value { int symbol = EncodedLiterals ? Decode(litcode, br) : br.ReadBits(8); outBuffer[next++] = (byte)symbol; if (next == MAXWIN) { for (int i = 0; i < next; i++) { ms.WriteByte(outBuffer[i]); } next = 0; first = false; } } } while (true); return(ms.ToArray()); }
/// <summary>PKWare Compression Library stream.</summary> /// <param name="input">Compressed input stream.</param> /// <param name="output">Stream to write the decompressed output.</param> /// <param name="onProgress">Progress callback, invoked with (read bytes, written bytes).</param> public static void Decompress(Stream input, Stream output, Action <long, long> onProgress = null) { var br = new BitReader(input); // 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 inputStart = input.Position; var outputStart = output.Position; // 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++) { output.WriteByte(outBuffer[i]); } if (onProgress != null) { onProgress(input.Position - inputStart, output.Position - outputStart); } 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++) { output.WriteByte(outBuffer[i]); } next = 0; first = false; if (onProgress != null) { onProgress(input.Position - inputStart, output.Position - outputStart); } } } 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++) { output.WriteByte(outBuffer[i]); } next = 0; first = false; if (onProgress != null) { onProgress(input.Position - inputStart, output.Position - outputStart); } } } } while (true); }