예제 #1
0
        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;
                }
            }
        }
예제 #2
0
        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];
        }
예제 #3
0
        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);
        }
예제 #4
0
 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;
     }
 }
예제 #5
0
        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);
        }
예제 #6
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);
        }
예제 #7
0
        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);
        }