protected virtual void FlushBrotliStream(Boolean finished) { //test if the resource has been freed if (_state == IntPtr.Zero) { return; } if (Brolib.BrotliEncoderIsFinished(_state)) { return; } BrotliEncoderOperation op = finished ? BrotliEncoderOperation.Finish : BrotliEncoderOperation.Flush; UInt32 totalOut = 0; while (true) { var compressOK = Brolib.BrotliEncoderCompressStream(_state, op, ref _availableIn, ref _ptrNextInput, ref _availableOut, ref _ptrNextOutput, out totalOut); if (!compressOK) { throw new BrotliException("Unable to finish encode stream"); } var extraData = _availableOut != BufferSize; if (extraData) { var bytesWrote = (int)(BufferSize - _availableOut); Marshal.Copy(_ptrOutputBuffer, _managedBuffer, 0, bytesWrote); _stream.Write(_managedBuffer, 0, bytesWrote); _availableOut = BufferSize; _ptrNextOutput = _ptrOutputBuffer; } if (Brolib.BrotliEncoderIsFinished(_state)) { break; } if (!extraData) { break; } } }
public BrotliStream(Stream baseStream, CompressionMode mode, bool leaveOpen) { if (baseStream == null) { throw new ArgumentNullException("baseStream"); } _mode = mode; _stream = baseStream; _leaveOpen = leaveOpen; if (_mode == CompressionMode.Compress) { _state = Brolib.BrotliEncoderCreateInstance(); if (_state == IntPtr.Zero) { throw new BrotliException("Unable to create brotli encoder instance"); } Brolib.BrotliEncoderSetParameter(_state, BrotliEncoderParameter.Quality, 5); Brolib.BrotliEncoderSetParameter(_state, BrotliEncoderParameter.LGWin, 22); } else { _state = Brolib.BrotliDecoderCreateInstance(); if (_state == IntPtr.Zero) { throw new BrotliException("Unable to create brotli decoder instance"); } //follow the brotli default standard var succ = Brolib.BrotliDecoderSetParameter(_state, BrotliDecoderParameter.LargeWindow, 1U); if (!succ) { throw new BrotliException("failed to set decoder parameter to large window"); } } _ptrInputBuffer = Marshal.AllocHGlobal(BufferSize); _ptrOutputBuffer = Marshal.AllocHGlobal(BufferSize); _ptrNextInput = _ptrInputBuffer; _ptrNextOutput = _ptrOutputBuffer; _managedBuffer = new Byte[BufferSize]; }
public void Dispose() { if (mPtrInputBuffer != IntPtr.Zero) { Marshal.FreeHGlobal(mPtrInputBuffer); mPtrInputBuffer = IntPtr.Zero; } if (mPtrOutputBuffer != IntPtr.Zero) { Marshal.FreeHGlobal(mPtrOutputBuffer); mPtrOutputBuffer = IntPtr.Zero; } if (mCompressionMode == CompressionMode.Compress) { Brolib.BrotliEncoderDestroyInstance(mPtrState); return; } Brolib.BrotliDecoderDestroyInstance(mPtrState); }
protected override void Dispose(bool disposing) { if (_mode == CompressionMode.Compress) { FlushBrotliStream(true); } base.Dispose(disposing); if (!_leaveOpen) { _stream.Dispose(); } _intermediateStream.Dispose(); if (_ptrInputBuffer != IntPtr.Zero) { Marshal.FreeHGlobal(_ptrInputBuffer); } if (_ptrOutputBuffer != IntPtr.Zero) { Marshal.FreeHGlobal(_ptrOutputBuffer); } _managedBuffer = null; _ptrInputBuffer = IntPtr.Zero; _ptrOutputBuffer = IntPtr.Zero; if (_state != IntPtr.Zero) { if (_mode == CompressionMode.Compress) { Brolib.BrotliEncoderDestroyInstance(_state); } else { Brolib.BrotliDecoderDestroyInstance(_state); } _state = IntPtr.Zero; } }
public override int Read(byte[] buffer, int offset, int count) { if (_mode != CompressionMode.Decompress) { throw new BrotliException("Can't read on this stream"); } int bytesRead = (int)(_intermediateStream.Length - _readOffset); uint totalCount = 0; Boolean endOfStream = false; Boolean errorDetected = false; while (bytesRead < count) { while (true) { if (_lastDecodeResult == BrotliDecoderResult.NeedsMoreInput) { _availableIn = (UInt32)_stream.Read(_managedBuffer, 0, (int)BufferSize); _ptrNextInput = _ptrInputBuffer; if (_availableIn <= 0) { endOfStream = true; break; } Marshal.Copy(_managedBuffer, 0, _ptrInputBuffer, (int)_availableIn); } else if (_lastDecodeResult == BrotliDecoderResult.NeedsMoreOutput) { Marshal.Copy(_ptrOutputBuffer, _managedBuffer, 0, BufferSize); _intermediateStream.Write(_managedBuffer, 0, BufferSize); bytesRead += BufferSize; _availableOut = BufferSize; _ptrNextOutput = _ptrOutputBuffer; } else { //Error or OK endOfStream = true; break; } _lastDecodeResult = Brolib.BrotliDecoderDecompressStream(_state, ref _availableIn, ref _ptrNextInput, ref _availableOut, ref _ptrNextOutput, out totalCount); if (bytesRead >= count) { break; } } if (endOfStream && !Brolib.BrotliDecoderIsFinished(_state)) { errorDetected = true; } if (_lastDecodeResult == BrotliDecoderResult.Error || errorDetected) { var error = Brolib.BrotliDecoderGetErrorCode(_state); var text = Brolib.BrotliDecoderErrorString(error); throw new BrotliDecodeException(String.Format("Unable to decode stream,possibly corrupt data.Code={0}({1})", error, text), error, text); } if (endOfStream && !Brolib.BrotliDecoderIsFinished(_state) && _lastDecodeResult == BrotliDecoderResult.NeedsMoreInput) { throw new BrotliException("Unable to decode stream,unexpected EOF"); } if (endOfStream && _ptrNextOutput != _ptrOutputBuffer) { int remainBytes = (int)(_ptrNextOutput.ToInt64() - _ptrOutputBuffer.ToInt64()); bytesRead += remainBytes; Marshal.Copy(_ptrOutputBuffer, _managedBuffer, 0, remainBytes); _intermediateStream.Write(_managedBuffer, 0, remainBytes); _ptrNextOutput = _ptrOutputBuffer; } if (endOfStream) { break; } } if (_intermediateStream.Length - _readOffset >= count || endOfStream) { _intermediateStream.Seek(_readOffset, SeekOrigin.Begin); var bytesToRead = (int)(_intermediateStream.Length - _readOffset); if (bytesToRead > count) { bytesToRead = count; } _intermediateStream.Read(buffer, offset, bytesToRead); TruncateBeginning(_intermediateStream, _readOffset + bytesToRead); _readOffset = 0; return(bytesToRead); } return(0); }
public int Compress(byte[] source, int offset, int count, byte[] destination) { if (mCompressionMode != CompressionMode.Compress) { throw new BrotliException( "The BrotliStream instance can not compress the buffer."); } int destinationLength = 0; int remainingBytes = count; int currentOffset = offset; #region Process while (remainingBytes > 0) { int bytesToCopy = remainingBytes > BUFFER_SIZE ? BUFFER_SIZE : remainingBytes; Marshal.Copy(source, currentOffset, mPtrInputBuffer, bytesToCopy); remainingBytes -= bytesToCopy; currentOffset += bytesToCopy; mAvailableIn = (UInt32)bytesToCopy; mPtrNextInput = mPtrInputBuffer; while (mAvailableIn > 0) { uint totalOut = 0; bool processedOk = Brolib.BrotliEncoderCompressStream( mPtrState, BrotliEncoderOperation.Process, ref mAvailableIn, ref mPtrNextInput, ref mAvailableOut, ref mPtrNextOutput, out totalOut); if (!processedOk) { throw new BrotliException("Could not compress the buffer."); } if (mAvailableOut == BUFFER_SIZE) { continue; } int bytesProcessed = (int)(BUFFER_SIZE - mAvailableOut); Marshal.Copy( mPtrOutputBuffer, destination, destinationLength, bytesProcessed); destinationLength += bytesProcessed; mAvailableOut = BUFFER_SIZE; mPtrNextOutput = mPtrOutputBuffer; } if (Brolib.BrotliEncoderIsFinished(mPtrState)) { break; } } #endregion #region Finish while (true) { UInt32 totalOut = 0; bool compressedOk = Brolib.BrotliEncoderCompressStream( mPtrState, BrotliEncoderOperation.Finish, ref mAvailableIn, ref mPtrNextInput, ref mAvailableOut, ref mPtrNextOutput, out totalOut); if (!compressedOk) { throw new BrotliException("Unable to correctly compress the buffer"); } bool extraData = mAvailableOut != BUFFER_SIZE; if (extraData) { int bytesWritten = (int)(BUFFER_SIZE - mAvailableOut); Marshal.Copy(mPtrOutputBuffer, destination, destinationLength, bytesWritten); destinationLength += bytesWritten; mAvailableOut = BUFFER_SIZE; mPtrNextOutput = mPtrOutputBuffer; } if (Brolib.BrotliEncoderIsFinished(mPtrState) || !extraData) { break; } } #endregion return(destinationLength); }
public int Decompress(byte[] source, int offset, int count, byte[] destination) { if (mCompressionMode != CompressionMode.Decompress) { throw new BrotliException( "The BrotliStream instance can not decompress the buffer."); } BrotliDecoderResult lastDecodeResult = BrotliDecoderResult.NeedsMoreInput; int bytesProcessed = 0; bool endOfSource = false; bool errorDetected = false; int destinationLength = 0; while (bytesProcessed < count) { while (true) { if (lastDecodeResult == BrotliDecoderResult.NeedsMoreInput) { mAvailableIn = (count - bytesProcessed) > BUFFER_SIZE ? BUFFER_SIZE : (uint)(count - bytesProcessed); mPtrNextInput = mPtrInputBuffer; if (mAvailableIn <= 0) { endOfSource = true; break; } Marshal.Copy( source, offset + bytesProcessed, mPtrInputBuffer, (int)mAvailableIn); } else if (lastDecodeResult == BrotliDecoderResult.NeedsMoreOutput) { Marshal.Copy( mPtrOutputBuffer, destination, destinationLength, BUFFER_SIZE); destinationLength += BUFFER_SIZE; bytesProcessed += BUFFER_SIZE; mAvailableOut = BUFFER_SIZE; mPtrNextOutput = mPtrOutputBuffer; } else { // Error or OK endOfSource = true; break; } uint totalCount = 0; lastDecodeResult = Brolib.BrotliDecoderDecompressStream( mPtrState, ref mAvailableIn, ref mPtrNextInput, ref mAvailableOut, ref mPtrNextOutput, out totalCount); if (bytesProcessed >= destination.Length) { break; } } if (endOfSource && !Brolib.BrotliDecoderIsFinished(mPtrState)) { errorDetected = true; } if (lastDecodeResult == BrotliDecoderResult.Error || errorDetected) { int errorCode = Brolib.BrotliDecoderGetErrorCode(mPtrState); string errorMessage = Brolib.BrotliDecoderErrorString(errorCode); throw new BrotliException(string.Format( "Unable to decompress the buffer. Error {0} - {1}", errorCode, errorMessage)); } if (endOfSource && Brolib.BrotliDecoderIsFinished(mPtrState) && lastDecodeResult == BrotliDecoderResult.NeedsMoreInput) { throw new Exception("Unable to decompress the buffer. Unexpected EOF."); } if (endOfSource && mPtrNextOutput != mPtrOutputBuffer) { int remainingBytes = (int)(mPtrNextOutput.ToInt64() - mPtrOutputBuffer.ToInt64()); bytesProcessed += remainingBytes; if (destinationLength + remainingBytes > destination.Length) { throw new BrotliException( "The destination buffer is smaller than the decompressed source buffer"); } Marshal.Copy(mPtrOutputBuffer, destination, destinationLength, remainingBytes); destinationLength += remainingBytes; mPtrNextOutput = mPtrOutputBuffer; } if (endOfSource) { break; } } return(destinationLength); }