物理の駅 Physics station by 現役研究者

テクノロジーは共有されてこそ栄える

Visual Studioで zlibとlibzip をコンパイル、C++からZIPファイルを生成してみる

ほぼ以下のブログが網羅しているので読んで欲しい

blog.sssoftware.main.jp

以下、私用のメモ

準備

cmakeをインストールする

Download | CMake

Windows win64-x64 Installer で良いだろう 途中のオプションで、Add CMake to the system PATH for the current user にチェックを入れておく(今回は使わないけど)

zlibのコンパイル

zlib-1.2.11のソースコードをダウンロードし、展開する。Windowsだと7zipを使って展開すると良いだろう。

https://www.zlib.net/zlib-1.2.11.tar.gz

buildフォルダを作り、CMakeにフォルダーとbuildフォルダーを貼り付けた。 構成は以下の画像のようにした。 Configure で Visual Studio 15 2017x64 を選び、適宜書き換えて、 Generate

f:id:onsanai:20200412133657p:plain

buildフォルダ内のzlib.sln を Visual Studio 2017 開いて、パッチビルドから全てをビルド。

libzipのコンパイル

zlib-1.2.11のソースコードをダウンロードし、展開する。

Download · libzip

buildフォルダを作り、CMakeにフォルダーとbuildフォルダーを貼り付けた。 構成は以下の画像のようにした。 Configure で Visual Studio 15 2017x64 を選び、適宜書き換えて、 Generate

f:id:onsanai:20200412134432p:plain

buildフォルダ内のlibzip.sln を Visual Studio 2017 開いて、パッチビルドから全てをビルド。

RUN_TESTS
distcheck
update_zip_err_str
update_zip_errors
check
dist

コンパイルに失敗したが、チェック用なので見なかったことにする。

Visual Studioからライブラリとして使う

環境変数にbinフォルダを、インクルードディレクトリにincludeフォルダを、リンカーに lib\zip.lib を通す。ソースコードは以下の通り。

ここでは、ファイルから圧縮するのではなく、RAM上のデータから直接ファイルに書き出す(だって、C++でやりたい理由って真っ先にそれやん?) をやってみる。

#include <zip.h>
#include <filesystem>

//https://gist.github.com/clalancette/bb5069a09c609e2d33c9858fcc6e170e をパクった

void zip_file_add_impl(zip_t* zipper, std::string filename, const std::vector<char>& buf) {

    zip_source_t* source = zip_source_buffer(zipper, buf.data(), buf.size(), 0);

    if (source == nullptr) {
        throw std::runtime_error("Failed to add file to zip: " + std::string(zip_strerror(zipper)));
    }

    if (zip_file_add(zipper, filename.c_str(), source, ZIP_FL_ENC_UTF_8) < 0) {
        zip_source_free(source);
        throw std::runtime_error("Failed to add file to zip: " + std::string(zip_strerror(zipper)));
    }
}
int main(int argc, char* argv[]) {

    //サンプルファイル用
    std::vector<char>buf;
    for (int i = 0; i < 10; i++) {
        buf.emplace_back(48 + i);
    }

    int errorp;
    std::string output_filename = "test.zip";

    //ZIpファイルが既に存在してれば削除
    if (std::filesystem::exists(output_filename)) {
        std::filesystem::remove(output_filename);
    }

    //ZIPファイルを作成
    zip_t* zipper = zip_open(output_filename.c_str(), ZIP_CREATE | ZIP_EXCL, &errorp);

    //エラー処理
    if (zipper == nullptr) {
        zip_error_t ziperror;
        zip_error_init_with_code(&ziperror, errorp);
        throw std::runtime_error("Failed to open output file " + output_filename + ": " + zip_error_strerror(&ziperror));
    }

    //ファイルをRAMから追加
    zip_file_add_impl(zipper, "0.txt", buf);
    zip_file_add_impl(zipper, "1.txt", buf);
    zip_file_add_impl(zipper, "2.txt", buf);

    //ZIPファイルを閉じる
    zip_close(zipper);

    return 0;
}