-
Couldn't load subscription status.
- Fork 5.2k
Description
Background and motivation
I am working with data that has packed objects that contain header bytes and then a ZLib blob. The DeflateStream class has an internal buffer that advances the BaseStream to fetch data. The problem is that the underlying Stream is then advanced past where the ZLib blob ends. Currently, I have to use reflection to reach down into the object model to get the number of bytes that were not consumed in the buffer so I can re-wind the BaseStream to where the ZLib data ended.
Like so:
//Get the Available Bytes in the internal buffer
//Reflection Path = deflateStream -> _inflater / inflater -> _zlibStream -> AvailIn
var flags = BindingFlags.NonPublic | BindingFlags.Instance;
var inflater = deflateStream
.GetType()
.GetFields(flags)
.ToList()
.Find(x => x.Name == "inflater" || x.Name == "_inflater");
var inflaterInstance = inflater.GetValue(deflateStream);
var zlibStream = inflaterInstance.GetType().GetField("_zlibStream", flags);
var zlibStreamInstance = zlibStream.GetValue(inflaterInstance);
var availIn = zlibStreamInstance.GetType().GetProperty("AvailIn");
var availInValue = availIn.GetValue(zlibStreamInstance);
//Rewind the BaseStream
deflateStream.BaseStream.Seek(-1 * (uint)availInValue, SeekOrigin.Current);NEW proposal
Make compression streams to rewind the underlying stream when they reach end of the compressed data. That way, the underlying stream can be used for further reads (assuming it supports seeking).
ORIGINAL - API Proposal
Can you add
public int AvailableInput => (int)_zlibStream.AvailIn;below this:
runtime/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Inflater.cs
Line 43 in a3fb0d3
| public int AvailableOutput => (int)_zlibStream.AvailOut; |
And then add
internal int RemainingBufferBytes
{
get
{
if (_inflater != null)
return _inflater.AvailableInput;
else
return -1;
}
}here:
runtime/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateZLib/DeflateStream.cs
Line 120 in a3fb0d3
And then add
public int RemainingBufferBytes { get { throw null; } }below:
Finally add:
/// <summary>Returns the number of unused Input Buffer bytes. This can be used to rewind the BaseStream when reading from mixed-use data.</summary>
public int RemainingBufferBytes
{
get
{
if (_deflateStream != null)
return _deflateStream.RemainingBufferBytes;
else
return -1;
}
}here:
runtime/src/libraries/System.IO.Compression/src/System/IO/Compression/ZLibStream.cs
Line 66 in d2c991e
I have added these to a local copy and built the whole thing. It works as expected.
API Usage
//Read the compressed data
ZLibStream inflater = new ZLibStream(mixedUseStream, CompressionMode.Decompress, true);
MemoryStream expandedContents = new MemoryStream();
inflater.CopyTo(expandedContents);
//Rewind the stream by the unused buffer bytes.
mixedUseStream.Seek(-1 * inflater.RemainingBufferBytes, SeekOrigin.Current);
//Close the stream
inflater.Close();Alternative Designs
No response
Risks
There are no risks as this is simply exposing data to read that is already present.