この頁では、HTTP内容コーディングに使用される“gzip”というデータ圧縮手法について、RFC1952を読みながら解説します。
まずは、RFC 2616のsection 3.5をご覧下さい。
内容コーディング値は、エンティティに適用されている、もしくは適用できるエンコーディング変換を示す。 内容コーディングは、文書をその根本的なメディアタイプのアイデンティティを失ったり、情報の欠落する事が無いように、圧縮したり、他の有用な変換が行われる事を許可するために、主に使用される。 しばしば、エンティティはコード化された形態で保存され、直接転送され、受け取り側によってのみデコードされる。
content-coding = token(中略)
- gzip
RFC 1952 に記述されているファイル圧縮プログラム "gzip" (GNU zip) によって作られるエンコーディングフォーマット。 このフォーマットは32 bit CRC 付きの Lempel-Ziv コーディング (LZ77) である。
section 3.5は、内容コーディングについて述べたものです。 この内容コーディングというものは、転送されるデータ量を圧縮する事によってデータ帯域幅を節約するために利用されます。
(※) section 3.6の転送コーディングとの違いに注意して下さい。 転送コーディングというのは、転送される部分データに対してコーディングを行うというものです。 データを圧縮するような性質は持っていません。
そして、この内容コーディングによく使われる圧縮方式にgzipというものがあります。 gzipのフォーマットは、RFC 1952にて記述されています。
この仕様書の目的は、以下のような可逆圧縮データフォーマットを定義する事である:
- CPU タイプ、OS、ファイルシステム及び文字セットに依存しないので、(異なるプラットフォーム間での) やりとりのために使用する事ができる;
- 優先的に限られた量の中間記憶装置を使用して、別のデータストリームを作り出すために (任意にアクセス可能なファイルに対するものとしての) データストリームを圧縮/展開する事ができるので、データ通信や Unix フィルタのような類似した構造の中で使用する事ができる;
- 現在利用可能な汎用の圧縮方法のうち最良のものと同等に、また特に "compress" プログラムよりもかなり優れた効率でデータを圧縮する;
- 特許によって保護されていない方法で容易に実装する事ができるので、自由に実行する事ができる;
- 現在広く使用されている gzip ユーティリィティによって生成されたファイルフォーマットと互換性を持つので、対応している展開器{decompressor} は、既存の gzip 圧縮器{compressor} によって生成されたデータを読み込む事ができるだろう。
gzipでは、圧縮アルゴリズムにDEFLATEというものを想定していますが、それ以外のアルゴリズムを使用することもできます。 DEFLATEの場合、テキストファイルにgzip圧縮を行ったとすると、およそ1/3〜1/4程度のファイルサイズにすることができ、その分転送量を減らすことができます。
(※) ただし、現在使用されているgzipの圧縮アルゴリズムのほとんどは、DEFLATEを使用しています。 DEFLATEのアルゴリズムは、RFC 1951にて規定されています。
gzip のフォーマットについては、RFC 1952 の section 2 に記述されています。 なお、以下の図の読み方については section 2.1 をご覧下さい。
以下の図において、このような箱:
+---+ | | <-- 縦棒は無いかもしれない +---+は、1 バイトを表し、このような箱:
+==============+ | | +==============+は、不定数のバイトを表す。
(中略)
コンピューター内では、ある数が複数バイトを占めるかもしれない。 ここで記述されたフォーマットでの多重バイト数は全て、最も大きくないバイトを最初に (より低いメモリアドレスにて) 格納される。 例えば、10 進数 520 は以下のように格納される:
0 1 +--------+--------+ |00001000|00000010| +--------+--------+ ^ ^ | | | + より大きなバイト = 2 x 256 + 大きくないバイト = 8
上にある通り、gzip 仕様書内では、データはいわゆるリトルエンディアンで扱われている事に注意して下さい。
gzip ファイルの全体の構造は以下のようになっています。
各メンバーは以下の構造を持っている:
+---+---+---+---+---+---+---+---+---+---+ |ID1|ID2|CM |FLG| MTIME |XFL|OS | (more-->) +---+---+---+---+---+---+---+---+---+---+(FLG.FEXTRA がセットされている場合)
+---+---+====================================+ | XLEN |...XLEN バイトの "追加フィールド"...| (more-->) +---+---+====================================+(FLG.FNAME がセットされている場合)
+=========================================+ |...0で区切られるオリジナルのファイル名...| (more-->) +=========================================+(FLG.FCOMMENT がセットされている場合)
+===================================+ |...0で区切られるファイルコメント...| (more-->) +===================================+(FLG.FHCRC がセットされている場合)
+---+---+ | CRC16 | +---+---+ +========================+ |...圧縮されたブロック...| (more-->) +========================+ 0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ | CRC32 | ISIZE | +---+---+---+---+---+---+---+---+
- ID1 (IDentification 1)
- ID2 (IDentification 2)
これらは ID1 = 31 (0x1f, \037), ID2 = 139 (0x8b, \213) という固定値を持っており、そのファイルが gzip フォーマットであるという事を示すものである。
- CM (Compression Method)
これはファイル中に使用される圧縮手法を示す。 CM = 0-7 は予約されている。 CM = 8 は "deflate" 圧縮手法を意味し、これは慣例上 gzip によって使用されまたこの他の所でも記述される。
この領域は、拡張性を持たせるために用意されたものですが、実質的に 0x08
で固定されていると考えてよいでしょう。
- FLG (FLaGs)
このフラグバイトは以下のように各ビットに分けられる:
- bit 0 FTEXT
- bit 1 FHCRC
- bit 2 FEXTRA
- bit 3 FNAME
- bit 4 FCOMMENT
- bit 5 予約済み
- bit 6 予約済み
- bit 7 予約済み
FTEXT がセットされている場合、ファイルはおそらく ASCII テキストである。 これはオプショナルな指示子であり、圧縮者が非-ASCII 文字があるかどうかを見るための小さな量の入力データをチェックする事によってセットする事ができる。 疑わしい場合は、FTEXT はクリアされ、バイナリデータである事を示す。 (中略)
FHCRC がセットされている場合、圧縮されたデータの直前に、gzip ヘッダについての CRC16 が存在する。 CRC16 は、それまでの gzip ヘッダの全てのバイトを含み、CRC16 を含まないものの CRC32 の下位 2 バイトから成る。 (中略)
FEXTRA がセットされている場合、以下の節に記述されるような、オプショナルな追加フィールドが存在する。
FNAME がセットされている場合、0 というバイトによって終わる、オリジナルのファイル名が存在する。 この名前は ISO 8859-1 (LATIN-1) 文字で構成されていなければならない; すなわち、ファイル名に EBCDIC や他の文字セットを使用している OS 上では、ISO LATIN-1 文字セットに変換されなければならない。 これは、あらゆる構成ディレクトリ部分が削除された、圧縮されているファイルのオリジナル名であり、また圧縮されているファイルが大文字小文字を区別しないファイルシステム上にある場合、強制的に小文字にする。 そのデータが名前を持つファイル以外のソースから圧縮された場合はオリジナルのファイル名はない; すなわち、例えば、そのソースが Unix システム上の標準入力だった場合は、ファイル名はない。
FCOMMENT がセットされている場合、0 で終了するファイルコメントが存在する。 このコメントは解釈されない; すなわち、これは単に人間によって使われるものという意図のものである。 コメントはISO 8859-1 (LATIN-1) 文字で構成されていなければならない。 改行は、単一の LF 文字 (10 進数の 10) によって示されるべきである。
予約済み FLG ビットはゼロでなければならない。
ファイルデータがテキストの場合、圧縮器はビット 0 を立てる事ができます。 (立てなくてもかまいません。)
ビット 1 が立っている場合、圧縮データの直前に gzip のヘッダについての CRC16 があります。
ビット 2 が立っている場合、section 2.3.1.1 にあるような追加フィールドが付加されます。
圧縮データにファイル名を持たせる場合、圧縮器はビット 3 を立てる事ができます。
「ファイル名 + 0x00
」として格納します。
また、ビット 4 を立てる事で、圧縮器はコメントを埋め込む事ができます。
「コメント名 + 0x00
」として格納します。
ビット 5 〜 7 は常に 0 でなければなりません。 このビットが立っているような場合は、エラーとして扱われるべきでしょう。
- MTIME (Modification TIME)
これは、圧縮されているオリジナルファイルの最新更新時刻を与える。 この時刻は Unix フォーマット、すなわち 1970 年 1 月 1 日 00:00:00 GMT 以来の秒で与えられる。 (これは国際時間ではなくローカルを使うような、MS-DOS や他のシステムにおいて問題を引き起こすかもしれない事に注意せよ。) 圧縮されたデータがファイルから来るものではなかった場合、MTIME は圧縮を開始した時刻にセットされる。 MTIME = 0 は、タイムスタンプが利用できない事を意味する。
圧縮されているファイルのエポック秒 (1970 年 1 月 1 日 00:00:00 GMT 以来の秒) を、16 進のリトルエンディアンで 4 バイトで格納します。
- XFL (eXtra FLags)
これらのフラグは特定の圧縮方法による使用が利用可能である事を意味する。 "deflate" という方法 (CM=8) では、以下のようなフラグをセットする:
- XFL = 2 - 圧縮器は、最も遅いが、最大の圧縮効率のアルゴリズムを使用した
- XFL = 4 - 圧縮器は、最速のアルゴリゴリズムを使用した
例えば、gzip -9 file
として圧縮した場合は 0x02
、また gzip -1 file
としたなら 0x04
とします。
それ以外の場合は 0x00
となります。
- OS (Operating System)
これは、圧縮がなされたファイルシステムのタイプを識別する。 これは、テキストファイルにおける行末の約束を決めるために有用かもしれない。 現在定義されている値は以下の通りである:
- 0 - FAT filesystem (MS-DOS, OS/2, NT/Win32)
- 1 - Amiga
- 2 - VMS (or OpenVMS)
- 3 - Unix
- 4 - VM/CMS
- 5 - Atari TOS
- 6 - HPFS filesystem (OS/2, NT)
- 7 - Macintosh
- 8 - Z-System
- 9 - CP/M
- 10 - TOPS-20
- 11 - NTFS filesystem (NT)
- 12 - QDOS
- 13 - Acorn RISCOS
- 255 - unknown
改行コードは OS によって異なりますので、適切な OS コードを入れるべきですが、よくわからなければ 0xFF
と指定しても問題はないと思われます。
FLG
の第 3 フラグを立てた場合、ここで「ファイル名 + 0x00
」という文字列が続きます。
そして、圧縮されたデータが入ります。
deflate というアルゴリズムで圧縮されたものは、CM = 0x08
となります。
- CRC32 (CRC-32)
これは、ISO 3309 標準及び ITU-T 勧告 V.42 の section 8.1.1.6.2 中で使用される CRC-32 アルゴリズムによって計算される圧縮されていないデータの巡回冗長検査値を含んでいる。 (規定される ISO 文書については http://www.iso.ch を、ITU-T V.42のオンラインバージョンについては gopher://info.itu.ch をそれぞれ参照の事。)
CRC とは、データのビット列を多項式とみなし、生成多項式を基に所定の手順によって CRC 符号を計算する事で、連続したビットの誤り (バースト誤り) の検出が可能な誤り検出方式の事です。 この計算のための C で書かれたコードが、section 8 にあります。
- ISIZE (Input SIZE)
これはオリジナルの (圧縮されていない) 入力データの 2^32 で割った余りを含む。
圧縮前のデータ長の mod(2^32) を、やはり16 進のリトルエンディアンで 4 バイトで格納します。