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 }