fuk アンパック
まず fuk のフォーマット
格納は LittleEndian
struct Fuk {
magic:u32,
fuk_version:u32,
entry_count:u32,
file_count:u32,
length:u32,
flag:u32,
entry:Vec<FukEntry>, // size entry_count
entry_info:Vec<FukEntryInfo>, // size entry_count
offsets:Vec<u32>, // size file_count
file_names:Vec<u8>, // null terminate * entry_count ANSI
}
struct FukEntry {
next_id:i32,
child_id:i32,
parent_id:i32,
name_offset:u32,
}
struct FukEntryInfo {
uncompressed_size:u32,
size:u32,
num0:u32,
}
実際のアンパック処理
entry[0]から開始
FF FF FF FF 0B 08 00 00 FF FF FF FF 00 00 00 00
child_id = 0x80B つまり子供が居るのでこの entry 自体はフォルダになる。
フォルダ名は name_offset = 0x0 なので file_names から
00
が取得される。Null 終端なのでフォルダ名は空き文字つまりルートフォルダ。
次に子供へ移行
entry[0x80B] = 0A 08 00 00 0E 08 00 00 00 00 00 00 BD BC 00 00
child_id = 0x80E, name_offset = 0xBCBD
file_names[0xBCBD] = 77 6F 72 6C 64 73 00
なので "worlds" を取得
entry[0x80E] = 0C 08 00 00 0F 08 00 00 0B 08 00 00 D3 BC 00 00
child_id = 0x80F, name_offset = 0xBCD3
file_names[0xBCD3] = 77 6F 72 6C 64 00 // "world"
entry[0x80F] = FF FF FF FF FF FF FF FF 0E 08 00 00 D9 BC 00 00
child_id = 0xFFFFFFFF(i32 なので -1), name_offset = 0xBCD9
file_names[0xBCD9] = 72 65 6E 64 65 72 70 69 70 65 2E 78 6D 6C 00 // "renderpipe.xml"
child_id = -1 つまり子供が無いのでこの entry はファイルを表す。
ここまでで path は worlds\world\renderpipe.xml になる。
ここで実際にファイルを書きだす処理
必要なのは offset, size, uncompressed_size
size と uncompressed_size は entry_info[0x80F] で取得可能
ここで問題になるのは offset で offsets にあるのだが entry_count と file_count は違う。
entry_count にはフォルダも含まれるが file_count はファイルしか含まれないため差異が生じる。
これに対応するには entry を読み込んだ時にファイルの index を振っておけばよい
let mut cnt = 0;
for ent in entry {
if ent.child_id == -1 {
ent.file_index = cnt;
cnt += 1;
}
}
3っつの値が判明したので offset へシークして size 分読み込んで path へ書き出せば良いのだが
ファイルはzlib圧縮されているものと非圧縮のものと混在しているのでそこを注意
if size != uncompressed_size {
zilb 展開後にファイル出力
} else {
そのまま出力
}
ここまでで1個のファイル出力は完了
entry[0x80F] = FF FF FF FF FF FF FF FF 0E 08 00 00 D9 BC 00 00
次に next_id = -1 つまり次が無いので親 parent_id = 0x80E に戻る
entry[0x80E] = 0C 08 00 00 0F 08 00 00 0B 08 00 00 D3 BC 00 00
next_id = 0x80C なので entry[0x80C] を処理する。
こんな感じでループしていくとすべてのファイルが展開されます。
再起で実装すると良いでしょう。
まず fuk のフォーマット
格納は LittleEndian
struct Fuk {
magic:u32,
fuk_version:u32,
entry_count:u32,
file_count:u32,
length:u32,
flag:u32,
entry:Vec<FukEntry>, // size entry_count
entry_info:Vec<FukEntryInfo>, // size entry_count
offsets:Vec<u32>, // size file_count
file_names:Vec<u8>, // null terminate * entry_count ANSI
}
struct FukEntry {
next_id:i32,
child_id:i32,
parent_id:i32,
name_offset:u32,
}
struct FukEntryInfo {
uncompressed_size:u32,
size:u32,
num0:u32,
}
実際のアンパック処理
entry[0]から開始
FF FF FF FF 0B 08 00 00 FF FF FF FF 00 00 00 00
child_id = 0x80B つまり子供が居るのでこの entry 自体はフォルダになる。
フォルダ名は name_offset = 0x0 なので file_names から
00
が取得される。Null 終端なのでフォルダ名は空き文字つまりルートフォルダ。
次に子供へ移行
entry[0x80B] = 0A 08 00 00 0E 08 00 00 00 00 00 00 BD BC 00 00
child_id = 0x80E, name_offset = 0xBCBD
file_names[0xBCBD] = 77 6F 72 6C 64 73 00
なので "worlds" を取得
entry[0x80E] = 0C 08 00 00 0F 08 00 00 0B 08 00 00 D3 BC 00 00
child_id = 0x80F, name_offset = 0xBCD3
file_names[0xBCD3] = 77 6F 72 6C 64 00 // "world"
entry[0x80F] = FF FF FF FF FF FF FF FF 0E 08 00 00 D9 BC 00 00
child_id = 0xFFFFFFFF(i32 なので -1), name_offset = 0xBCD9
file_names[0xBCD9] = 72 65 6E 64 65 72 70 69 70 65 2E 78 6D 6C 00 // "renderpipe.xml"
child_id = -1 つまり子供が無いのでこの entry はファイルを表す。
ここまでで path は worlds\world\renderpipe.xml になる。
ここで実際にファイルを書きだす処理
必要なのは offset, size, uncompressed_size
size と uncompressed_size は entry_info[0x80F] で取得可能
ここで問題になるのは offset で offsets にあるのだが entry_count と file_count は違う。
entry_count にはフォルダも含まれるが file_count はファイルしか含まれないため差異が生じる。
これに対応するには entry を読み込んだ時にファイルの index を振っておけばよい
let mut cnt = 0;
for ent in entry {
if ent.child_id == -1 {
ent.file_index = cnt;
cnt += 1;
}
}
3っつの値が判明したので offset へシークして size 分読み込んで path へ書き出せば良いのだが
ファイルはzlib圧縮されているものと非圧縮のものと混在しているのでそこを注意
if size != uncompressed_size {
zilb 展開後にファイル出力
} else {
そのまま出力
}
ここまでで1個のファイル出力は完了
entry[0x80F] = FF FF FF FF FF FF FF FF 0E 08 00 00 D9 BC 00 00
次に next_id = -1 つまり次が無いので親 parent_id = 0x80E に戻る
entry[0x80E] = 0C 08 00 00 0F 08 00 00 0B 08 00 00 D3 BC 00 00
next_id = 0x80C なので entry[0x80C] を処理する。
こんな感じでループしていくとすべてのファイルが展開されます。
再起で実装すると良いでしょう。
コメント