DOBON.NET DOBON.NETプログラミング掲示板過去ログ

zlib.netのZStream と 元祖zlibのz_stream との互換性

  • 題名: zlib.netのZStream と 元祖zlibのz_stream との互換性
  • 著者: スシボンバ−
  • 日時: 2008/03/08 8:19:19
  • ID: 21611
  • この記事の返信元:
    • (なし)
  • この記事への返信:
  • ツリーを表示
環境/言語:[WindowsVista, Viual C# 2008 Express, .NET Framework3.5]
分類:[.NET]

2008/03/08(Sat) 18:09:53 編集(投稿者)
2008/03/08(Sat) 18:09:32 編集(投稿者)

zlibを用いてベーシックレベルでのバイナリの圧縮・展開(Deflate/Inflate)を行っています。
しかしCで処理したものとC#で処理したものに互換性がなくてこまっています。

Cでは
[元祖zlib] http://zlib.net/
のz_streamを用いてオーソドックスにDeflate/Inflateしています。
(参考にした解説はhttp://oku.edu.mie-u.ac.jp/~okumura/compression/zlib.html)

.NET用ではマネージドコード用のzlibがあり、
[ZLIB.NET] http://www.componentace.com/zlib_.NET.htm
のzlib.ZStreamを用いて、自分なりに移植してみました。Cからわずかな変更でうごきます。

CのzlibでDeflateしたものは、CのzlibでInflateできますし、C#でもそれぞれのライブラリでのDeflate/Inflateは成功しました。
しかし、たとえばCのzlibでDeflateしたものを、C#のZLIB.NETでInflateしようとすると、未知の形式としてエラーがでます。

試しに、短いバイナリを圧縮レベル6でCのzlibとC#のZLIB.NETでそれぞれ圧縮してみると、できあがった圧縮バイナリが微妙にことなっていました。私自身、zlibを使うのが今回初めてで、ゼロから調べていったのですが、なぜ同じ結果にならないのかわからず途方にくれています。どちらもRFC 1951にそって同じアルゴリズムで圧縮されているのではないのでしょうか?

最終的にしたいことは、"Cの元祖zlib"に準じたデータをC#でも処理(圧縮・展開)したい、ということです。
.NEt用のzlibについて詳しい方で解決方法をご存じの方がいらしたら教えていただけないでしょうか?よろしくお願いいたします。




*Cでの圧縮は以下のサンプルソースを参考にして、(CompLevelを変えて)一般的に処理しました。
http://oku.edu.mie-u.ac.jp/~okumura/compression/comptest.c


*ZLIB.NET用にとりあえずC#用につくった、バイナリ配列→バイナリ配列のソース
エラー処理でstreamのcloseとかはやってません。


public static byte[] compressZ( byte[] inbuf, int level ) //CompLevel= 0-9
{
zlib.ZStream z = new zlib.ZStream();
MemoryStream ms = new MemoryStream();
byte[] outbuf = new byte[1024]; //任意のバッファサイズ

if( z.deflateInit( level ) != zlib.zlibConst.Z_OK ) return null;

z.next_in = inbuf; /* 入力ポインタを入力バッファの先頭に */
z.avail_in = inbuf.Length; /* データを読み込む */
z.next_in_index = 0; /* for C# */

z.next_out = outbuf; /* 出力ポインタ */
z.avail_out = outbuf.Length; /* 出力バッファのサイズ */
z.next_out_index = 0; /* for C# */

while( true )
{
int status = z.deflate( zlib.zlibConst.Z_FINISH ); /* 圧縮する */
if( status == zlib.zlibConst.Z_STREAM_END ) break; /* 完了 */
if( status != zlib.zlibConst.Z_OK ) return null; /* エラー */
if( z.avail_out == 0 )
{ /* 出力バッファが尽きれば */
/* まとめて書き出す */
ms.Write( outbuf, 0, outbuf.Length );
z.next_out = outbuf; /* 出力バッファ残量を元に戻す */
z.avail_out = outbuf.Length; /* 出力ポインタを元に戻す */
z.next_out_index = 0; /* for C# */
}
}

/* 残りを吐き出す */
if( (outbuf.Length - z.avail_out) != 0 )
{
ms.Write( outbuf, 0, outbuf.Length - z.avail_out );
}

/* 後始末 */
if( z.deflateEnd( ) != zlib.zlibConst.Z_OK ) return null;
z.free();

return ms.ToArray();
}

public static byte[] decompressZ( byte[] inbuf )
{
zlib.ZStream z = new zlib.ZStream();
MemoryStream ms = new MemoryStream();
byte[] outbuf = new byte[1024]; //任意のバッファサイズ

if( z.inflateInit( ) != zlib.zlibConst.Z_OK ) return null;

/* 初期化 */
z.next_in = inbuf; /* 入力ポインタを入力バッファの先頭に */
z.avail_in = inbuf.Length; /* データを読み込む */
z.next_in_index = 0; /* for C# */

z.next_out = outbuf; /* 出力ポインタ */
z.avail_out = outbuf.Length; /* 出力バッファ残量 */
z.next_out_index = 0; /* for C# */

while( true )
{
int status = z.inflate( zlib.zlibConst.Z_NO_FLUSH ); /* 展開 */
if( status == zlib.zlibConst.Z_STREAM_END ) break; /* 完了 */
if( status != zlib.zlibConst.Z_OK ) return null; /* エラー */

if( z.avail_out == 0 )
{ /* 出力バッファが尽きれば */
/* まとめて書き出す */
ms.Write( outbuf, 0, outbuf.Length );
z.next_out = outbuf; /* 出力バッファ残量を元に戻す */
z.avail_out = outbuf.Length; /* 出力ポインタを元に戻す */
z.next_out_index = 0; /* for C# */
}
}

/* 残りを吐き出す */
if( (outbuf.Length - z.avail_out) != 0 )
{
ms.Write( outbuf, 0, outbuf.Length - z.avail_out );
}

/* 後始末 */
if( z.inflateEnd() != zlib.zlibConst.Z_OK ) return null;
z.free();

return ms.ToArray();
}
自己レスですみません。

調べてみたらRFCもいろいろあったんんですね。バイナリは互換性がないそうです。

zlibはRFC1950
GZIPはRFC1952
SharpZipLibのdeflateはRFC1951
System.IO.CompressionはRFC1952
java.util.zip.DeflaterOutputStreamはRFC1950、1951、1952 のどれかを指定可....

zlib.netがどのバージョンかはわかりませんでしたが、RFC1950ではなかったということみたいです。
  • 題名: Re[2]: RFCのバージョン違い
  • 著者: スシボンバ−
  • 日時: 2008/03/12 19:25:33
  • ID: 21652
  • この記事の返信元:
  • この記事への返信:
    • (なし)
  • ツリーを表示
自己解決しましたのでご報告します。

zlibのInitにマイナスのWindowBitを指定すると、ヘッダのないRFC1950になることがわかりました。具体的には上記のコードで

z.deflateInit( level , WindowBit )
z.inflateInit( WindowBit )

などに書き換え、WindowBitに-15とか指定してやります。
おさわがせしました〜〜。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板