Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c#

zlib

byte

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?

like image 901
Ivan Prodanov Avatar asked Apr 10 '09 10:04

Ivan Prodanov


People also ask

What is zlib C library?

The zlib open source free data compression C library enables computer programmers to create Archive for working with compression file formats inside their own applications. It is a lossless data-compression library for use on virtually any computer hardware and operating system.

How to compress a string of data in zlib?

The zlib library provides us with the compress function, which can be used to compress a string of data. It requires two arguments for data that need to compressed and a parameter for the level of compression. The open source zlib library provides us with some handy set of functions for file compression.

What is level 0 zlib compression in Linux?

Level 0 actually does no compression at all, and in fact expands the data slightly to produce the zlib format (it is not a byte-for-byte copy of the input). More advanced applications of zlib may use deflateInit2 () here instead. Such an application may want to reduce how much memory will be used, at some price in compression.

What is the zlib engine?

The Zlib engine uses a simple API that mechanizes the compression and decompression of your files. The library uses virtual functions that allow users to customize their user interface to zlib. zlib is also a crucial component of many software platforms, including Linux, macOS, and iOS.


2 Answers

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();
}
like image 102
Jon Skeet Avatar answered Oct 27 '22 19:10

Jon Skeet


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)

like image 26
Josh Stribling Avatar answered Oct 27 '22 21:10

Josh Stribling