Guilherme Oliveira
Guilherme Oliveira

Reputation: 2028

Decompress a Stream

I'm trying to decompress a stream, using a GZipStream and BinaryStream, but I'm failing.

Can you help me?

    public static LicenseOwnerRoot GetLicenseFromStream(Stream stream)
    {
        using (BinaryReader br = new BinaryReader(stream))
        {
            string keyCrypto = br.ReadString();
            string xmlCrypto = br.ReadString();
            string key = Cryptography.Decrypt(keyCrypto);
            string xml = Cryptography.Decrypt(key, xmlCrypto);
            byte[] data = Encoding.UTF8.GetBytes(xml.ToCharArray());

            using (MemoryStream ms = new MemoryStream(data))
            {
                using (GZipStream decompress = new GZipStream(ms, CompressionMode.Decompress))
                {
                    xml = Encoding.UTF8.GetString(data);
                    LicenseOwnerRoot root = (LicenseOwnerRoot)Utility.XmlDeserialization(typeof(LicenseOwnerRoot), xml);
                    foreach (LicenseOwnerItem loi in root.Licenses)
                        loi.Root = root;
                    return root;
                }
            }
        }
    }

That xml is compressed and encrypted, so I have to decompress and then decrypt. When I try to read, throws one expections with this message: The magic number in GZip header is not correct. I tried so many times to fix that, but It's sounds workable. The question is: how I should use the 'usings' and if that way is right, or exists another way to do what I'm trying to do? I have to decompress before to use BinaryReader?

Actually, I have to do the inverse of this method:

    public static void GenerateLicenseStream(string key, LicenseOwnerRoot root, Stream stream)
    {
        using (BinaryWriter sw = new BinaryWriter(stream))
        {
            string xml = Utility.XmlSerialization(root);
            using (MemoryStream ms = new MemoryStream())
            {
                using (GZipStream compress = new GZipStream(ms, CompressionMode.Compress))
                {
                    byte[] data = Encoding.UTF8.GetBytes(xml.ToCharArray());
                    compress.Write(data, 0, data.Length);
                    string keyCrypto = Cryptography.Encrypt(key);
                    string xmlCrypto = Cryptography.Encrypt(key, Encoding.UTF8.GetString(ms.ToArray()));
                    sw.Write(keyCrypto);
                    sw.Write(xmlCrypto);
                }
            }
        }
   } 

Upvotes: 4

Views: 3441

Answers (3)

Glenn Ferrie
Glenn Ferrie

Reputation: 10380

I wrote up a quick sample for you, it doesnt do the encryption but it highlights where encryption / decryption should occur. This is the content of a .NET Console app that you can run "as is":

    static void Main(string[] args)
    {
        var content = @"someTextOrXMLContentGoesHereCanBeAnything#$&%&*(@#$^";
        var data = Encoding.UTF8.GetBytes(content.ToCharArray());
        var fs = new StreamWriter(@"c:\users\stackoverflow\desktop\sample.bin");
        using (var bw = new BinaryWriter(fs.BaseStream))
        {
            using (var ms = new MemoryStream())
            {
                using (var compress = new GZipStream(ms, CompressionMode.Compress, true))
                {
                    compress.Write(data, 0, data.Length);
                }
                // encrypt goes here
                var compressedData = ms.ToArray();
                Console.WriteLine(compressedData.Length); // 179
                bw.Write(compressedData);
            }
        }
        // and the reverse...
        using (var fs2 = new StreamReader(@"c:\users\stackoverflow\desktop\sample.bin"))
        {
            using (var br = new BinaryReader(fs2.BaseStream))
            {
                var len = (int)br.BaseStream.Length;
                var encrypted = br.ReadBytes(len);
                // decrypt here
                var decrypted = encrypted; // <== new result after decryption
                using (var ms = new MemoryStream(decrypted))
                {
                    List<byte> bytesList = new List<byte>();
                    using (var decompress = new GZipStream(ms, CompressionMode.Decompress, true))
                    {
                        int val = decompress.ReadByte();
                        while (val > -1)
                        {
                            bytesList.Add((byte)val);
                            val = decompress.ReadByte();
                        }  
                    }
                    var final_result = new String(Encoding.UTF8.GetChars(bytesList.ToArray()));
                    Console.WriteLine(final_result);
                }
            }
        }

        Console.ReadLine();
    }

Upvotes: 2

Sven
Sven

Reputation: 22673

You are treating compressed data as a utf-8 byte array. Utf-8 actually has very strict rules so half of your compressed data is probably getting replaced by question marks (placeholders for an invalid character) in that step.

You need to encrypt/decrypt the raw binary data, and lose the string conversion. Compressed data is not a string and shouldn't be treated as such.

If your encryption method can only operate on strings (I don't have the definition of your Cryptography class), then you have no choice but to encrypt the XML data first and then compress it (though it will probably not compress as well that way).

You are also not actually doing any decompression; you construct a MemoryStream and GZipStream for the compressed data, but then don't do anything with them and try to use data directly.

Upvotes: 2

Alexei Levenkov
Alexei Levenkov

Reputation: 100527

You are not reading anything from "decompress". You need to read all data from the "decompress" (since there is no length of the data stored you have to read till stream is empty) and than convert it to string as you are doing.

Upvotes: 2

Related Questions