この章では、ebzip
が扱っている圧縮ファイル形式の詳細について説
明します。
圧縮ファイル形式は次のような特徴を持っています。
圧縮されたファイルは、ヘッダ部、インデックス部、およびデータ部から構成 され、この順でファイルに配置されます。
+--------+-------------+-----------------------------+ | ヘッダ |インデックス | データ | +--------+-------------+-----------------------------+ EOF
元のファイルは、次の行程で圧縮されます。
まず、ebzip
は元のファイルを分割します。
個々の スライス (slice) は、末尾のものを除けば、
同じ大きさになっています。
+---------------+---------------+-- --+----------+ | スライス 1 | スライス 2 | ... |スライス N| +---------------+---------------+-- --+----------+ EOF
スライス・サイズは、圧縮レベルから決まります (圧縮レベルについては 「圧縮レベル」を 参照のこと)。
圧縮レベル | スライスの大きさ |
0 | 2048 バイト |
1 | 4096 バイト |
2 | 8192 バイト |
3 | 16384 バイト |
4 | 32768 バイト |
5 | 65536 バイト |
次に、末尾のスライスがスライス・サイズよりも短かった場合、
ebzip
はスライス・サイズと同じになるまで伸ばし、伸ばした
部分に 0x00 を埋めます。
伸した部分 +---------------+---------------+-- --+---------+-----+ | スライス 1 | スライス 2 | ... | スライス N | +---------------+---------------+-- --+---------+-----+ EOF
最後に、ebzip
は個々のスライスを、RFC 1951 に記されている
DEFLATE 圧縮データ形式で圧縮します。
おのおののスライスは、他のスライスとは独立して圧縮されます。
圧縮されたスライスのビット数が 8 の倍数でなければ、1 〜 7 ビットを圧
縮されたスライスの末尾に足し、8 の倍数になるようにします。
これにより、圧縮されたそれぞれのスライスはバイトの境界から開始されます。
足されたビットの内容は未定義ですが、このビットは決して使用されません。
+------------+----------+-- --+--------------+ | 圧縮された |圧縮された| ... | 圧縮された | | スライス 1 |スライス 2| ... | スライス N | +------------+----------+-- --+--------------+
これが圧縮ファイル形式における データ部 になり、圧縮された スライスから構成されます。
末尾のスライスの伸ばした部分は、末尾のスライスの一部として圧縮され
ます。
ebunzip
が末尾のスライスを復元するときは、スライスを伸長して
から伸ばした部分を取り除くという作業を行います。
圧縮したスライスの大きさが、スライス・サイズよりも大きいか等しいときは、
ebzip
はそのスライスの圧縮データを廃棄します。
この場合、ebzip
は元のデータをそのスライスの圧縮データとして
代わりに記録します。
元のファイルが空だったときは、圧縮ファイルのデータ部はありません。
圧縮時に、ebzip
は圧縮した個々のスライスの
インデックス (index) を記録します。
個々のインデックスは、圧縮ファイルの先頭から圧縮されたスライスの先頭
までの距離を表します。
距離の単位はバイトです。
+---------+---------+-- --+---------+---------+ |インデッ |インデッ | ........... |インデッ |インデッ | |クス 1 |クス 2 | ........... |クス N |クス END | +---------+---------+-- --+---------+---------+ | | | | +---+ +----+ +------+ +-----------+ V V V V +------------------+------------------+-- --+--------------+ | 圧縮された | 圧縮された | ... | 圧縮された | | スライス 1 | スライス 2 | ... | スライス N | +------------------+------------------+-- --+--------------+
個々のインデックスは 2 〜 5 バイトの大きさを持ちます。 インデックスの大きさは、元のファイルの大きさで決まります。
元のファイルの大きさ | インデックスの大きさ |
0 〜 65535 バイト | 2 バイト |
65535 〜 16777215 バイト | 3 バイト |
16777216 〜 4294967295 バイト | 4 バイト |
4294967296 〜 1099511627775 バイト | 5 バイト |
インデックス内での、複数バイトからなる数値はすべて、値の大きい方の部分 を表すバイト (most significant byte) が先に来た形で記録されます。 たとえば、0x1234 は次のように記録されます。 最初のバイトは 0x12 となり、次のバイトは 0x34 になります。
+---------+---------+ |0001 0010|0011 0100| +---------+---------+ (0x12) (0x34)
インデックス部は、圧縮されたスライス 1 のインデックスで始まり、その後ろ に圧縮されたスライス 2 のインデックスが続きます。 圧縮されたスライス N のインデックスの後ろには、「終端」へのインデックス が置かれます。 このインデックスは、圧縮されたスライス N の末尾の次のバイトへの インデックスになります。 また、圧縮されたファイルのサイズを示すことにもなります。
+---------+---------+-- --+---------+---------+ |インデッ |インデッ | ........... |インデッ |インデッ | |クス 1 |クス 2 | ........... |クス N |クス END | +---------+---------+-- --+---------+---------+
圧縮されたスライスの大きさがスライスサイズに等しいときは、そのスライス のデータは実際には圧縮されていないことを示します。
元のファイルが空だったときは、インデックス部はインデックスを一つだけ 持ちます。 このインデックスは圧縮されたファイルの大きさを表します。
ヘッダ部は 22 バイトからなります。 次のフィールドから構成されます。
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | マジック ID |*1| *2 |ファイルの大きさ | Adler-32 | 修正時刻 | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 *1: zip モードと圧縮レベル *2: 予約領域
マジック ID (5 バイト)
zip モード (MSB 側の 4 ビット)
ファイルの大きさで値が変わるのは、歴史的な事情によります。 以前の EB Library は圧縮モード 1 しか既定しておらず、また 4GB バイト を超えるファイルを扱えませんでした。 4G バイトを超えるファイルを扱えるように EB Library を改良した際に、 「4G バイトを超えたら、圧縮モードは 2 にセットする」というルールを 新たに設けました。 これにより、以前の EB Library で 4GB バイトを超えたファイルを扱おう とすると、非対応の圧縮モードとみなされ、エラーが発生するようになって います。
圧縮レベル (LSB 側の 4 ビット)
予約領域 (2 バイト)
ファイルの大きさ (6 バイト)
Adler-32 (4 バイト)
修正時刻 (4 バイト)
zip モード
と 圧縮レベル
は、両方ともヘッダの
5 バイト目に入ります。
zip モード
は、値の最も大きい部分を表すビット
(most significant bit) を含み、圧縮レベル
は最も小さい部分を
表すビット (least significant bit) を含んでいます。
zip モード
が 1 で、圧縮レベル
が 2 なら、
ヘッダの 5 バイト目は 0x12 になります。
MSB LSB +---+---+---+---+---+---+---+---+ | 0 0 0 1 0 0 1 0 | = 0x12 +---+---+---+---+---+---+---+---+ (zip モード) | (圧縮レベル)
ヘッダ内での、複数バイトからなる数値はすべて、値の大きい方の部分 を表すバイト (most significant byte) が先に来た形で記録されます。