/// <summary> /// Parse an XML document in as a SkipperTest /// </summary> /// <param name="xtr">XmlReader representing the document</param> /// <returns>Filled SkipperTest on success, null otherwise</returns> private SkipperTest ParseTest(XmlReader xtr) { if (xtr == null) { return(null); } try { // 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 (xtr.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: return(null); } // Now populate all the parts that we can if (xtr.GetAttribute("offset") != null) { string offset = xtr.GetAttribute("offset"); if (offset.ToLowerInvariant() == "eof") { test.Offset = null; } else { test.Offset = Convert.ToInt64(offset, 16); } } if (xtr.GetAttribute("value") != null) { string value = xtr.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 (xtr.GetAttribute("result") != null) { string result = xtr.GetAttribute("result"); if (!bool.TryParse(result, out bool resultBool)) { resultBool = true; } test.Result = resultBool; } if (xtr.GetAttribute("mask") != null) { string mask = xtr.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 (xtr.GetAttribute("size") != null) { string size = xtr.GetAttribute("size"); if (size.ToLowerInvariant() == "po2") { test.Size = null; } else { test.Size = Convert.ToInt64(size, 16); } } if (xtr.GetAttribute("operator") != null) { string oper = xtr.GetAttribute("operator"); test.Operator = oper.ToLowerInvariant() switch { "less" => HeaderSkipTestFileOperator.Less, "greater" => HeaderSkipTestFileOperator.Greater, "equal" => HeaderSkipTestFileOperator.Equal, _ => HeaderSkipTestFileOperator.Equal, }; } return(test); } catch { return(null); } }
/// <summary> /// Parse an XML document in as a SkipperRule /// </summary> /// <param name="xtr">XmlReader representing the document</param> /// <returns>Filled SkipperRule on success, null otherwise</returns> private SkipperRule ParseRule(XmlReader xtr) { if (xtr == null) { return(null); } try { // Get the information from the rule first SkipperRule rule = new SkipperRule { StartOffset = null, EndOffset = null, Operation = HeaderSkipOperation.None, Tests = new List <SkipperTest>(), SourceFile = this.SourceFile, }; string startOffset = xtr.GetAttribute("start_offset"); if (startOffset != null) { if (startOffset.ToLowerInvariant() == "eof") { rule.StartOffset = null; } else { rule.StartOffset = Convert.ToInt64(startOffset, 16); } } string endOffset = xtr.GetAttribute("end_offset"); if (endOffset != null) { if (endOffset.ToLowerInvariant() == "eof") { rule.EndOffset = null; } else { rule.EndOffset = Convert.ToInt64(endOffset, 16); } } string operation = xtr.GetAttribute("operation"); if (operation != null) { 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) { subreader.MoveToContent(); while (!subreader.EOF) { if (subreader.NodeType != XmlNodeType.Element) { subreader.Read(); } switch (xtr.Name.ToLowerInvariant()) { case "data": case "or": case "xor": case "and": case "file": SkipperTest test = ParseTest(subreader); if (test != null) { rule.Tests.Add(test); } subreader.Read(); break; default: subreader.Read(); break; } } } return(rule); } catch { return(null); } }
/// <summary> /// Generate a SkipperFile for Super Nintendo Entertainment System headers /// </summary> /// <remarks>Originally from snes.xml</remarks> private static SkipperFile GetSuperNintendoEntertainmentSystem() { // Create tests var rule1Test1 = new SkipperTest { Type = HeaderSkipTest.Data, Offset = 0x16, Value = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, Result = true, }; var rule2Test1 = new SkipperTest { Type = HeaderSkipTest.Data, Offset = 0x16, Value = new byte[] { 0xAA, 0xBB, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }, Result = true, }; var rule3Test1 = new SkipperTest { Type = HeaderSkipTest.Data, Offset = 0x16, Value = new byte[] { 0x53, 0x55, 0x50, 0x45, 0x52, 0x55, 0x46, 0x4F }, Result = true, }; // Create rules var rule1 = new SkipperRule { StartOffset = 0x200, EndOffset = null, Operation = HeaderSkipOperation.None, Tests = new List <SkipperTest> { rule1Test1, } }; var rule2 = new SkipperRule { StartOffset = 0x200, EndOffset = null, Operation = HeaderSkipOperation.None, Tests = new List <SkipperTest> { rule2Test1, } }; var rule3 = new SkipperRule { StartOffset = 0x200, EndOffset = null, Operation = HeaderSkipOperation.None, Tests = new List <SkipperTest> { rule3Test1, } }; // Create file var skipperFile = new SkipperFile { Name = "Nintendo Super Famicom/SNES", Author = "Matt Nadareski (darksabre76)", Version = "1.0", SourceFile = "snes", Rules = new List <SkipperRule> { rule1, // FIG rule2, // SMC rule3, // UFO }, }; return(skipperFile); }
/// <summary> /// Generate a SkipperFile for Nintendo Famicom Disk System headers /// </summary> /// <remarks>Originally from fds.xml</remarks> private static SkipperFile GetNintendoFamicomDiskSystem() { // Create tests var rule1Test1 = new SkipperTest { 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 { 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 { 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 { 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, }; // Create rules var rule1 = new SkipperRule { StartOffset = 0x10, EndOffset = null, Operation = HeaderSkipOperation.None, Tests = new List <SkipperTest> { rule1Test1, } }; var rule2 = new SkipperRule { StartOffset = 0x10, EndOffset = null, Operation = HeaderSkipOperation.None, Tests = new List <SkipperTest> { rule2Test1, } }; var rule3 = new SkipperRule { StartOffset = 0x10, EndOffset = null, Operation = HeaderSkipOperation.None, Tests = new List <SkipperTest> { rule3Test1, } }; var rule4 = new SkipperRule { StartOffset = 0x10, EndOffset = null, Operation = HeaderSkipOperation.None, Tests = new List <SkipperTest> { rule4Test1, } }; // Create file var skipperFile = new SkipperFile { Name = "fds", Author = "Yori Yoshizuki", Version = "1.0", SourceFile = "fds", Rules = new List <SkipperRule> { rule1, rule2, rule3, rule4, }, }; return(skipperFile); }
/// <summary> /// Generate a SkipperFile for Nintendo 64 headers /// </summary> /// <remarks>Originally from n64.xml</remarks> private static SkipperFile GetNintendo64() { // Create tests var rule1Test1 = new SkipperTest { Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x80, 0x37, 0x12, 0x40 }, Result = true, }; var rule2Test1 = new SkipperTest { Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x37, 0x80, 0x40, 0x12 }, Result = true, }; var rule3Test1 = new SkipperTest { Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x40, 0x12, 0x37, 0x80 }, Result = true, }; // Create rules var rule1 = new SkipperRule { StartOffset = 0x00, EndOffset = null, Operation = HeaderSkipOperation.None, Tests = new List <SkipperTest> { rule1Test1, } }; var rule2 = new SkipperRule { StartOffset = 0x00, EndOffset = null, Operation = HeaderSkipOperation.Byteswap, Tests = new List <SkipperTest> { rule2Test1, } }; var rule3 = new SkipperRule { StartOffset = 0x00, EndOffset = null, Operation = HeaderSkipOperation.Wordswap, Tests = new List <SkipperTest> { rule3Test1, } }; // Create file var skipperFile = new SkipperFile { Name = "Nintendo 64 - ABCD", Author = "CUE", Version = "1.1", SourceFile = "n64", Rules = new List <SkipperRule> { rule1, // V64 rule2, // Z64 rule3, // N64 }, }; return(skipperFile); }
/// <summary> /// Generate a SkipperFile for Commodore PSID headers /// </summary> /// <remarks>Originally from psid.xml</remarks> private static SkipperFile GetCommodorePSID() { // Create tests var rule1Test1 = new SkipperTest { Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x50, 0x53, 0x49, 0x44, 0x00, 0x01, 0x00, 0x76 }, Result = true, }; var rule2Test1 = new SkipperTest { Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x50, 0x53, 0x49, 0x44, 0x00, 0x03, 0x00, 0x7c }, Result = true, }; var rule3Test1 = new SkipperTest { Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x50, 0x53, 0x49, 0x44, 0x00, 0x02, 0x00, 0x7c }, Result = true, }; var rule4Test1 = new SkipperTest { Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x50, 0x53, 0x49, 0x44, 0x00, 0x01, 0x00, 0x7c }, Result = true, }; var rule5Test1 = new SkipperTest { Type = HeaderSkipTest.Data, Offset = 0x00, Value = new byte[] { 0x52, 0x53, 0x49, 0x44, 0x00, 0x02, 0x00, 0x7c }, Result = true, }; // Create rules var rule1 = new SkipperRule { StartOffset = 0x76, EndOffset = null, Operation = HeaderSkipOperation.None, Tests = new List <SkipperTest> { rule1Test1, } }; var rule2 = new SkipperRule { StartOffset = 0x76, EndOffset = null, Operation = HeaderSkipOperation.None, Tests = new List <SkipperTest> { rule2Test1, } }; var rule3 = new SkipperRule { StartOffset = 0x7c, EndOffset = null, Operation = HeaderSkipOperation.None, Tests = new List <SkipperTest> { rule3Test1, } }; var rule4 = new SkipperRule { StartOffset = 0x7c, EndOffset = null, Operation = HeaderSkipOperation.None, Tests = new List <SkipperTest> { rule4Test1, } }; var rule5 = new SkipperRule { StartOffset = 0x7c, EndOffset = null, Operation = HeaderSkipOperation.None, Tests = new List <SkipperTest> { rule5Test1, } }; // Create file var skipperFile = new SkipperFile { Name = "psid", Author = "Yori Yoshizuki", Version = "1.2", SourceFile = "psid", Rules = new List <SkipperRule> { rule1, rule2, rule3, rule4, rule5, }, }; return(skipperFile); }