圧縮処理(ExternalObject 3)

寒い季節がやってきました。先週まで垂れっぱなしだった鼻水もようやく止まって少し元気になってきました。その前はノロで苦しんだ訳ですが、年の瀬も近づき忙しくなってきて寝込むどころの騒ぎではない訳です。
まあ、それは置いておいて、今回は久しぶりにExternalObjectネタです。以前からJavascript上でのdeflate関連の実装を考えていたのですが、インタープリタが故、非常に鈍く実用化にはほど遠い状況です。わたしのコーディングの問題だと言われれば反論のしようも無いのですが。
で、現実的な所を考えるとzlibの利用が一番確実だと思ったのでExternalObjectから利用する方法を考えてみました。

プロジェクトの構成については「ExternalObjectで高速化」を参照してください。こちらの方に詳細な解説があります。しかしながら今回は既存のライブラリを活用する為にあとひと手間必要です。今回利用するzlibに関してはhttp://zlib.net/を一読下さい。と言いましてもOSXでは既にインストールされていますから利用方法だけ把握していただければ結構です。Winな方々はググって下さい。必要なのは共有MFC DLLですのでプロジェクト自体はbase64の時と変わりません。しかしながらウインドウズのダイナミックライブラリやスタティックライブラリに関しては、わたしも調べてませんがググれば導入方法はすぐに見つかるでしょう。

コンパイルに必要なヘッダ関係は

/usr/include/

辺りに収まっていますし。実際にリンクするダイナミックライブラリも

/usr/lib/libz.dylib

があるはずです。無い場合はソース落としてきて

./configure –shared –prefix=/usr

としてダイナミックライブラリ用にコンパイルするとよろしいかと。しかし、ここで一つ。version1.2.3のzlibのソースはダイナミックライブラリを生成する時にCFLAG絡みの問題があって不正なライブラリが出来ちゃうので最新版を利用するようにしてください。

話を戻してプロジェクトの設定です。
carbonフレームワークを指定するのは以前と同じです。しかし、Xcodeのバージョンによってはcarbon自体がテンプレートから外れてたりします。そう言う場合は旧バージョンから持ってこないといけません。
今回はダイナミックライブラリを利用しますのでそれもプロジェクトに追加します。どうするかというと「External Frameworks and Libraries」に直接「libz.dylib」をリンクさせます。
基本的に「追加→既存のフレームワーク」から選択すればいいのですが「/usr/lib/libz.dylib」をダイレクトに選択しても同じです。
ちなみにこの時の「libz.dylib」はリンクを選びましょう。

deflate_project.png

正しく設定できると上の見本の様になるはずです。
では、メインのコードを

#include “SoSharedLibDefs.h”
#include “SoCClient.h”
#include <stdlib.h>
#include <stdio.h>
#include <zlib.h>

using namespace std;

#define CHUNK  16384

z_stream z;

unsigned char inbuf[CHUNK];
unsigned char outbuf[CHUNK];
FILE *fin, *fout;

extern “C” void do_compress(void)
{
    int count, flush, status;

    z.zalloc = Z_NULL;
    z.zfree = Z_NULL;
    z.opaque = Z_NULL;

    if (deflateInit(&z, Z_DEFAULT_COMPRESSION) != Z_OK)
    {
        exit(1);
    }
    
    z.avail_in = 0;
    z.next_out = outbuf;
    z.avail_out = CHUNK;
    flush = Z_NO_FLUSH;

    while (1)
    {
        if (z.avail_in == 0)
        {
            z.next_in = inbuf;
            z.avail_in = fread(inbuf, 1, CHUNK, fin);

            if (z.avail_in < CHUNK) flush = Z_FINISH;
        }
        status = deflate(&z, flush);

        if (status == Z_STREAM_END) break;

        if (status != Z_OK)
        {
            exit(1);
        }

        if (z.avail_out == 0)
        {
            if (fwrite(outbuf, 1, CHUNK, fout) != CHUNK)
            {
                exit(1);
            }
            z.next_out = outbuf;
            z.avail_out = CHUNK;
        }
    }

    if ((count = CHUNK – z.avail_out) != 0)
    {
        if (fwrite(outbuf, 1, count, fout) != count)
        {
            exit(1);
        }
    }
    
    if (deflateEnd(&z) != Z_OK)
    {
        exit(1);
    }
}

extern “C” int comp_def ( TaggedData* argv, int argc, TaggedData* result )
{
    char *getStr;

    getStr = argv[0].data.string;
    if ((fin = fopen(getStr, “r”)) == NULL)
    {
        exit(1);
    }
    if ((fout = fopen(“/tmp_file.txt”, “w”)) == NULL)
    {
        exit(1);
    }
    do_compress();
    fclose(fin);
    fclose(fout);

    result->type = kTypeBool;
    result->data.intval = 1;
    return kESErrOK;
}

以前と同様に2段がまえです。cppですが、内容は全てCスタイルなのはいつもの事ですので気にしないでください。

#include “SoSharedLibDefs.h”
#include “SoCClient.h”

この2点のヘッダファイルのリンクは忘れてはいけません。

#include <zlib.h>

今回は上のファイルへリンクします。ダイナミックライブラリをリンクしていますので、一行書いとけば良いだけです。ヘッダファイル自身をプロジェクトに追加する必要はありません。

続くルーチンはzlibのお手本通りの構成ですのでzlibホームページを確認してください。
直接ExtendScriptからアクセスする「comp_def」は以前のbase64の時の構成とほぼ一緒です。今回も特にreturnするものはありません。ファイルからデータを読み込み、ファイルへと書き出していますので。
base64の時はファイルストリーム上で処理していましたが、今回はバッファ上で処理しています。バッファの容量はCHUNKを調節してください。大きなデータを扱う必要が無ければこれぐらいで十分です(十分すぎます)。

一方、ExtendScript側はというと、

var libPath = “/deflate.framework”;
var libdef = new ExternalObject(“lib:” + libPath);
libdef.comp_def(“cvtfile.txt”);
libdef.unload();

今回も出来上がったフレームワークは起動ディスクの第一階層に置いておくとして、上記の様になります。
フレームワークのパスを指定して、圧縮かけたいファイルを引数にファンクションを呼び出して、フレームワークをアンロードするという具合です。ちなみに圧縮されたデータは「tmp_file.txt」です。このファイルにヘッダとかフッタをつけて体裁を整えてあげればzipファイルと同じものになります。圧縮率は当然zip処理した時と同じです。バイナリエディタで覗けばデータ自体は同じ状態になっています。

bin_comp.png

一応、バイナリエディタで覗いてみます。左がzipファイル。右側がフレームワークが生成したファイルです。zipファイルよりも容量が小さくなっているのはヘッダ+フッタの分だと思われます。
最後に、Xcodeのプロジェクトも置いておきます。versionは3.2.2、GCC4.2.2ですがGCC4.0でもコンパイルは通ると思います。

deflate.zip

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中