[前へ] [目次]

## 圧縮ファイルの形式

この章では、`ebzip` が扱っている圧縮ファイル形式の詳細について説 明します。

### 圧縮ファイル形式の概要

圧縮ファイル形式は次のような特徴を持っています。

- CPU の種類、オペレーティングシステム、ファイルシステムに依存しません。
- 非損失圧縮です。
  圧縮ファイルを伸長することによって、元のファイルを復元できます。
- 6 つの圧縮レベルがあります。
  伸長の速さか圧縮率の良さの、いずれかを選ぶことができます。

圧縮されたファイルは、ヘッダ部、インデックス部、およびデータ部から構成 され、この順でファイルに配置されます。

>     +--------+-------------+-----------------------------+
>     | ヘッダ |インデックス |          データ             |
>     +--------+-------------+-----------------------------+
>                                                          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 バイト)`
  0x45, 0x42, 0x5a, 0x69, 0x70 (ASCII 文字列で表すと `EBZip`) という固定した値を持ちます。
`zip モード (MSB 側の 4 ビット)`
  圧縮モードを表します。 元の (非圧縮時の) ファイルの大きさが 4294967295 バイト (= 4Gバイト) 以内のときは 1 (2 進数で 0001)、それより大きいときは 2 (2 進数で 0002) をセットします。

  ファイルの大きさで値が変わるのは、歴史的な事情によります。 以前の EB Library は圧縮モード 1 しか既定しておらず、また 4GB バイト を超えるファイルを扱えませんでした。 4G バイトを超えるファイルを扱えるように EB Library を改良した際に、 「4G バイトを超えたら、圧縮モードは 2 にセットする」というルールを 新たに設けました。 これにより、以前の EB Library で 4GB バイトを超えたファイルを扱おう とすると、非対応の圧縮モードとみなされ、エラーが発生するようになって います。

`圧縮レベル (LSB 側の 4 ビット)`
  圧縮レベルを表します。
`予約領域 (2 バイト)`
  予約されていますが、使われていません。 0x0000 で埋められます。
`ファイルの大きさ (6 バイト)`
  元の (非圧縮時の) ファイルの大きさを記録しています。
`Adler-32 (4 バイト)`
  RFC 1950 に記されている Adler-32 というアルゴリズムを用いて計算した、 非圧縮データのチェックサムの値です。
`修正時刻 (4 バイト)`
  元のファイルの最終修正時刻です。 グリニッジ標準時の 1970 年 1 月 1 日 0 時 0 分 0 秒からの経過秒数で 表します。

`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) が先に来た形で記録されます。

[前へ] [目次]