2010/03/20
KAICHO: s_naray[at]yahoo[dot]co[dot]jp
※SPAM防止のため捻ってある

xp3ファイルの構造

■はじめに

探してみたのだがどこにも転がってなかったので、吉里吉里の吐き出す xp3 ファイルの ファイル構造を以下に書き下す。2.30 になってからちょっとヘッダ構造が変わって しまったために、今までのツール(xp3dec.exeとか)だと展開できなくなって しまっている。のだが、大きく変わったワケではないので、まぁそのアレだ、 ちょいちょい、とすれば対応できる。 ちなみに、ソースコードはここいらへんを見ると良い。

なんでこんなこと調べたのかというと、自分が過去作ったゲームのバックアップ データを飛ばしてしまい、どうしてもxp3ファイルから元データを引っ張り出す 必要に迫られたため。吉里吉里/KAGにデフォルトでそういうツールがついてない 理由は理解しているつもり。

●ファイル構造概要

吉里吉里のデータファイル xp3 は、大きく以下の三つのセクションに分けられる。
  1. XP3ヘッダ部
  2. データ部
  3. ファイル管理部
それぞれ、非常にシンプルな構造になっているため、ちょっとソースコード見れば よく分かると思う。のであるが、何度もソースコード見直すの面倒だから、 自分のためにココに書いておく所存ナリ。

ちなみに、「サイズ」などの数値データは、 全てリトルエンディアンで格納されていることに注意。

●XP3ヘッダ部

XP3ヘッダ部は、吉里吉里2.28までと、吉里吉里2.30とで異なる。具体的には、 間に「クッション」なんてものが挿入されている。なんでこう変えてしまったのかは 不明。とりあえず、ファイル先頭から12byte目からが 17 00 00 00 00 00 00 00 かどうか、くらいで区別できるが、そんな安直なのでイイんだろうか。 ヤバそうなら教えてください。

吉里吉里2.28まで 吉里吉里2.30から
セクション名 データ名byteデータ例(16進数)備考 セクション名 データ名byteデータ例(16進数)備考
XP3ヘッダ XP3ヘッダ1858 50 33 0d 0a 20 0a 1a固定値 ←同じ
XP3ヘッダ238b 67 01固定値 ←同じ
なし クッション クッションインデックス817 00 00 00 00 00 00 00固定値
なし ヘッダマイナーバージョン401 00 00 00 今は固定値
なし クッションヘッダ180固定値
なし インデックスサイズ800 00 00 00 00 00 00 00今は0固定
ファイル管理部のインデックス8-後述のファイル管理部が存在するXP3ファイル上の位置 ←同じ

●データ部

データ部は本当にデータの羅列しか入っていない。 どこからどこまで格納されているかは、 後述のファイル管理部に格納されているので、ここでは説明を割愛する。

●ファイル管理部

ファイル管理部は、吉里吉里2.28と2.30とで共通。 ファイル情報の配列となっている。ただし、一管理部に対し、 一つ28byteのセグメントが不定数存在するため、 配列の要素サイズは一定ではないことに 注意。また、一部が圧縮されている場合があることにも注意。 圧縮にはzlibが使われており、単純にzlibのuncompress()関数で展開できる。

ファイル管理部の並びを以下に示す。

  1. ファイル管理部ヘッダ(1つ)
  2. ファイル管理部 xN(この中それぞれにセグメント管理部が複数存在する)

ファイル管理部ヘッダ
データ名byteデータ例(16進数)備考
圧縮フラグ1-0 = 管理部非圧縮
1 = 管理部圧縮
圧縮管理部サイズ8-管理部非圧縮の場合は存在しない
管理部サイズ8-圧縮されていた場合は、展開後のサイズ
ここにファイル管理部の配列が入る(圧縮時は管理部配列をzlib圧縮したデータ)

ファイル管理部(一つ)
セクション名 データ名byteデータ例(16進数)備考
File 管理部ヘッダ4文字列"File"固定値
この管理部のサイズ8-これ以降のデータサイズであり、"File"と「この管理部のサイズ」自身は含まない
Info infoヘッダ4文字列"info"固定値
infoサイズ8-4+8+8+2+ファイル名長*2、すなわち、これ以降次のSegmentまでのバイト数
フラグ4-0 = プロテクトなし
1<<31 = プロテクトあり
「プロテクト」とは「このデータ展開しないで欲しいなぁ」というフラグであり、 実際にデータに何か細工がしてあるわけではない。紳士協定というヤツ。 ここいらへんに書いてある
展開後のファイルサイズ8--
格納されているファイルサイズ8--
ファイル名長2-wcharなので、/2されていることに注意(0x0bなら下のファイル名は22byte)
ファイル名ファイル名長に依存"s.y.s.t.e.m./.C.o.n.f.i.g...t.j.s."WStringになっている(末尾の'\0'は存在しない)。また、相対パスになっており、ディレクトリ名を含む。ディレクトリ区切り記号は'\'ではなく'/'であることに注意
Segment segmentヘッダ4文字列"segm"固定値
segmentサイズ8-セグメント数*28(1セグメント管理部=28byteのため)
ここにセグメント管理部がセグメント数繰り返し入る
Adler-32 Adler ID4文字列"adlr"固定値
Adler長804 00 00 00 00 00 00 00現在はAdler長は4byteと決まっているので 4 固定
Adler-324-Adler-32 チェックサム(Wikipedia参照)

「セグメント」が複数あるということは、一つのファイルを複数に分割して 格納していることを意味する。とはいえ、実際には複数に分割されることは 少ないみたい。セグメントごとに圧縮・非圧縮を指定でき、圧縮されている場合は、 データは例によってzlibで圧縮されている。

セグメント管理部(一つ) 28byte
データ名byteデータ例(16進数)備考
フラグ4-0 = 非圧縮
1 = 圧縮
オフセット8-XP3ファイル中でのデータ開始位置
オリジナルサイズ8-データの元サイズ
格納サイズ8-XP3ファイルに格納されているデータのサイズ。圧縮されている場合は元サイズより小さく、圧縮されていない場合は上の「オリジナルサイズ」と同じ

Adler-32は、簡単なチェックサム値。md5sumのようなもの。まぁ…シカトしてよし。 実際、一部のデータには存在していなかった。 最近になって後から追加されたようだ。すなわち、今後も、 管理部のセクション(チャンクとも呼ぶ)は拡張され、追加されていく可能性がある。 ファイル管理部の各セクション先頭は

  1. 4byte:ヘッダ文字列
  2. 8byte:このセクションのサイズ(先頭12byteを含まない)
  3. セクション内データ
と並んでいるので、 「1.と2.を読み込んで、知らないセクションだったらスキップする」、 という処理をした方が良いだろう。それで今後うまく動くかどうかの保証は 全くないけれど、少なくとも拡張はしやすくなる。

■そんなワケで

作ってみた。ただしcygwin 専用という、一体誰が使うんだというそんな。 我輩、Windows上のCの開発環境持ってないんでスよ。こういう表を書いて、 ツールのソースコード公開しておいたら、誰かもっとイイの作ってくんないかなー、 と期待したりしないでもない。