前説
これまでcisoやdaxcrといった、PSP用のseekable compressorの再実装を行ってきた。次に着手しようと考えたのはRAZF/BGZFである。
RAZF/BGZFはバイオインフォマティクスのsamtoolsで使われる圧縮フォーマットであり、gzip拡張である。学術であることから、cisoやdaxcrよりも広く使われているだろうと想像できる。また、広く使われているgzipで展開できることも特徴である。
なお、これらの圧縮フォーマットは、実際には、PSP/バイオインフォマティクスにかぎらず、 general purposeである ことに留意されたい。
BGZF
BGZFの構造は容易である。各ブロックは独立したgzipであり、エクストラフィールドとして"\0BC\x02\0"+(ブロックサイズ-1、リトルエンディアン)を記録すればよい。この数値は65535以下でなければならない。ヘッダは18バイト、フッタは8バイトであるから、圧縮後のサイズが65510以下であれば良い。
RAZF
BGZFをランダムアクセスするには、ブロックの開始位置をgzipフィールドによらずに知る必要がある。RAZFは(cisoと同様)ファイルの一部分(今回はフッタ)を見ればブロックの開始位置を知ることができる。
RAZFはgzipのエクストラフィールドとして"RAZF\x01\x80\x00"を持つ。この0x8000はブロックサイズを示す。
オフセットの指定方法は少々トリッキーである。最初のブロック(-1ブロック)はヘッダ終了位置なので書かれておらず、次のブロック(0ブロック)以降は、大区切り( (1LLU << 32)/block_size )ごとに8バイト絶対オフセット、小区切りごとに大区切りからの4バイト相対オフセットを記録する(この部分、仕様書がなかったのでソースから読み取る必要があり辛かった)。
また、gzipで展開できるよう、deflate(Z_FINISH)ではなくdeflate(Z_FULL_FLUSH)を用いている特徴がある。7-zip/zopfliは仕様上Z_FULL_FLUSHを指定できないので、Z_FINISHから変換する処理が必要となる。変換する必要があるのは、deflateブロックの最終ブロックの最終フラグ解除、および再ブロックの継続である。
今回は、Z_FINISHなブロックを一旦展開しなおし、この2つのオフセットを取得することに成功した(7razf_testdecode.c)。
入手
余談
オプションパーサはpoptを使用。非コピーレフトで、かつgetoptぐらい強力。最近開発が止まっているようなので適当に直した。
(getopt使った結果ファイルごとにライセンスが分断されたソフト、いくつも見てるので)