zip data descriptor

raw_zip_file.hppをコミットし忘れていたので差分が見れないんですが、拡張タイムスタンプヘッダとInfo-ZIP新UNIXヘッダに対応しました。
<hamigaki/iostreams/device/raw_zip_file.hpp>


さて、多くのアーカイバは圧縮イメージの前にヘッダを持っていて、そこにはファイル名や元のファイルサイズ、圧縮イメージのサイズを記録しています。
この構造は読み出す際には都合がいいのですが、書き込みの際は一旦圧縮イメージを書き出した後、ヘッダの位置にシークしてサイズを書き込む必要があります。
ZIPではシークできないデバイスも考慮し、これらの情報を圧縮イメージの後ろに書き込む(data descriptor)オプションが用意されています。
Javajava.util.zipパッケージがこのオプションに対応していたので、これを使ってテスト用の書庫を作成しました。

import java.io.FileOutputStream;
import java.util.zip.*;

public class ZipTest
{
    public static void main(String[] args) throws Exception
    {
        ZipOutputStream zip = new ZipOutputStream(new FileOutputStream("java.zip"));
        zip.putNextEntry(new ZipEntry("abc.txt"));

        byte[] data = new byte[3];
        data[0] = (byte)0x61; // 'a'
        data[1] = (byte)0x62; // 'b'
        data[2] = (byte)0x63; // 'c'
        zip.write(data, 0, 3);
        zip.closeEntry();
        zip.close();
    }
}

サンプル書庫は用意できたものの、zip_file_sourceでの対応はかなり面倒そうです。
ZIPで使われているdeflate圧縮アルゴリズムはそれ自体で(ストリームの終端とは別に)終端を検知できます。
だからこそ、このようなオプションがあるわけで、無圧縮の場合はこのオプションは使えないようになっています。
同様に、生の圧縮イメージを扱うraw_zip_file_sourceは、deflateの終端を検知できません。


また、zlib_decompressorが終端を検知した場合、Sourceから読みすぎてしまったデータをどうするかという問題があります。
読みすぎた分をシークで巻き戻すとなると本末転倒な気がします。
一応、読みすぎたデータはunconsumed_input()で取得できるようです。
フィルタのclose()の際にこのデータをpush_back()できれば綺麗に実装できるのですが、そういった仕組みもありませんし、適当に裏口を作るしかないかもしれません。