BZIP2 ファイル形式
bzip2 で圧縮されたデータ。Burrows-Wheeler ブロックソート法を使います。
- MIME タイプ
- application/x-bzip2
- 拡張子
- .bz2
- カテゴリ
- アーカイブ・圧縮
マジックナンバー(ファイル署名)
| 0x00000000 | 425A68 | BZh | 'BZh' header |
BZIP2 形式について
bzip2 は Burrows-Wheeler 変換を使い、gzip より圧縮率は高いものの速度は落ちます。Unix のソース tarball でよく見かけます。ヘッダは BZh に続いてブロックサイズを表す 1 桁の数字です。その 4 バイトから先、ファイルはバイト単位であることをやめます。ブロック、ハフマンテーブル、符号化されたシンボルが位置合わせなしに 1 ビットずつ詰め込まれるからです。バイト境界から始まるのは最初のブロックだけで、hex エディタで bzip2 ファイルの先頭は見えても途中は見えないのはそのためです。その代償として得られるのが、各ブロックが独立していることです。おかげで破損は封じ込められ、復旧も現実的にできます。
ヘッダーの構造(バイト単位)
| オフセット | 長さ | フィールド | 意味 |
|---|---|---|---|
| 0 | 2 | 'BZ' magic | 42 5A。印字可能な文字が 2 つで、バイナリ形式としては珍しく、hex ダンプに BZh が読めるテキストとして現れるのはそのためです。 |
| 2 | 1 | Version byte | h(0x68)で、ハフマン符号を表します。0.9.0 以降このツールが出力した唯一のバージョンで、デコーダもこれ以外を受け付けません。つまり見慣れた 3 バイトの接頭辞は、マジック単体ではなくマジックとバージョンの組です。 |
| 3 | 1 | Block-size digit | 1 から 9 の ASCII 数字で、ブロックサイズを 100 kB 単位で表します。9 は 0x39 で 900 kB、これが既定値です。圧縮時、そしてより重要なことに展開時のメモリ使用量を決めるので、書き手が一度選べば、すべての読み手がそれに従わなければなりません。 |
| 4 | 6 | First block magic | 31 41 59 26 53 59、円周率の桁をパック 10 進数で並べたものです。バイト境界に載るのはここ、つまり最初のブロックの先頭だけです。以降のブロックにある同じ値は、前のブロックがたまたま終わったビット位置に置かれます。 |
| 10 | 4 | Block CRC-32 | このブロックの非圧縮データのチェックサムで、これもバイト境界に載るのは最初のブロックだけです。部分的な復旧が意味を持つのはブロックごとのチェックサムのおかげで、どのブロックが壊れたかを正確に言い当てられます。 |
| 14 | variable | Randomised flag and BWT origin pointer | 廃止された 1 ビットのフラグ(今世紀に書かれたものでは常に 0)に続いて、元の順序を復元する Burrows-Wheeler 行列の行を指す 24 ビットのポインタが入ります。ここから先はバイト境界がまったくありません。シンボルマップ、ハフマンテーブル、セレクタ、符号化データが連続したビットストリームになります。 |
| variable | 6 | End-of-stream magic | 17 72 45 38 50 90、円周率の平方根の桁で、これ以上ブロックが続かないことを示します。位置はファイルの終わり近くですが、ビットオフセットは手前のすべてによって決まるので、末尾からの距離は固定ではありません。 |
| variable | 4 | Combined CRC-32 | 全ブロックの CRC を順に組み合わせた値で、終端マジックの直後に置かれ、その後ろにファイルがバイト境界で終わるよう 0〜7 ビットのパディングが付きます。bzip2 が持つ唯一のファイル全体の整合性値です。 |
似た形式との見分け方
| 紛らわしい形式 | 見分け方 |
|---|---|
| GZIP | BZh に数字が続く形と 1F 8B です。スクリプトの中での使われ方は同一で拡張子も絶えず取り違えられますが、共有しているものは他に何もありません。gzip は deflate ストリームの上に載ったバイト境界のヘッダ、bzip2 はブロックごとのチェックサムを持つビットストリームの上に載った 4 バイトのヘッダです。 |
| 7-Zip | こちらは逆向きの誤検出が待ち構えています。7-Zip 自身のマジックは 37 7A で始まり、7z と読めます。そして 7z アーカイブは内部の圧縮方式として bzip2 を使えるので、.7z ファイルの中に BZh の文字列が現れます。決めるのはオフセット 0 だけで、.7z はそこが 37 7A BC AF 27 1C です。 |
| ZIP | ZIP の圧縮方式 12 は bzip2 なので、ZIP エントリのデータがローカルファイルヘッダと可変長フィールドの直後に BZh から始まることがあります。ファイルの中から BZh を探して .bz2 だと結論づけるのは、オフセット 0 が 50 4B 03 04 である限り常に誤りです。 |
| XZ | 大半のソース配布でこれを置き換えた形式です。XZ は FD 37 7A 58 5A 00 で始まり、より高い圧縮率に届きます。bzip2 に残った優位は、ブロックが独立していることです。xz のブロックは既定では独立していません。 |
| pbzip2/lbzip2 | 並列圧縮ツールは、完結した独立の bzip2 ストリームを連結して出力します。したがって BZh がファイルの中にバイト境界の位置で繰り返し現れ、円周率のブロックマジックはストリームごとに 1 回ずつ出てきます。できあがるものは通常の展開器が最後まで読める合法な .bz2 のままです。 |
よくある壊れ方
- 途中切れ。切れた位置より手前の完全なブロックはすべてデコードできます。ブロックが互いに依存していないからです。bzip2recover が突いているのがまさにそこで、円周率のブロックマジックごとにビットストリームを切り分け、各ブロックをそれぞれ小さな .bz2 として書き出します。壊れたアーカイブから、1 ブロック分を除く全データが戻ってきます。
- ブロック内部のビット反転。ブロックはハフマン符号化されているので、破損はたいてい終端に着く前にデコードを脱線させます。チェックサム不一致ではなくデータエラーです。デコードが終端まで到達した場合は、オフセット 10 のブロックごとの CRC が捕まえ、どのブロックが失敗したかを名指しします。
- テキストモード転送。ビットストリーム内の改行変換は、壊れたバイトより後ろすべてを 8 ビットずらすので、4 バイトのヘッダは無傷でファイルも正しく認識されるのに、デコードはほぼ即座に失敗します。
- ブロックサイズの数字を手で書き換えた場合。9 を 1 に変えても、どの検出器から見てもまだ bzip2 に見えるファイルが残り、最初のブロックで失敗します。展開器はその 1 バイトからバッファサイズを決めるからです。
- 連結ストリームが途中で切れた場合。並列圧縮したアーカイブは 1 ファイルの中に複数のストリームが入っているので、末尾を失っても最後のストリームだけが失われ、手前のものはきれいに展開できます。途中までダウンロードした pbzip2 のファイルから中身の大半が取り出せることが多いのは、そのためです。
この形式の現在地
bzip2 の時代はおおよそ 1999 年から 2010 年で、ソース tarball を gzip から一段上げるなら当然の選択でした。インターネット上に保管されたソフトウェアの相当な量が今も .tar.bz2 で、それだけでデコーダは永遠に配られ続けます。新規の用途では両側から挟まれています。xz は同等かそれ以上の展開速度で目に見えて小さくなり、Zstandard は gzip 並みの圧縮率をはるかに速い圧縮で出すので、ディストリビューションは何年も前に離れました。上流の勢いもありません。オリジナルの実装は 10 年ほど事実上メンテナンスされていませんでした。それでも擁護できるのはブロック構造です。ブロックが独立しているので pbzip2 で圧縮を簡単に並列化できますし、よくある Unix の圧縮ツールの中では唯一、壊れたアーカイブを最初の不良バイトで諦めるのではなくブロック単位で救い出せます。
BZIP2 ファイルをこのサイトで開く
どれもブラウザ内で動きます。ファイルが端末から出ることはありません。
関連する形式
BZIP2 と混同しやすい形式です。先頭バイトを見比べてください。