Auto-clean save file names of duplicate suffixes

`main (17)` now backs up as `main [...].bak` instead of `main (17) [...]`
Adds a debug-callable method to clean the main backup folder via:
`CleanBackups(Main.BackupPath, true);`
This commit is contained in:
Kurt 2024-05-27 19:23:56 -05:00
parent c10c2a0dc2
commit b7298a7361
6 changed files with 100 additions and 20 deletions

View File

@ -10,7 +10,7 @@ namespace PKHeX.Core;
/// </summary>
public abstract class SAV_STADIUM : SaveFile, ILangDeviantSave
{
protected internal sealed override string ShortSummary => $"{OT} ({Version})";
protected internal sealed override string ShortSummary => $"{OT} ({Version}) {Checksums.CRC16_CCITT(Data):X4}";
public sealed override string Extension => ".sav";
public abstract int SaveRevision { get; }

View File

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
namespace PKHeX.Core;
@ -97,9 +99,67 @@ private void SetAsLoadedFile(string path)
private static string GetFileName(string path, string bak)
{
var fileName = Path.GetFileName(path);
// Trim off existing backup name if present
var bakName = Util.CleanFileName(bak);
var fn = Path.GetFileName(path);
return fn.EndsWith(bakName, StringComparison.Ordinal) ? fn[..^bakName.Length] : fn;
if (fileName.EndsWith(bakName, StringComparison.Ordinal))
fileName = fileName[..^bakName.Length];
if (fileName.StartsWith("savedata ", StringComparison.OrdinalIgnoreCase) && fileName.Contains(".bin"))
return fileName[..8] + ".bin";
if (fileName.StartsWith("main"))
return "main";
var extensions = CollectionsMarshal.AsSpan(CustomSaveExtensions);
return TrimNames(fileName, extensions);
}
public static readonly List<string> CustomSaveExtensions =
[
"sav", // standard
"dat", // VC data
"gci", // Dolphin GameCubeImage
"dsv", // DeSmuME
"srm", // RetroArch save files
"fla", // flash
"SaveRAM", // BizHawk
];
private static string TrimNames(string fileName, ReadOnlySpan<string> extensions)
{
foreach (var ext in extensions)
{
var index = fileName.LastIndexOf(ext, StringComparison.OrdinalIgnoreCase);
if (index == -1)
continue;
// Check for a period before the extension
if (index == 0 || fileName[index - 1] != '.')
continue;
var result = fileName.AsSpan();
result = result[..(index-1)];
// Files can have (#) appended to them, so we need to trim that off
var open = result.LastIndexOf('(');
var close = result.LastIndexOf(')');
if (open != -1 && close != -1 && close > open && char.IsDigit(result[open + 1]))
result = result[..open].Trim();
var copy = result.IndexOf(" - Copy", StringComparison.OrdinalIgnoreCase);
if (copy == -1)
copy = result.IndexOf("_-_Copy", StringComparison.OrdinalIgnoreCase);
if (copy != -1)
result = result[..copy].Trim();
// Re-add the extension
return $"{result}.{ext}";
}
return fileName;
}
public string GetBackupFileName(string destDir)
{
return Path.Combine(destDir, Util.CleanFileName(BAKName));
}
private void SetAsBlank()

View File

@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
@ -69,7 +68,6 @@ private void Generate(int width, int height)
int h = (2 * padEdge) + border + (height * (rowHeight + border));
Size = new Size(w, h);
Controls.AddRange(Entries.Cast<Control>().ToArray());
Debug.WriteLine($"{Name} -- Width: {Width}, Height: {Height}");
ResumeLayout();
}

View File

@ -886,19 +886,19 @@ private static bool TryBackupExportCheck(SaveFile sav, string path)
return false;
var meta = sav.Metadata;
string backupName = Path.Combine(dir, Util.CleanFileName(meta.BAKName));
var backupName = meta.GetBackupFileName(dir);
if (File.Exists(backupName))
return false; // Already backed up.
// Ensure the file we are copying exists.
var src = meta.FilePath;
if (src is not { } x || !File.Exists(x))
if (src is null || !File.Exists(src))
return false;
try
{
// Don't need to force overwrite, but on the off-chance it was written externally, we force ours.
File.Copy(x, backupName, true);
File.Copy(src, backupName, true);
return true;
}
catch (Exception ex)

View File

@ -288,6 +288,39 @@ private SaveList<SavePreview> PopulateData(DataGridView dgData, IEnumerable<Save
return list;
}
private static void CleanBackups(string path, bool deleteNotSaves)
{
var files = Directory.GetFiles(path);
foreach (var file in files)
{
var fi = new FileInfo(file);
if (!SaveUtil.IsSizeValid(fi.Length) || SaveUtil.GetVariantSAV(file) is not { } sav)
{
if (deleteNotSaves)
File.Delete(file);
continue;
}
var self = sav.Metadata.FilePath;
if (self is null)
continue; // shouldn't hit
var index = self.IndexOf(" [", StringComparison.OrdinalIgnoreCase);
if (index < 0)
continue;
var original = self[..index];
sav.Metadata.SetExtraInfo(original);
string backupName = sav.Metadata.GetBackupFileName(Main.BackupPath);
if (self == backupName)
continue;
if (File.Exists(backupName))
File.Delete(self);
else
File.Move(self, backupName);
}
}
private static void Refresh(DataGridView dgData)
{
dgData.SuspendLayout();

View File

@ -20,8 +20,6 @@ public static class WinFormsUtil
/// <summary>
/// Centers the <see cref="child"/> horizontally and vertically so that its center is the same as the <see cref="parent"/>'s center.
/// </summary>
/// <param name="child"></param>
/// <param name="parent"></param>
internal static void CenterToForm(this Control child, Control? parent)
{
if (parent == null)
@ -230,16 +228,7 @@ public static void AddSaveFileExtensions(IEnumerable<string> exts)
}
}
private static readonly List<string> CustomSaveExtensions =
[
"sav", // standard
"dat", // VC data
"gci", // Dolphin GameCubeImage
"dsv", // DeSmuME
"srm", // RetroArch save files
"fla", // flash
"SaveRAM", // BizHawk
];
private static List<string> CustomSaveExtensions => SaveFileMetadata.CustomSaveExtensions;
public static bool IsFileExtensionSAV(ReadOnlySpan<char> file)
{