BizHawk/BizHawk.Client.Common/config/PathEntryCollectionExtensio...

353 lines
11 KiB
C#

using System;
using System.IO;
using BizHawk.Common;
using BizHawk.Common.PathExtensions;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
{
public static class PathEntryExtensions
{
/// <summary>
/// Returns the base path of the given system.
/// If the system can not be found, an empty string is returned
/// </summary>
public static string BaseFor(this PathEntryCollection collection, string systemId)
{
return string.IsNullOrWhiteSpace(systemId)
? ""
: collection[systemId, "Base"]?.Path ?? "";
}
public static string GlobalBaseAbsolutePath(this PathEntryCollection collection)
{
var globalBase = collection["Global", "Base"].Path;
// if %exe% prefixed then substitute exe path and repeat
if (globalBase.StartsWith("%exe%", StringComparison.InvariantCultureIgnoreCase))
{
globalBase = PathUtils.ExeDirectoryPath + globalBase.Substring(5);
}
// rooted paths get returned without change
// (this is done after keyword substitution to avoid problems though)
if (Path.IsPathRooted(globalBase))
{
return globalBase;
}
// not-rooted things are relative to exe path
globalBase = Path.Combine(PathUtils.ExeDirectoryPath, globalBase);
return globalBase;
}
/// <summary>
/// Returns an entry for the given system and pathType (ROM, screenshot, etc)
/// but falls back to the base system or global system if it fails
/// to find pathType or systemId
/// </summary>
public static PathEntry EntryWithFallback(this PathEntryCollection collection, string pathType, string systemId)
{
return (collection[systemId, pathType]
?? collection[systemId, "Base"])
?? collection["Global", "Base"];
}
public static string AbsolutePathForType(this PathEntryCollection collection, string systemId, string type)
{
var path = collection.EntryWithFallback(type, systemId).Path;
return collection.AbsolutePathFor(path, systemId);
}
/// <summary>
/// Returns an absolute path for the given relative path.
/// If provided, the systemId will be used to generate the path.
/// Wildcards are supported.
/// Logic will fallback until an absolute path is found,
/// using Global Base as a last resort
/// </summary>
public static string AbsolutePathFor(this PathEntryCollection collection, string path, string systemId)
{
// warning: supposedly Path.GetFullPath accesses directories (and needs permissions)
// if this poses a problem, we need to paste code from .net or mono sources and fix them to not pose problems, rather than homebrew stuff
return Path.GetFullPath(collection.AbsolutePathForInner(path, systemId));
}
private static string AbsolutePathForInner(this PathEntryCollection collection, string path, string systemId)
{
// Hack
if (systemId == "Global")
{
systemId = null;
}
// This function translates relative path and special identifiers in absolute paths
if (path.Length < 1)
{
return collection.GlobalBaseAbsolutePath();
}
if (path == "%recent%")
{
return Environment.SpecialFolder.Recent.ToString();
}
if (path.StartsWith("%exe%"))
{
return PathUtils.ExeDirectoryPath + path.Substring(5);
}
if (path.StartsWith("%rom%"))
{
return collection.LastRomPath + path.Substring(5);
}
if (path[0] == '.')
{
if (!string.IsNullOrWhiteSpace(systemId))
{
path = path.Remove(0, 1);
path = path.Insert(0, collection.BaseFor(systemId));
}
if (path.Length == 1)
{
return collection.GlobalBaseAbsolutePath();
}
if (path[0] == '.')
{
path = path.Remove(0, 1);
path = path.Insert(0, collection.GlobalBaseAbsolutePath());
}
return path;
}
if (Path.IsPathRooted(path))
{
return path;
}
//handling of initial .. was removed (Path.GetFullPath can handle it)
//handling of file:// or file:\\ was removed (can Path.GetFullPath handle it? not sure)
// all bad paths default to EXE
return PathUtils.ExeDirectoryPath;
}
public static string MovieAbsolutePath(this PathEntryCollection collection)
{
var path = collection["Global", "Movies"].Path;
return collection.AbsolutePathFor(path, null);
}
public static string MovieBackupsAbsolutePath(this PathEntryCollection collection)
{
var path = collection["Global", "Movie backups"].Path;
return collection.AbsolutePathFor(path, null);
}
public static string AvAbsolutePath(this PathEntryCollection collection)
{
var path = collection["Global", "A/V Dumps"].Path;
return collection.AbsolutePathFor(path, null);
}
public static string LuaAbsolutePath(this PathEntryCollection collection)
{
var path = collection["Global", "Lua"].Path;
return collection.AbsolutePathFor(path, null);
}
public static string FirmwareAbsolutePath(this PathEntryCollection collection)
{
return collection.AbsolutePathFor(collection.FirmwaresPathFragment, null);
}
public static string LogAbsolutePath(this PathEntryCollection collection)
{
var path = collection.ResolveToolsPath(collection["Global", "Debug Logs"].Path);
return collection.AbsolutePathFor(path, null);
}
public static string WatchAbsolutePath(this PathEntryCollection collection)
{
var path = collection.ResolveToolsPath(collection["Global", "Watch (.wch)"].Path);
return collection.AbsolutePathFor(path, null);
}
public static string ToolsAbsolutePath(this PathEntryCollection collection)
{
var path = collection["Global", "Tools"].Path;
return collection.AbsolutePathFor(path, null);
}
public static string TastudioStatesAbsolutePath(this PathEntryCollection collection)
{
var path = collection["Global", "TAStudio states"].Path;
return collection.AbsolutePathFor(path, null);
}
public static string MultiDiskAbsolutePath(this PathEntryCollection collection)
{
var path = collection.ResolveToolsPath(collection["Global", "Multi-Disk Bundles"].Path);
return collection.AbsolutePathFor(path, null);
}
public static string RomAbsolutePath(this PathEntryCollection collection, string systemId = null)
{
if (string.IsNullOrWhiteSpace(systemId))
{
return collection.AbsolutePathFor(collection["Global_NULL", "ROM"].Path, "Global_NULL");
}
if (collection.UseRecentForRoms)
{
return Environment.SpecialFolder.Recent.ToString();
}
var path = collection[systemId, "ROM"];
if (!path.Path.PathIsSet())
{
path = collection["Global", "ROM"];
if (path.Path.PathIsSet())
{
return collection.AbsolutePathFor(path.Path, null);
}
}
return collection.AbsolutePathFor(path.Path, systemId);
}
public static string SaveRamAbsolutePath(this PathEntryCollection collection, GameInfo game, bool movieIsActive)
{
var name = game.FilesystemSafeName();
if (movieIsActive)
{
name += $".{Path.GetFileNameWithoutExtension(Global.MovieSession.Movie.Filename)}";
}
var pathEntry = collection[game.System, "Save RAM"]
?? collection[game.System, "Base"];
return $"{Path.Combine(collection.AbsolutePathFor(pathEntry.Path, game.System), name)}.SaveRAM";
}
// Shenanigans
public static string RetroSaveRamAbsolutePath(this PathEntryCollection collection, GameInfo game, bool movieIsActive, string movieFilename)
{
var name = game.FilesystemSafeName();
name = Path.GetDirectoryName(name);
if (name == "")
{
name = game.FilesystemSafeName();
}
if (movieIsActive)
{
name = Path.Combine(name, $"movie-{Path.GetFileNameWithoutExtension(movieFilename)}");
}
var pathEntry = collection[game.System, "Save RAM"]
?? collection[game.System, "Base"];
return Path.Combine(collection.AbsolutePathFor(pathEntry.Path, game.System), name);
}
// Shenanigans
public static string RetroSystemAbsolutePath(this PathEntryCollection collection, GameInfo game)
{
var name = game.FilesystemSafeName();
name = Path.GetDirectoryName(name);
if (string.IsNullOrEmpty(name))
{
name = game.FilesystemSafeName();
}
var pathEntry = collection[game.System, "System"]
?? collection[game.System, "Base"];
return Path.Combine(collection.AbsolutePathFor(pathEntry.Path, game.System), name);
}
public static string AutoSaveRamAbsolutePath(this PathEntryCollection collection, GameInfo game, bool movieIsActive)
{
var path = collection.SaveRamAbsolutePath(game, movieIsActive);
return path.Insert(path.Length - 8, ".AutoSaveRAM");
}
public static string CheatsAbsolutePath(this PathEntryCollection collection, string systemId)
{
var pathEntry = collection[systemId, "Cheats"]
?? collection[systemId, "Base"];
return collection.AbsolutePathFor(pathEntry.Path,systemId);
}
public static string SaveStateAbsolutePath(this PathEntryCollection collection, string systemId)
{
var pathEntry = collection[systemId, "Savestates"]
?? collection[systemId, "Base"];
return collection.AbsolutePathFor(pathEntry.Path, systemId);
}
public static string ScreenshotAbsolutePathFor(this PathEntryCollection collection, string systemId)
{
var entry = collection[systemId, "Screenshots"]
?? collection[systemId, "Base"];
return collection.AbsolutePathFor(entry.Path, systemId);
}
public static string PalettesAbsolutePathFor(this PathEntryCollection collection, string systemId)
{
return collection.AbsolutePathFor(collection[systemId, "Palettes"].Path, systemId);
}
/// <summary>
/// Takes an absolute path and attempts to convert it to a relative, based on the system,
/// or global base if no system is supplied, if it is not a subfolder of the base, it will return the path unaltered
/// </summary>
public static string TryMakeRelative(this PathEntryCollection collection, string absolutePath, string system = null) => absolutePath.MakeRelativeTo(
string.IsNullOrWhiteSpace(system)
? collection.GlobalBaseAbsolutePath()
: collection.AbsolutePathFor(collection.BaseFor(system), system)
);
/// <summary>
/// Puts the currently configured temp path into the environment for use as actual temp directory
/// </summary>
public static void RefreshTempPath(this PathEntryCollection collection)
{
if (!string.IsNullOrWhiteSpace(collection.TempFilesFragment))
{
// TODO - BUG - needs to route through PathManager.MakeAbsolutePath or something similar, but how?
string target = collection.TempFilesFragment;
TempFileManager.HelperSetTempPath(target);
}
}
private static string ResolveToolsPath(this PathEntryCollection collection, string subPath)
{
if (Path.IsPathRooted(subPath) || subPath.StartsWith("%"))
{
return subPath;
}
var toolsPath = collection["Global", "Tools"].Path;
// Hack for backwards compatibility, prior to 1.11.5, .wch files were in .\Tools, we don't want that to turn into .Tools\Tools
if (subPath == "Tools")
{
return toolsPath;
}
return Path.Combine(toolsPath, subPath);
}
}
}