コマンドラインでBSAファイルを展開するツールを作った話
BSA(BethesdaArchive)ファイルを展開するツールは、去年末~年初に調べた限りGUIのものばかり。
コマンドラインで使えるものがないなら作ってしまおう!、ということで作ってみた。
ソースコードを探せ!
冒頭、『作ってしまおう!』といかにもスクラッチで作るかのように装っているが、既存GUIツールでソース公開されているものを改変すりゃいいだろう、という目論見だった。
いくつか GitHub で公開されているモノ(ソース)を調べたが、C++製のものが多く、なんも考えずに弄ると痛い目に合う*1のが想像できるので半ばあきらめていた。
そんな中、QuickBSAExtrator*2 が同時配布しているソースコードを見ると、Delphi製であることが判明。個人的に C++ よりも Delphi のが気楽なのでこのソースを改変することにした。
ソースコードを調査せよ!
ソースコードを注意深く調べてみると、TES5Edit*3 のソースコードからBSAファイルの展開に必要な部分だけを流用し、改変している。
ならば、TES5Edit のソースコードをベースにするほうがいいのかな、と QuickBSAExtractor が流用し改変しているファイルについて少し調べてみた。
該当するソースコードについて、TES5Edit では思った以上に詳細な記述(定義)を行っている箇所もあり、またインクルードしているファイルもそこそこある。それらを解析して整理していくのは時間がかかる。
今回は、最低限BSAファイルの中身を展開するだけの実装が目的で、TES5Edit の詳細な解析やBSAファイルの構造を知ることではない。
そこで、先に書いた QuickBSAExtractor が流用し改変してライブラリ化したファイルを使うことに決めた。
必要になる外部ライブラリ*4については、QuickBSAExtractor のソースアーカイブよりも TES5Edit のリポジトリのほうが新しいため、リポジトリのモノを使用することにした。
そして実装へ………
先の目的に従って、必要なコードを書いてみると、展開ルーティンはQuickBSAExtractor(と元のTES5Edit)の実装が優れていて数行のコードであっさりとできてしまった。
むしろ、コマンドラインへの出力内容や前処理を作るほうに時間がかかっていた。
外部ライブラリについては、コンパイルエラーもなく簡単な動作テストでも問題なかった。
素人プログラマの私が、簡単に展開ツールを実装することができたのは、QuickBSAExtractor のソースコードが公開されていたことが大きい。
また、機能をBSAファイルを展開することに絞った*5ことも実装を容易にした。
そもそも、無償かつ無期限で利用できる Delphi Starter Edtion が存在しなければ、この展開ツールの作成はあきらめていただろう。
なぜコマンドラインツールが必要になったのか?
SkyrimSE英語版を日本語化するという要求は、英語版がパッチ1.4、日本語版*6がパッチ1.1とその差が開いている状況ではそれなりに多いと思われる。
そして、英語版を日本語化する手順は確立されている。
それならば、自動化できるよね。むしろ自動化しておくといいよね、と考えた。
自動化するなら、人間が操作するのは日本語版と英語版の切替ぐらいで、あとはバッチファイルを実行するだけで済ませたい。
手順のうち、『BSAファイルの展開』以外の部分*7はバッチファイルによる自動化ができる。
『BSAファイルの展開』だけは、GUIツールを使って人間が操作しないといけない。
この部分も自動化するには、『BSAファイルの展開』を行うコマンドラインのツールが必要だった。
そして、コマンドラインでBSAファイルを展開できるツールが出来上がった。
作ったツールの実行例: Z:\>SimpleBSAExtractor.exe /s "Skyrim - Patch.bsa" /d Output /l JPPatch_en_files.txt <00:00:00.000>: <---------------------- Process Start ---------------------> <00:00:00.000>: Read and check list file: JPPatch_en_files.txt <00:00:00.000>: <00:00:00.000>: Valid file name/Invalid file name : 20/0 <00:00:00.001>: <----------------------------------------------------------> <00:00:00.001>: Read and check source file: Skyrim - Patch.bsa <00:00:00.008>: <----------------------------------------------------------> <00:00:00.009>: Extract to destination folder: Z:\Output <00:00:00.009>: Extract file: <00:00:00.645>: interface\inventory components\bottombar.swf <00:00:00.651>: interface\book.swf <00:00:00.655>: interface\fontconfig.txt <00:00:00.660>: interface\translate_english.txt <00:00:00.667>: strings\dawnguard_english.dlstrings <00:00:00.673>: strings\dawnguard_english.ilstrings <00:00:00.684>: strings\dawnguard_english.strings <00:00:00.689>: strings\dragonborn_english.dlstrings <00:00:00.694>: strings\dragonborn_english.ilstrings <00:00:00.697>: strings\dragonborn_english.strings <00:00:00.700>: strings\hearthfires_english.dlstrings <00:00:00.703>: strings\hearthfires_english.ilstrings <00:00:00.705>: strings\hearthfires_english.strings <00:00:00.731>: strings\skyrim_english.dlstrings <00:00:00.762>: strings\skyrim_english.ilstrings <00:00:00.769>: strings\skyrim_english.strings <00:00:00.771>: strings\update_english.dlstrings <00:00:00.773>: strings\update_english.ilstrings <00:00:00.775>: strings\update_english.strings <00:00:00.775>: <------------------------ Summary -------------------------> <00:00:00.775>: Source file : Z:\Skyrim - Patch.bsa <00:00:00.776>: Destination folder : Z:\Output <00:00:00.776>: List file : Z:\JPPatch_en_files.txt <00:00:00.776>: <00:00:00.777>: Extract files/Skip files : 19/1 <00:00:00.777>: Skip file: <00:00:00.777>: interface\fonts_jp.swf <00:00:00.778>: <---------------------- Process End -----------------------> Z:\>