diff --git a/SabreTools.Skippers/Enums.cs b/SabreTools.Skippers/Enums.cs index 8535aa6f..ab4ae5d6 100644 --- a/SabreTools.Skippers/Enums.cs +++ b/SabreTools.Skippers/Enums.cs @@ -12,18 +12,6 @@ WordByteswap, } - /// - /// Determines the type of test to be done - /// - public enum HeaderSkipTest - { - Data = 0, - Or, - Xor, - And, - File, - } - /// /// Determines the operator to be used in a file test /// diff --git a/SabreTools.Skippers/SkipperFile.cs b/SabreTools.Skippers/SkipperFile.cs index 44fca1e3..4fc07528 100644 --- a/SabreTools.Skippers/SkipperFile.cs +++ b/SabreTools.Skippers/SkipperFile.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.IO; using System.Xml; using System.Xml.Schema; +using System.Xml.Serialization; namespace SabreTools.Skippers { @@ -20,26 +21,31 @@ namespace SabreTools.Skippers /// /// Skipper name /// + [XmlElement("name")] public string Name { get; set; } = string.Empty; /// /// Author names /// + [XmlElement("author")] public string Author { get; set; } = string.Empty; /// /// File version /// + [XmlElement("version")] public string Version { get; set; } = string.Empty; /// /// Set of all rules in the skipper /// + [XmlArray("rule")] public List Rules { get; set; } = new List(); /// /// Filename the skipper lives in /// + [XmlIgnore] public string SourceFile { get; set; } = string.Empty; #endregion @@ -129,7 +135,7 @@ namespace SabreTools.Skippers SkipperRule rule = ParseRule(xtr); if (rule != null) Rules.Add(rule); - + xtr.Read(); break; @@ -227,7 +233,7 @@ namespace SabreTools.Skippers subreader.Read(); break; - + default: subreader.Read(); break; @@ -256,41 +262,27 @@ namespace SabreTools.Skippers try { // Get the test type - SkipperTest test = new SkipperTest + SkipperTest test = xtr.Name.ToLowerInvariant() switch { - Offset = 0, - Value = new byte[0], - Result = true, - Mask = new byte[0], - Size = 0, - Operator = HeaderSkipTestFileOperator.Equal, + "and" => new AndSkipperTest(), + "data" => new DataSkipperTest(), + "file" => new FileSkipperTest(), + "or" => new OrSkipperTest(), + "xor" => new XorSkipperTest(), + _ => null, }; - switch (xtr.Name.ToLowerInvariant()) - { - case "data": - test.Type = HeaderSkipTest.Data; - break; + // If we had an invalid test type + if (test == null) + return null; - 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: - return null; - } + // Set the default values + test.Offset = 0; + test.Value = Array.Empty(); + test.Result = true; + test.Mask = Array.Empty(); + test.Size = 0; + test.Operator = HeaderSkipTestFileOperator.Equal; // Now populate all the parts that we can if (xtr.GetAttribute("offset") != null) diff --git a/SabreTools.Skippers/SkipperFiles/Atari7800.cs b/SabreTools.Skippers/SkipperFiles/Atari7800.cs index bd3f4005..9f196194 100644 --- a/SabreTools.Skippers/SkipperFiles/Atari7800.cs +++ b/SabreTools.Skippers/SkipperFiles/Atari7800.cs @@ -11,17 +11,15 @@ namespace SabreTools.Skippers.SkipperFiles public Atari7800() { // Create tests - var rule1Test1 = new SkipperTest + var rule1Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x01, Value = new byte[] { 0x41, 0x54, 0x41, 0x52, 0x49, 0x37, 0x38, 0x30, 0x30 }, Result = true, }; - var rule2Test1 = new SkipperTest + var rule2Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x64, Value = new byte[] { 0x41, 0x43, 0x54, 0x55, 0x41, 0x4C, 0x20, 0x43, 0x41, 0x52, 0x54, 0x20, 0x44, 0x41, 0x54, 0x41, 0x20, 0x53, 0x54, 0x41, 0x52, 0x54, 0x53, 0x20, 0x48, 0x45, 0x52, 0x45 }, Result = true, diff --git a/SabreTools.Skippers/SkipperFiles/AtariLynx.cs b/SabreTools.Skippers/SkipperFiles/AtariLynx.cs index 44b424a3..8399e9b6 100644 --- a/SabreTools.Skippers/SkipperFiles/AtariLynx.cs +++ b/SabreTools.Skippers/SkipperFiles/AtariLynx.cs @@ -11,17 +11,15 @@ namespace SabreTools.Skippers.SkipperFiles public AtariLynx() { // Create tests - var rule1Test1 = new SkipperTest + var rule1Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x4C, 0x59, 0x4E, 0x58 }, Result = true, }; - var rule2Test1 = new SkipperTest + var rule2Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x06, Value = new byte[] { 0x42, 0x53, 0x39 }, Result = true, diff --git a/SabreTools.Skippers/SkipperFiles/CommodorePSID.cs b/SabreTools.Skippers/SkipperFiles/CommodorePSID.cs index 2ddf741d..46ac4740 100644 --- a/SabreTools.Skippers/SkipperFiles/CommodorePSID.cs +++ b/SabreTools.Skippers/SkipperFiles/CommodorePSID.cs @@ -11,41 +11,36 @@ namespace SabreTools.Skippers.SkipperFiles public CommodorePSID() { // Create tests - var rule1Test1 = new SkipperTest + var rule1Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x50, 0x53, 0x49, 0x44, 0x00, 0x01, 0x00, 0x76 }, Result = true, }; - var rule2Test1 = new SkipperTest + var rule2Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x50, 0x53, 0x49, 0x44, 0x00, 0x03, 0x00, 0x7c }, Result = true, }; - var rule3Test1 = new SkipperTest + var rule3Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x50, 0x53, 0x49, 0x44, 0x00, 0x02, 0x00, 0x7c }, Result = true, }; - var rule4Test1 = new SkipperTest + var rule4Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x50, 0x53, 0x49, 0x44, 0x00, 0x01, 0x00, 0x7c }, Result = true, }; - var rule5Test1 = new SkipperTest + var rule5Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x52, 0x53, 0x49, 0x44, 0x00, 0x02, 0x00, 0x7c }, Result = true, diff --git a/SabreTools.Skippers/SkipperFiles/NECPCEngine.cs b/SabreTools.Skippers/SkipperFiles/NECPCEngine.cs index acfc72e4..a4e973fe 100644 --- a/SabreTools.Skippers/SkipperFiles/NECPCEngine.cs +++ b/SabreTools.Skippers/SkipperFiles/NECPCEngine.cs @@ -11,9 +11,8 @@ namespace SabreTools.Skippers.SkipperFiles public NECPCEngine() { // Create tests - var rule1Test1 = new SkipperTest + var rule1Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xBB, 0x02 }, Result = true, diff --git a/SabreTools.Skippers/SkipperFiles/Nintendo64.cs b/SabreTools.Skippers/SkipperFiles/Nintendo64.cs index 2df5b23b..2178d9e3 100644 --- a/SabreTools.Skippers/SkipperFiles/Nintendo64.cs +++ b/SabreTools.Skippers/SkipperFiles/Nintendo64.cs @@ -11,25 +11,22 @@ namespace SabreTools.Skippers.SkipperFiles public Nintendo64() { // Create tests - var rule1Test1 = new SkipperTest + var rule1Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x80, 0x37, 0x12, 0x40 }, Result = true, }; - var rule2Test1 = new SkipperTest + var rule2Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x37, 0x80, 0x40, 0x12 }, Result = true, }; - var rule3Test1 = new SkipperTest + var rule3Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x40, 0x12, 0x37, 0x80 }, Result = true, diff --git a/SabreTools.Skippers/SkipperFiles/NintendoEntertainmentSystem.cs b/SabreTools.Skippers/SkipperFiles/NintendoEntertainmentSystem.cs index edb024fb..04ce1ebe 100644 --- a/SabreTools.Skippers/SkipperFiles/NintendoEntertainmentSystem.cs +++ b/SabreTools.Skippers/SkipperFiles/NintendoEntertainmentSystem.cs @@ -11,9 +11,8 @@ namespace SabreTools.Skippers.SkipperFiles public NintendoEntertainmentSystem() { // Create tests - var rule1Test1 = new SkipperTest + var rule1Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x4E, 0x45, 0x53, 0x1A }, Result = true, diff --git a/SabreTools.Skippers/SkipperFiles/NintendoFamicomDiskSystem.cs b/SabreTools.Skippers/SkipperFiles/NintendoFamicomDiskSystem.cs index ce25cd98..9708441c 100644 --- a/SabreTools.Skippers/SkipperFiles/NintendoFamicomDiskSystem.cs +++ b/SabreTools.Skippers/SkipperFiles/NintendoFamicomDiskSystem.cs @@ -11,33 +11,29 @@ namespace SabreTools.Skippers.SkipperFiles public NintendoFamicomDiskSystem() { // Create tests - var rule1Test1 = new SkipperTest + var rule1Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x46, 0x44, 0x53, 0x1A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, Result = true, }; - var rule2Test1 = new SkipperTest + var rule2Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x46, 0x44, 0x53, 0x1A, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, Result = true, }; - var rule3Test1 = new SkipperTest + var rule3Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x46, 0x44, 0x53, 0x1A, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, Result = true, }; - var rule4Test1 = new SkipperTest + var rule4Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x46, 0x44, 0x53, 0x1A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, Result = true, diff --git a/SabreTools.Skippers/SkipperFiles/SuperFamicomSPC.cs b/SabreTools.Skippers/SkipperFiles/SuperFamicomSPC.cs index f693d0d8..ffd677f3 100644 --- a/SabreTools.Skippers/SkipperFiles/SuperFamicomSPC.cs +++ b/SabreTools.Skippers/SkipperFiles/SuperFamicomSPC.cs @@ -11,9 +11,8 @@ namespace SabreTools.Skippers.SkipperFiles public SuperFamicomSPC() { // Create tests - var rule1Test1 = new SkipperTest + var rule1Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x53, 0x4E, 0x45, 0x53, 0x2D, 0x53, 0x50, 0x43 }, Result = true, diff --git a/SabreTools.Skippers/SkipperFiles/SuperNintendoEntertainmentSystem.cs b/SabreTools.Skippers/SkipperFiles/SuperNintendoEntertainmentSystem.cs index e28d54f3..24ea94ce 100644 --- a/SabreTools.Skippers/SkipperFiles/SuperNintendoEntertainmentSystem.cs +++ b/SabreTools.Skippers/SkipperFiles/SuperNintendoEntertainmentSystem.cs @@ -11,25 +11,22 @@ namespace SabreTools.Skippers.SkipperFiles public SuperNintendoEntertainmentSystem() { // Create tests - var rule1Test1 = new SkipperTest + var rule1Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x16, Value = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, Result = true, }; - var rule2Test1 = new SkipperTest + var rule2Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x16, Value = new byte[] { 0xAA, 0xBB, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }, Result = true, }; - var rule3Test1 = new SkipperTest + var rule3Test1 = new DataSkipperTest { - Type = HeaderSkipTest.Data, Offset = 0x16, Value = new byte[] { 0x53, 0x55, 0x50, 0x45, 0x52, 0x55, 0x46, 0x4F }, Result = true, diff --git a/SabreTools.Skippers/SkipperRule.cs b/SabreTools.Skippers/SkipperRule.cs index a845d686..0187e1be 100644 --- a/SabreTools.Skippers/SkipperRule.cs +++ b/SabreTools.Skippers/SkipperRule.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Xml.Serialization; using SabreTools.Logging; @@ -13,26 +14,36 @@ namespace SabreTools.Skippers /// /// Starting offset for applying rule /// + [XmlAttribute("start_offset")] public long? StartOffset { get; set; } // null is EOF /// /// Ending offset for applying rule /// + [XmlAttribute("end_offset")] public long? EndOffset { get; set; } // null if EOF /// /// Byte manipulation operation /// + [XmlAttribute("operation")] public HeaderSkipOperation Operation { get; set; } /// /// List of matching tests in a rule /// + [XmlArray] + [XmlArrayItem("data")] + [XmlArrayItem("or")] + [XmlArrayItem("xor")] + [XmlArrayItem("and")] + [XmlArrayItem("file")] public List Tests { get; set; } /// /// Filename the skipper rule lives in /// + [XmlIgnore] public string SourceFile { get; set; } #endregion diff --git a/SabreTools.Skippers/SkipperTest.cs b/SabreTools.Skippers/SkipperTest.cs index b6510fa9..25fa472e 100644 --- a/SabreTools.Skippers/SkipperTest.cs +++ b/SabreTools.Skippers/SkipperTest.cs @@ -1,49 +1,52 @@ using System; using System.IO; +using System.Xml; +using System.Xml.Serialization; namespace SabreTools.Skippers { /// /// Individual test that applies to a SkipperRule /// - public class SkipperTest + public abstract class SkipperTest { #region Fields - /// - /// Type of test to be run - /// - public HeaderSkipTest Type { get; set; } - /// /// File offset to run the test /// /// null is EOF + [XmlAttribute("offset")] public long? Offset { get; set; } /// /// Static value to be checked at the offset /// + [XmlAttribute("value")] public byte[] Value { get; set; } /// /// Determines whether a pass or failure is expected /// + [XmlAttribute("result")] public bool Result { get; set; } /// /// Byte mask to be applied to the tested bytes /// + [XmlAttribute("mask")] public byte[] Mask { get; set; } /// /// Expected size of the input byte array, used with the Operator /// + [XmlAttribute("size")] public long? Size { get; set; } // null is PO2, "power of 2" filesize /// /// Expected range value for the input byte array size, used with Size /// + [XmlAttribute("operator")] public HeaderSkipTestFileOperator Operator { get; set; } #endregion @@ -53,27 +56,50 @@ namespace SabreTools.Skippers /// /// Stream to check rule against /// The Stream is assumed to be in the proper position for a given test - public bool Passes(Stream input) - { - return Type switch - { - HeaderSkipTest.And => CheckAnd(input), - HeaderSkipTest.Data => CheckData(input), - HeaderSkipTest.File => CheckFile(input), - HeaderSkipTest.Or => CheckOr(input), - HeaderSkipTest.Xor => CheckXor(input), - _ => true, - }; - } + public abstract bool Passes(Stream input); #region Checking Helpers /// - /// Run an And test against an input stream + /// Seek an input stream based on the test value /// - /// Stream to check rule against - /// True if the stream passed, false otherwise - private bool CheckAnd(Stream input) + /// Stream to seek + /// True if the stream could seek, false on error + protected bool Seek(Stream input) + { + try + { + // Null offset means EOF + if (Offset == null) + input.Seek(0, SeekOrigin.End); + + // Positive offset means from beginning + else if (Offset >= 0 && Offset <= input.Length) + input.Seek(Offset.Value, SeekOrigin.Begin); + + // Negative offset means from end + else if (Offset < 0 && Math.Abs(Offset.Value) <= input.Length) + input.Seek(Offset.Value, SeekOrigin.End); + + return true; + } + catch + { + return false; + } + } + + #endregion + } + + /// + /// Skipper test using AND + /// + [XmlRoot("and")] + public class AndSkipperTest : SkipperTest + { + /// + public override bool Passes(Stream input) { // First seek to the correct position Seek(input); @@ -109,13 +135,16 @@ namespace SabreTools.Skippers // Return if the expected and actual results match return result == Result; } + } - /// - /// Run a Data test against an input stream - /// - /// Stream to check rule against - /// True if the stream passed, false otherwise - private bool CheckData(Stream input) + /// + /// Skipper test using DATA + /// + [XmlRoot("data")] + public class DataSkipperTest : SkipperTest + { + /// + public override bool Passes(Stream input) { // First seek to the correct position if (!Seek(input)) @@ -143,13 +172,16 @@ namespace SabreTools.Skippers // Return if the expected and actual results match return result == Result; } + } - /// - /// Run a File test against an input stream - /// - /// Stream to check rule against - /// True if the stream passed, false otherwise - private bool CheckFile(Stream input) + /// + /// Skipper test using FILE + /// + [XmlRoot("file")] + public class FileSkipperTest : SkipperTest + { + /// + public override bool Passes(Stream input) { // First get the file size from stream long size = input.Length; @@ -177,13 +209,16 @@ namespace SabreTools.Skippers // Return if the expected and actual results match return result == Result; } + } - /// - /// Run an Or test against an input stream - /// - /// Stream to check rule against - /// True if the stream passed, false otherwise - private bool CheckOr(Stream input) + /// + /// Skipper test using OR + /// + [XmlRoot("or")] + public class OrSkipperTest : SkipperTest + { + /// + public override bool Passes(Stream input) { // First seek to the correct position Seek(input); @@ -219,13 +254,16 @@ namespace SabreTools.Skippers // Return if the expected and actual results match return result == Result; } + } - /// - /// Run an Xor test against an input stream - /// - /// Stream to check rule against - /// True if the stream passed, false otherwise - private bool CheckXor(Stream input) + /// + /// Skipper test using XOR + /// + [XmlRoot("xor")] + public class XorSkipperTest : SkipperTest + { + /// + public override bool Passes(Stream input) { // First seek to the correct position Seek(input); @@ -261,36 +299,5 @@ namespace SabreTools.Skippers // Return if the expected and actual results match return result == Result; } - - /// - /// Seek an input stream based on the test value - /// - /// Stream to seek - /// True if the stream could seek, false on error - private bool Seek(Stream input) - { - try - { - // Null offset means EOF - if (Offset == null) - input.Seek(0, SeekOrigin.End); - - // Positive offset means from beginning - else if (Offset >= 0 && Offset <= input.Length) - input.Seek(Offset.Value, SeekOrigin.Begin); - - // Negative offset means from end - else if (Offset < 0 && Math.Abs(Offset.Value) <= input.Length) - input.Seek(Offset.Value, SeekOrigin.End); - - return true; - } - catch - { - return false; - } - } - - #endregion } } \ No newline at end of file