diff --git a/Deheader/Headerer.cs b/Deheader/Headerer.cs index 498987ff..b6cbc335 100644 --- a/Deheader/Headerer.cs +++ b/Deheader/Headerer.cs @@ -17,7 +17,21 @@ namespace SabreTools { private static string _dbName = "Headerer.sqlite"; private static string _connectionString = "Data Source=" + _dbName + ";Version = 3;"; - private static Dictionary types; + + /// + /// Possible detected header type + /// + private enum HeaderType + { + None = 0, + A7800, + FDS, + Lynx, + //N64, + NES, + PCE, + SNES, + } /// /// Start deheader operation with supplied parameters @@ -27,15 +41,6 @@ namespace SabreTools { Console.Title = "Headerer " + Build.Version; - // Type mapped to header size (in decimal bytes) - types = new Dictionary(); - types.Add("a7800", 128); - types.Add("fds", 16); - types.Add("lynx", 64); - types.Add("pce", 512); - types.Add("nes", 16); - types.Add("snes", 512); - // Ensure that the header database is set up DBTools.EnsureDatabase(_dbName, _connectionString); @@ -131,38 +136,64 @@ namespace SabreTools string header = BitConverter.ToString(hbin).Replace("-", string.Empty); // Determine the type of the file from the header, if possible - string type = ""; - if (Regex.IsMatch(header, "^.{2}415441524937383030") || Regex.IsMatch(header, "^.{200}41435455414C20434152542044415441205354415254532048455245")) + HeaderType type = HeaderType.None; + int headerSize = 0; + + // Loop over the header types and see if there's a match + foreach (HeaderType test in Enum.GetValues(typeof(HeaderType))) { - type = "a7800"; - } - else if (Regex.IsMatch(header, "^4644531A0[1-4]0000000000000000000000")) - { - type = "fds"; - } - else if (Regex.IsMatch(header, "^4C594E58") || Regex.IsMatch(header, "^425339")) - { - type = "lynx"; - } - else if (Regex.IsMatch(header, "^4000000000000000AABB02")) - { - type = "pce"; - } - else if (Regex.IsMatch(header, "^4E45531A")) - { - type = "nes"; - } - else if (Regex.IsMatch(header, "^.{16}0000000000000000") || Regex.IsMatch(header, "^.{16}AABB040000000000") || Regex.IsMatch(header, "^.{16}535550455255464F")) // fig, smc, ufo - { - type = "snes"; + Dictionary tempDict = new Dictionary(); + switch (test) + { + case HeaderType.A7800: + tempDict = Remapping.A7800; + break; + case HeaderType.FDS: + tempDict = Remapping.FDS; + break; + case HeaderType.Lynx: + tempDict = Remapping.Lynx; + break; + case HeaderType.PCE: + tempDict = Remapping.PCE; + break; + /* + case HeaderType.N64: + tempDict = Remapping.N64; + break; + */ + case HeaderType.NES: + tempDict = Remapping.NES; + break; + case HeaderType.SNES: + tempDict = Remapping.SNES; + break; + } + + // Loop over the dictionary and see if there are matches + foreach (KeyValuePair entry in tempDict) + { + if (Regex.IsMatch(header, entry.Key)) + { + type = test; + headerSize = entry.Value; + break; + } + } + + // If we found something, break out + if (type != HeaderType.None) + { + break; + } } - Console.WriteLine("File has header: " + (type != "")); + Console.WriteLine("File has header: " + (type != HeaderType.None)); - if (type != "") + if (type != HeaderType.None) { Console.WriteLine("Deteched header type: " + type); - int hs = types[type]; + int hs = headerSize; // Save header as string in the database string realhead = ""; @@ -206,7 +237,7 @@ namespace SabreTools query = @"INSERT INTO data (sha1, header, type) VALUES ('" + BitConverter.ToString(sha1.Hash) + "', " + "'" + realhead + "', " + - "'" + type + "')"; + "'" + type.ToString() + "')"; using (SQLiteConnection dbc = new SQLiteConnection(_connectionString)) { dbc.Open(); diff --git a/Deheader/Headerer.csproj b/Deheader/Headerer.csproj index 0ebb5875..adaf2c31 100644 --- a/Deheader/Headerer.csproj +++ b/Deheader/Headerer.csproj @@ -89,6 +89,7 @@ + diff --git a/Deheader/Skippers/pce.xml b/Deheader/Skippers/pce.xml new file mode 100644 index 00000000..f3b8416b --- /dev/null +++ b/Deheader/Skippers/pce.xml @@ -0,0 +1,13 @@ + + + + + NEC TurboGrafx-16/PC-Engine + Matt Nadareski (darksabre76) + 1.0 + + + + + + diff --git a/SabreHelper/Remapping.cs b/SabreHelper/Remapping.cs index 43363c68..04ec2cef 100644 --- a/SabreHelper/Remapping.cs +++ b/SabreHelper/Remapping.cs @@ -10,7 +10,7 @@ namespace SabreTools.Helper /// public class Remapping { - // Remapping classes represented by dictionaries + // Remapping classes represented by dictionaries (from, to) public static Dictionary MAME = new Dictionary(); public static Dictionary MaybeIntro = new Dictionary(); public static Dictionary NoIntro = new Dictionary(); @@ -19,6 +19,15 @@ namespace SabreTools.Helper public static Dictionary TOSEC = new Dictionary(); public static Dictionary TruRip = new Dictionary(); + // Header skip classes represented by dictionaries (header, size) + public static Dictionary A7800 = new Dictionary(); + public static Dictionary FDS = new Dictionary(); + public static Dictionary Lynx = new Dictionary(); + //public static Dictionary N64 = new Dictionary(); + public static Dictionary NES = new Dictionary(); + public static Dictionary PCE = new Dictionary(); + public static Dictionary SNES = new Dictionary(); + /// /// Create all remappings to be used by the program /// @@ -111,5 +120,115 @@ namespace SabreTools.Helper } } } + + /// + /// Create all header mappings to be used by the program + /// + public static void CreateHeaderSkips() + { + // Create array of dictionary names + string[] skippers = + { + "a780", "fds", "lynx", /* "n64", */ "nes", "pce", "snes", + }; + + // Loop through and add all remappings + foreach (string skipper in skippers) + { + SkipperHelper(skipper); + } + } + + /// + /// Create a remapping from XML + /// + /// Name of the header skipper to be populated + private static void SkipperHelper(string skipper) + { + // Read in remapping from file + XmlDocument doc = new XmlDocument(); + try + { + doc.LoadXml(File.ReadAllText("Skippers/" + skipper + ".xml")); + } + catch (XmlException ex) + { + Console.WriteLine(skipper + " header skippers could not be loaded! " + ex.ToString()); + return; + } + + // Get the detector parent node + XmlNode node = doc.FirstChild; + while (node.Name != "detector") + { + node = node.NextSibling; + } + + // Get the first rule node + node = node.FirstChild; + while (node.NodeType != XmlNodeType.Element && node.Name != "rule") + { + node = node.NextSibling; + } + + // Now read in the rules + while (node != null && node.Name == "rule") + { + // Size is the offset for the actual game data + int size = (node.Attributes["start_offset"] != null ? Convert.ToInt32(node.Attributes["start_offset"].Value, 16) : 0); + + // Each rule set can have more than one data rule. We can't really use multiples right now + if (node.SelectNodes("data") != null) + { + foreach (XmlNode child in node.SelectNodes("data")) + { + // Add an offset to the match if one exists + string header = (child.Attributes["offset"] != null && child.Attributes["offset"].Value != "0" ? "^.{" + Convert.ToInt32(child.Attributes["offset"].Value, 16) + "}" : "^"); + header += child.Attributes["value"].Value; + + // Now add the header and value to the appropriate skipper dictionary + switch (skipper) + { + case "a7800": + A7800.Add(header, size); + break; + case "fds": + FDS.Add(header, size); + break; + case "lynx": + Lynx.Add(header, size); + break; + /* + case "n64": + N64.Add(header, size); + break; + */ + case "nes": + NES.Add(header, size); + break; + case "pce": + PCE.Add(header, size); + break; + case "snes": + SNES.Add(header, size); + break; + } + } + } + + // Get the next node and skip over anything that's not an element + node = node.NextSibling; + + if (node == null) + { + break; + } + + while (node.NodeType != XmlNodeType.Element && node.Name != "rule") + { + node = node.NextSibling; + } + } + } } }