zip data descriptor
raw_zip_file.hppをコミットし忘れていたので差分が見れないんですが、拡張タイムスタンプヘッダとInfo-ZIP新UNIXヘッダに対応しました。
<hamigaki/iostreams/device/raw_zip_file.hpp>
さて、多くのアーカイバは圧縮イメージの前にヘッダを持っていて、そこにはファイル名や元のファイルサイズ、圧縮イメージのサイズを記録しています。
この構造は読み出す際には都合がいいのですが、書き込みの際は一旦圧縮イメージを書き出した後、ヘッダの位置にシークしてサイズを書き込む必要があります。
ZIPではシークできないデバイスも考慮し、これらの情報を圧縮イメージの後ろに書き込む(data descriptor)オプションが用意されています。
Javaのjava.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()できれば綺麗に実装できるのですが、そういった仕組みもありませんし、適当に裏口を作るしかないかもしれません。