外部DLLをつかわずにZIPを解凍する(VC++6/2010でzlibを使用する)

zlib-1.2.3を使いました。

http://gnuwin32.sourceforge.net/packages/zlib.htm

zlibのビルド(zlib.libの作成)

  • zconf.hの287行目 #if 1 を #if 0 にする
  • gzio.cの884行目 return gzseek(file, 0LL, SEEK_CUR); を return gzseek(file, 0L, SEEK_CUR); に変更
  • Makefile.mscを開いて CFLAGS = -nologo -MD -O2 $(LOC) を CFLAGS = -nologo -MDd -O2 $(LOC) に変更
    • これはコード生成の設定が「マルチスレッド(DLL,デバッグ)」になっている人用の設定
  • DOS窓を開いて zlib-1.2.3フォルダに移動し、nmake -f win32/Makefile.msc と実行。
    • VisualStudio2010ならVisual Studio コマンドプロンプト(2010)で行う
  • zdll.libができあがり。

ネタ元

zlibを自作プログラムに組み込む

  • 以下のファイルをプロジェクトに追加します。
    • zlib-1.2.3\contrib\minizip\crypt.h
    • zlib-1.2.3\contrib\minizip\ioapi.c
    • zlib-1.2.3\contrib\minizip\ioapi.h
    • zlib-1.2.3\contrib\minizip\unzip.c
    • zlib-1.2.3\contrib\minizip\unzip.h
    • zlib-1.2.3\zconf.h
    • zlib-1.2.3\zlib.h
  • 以下のファイルをプロジェクトフォルダにコピーします。
    • zlib-1.2.3\zdll.lib
  • 以下ファイルを保存してプロジェクトに追加します。
#define STRICT
#include <string>
#include <windows.h>
#include "unzip.h"
using namespace std;

#pragma comment(lib, "zlib.lib")

#define for if (0) ; else for
#define IsShiftJIS(x) ((BYTE)((x ^ 0x20) - 0xA1) <= 0x3B)

//---------------------------------------------------------------------------
// ファイルが存在するかどうか
bool IsFileExist(const string &strFilename) {
  return GetFileAttributes(strFilename.c_str()) != 0xffffffff;
}

//---------------------------------------------------------------------------
// 再帰的にディレクトリを作成(strPathの末尾には必ず\をつけること)
bool CreateDirectoryReflex(const string &strPath) {
  const char *p = strPath.c_str();
  for (; *p; p += IsShiftJIS(*p) ? 2 : 1)
    if (*p == '\\') {
      string strSubPath(strPath.c_str(), p);
      if (!IsFileExist(strSubPath.c_str()))
        if (!CreateDirectory(strSubPath.c_str(), NULL))
          return false;
    }
  return true;
}

//---------------------------------------------------------------------------
// ZIPファイルを解凍する
bool Unzip(const string &strZipFilename, const string &strTargetPath) {
  unzFile hUnzip = unzOpen(strZipFilename.c_str());
  if (!hUnzip)
    return false;

  do {
    char szConFilename[512];
    unz_file_info fileInfo;
    if (unzGetCurrentFileInfo(hUnzip, &fileInfo, szConFilename, sizeof szConFilename, NULL, 0, NULL, 0) != UNZ_OK)
      break;

    int nLen = strlen(szConFilename);
    for (int i = 0; i < nLen; ++i)
      if (szConFilename[i] == '/')
        szConFilename[i] = '\\';

    // ディレクトリの場合
    if (nLen >= 2 && !IsShiftJIS(szConFilename[nLen - 2]) && szConFilename[nLen - 1] == '\\') {
      CreateDirectoryReflex(strTargetPath + szConFilename);
      continue;
    }

    // ファイルの場合
    if (unzOpenCurrentFile(hUnzip) != UNZ_OK)
      break;
    CreateDirectoryReflex(strTargetPath + szConFilename);
    HANDLE hFile = CreateFile((strTargetPath + szConFilename).c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
    BYTE szBuffer[8192];
    DWORD dwSizeRead;
    while ((dwSizeRead = unzReadCurrentFile(hUnzip, szBuffer, sizeof szBuffer)) > 0)
      WriteFile(hFile, szBuffer, dwSizeRead, &dwSizeRead, NULL);
    FlushFileBuffers(hFile);
    CloseHandle(hFile);
    unzCloseCurrentFile(hUnzip);

  } while (unzGoToNextFile(hUnzip) != UNZ_END_OF_LIST_OF_FILE);

  unzClose(hUnzip);

  return true;
}
#ifndef _ZIP_H__
#define _ZIP_H__

//---------------------------------------------------------------------------
// ZIPƒtƒ@ƒCƒ‹‚ð‰ð“€‚·‚é
bool Unzip(const string &strZipFilename, const string &strTargetPath);

#endif //_ZIP_H__
  • 上記C/CPPファイル群を「プリコンパイル済みヘッダを使用しない」設定にする
    • プロジェクト>設定を選んで「Source Files」の中上記C/CPPファイルを選択
    • 右側の「C/C++」のタブを選んで、さらにカテゴリを「プリコンパイル済みヘッダ」にして「プリコンパイル済みヘッダを使用しない」にする
  • あとはzip.hをインクルードすれば、zipを解凍するUnzip関数が使えます。
    • 以下の定義も必要
      • #include
      • using namespace std;

Unzip関数の使い方

bool Unzip(const string &strZipFilename, const string &strTargetPath);
strZipFilename 解凍したいzipファイルを指定します。
strTargetPath 解凍先のディレクトリ名を指定します。必ず末尾を\にしてください。
戻り値 解凍に成功すればtrue、失敗すればfalseを返します。


ネタ元