using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Xml; using BizHawk.Common; using BizHawk.Common.BufferExtensions; using BizHawk.Common.IOExtensions; using BizHawk.Emulation.Common; namespace BizHawk.Client.Common { public class XmlGame { public XmlGame() { Assets = new List>(); AssetFullPaths = new List(); GI = new GameInfo(); } public XmlDocument Xml { get; set; } public GameInfo GI { get; } public IList> Assets { get; } public IList AssetFullPaths { get; } // TODO: Hack work around, to avoid having to refactor Assets into a object array, should be refactored! 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 = 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 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(); } else { data = File.ReadAllBytes(fullpath.Split('|').First()); } } } catch { throw new Exception("Couldn't load XMLGame LoadAsset \"" + filename + "\""); } } ret.Assets.Add(new KeyValuePair(filename, data)); ret.AssetFullPaths.Add(fullpath); 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()); } } } }