/// <summary> /// Creates a <see cref="Stream"/> wrapper that decompresses brotli data. /// <para> For byte-by-byte reading (<see cref="ReadByte()"/>) internal buffer of specified size is /// allocated and used.</para> /// <para> Will block the thread until first kilobyte of data of source is available.</para> /// </summary> /// <param name="source">compressed data source</param> /// <param name="byteReadBufferSize">size of internal buffer used in case of byte-by-byte reading</param> /// <param name="customDictionary">custom dictionary data; <see langword="null"/> if not used</param> /// <exception cref="IOException">in case of corrupted data or source stream problems</exception> public BrotliInputStream(Stream source, int byteReadBufferSize, byte[] customDictionary) { if (byteReadBufferSize <= 0) { throw new ArgumentException("Bad buffer size:" + byteReadBufferSize); } else if (source == null) { throw new ArgumentException("source is null"); } _buffer = new byte[byteReadBufferSize]; _remainingBufferBytes = 0; _bufferOffset = 0; try { BrotliState.SetInput(_state, source); } catch (BrotliRuntimeException ex) { throw new IOException("Brotli decoder initialization failed", ex); } if (customDictionary != null && customDictionary.Length != 0) { BrotliDecode.SetCustomDictionary(_state, customDictionary); } }
/// <summary><inheritDoc/></summary> /// <exception cref="IOException"/> public override int Read(byte[] destBuffer, int destOffset, int destLen) { if (destOffset < 0) { throw new ArgumentException("Bad offset: " + destOffset); } else if (destLen < 0) { throw new ArgumentException("Bad length: " + destLen); } else if (destOffset + destLen > destBuffer.Length) { throw new ArgumentException("Buffer overflow: " + (destOffset + destLen) + " > " + destBuffer.Length); } else if (destLen == 0) { return(0); } int copyLen = Math.Max(_remainingBufferBytes - _bufferOffset, 0); if (copyLen != 0) { copyLen = Math.Min(copyLen, destLen); Array.Copy(_buffer, _bufferOffset, destBuffer, destOffset, copyLen); _bufferOffset += copyLen; destOffset += copyLen; destLen -= copyLen; if (destLen == 0) { return(copyLen); } } try { _state.output = destBuffer; _state.outputOffset = destOffset; _state.outputLength = destLen; _state.outputUsed = 0; BrotliDecode.Decompress(_state); if (_state.outputUsed == 0) { return(-1); } return(_state.outputUsed + copyLen); } catch (BrotliRuntimeException ex) { throw new IOException("Brotli stream decoding failed", ex); } }