Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.Net zlib inflate with .Net 4.5

According to MSDN in .Net 4.5 System.IO.Compression is based on zlib.
I am trying now to change my current interop based reading from a zlib deflated stream from a non .NET server into a BCL based implementation.
My implementation looks like this:

    var enc = new UTF8Encoding();            
        var readBytes = BufferSizeRaw;
        var outputBuffer = new byte[BufferSizeRaw];            
        var networkBuffer = _networkQueue.Take();
        var ms = new MemoryStream(networkBuffer.InputBuffer, 0, networkBuffer.UsedLength);
        using (Stream stream = new DeflateStream(ms, CompressionMode.Decompress))
            while (readBytes==BufferSizeRaw)
            {
                readBytes = stream.Read(outputBuffer, 0, outputBuffer.Length);                
                stringBuffer+= enc.GetString(outputBuffer, 0, readBytes);                
            }

I receive the following exception on the first call of the decompression/read on the DeflateStream :

Block length does not match with its complement

The interop based call uses var result=inflate(ref zStyream, ZLibFlush.NoFlush;
Has anyone tried the same or sees a reason for an error in the code or is there a wrong understanding on my end? I have also tried it with truncating the first two bytes without any luck.
The first few bytes are 20, 202, 177,13.

like image 997
weismat Avatar asked Jun 20 '13 11:06

weismat


2 Answers

The answer above is correct but isn't exactly clear on the "why". The first two bytes of a raw ZLib stream provide details about the type of compression used. Microsoft's DeflateStream class in System.Io.Compression doesn't understand these. The fix is as follows:

using (MemoryStream ms = new MemoryStream(data))
{
    MemoryStream msInner = new MemoryStream();

    // Read past the first two bytes of the zlib header
    ms.Seek(2, SeekOrigin.Begin);

    using (DeflateStream z = new DeflateStream(ms, CompressionMode.Decompress))
    {
        z.CopyTo(msInner);

In this example, data is a Byte[] with the raw Zlib file. After loading it into a MemoryStream, we simply "seek" past the first two bytes.

The post explains what a Zlib header looks like if you are looking at the raw bytes.

What does a zlib header look like?

like image 147
ProVega Avatar answered Oct 06 '22 00:10

ProVega


What are the first several bytes of the data you are trying to compress?

You might have zlib, gzip, or raw deflate data that you're trying to decode.

By the way, I highly recommend that you use DotNetZip's interface to zlib instead of NET 4.5's (or NET any version). NET 4.5 has bugs in that interface that Microsoft has declared that they won't fix (!).

like image 25
Mark Adler Avatar answered Oct 05 '22 22:10

Mark Adler