Refactor backup/restore method

Now restores all files; users can still manually restore individual
files.
Closes #31
This commit is contained in:
Kurt
2017-04-17 23:30:31 -07:00
parent 20a6b701e2
commit 329425a69d
4 changed files with 247 additions and 77 deletions

224
pk3DS/Game/GameBackup.cs Normal file
View File

@@ -0,0 +1,224 @@
using System;
using System.IO;
using System.Linq;
namespace pk3DS
{
public static class GameBackup
{
private const string bakpath = "backup";
private const string bakexefs = "exefs";
private const string baka = "a";
private const string bakdll = "dll";
public static void backupFiles(this GameConfig config, bool overwrite = false)
{
// Users may use pk3DS for multiple games, and even the same game but from different paths.
// A simple way is to create a backup for each unique game, but... some carts may be pre-patched.
// Just save the backup based on the folder name, as the user may move that parent folder.
// Store a text file in each backup to keep track of its origin in case they rename the folder.
if (!Directory.Exists(bakpath))
Directory.CreateDirectory(bakpath);
var gamePath = new DirectoryInfo(config.RomFS).Parent;
string gameFolder = gamePath.Name;
string gameBackup = Path.Combine(bakpath, gameFolder);
if (!Directory.Exists(gameBackup))
Directory.CreateDirectory(gameBackup);
string bak_exefs = Path.Combine(gameBackup, bakexefs);
string bak_a = Path.Combine(gameBackup, baka);
string bak_dll = Path.Combine(gameBackup, bakdll);
if (!Directory.Exists(bak_exefs))
Directory.CreateDirectory(bak_exefs);
if (!Directory.Exists(bak_a))
Directory.CreateDirectory(bak_a);
if (!Directory.Exists(bak_dll))
Directory.CreateDirectory(bak_dll);
// Backup files
if (config.ExeFS != null) // exefs
backupExeFS(config, overwrite, bak_exefs);
if (config.RomFS != null) // a
backupGARC(config, overwrite, bak_a);
if (config.RomFS != null) // dll
backupDLL(config, overwrite, bak_dll);
File.WriteAllText(Path.Combine(gameBackup, "bakinfo.txt"), "Backup created from the following location:" + Environment.NewLine + gamePath.FullName);
}
private static void backupExeFS(GameConfig config, bool overwrite, string bak_exefs)
{
var files = Directory.GetFiles(config.ExeFS);
foreach (var f in files)
{
string dest = Path.Combine(bak_exefs, Path.GetFileName(f));
if (overwrite || !File.Exists(dest))
File.Copy(f, dest);
}
}
private static void backupGARC(GameConfig config, bool overwrite, string bak_a)
{
var files = config.Files.Select(file => file.Name);
foreach (var f in files)
{
string GARC = config.getGARCFileName(f);
string name = f + $" ({GARC.Replace(Path.DirectorySeparatorChar.ToString(), "")})";
string src = Path.Combine(config.RomFS, GARC);
string dest = Path.Combine(bak_a, name);
if (overwrite || !File.Exists(dest))
File.Copy(src, dest);
}
}
private static void backupDLL(GameConfig config, bool overwrite, string bak_dll)
{
string path = config.RomFS;
string[] files = Directory.GetFiles(path);
string[] CROs = files.Where(x => new FileInfo(x).Name.Contains("Dll")).ToArray();
string[] CRSs = files.Where(x => new FileInfo(x).Extension.Contains("crs")).ToArray();
string[] CRRs = Directory.Exists(Path.Combine(path, ".crr"))
? Directory.GetFiles(Path.Combine(path, ".crr"))
: new string[0];
int count = CROs.Length + CRSs.Length + CRRs.Length;
if (count <= 0)
return;
if (!Directory.Exists(bak_dll))
Directory.CreateDirectory(bak_dll);
foreach (string src in CROs.Concat(CRSs))
{
string dest = Path.Combine(bak_dll, Path.GetFileName(src));
if (overwrite || !File.Exists(dest))
File.Copy(src, dest);
}
if (CRRs.Length <= 0)
return;
// Separate folder for the .crr
string CRRBAKPATH = Path.Combine(bak_dll, ".crr");
if (!Directory.Exists(CRRBAKPATH))
Directory.CreateDirectory(CRRBAKPATH);
foreach (string src in CRRs)
{
string dest = Path.Combine(CRRBAKPATH, Path.GetFileName(src));
if (overwrite || !File.Exists(dest))
File.Copy(src, dest);
}
}
public static string[] restoreFiles(this GameConfig config)
{
// Do the same process as backing up, but copy files in the opposite direction.
string gameFolder = new DirectoryInfo(config.RomFS).Parent.Name;
string gameBackup = Path.Combine(bakpath, gameFolder);
if (!Directory.Exists(gameBackup))
return new[] {"Unable to find the backup folder for this game.", $"Expected:\n{gameBackup}"};
string bak_exefs = Path.Combine(gameBackup, bakexefs);
string bak_a = Path.Combine(gameBackup, baka);
string bak_dll = Path.Combine(gameBackup, bakdll);
int[] count = new int[3];
// restore exefs
if (Directory.Exists(bak_exefs))
count[0] = restoreExeFS(config, bak_exefs);
if (Directory.Exists(bak_a))
count[1] = restoreGARC(config, bak_a);
if (Directory.Exists(bak_dll))
count[2] = restoreDLL(config, bak_dll);
string[] sources = { "ExeFS", "'a'", "CRO" };
var info = count.Select((c, i) => $"{sources[i]}: {c}");
var result = string.Join(Environment.NewLine, info);
return new[] {result};
}
private static int restoreExeFS(GameConfig config, string bak_exefs)
{
int count = 0;
var files = Directory.GetFiles(config.ExeFS);
foreach (var f in files)
{
string dest = Path.Combine(bak_exefs, Path.GetFileName(f));
if (File.Exists(dest))
{
File.Copy(dest, f);
count++;
}
else
Console.WriteLine("Unable to find backup: " + dest);
}
return count;
}
private static int restoreGARC(GameConfig config, string bak_a)
{
int count = 0;
var files = config.Files.Select(file => file.Name);
foreach (var f in files)
{
string GARC = config.getGARCFileName(f);
string name = f + $" ({GARC.Replace(Path.DirectorySeparatorChar.ToString(), "")})";
string src = Path.Combine(config.RomFS, GARC);
string dest = Path.Combine(bak_a, name);
if (File.Exists(dest))
{
File.Copy(dest, src);
count++;
}
else
Console.WriteLine("Unable to find backup: " + dest);
}
return count;
}
private static int restoreDLL(GameConfig config, string bak_dll)
{
int count = 0;
string path = config.RomFS;
string[] files = Directory.GetFiles(path);
string[] CROs = files.Where(x => new FileInfo(x).Name.Contains("Dll")).ToArray();
string[] CRSs = files.Where(x => new FileInfo(x).Extension.Contains("crs")).ToArray();
string[] CRRs = Directory.Exists(Path.Combine(path, ".crr"))
? Directory.GetFiles(Path.Combine(path, ".crr"))
: new string[0];
if (CROs.Length + CRSs.Length + CRRs.Length <= 0)
return 0;
foreach (string src in CROs.Concat(CRSs))
{
string dest = Path.Combine(bak_dll, Path.GetFileName(src));
if (File.Exists(dest))
{
File.Copy(dest, src);
count++;
}
else
Console.WriteLine("Unable to find backup: " + dest);
}
if (CRRs.Length <= 0)
return count;
// Separate folder for the .crr
string CRRBAKPATH = Path.Combine(bak_dll, ".crr");
foreach (string src in CRRs)
{
string dest = Path.Combine(CRRBAKPATH, Path.GetFileName(src));
if (File.Exists(dest))
{
File.Copy(dest, src);
count++;
}
else
Console.WriteLine("Unable to find backup: " + dest);
}
return count;
}
}
}

