GZip decompress not working

Aug 16, 2010 at 3:37 PM

Hi,

First, thanks for your work in porting the code over to Silverlight. It's much appreciated.

I'm running into a problem where the GZipInputStream Read is getting into an infinite loop trying to read data from the memory stream. Here's my code:

 

public string StringDecompress(string type, string String)
        {
            MemoryStream ms = new MemoryStream(Convert.FromBase64String(String));

            Stream inStream;

            switch (type)
            {
                case "GZIP":
                    inStream = new GZipInputStream(ms);
                    break;

                case "BZIP":
                    inStream = new BZip2InputStream(ms);
                    break;

                case "ZIP":
                    inStream = new ZipInputStream(ms);
                    break;

                default:
                    throw new Exception("Unsupported type. Type must be: [GZIP BZIP ZIP]");
            }

            byte[] buffer = new byte[inStream.Length];
            inStream.Read(buffer, 0, buffer.Length);
            inStream.Close();
            ms.Close();

            string s = Encoding.Unicode.GetString(buffer, 0, buffer.Length);
            StringBuilder sb = new StringBuilder();
            foreach (char c in s)
            {
                if (c.Equals('\0'))
                    break;
                else
                    sb.Append(c);
            }

            return sb.ToString();
        }

The problem occurs on the inStream.Read(buffer, 0, buffer.Length) line. I passed a string of text in from a StringCompress routine that does something similar to the above but just with the OutputStream instead of the InputStream. I have confirmed that the code works when BZIP is specified, just not GZIP. Any ideas?

Thanks,

Chris

Developer
Aug 18, 2010 at 8:32 PM

Hey Chris,

I have written a test against this case and it passes. You seem to have a few issues with your code.

1) You are allocating your buffer to the length of an un-read inflation stream, which is 0.

The length of the inflated output is not quantifiable until the deflated bytes are actually read by the inflater stream.

I would suggest a read of the most excellent overview of binary stream operations by Jon Skeet @ http://www.yoda.arachsys.com/csharp/readbinary.html

In this case, you can simply pass your inStream to ReadFully to get your buffer.

 

2) The silverlight sharpziplib supports only UTF8 encoding. I should document this more fully. so 

string s = Encoding.Unicode.GetString(buffer, 0, buffer.Length);
should read string
s = Encoding.UTF8.GetString(buffer, 0, buffer.Length);

 

Given these adjustments, with some arbitrary text, the test case passes.

 

 

Developer
Aug 18, 2010 at 8:33 PM

Here is the test

 

/// <summary>
/// http://slsharpziplib.codeplex.com/Thread/View.aspx?ThreadId=223706
/// </summary>
[Test]
[Category("GZip_BugFix")]
public void TestGZip_BugFix000()
{

    // MemoryStream ms = new MemoryStream(Convert.FromBase64String(String));
    // get MS of gzipped string data 

    string inputString = @"
                Silverlight NUnit Project Template
                ==================================

                NOTE: New references must be marked with... Copy Local: True.

                This project template is designed to work with TestDriven.Net 2.13 or greater.
                http://www.testdriven.net/download.aspx

                To execute one or more unit tests use the 'Run Test(s)', 'Test With > Debugger'
                or 'Test With > Coverage' commands. Tests will execute using the Silverlight
                assemblies, but using the .NET 2.0 runtime.

                Individual methods can be executed using the Silverlight 2.0/CoreCLR runtime
                using the 'Test With > silverlight' command.

                For more information see:
                http://www.testdriven.net
                http://weblogs.asp.net/nunitaddon

                Alternatively you can email:
                Jamie Cansdale <jamie.cansdale@testdriven.net>
                ";
    var data = Encoding.UTF8.GetBytes(inputString);
    var ms = new MemoryStream();
    var gzip = new GZipOutputStream(ms);
    gzip.SetLevel(7);
    gzip.Write(data, 0, data.Length);
    gzip.Finish();

    ms.Position = 0;
            
    var inStream = new GZipInputStream(ms);
    var buffer = ReadFully(inStream);
    inStream.Close();
    ms.Close();

    string s = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
    StringBuilder sb = new StringBuilder();
    foreach (char c in s)
    {
        if (c.Equals('\0'))
            break;
        else
            sb.Append(c);
    }
    Assert.AreEqual(inputString, sb.ToString());
             
}

Aug 18, 2010 at 9:50 PM
Hi, Thanks, that solved my GZIP problem. I can now compress/decompress both GZIP and BZIP. I'm still having a problem if I switch to ZIP. I get an error of "No open entry." Any ideas? Thanks!
Developer
Aug 20, 2010 at 8:01 PM
coallen wrote:
Hi, Thanks, that solved my GZIP problem. I can now compress/decompress both GZIP and BZIP. I'm still having a problem if I switch to ZIP. I get an error of "No open entry." Any ideas? Thanks!

a zip stream is a bit different than other streams. you need to create and add ZipEntry objects.

see http://www.incrementalcoding.com/post/2010/07/28/Use-SharpZipLIb-to-create-zip-file-directly-from-database-without-saving-any-temporary-files-on-the-hard-disk.aspx for an example.