memo‎ > ‎

zlib

zlibの使い方についてメモ
環境は Visual Studio 2010 Professional とする。

ダウンロード
ここをクリックすると zlib-1.2.3-src.exe が勝手にダウンロードされる。
zlib-1.2.3-src.exe を起動し、インストールする。
デフォルトでインストールした場合は
C:\Program Files (x86)\GnuWin32\src\zlib\1.2.3\zlib-1.2.3
以下のフォルダに必要なファイルが保存される。
zlib-1.2.3 を必要なところにコピー(移動)する。

ソリューションファイル・プロジェクトファイルを開く
zlib-1.2.3\win32\VisualC.txt にはプロジェクトの場所が記述してある。
zlib-1.2.3\projects\visualc6\zlib.dsw がソリューションファイル。
同フォルダにプロジェクトファイル zlib.dsp と minigzip.dsp と example.dsp の3つがある。
それら全4つのファイルはVisualStudio 6.0の古い形式なので開くと自動的に変換される。
構成マネージャはDebugかRelease、ダイナミックリンクかスタティックリンク、ASMかで計8通りのビルド方法がある。
このうち、ASMはビルドができないようだ。
以下デフォルトのDebug(スタティックリンク、ASMなし)として解説する。

zlibプロジェクトのビルド
(VSソリューションを開き、下位フォルダに zlib-1.2.3 があるものとして)
ソリューションを右クリック>[追加]>[既存のプロジェクト]で zlib.dsp を追加する。(プロジェクトファイルは自動変換)
この状態でプロジェクトを右クリックしてビルドすると、fatal error C1083: include ファイルを開けません。'unistd.h': No such file or directory エラーが出る。
エラーをダブルクリックし、2行上(287行目)の
#if 1           /* HAVE_UNISTD_H -- this line is updated by ./configure */
の行の 1 を 0 にして、
#if 0           /* HAVE_UNISTD_H -- this line is updated by ./configure */
と書き換えてビルドすると、ビルドが成功する。
ビルドが成功するとDebug ビルドなら、zlib-1.2.3\projects\visualc6\Win32_LIB_Debug フォルダ内に 
zlibd.lib というスタティックリンクライブラリが作成される。

example プロジェクトと minigzip プロジェクトのビルド
「zlibプロジェクトのビルド」の続きとする。
minigzip.dsp と example.dsp をプロジェクトに追加する。
それぞれ、プロジェクトを右クリック>[構成プロパティ]>[リンカー]>[全般]>[追加のライブラリ ディレクトリ]に
zlib-1.2.3\projects\visualc6\Win32_LIB_Debug フォルダをフルパスで追加する。
プロジェクトを右クリック>[構成プロパティ]>[リンカー]>[入力]>[追加の依存ファイル]に 
zlibプロジェクトのビルドで作成された zlibd.lib を追加する。
[構成プロパティ]>[VC++ ディレクトリ]>[インクルード ディレクトリ]に zlib-1.2.3 フォルダをフルパスで追加する。
プロジェクトを右クリック>[プロジェクト依存関係]で zlib にチェックする。
これで両方共ビルドできるようになり、zlib-1.2.3\projects\visualc6\Win32_LIB_Debug に出力される。
minigzip.exe にはファイル・フォルダをドラッグすると gz 形式で圧縮される。

zlib のcompress()、uncompress()の使い方
必要なヘッダファイルは zlib.h と zconf.h(287行目 1を0にしたもの) なので準備する。
インクルードに必要なのは zlib.h。
ライブラリファイルはデフォルトで zlib をビルドした zlibd.lib とする。
zlibd.lib を必要なプロジェクトで可視にする([構成プロパティ]>[リンカー]>[入力]>[追加の依存ファイル]を編集など)。
圧縮したい時は compress() を使う。

//戻り値:Z_OKなら成功。ZM_MEM_ERRORはメモリ不足、Z_BUFF_ERRORは出力バッファのサイズ不足エラー。
int compress(unsigned char *dest,         // 出力:圧縮データを書き込むための、予め確保されたメモリ
             unsigned long *destLen,      // 入出力:dest で確保済みのサイズを入力し、書き込んだサイズを出力
             const unsigned char *source, // 入力:圧縮するデータ
             unsigned long sourceLen      // 入力:圧縮するデータのサイズ
             );

compress2()は圧縮レベルを最後の引数で1~9の範囲で指定できる。9が最も圧縮できるが低速。
元に戻すには uncompress() を使う。

//戻り値:Z_OKなら成功。ZM_MEM_ERRORはメモリ不足、Z_BUFF_ERRORは出力バッファのサイズ不足エラー。
int uncompress(unsigned char *dest,         // 出力:復号データを書き込むための、予め確保されたメモリ
               unsigned long *destLen,      // 入出力:dest で確保済みのサイズを入力し、書き込んだサイズを出力
               const unsigned char *source, // 入力:復号するデータ
               unsigned long sourceLen      // 入力:復号するデータのサイズ
               );

サンプルコード
zlib のcompress()、uncompress()のサンプルコード
#include <stdio.h>
#include <string.h>
#include "zlib.h"

int main()
{
  char src[100] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
  char* dest;
  unsigned long src_size, dest_size, compressed_size;
  int result;


  src_size = strlen(src) + 1;
  dest_size = src_size + 100;
  dest = new char[dest_size];
  printf("%s ($dバイト)を圧縮します\n\n", src, src_size);

  result = compress((unsigned char*)dest, &dest_size, (unsigned char*)src, src_size);
  //result = compress2((unsigned char*)dest, &dest_size, (unsigned char*)src, src_size, 9); // サイズ最適化

  if (result == Z_OK) {
    printf("圧縮に成功しました\n圧縮前=%dバイト、圧縮後=%dバイト\n\n", src_size, dest_size);
  } else if (result == Z_MEM_ERROR) {
    printf("メモリ不足のため失敗しました\n");
  } else if (result == Z_BUF_ERROR) {
    printf("出力バッファサイズ不足で失敗しました\n");
  } else {
    printf("ここにはこないはず\n");
  }

  unsigned long dest2_size = src_size + 100;
  char* dest2 = new char[dest2_size];
  uncompress((unsigned char*)dest2, &dest2_size, (unsigned char*)dest, dest_size);

  if (result == Z_OK) {
    printf("復号に成功しました\n復号前=%dバイト、復号後=%dバイト\n\n", dest_size, dest2_size);
  } else if (result == Z_MEM_ERROR) {
    printf("メモリ不足のため失敗しました\n");
  } else if (result == Z_BUF_ERROR) {
    printf("出力バッファサイズ不足で失敗しました\n");
  } else {
    printf("ここにはこないはず\n");
  }

  printf("%s このように復号されました\n", dest2);

  delete[] dest2;
  delete[] dest;
  return 0;
}

//実行結果
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa (53バイト)を圧縮します

圧縮に成功しました
圧縮前=53バイト、圧縮後=13バイト

復号に成功しました
復号前=13バイト、復号後=53バイト

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa このように復号されました
続行するには何かキーを押してください . . .

リンク