Reputation: 857
I am trying to use a dictionary with the ZLIB .NET library but the ZStream
member inflateSetDictionary
always returns Z_STREAM_ERROR
. I have tracked this down to a sub call to Inflate.inflateSetDictionary
which tests if (z.istate.mode == DICT0
)
Does anyone know how to use dictionaries with this library or know of any good examples. A simplified version of my code is shown below...
public class Form1 : System.Windows.Forms.Form
{
static private string sDictionary = "VALUE1,VALUE2,VALUE3";
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);
}
}
class GZInputStream : ZInputStream
{
public GZInputStream(Stream in_Renamed)
: base(in_Renamed)
{
byte[] dictionary = System.Text.ASCIIEncoding.ASCII.GetBytes(sDictionary);
z.inflateSetDictionary(dictionary, dictionary.Length);
}
public GZInputStream(Stream in_Renamed, int level)
: base(in_Renamed, level)
{
byte[] dictionary = System.Text.ASCIIEncoding.ASCII.GetBytes(sDictionary);
z.deflateSetDictionary(dictionary, dictionary.Length);
}
}
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();
}
private void compressFile(string inFile, string outFile)
{
FileStream outFileStream = new System.IO.FileStream(outFile, System.IO.FileMode.Create);
GZOutputStream outZStream = new GZOutputStream(outFileStream, 1); // zlibConst.Z_DEFAULT_COMPRESSION);
System.IO.FileStream inFileStream = new System.IO.FileStream(inFile, System.IO.FileMode.Open);
try
{
CopyStream(inFileStream, outZStream);
}
finally
{
outZStream.Close();
outFileStream.Close();
inFileStream.Close();
}
}
private void decompressFile(string inFile, string outFile)
{
FileStream outFileStream = new FileStream(outFile, FileMode.Create);
GZOutputStream outZStream = new GZOutputStream(outFileStream);
FileStream inFileStream = new FileStream(inFile, FileMode.Open);
try
{
CopyStream(inFileStream, outZStream);
}
finally
{
outZStream.Close();
outFileStream.Close();
inFileStream.Close();
}
}
}
Upvotes: 1
Views: 1083
Reputation: 48066
I managed to get zlib compression with dictionary to work based on DotNetZip (nuget, github).
Since the api calls requires neither obvious, well documented, nor short, I placed the wrapper in its own nuget package ZlibWithDictionary (nuget, github).
Usage is simple:
var compressed_byte_array = DeflateCompression.ZlibCompressWithDictionary(
bytes_array_to_compress,
CompressionLevel.Default,
null /*use default window size in bits; possible values 9-15*/,
CompressionStrategy.Default,
byte_array_of_dictionary
);
var decompressed_byte_array = DeflateCompression.ZlibDecompressWithDictionary(
compressed_byte_array,
byte_array_of_dictionary
);
If you prefer to manually use the appropriate zlib apis, you can peruse the source for the DeflateCompression
wrapper.
Upvotes: 1
Reputation: 857
Although I haven't completley solved my problem I wanted to share my progress...
When decompressing the data stream you must wait until Z_NEED_DICT is returned by the inflate(..) function, therefor I have added the following section of code to the ZLIB classes ZInputStream and ZOutputStream to check the error value returned from z.inflate...
if (err == zlibConst.Z_NEED_DICT)
{
byte[] dictionary = System.Text.ASCIIEncoding.ASCII.GetBytes(sDictionary);
z.inflateSetDictionary(dictionary, dictionary.Length);
err = z.inflate(flush_Renamed_Field);
}
Additionaly there appears to be an error in for following section of code from the Inflate.inflate function...
case DICT4:
if (z.avail_in == 0)
return r; r = f;
z.avail_in--; z.total_in++;
z.istate.need = ((z.next_in[z.next_in_index++] & 0xff) << 24) & unchecked((int)0xff000000L);
z.istate.mode = DICT3;
goto case DICT3;
In this code the value of z.istate.need gets set to a value 0xffffffffxx000000, this is incorrect as the top bits should be zero e.g. 0x00000000xx0000.
The following change fixes this problem..
z.istate.need = ((z.next_in[z.next_in_index++] & 0xff) << 24) & 0xff000000L;
Upvotes: 0