Reputation: 11
I am using zlib.net in c# to compress and decompress string.
This is my code
class GZOutputStream : ZOutputStream
{
public GZOutputStream(Stream in_Renamed) : base(in_Renamed)
{
byte[] dictionary = System.Text.ASCIIEncoding.ASCII.GetBytes(sDictionary);
z.inflateSetDictionary(dictionary, dictionary.Length);
}
public GZOutputStream(Stream in_Renamed, int level) : base(in_Renamed, level)
{
byte[] dictionary = System.Text.ASCIIEncoding.ASCII.GetBytes(sDictionary);
z.deflateSetDictionary(dictionary, dictionary.Length);
}
}
public static byte[] compressString(string source)
{
byte[] buffer = System.Text.Encoding.Default.GetBytes (source);
MemoryStream memOutput = new MemoryStream ();
GZOutputStream zipOut = new GZOutputStream(memOutput, zlibConst.Z_DEFAULT_COMPRESSION);
zipOut.Write(buffer, 0, buffer.Length);
zipOut.finish();
memOutput.Seek(0, SeekOrigin.Begin);
byte[] result = memOutput.ToArray();
return result;
}
public static byte[] deCompressString(string source)
{
byte[] buffer = System.Text.Encoding.Default.GetBytes (source);
MemoryStream memOutput = new MemoryStream ();
GZOutputStream zipOut = new GZOutputStream(memOutput);
zipOut.Write(buffer, 0, buffer.Length);
zipOut.finish();
memOutput.Seek(0, SeekOrigin.Begin);
byte[] result = memOutput.ToArray();
return result;
}
When I compress a string, it works well. However, when I decompress the result string of the compress function, there is an exception :
ZStreamException: inflating:
zlib.ZOutputStream.Write (System.Byte[] b1, Int32 off, Int32 len)
So what's the solution?
Upvotes: 1
Views: 3768
Reputation: 7793
Stumbled across the same error message today. After using zlib.net for more than 15 years in productive code.
For a specific binary file, I could compress it but when decompressing it, this seemingly random file could not be decompressed and I always got the ZStreamException: inflating:
error.
After reviewing the above answer from Glen, I tested the Write(byte[], int, int)
method override and saw that z.inflate
returned -5 (Z_BUF_ERROR) after about 700 of 800 chunks. The zlib manual states the following:
inflate() returns [...] Z_BUF_ERROR if no progress was possible or if there was not enough room in the output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and inflate() can be called again with more input and more output space to continue decompressing.
And basically the same for the deflate()
function. According to this, there may be the case that Z_BUF_ERROR is returned in which case (de-)compression can just continue instead of throwing an exception. The derived class we are now using is this:
/// <summary>
/// ZOutputStream which fixes issues in zlib.net 1.0.4
/// </summary>
internal class MyOutputStream : zlib.ZOutputStream
{
private Stream m_outStream;
public MyOutputStream(Stream outStream) : base(outStream)
{
m_outStream = outStream;
}
public MyOutputStream(Stream outStream, int level) : base(outStream, level)
{
m_outStream = out_Renamed;
}
public override void Write(byte[] buffer, int offset, int length)
{
if (length == 0)
return;
int err;
z.next_in = buffer;
z.next_in_index = offset;
z.avail_in = length;
do
{
z.next_out = buf;
z.next_out_index = 0;
z.avail_out = bufsize;
if (compress)
err = z.deflate(flush_Renamed_Field);
else
err = z.inflate(flush_Renamed_Field);
// Z_STREAM_END -> end of stream is not an error, this is also in zlib.net 1.0.4
// Z_BUF_ERROR -> no data was available in the source stream is not an error,
// this caused an exception in zlib.net 1.0.4
// (see https://www.zlib.net/manual.html)
if (err != zlib.zlibConst.Z_OK
&& err != zlib.zlibConst.Z_STREAM_END
&& err != zlib.zlibConst.Z_BUF_ERROR)
{
throw new zlib.ZStreamException((compress ? "de" : "in") + "flating: " + z.msg);
}
m_outStream.Write(buf, 0, bufsize - z.avail_out);
}
while (z.avail_in > 0 || z.avail_out == 0);
}
}
For comparison, see the zlib.net source code on github.
Upvotes: 0
Reputation: 466
5 year old question, I know, but for anyone still looking (and I was), the problem is that the Write method in ZOutputStream returns zlibConst.Z_NEED_DICT after the first call to z.inflate and that's when the dictionary needs to be supplied. So you need to override the Write method, test for that return and supply the dictionary at that point...
public override void Write(System.Byte[] b1, int off, int len)
{
if (len == 0)
return;
int err;
z.next_in = b1;
z.next_in_index = off;
z.avail_in = len;
do
{
z.next_out = buf;
z.next_out_index = 0;
z.avail_out = bufsize;
if (compress)
err = z.deflate(flush_Renamed_Field);
else
err = z.inflate(flush_Renamed_Field);
if (err == zlibConst.Z_NEED_DICT)
{
int y=z.inflateSetDictionary(dict, dict.Length);
err = z.inflate(flush_Renamed_Field);
}
if (err != zlibConst.Z_OK && err != zlibConst.Z_STREAM_END)
{
throw new ZStreamException((compress ? "de" : "in") + "flating: " + z.msg);
}
ms.Write(buf, 0, bufsize - z.avail_out);
}
while (z.avail_in > 0 || z.avail_out == 0);
}
}
Upvotes: 0
Reputation: 11
public static string DeCompressToString(byte[] buffer)
{
MemoryStream memOutput = new MemoryStream();
ZOutputStream zipOut = new ZOutputStream(memOutput);
zipOut.Write(buffer, 0, buffer.Length);
zipOut.finish();
memOutput.Seek(0, SeekOrigin.Begin);
byte[] result = memOutput.ToArray();
var str = System.Text.Encoding.Default.GetString(result);
return str;
}
Upvotes: 0