private bool HandleArchiveBinding(HawkFile file) { var romExtensions = new[] { "SMS", "SMC", "SFC", "PCE", "SGX", "GG", "SG", "BIN", "GEN", "MD", "SMD", "GB", "NES", "FDS", "ROM", "INT", "GBC", "UNF", "A78", "CRT", "COL", "XML", "Z64", "V64", "N64", "WS", "WSC", "GBA", "32X", "VEC", "O2" }; // try binding normal rom extensions first if (!file.IsBound) { file.BindSoleItemOf(romExtensions); } // if we have an archive and need to bind something, then pop the dialog if (file.IsArchive && !file.IsBound) { int?result = HandleArchive(file); if (result.HasValue) { file.BindArchiveMember(result.Value); } else { return(false); } } CanonicalFullPath = file.CanonicalFullPath; return(true); }
private bool HandleArchiveBinding(HawkFile file) { var romExtensions = new[] { ".sms", ".smc", ".sfc", ".pce", ".sgx", ".gg", ".sg", ".bin", ".gen", ".md", ".smd", ".gb", ".nes", ".fds", ".rom", ".int", ".gbc", ".unf", ".a78", ".crt", ".col", ".xml", ".z64", ".v64", ".n64", ".ws", ".wsc", ".gba", ".32x", ".vec", ".o2" }; // try binding normal rom extensions first if (!file.IsBound) { file.BindSoleItemOf(romExtensions); } // if we have an archive and need to bind something, then pop the dialog if (file.IsArchive && !file.IsBound) { int?result = HandleArchive(file); if (result.HasValue) { file.BindArchiveMember(result.Value); } else { return(false); } } CanonicalFullPath = file.CanonicalFullPath; return(true); }
private void RunImportJob(IEnumerable <string> files) { bool didSomething = false; var basePath = PathManager.MakeAbsolutePath(Global.Config.PathEntries.FirmwaresPathFragment, null); string errors = ""; foreach (var f in files) { using var hf = new HawkFile(f); if (hf.IsArchive) { // blech. the worst extraction code in the universe. string extractPath = $"{Path.GetTempFileName()}.dir"; DirectoryInfo di = Directory.CreateDirectory(extractPath); try { foreach (var ai in hf.ArchiveItems) { hf.BindArchiveMember(ai); var stream = hf.GetStream(); var ms = new MemoryStream(); Util.CopyStream(hf.GetStream(), ms, stream.Length); string outfile = ai.Name; string myname = Path.GetFileName(outfile); outfile = Path.Combine(extractPath, myname); File.WriteAllBytes(outfile, ms.ToArray()); hf.Unbind(); if (_cbAllowImport.Checked || Manager.CanFileBeImported(outfile)) { didSomething |= RunImportJobSingle(basePath, outfile, ref errors); } } } finally { di.Delete(true); } } else { if (_cbAllowImport.Checked || Manager.CanFileBeImported(hf.CanonicalFullPath)) { didSomething |= RunImportJobSingle(basePath, f, ref errors); } } } if (!string.IsNullOrEmpty(errors)) { MessageBox.Show(errors, "Error importing these files"); } if (didSomething) { DoScan(); } }
void RunImportJob(IEnumerable <string> files) { bool didSomething = false; var basepath = PathManager.MakeAbsolutePath(Global.Config.PathEntries.FirmwaresPathFragment, null); string errors = ""; foreach (var f in files) { using (var hf = new HawkFile(f)) { if (hf.IsArchive) { //blech. the worst extraction code in the universe. string extractpath = System.IO.Path.GetTempFileName() + ".dir"; DirectoryInfo di = null; di = System.IO.Directory.CreateDirectory(extractpath); try { foreach (var ai in hf.ArchiveItems) { hf.BindArchiveMember(ai); var stream = hf.GetStream(); var ms = new MemoryStream(); Util.CopyStream(hf.GetStream(), ms, stream.Length); string outfile = ai.Name; string myname = Path.GetFileName(outfile); outfile = Path.Combine(extractpath, myname); File.WriteAllBytes(outfile, ms.ToArray()); hf.Unbind(); didSomething |= RunImportJobSingle(basepath, outfile, ref errors); } } finally { di.Delete(true); } } else { didSomething |= RunImportJobSingle(basepath, f, ref errors); } } } if (errors != "") { System.Windows.Forms.MessageBox.Show(errors, "Error importing these files"); } if (didSomething) { DoScan(); } }
public static XmlGame Create(HawkFile f) { try { var x = new XmlDocument(); x.Load(f.GetStream()); var y = x.SelectSingleNode("./BizHawk-XMLGame"); if (y == null) { return(null); } var ret = new XmlGame { GI = { System = y.Attributes["System"].Value, Name = y.Attributes["Name"].Value, Status = RomStatus.Unknown }, Xml = x }; var n = y.SelectSingleNode("./LoadAssets"); if (n != null) { var HashStream = new MemoryStream(); int?OriginalIndex = null; foreach (XmlNode a in n.ChildNodes) { string filename = a.Attributes["FileName"].Value; byte[] data = new byte[0]; if (filename[0] == '|') { // in same archive var ai = f.FindArchiveMember(filename.Substring(1)); if (ai != null) { if (OriginalIndex == null) { OriginalIndex = f.GetBoundIndex(); } f.Unbind(); f.BindArchiveMember(ai); data = f.GetStream().ReadAllBytes(); } else { throw new Exception("Couldn't load XMLGame Asset \"" + filename + "\""); } } else { // relative path var fullpath = Path.GetDirectoryName(f.CanonicalFullPath.Split('|').First()) ?? string.Empty; fullpath = Path.Combine(fullpath, filename.Split('|').First()); try { using (var hf = new HawkFile(fullpath)) { if (hf.IsArchive) { var archiveItem = hf.ArchiveItems.First(ai => ai.Name == filename.Split('|').Skip(1).First()); hf.Unbind(); hf.BindArchiveMember(archiveItem); data = hf.GetStream().ReadAllBytes(); } else { data = File.ReadAllBytes(fullpath.Split('|').First()); } } } catch { throw new Exception("Couldn't load XMLGame LoadAsset \"" + filename + "\""); } } ret.Assets.Add(new KeyValuePair <string, byte[]>(filename, data)); using (var sha1 = System.Security.Cryptography.SHA1.Create()) { sha1.TransformFinalBlock(data, 0, data.Length); HashStream.Write(sha1.Hash, 0, sha1.Hash.Length); } } ret.GI.Hash = HashStream.GetBuffer().HashSHA1(0, (int)HashStream.Length); HashStream.Close(); if (OriginalIndex != null) { f.Unbind(); f.BindArchiveMember((int)OriginalIndex); } } else { ret.GI.Hash = "0000000000000000000000000000000000000000"; } return(ret); } catch (Exception ex) { throw new InvalidOperationException(ex.ToString()); } }
private void tsmiSetCustomization_Click(object sender, EventArgs e) { using (var ofd = new OpenFileDialog()) { ofd.InitialDirectory = currSelectorDir; ofd.RestoreDirectory = true; string frmwarePath = PathManager.MakeAbsolutePath(Global.Config.PathEntries.FirmwaresPathFragment, null); if (ofd.ShowDialog() == DialogResult.OK) { // remember the location we selected this firmware from, maybe there are others currSelectorDir = Path.GetDirectoryName(ofd.FileName); try { using (var hf = new HawkFile(ofd.FileName)) { // for each selected item, set the user choice (even though multiple selection for this operation is no longer allowed) foreach (ListViewItem lvi in lvFirmwares.SelectedItems) { var fr = lvi.Tag as FirmwareDatabase.FirmwareRecord; string filePath = ofd.FileName; // if the selected file is an archive, allow the user to pick the inside file // to always be copied to the global firmwares directory if (hf.IsArchive) { var ac = new ArchiveChooser(new HawkFile(filePath)); int memIdx = -1; if (ac.ShowDialog(this) == DialogResult.OK) { memIdx = ac.SelectedMemberIndex; } else { return; } var insideFile = hf.BindArchiveMember(memIdx); var fileData = insideFile.ReadAllBytes(); // write to file in the firmwares folder File.WriteAllBytes(Path.Combine(frmwarePath, insideFile.Name), fileData); filePath = Path.Combine(frmwarePath, insideFile.Name); } else { // selected file is not an archive // check whether this file is currently outside of the global firmware directory if (currSelectorDir != frmwarePath) { var askMoveResult = MessageBox.Show(this, "The selected custom firmware does not reside in the root of the global firmware directory.\nDo you want to copy it there?", "Import Custom Firmware", MessageBoxButtons.YesNo); if (askMoveResult == DialogResult.Yes) { try { FileInfo fi = new FileInfo(filePath); filePath = Path.Combine(frmwarePath, fi.Name); File.Copy(ofd.FileName, filePath); } catch (Exception ex) { MessageBox.Show(this, $"There was an issue copying the file. The customization has NOT been set.\n\n{ex.StackTrace}"); continue; } } } } Global.Config.FirmwareUserSpecifications[fr.ConfigKey] = filePath; } } } catch (Exception ex) { MessageBox.Show(this, $"There was an issue during the process. The customization has NOT been set.\n\n{ex.StackTrace}"); return; } DoScan(); } } }
public bool LoadRom(string path, CoreComm nextComm, bool forceAccurateCore = false) // forceAccurateCore is currently just for Quicknes vs Neshawk but could be used for other situations { bool cancel = false; if (path == null) { return(false); } using (var file = new HawkFile()) { var romExtensions = new[] { "SMS", "SMC", "SFC", "PCE", "SGX", "GG", "SG", "BIN", "GEN", "MD", "SMD", "GB", "NES", "FDS", "ROM", "INT", "GBC", "UNF", "A78", "CRT", "COL", "XML", "Z64", "V64", "N64", "WS", "WSC", "GBA" }; // lets not use this unless we need to // file.NonArchiveExtensions = romExtensions; file.Open(path); // if the provided file doesnt even exist, give up! if (!file.Exists) { return(false); } // try binding normal rom extensions first if (!file.IsBound) { file.BindSoleItemOf(romExtensions); } // if we have an archive and need to bind something, then pop the dialog if (file.IsArchive && !file.IsBound) { int?result = HandleArchive(file); if (result.HasValue) { file.BindArchiveMember(result.Value); } else { return(false); } } // set this here so we can see what file we tried to load even if an error occurs CanonicalFullPath = file.CanonicalFullPath; IEmulator nextEmulator = null; RomGame rom = null; GameInfo game = null; try { var ext = file.Extension.ToLower(); if (ext == ".m3u") { //HACK ZONE - currently only psx supports m3u M3U_File m3u; using (var sr = new StreamReader(path)) m3u = M3U_File.Read(sr); if (m3u.Entries.Count == 0) { throw new InvalidOperationException("Can't load an empty M3U"); } //load discs for all the m3u m3u.Rebase(Path.GetDirectoryName(path)); List <Disc> discs = new List <Disc>(); List <string> discNames = new List <string>(); foreach (var e in m3u.Entries) { Disc disc = null; string discPath = e.Path; string discExt = Path.GetExtension(discPath).ToLower(); if (discExt == ".iso") { disc = Disc.FromIsoPath(discPath); } if (discExt == ".cue") { disc = Disc.FromCuePath(discPath, new CueBinPrefs()); } if (discExt == ".ccd") { disc = Disc.FromCCDPath(discPath); } if (disc == null) { throw new InvalidOperationException("Can't load one of the files specified in the M3U"); } discNames.Add(Path.GetFileNameWithoutExtension(discPath)); discs.Add(disc); } nextEmulator = new Octoshock(nextComm, discs, discNames, null, GetCoreSettings <Octoshock>(), GetCoreSyncSettings <Octoshock>()); nextEmulator.CoreComm.RomStatusDetails = "PSX etc."; game = new GameInfo { Name = Path.GetFileNameWithoutExtension(file.Name) }; game.System = "PSX"; } else if (ext == ".iso" || ext == ".cue" || ext == ".ccd") { if (file.IsArchive) { throw new InvalidOperationException("Can't load CD files from archives!"); } Disc disc = null; if (ext == ".iso") { disc = Disc.FromIsoPath(path); } if (ext == ".cue") { disc = Disc.FromCuePath(path, new CueBinPrefs()); } if (ext == ".ccd") { disc = Disc.FromCCDPath(path); } var hash = disc.GetHash(); game = Database.CheckDatabase(hash); if (game == null) { // try to use our wizard methods game = new GameInfo { Name = Path.GetFileNameWithoutExtension(file.Name), Hash = hash }; switch (disc.DetectDiscType()) { case DiscType.SegaSaturn: game.System = "SAT"; break; case DiscType.SonyPSP: game.System = "PSP"; break; default: case DiscType.SonyPSX: game.System = "PSX"; break; case DiscType.MegaCD: game.System = "GEN"; break; case DiscType.TurboCD: case DiscType.UnknownCDFS: case DiscType.UnknownFormat: game.System = "PCECD"; break; } } switch (game.System) { case "GEN": var genesis = new GPGX( nextComm, null, disc, GetCoreSettings <GPGX>(), GetCoreSyncSettings <GPGX>()); nextEmulator = genesis; break; case "SAT": nextEmulator = new Yabause(nextComm, disc, GetCoreSyncSettings <Yabause>()); break; case "PSP": nextEmulator = new PSP(nextComm, file.Name); break; case "PSX": nextEmulator = new Octoshock(nextComm, new List <Disc>(new[] { disc }), new List <string>(new[] { Path.GetFileNameWithoutExtension(path) }), null, GetCoreSettings <Octoshock>(), GetCoreSyncSettings <Octoshock>()); nextEmulator.CoreComm.RomStatusDetails = "PSX etc."; break; case "PCE": case "PCECD": nextEmulator = new PCEngine(nextComm, game, disc, GetCoreSettings <PCEngine>(), GetCoreSyncSettings <PCEngine>()); break; } } else if (file.Extension.ToLower() == ".xml") { try { var xmlGame = XmlGame.Create(file); // if load fails, are we supposed to retry as a bsnes XML???????? game = xmlGame.GI; switch (game.System) { case "DGB": var left = Database.GetGameInfo(xmlGame.Assets["LeftRom"], "left.gb"); var right = Database.GetGameInfo(xmlGame.Assets["RightRom"], "right.gb"); nextEmulator = new GambatteLink( nextComm, left, xmlGame.Assets["LeftRom"], right, xmlGame.Assets["RightRom"], GetCoreSettings <GambatteLink>(), GetCoreSyncSettings <GambatteLink>(), Deterministic); // other stuff todo break; case "AppleII": var assets = xmlGame.Assets.Select(a => Database.GetGameInfo(a.Value, a.Key)); var roms = xmlGame.Assets.Select(a => a.Value); nextEmulator = new AppleII( nextComm, assets, roms, GetCoreSettings <AppleII>()); break; default: return(false); } } catch (Exception ex) { try { // need to get rid of this hack at some point rom = new RomGame(file); ((CoreFileProvider)nextComm.CoreFileProvider).SubfileDirectory = Path.GetDirectoryName(path.Replace("|", String.Empty)); // Dirty hack to get around archive filenames (since we are just getting the directory path, it is safe to mangle the filename byte[] romData = null; byte[] xmlData = rom.FileData; game = rom.GameInfo; game.System = "SNES"; var snes = new LibsnesCore(game, romData, Deterministic, xmlData, nextComm, GetCoreSettings <LibsnesCore>(), GetCoreSyncSettings <LibsnesCore>()); nextEmulator = snes; } catch { DoLoadErrorCallback(ex.ToString(), "DGB", LoadErrorType.XML); return(false); } } } else // most extensions { rom = new RomGame(file); //hacky for now if (file.Extension.ToLower() == ".exe") { rom.GameInfo.System = "PSX"; } if (string.IsNullOrEmpty(rom.GameInfo.System)) { // Has the user picked a preference for this extension? if (PreferredPlatformIsDefined(rom.Extension.ToLower())) { rom.GameInfo.System = Global.Config.PreferredPlatformsForExtensions[rom.Extension.ToLower()]; } else if (ChoosePlatform != null) { var result = ChoosePlatform(rom); if (!string.IsNullOrEmpty(result)) { rom.GameInfo.System = ChoosePlatform(rom); } else { cancel = true; } } } game = rom.GameInfo; var isXml = false; // other xml has already been handled if (file.Extension.ToLower() == ".xml") { game.System = "SNES"; isXml = true; } CoreInventory.Core core = null; switch (game.System) { default: core = CoreInventory.Instance[game.System]; break; case null: // The user picked nothing in the Core picker break; case "83P": var ti83Bios = ((CoreFileProvider)nextComm.CoreFileProvider).GetFirmware("TI83", "Rom", true); var ti83BiosPath = ((CoreFileProvider)nextComm.CoreFileProvider).GetFirmwarePath("TI83", "Rom", true); using (var ti83AsHawkFile = new HawkFile()) { ti83AsHawkFile.Open(ti83BiosPath); var ti83BiosAsRom = new RomGame(ti83AsHawkFile); var ti83 = new TI83(nextComm, ti83BiosAsRom.GameInfo, ti83Bios, GetCoreSettings <TI83>()); ti83.LinkPort.SendFileToCalc(File.OpenRead(path), false); nextEmulator = ti83; } break; case "SNES": if (Global.Config.SNES_InSnes9x && VersionInfo.DeveloperBuild) { core = CoreInventory.Instance["SNES", "Snes9x"]; } else { // need to get rid of this hack at some point ((CoreFileProvider)nextComm.CoreFileProvider).SubfileDirectory = Path.GetDirectoryName(path.Replace("|", String.Empty)); // Dirty hack to get around archive filenames (since we are just getting the directory path, it is safe to mangle the filename var romData = isXml ? null : rom.FileData; var xmlData = isXml ? rom.FileData : null; var snes = new LibsnesCore(game, romData, Deterministic, xmlData, nextComm, GetCoreSettings <LibsnesCore>(), GetCoreSyncSettings <LibsnesCore>()); nextEmulator = snes; } break; case "NES": if (!Global.Config.NES_InQuickNES || forceAccurateCore) { core = CoreInventory.Instance["NES", "NesHawk"]; } else { core = CoreInventory.Instance["NES", "QuickNes"]; } break; case "GB": case "GBC": if (!Global.Config.GB_AsSGB) { core = CoreInventory.Instance["GB", "Gambatte"]; } else { try { game.System = "SNES"; game.AddOption("SGB"); var snes = new LibsnesCore(game, rom.FileData, Deterministic, null, nextComm, GetCoreSettings <LibsnesCore>(), GetCoreSyncSettings <LibsnesCore>()); nextEmulator = snes; } catch { // failed to load SGB bios or game does not support SGB mode. // To avoid catch-22, disable SGB mode Global.Config.GB_AsSGB = false; throw; } } break; case "A78": var gamedbpath = Path.Combine(PathManager.GetExeDirectoryAbsolute(), "gamedb", "EMU7800.csv"); nextEmulator = new Atari7800(nextComm, game, rom.RomData, gamedbpath); break; case "C64": var c64 = new C64(nextComm, game, rom.RomData, rom.Extension); nextEmulator = c64; break; case "AppleII": var appleII = new AppleII(nextComm, game, rom.RomData, rom.Extension); nextEmulator = appleII; break; case "GBA": //core = CoreInventory.Instance["GBA", "Meteor"]; core = CoreInventory.Instance["GBA", "VBA-Next"]; break; case "PSX": nextEmulator = new Octoshock(nextComm, null, null, rom.FileData, GetCoreSettings <Octoshock>(), GetCoreSyncSettings <Octoshock>()); nextEmulator.CoreComm.RomStatusDetails = "PSX etc."; break; case "DEBUG": if (VersionInfo.DeveloperBuild) { nextEmulator = LibRetroEmulator.CreateDebug(nextComm, rom.RomData); } break; } if (core != null) { // use coreinventory nextEmulator = core.Create(nextComm, game, rom.RomData, rom.FileData, Deterministic, GetCoreSettings(core.Type), GetCoreSyncSettings(core.Type)); } } if (nextEmulator == null) { if (!cancel) { DoLoadErrorCallback("No core could load the rom.", null); } return(false); } } catch (Exception ex) { string system = null; if (game != null) { system = game.System; } // all of the specific exceptions we're trying to catch here aren't expected to have inner exceptions, // so drill down in case we got a TargetInvocationException or something like that while (ex.InnerException != null) { ex = ex.InnerException; } // Specific hack here, as we get more cores of the same system, this isn't scalable if (ex is UnsupportedGameException) { if (system == "NES") { DoMessageCallback("Unable to use quicknes, using NESHawk instead"); } return(LoadRom(path, nextComm, forceAccurateCore: true)); } else if (ex is MissingFirmwareException) { DoLoadErrorCallback(ex.Message, system, LoadErrorType.MissingFirmware); } else if (ex is CGBNotSupportedException) { // Note: GB as SGB was set to false by this point, otherwise we would want to do it here DoMessageCallback("Failed to load a GB rom in SGB mode. Disabling SGB Mode."); return(LoadRom(path, nextComm)); } else { DoLoadErrorCallback("A core accepted the rom, but threw an exception while loading it:\n\n" + ex, system); } return(false); } Rom = rom; LoadedEmulator = nextEmulator; Game = game; return(true); } }
protected override void RunImport() { Result.Movie.HeaderEntries[HeaderKeys.Core] = CoreNames.Bsnes; var hf = new HawkFile(SourceFile.FullName); // .LSMV movies are .zip files containing data files. if (!hf.IsArchive) { Result.Errors.Add("This is not an archive."); return; } var ss = new LibsnesCore.SnesSyncSettings { LeftPort = LibsnesControllerDeck.ControllerType.Gamepad, RightPort = LibsnesControllerDeck.ControllerType.Gamepad }; _deck = new LibsnesControllerDeck(ss); string platform = "SNES"; foreach (var item in hf.ArchiveItems) { if (item.Name == "authors") { hf.BindArchiveMember(item.Index); var stream = hf.GetStream(); string authors = Encoding.UTF8.GetString(stream.ReadAllBytes()); string authorList = ""; string authorLast = ""; using (var reader = new StringReader(authors)) { string line; // Each author is on a different line. while ((line = reader.ReadLine()) != null) { string author = line.Trim(); if (author != "") { if (authorLast != "") { authorList += $"{authorLast}, "; } authorLast = author; } } } if (authorList != "") { authorList += "and "; } if (authorLast != "") { authorList += authorLast; } Result.Movie.HeaderEntries[HeaderKeys.Author] = authorList; hf.Unbind(); } else if (item.Name == "coreversion") { hf.BindArchiveMember(item.Index); var stream = hf.GetStream(); string coreVersion = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim(); Result.Movie.Comments.Add($"CoreOrigin {coreVersion}"); hf.Unbind(); } else if (item.Name == "gamename") { hf.BindArchiveMember(item.Index); var stream = hf.GetStream(); string gameName = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim(); Result.Movie.HeaderEntries[HeaderKeys.GameName] = gameName; hf.Unbind(); } else if (item.Name == "gametype") { hf.BindArchiveMember(item.Index); var stream = hf.GetStream(); string gametype = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim(); // TODO: Handle the other types. switch (gametype) { case "gdmg": platform = "GB"; break; case "ggbc": case "ggbca": platform = "GBC"; break; case "sgb_ntsc": case "sgb_pal": platform = "SNES"; Config.GbAsSgb = true; break; } bool pal = gametype == "snes_pal" || gametype == "sgb_pal"; Result.Movie.HeaderEntries[HeaderKeys.Pal] = pal.ToString(); hf.Unbind(); } else if (item.Name == "input") { hf.BindArchiveMember(item.Index); var stream = hf.GetStream(); string input = Encoding.UTF8.GetString(stream.ReadAllBytes()); int lineNum = 0; using (var reader = new StringReader(input)) { lineNum++; string line; while ((line = reader.ReadLine()) != null) { if (line == "") { continue; } // Insert an empty frame in lsmv snes movies // https://github.com/TASVideos/BizHawk/issues/721 // Both emulators send the input to bsnes core at the same V interval, but: // lsnes' frame boundary occurs at V = 241, after which the input is read; // BizHawk's frame boundary is just before automatic polling; // This isn't a great place to add this logic but this code is a mess if (lineNum == 1 && platform == "SNES") { // Note that this logic assumes the first non-empty log entry is a valid input log entry // and that it is NOT a subframe input entry. It seems safe to assume subframe input would not be on the first line Result.Movie.AppendFrame(EmptyLmsvFrame()); } ImportTextFrame(line, platform); } } hf.Unbind(); } else if (item.Name.StartsWith("moviesram.")) { hf.BindArchiveMember(item.Index); var stream = hf.GetStream(); byte[] movieSram = stream.ReadAllBytes(); if (movieSram.Length != 0) { Result.Errors.Add("Movies that begin with SRAM are not supported."); hf.Unbind(); return; } } else if (item.Name == "port1") { hf.BindArchiveMember(item.Index); var stream = hf.GetStream(); string port1 = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim(); Result.Movie.HeaderEntries["port1"] = port1; ss.LeftPort = LibsnesControllerDeck.ControllerType.Gamepad; _deck = new LibsnesControllerDeck(ss); hf.Unbind(); } else if (item.Name == "port2") { hf.BindArchiveMember(item.Index); var stream = hf.GetStream(); string port2 = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim(); Result.Movie.HeaderEntries["port2"] = port2; ss.RightPort = LibsnesControllerDeck.ControllerType.Gamepad; _deck = new LibsnesControllerDeck(ss); hf.Unbind(); } else if (item.Name == "projectid") { hf.BindArchiveMember(item.Index); var stream = hf.GetStream(); string projectId = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim(); Result.Movie.HeaderEntries["ProjectID"] = projectId; hf.Unbind(); } else if (item.Name == "rerecords") { hf.BindArchiveMember(item.Index); var stream = hf.GetStream(); string rerecords = Encoding.UTF8.GetString(stream.ReadAllBytes()); int rerecordCount; // Try to parse the re-record count as an integer, defaulting to 0 if it fails. try { rerecordCount = int.Parse(rerecords); } catch { rerecordCount = 0; } Result.Movie.Rerecords = (ulong)rerecordCount; hf.Unbind(); } else if (item.Name.EndsWith(".sha256")) { hf.BindArchiveMember(item.Index); var stream = hf.GetStream(); string rom = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim(); int pos = item.Name.LastIndexOf(".sha256"); string name = item.Name.Substring(0, pos); Result.Movie.HeaderEntries[$"SHA256_{name}"] = rom; hf.Unbind(); } else if (item.Name == "savestate") { Result.Errors.Add("Movies that begin with a savestate are not supported."); return; } else if (item.Name == "subtitles") { hf.BindArchiveMember(item.Index); var stream = hf.GetStream(); string subtitles = Encoding.UTF8.GetString(stream.ReadAllBytes()); using (var reader = new StringReader(subtitles)) { string line; while ((line = reader.ReadLine()) != null) { var subtitle = ImportTextSubtitle(line); if (!string.IsNullOrEmpty(subtitle)) { Result.Movie.Subtitles.AddFromString(subtitle); } } } hf.Unbind(); } else if (item.Name == "starttime.second") { hf.BindArchiveMember(item.Index); var stream = hf.GetStream(); string startSecond = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim(); Result.Movie.HeaderEntries["StartSecond"] = startSecond; hf.Unbind(); } else if (item.Name == "starttime.subsecond") { hf.BindArchiveMember(item.Index); var stream = hf.GetStream(); string startSubSecond = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim(); Result.Movie.HeaderEntries["StartSubSecond"] = startSubSecond; hf.Unbind(); } else if (item.Name == "systemid") { hf.BindArchiveMember(item.Index); var stream = hf.GetStream(); string systemId = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim(); Result.Movie.Comments.Add($"{EmulationOrigin} {systemId}"); hf.Unbind(); } } Result.Movie.HeaderEntries[HeaderKeys.Platform] = platform; Result.Movie.SyncSettingsJson = ConfigService.SaveWithType(ss); Config.PreferredCores["SNES"] = CoreNames.Bsnes; // TODO: convert to snes9x if it is the user's preference }
} = new List <string>(); // TODO: Hack work around, to avoid having to refactor Assets into a object array, should be refactored! /// <exception cref="InvalidOperationException">internal error</exception> public static XmlGame Create(HawkFile f) { try { var x = new XmlDocument(); x.Load(f.GetStream()); var y = x.SelectSingleNode("./BizHawk-XMLGame"); if (y == null) { return(null); } var ret = new XmlGame { GI = { System = y.Attributes["System"].Value, Name = y.Attributes["Name"].Value, Status = RomStatus.Unknown }, Xml = x }; string fullPath = ""; var n = y.SelectSingleNode("./LoadAssets"); if (n != null) { var hashStream = new MemoryStream(); int?originalIndex = null; foreach (XmlNode a in n.ChildNodes) { string filename = a.Attributes["FileName"].Value; byte[] data; if (filename[0] == '|') { // in same archive var ai = f.FindArchiveMember(filename.Substring(1)); if (ai != null) { originalIndex ??= f.BoundIndex; f.Unbind(); f.BindArchiveMember(ai.Value); data = f.GetStream().ReadAllBytes(); } else { throw new Exception($"Couldn't load XMLGame Asset \"{filename}\""); } } else { // relative path fullPath = Path.GetDirectoryName(f.CanonicalFullPath.Split('|').First()) ?? ""; fullPath = Path.Combine(fullPath, filename.Split('|').First()); try { using var hf = new HawkFile(fullPath); if (hf.IsArchive) { var archiveItem = hf.ArchiveItems.First(ai => ai.Name == filename.Split('|').Skip(1).First()); hf.Unbind(); hf.BindArchiveMember(archiveItem); data = hf.GetStream().ReadAllBytes(); filename = filename.Split('|').Skip(1).First(); } else { data = File.ReadAllBytes(fullPath.Split('|').First()); } } catch { throw new Exception($"Couldn't load XMLGame LoadAsset \"{filename}\""); } } ret.Assets.Add(new KeyValuePair <string, byte[]>(filename, data)); ret.AssetFullPaths.Add(fullPath); var sha1 = SHA1Checksum.Compute(data); hashStream.Write(sha1, 0, sha1.Length); } ret.GI.Hash = SHA1Checksum.ComputeDigestHex(hashStream.GetBufferAsSpan()); hashStream.Close(); if (originalIndex != null) { f.Unbind(); f.BindArchiveMember((int)originalIndex); } } else { ret.GI.Hash = SHA1Checksum.Zero; } return(ret); } catch (Exception ex) { throw new InvalidOperationException(ex.ToString()); } }
public bool LoadRom(string path, CoreComm nextComm, bool forceAccurateCore = false, int recursiveCount = 0) // forceAccurateCore is currently just for Quicknes vs Neshawk but could be used for other situations { if (recursiveCount > 1) // hack to stop recursive calls from endlessly rerunning if we can't load it { DoLoadErrorCallback("Failed multiple attempts to load ROM.", ""); return(false); } bool cancel = false; if (path == null) { return(false); } using (var file = new HawkFile()) { var romExtensions = new[] { "SMS", "SMC", "SFC", "PCE", "SGX", "GG", "SG", "BIN", "GEN", "MD", "SMD", "GB", "NES", "FDS", "ROM", "INT", "GBC", "UNF", "A78", "CRT", "COL", "XML", "Z64", "V64", "N64", "WS", "WSC", "GBA" }; // lets not use this unless we need to // file.NonArchiveExtensions = romExtensions; file.Open(path); // if the provided file doesnt even exist, give up! if (!file.Exists) { return(false); } // try binding normal rom extensions first if (!file.IsBound) { file.BindSoleItemOf(romExtensions); } // if we have an archive and need to bind something, then pop the dialog if (file.IsArchive && !file.IsBound) { int?result = HandleArchive(file); if (result.HasValue) { file.BindArchiveMember(result.Value); } else { return(false); } } // set this here so we can see what file we tried to load even if an error occurs CanonicalFullPath = file.CanonicalFullPath; IEmulator nextEmulator = null; RomGame rom = null; GameInfo game = null; try { var ext = file.Extension.ToLowerInvariant(); if (ext == ".m3u") { //HACK ZONE - currently only psx supports m3u M3U_File m3u; using (var sr = new StreamReader(path)) m3u = M3U_File.Read(sr); if (m3u.Entries.Count == 0) { throw new InvalidOperationException("Can't load an empty M3U"); } //load discs for all the m3u m3u.Rebase(Path.GetDirectoryName(path)); List <Disc> discs = new List <Disc>(); List <string> discNames = new List <string>(); StringWriter sw = new StringWriter(); foreach (var e in m3u.Entries) { Disc disc = null; string discPath = e.Path; //--- load the disc in a context which will let us abort if it's going to take too long var discMountJob = new DiscMountJob { IN_FromPath = discPath }; discMountJob.IN_SlowLoadAbortThreshold = 8; discMountJob.Run(); disc = discMountJob.OUT_Disc; if (discMountJob.OUT_SlowLoadAborted) { System.Windows.Forms.MessageBox.Show("This disc would take too long to load. Run it through discohawk first, or find a new rip because this one is probably junk"); return(false); } if (discMountJob.OUT_ErrorLevel) { throw new InvalidOperationException(discMountJob.OUT_Log); } if (disc == null) { throw new InvalidOperationException("Can't load one of the files specified in the M3U"); } var discName = Path.GetFileNameWithoutExtension(discPath); discNames.Add(discName); discs.Add(disc); var discType = new DiscIdentifier(disc).DetectDiscType(); sw.WriteLine("{0}", Path.GetFileName(discPath)); if (discType == DiscType.SonyPSX) { string discHash = new DiscHasher(disc).Calculate_PSX_BizIDHash().ToString("X8"); game = Database.CheckDatabase(discHash); if (game == null || game.IsRomStatusBad() || game.Status == RomStatus.NotInDatabase) { sw.WriteLine("Disc could not be identified as known-good. Look for a better rip."); } else { sw.WriteLine("Disc was identified (99.99% confidently) as known good with disc id hash CRC32:{0:X8}", discHash); sw.WriteLine("Nonetheless it could be an unrecognized romhack or patched version."); sw.WriteLine("According to redump.org, the ideal hash for entire disc is: CRC32:{0:X8}", game.GetStringValue("dh")); sw.WriteLine("The file you loaded hasn't been hashed entirely (it would take too long)"); sw.WriteLine("Compare it with the full hash calculated by the PSX menu's Hash Discs tool"); } } else { sw.WriteLine("Not a PSX disc"); } sw.WriteLine("-------------------------"); } nextEmulator = new Octoshock(nextComm, discs, discNames, null, GetCoreSettings <Octoshock>(), GetCoreSyncSettings <Octoshock>()); nextEmulator.CoreComm.RomStatusDetails = sw.ToString(); game = new GameInfo { Name = Path.GetFileNameWithoutExtension(file.Name) }; game.System = "PSX"; } else if (ext == ".iso" || ext == ".cue" || ext == ".ccd") { if (file.IsArchive) { throw new InvalidOperationException("Can't load CD files from archives!"); } string discHash = null; //--- load the disc in a context which will let us abort if it's going to take too long var discMountJob = new DiscMountJob { IN_FromPath = path }; discMountJob.IN_SlowLoadAbortThreshold = 8; discMountJob.Run(); if (discMountJob.OUT_SlowLoadAborted) { System.Windows.Forms.MessageBox.Show("This disc would take too long to load. Run it through discohawk first, or find a new rip because this one is probably junk"); return(false); } if (discMountJob.OUT_ErrorLevel) { throw new InvalidOperationException(discMountJob.OUT_Log); } var disc = discMountJob.OUT_Disc; //----------- //TODO - use more sophisticated IDer var discType = new DiscIdentifier(disc).DetectDiscType(); if (discType == DiscType.SonyPSX) { discHash = new DiscHasher(disc).Calculate_PSX_BizIDHash().ToString("X8"); } else { discHash = new DiscHasher(disc).OldHash(); } game = Database.CheckDatabase(discHash); if (game == null) { // try to use our wizard methods game = new GameInfo { Name = Path.GetFileNameWithoutExtension(file.Name), Hash = discHash }; switch (new DiscIdentifier(disc).DetectDiscType()) { case DiscType.SegaSaturn: game.System = "SAT"; break; case DiscType.SonyPSP: game.System = "PSP"; break; default: case DiscType.SonyPSX: game.System = "PSX"; break; case DiscType.MegaCD: game.System = "GEN"; break; case DiscType.AudioDisc: case DiscType.TurboCD: case DiscType.UnknownCDFS: case DiscType.UnknownFormat: game.System = "PCECD"; break; } } switch (game.System) { case "GEN": var genesis = new GPGX( nextComm, null, disc, GetCoreSettings <GPGX>(), GetCoreSyncSettings <GPGX>()); nextEmulator = genesis; break; case "SAT": nextEmulator = new Yabause(nextComm, disc, GetCoreSyncSettings <Yabause>()); break; case "PSP": nextEmulator = new PSP(nextComm, file.Name); break; case "PSX": nextEmulator = new Octoshock(nextComm, new List <Disc>(new[] { disc }), new List <string>(new[] { Path.GetFileNameWithoutExtension(path) }), null, GetCoreSettings <Octoshock>(), GetCoreSyncSettings <Octoshock>()); if (game.IsRomStatusBad() || game.Status == RomStatus.NotInDatabase) { nextEmulator.CoreComm.RomStatusDetails = "Disc could not be identified as known-good. Look for a better rip."; } else { StringWriter sw = new StringWriter(); sw.WriteLine("Disc was identified (99.99% confidently) as known good with disc id hash CRC32:{0:X8}", discHash); sw.WriteLine("Nonetheless it could be an unrecognized romhack or patched version."); sw.WriteLine("According to redump.org, the ideal hash for entire disc is: CRC32:{0:X8}", game.GetStringValue("dh")); sw.WriteLine("The file you loaded hasn't been hashed entirely (it would take too long)"); sw.WriteLine("Compare it with the full hash calculated by the PSX menu's Hash Discs tool"); nextEmulator.CoreComm.RomStatusDetails = sw.ToString(); } break; case "PCE": case "PCECD": nextEmulator = new PCEngine(nextComm, game, disc, GetCoreSettings <PCEngine>(), GetCoreSyncSettings <PCEngine>()); break; } } else if (file.Extension.ToLowerInvariant() == ".xml") { try { var xmlGame = XmlGame.Create(file); // if load fails, are we supposed to retry as a bsnes XML???????? game = xmlGame.GI; switch (game.System) { case "GB": case "DGB": // adelikat: remove need for tags to be hardcoded to left and right, we should clean this up, also maybe the DGB core should just take the xml file and handle it itself var leftBytes = xmlGame.Assets.First().Value; var rightBytes = xmlGame.Assets.Skip(1).First().Value; var left = Database.GetGameInfo(leftBytes, "left.gb"); var right = Database.GetGameInfo(rightBytes, "right.gb"); nextEmulator = new GambatteLink( nextComm, left, leftBytes, right, rightBytes, GetCoreSettings <GambatteLink>(), GetCoreSyncSettings <GambatteLink>(), Deterministic); // other stuff todo break; case "AppleII": var assets = xmlGame.Assets.Select(a => Database.GetGameInfo(a.Value, a.Key)); var roms = xmlGame.Assets.Select(a => a.Value); nextEmulator = new AppleII( nextComm, assets, roms, (AppleII.Settings)GetCoreSettings <AppleII>()); break; case "PSX": var entries = xmlGame.AssetFullPaths; var discs = new List <Disc>(); var discNames = new List <string>(); var sw = new StringWriter(); foreach (var e in entries) { Disc disc = null; string discPath = e; //--- load the disc in a context which will let us abort if it's going to take too long var discMountJob = new DiscMountJob { IN_FromPath = discPath }; discMountJob.IN_SlowLoadAbortThreshold = 8; discMountJob.Run(); disc = discMountJob.OUT_Disc; if (discMountJob.OUT_SlowLoadAborted) { System.Windows.Forms.MessageBox.Show("This disc would take too long to load. Run it through discohawk first, or find a new rip because this one is probably junk"); return(false); } if (discMountJob.OUT_ErrorLevel) { throw new InvalidOperationException(discMountJob.OUT_Log); } if (disc == null) { throw new InvalidOperationException("Can't load one of the files specified in the M3U"); } var discName = Path.GetFileNameWithoutExtension(discPath); discNames.Add(discName); discs.Add(disc); var discType = new DiscIdentifier(disc).DetectDiscType(); sw.WriteLine("{0}", Path.GetFileName(discPath)); if (discType == DiscType.SonyPSX) { string discHash = new DiscHasher(disc).Calculate_PSX_BizIDHash().ToString("X8"); game = Database.CheckDatabase(discHash); if (game == null || game.IsRomStatusBad() || game.Status == RomStatus.NotInDatabase) { sw.WriteLine("Disc could not be identified as known-good. Look for a better rip."); } else { sw.WriteLine("Disc was identified (99.99% confidently) as known good with disc id hash CRC32:{0:X8}", discHash); sw.WriteLine("Nonetheless it could be an unrecognized romhack or patched version."); sw.WriteLine("According to redump.org, the ideal hash for entire disc is: CRC32:{0:X8}", game.GetStringValue("dh")); sw.WriteLine("The file you loaded hasn't been hashed entirely (it would take too long)"); sw.WriteLine("Compare it with the full hash calculated by the PSX menu's Hash Discs tool"); } } else { sw.WriteLine("Not a PSX disc"); } sw.WriteLine("-------------------------"); } // todo: copy pasta from PSX .cue section nextEmulator = new Octoshock(nextComm, discs, discNames, null, GetCoreSettings <Octoshock>(), GetCoreSyncSettings <Octoshock>()); nextEmulator.CoreComm.RomStatusDetails = sw.ToString(); game = new GameInfo { Name = Path.GetFileNameWithoutExtension(file.Name) }; game.System = "PSX"; break; default: return(false); } } catch (Exception ex) { try { // need to get rid of this hack at some point rom = new RomGame(file); ((CoreFileProvider)nextComm.CoreFileProvider).SubfileDirectory = Path.GetDirectoryName(path.Replace("|", String.Empty)); // Dirty hack to get around archive filenames (since we are just getting the directory path, it is safe to mangle the filename byte[] romData = null; byte[] xmlData = rom.FileData; game = rom.GameInfo; game.System = "SNES"; var snes = new LibsnesCore(game, romData, Deterministic, xmlData, nextComm, GetCoreSettings <LibsnesCore>(), GetCoreSyncSettings <LibsnesCore>()); nextEmulator = snes; } catch { DoLoadErrorCallback(ex.ToString(), "DGB", LoadErrorType.XML); return(false); } } } else if (file.Extension.ToLowerInvariant() == ".psf" || file.Extension.ToLowerInvariant() == ".minipsf") { Func <Stream, int, byte[]> cbDeflater = (Stream instream, int size) => { var inflater = new ICSharpCode.SharpZipLib.Zip.Compression.Inflater(false); var iis = new ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream(instream, inflater); MemoryStream ret = new MemoryStream(); iis.CopyTo(ret); return(ret.ToArray()); }; PSF psf = new PSF(); psf.Load(path, cbDeflater); nextEmulator = new Octoshock(nextComm, psf, GetCoreSettings <Octoshock>(), GetCoreSyncSettings <Octoshock>()); nextEmulator.CoreComm.RomStatusDetails = "It's a PSF, what do you want."; //total garbage, this rom = new RomGame(file); game = rom.GameInfo; } else // most extensions { rom = new RomGame(file); //hacky for now if (file.Extension.ToLowerInvariant() == ".exe") { rom.GameInfo.System = "PSX"; } if (string.IsNullOrEmpty(rom.GameInfo.System)) { // Has the user picked a preference for this extension? if (PreferredPlatformIsDefined(rom.Extension.ToLowerInvariant())) { rom.GameInfo.System = Global.Config.PreferredPlatformsForExtensions[rom.Extension.ToLowerInvariant()]; } else if (ChoosePlatform != null) { var result = ChoosePlatform(rom); if (!string.IsNullOrEmpty(result)) { rom.GameInfo.System = result; } else { cancel = true; } } } game = rom.GameInfo; var isXml = false; // other xml has already been handled if (file.Extension.ToLowerInvariant() == ".xml") { game.System = "SNES"; isXml = true; } CoreInventory.Core core = null; switch (game.System) { default: core = CoreInventory.Instance[game.System]; break; case null: // The user picked nothing in the Core picker break; case "83P": var ti83Bios = ((CoreFileProvider)nextComm.CoreFileProvider).GetFirmware("TI83", "Rom", true); var ti83BiosPath = ((CoreFileProvider)nextComm.CoreFileProvider).GetFirmwarePath("TI83", "Rom", true); using (var ti83AsHawkFile = new HawkFile()) { ti83AsHawkFile.Open(ti83BiosPath); var ti83BiosAsRom = new RomGame(ti83AsHawkFile); var ti83 = new TI83(nextComm, ti83BiosAsRom.GameInfo, ti83Bios, GetCoreSettings <TI83>()); ti83.LinkPort.SendFileToCalc(File.OpenRead(path), false); nextEmulator = ti83; } break; case "SNES": if (Global.Config.SNES_InSnes9x && VersionInfo.DeveloperBuild) { core = CoreInventory.Instance["SNES", "Snes9x"]; } else { // need to get rid of this hack at some point ((CoreFileProvider)nextComm.CoreFileProvider).SubfileDirectory = Path.GetDirectoryName(path.Replace("|", String.Empty)); // Dirty hack to get around archive filenames (since we are just getting the directory path, it is safe to mangle the filename var romData = isXml ? null : rom.FileData; var xmlData = isXml ? rom.FileData : null; var snes = new LibsnesCore(game, romData, Deterministic, xmlData, nextComm, GetCoreSettings <LibsnesCore>(), GetCoreSyncSettings <LibsnesCore>()); nextEmulator = snes; } break; case "NES": if (!Global.Config.NES_InQuickNES || forceAccurateCore) { core = CoreInventory.Instance["NES", "NesHawk"]; } else { core = CoreInventory.Instance["NES", "QuickNes"]; } break; case "GB": case "GBC": if (!Global.Config.GB_AsSGB) { core = CoreInventory.Instance["GB", "Gambatte"]; } else { try { game.System = "SNES"; game.AddOption("SGB"); var snes = new LibsnesCore(game, rom.FileData, Deterministic, null, nextComm, GetCoreSettings <LibsnesCore>(), GetCoreSyncSettings <LibsnesCore>()); nextEmulator = snes; } catch { // failed to load SGB bios or game does not support SGB mode. // To avoid catch-22, disable SGB mode Global.Config.GB_AsSGB = false; throw; } } break; case "A78": var gamedbpath = Path.Combine(PathManager.GetExeDirectoryAbsolute(), "gamedb", "EMU7800.csv"); nextEmulator = new Atari7800(nextComm, game, rom.RomData, gamedbpath); break; case "C64": var c64 = new C64(nextComm, game, rom.RomData, rom.Extension); nextEmulator = c64; break; case "GBA": //core = CoreInventory.Instance["GBA", "Meteor"]; if (Global.Config.GBA_UsemGBA) { core = CoreInventory.Instance["GBA", "mGBA"]; } else { core = CoreInventory.Instance["GBA", "VBA-Next"]; } break; case "PSX": nextEmulator = new Octoshock(nextComm, null, null, rom.FileData, GetCoreSettings <Octoshock>(), GetCoreSyncSettings <Octoshock>()); nextEmulator.CoreComm.RomStatusDetails = "PSX etc."; break; case "DEBUG": if (VersionInfo.DeveloperBuild) { nextEmulator = LibRetroEmulator.CreateDebug(nextComm, rom.RomData); } break; } if (core != null) { // use coreinventory nextEmulator = core.Create(nextComm, game, rom.RomData, rom.FileData, Deterministic, GetCoreSettings(core.Type), GetCoreSyncSettings(core.Type)); } } if (nextEmulator == null) { if (!cancel) { DoLoadErrorCallback("No core could load the rom.", null); } return(false); } } catch (Exception ex) { string system = null; if (game != null) { system = game.System; } // all of the specific exceptions we're trying to catch here aren't expected to have inner exceptions, // so drill down in case we got a TargetInvocationException or something like that while (ex.InnerException != null) { ex = ex.InnerException; } // Specific hack here, as we get more cores of the same system, this isn't scalable if (ex is UnsupportedGameException) { if (system == "NES") { DoMessageCallback("Unable to use quicknes, using NESHawk instead"); } return(LoadRom(path, nextComm, true, recursiveCount + 1)); } else if (ex is MissingFirmwareException) { DoLoadErrorCallback(ex.Message, system, path, Deterministic, LoadErrorType.MissingFirmware); } else if (ex is CGBNotSupportedException) { // Note: GB as SGB was set to false by this point, otherwise we would want to do it here DoMessageCallback("Failed to load a GB rom in SGB mode. Disabling SGB Mode."); return(LoadRom(path, nextComm, false, recursiveCount + 1)); } else { DoLoadErrorCallback("A core accepted the rom, but threw an exception while loading it:\n\n" + ex, system); } return(false); } Rom = rom; LoadedEmulator = nextEmulator; Game = game; return(true); } }
private void Download() { //the temp file is owned by this thread var fn = TempFileManager.GetTempFilename("ffmpeg_download", ".7z", false); try { using (var evt = new ManualResetEvent(false)) { using (var client = new System.Net.WebClient()) { System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12; client.DownloadFileAsync(new Uri(FFmpegService.Url), fn); client.DownloadProgressChanged += (object sender, System.Net.DownloadProgressChangedEventArgs e) => { pct = e.ProgressPercentage; }; client.DownloadFileCompleted += (object sender, System.ComponentModel.AsyncCompletedEventArgs e) => { //we don't really need a status. we'll just try to unzip it when it's done evt.Set(); }; for (; ;) { if (evt.WaitOne(10)) { break; } //if the gui thread ordered an exit, cancel the download and wait for it to acknowledge if (exiting) { client.CancelAsync(); evt.WaitOne(); break; } } } } //throw new Exception("test of download failure"); //if we were ordered to exit, bail without wasting any more time if (exiting) { return; } //try acquiring file using (var hf = new HawkFile(fn)) { using (var exe = OSTailoredCode.IsUnixHost ? hf.BindArchiveMember("ffmpeg") : hf.BindFirstOf(".exe")) { var data = exe !.ReadAllBytes(); //last chance. exiting, don't dump the new ffmpeg file if (exiting) { return; } DirectoryInfo parentDir = new(Path.GetDirectoryName(FFmpegService.FFmpegPath) !); if (!parentDir.Exists) { parentDir.Create(); } File.WriteAllBytes(FFmpegService.FFmpegPath, data); if (OSTailoredCode.IsUnixHost) { OSTailoredCode.ConstructSubshell("chmod", $"+x {FFmpegService.FFmpegPath}", checkStdout: false).Start(); Thread.Sleep(50); // Linux I/O flush idk } } } //make sure it worked if (!FFmpegService.QueryServiceAvailable()) { throw new Exception("download failed"); } succeeded = true; } catch { failed = true; } finally { try { File.Delete(fn); } catch { } } }
public bool LoadRom(string path, CoreComm nextComm, bool forceAccurateCore = false) // forceAccurateCore is currently just for Quicknes vs Neshawk but could be used for other situations { if (path == null) { return(false); } using (var file = new HawkFile()) { var romExtensions = new[] { "SMS", "SMC", "SFC", "PCE", "SGX", "GG", "SG", "BIN", "GEN", "MD", "SMD", "GB", "NES", "FDS", "ROM", "INT", "GBC", "UNF", "A78", "CRT", "COL", "XML", "Z64", "V64", "N64", "WS", "WSC" }; // lets not use this unless we need to // file.NonArchiveExtensions = romExtensions; file.Open(path); // if the provided file doesnt even exist, give up! if (!file.Exists) { return(false); } // try binding normal rom extensions first if (!file.IsBound) { file.BindSoleItemOf(romExtensions); } // if we have an archive and need to bind something, then pop the dialog if (file.IsArchive && !file.IsBound) { var result = HandleArchive(file); if (result.HasValue) { file.BindArchiveMember(result.Value); } else { return(false); } } // set this here so we can see what file we tried to load even if an error occurs CanonicalFullPath = file.CanonicalFullPath; IEmulator nextEmulator = null; RomGame rom = null; GameInfo game = null; try { var ext = file.Extension.ToLower(); if (ext == ".iso" || ext == ".cue") { var disc = ext == ".iso" ? Disc.FromIsoPath(path) : Disc.FromCuePath(path, new CueBinPrefs()); var hash = disc.GetHash(); game = Database.CheckDatabase(hash); if (game == null) { // try to use our wizard methods game = new GameInfo { Name = Path.GetFileNameWithoutExtension(file.Name), Hash = hash }; switch (disc.DetectDiscType()) { case DiscType.SegaSaturn: game.System = "SAT"; break; case DiscType.SonyPSP: game.System = "PSP"; break; case DiscType.SonyPSX: game.System = "PSX"; break; case DiscType.MegaCD: game.System = "GEN"; break; case DiscType.TurboCD: case DiscType.UnknownCDFS: case DiscType.UnknownFormat: default: // PCECD was bizhawk's first CD core, // and during that time, all CDs were blindly sent to it // so this prevents regressions game.System = "PCECD"; break; } } switch (game.System) { case "GEN": var genesis = new GPGX( nextComm, null, disc, "GEN", GetCoreSettings <GPGX>(), GetCoreSyncSettings <GPGX>()); nextEmulator = genesis; break; case "SAT": nextEmulator = new Yabause(nextComm, disc, GetCoreSyncSettings <Yabause>()); break; case "PSP": nextEmulator = new PSP(nextComm, file.Name); break; case "PSX": nextEmulator = new Octoshock(nextComm); (nextEmulator as Octoshock).LoadCuePath(file.CanonicalFullPath); nextEmulator.CoreComm.RomStatusDetails = "PSX etc."; break; case "PCE": case "PCECD": nextEmulator = new PCEngine(nextComm, game, disc, GetCoreSettings <PCEngine>(), GetCoreSyncSettings <PCEngine>()); break; } } else if (file.Extension.ToLower() == ".xml") { try { var xmlGame = XmlGame.Create(file); // if load fails, are we supposed to retry as a bsnes XML???????? game = xmlGame.GI; switch (game.System) { case "DGB": var left = Database.GetGameInfo(xmlGame.Assets["LeftRom"], "left.gb"); var right = Database.GetGameInfo(xmlGame.Assets["RightRom"], "right.gb"); nextEmulator = new GambatteLink( nextComm, left, xmlGame.Assets["LeftRom"], right, xmlGame.Assets["RightRom"], GetCoreSettings <GambatteLink>(), GetCoreSyncSettings <GambatteLink>(), Deterministic); // other stuff todo break; default: return(false); } } catch (Exception ex) { DoLoadErrorCallback(ex.ToString(), "DGB", LoadErrorType.XML); return(false); } } else // most extensions { rom = new RomGame(file); if (string.IsNullOrEmpty(rom.GameInfo.System)) { // Has the user picked a preference for this extension? if (PreferredPlatformIsDefined(rom.Extension.ToLower())) { rom.GameInfo.System = Global.Config.PreferredPlatformsForExtensions[rom.Extension.ToLower()]; } else if (ChoosePlatform != null) { rom.GameInfo.System = ChoosePlatform(rom); } } game = rom.GameInfo; var isXml = false; // other xml has already been handled if (file.Extension.ToLower() == ".xml") { game.System = "SNES"; isXml = true; } switch (game.System) { case "SNES": if (Global.Config.SNES_InSnes9x && VersionInfo.DeveloperBuild) { var snes = new Emulation.Cores.Nintendo.SNES9X.Snes9x(nextComm, rom.FileData); nextEmulator = snes; } else { // need to get rid of this hack at some point ((CoreFileProvider)nextComm.CoreFileProvider).SubfileDirectory = Path.GetDirectoryName(path.Replace("|", String.Empty)); // Dirty hack to get around archive filenames (since we are just getting the directory path, it is safe to mangle the filename var romData = isXml ? null : rom.FileData; var xmlData = isXml ? rom.FileData : null; var snes = new LibsnesCore(game, romData, Deterministic, xmlData, nextComm, GetCoreSettings <LibsnesCore>(), GetCoreSyncSettings <LibsnesCore>()); nextEmulator = snes; } RACore.OnLoad(RAConsoleID.SNES, rom.GameInfo.Name, rom.GameInfo.Hash); break; case "SMS": case "SG": case "GG": nextEmulator = new SMS(nextComm, game, rom.RomData, GetCoreSettings <SMS>(), GetCoreSyncSettings <SMS>()); RACore.OnLoad(RAConsoleID.MasterSystem, rom.GameInfo.Name, rom.GameInfo.Hash); break; case "A26": nextEmulator = new Atari2600( nextComm, game, rom.FileData, GetCoreSettings <Atari2600>(), GetCoreSyncSettings <Atari2600>()); break; case "PCE": case "PCECD": case "SGX": nextEmulator = new PCEngine(nextComm, game, rom.RomData, GetCoreSettings <PCEngine>(), GetCoreSyncSettings <PCEngine>()); RACore.OnLoad(RAConsoleID.PCEngine, rom.GameInfo.Name, rom.GameInfo.Hash); break; case "GEN": nextEmulator = new GPGX(nextComm, rom.RomData, null, "GEN", GetCoreSettings <GPGX>(), GetCoreSyncSettings <GPGX>()); RACore.OnLoad(RAConsoleID.MegaDrive, rom.GameInfo.Name, rom.GameInfo.Hash); break; case "TI83": nextEmulator = new TI83(nextComm, game, rom.RomData, GetCoreSettings <TI83>()); break; case "NES": if (!Global.Config.NES_InQuickNES || forceAccurateCore) { nextEmulator = new NES( nextComm, game, rom.FileData, GetCoreSettings <NES>(), GetCoreSyncSettings <NES>()); } else { nextEmulator = new QuickNES(nextComm, rom.FileData, GetCoreSettings <QuickNES>()); } RACore.OnLoad(RAConsoleID.NES, rom.GameInfo.Name, rom.GameInfo.Hash); break; case "GB": case "GBC": if (!Global.Config.GB_AsSGB) { nextEmulator = new Gameboy( nextComm, game, rom.FileData, GetCoreSettings <Gameboy>(), GetCoreSyncSettings <Gameboy>(), Deterministic); } else { try { game.System = "SNES"; game.AddOption("SGB"); var snes = new LibsnesCore(game, rom.FileData, Deterministic, null, nextComm, GetCoreSettings <LibsnesCore>(), GetCoreSyncSettings <LibsnesCore>()); nextEmulator = snes; } catch { // failed to load SGB bios or game does not support SGB mode. // To avoid catch-22, disable SGB mode Global.Config.GB_AsSGB = false; throw; } } if (game.System == "GB") { RACore.OnLoad(RAConsoleID.Gameboy, rom.GameInfo.Name, rom.GameInfo.Hash); } else if (game.System == "GBC") { RACore.OnLoad(RAConsoleID.GameboyColor, rom.GameInfo.Name, rom.GameInfo.Hash); } break; case "Coleco": nextEmulator = new ColecoVision(nextComm, game, rom.RomData, GetCoreSyncSettings <ColecoVision>()); break; case "INTV": nextEmulator = new Intellivision(nextComm, game, rom.RomData); break; case "A78": var gamedbpath = Path.Combine(PathManager.GetExeDirectoryAbsolute(), "gamedb", "EMU7800.csv"); nextEmulator = new Atari7800(nextComm, game, rom.RomData, gamedbpath); break; case "C64": var c64 = new C64(nextComm, game, rom.RomData, rom.Extension); nextEmulator = c64; break; case "GBA": if (false) { //var gba = new GBA(nextComm); //gba.Load(rom.RomData); //nextEmulator = gba; } else { var gba = new VBANext(rom.RomData, nextComm); nextEmulator = gba; RACore.OnLoad(RAConsoleID.GameboyAdvance, rom.GameInfo.Name, rom.GameInfo.Hash); } break; case "N64": nextEmulator = new N64(nextComm, game, rom.RomData, GetCoreSettings <N64>(), GetCoreSyncSettings <N64>()); RACore.OnLoad(RAConsoleID.Nintendo64, rom.GameInfo.Name, rom.GameInfo.Hash); break; case "WSWAN": nextEmulator = new WonderSwan(nextComm, rom.RomData, Deterministic, GetCoreSettings <WonderSwan>(), GetCoreSyncSettings <WonderSwan>()); break; case "DEBUG": if (VersionInfo.DeveloperBuild) { nextEmulator = LibRetroEmulator.CreateDebug(nextComm, rom.RomData); } break; } } if (nextEmulator == null) { DoLoadErrorCallback("No core could load the rom.", null); return(false); } } catch (Exception ex) { string system = null; if (game != null) { system = game.System; } // Specific hack here, as we get more cores of the same system, this isn't scalable if (ex is UnsupportedMapperException) { return(LoadRom(path, nextComm, forceAccurateCore: true)); } else if (ex is MissingFirmwareException) { DoLoadErrorCallback(ex.Message, system, LoadErrorType.MissingFirmware); } else if (ex is CGBNotSupportedException) { // Note: GB as SGB was set to false by this point, otherwise we would want to do it here DoMessageCallback("Failed to load a GB rom in SGB mode. Disabling SGB Mode."); return(LoadRom(path, nextComm)); } else { DoLoadErrorCallback("A core accepted the rom, but threw an exception while loading it:\n\n" + ex, system); } return(false); } Rom = rom; LoadedEmulator = nextEmulator; Game = game; return(true); } }