mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
hactoolnet: Add option to replace a savedata's entire contents
This commit is contained in:
parent
26ac0ed975
commit
c766a413e2
4 changed files with 44 additions and 29 deletions
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>netcoreapp2.1;net46</TargetFrameworks>
|
<TargetFrameworks>netcoreapp2.1;net46</TargetFrameworks>
|
||||||
|
<LangVersion>7.3</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -46,6 +46,7 @@ namespace hactoolnet
|
||||||
new CliOption("normaldir", 1, (o, a) => o.NormalDir = a[0]),
|
new CliOption("normaldir", 1, (o, a) => o.NormalDir = a[0]),
|
||||||
new CliOption("securedir", 1, (o, a) => o.SecureDir = a[0]),
|
new CliOption("securedir", 1, (o, a) => o.SecureDir = a[0]),
|
||||||
new CliOption("logodir", 1, (o, a) => o.LogoDir = a[0]),
|
new CliOption("logodir", 1, (o, a) => o.LogoDir = a[0]),
|
||||||
|
new CliOption("repack", 1, (o, a) => o.RepackSource = a[0]),
|
||||||
new CliOption("listapps", 0, (o, a) => o.ListApps = true),
|
new CliOption("listapps", 0, (o, a) => o.ListApps = true),
|
||||||
new CliOption("listtitles", 0, (o, a) => o.ListTitles = true),
|
new CliOption("listtitles", 0, (o, a) => o.ListTitles = true),
|
||||||
new CliOption("listncas", 0, (o, a) => o.ListNcas = true),
|
new CliOption("listncas", 0, (o, a) => o.ListNcas = true),
|
||||||
|
@ -235,6 +236,7 @@ namespace hactoolnet
|
||||||
sb.AppendLine(" --sign Sign the save file. (Requires device_key in key file)");
|
sb.AppendLine(" --sign Sign the save file. (Requires device_key in key file)");
|
||||||
sb.AppendLine(" --trim Trim garbage data in the save file. (Requires device_key in key file)");
|
sb.AppendLine(" --trim Trim garbage data in the save file. (Requires device_key in key file)");
|
||||||
sb.AppendLine(" --listfiles List files in save file.");
|
sb.AppendLine(" --listfiles List files in save file.");
|
||||||
|
sb.AppendLine(" --repack <dir> Replaces the contents of the save data with the specified directory.");
|
||||||
sb.AppendLine(" --replacefile <filename in save> <file> Replaces a file in the save data");
|
sb.AppendLine(" --replacefile <filename in save> <file> Replaces a file in the save data");
|
||||||
sb.AppendLine("NDV0 (Delta) options:");
|
sb.AppendLine("NDV0 (Delta) options:");
|
||||||
sb.AppendLine(" Input delta patch can be a delta NCA file or a delta fragment file.");
|
sb.AppendLine(" Input delta patch can be a delta NCA file or a delta fragment file.");
|
||||||
|
|
|
@ -39,6 +39,7 @@ namespace hactoolnet
|
||||||
public string LogoDir;
|
public string LogoDir;
|
||||||
public string ReplaceFileSource;
|
public string ReplaceFileSource;
|
||||||
public string ReplaceFileDest;
|
public string ReplaceFileDest;
|
||||||
|
public string RepackSource;
|
||||||
public bool ListApps;
|
public bool ListApps;
|
||||||
public bool ListTitles;
|
public bool ListTitles;
|
||||||
public bool ListNcas;
|
public bool ListNcas;
|
||||||
|
|
|
@ -16,6 +16,8 @@ namespace hactoolnet
|
||||||
{
|
{
|
||||||
using (var file = new LocalStorage(ctx.Options.InFile, FileAccess.ReadWrite))
|
using (var file = new LocalStorage(ctx.Options.InFile, FileAccess.ReadWrite))
|
||||||
{
|
{
|
||||||
|
bool signNeeded = ctx.Options.SignSave;
|
||||||
|
|
||||||
var save = new SaveDataFileSystem(ctx.Keyset, file, ctx.Options.IntegrityLevel, true);
|
var save = new SaveDataFileSystem(ctx.Keyset, file, ctx.Options.IntegrityLevel, true);
|
||||||
|
|
||||||
if (ctx.Options.Validate)
|
if (ctx.Options.Validate)
|
||||||
|
@ -30,52 +32,61 @@ namespace hactoolnet
|
||||||
|
|
||||||
if (ctx.Options.DebugOutDir != null)
|
if (ctx.Options.DebugOutDir != null)
|
||||||
{
|
{
|
||||||
// todo
|
|
||||||
string dir = ctx.Options.DebugOutDir;
|
string dir = ctx.Options.DebugOutDir;
|
||||||
|
|
||||||
ExportSaveDebug(ctx, dir, save);
|
ExportSaveDebug(ctx, dir, save);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.Options.ReplaceFileDest != null && ctx.Options.ReplaceFileSource != null)
|
try
|
||||||
{
|
{
|
||||||
string destFilename = ctx.Options.ReplaceFileDest;
|
if (ctx.Options.ReplaceFileDest != null && ctx.Options.ReplaceFileSource != null)
|
||||||
if (!destFilename.StartsWith("/")) destFilename = '/' + destFilename;
|
|
||||||
|
|
||||||
using (IFile inFile = new LocalFile(ctx.Options.ReplaceFileSource, OpenMode.Read))
|
|
||||||
{
|
{
|
||||||
using (IFile outFile = save.OpenFile(destFilename, OpenMode.ReadWrite))
|
string destFilename = ctx.Options.ReplaceFileDest;
|
||||||
|
if (!destFilename.StartsWith("/")) destFilename = '/' + destFilename;
|
||||||
|
|
||||||
|
using (IFile inFile = new LocalFile(ctx.Options.ReplaceFileSource, OpenMode.Read))
|
||||||
{
|
{
|
||||||
if (inFile.GetSize() != outFile.GetSize())
|
using (IFile outFile = save.OpenFile(destFilename, OpenMode.ReadWrite))
|
||||||
{
|
{
|
||||||
outFile.SetSize(inFile.GetSize());
|
if (inFile.GetSize() != outFile.GetSize())
|
||||||
|
{
|
||||||
|
outFile.SetSize(inFile.GetSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
inFile.CopyTo(outFile, ctx.Logger);
|
||||||
|
|
||||||
|
ctx.Logger.LogMessage($"Replaced file {destFilename}");
|
||||||
}
|
}
|
||||||
|
|
||||||
inFile.CopyTo(outFile, ctx.Logger);
|
|
||||||
|
|
||||||
ctx.Logger.LogMessage($"Replaced file {destFilename}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signNeeded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (save.Commit(ctx.Keyset))
|
if (ctx.Options.RepackSource != null)
|
||||||
{
|
{
|
||||||
ctx.Logger.LogMessage("Successfully signed save file");
|
var source = new LocalFileSystem(ctx.Options.RepackSource);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ctx.Logger.LogMessage("ERROR: Unable to sign save file. Do you have all the required keys?");
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
save.CleanDirectoryRecursively("/");
|
||||||
|
save.Commit(ctx.Keyset);
|
||||||
|
source.CopyFileSystem(save);
|
||||||
|
|
||||||
|
signNeeded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
save.Commit(ctx.Keyset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.Options.SignSave || ctx.Options.TrimSave)
|
if (ctx.Options.TrimSave)
|
||||||
{
|
{
|
||||||
if (ctx.Options.TrimSave)
|
save.FsTrim();
|
||||||
{
|
signNeeded = true;
|
||||||
save.FsTrim();
|
ctx.Logger.LogMessage("Trimmed save file");
|
||||||
ctx.Logger.LogMessage("Trimmed save file");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
if (signNeeded)
|
||||||
|
{
|
||||||
if (save.Commit(ctx.Keyset))
|
if (save.Commit(ctx.Keyset))
|
||||||
{
|
{
|
||||||
ctx.Logger.LogMessage("Successfully signed save file");
|
ctx.Logger.LogMessage("Successfully signed save file");
|
||||||
|
@ -90,14 +101,14 @@ namespace hactoolnet
|
||||||
|
|
||||||
if (ctx.Options.ListFiles)
|
if (ctx.Options.ListFiles)
|
||||||
{
|
{
|
||||||
foreach (DirectoryEntry entry in save.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File))
|
foreach (DirectoryEntry entry in save.EnumerateEntries())
|
||||||
{
|
{
|
||||||
ctx.Logger.LogMessage(entry.FullPath);
|
ctx.Logger.LogMessage(entry.FullPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Logger.LogMessage(save.Print());
|
ctx.Logger.LogMessage(save.Print());
|
||||||
//ctx.Logger.LogMessage(PrintFatLayout(save));
|
//ctx.Logger.LogMessage(PrintFatLayout(save.SaveDataFileSystemCore));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue