無圧縮zipを作ってみる(2)

アーカイブデータに関する定義(中央ディレクトリ)は、アーカイブデータの数だけファイル内に存在します。中央ディレクトリのヘッダ内容は下記の構造に加え、ファイル名、拡張データ、コメントの可変長データが続きます。
struct CentralDirHeader
{
unsigned int signature;
unsigned short madever;
unsigned short needver;
unsigned short option;
unsigned short comptype;
unsigned short filetime;
unsigned short filedate;
unsigned int crc32;
unsigned int compsize;
unsigned int uncompsize;
unsigned short fnamelen;
unsigned short extralen;
unsigned short commentlen;
unsigned short disknum;
unsigned short inattr;
unsigned int outattr;
unsigned int headerpos;
};
signatureでは、0x04034B50(KB0304)を指定します。
madeverでは、zipファイルを作成する際に利用したフォーマットのバージョンを指定します。今回はVer 1.0をあらわす「10」を代入します。
needver,option,comptype,filetime,crc32,filedate,compsize,uncompsize,fnamelen,extralenは、ZipHeaderで宣言されている同名の変数と同じ意味なので、参照先となるアーカイブデータと同じ値を使用します。全く同じデータがひとつのzipファイルに繰り返して格納されることになりますが、これは過去のzipフォーマットとの互換性を維持するためなので、アーカイブデータで宣言されているデータとは違うものを入れてしまわないようにしましょう。
commentlenでは、アーカイブデータにたいするコメントのサイズを指定します。コメントがない場合は0になります。
disknumでは、ファイルの始まるディスクの番号を指定することになりますが、0でも特に問題はありません。
inattrでは、アーカイブデータの属性を指定します。0x0ならバイナリデータ、0x1ならテキストデータとなり、アーカイバによっては、テキストデータ属性のデータは、展開時に改行コードなどを修正することもあります。
outattrでは、オリジナルのファイルが持っていたファイル属性を指定します。これはOSによって値が変わってきますが、ウィンドウズならばGetFileAttributes()で取得した値を格納することになります(たとえばファイルが隠し属性ならFILE_ATTRIBUTE_HIDDEN=2となります)。
headerposには対応するアーカイブデータの始まるファイル位置(ヘッダの先頭)を入力します。
zipファイルの最後には、上記で解説した中央ディレクトリ全体に関するデータを格納します。
struct EndCentDirHeader
{
unsigned int signature;
unsigned short disknum;
unsigned short startdisknum;
unsigned short diskdirentry;
unsigned short direntry;
unsigned int dirsize;
unsigned int startpos;
unsigned short commentlen;
};
signatureでは、0x06054B50(KB0506)を指定します。
disknum,startdisknumには中央ディレクトリに関するディスク番号をいれますが、これらは0で問題ありません。
diskdirentry,direntryにはそれぞれ、ファイルに存在するアーカイブデータの総数を代入します。
dirsizeには、中央ディレクトリ(KB0304)のすべてのヘッダを含めたサイズを指定します。
startposには始めの中央ディレクトリが置かれている場所を指定します。たとえばKB0304グループが500バイト目から始まるのであれば、startposには500が入ります。
commentlenにはこのヘッダに続くzipファイル自体に対するコメントのサイズを入力します。コメントがない場合は0になります。
以上を踏まえ、Windows標準のzipアーカイバで開くことのできる無圧縮zipファイルを生成するプログラムを作ってみましょう。
構造体をそのまま保存すると、変なデータが紛れ込むこともあるので、構造体からファイルに出力する際はfwrite(&header,...)のようにはせず、個別に変数を保存していくようにしましょう。

CRC32を生成したり、構造体に関する処理のヘッダやソースファイルを含めたプロジェクトファイルはこちらのリンクよりダウンロードできます。