View File

@@ -169,7 +169,7 @@ private GARC.lzGARC getlzGARC(string file)
return new GARC.lzGARC(File.ReadAllBytes(getGARCPath(file)));
}
private string RomFS, ExeFS;
public string RomFS, ExeFS;
public GARCReference getGARCReference(string name) { return Files.FirstOrDefault(f => f.Name == name); }
public TextVariableCode getVariableCode(string name) { return Variables.FirstOrDefault(v => v.Name == name); }

View File

@@ -70,21 +70,31 @@ private void L_About_Click(object sender, EventArgs e)
}
private void L_GARCInfo_Click(object sender, EventArgs e)
{
if (RomFSPath != null)
{
string s = "Game Type: " + Config.Version + Environment.NewLine;
s = Config.Files.Select(file => file.Name).Aggregate(s, (current, t) => current + string.Format(Environment.NewLine + "{0} - {1}", t, Config.getGARCFileName(t)));
if (RomFSPath == null)
return;
if (DialogResult.Yes != Util.Prompt(MessageBoxButtons.YesNo, s, "Copy to Clipboard?")) return;
string s = "Game Type: " + Config.Version + Environment.NewLine;
s = Config.Files.Select(file => file.Name).Aggregate(s, (current, t) => current + string.Format(Environment.NewLine + "{0} - {1}", t, Config.getGARCFileName(t)));
try { Clipboard.SetText(s); }
catch { Util.Alert("Unable to copy to Clipboard."); }
}
if (DialogResult.Yes != Util.Prompt(MessageBoxButtons.YesNo, s, "Copy to Clipboard?")) return;
try { Clipboard.SetText(s); }
catch { Util.Alert("Unable to copy to Clipboard."); }
}
private void L_Game_Click(object sender, EventArgs e)
{
if (DialogResult.Yes == Util.Prompt(MessageBoxButtons.YesNo, "Restore Original Files?"))
restoreGARCs(Config.Files.Select(file => file.Name).ToArray());
if (DialogResult.Yes != Util.Prompt(MessageBoxButtons.YesNo, "Restore Original Files?"))
return;
string[] result = Config.restoreFiles();
if (result.Length == 2) // error
{
Util.Alert(result);
return;
}
Util.Alert("Restored files:", result[0], "The program will now close.");
Application.Exit(); // do not call closing events that repackage personal/gametext
}
private void B_Open_Click(object sender, EventArgs e)
@@ -203,8 +213,7 @@ private void openQuick(string path)
if (RTB_Status.Text.Length > 0) RTB_Status.Clear();
updateStatus("Data found! Loading persistent data for subforms...", false);
Config.Initialize(RomFSPath, ExeFSPath, Language);
backupGARCs(false, Config.Files.Select(file => file.Name).ToArray());
backupCROs(false, RomFSPath);
Config.backupFiles();
}
// Enable Rebuilding options if all files have been found
@@ -289,7 +298,6 @@ private static GameConfig checkGameType(string[] files)
if (files.Length > 1000)
return null;
string[] fileArr = Directory.GetFiles(Path.Combine(Directory.GetParent(files[0]).FullName, "a"), "*", SearchOption.AllDirectories);
var afiles = fileArr.Where(file => Path.GetFileName(file)?.Length == 1).ToArray();
int fileCount = fileArr.Count(file => Path.GetFileName(file)?.Length == 1);
return new GameConfig(fileCount);
}
@@ -781,7 +789,6 @@ private void B_TitleScreen_Click(object sender, EventArgs e)
// RomFS File Requesting Method Wrapper
private void fileGet(string[] files, bool skipDecompression = true, bool skipGet = false)
{
if (ModifierKeys == (Keys.Control | Keys.Shift)) restoreGARCs(files.ToArray());
if (skipGet || skipBoth) return;
foreach (string toEdit in files)
{
@@ -998,42 +1005,6 @@ private void B_Static_Click(object sender, EventArgs e)
}
new StaticEncounterEditor6().ShowDialog();
}
private void backupCROs(bool overwrite, string path)
{
if (!Directory.Exists(path))
return;
string[] files = Directory.GetFiles(path);
string[] CROs = files.Where(x => new FileInfo(x).Name.Contains("Dll")).ToArray();
string[] CRSs = files.Where(x => new FileInfo(x).Extension.Contains("crs")).ToArray();
string[] CRRs = Directory.Exists(Path.Combine(path, ".crr"))
? Directory.GetFiles(Path.Combine(path, ".crr"))
: new string[0];
int count = CROs.Length + CRSs.Length + CRRs.Length;
if (count <= 0)
return;
// Somewhat unique ID for the dlls to separate backup folders between versions
string CROBAKPATH = Path.Combine("backup", "DLL_" + count);
if (!Directory.Exists(CROBAKPATH))
Directory.CreateDirectory(CROBAKPATH);
foreach (string file in CROs.Concat(CRSs).Where(file => overwrite || !File.Exists(Path.Combine(CROBAKPATH, Path.GetFileName(file)))))
File.Copy(file, Path.Combine(CROBAKPATH, Path.GetFileName(file)));
if (CRRs.Length <= 0)
return;
// Separate folder for the .crr
string CRRBAKPATH = Path.Combine(CROBAKPATH, ".crr");
if (!Directory.Exists(CRRBAKPATH))
Directory.CreateDirectory(CRRBAKPATH);
foreach (string file in CRRs.Where(file => overwrite || !File.Exists(Path.Combine(CRRBAKPATH, Path.GetFileName(file)))))
File.Copy(file, Path.Combine(CRRBAKPATH, Path.GetFileName(file)));
}
// 3DS Building
private void B_Rebuild3DS_Click(object sender, EventArgs e)
@@ -1185,32 +1156,6 @@ private void threadSet(string outfile, string infolder, int padBytes, bool PB =
new Thread(() => setGARC(outfile, infolder, padBytes, PB)).Start();
}
private static void backupGARCs(bool overwrite, params string[] g)
{
if (!Directory.Exists("backup")) Directory.CreateDirectory("backup");
foreach (string s in g)
{
string GARC = Config.getGARCFileName(s);
string dest = "backup" + Path.DirectorySeparatorChar + s +
$" ({GARC.Replace(Path.DirectorySeparatorChar.ToString(), "")})";
if (overwrite || !File.Exists(dest))
File.Copy(Path.Combine(RomFSPath, GARC), dest);
}
}
private static void restoreGARCs(params string[] g)
{
foreach (string s in g)
{
string dest = Path.Combine(RomFSPath, Config.getGARCFileName(s));
string src = "backup" + Path.DirectorySeparatorChar + s +
$" ({Config.getGARCFileName(s).Replace(Path.DirectorySeparatorChar.ToString(), "")})";
File.Copy(src, dest, true);
if (s == "personal" || s == "gametext")
Util.Alert("In order to restore " + s + ", restart the program. While exiting, hold the Control Key to prevent writebacks.");
}
Util.Alert(g.Length + " files restored.");
}
// Text Requests
internal static string[] getText(TextName file)
{

View File

@@ -84,6 +84,7 @@
<Compile Include="3DS\CTR.cs" />
<Compile Include="3DS\ExeFS.cs" />
<Compile Include="3DS\BCLIM.cs" />
<Compile Include="Game\GameBackup.cs" />
<Compile Include="Game\GameRNG.cs" />
<Compile Include="Game\GameVersion.cs" />
<Compile Include="Game\GARCFile.cs" />