1
votes

I am using the following code to compress 2 strings, it works well in compression. However, when I try to decompress the second strings and if the first one is short (about 4 characters) I got Block length does not match with its complement exception. Here is the class I used for compression:

    using System;
    using System.IO;
    using System.IO.Compression;
    using System.Text;

    namespace CompressString {
    internal static class StringCompressor
{
    /// <summary>
    /// Compresses the string.
    /// </summary>
    /// <param name="text">The text.</param>
    /// <returns></returns>
    public static string CompressString(string value)
    {
        //Transform string into byte[] 
        byte[] byteArray = new byte[value.Length];
        int indexBA = 0;
        foreach (char item in value.ToCharArray())
        {
            byteArray[indexBA++] = (byte)item;
        }

        //Prepare for compress
        System.IO.MemoryStream ms = new System.IO.MemoryStream();
        System.IO.Compression.GZipStream sw = new System.IO.Compression.GZipStream(ms,
        System.IO.Compression.CompressionMode.Compress);

        //Compress
        sw.Write(byteArray, 0, byteArray.Length);
        //Close, DO NOT FLUSH cause bytes will go missing...
        sw.Close();

        //Transform byte[] zip data to string
        byteArray = ms.ToArray();
        System.Text.StringBuilder sB = new System.Text.StringBuilder(byteArray.Length);
        foreach (byte item in byteArray)
        {
            sB.Append((char)item);
        }
        ms.Close();
        sw.Dispose();
        ms.Dispose();

        return sB.ToString();
    }

    /// <summary>
    /// Decompresses the string.
    /// </summary>
    /// <param name="compressedText">The compressed text.</param>
    /// <returns></returns>
    public static string DecompressString(string sData)
    {
        byte[] byteArray = new byte[sData.Length];

        int indexBa = 0;
        foreach (char item in sData)
            byteArray[indexBa++] = (byte)item;

        MemoryStream memoryStream = new MemoryStream(byteArray);
        GZipStream gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress);

        byteArray = new byte[1024];

        StringBuilder stringBuilder = new StringBuilder();

        int readBytes;
        while ((readBytes = gZipStream.Read(byteArray, 0, byteArray.Length)) != 0)
        {
            for (int i = 0; i < readBytes; i++) stringBuilder.Append((char)byteArray[i]);
        } gZipStream.Close(); memoryStream.Close(); gZipStream.Dispose(); memoryStream.Dispose(); return stringBuilder.ToString();
    }
}

}

I got the exception in DecompressString method in the line:

while ((readBytes = gZipStream.Read(byteArray, 0, byteArray.Length)) != 0)
3
The built-in deflation algorithm of .NET is flaky and not recommended in any case - I'm not sure it's even been improves in more recent versions (can anyone clarify?) I'd say use SharpZipLib or something similar, just for starters.Grant Thomas
What do you mean by that Grant? sorry but I am novice in compression algorithms.. Will SharpZipLib solve my problem?user1477701
I've used the .NET built-in compression algorithms with great success. At the core, they are useful for compressing/decompressing data that you control directly.dblood

3 Answers

2
votes

For others that are receiving the error message "Block length does not match with its complement", this can occur if you are trying to decompress a file that was not compressed.

1
votes

Your Compress and Decompress methods should accept and return byte arrays. If you then are required to produce string output you can convert the byte array to a base64 string.

For example:

// compress some string data
string stringData = GetSomeStringData();

// assumes the string data is UTF8 string - would work for ASCII encoding as well
byte[] uncompressedData = Encoding.UTF8.GetBytes(stringData);

byte[] compressedData = StringCompressor.Compress(uncompressedData);

// produce base64 encode string of compressed data
string compressedString = Convert.ToBase64String(compressedData);

// decompress base64 encoded string 
// first convert to byte array
byte[] dataToDecompress = Convert.FromBase64String(compressedString);

byte[] decompressedData = StringCompressor.Decompress(dataToDecompress);

// encode decompressed data as a UTF8 encoded string
string decompressedString = Encoding.UTF8.GetString(decompressedData);

Rename and Tweak your Compress() and Decompress() methods accordingly. If you really wanted to have a class that strictly worked with strings, embed the logic of the Base 64 encoding/decoding in your methods. However, if your class works directly with 'byte[]` your code will be much more flexible and reusable in other instances.

1
votes

I get the same "Block length does not match with its complement." System.IO.InvalidDataException.

I've found this information: http://yvanrodrigues.com/content/block-length-does-not-match-its-complement

It states: "Seek forward 2 bytes first. There is a two byte signature 0x789c at the beginning of the deflated file."

It should work if you skip these 2 bytes.

Further information: What does a zlib header look like? and .Net zlib inflate with .Net 4.5