// Calculate the huffman code for each character based on the code length for each character. // This algorithm is described in standard RFC 1951 private uint[] CalculateHuffmanCode() { uint[] bitLengthCount = new uint[17]; foreach (int codeLength in _codeLengthArray) { bitLengthCount[codeLength]++; } bitLengthCount[0] = 0; // clear count for length 0 uint[] nextCode = new uint[17]; uint tempCode = 0; for (int bits = 1; bits <= 16; bits++) { tempCode = (tempCode + bitLengthCount[bits - 1]) << 1; nextCode[bits] = tempCode; } uint[] code = new uint[MaxLiteralTreeElements]; for (int i = 0; i < _codeLengthArray.Length; i++) { int len = _codeLengthArray[i]; if (len > 0) { code[i] = DecodeHelper.BitReverse(nextCode[len], len); nextCode[len]++; } } return(code); }
public int Inflate(byte[] bytes, int offset, int length) { // copy bytes from output to outputbytes if we have aviable bytes // if buffer is not filled up. keep decoding until no input are available // if decodeBlock returns false. Throw an exception. int count = 0; do { int copied = _output.CopyTo(bytes, offset, length); if (copied > 0) { if (_usingGzip) { _crc32 = DecodeHelper.UpdateCrc32(_crc32, bytes, offset, copied); uint n = _streamSize + (uint) copied; if (n < _streamSize) { // overflow, the gzip stream is probably malicious. throw new InvalidDataException("SR.StreamSizeOverflow"); } _streamSize = n; } offset += copied; count += copied; length -= copied; } if (length == 0) { // filled in the bytes array break; } // Decode will return false when more input is needed } while (!Finished() && Decode()); if (_state == InflaterState.VerifyingGZIPFooter) { // finished reading CRC // In this case finished is true and output window has all the data. // But some data in output window might not be copied out. if (_output.AvailableBytes == 0) { if (_crc32 != _gZipDecoder.Crc32) { throw new InvalidDataException("SR.InvalidCRC"); } if (_streamSize != _gZipDecoder.StreamSize) { throw new InvalidDataException("SR.InvalidStreamSize"); } } } return count; }
// // Copy the compressed byte to outputBuffer // Returns the bytes we have copied. The caller needs to provide the buffer // to avoid extra coping. // public int GetCompressedOutput(byte[] outputBuffer) { Debug.Assert(!NeedsInput(), "call SetInput before trying to compress!"); _output.UpdateBuffer(outputBuffer); if (_usingGzip && !_hasGzipHeader) { // Write the GZIP header only once _output.WriteGzipHeader(3); _hasGzipHeader = true; } if (!_hasBlockHeader) { // Output dynamic block header only once _hasBlockHeader = true; _output.WritePreamble(); } do { // read more input data into the window if there is space available int bytesToCopy = (_inputBuffer.Count < _inputWindow.FreeWindowSpace) ? _inputBuffer.Count : _inputWindow.FreeWindowSpace; if (bytesToCopy > 0) { // copy data into history window _inputWindow.CopyBytes(_inputBuffer.Buffer, _inputBuffer.StartIndex, bytesToCopy); if (_usingGzip) { // update CRC for gzip stream _gzipCrc32 = DecodeHelper.UpdateCrc32(_gzipCrc32, _inputBuffer.Buffer, _inputBuffer.StartIndex, bytesToCopy); uint n = _inputStreamSize + (uint)bytesToCopy; if (n < _inputStreamSize) { // overflow, gzip doesn't support compressing more than Int32.Maxvalue bytes. throw new InvalidDataException("SR.StreamSizeOverflow"); } _inputStreamSize = n; } _inputBuffer.ConsumeBytes(bytesToCopy); } // compress the bytes in input history window while (_inputWindow.BytesAvailable > 0 && _output.SafeToWriteTo()) { // Find next match. A match can be a symbol, // a distance/length pair, a symbol followed by a distance/Length pair _inputWindow.GetNextSymbolOrMatch(_currentMatch); if (_currentMatch.State == MatchState.HasSymbol) { _output.WriteChar(_currentMatch.Symbol); } else if (_currentMatch.State == MatchState.HasMatch) { _output.WriteMatch(_currentMatch.Length, _currentMatch.Position); } else { _output.WriteChar(_currentMatch.Symbol); _output.WriteMatch(_currentMatch.Length, _currentMatch.Position); } } } while (_output.SafeToWriteTo() && !NeedsInput()); // update book keeping needed to write end of block data _needsEob = true; return(_output.BytesWritten); // number of bytes we have written }