zlib from C++ to C#(How to convert byte[] to stream and stream to byte[])

6

My task is to decompress a packet(received) using zlib and then use an algoritm to make a picture from the data

The good news is that I have the code in C++,but the task is to do it in C#

C++

        //Read the first values of the packet received

        DWORD image[200 * 64] = {0}; //used for algoritm(width always = 200 and height always == 64)
        int imgIndex = 0; //used for algoritm
        unsigned char rawbytes_[131072] = {0}; //read below
        unsigned char * rawbytes = rawbytes_; //destrination parameter for decompression(ptr)
        compressed = r.Read<WORD>(); //the length of the compressed bytes(picture)
        uncompressed = r.Read<WORD>(); //the length that should be after decompression
        width = r.Read<WORD>(); //the width of the picture
        height = r.Read<WORD>(); //the height of the picture

        LPBYTE ptr = r.GetCurrentStream(); //the bytes(file that must be decompressed)

        outLen = uncompressed; //copy the len into another variable

        //Decompress

        if(uncompress((Bytef*)rawbytes, &outLen, ptr, compressed) != Z_OK)
        {
            printf("Could not uncompress the image code.\n");
            Disconnect();
            return;
        }

        //Algoritm to make up the picture
        // Loop through the data
        for(int c = 0; c < (int)height; ++c)
        {
            for(int r = 0; r < (int)width; ++r)
            {
                imgIndex = (height - 1 - c) * width + r;
                image[imgIndex] = 0xFF000000;
                if(-((1 << (0xFF & (r & 0x80000007))) & rawbytes[((c * width + r) >> 3)])) 
                    image[imgIndex] = 0xFFFFFFFF;
            }
        }

I'm trying to do this with zlib.NET ,but all demos have that code to decompress(C#)

    private void decompressFile(string inFile, string outFile)
    {
        System.IO.FileStream outFileStream = new System.IO.FileStream(outFile, System.IO.FileMode.Create);
        zlib.ZOutputStream outZStream = new zlib.ZOutputStream(outFileStream);
        System.IO.FileStream inFileStream = new System.IO.FileStream(inFile, System.IO.FileMode.Open);          
        try
        {
            CopyStream(inFileStream, outZStream);
        }
        finally
        {
            outZStream.Close();
            outFileStream.Close();
            inFileStream.Close();
        }
    }

    public static void CopyStream(System.IO.Stream input, System.IO.Stream output)
    {
        byte[] buffer = new byte[2000];
        int len;
        while ((len = input.Read(buffer, 0, 2000)) > 0)
        {
            output.Write(buffer, 0, len);
        }
        output.Flush();
    }

My problem:I don't want to save the file after decompression,because I have to use the algoritm shown in the C++ code.

How to convert the byte[] array into a stream similiar to the one in the C# zlib code to decompress the data and then how to convert the stream back into byte array?

Also,How to change the zlib.NET code to NOT save files?

c#
byte
zlib
asked on Stack Overflow Apr 10, 2009 by Ivan Prodanov

2 Answers

10

Just use MemoryStreams instead of FileStreams:

// Assuming inputData is a byte[]
MemoryStream input = new MemoryStream(inputData);
MemoryStream output = new MemoryStream();

Then you can use output.ToArray() afterwards to get a byte array out.

Note that it's generally better to use using statements instead of a single try/finally block - as otherwise if the first call to Close fails, the rest won't be made. You can nest them like this:

using (MemoryStream output = new MemoryStream())
using (Stream outZStream = new zlib.ZOutputStream(output))
using (Stream input = new MemoryStream(bytes))
{
    CopyStream(inFileStream, outZStream);
    return output.ToArray();
}
answered on Stack Overflow Apr 10, 2009 by Jon Skeet
6

I just ran into this same issue.

For Completeness... (since this stumped me for several hours)

In the case of ZLib.Net you also have to call finish(), which usually happens during Close(), before you call return output.ToArray()

Otherwise you will get an empty/incomplete byte array from your memory stream, because the ZStream hasn't actually written all of the data yet:

public static void CompressData(byte[] inData, out byte[] outData)
{
    using (MemoryStream outMemoryStream = new MemoryStream())
    using (ZOutputStream outZStream = new ZOutputStream(outMemoryStream, zlibConst.Z_DEFAULT_COMPRESSION))
    using (Stream inMemoryStream = new MemoryStream(inData))
    {
        CopyStream(inMemoryStream, outZStream);
        outZStream.finish();
        outData = outMemoryStream.ToArray();
    }
}

public static void DecompressData(byte[] inData, out byte[] outData)
{
    using (MemoryStream outMemoryStream = new MemoryStream())
    using (ZOutputStream outZStream = new ZOutputStream(outMemoryStream))
    using (Stream inMemoryStream = new MemoryStream(inData))
    {
        CopyStream(inMemoryStream, outZStream);
        outZStream.finish();
        outData = outMemoryStream.ToArray();
    }
}

In this example I'm also using the zlib namespace:

using zlib;

Originally found in this thread: ZLib decompression

I don't have enough points to vote up yet, so...

Thanks to Tim Greaves for the tip regarding finish before ToArray

And Jon Skeet for the tip regarding nesting the using statements for streams (which I like much better than try/finally)

answered on Stack Overflow Oct 2, 2010 by Josh Stribling • edited May 23, 2017 by Community

User contributions licensed under CC BY-SA 3.0