bag 書庫形式

wotsit.org にあった "BAG ARCHIVE FILE FORMAT V1.1" の適当訳。はてなでは行頭に '-' や '*' が置けないので、ちょっとだけフォーマットを変えている。
シンプルなのは確かだが、圧縮周りはちょっと微妙。圧縮専用にフィールド用意した方がいいよなぁ。LZW に依存した圧縮方法が多いし、LZHF と LZAR の括弧内が逆になっていたりもする。

bag 書庫ファイルフォーマット V1.1
by Jeff Connelly

bag 書庫の第一の目標は、多数のファイルをひとつにまとめるための
シンプルで効率的な方法を提供することです。このことから、
非常にシンプルなものになっています。

ヘッダがファイル先頭に置かれます。
オフセット          個数 型     説明
0000h                  3 char   ID='BAG'
0003h                  2 char   バージョン、ID='11'

ファイルごとに 1 つ、以下のようなファイルブロックが置かれます。
オフセット          個数 型     説明
0000h                  1 dword  ファイルの長さ (単位はバイト)
0004h                  1 byte   ファイル名の長さ
????h                  ? char   ファイル名
????h                  ? char   ファイル内容

ファイルの一番最後には以下の内容がきます。
オフセット          個数 型     説明
0000h                  1 char   EOF マーカ, ID=1A

ファイルの長さが 0 になっているファイルブロックは、説明として使われる
特殊なファイルを示します。ディレクトリもファイル名フィールドに格納されます。
    Filename='> dirname' の場合、カレントディレクトリを 'dirname' に変更します。
例えば、
Filename='> JEFF'
Filename='> COMPUTER'
Filename='> BAG'
という場合なら、ディレクトリ JEFF\COMPUTER\BAG が作成されることになります。
ファイルはカレントディレクトリに配置されます。

ファイル内容は、必ずしも元のデータそのままではなく、圧縮することができます。
4 文字のシグネチャで圧縮方法を示します。
 ---- 圧縮方法 ----
 LZW     LZW 符号化 (末尾に空白がつく点に注意)
 RLEn    RLE 法 N (1〜4) 符号化
 HUFF    ハフマン符号化
 LZHF    LZHUF 符号化 (LZSS + Arithmetic) (注意 - LZHUF の作者は
         商用利用を認めていません)
 LZAR    LZARI 符号化 (LZSS + ハフマン)
 WCOD    単語符号化 -- テキストのみ
 シグネチャがなければ、元のデータそのままだとみなされます。

単語符号化の圧縮方法については、以下の通りとします。
 * 辞書を初期化する (最大サイズ FFFF)
 * ファイル終端 (EOF) まで繰り返す
   * 入力ストリームから、空白で区切られた単語をひとつ読み込む
   * 辞書から単語を探す
     * 見つからなかった場合は、空いている最初の位置にその単語を追加し、
       辞書へ追加した位置を 16 ビット整数として出力する。
     * 見つかった場合は、その位置を 16 ビット整数として出力する。
 * ファイル終端に辞書を書き込む。各単語は NULL 終端とし、辞書全体は
   二重 NULL 終端とする。
これにより、各単語が 2 バイトで符号化されることになります。

最後の文字はファイル終端 (EOF) 文字で、これを見れば、bag アーカイブを
転送した際にファイル全体を受け取れたか確認することができます。