「How to 日本語化(Hard mode) – お~るげーむず(仮)」
https://agk.saloon.jp/game/overseasgame/jp-localize/how-to-ogj-06
この記事では、ポイント&クリック スタイルのパズルゲーム 「The Tiny Bang Story」 を題材に data.pfp ファイルの解析とアンパックするプログラムが公開されています。
「Steam:The Tiny Bang Story」
https://store.steampowered.com/app/96000/The_Tiny_Bang_Story/
今回は、AutoITで作成されているプログラムを C# に移植してみました。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// The Tiny Bang Story pfp file packer. | |
/// This software is released under the GPL. | |
/// | |
/// Copyright(c) お~るげーむず(仮) | |
/// 「How to 日本語化(Hard mode) – お~るげーむず(仮)」 | |
/// http://ryo.game.coocan.jp/blog/game/overseasgame/jp-localize/how-to-ogj-06 | |
/// Ported from AutoIT to C# by synctam. | |
/// </summary> | |
namespace TtbsPacker | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Text; | |
using System.Windows.Forms; | |
internal class Program | |
{ | |
[STAThread] | |
private static void Main(string[] args) | |
{ | |
FolderBrowserDialog fbd = new FolderBrowserDialog(); | |
fbd.Description = "パックするフォルダを選択"; | |
fbd.RootFolder = Environment.SpecialFolder.Desktop; | |
fbd.ShowNewFolderButton = false; | |
if (fbd.ShowDialog() != DialogResult.OK) | |
{ | |
return; | |
} | |
int fspos = 0; | |
//// 選択フォルダのファイル一覧を取得 | |
//// path,対象ファイル,ファイルのみ,サブフォルダも検索 | |
string[] files = Directory.GetFiles(fbd.SelectedPath, "*", SearchOption.AllDirectories); | |
//// 新Packファイル作成 | |
using (FileStream fsPack = new FileStream($@"{fbd.SelectedPath}\..\data.pfp.new", FileMode.Create, FileAccess.Write, FileShare.None)) | |
{ | |
using (BinaryWriter packFile = new BinaryWriter(fsPack, Encoding.UTF8)) | |
{ | |
//// ヘッダの書き込み | |
packFile.Write(Encoding.ASCII.GetBytes("PFPK")); | |
//// ファイル数の書き込み。 | |
packFile.Write(files.Length); | |
//// アンパックしたファイルを書きこむ開始アドレス | |
//// ヘッダ部分4byte+ファイル数4byte | |
fspos += 4 + 4; | |
//// ファイル名の長さ1byte+ファイル名(可変) | |
//// +ファイルサイズ4byte+ファイル開始アドレス4byte | |
foreach (string path in files) | |
{ | |
//// ファイル名を相対パスに変更(¥マークを / に置換え) | |
var archivePath = ConvertPath(fbd.SelectedPath, path); | |
fspos += 1 + Encoding.UTF8.GetBytes(archivePath).Length + 4 + 4; | |
} | |
var filepath = new List<string>(); | |
foreach (var path in files) | |
{ | |
//// ファイル名を相対パスに変更(¥マークを / に置換え) | |
var archivePath = ConvertPath(fbd.SelectedPath, path); | |
//// ファイル名の長さ | |
packFile.Write((byte)archivePath.Length); | |
//// ファイル名 | |
packFile.Write(Encoding.UTF8.GetBytes(archivePath)); | |
//// ファイル開始アドレス位置 | |
packFile.Write(fspos); | |
//// ファイルサイズアドレス位置 | |
var size = (int)new FileInfo(path).Length; | |
packFile.Write(size); | |
//// ファイルの開始位置更新 | |
fspos += size; | |
} | |
//// アンパックしたファイルの書き込み | |
foreach (var path in files) | |
{ | |
using (FileStream fsData = new FileStream(path, FileMode.Open, FileAccess.Read)) | |
{ | |
byte[] data = new byte[fsData.Length]; | |
fsData.Read(data, 0, data.Length); | |
packFile.Write(data); | |
} | |
} | |
MessageBox.Show("パックしました", "TBS Unpacker", MessageBoxButtons.OK, MessageBoxIcon.Information); | |
} | |
} | |
Console.Write("Hit enter key."); | |
Console.Read(); | |
} | |
/// <summary> | |
/// Faile名を相対パスに変換し、セパレーターを"/"に変更する。 | |
/// </summary> | |
/// <param name="selectedFolder">選択したフォルダー名</param> | |
/// <param name="path">ファイルのパス</param> | |
/// <returns>変換後のパス</returns> | |
private static string ConvertPath(string selectedFolder, string path) | |
{ | |
return path | |
//// 相対パスに変換 | |
.Replace(selectedFolder, string.Empty) | |
//// セパレーターを'/'に変更 | |
.Replace('\\', '/') | |
//// 先頭の不要なセパレータを除去。 | |
.TrimStart('/'); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// The Tiny Bang Story pfp file unpacker. | |
/// This software is released under the GPL. | |
/// | |
/// Copyright(c) お~るげーむず(仮) | |
/// 「How to 日本語化(Hard mode) – お~るげーむず(仮)」 | |
/// http://ryo.game.coocan.jp/blog/game/overseasgame/jp-localize/how-to-ogj-06 | |
/// Ported from AutoIT to C# by synctam. | |
/// </summary> | |
namespace TtbsUnpacker | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Text; | |
using System.Windows.Forms; | |
internal class Program | |
{ | |
[STAThread] | |
private static void Main(string[] args) | |
{ | |
OpenFileDialog ofd = new OpenFileDialog(); | |
ofd.Filter = "pfp file (*.pfp)|*.pfp"; | |
ofd.Title = "Select the file"; | |
if (ofd.ShowDialog() != DialogResult.OK) | |
{ | |
return; | |
} | |
using (BinaryReader binaryReader = new BinaryReader(new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read))) | |
{ | |
byte[] signature = binaryReader.ReadBytes(4); | |
//// ヘッダのチェックして該当ファイルならアンパック開始 | |
if (Encoding.ASCII.GetString(signature) == "PFPK") | |
{ | |
//// 文字コードを指定 | |
Encoding enc = Encoding.UTF8; | |
//// ファイルの数 | |
var fileno = binaryReader.ReadInt32(); | |
//// ファイルを格納するための変数 | |
var filepath = new List<string>(); | |
var filesize = new List<int>(); | |
var filepos = new List<int>(); | |
//// 作業用フォルダを作成し、そこへ移動する | |
Directory.CreateDirectory("data"); | |
Environment.CurrentDirectory = "data"; | |
for (int i = 0; i < fileno; i++) | |
{ | |
//// ファイル名の文字数取得 | |
var fnmoji = binaryReader.ReadByte(); | |
//// ファイル名をフォルダ構成毎取得 | |
filepath.Add(enc.GetString(binaryReader.ReadBytes(fnmoji))); | |
//// ファイルの開始位置取得 | |
filepos.Add(binaryReader.ReadInt32()); | |
//// ファイルサイズを取得 | |
filesize.Add(binaryReader.ReadInt32()); | |
} | |
for (int i = 0; i < fileno; i++) | |
{ | |
//// ファイル名のスラッシュを¥マークに変換 | |
var fw = filepath[i].Replace('/', '\\'); | |
//// ファイルの開始位置へ移動 | |
binaryReader.BaseStream.Seek(filepos[i], SeekOrigin.Begin); | |
//// data.pfpよりデータを読み取る | |
var filedata = binaryReader.ReadBytes(filesize[i]); | |
Console.WriteLine($"Extracted file: {fw} Size({filesize[i]})"); | |
//// フォルダーの有無を確認しなければ作成 | |
var folderName = Path.GetDirectoryName(fw); | |
if (!Directory.Exists(folderName)) | |
{ | |
Directory.CreateDirectory(folderName); | |
} | |
//// 書き込み用ファイルをオープン(フォルダ毎作成する設定) | |
using (BinaryWriter binaryWriter = new BinaryWriter(new FileStream(fw, FileMode.OpenOrCreate, FileAccess.Write), enc)) | |
{ | |
//// 書き込み | |
binaryWriter.Write(filedata); | |
} | |
} | |
MessageBox.Show("全てのファイルを書きだしました", "TBS Unpacker", MessageBoxButtons.OK, MessageBoxIcon.Information); | |
} | |
else | |
{ | |
string msg = BitConverter.ToString(signature); | |
MessageBox.Show("The selected file is not *.pfp.\r\nPlease restart it.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); | |
} | |
} | |
Console.Write("Hit enter key."); | |
Console.Read(); | |
} | |
} | |
} |
This software is released under the GPL.
では・・・
C#はまったくもって触って来なかったので半分以上???ですが大変勉強になります。
返信削除様々な言語で紹介できて少しでもこういうところへ興味を持ってくれたらうれしいかなと思います。
私も AutoIt はほとんど触ったことがありませんが、他人のプログラムを読むのはとても勉強になります。プログラムの組み立て方は人それぞれ特徴があって見ていて楽しいです。
削除