diff --git a/src/BizHawk.Client.Common/RomLoader.cs b/src/BizHawk.Client.Common/RomLoader.cs index d47520fa08..1326eaccbc 100644 --- a/src/BizHawk.Client.Common/RomLoader.cs +++ b/src/BizHawk.Client.Common/RomLoader.cs @@ -559,7 +559,7 @@ namespace BizHawk.Client.Common RomData = rom.RomData, FileData = rom.FileData, Extension = rom.Extension, - RomPath = file.FullPathWithoutMember, + RomPath = file.CanonicalFullPath, Game = game, }, }, @@ -657,6 +657,11 @@ namespace BizHawk.Client.Common // (in general, this is kind of bad as CHD hard drives might be useful for other future cores?) private static bool IsDiscForXML(string system, string path) { + if (HawkFile.PathContainsPipe(path)) + { + return false; + } + var ext = Path.GetExtension(path); if (system is VSystemID.Raw.Arcade && ".chd".EqualsIgnoreCase(ext)) { @@ -682,21 +687,21 @@ namespace BizHawk.Client.Common Comm = nextComm, Game = game, Roms = xmlGame.Assets - .Where(kvp => !IsDiscForXML(system, kvp.Key)) - .Select(kvp => (IRomAsset)new RomAsset + .Where(pfd => !IsDiscForXML(system, pfd.Filename)) + .Select(IRomAsset (pfd) => new RomAsset { - RomData = kvp.Value, - FileData = kvp.Value, // TODO: Hope no one needed anything special here - Extension = Path.GetExtension(kvp.Key), - RomPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path.SubstringBefore('|'))!, kvp.Key!)), - Game = Database.GetGameInfo(kvp.Value, Path.GetFileName(kvp.Key)), + RomData = pfd.FileData, // TODO: Do RomGame RomData conversions here + FileData = pfd.FileData, + Extension = Path.GetExtension(pfd.Filename), + RomPath = pfd.Path, + Game = Database.GetGameInfo(pfd.FileData, Path.GetFileName(pfd.Filename)), }) .ToList(), - Discs = xmlGame.AssetFullPaths - .Where(p => IsDiscForXML(system, p)) - .Select(discPath => (p: discPath, d: DiscExtensions.CreateAnyType(discPath, str => DoLoadErrorCallback(str, system, LoadErrorType.DiscError)))) + Discs = xmlGame.Assets + .Where(pfd => IsDiscForXML(system, pfd.Path)) + .Select(pfd => (p: pfd.Path, d: DiscExtensions.CreateAnyType(pfd.Path, str => DoLoadErrorCallback(str, system, LoadErrorType.DiscError)))) .Where(a => a.d != null) - .Select(a => (IDiscAsset)new DiscAsset + .Select(IDiscAsset (a) => new DiscAsset { DiscData = a.d, DiscType = new DiscIdentifier(a.d).DetectDiscType(), diff --git a/src/BizHawk.Client.Common/XmlGame.cs b/src/BizHawk.Client.Common/XmlGame.cs index bc69b49064..b91db2c33c 100644 --- a/src/BizHawk.Client.Common/XmlGame.cs +++ b/src/BizHawk.Client.Common/XmlGame.cs @@ -8,6 +8,7 @@ using BizHawk.Common.IOExtensions; using BizHawk.Common.StringExtensions; using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores.Arcades.MAME; +using BizHawk.Emulation.DiscSystem; namespace BizHawk.Client.Common { @@ -15,8 +16,7 @@ namespace BizHawk.Client.Common { public XmlDocument Xml { get; set; } public GameInfo GI { get; } = new(); - public IList> Assets { get; } = new List>(); - public IList AssetFullPaths { get; } = new List(); // TODO: Hack work around, to avoid having to refactor Assets into a object array, should be refactored! + public IList<(string Path, string Filename, byte[] FileData)> Assets { get; } = [ ]; /// internal error public static XmlGame Create(HawkFile f) @@ -79,19 +79,26 @@ namespace BizHawk.Client.Common using var hf = new HawkFile(fullPath, allowArchives: !MAMEMachineDB.IsMAMEMachine(fullPath)); if (hf.IsArchive) { - var archiveItem = hf.ArchiveItems.First(ai => ai.Name == filename.Split('|').Skip(1).First()); + var archiveItem = hf.ArchiveItems.First(ai => ai.Name == filename.SubstringAfter('|')); hf.Unbind(); hf.BindArchiveMember(archiveItem); data = hf.GetStream().ReadAllBytes(); - filename = filename.Split('|').Skip(1).First(); + filename = filename.SubstringAfter('|'); + fullPath += $"|{filename}"; } else { - var path = fullPath.SubstringBefore('|'); - data = RomGame.Is3DSRom(Path.GetExtension(path).ToUpperInvariant()) - ? Array.Empty() - : File.ReadAllBytes(path); + var ext = Path.GetExtension(fullPath).ToUpperInvariant(); + var isArcadeChd = ret.GI.System == VSystemID.Raw.Arcade && ext == ".CHD"; + if (RomGame.Is3DSRom(ext) || (Disc.IsValidExtension(ext) && !isArcadeChd)) + { + data = [ ]; + } + else + { + data = File.ReadAllBytes(fullPath); + } } } catch (Exception e) @@ -100,8 +107,7 @@ namespace BizHawk.Client.Common } } - ret.Assets.Add(new(filename, data)); - ret.AssetFullPaths.Add(fullPath); + ret.Assets.Add((fullPath, filename, data)); var sha1 = SHA1Checksum.Compute(data); hashStream.Write(sha1, 0, sha1.Length); } diff --git a/src/BizHawk.Client.EmuHawk/MainForm.cs b/src/BizHawk.Client.EmuHawk/MainForm.cs index 44490cb5d4..307af89825 100644 --- a/src/BizHawk.Client.EmuHawk/MainForm.cs +++ b/src/BizHawk.Client.EmuHawk/MainForm.cs @@ -3841,10 +3841,9 @@ namespace BizHawk.Client.EmuHawk for (int xg = 0; xg < xmlGame.Assets.Count; xg++) { - var ext = Path.GetExtension(xmlGame.AssetFullPaths[xg])?.ToLowerInvariant(); - - var (filename, data) = xmlGame.Assets[xg]; - if (Disc.IsValidExtension(ext)) + var (_, filename, data) = xmlGame.Assets[xg]; + // data length is 0 in the case of discs or 3DS roms + if (data.Length == 0) { xSw.WriteLine(Path.GetFileNameWithoutExtension(filename)); xSw.WriteLine("SHA1:N/A"); diff --git a/src/BizHawk.Client.EmuHawk/RetroAchievements/RCheevos.Debug.cs b/src/BizHawk.Client.EmuHawk/RetroAchievements/RCheevos.Debug.cs index 2bcfb1d0c3..911460c881 100644 --- a/src/BizHawk.Client.EmuHawk/RetroAchievements/RCheevos.Debug.cs +++ b/src/BizHawk.Client.EmuHawk/RetroAchievements/RCheevos.Debug.cs @@ -7,6 +7,7 @@ using System.Windows.Forms; using BizHawk.Client.Common; using BizHawk.Common; using BizHawk.Common.PathExtensions; +using BizHawk.Common.StringExtensions; using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores.Arcades.MAME; using BizHawk.Emulation.DiscSystem; @@ -304,9 +305,9 @@ namespace BizHawk.Client.EmuHawk case ".xml": { var xml = XmlGame.Create(new(path)); - foreach (var kvp in xml.Assets) + foreach (var pfd in xml.Assets) { - InternalDebugHash(kvp.Key); + InternalDebugHash(pfd.Path); } break; diff --git a/src/BizHawk.Client.EmuHawk/RetroAchievements/RetroAchievements.GameVerification.cs b/src/BizHawk.Client.EmuHawk/RetroAchievements/RetroAchievements.GameVerification.cs index a5af1391cf..63e3e9c919 100644 --- a/src/BizHawk.Client.EmuHawk/RetroAchievements/RetroAchievements.GameVerification.cs +++ b/src/BizHawk.Client.EmuHawk/RetroAchievements/RetroAchievements.GameVerification.cs @@ -239,7 +239,7 @@ namespace BizHawk.Client.EmuHawk private uint HashArcade(string path) { // Arcade wants to just hash the filename (with no extension) - var name = Encoding.UTF8.GetBytes(Path.GetFileNameWithoutExtension(path)); + var name = Encoding.UTF8.GetBytes(Path.GetFileNameWithoutExtension(path.SubstringAfter('|'))); var hash = MD5Checksum.ComputeDigestHex(name); return IdentifyHash(hash); } @@ -451,23 +451,23 @@ namespace BizHawk.Client.EmuHawk else if (ext == ".xml") { var xml = XmlGame.Create(new(ioa.SimplePath)); - foreach (var kvp in xml.Assets) + foreach (var pfd in xml.Assets) { if (consoleID is ConsoleID.Arcade) { - ret.Add(HashArcade(kvp.Key)); + ret.Add(HashArcade(pfd.Path)); break; } if (consoleID is ConsoleID.Nintendo3DS) { - ret.Add(Hash3DS(kvp.Key)); + ret.Add(Hash3DS(pfd.Filename)); break; } - ret.Add(Disc.IsValidExtension(Path.GetExtension(kvp.Key)) - ? HashDisc(kvp.Key, consoleID) - : IdentifyRom(kvp.Value)); + ret.Add(pfd.FileData.Length == 0 + ? HashDisc(pfd.Path, consoleID) + : IdentifyRom(pfd.FileData)); } } else diff --git a/src/BizHawk.Client.EmuHawk/tools/MultiDiskBundler/MultiDiskBundler.cs b/src/BizHawk.Client.EmuHawk/tools/MultiDiskBundler/MultiDiskBundler.cs index 7a257bdf2d..93b6ec17fd 100644 --- a/src/BizHawk.Client.EmuHawk/tools/MultiDiskBundler/MultiDiskBundler.cs +++ b/src/BizHawk.Client.EmuHawk/tools/MultiDiskBundler/MultiDiskBundler.cs @@ -101,7 +101,7 @@ namespace BizHawk.Client.EmuHawk try { var xmlGame = XmlGame.Create(new HawkFile(xmlPath)); - AddFiles(xmlGame.AssetFullPaths); + AddFiles(xmlGame.Assets.Select(static pfd => pfd.Path).ToList()); } catch { diff --git a/src/BizHawk.Common/Extensions/StringExtensions.cs b/src/BizHawk.Common/Extensions/StringExtensions.cs index f3b02bf1ea..34a39cb9fe 100644 --- a/src/BizHawk.Common/Extensions/StringExtensions.cs +++ b/src/BizHawk.Common/Extensions/StringExtensions.cs @@ -153,6 +153,23 @@ namespace BizHawk.Common.StringExtensions public static bool StartsWithIgnoreCase(this string haystack, string needle) => haystack.StartsWith(needle, StringComparison.OrdinalIgnoreCase); + /// + /// the substring of after the first occurrence of , or + /// the original if not found + /// + public static string SubstringAfter(this string str, char delimiter) + => str.SubstringAfter(delimiter, notFoundValue: str); + + /// + /// the substring of after the first occurrence of , or + /// the original if not found + /// + public static string SubstringAfter(this string str, char delimiter, string notFoundValue) + { + var index = str.IndexOf(delimiter); + return index < 0 ? notFoundValue : str.Substring(index + 1, str.Length - index - 1); + } + /// /// the substring of after the first occurrence of , or /// the original if not found diff --git a/src/BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs b/src/BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs index 7da111e2dc..9ad060b87e 100644 --- a/src/BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs +++ b/src/BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs @@ -22,7 +22,7 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME [CoreConstructor(VSystemID.Raw.Arcade)] public MAME(CoreLoadParameters lp) { - _gameFileName = Path.GetFileName(lp.Roms[0].RomPath).ToLowerInvariant(); + _gameFileName = Path.GetFileName(lp.Roms[0].RomPath.SubstringAfter('|')).ToLowerInvariant(); _syncSettings = lp.SyncSettings ?? new(); ServiceProvider = new BasicServiceProvider(this); @@ -172,8 +172,8 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME // mame expects chd files in a folder of the game name string MakeFileName(IRomAsset rom) => rom.Extension.ToLowerInvariant() is ".chd" - ? gameName + '/' + Path.GetFileNameWithoutExtension(rom.RomPath).ToLowerInvariant() + rom.Extension.ToLowerInvariant() - : Path.GetFileNameWithoutExtension(rom.RomPath).ToLowerInvariant() + rom.Extension.ToLowerInvariant(); + ? gameName + '/' + Path.GetFileNameWithoutExtension(rom.RomPath.SubstringAfter('|')).ToLowerInvariant() + rom.Extension.ToLowerInvariant() + : Path.GetFileNameWithoutExtension(rom.RomPath.SubstringAfter('|')).ToLowerInvariant() + rom.Extension.ToLowerInvariant(); foreach (var rom in roms) { diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.cs index f06897c9cf..2733d5477a 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.cs @@ -3,6 +3,7 @@ using System.Runtime.InteropServices; using BizHawk.Common; using BizHawk.Common.PathExtensions; +using BizHawk.Common.StringExtensions; using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores.Components.W65816; using BizHawk.Emulation.Cores.Nintendo.SNES; @@ -24,7 +25,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES var ser = new BasicServiceProvider(this); ServiceProvider = ser; - this._romPath = Path.ChangeExtension(loadParameters.Roms[0].RomPath, null); + this._romPath = Path.ChangeExtension(loadParameters.Roms[0].RomPath.SubstringAfter('|'), null); CoreComm = loadParameters.Comm; _syncSettings = loadParameters.SyncSettings ?? new SnesSyncSettings(); SystemId = loadParameters.Game.System; diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES9X/Snes9x.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES9X/Snes9x.cs index 630606af94..bbd240c802 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES9X/Snes9x.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES9X/Snes9x.cs @@ -2,6 +2,7 @@ using System.ComponentModel; using System.IO; using BizHawk.Common; +using BizHawk.Common.StringExtensions; using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores.Waterbox; @@ -29,7 +30,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES9X SystemId = VSystemID.Raw.SNES, }) { - this._romPath = Path.ChangeExtension(loadParameters.Roms[0].RomPath, null); + this._romPath = Path.ChangeExtension(loadParameters.Roms[0].RomPath.SubstringAfter('|'), null); this._currentMsuTrack = new ProxiedFile(); LibSnes9x.OpenAudio openAudioCb = MsuOpenAudio; diff --git a/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.cs b/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.cs index be88a2155a..117bb2e532 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using BizHawk.BizInvoke; using BizHawk.Common; +using BizHawk.Common.StringExtensions; using BizHawk.Emulation.Common; using BizHawk.Emulation.DiscSystem; @@ -56,7 +57,7 @@ namespace BizHawk.Emulation.Cores.Waterbox { return DoInit( lp.Roms.Select(r => (r.RomData, - Path.GetFileName(r.RomPath[(r.RomPath.LastIndexOf('|') + 1)..])!.ToLowerInvariant())).ToArray(), + Path.GetFileName(r.RomPath.SubstringAfter('|')).ToLowerInvariant())).ToArray(), lp.Discs.Select(d => d.DiscData).ToArray(), wbxFilename, lp.Roms.FirstOrDefault()?.Extension,