diff --git a/Deheader/Headerer.cs b/Deheader/Headerer.cs index ada40809..281c020f 100644 --- a/Deheader/Headerer.cs +++ b/Deheader/Headerer.cs @@ -31,7 +31,6 @@ namespace SabreTools logger = new Logger(true, "headerer.log"); logger.Start(); DBTools.EnsureDatabase(_dbName, _connectionString); - Remapping.CreateHeaderSkips(); // Credits take precidence over all if ((new List(args)).Contains("--credits")) diff --git a/SabreTools.Helper/Data/Structs.cs b/SabreTools.Helper/Data/Structs.cs index a60ca828..2ad22b9d 100644 --- a/SabreTools.Helper/Data/Structs.cs +++ b/SabreTools.Helper/Data/Structs.cs @@ -150,15 +150,26 @@ namespace SabreTools.Helper } } + /// + /// Intermediate struct for holding header skipper information + /// + public struct Skipper + { + public string Name; + public string Author; + public string Version; + public List Rules; + } + /// /// Intermediate struct for holding header skipper rule information /// public struct SkipperRule { - long? StartOffset; // null is EOF - long? EndOffset; // null if EOF - HeaderSkipOperation Operation; - List Tests; + public long? StartOffset; // null is EOF + public long? EndOffset; // null if EOF + public HeaderSkipOperation Operation; + public List Tests; } /// @@ -166,12 +177,12 @@ namespace SabreTools.Helper /// public struct SkipperTest { - HeaderSkipTest Type; - long? Offset; // null is EOF - byte[] Value; - bool Result; - byte[] Mask; - long? Size; // null is PO2, "power of 2" filesize - HeaderSkipTestFileOperator Operator; + public HeaderSkipTest Type; + public long? Offset; // null is EOF + public byte[] Value; + public bool Result; + public byte[] Mask; + public long? Size; // null is PO2, "power of 2" filesize + public HeaderSkipTestFileOperator Operator; } } diff --git a/SabreTools.Helper/Remapping.cs b/SabreTools.Helper/Remapping.cs index c232f8c3..f6248cac 100644 --- a/SabreTools.Helper/Remapping.cs +++ b/SabreTools.Helper/Remapping.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Xml; @@ -10,16 +11,58 @@ namespace SabreTools.Helper /// public class Remapping { - // Remapping classes represented by a dictionary of dictionaries (name, (from, to)) - public static Dictionary> DatMaps = new Dictionary>(); + // Local paths + private const string _remappersPath = "Mappings"; + private const string _skippersPath = "Skippers"; - // Header skip classes represented by a dictionary of dictionaries (name, (header, size)) - public static Dictionary> HeaderMaps = new Dictionary>(); + // Remapping classes represented by a dictionary of dictionaries (name, (from, to)) + private static Dictionary> _datMaps = new Dictionary>(); + public static Dictionary> DatMaps + { + get + { + if (_datMaps.Count == 0) + { + CreateRemappings(); + } + return _datMaps; + } + } + + // Header skippers represented by a list of skipper objects + private static List _list; + public static List List + { + get + { + if (_list == null || _list.Count == 0) + { + PopulateSkippers(); + } + return _list; + } + } + + // Header skippers classes represented by a dictionary of dictionaries (name, (header, size)) + private static Dictionary> _headerMaps = new Dictionary>(); + public static Dictionary> HeaderMaps + { + get + { + if (_headerMaps.Count == 0) + { + CreateHeaderSkips(); + } + return _headerMaps; + } + } + + #region DAT Name Remappings /// /// Create all remappings to be used by the program /// - public static void CreateRemappings() + private static void CreateRemappings() { // Create array of dictionary names string[] remappings = @@ -30,7 +73,7 @@ namespace SabreTools.Helper // Loop through and add all remappings foreach (string remapping in remappings) { - DatMaps.Add(remapping, new Dictionary()); + _datMaps.Add(remapping, new Dictionary()); RemappingHelper(remapping); } } @@ -45,7 +88,7 @@ namespace SabreTools.Helper XmlDocument doc = new XmlDocument(); try { - doc.LoadXml(File.ReadAllText("Mappings/" + mapping + ".xml")); + doc.LoadXml(File.ReadAllText(Path.Combine(_remappersPath, mapping + ".xml"))); } catch (XmlException ex) { @@ -76,7 +119,7 @@ namespace SabreTools.Helper // Now read in the mappings while (node != null && node.Name == "mapping") { - DatMaps[mapping].Add(node.Attributes["from"].Value, node.Attributes["to"].Value); + _datMaps[mapping].Add(node.Attributes["from"].Value, node.Attributes["to"].Value); // Get the next node and skip over anything that's not an element node = node.NextSibling; @@ -93,10 +136,283 @@ namespace SabreTools.Helper } } + #endregion + + #region Header Skips (new) + + /// + /// Populate the entire list of header Skippers + /// + private static void PopulateSkippers() + { + if (_list == null) + { + _list = new List(); + } + + foreach (string skipperFile in Directory.EnumerateFiles(_skippersPath, "*", SearchOption.AllDirectories)) + { + _list.Add(PopulateSkippersHelper(Path.GetFullPath(skipperFile))); + } + } + + /// + /// Populate an individual Skipper from file + /// + /// Name of the file to be read from + /// The Skipper object associated with the file + private static Skipper PopulateSkippersHelper(string filename) + { + Skipper skipper = new Skipper(); + + if (!File.Exists(filename)) + { + return skipper; + } + + Logger logger = new Logger(false, ""); + logger.Start(); + XmlTextReader xtr = DatTools.GetXmlTextReader(filename, logger); + + if (xtr == null) + { + return skipper; + } + + bool valid = false; + xtr.MoveToContent(); + while (!xtr.EOF) + { + if (xtr.NodeType != XmlNodeType.Element) + { + xtr.Read(); + } + + switch (xtr.Name.ToLowerInvariant()) + { + case "detector": + valid = true; + break; + case "name": + skipper.Name = xtr.ReadElementContentAsString(); + break; + case "author": + skipper.Author = xtr.ReadElementContentAsString(); + break; + case "version": + skipper.Version = xtr.ReadElementContentAsString(); + break; + case "rule": + // Get the information from the rule first + SkipperRule rule = new SkipperRule + { + StartOffset = 0, + EndOffset = 0, + Operation = HeaderSkipOperation.None, + Tests = new List(), + }; + + if (xtr.GetAttribute("start_offset") != null) + { + string offset = xtr.GetAttribute("start_offset"); + if (offset.ToLowerInvariant() == "eof") + { + rule.StartOffset = null; + } + else + { + long temp = 0; + Int64.TryParse(offset, out temp); + rule.StartOffset = temp; + } + } + if (xtr.GetAttribute("end_offset") != null) + { + string offset = xtr.GetAttribute("end_offset"); + if (offset.ToLowerInvariant() == "eof") + { + rule.EndOffset = null; + } + else + { + long temp = 0; + Int64.TryParse(offset, out temp); + rule.EndOffset = temp; + } + } + if (xtr.GetAttribute("operation") != null) + { + string operation = xtr.GetAttribute("operation"); + switch (operation.ToLowerInvariant()) + { + case "bitswap": + rule.Operation = HeaderSkipOperation.Bitswap; + break; + case "byteswap": + rule.Operation = HeaderSkipOperation.Byteswap; + break; + case "wordswap": + rule.Operation = HeaderSkipOperation.Wordswap; + break; + } + } + + // Now read the individual tests into the Rule + XmlReader subreader = xtr.ReadSubtree(); + + if (subreader != null) + { + while (!subreader.EOF) + { + if (subreader.NodeType != XmlNodeType.Element) + { + subreader.Read(); + } + + // Get the test type + SkipperTest test = new SkipperTest + { + Offset = 0, + Value = new byte[0], + Result = true, + Mask = new byte[0], + Size = 0, + Operator = HeaderSkipTestFileOperator.Equal, + }; + switch (subreader.Name.ToLowerInvariant()) + { + case "data": + test.Type = HeaderSkipTest.Data; + break; + case "or": + test.Type = HeaderSkipTest.Or; + break; + case "xor": + test.Type = HeaderSkipTest.Xor; + break; + case "and": + test.Type = HeaderSkipTest.And; + break; + case "file": + test.Type = HeaderSkipTest.File; + break; + default: + subreader.Read(); + break; + } + + // Now populate all the parts that we can + if (subreader.GetAttribute("offset") != null) + { + string offset = subreader.GetAttribute("offset"); + if (offset.ToLowerInvariant() == "eof") + { + test.Offset = null; + } + else + { + long temp = 0; + Int64.TryParse(offset, out temp); + test.Offset = temp; + } + } + if (subreader.GetAttribute("value") != null) + { + string value = subreader.GetAttribute("value"); + + // http://stackoverflow.com/questions/321370/how-can-i-convert-a-hex-string-to-a-byte-array + test.Value = new byte[value.Length / 2]; + for (int index = 0; index < test.Value.Length; index++) + { + string byteValue = value.Substring(index * 2, 2); + test.Value[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture); + } + } + if (subreader.GetAttribute("result") != null) + { + string result = subreader.GetAttribute("result"); + switch (result.ToLowerInvariant()) + { + case "false": + test.Result = false; + break; + case "true": + default: + test.Result = true; + break; + } + } + if (subreader.GetAttribute("mask") != null) + { + string mask = subreader.GetAttribute("mask"); + + // http://stackoverflow.com/questions/321370/how-can-i-convert-a-hex-string-to-a-byte-array + test.Mask = new byte[mask.Length / 2]; + for (int index = 0; index < test.Mask.Length; index++) + { + string byteValue = mask.Substring(index * 2, 2); + test.Mask[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture); + } + } + if (subreader.GetAttribute("size") != null) + { + string size = subreader.GetAttribute("size"); + if (size.ToLowerInvariant() == "po2") + { + test.Size = null; + } + else + { + long temp = 0; + Int64.TryParse(size, out temp); + test.Size = temp; + } + } + if (subreader.GetAttribute("operator") != null) + { + string oper = subreader.GetAttribute("operator"); + switch (oper.ToLowerInvariant()) + { + case "less": + test.Operator = HeaderSkipTestFileOperator.Less; + break; + case "greater": + test.Operator = HeaderSkipTestFileOperator.Greater; + break; + case "equal": + default: + test.Operator = HeaderSkipTestFileOperator.Equal; + break; + } + } + + // Add the created test to the rule + rule.Tests.Add(test); + subreader.Read(); + } + } + + // Add the created rule to the skipper + skipper.Rules.Add(rule); + xtr.Skip(); + break; + default: + xtr.Read(); + break; + } + } + + return (valid ? skipper : new Skipper()); + } + + #endregion + + #region Header Skips (old) + /// /// Create all header mappings to be used by the program /// - public static void CreateHeaderSkips() + private static void CreateHeaderSkips() { // Create array of dictionary names string[] skippers = @@ -107,7 +423,7 @@ namespace SabreTools.Helper // Loop through and add all remappings foreach (string skipper in skippers) { - HeaderMaps.Add(skipper, new Dictionary()); + _headerMaps.Add(skipper, new Dictionary()); SkipperHelper(skipper); } } @@ -122,7 +438,7 @@ namespace SabreTools.Helper XmlDocument doc = new XmlDocument(); try { - doc.LoadXml(File.ReadAllText("Skippers/" + skipper + ".xml")); + doc.LoadXml(File.ReadAllText(Path.Combine(_skippersPath, skipper + ".xml"))); } catch (XmlException ex) { @@ -156,7 +472,7 @@ namespace SabreTools.Helper header += child.Attributes["value"].Value; // Now add the header and value to the appropriate skipper dictionary - HeaderMaps[skipper].Add(header, size); + _headerMaps[skipper].Add(header, size); } } @@ -174,5 +490,7 @@ namespace SabreTools.Helper } } } + + #endregion } } diff --git a/SabreTools.Helper/Tools/ArchiveTools.cs b/SabreTools.Helper/Tools/ArchiveTools.cs index 19397260..b07782a7 100644 --- a/SabreTools.Helper/Tools/ArchiveTools.cs +++ b/SabreTools.Helper/Tools/ArchiveTools.cs @@ -20,7 +20,7 @@ namespace SabreTools.Helper /// RomData representing the new information public static void WriteToArchive(string input, string output, Rom rom) { - string archiveFileName = output + Path.DirectorySeparatorChar + rom.Game + ".zip"; + string archiveFileName = Path.Combine(output, rom.Game + ".zip"); ZipArchive outarchive = null; try @@ -212,8 +212,8 @@ namespace SabreTools.Helper logger.Log("Current entry name: '" + reader.Entry.Key + "'"); if (reader.Entry != null && reader.Entry.Key.Contains(entryname)) { - reader.WriteEntryToFile(tempdir + Path.DirectorySeparatorChar + reader.Entry.Key); - outfile = tempdir + Path.DirectorySeparatorChar + reader.Entry.Key; + outfile = Path.Combine(tempdir, reader.Entry.Key); + reader.WriteEntryToFile(outfile); } } } diff --git a/SabreTools.Helper/Tools/Output.cs b/SabreTools.Helper/Tools/Output.cs index 46ace61c..5c200cc3 100644 --- a/SabreTools.Helper/Tools/Output.cs +++ b/SabreTools.Helper/Tools/Output.cs @@ -423,9 +423,8 @@ namespace SabreTools.Helper if (datdata.RepExt != "") { string dir = Path.GetDirectoryName(name); - dir = (dir.EndsWith(Path.DirectorySeparatorChar.ToString()) ? dir : dir + Path.DirectorySeparatorChar); dir = (dir.StartsWith(Path.DirectorySeparatorChar.ToString()) ? dir.Remove(0, 1) : dir); - name = dir + Path.GetFileNameWithoutExtension(name) + datdata.RepExt; + name = Path.Combine(dir, Path.GetFileNameWithoutExtension(name) + datdata.RepExt); } if (datdata.AddExt != "") { @@ -433,7 +432,7 @@ namespace SabreTools.Helper } if (!datdata.UseGame && datdata.GameName) { - name = (rom.Game.EndsWith(Path.DirectorySeparatorChar.ToString()) ? rom.Game : rom.Game + Path.DirectorySeparatorChar) + name; + name = Path.Combine(rom.Game, name); } if (datdata.UseGame && rom.Game != lastgame) diff --git a/SabreTools/DATFromDir.cs b/SabreTools/DATFromDir.cs index b2f75f73..a262abe4 100644 --- a/SabreTools/DATFromDir.cs +++ b/SabreTools/DATFromDir.cs @@ -332,8 +332,9 @@ namespace SabreTools foreach (string entry in Directory.EnumerateFiles(tempdir, "*", SearchOption.AllDirectories)) { lastparent = ProcessFile(Path.GetFullPath(entry), sw, Path.GetFullPath(tempdir), - (Path.GetDirectoryName(Path.GetFullPath(item)) + Path.DirectorySeparatorChar).Remove(0, _basePath.Length) + - Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(item), _datdata, lastparent); + Path.Combine((Path.GetDirectoryName(Path.GetFullPath(item)) + Path.DirectorySeparatorChar).Remove(0, _basePath.Length) + + Path.GetFileNameWithoutExtension(item) + ), _datdata, lastparent); } // Clear the temp directory diff --git a/SabreTools/ImportExport/GenerateTwo.cs b/SabreTools/ImportExport/GenerateTwo.cs index f255eeca..ce4a4779 100644 --- a/SabreTools/ImportExport/GenerateTwo.cs +++ b/SabreTools/ImportExport/GenerateTwo.cs @@ -85,8 +85,8 @@ namespace SabreTools return false; } - path += Path.DirectorySeparatorChar + system.Trim(); name = system.Trim(); + path = Path.Combine(path, name); } else { diff --git a/SabreTools/ImportExport/ImportTwo.cs b/SabreTools/ImportExport/ImportTwo.cs index a1543ea4..c8348a24 100644 --- a/SabreTools/ImportExport/ImportTwo.cs +++ b/SabreTools/ImportExport/ImportTwo.cs @@ -110,7 +110,7 @@ namespace SabreTools _logger.User("Processing DATs for system: '" + kv.Key + "'"); // Set the folder to iterate through based on the DAT root - string folder = _datroot + Path.DirectorySeparatorChar + kv.Key.Trim(); + string folder = Path.Combine(_datroot, kv.Key.Trim()); // Audit all files in the folder foreach (string file in Directory.EnumerateFiles(folder, "*", SearchOption.AllDirectories)) diff --git a/SabreTools/MergeDiff.cs b/SabreTools/MergeDiff.cs index 872dd489..1390d9c1 100644 --- a/SabreTools/MergeDiff.cs +++ b/SabreTools/MergeDiff.cs @@ -482,8 +482,7 @@ namespace SabreTools rootpath += (rootpath == "" ? "" : Path.DirectorySeparatorChar.ToString()); filename = filename.Remove(0, rootpath.Length); - newrom.Game = Path.GetDirectoryName(filename) + Path.DirectorySeparatorChar.ToString() + - Path.GetFileNameWithoutExtension(filename) + Path.DirectorySeparatorChar + newrom.Game; + newrom.Game = Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename), newrom.Game); newroms.Add(newrom); } userData.Roms[key] = newroms; diff --git a/SabreTools/Partials/SabreTools_Helpers.cs b/SabreTools/Partials/SabreTools_Helpers.cs index c8e3c767..e7a6043f 100644 --- a/SabreTools/Partials/SabreTools_Helpers.cs +++ b/SabreTools/Partials/SabreTools_Helpers.cs @@ -14,7 +14,6 @@ namespace SabreTools /// private static void Setup() { - Remapping.CreateRemappings(); Build.Start("DATabase"); // Perform initial database and folder setup @@ -40,7 +39,7 @@ namespace SabreTools while (sldr.Read()) { int systemid = sldr.GetInt32(0); - string system = _datroot + Path.DirectorySeparatorChar + sldr.GetString(1) + " - " + sldr.GetString(2); + string system = Path.Combine(_datroot, sldr.GetString(1) + " - " + sldr.GetString(2)); system = system.Trim(); if (!Directory.Exists(system)) diff --git a/SimpleSort/SimpleSort.cs b/SimpleSort/SimpleSort.cs index 0299dfcc..6976a9f0 100644 --- a/SimpleSort/SimpleSort.cs +++ b/SimpleSort/SimpleSort.cs @@ -64,7 +64,6 @@ namespace SabreTools // Perform initial setup and verification Logger logger = new Logger(true, "simplesort.log"); logger.Start(); - Remapping.CreateHeaderSkips(); // Credits take precidence over all if ((new List(args)).Contains("--credits")) @@ -535,7 +534,7 @@ namespace SabreTools // Assuming archived sets, move all toplevel folders to temp foreach (string directory in Directory.EnumerateDirectories(_outdir, "*", SearchOption.TopDirectoryOnly)) { - Directory.Move(directory, _tempdir + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(directory)); + Directory.Move(directory, Path.Combine(_tempdir, Path.GetFileNameWithoutExtension(directory))); } // Now process the inputs (assumed that it's archived sets as of right now @@ -544,12 +543,12 @@ namespace SabreTools // If the name of the archive is not in the set exactly, move it to temp if (!sortedByGame.ContainsKey(Path.GetFileNameWithoutExtension(archive))) { - File.Move(archive, _tempdir + Path.DirectorySeparatorChar + archive); + File.Move(archive, Path.Combine(_tempdir, archive)); } // Otherwise, we check if it's an archive. If it's not, move it to temp else if (ArchiveTools.GetCurrentArchiveType(Path.GetFullPath(archive), _logger) == null) { - File.Move(Path.GetFullPath(archive), _tempdir + Path.DirectorySeparatorChar + archive); + File.Move(Path.GetFullPath(archive), Path.Combine(_tempdir, archive)); } // Finally, if it's an archive and exists properly, we check the insides else @@ -564,7 +563,7 @@ namespace SabreTools // Otherwise, extract it and get info one by one else { - string temparcdir = _tempdir + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(archive); + string temparcdir = Path.Combine(_tempdir, Path.GetFileNameWithoutExtension(archive)); ArchiveTools.ExtractArchive(Path.GetFullPath(archive), temparcdir, _logger); foreach (string tempfile in Directory.EnumerateFiles(temparcdir, "*", SearchOption.AllDirectories)) {