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()); } }
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()); } }