From ce648ad8537c1fa57e521c7ac55add4d2146fa29 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Tue, 5 Apr 2016 15:54:58 -0700 Subject: [PATCH] Create DatSplit This new tool can split DAT files by the extension of the files involved. This will help split things like the NonGoods properly. It's highly in beta, but hey, it's working! --- DatSplit/App.config | 6 + DatSplit/DatSplit.cs | 182 ++++++++++++++++++++++++++++ DatSplit/DatSplit.csproj | 66 ++++++++++ DatSplit/Properties/AssemblyInfo.cs | 36 ++++++ SabreTools.sln | 6 + 5 files changed, 296 insertions(+) create mode 100644 DatSplit/App.config create mode 100644 DatSplit/DatSplit.cs create mode 100644 DatSplit/DatSplit.csproj create mode 100644 DatSplit/Properties/AssemblyInfo.cs diff --git a/DatSplit/App.config b/DatSplit/App.config new file mode 100644 index 00000000..88fa4027 --- /dev/null +++ b/DatSplit/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/DatSplit/DatSplit.cs b/DatSplit/DatSplit.cs new file mode 100644 index 00000000..5c2fa110 --- /dev/null +++ b/DatSplit/DatSplit.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Xml; +using System.Xml.Linq; + +using SabreTools.Helper; + +namespace DatSplit +{ + class DatSplit + { + private static string extA; + private static string extB; + private static string filename; + + public static void Main(string[] args) + { + // If we don't have arguments, show help + if (args.Length == 0 && args.Length != 3) + { + Help(); + return; + } + + // Set needed strings + filename = args[0]; + extA = args[1]; + extB = args[2]; + + // Take the filename, and load it as an XML document + XmlDocument doc = new XmlDocument(); + try + { + doc.LoadXml(File.ReadAllText(filename)); + } + catch (XmlException ex) + { + doc.LoadXml(Converters.RomVaultToXML(File.ReadAllLines(filename)).ToString()); + } + + // We all start the same + XmlNode node = doc.FirstChild; + if (node != null && node.Name == "xml") + { + // Skip over everything that's not an element + while (node.NodeType != XmlNodeType.Element) + { + node = node.NextSibling; + } + } + + XmlDocument tempDoc = new XmlDocument(); + XmlNode outA = tempDoc.CreateNode(XmlNodeType.Element, node.Name, ""); + XmlNode outB = tempDoc.CreateNode(XmlNodeType.Element, node.Name, ""); + + // Once we find the main body, enter it + if (node != null && node.Name == "datafile") + { + node = node.FirstChild; + } + + // Now here's where it differs from import + while (node != null) + { + // If we're at a game node, add the parent node but not all the internals + if (node.NodeType == XmlNodeType.Element && (node.Name == "machine" || node.Name == "game")) + { + bool inA = false; + bool inB = false; + + // Get the roms from the machine + if (node.HasChildNodes) + { + // If this node has children, traverse the children + foreach (XmlNode child in node.ChildNodes) + { + // If we find a rom or disk, add it + if (child.NodeType == XmlNodeType.Element && (child.Name == "rom" || child.Name == "disk")) + { + // Take care of hex-sized files + long size = -1; + if (child.Attributes["size"] != null && child.Attributes["size"].Value.Contains("0x")) + { + size = Convert.ToInt64(child.Attributes["size"].Value, 16); + } + else if (child.Attributes["size"] != null) + { + size = Int64.Parse(child.Attributes["size"].Value); + } + + if (child.Attributes["name"].Value.EndsWith(extA)) + { + if (!inA) + { + //XmlNode temp = tempDoc.CreateNode(XmlNodeType.Element, node.Name, ""); + XmlNode temp = tempDoc.ImportNode(node, false); + outA.AppendChild(temp); + outA = outA.LastChild; + inA = true; + } + outA.AppendChild(tempDoc.ImportNode(child, true)); + } + else if (child.Attributes["name"].Value.EndsWith(extB)) + { + if (!inB) + { + //XmlNode temp = tempDoc.CreateNode(XmlNodeType.Element, node.Name, ""); + XmlNode temp = tempDoc.ImportNode(node, false); + outB.AppendChild(temp); + outB = outB.LastChild; + inB = true; + } + outB.AppendChild(tempDoc.ImportNode(child, true)); + } + else + { + outA.AppendChild(tempDoc.ImportNode(child, true)); + outB.AppendChild(tempDoc.ImportNode(child, true)); + } + } + } + + // Set the output node to the right one for both + if (inA) + { + outA = outA.ParentNode; + } + if (inB) + { + outB = outB.ParentNode; + } + } + } + else + { + XmlNode tempNode = tempDoc.ImportNode(node, true); + outA.AppendChild(tempNode); + tempNode = tempDoc.ImportNode(node, true); + outB.AppendChild(tempNode); + } + node = node.NextSibling; + } + + XmlDocument outDocA = new XmlDocument(); + outDocA.AppendChild(outDocA.CreateDocumentType("datafile", "-//Logiqx//DTD ROM Management Datafile//EN", "http://www.logiqx.com/Dats/datafile.dtd", null)); + outDocA.AppendChild(outDocA.ImportNode(outA, true)); + string outPathA = Path.GetFileNameWithoutExtension(filename) + extA + Path.GetExtension(filename); + File.WriteAllText(outPathA, Beautify(outDocA)); + + XmlDocument outDocB = new XmlDocument(); + outDocB.AppendChild(outDocB.CreateDocumentType("datafile", "-//Logiqx//DTD ROM Management Datafile//EN", "http://www.logiqx.com/Dats/datafile.dtd", null)); + outDocB.AppendChild(outDocB.ImportNode(outB, true)); + string outPathB = Path.GetFileNameWithoutExtension(filename) + extB + Path.GetExtension(filename); + File.WriteAllText(outPathB, Beautify(outDocB)); + } + + public static void Help() + { + Console.WriteLine("DatSplit.exe "); + } + + // http://stackoverflow.com/questions/203528/what-is-the-simplest-way-to-get-indented-xml-with-line-breaks-from-xmldocument + static public string Beautify(XmlDocument doc) + { + StringBuilder sb = new StringBuilder(); + XmlWriterSettings settings = new XmlWriterSettings + { + Indent = true, + IndentChars = "\t", + NewLineChars = "\r\n", + NewLineHandling = NewLineHandling.Replace + }; + using (XmlWriter writer = XmlWriter.Create(sb, settings)) + { + doc.Save(writer); + } + return sb.ToString(); + } + } +} diff --git a/DatSplit/DatSplit.csproj b/DatSplit/DatSplit.csproj new file mode 100644 index 00000000..3b024aa3 --- /dev/null +++ b/DatSplit/DatSplit.csproj @@ -0,0 +1,66 @@ + + + + + Debug + AnyCPU + {9EB4738D-CAE7-420D-8A26-78A53CEA5E82} + Exe + Properties + DatSplit + DatSplit + v4.5.2 + 512 + true + + + AnyCPU + true + full + false + ..\..\Builds\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + {3b615702-1866-4d7b-8af1-7b43fd0cc1d0} + DATabase + + + + + \ No newline at end of file diff --git a/DatSplit/Properties/AssemblyInfo.cs b/DatSplit/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..93cee71c --- /dev/null +++ b/DatSplit/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DatSplit")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DatSplit")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("9eb4738d-cae7-420d-8a26-78a53cea5e82")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SabreTools.sln b/SabreTools.sln index beb29ed7..6c8ab127 100644 --- a/SabreTools.sln +++ b/SabreTools.sln @@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Headerer", "Deheader\Header EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SabreToolsUI", "SabreToolsUI\SabreToolsUI.csproj", "{7DC54E53-4A46-4323-97E1-062EEFB7E4BC}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DatSplit", "DatSplit\DatSplit.csproj", "{9EB4738D-CAE7-420D-8A26-78A53CEA5E82}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,6 +29,10 @@ Global {7DC54E53-4A46-4323-97E1-062EEFB7E4BC}.Debug|Any CPU.Build.0 = Debug|Any CPU {7DC54E53-4A46-4323-97E1-062EEFB7E4BC}.Release|Any CPU.ActiveCfg = Release|Any CPU {7DC54E53-4A46-4323-97E1-062EEFB7E4BC}.Release|Any CPU.Build.0 = Release|Any CPU + {9EB4738D-CAE7-420D-8A26-78A53CEA5E82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9EB4738D-CAE7-420D-8A26-78A53CEA5E82}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9EB4738D-CAE7-420D-8A26-78A53CEA5E82}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9EB4738D-CAE7-420D-8A26-78A53CEA5E82}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE