diff --git a/README.MD b/README.MD index 23fd9564..7d376ce0 100644 --- a/README.MD +++ b/README.MD @@ -4,6 +4,8 @@ This project started as a desktop port of some core features of Wizard of DATz Redux, but it has since grown into a fully-featured DAT management tool. Below is a brief description of the features available in the suite. For more information about each feature, see the help text in each of the programs. For more information about the parent project, see here. + +

Features

For the most complete set of information, see the README.1ST file. Currently, the SabreTools suite consists of the following programs: diff --git a/RombaSharp/Partials/RombaSharp_Inits.cs b/RombaSharp/Partials/RombaSharp_Inits.cs index 4627660e..a5fe959f 100644 --- a/RombaSharp/Partials/RombaSharp_Inits.cs +++ b/RombaSharp/Partials/RombaSharp_Inits.cs @@ -71,7 +71,7 @@ namespace SabreTools { datdata.PopulateDatFromDir(input, false /* noMD5 */, false /* noSHA1 */, true /* bare */, false /* archivesAsFiles */, true /* enableGzip */, false /* addBlanks */, false /* addDate */, "__temp__" /* tempDir */, false /* copyFiles */, - false /* removeHeader */, 4 /* maxDegreeOfParallelism */, _logger); + null /* headerToCheckAgainst */, 4 /* maxDegreeOfParallelism */, _logger); datdata.WriteToFile("", logger); } logger.Close(); diff --git a/SabreTools.Helper/Data/Structs.cs b/SabreTools.Helper/Data/Structs.cs deleted file mode 100644 index 4587947f..00000000 --- a/SabreTools.Helper/Data/Structs.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Collections.Generic; - -namespace SabreTools.Helper -{ - #region Skipper structs - - /// - /// Intermediate struct for holding header skipper information - /// - public struct Skipper - { - public string Name; - public string Author; - public string Version; - public List Rules; - public string SourceFile; - } - - /// - /// Intermediate struct for holding header skipper rule information - /// - public struct SkipperRule - { - public long? StartOffset; // null is EOF - public long? EndOffset; // null if EOF - public HeaderSkipOperation Operation; - public List Tests; - public string SourceFile; - } - - /// - /// Intermediate struct for holding header test information - /// - public struct SkipperTest - { - 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; - } - - #endregion -} diff --git a/SabreTools.Helper/Objects/Dat/DatFile.cs b/SabreTools.Helper/Objects/Dat/DatFile.cs index 95f8d845..6c24a3ef 100644 --- a/SabreTools.Helper/Objects/Dat/DatFile.cs +++ b/SabreTools.Helper/Objects/Dat/DatFile.cs @@ -4564,11 +4564,12 @@ namespace SabreTools.Helper /// True if dates should be archived for all files, false otherwise /// Name of the directory to create a temp folder in (blank is current directory) /// True if files should be copied to the temp directory before hashing, false otherwise - /// True if headers should be removed from files if possible, false otherwise + /// Populated string representing the name of the skipper to use, a blank string to use the first available checker, null otherwise /// Integer representing the maximum amount of parallelization to be used /// Logger object for console and file output public bool PopulateDatFromDir(string basePath, bool noMD5, bool noSHA1, bool bare, bool archivesAsFiles, - bool enableGzip, bool addBlanks, bool addDate, string tempDir, bool copyFiles, bool tryRemoveHeader, int maxDegreeOfParallelism, Logger logger) + bool enableGzip, bool addBlanks, bool addDate, string tempDir, bool copyFiles, string headerToCheckAgainst, + int maxDegreeOfParallelism, Logger logger) { // If the description is defined but not the name, set the name from the description if (String.IsNullOrEmpty(Name) && !String.IsNullOrEmpty(Description)) @@ -4599,7 +4600,7 @@ namespace SabreTools.Helper item => { DFDProcessPossibleArchive(item, basePath, noMD5, noSHA1, bare, archivesAsFiles, enableGzip, addBlanks, addDate, - tempDir, copyFiles, tryRemoveHeader, maxDegreeOfParallelism, logger); + tempDir, copyFiles, headerToCheckAgainst, maxDegreeOfParallelism, logger); }); // Now find all folders that are empty, if we are supposed to @@ -4688,11 +4689,12 @@ namespace SabreTools.Helper /// True if dates should be archived for all files, false otherwise /// Name of the directory to create a temp folder in (blank is current directory) /// True if files should be copied to the temp directory before hashing, false otherwise - /// True if headers should be removed from files if possible, false otherwise + /// Populated string representing the name of the skipper to use, a blank string to use the first available checker, null otherwise /// Integer representing the maximum amount of parallelization to be used /// Logger object for console and file output private void DFDProcessPossibleArchive(string item, string basePath, bool noMD5, bool noSHA1, bool bare, bool archivesAsFiles, - bool enableGzip, bool addBlanks, bool addDate, string tempDir, bool copyFiles, bool tryRemoveHeader, int maxDegreeOfParallelism, Logger logger) + bool enableGzip, bool addBlanks, bool addDate, string tempDir, bool copyFiles, string headerToCheckAgainst, + int maxDegreeOfParallelism, Logger logger) { // Define the temporary directory string tempSubDir = Path.GetFullPath(Path.Combine(tempDir, Path.GetRandomFileName())) + Path.DirectorySeparatorChar; @@ -4762,7 +4764,7 @@ namespace SabreTools.Helper // Otherwise, just get the info on the file itself else if (File.Exists(newItem)) { - DFDProcessFile(newItem, "", newBasePath, noMD5, noSHA1, addDate, tryRemoveHeader, logger); + DFDProcessFile(newItem, "", newBasePath, noMD5, noSHA1, addDate, headerToCheckAgainst, logger); } } // Otherwise, attempt to extract the files to the temporary directory @@ -4794,14 +4796,14 @@ namespace SabreTools.Helper noMD5, noSHA1, addDate, - tryRemoveHeader, + headerToCheckAgainst, logger); }); } // Otherwise, just get the info on the file itself else if (File.Exists(newItem)) { - DFDProcessFile(newItem, "", newBasePath, noMD5, noSHA1, addDate, tryRemoveHeader, logger); + DFDProcessFile(newItem, "", newBasePath, noMD5, noSHA1, addDate, headerToCheckAgainst, logger); } } @@ -4831,12 +4833,12 @@ namespace SabreTools.Helper /// True if MD5 hashes should be skipped over, false otherwise /// True if SHA-1 hashes should be skipped over, false otherwise /// True if dates should be archived for all files, false otherwise - /// True if headers should be removed from files if possible, false otherwise + /// Populated string representing the name of the skipper to use, a blank string to use the first available checker, null otherwise /// Logger object for console and file output - private void DFDProcessFile(string item, string parent, string basePath, bool noMD5, bool noSHA1, bool addDate, bool tryRemoveHeader, Logger logger) + private void DFDProcessFile(string item, string parent, string basePath, bool noMD5, bool noSHA1, bool addDate, string headerToCheckAgainst, Logger logger) { logger.Verbose(Path.GetFileName(item) + " treated like a file"); - Rom rom = FileTools.GetFileInfo(item, logger, noMD5: noMD5, noSHA1: noSHA1, date: addDate, tryRemoveHeader: tryRemoveHeader); + Rom rom = FileTools.GetFileInfo(item, logger, noMD5: noMD5, noSHA1: noSHA1, date: addDate, header: headerToCheckAgainst); DFDProcessFileHelper(item, rom, basePath, parent, logger); } diff --git a/SabreTools.Helper/Objects/SimpleSort.cs b/SabreTools.Helper/Objects/SimpleSort.cs index ded2d907..7f67d44d 100644 --- a/SabreTools.Helper/Objects/SimpleSort.cs +++ b/SabreTools.Helper/Objects/SimpleSort.cs @@ -139,7 +139,7 @@ namespace SabreTools.Helper { _datdata.PopulateDatFromDir(input, false /* noMD5 */, false /* noSHA1 */, true /* bare */, false /* archivesAsFiles */, true /* enableGzip */, false /* addBlanks */, false /* addDate */, "" /* tempDir */, false /* copyFiles */, - false /* removeHeader */, 4 /* maxDegreeOfParallelism */, _logger); + null /* headerToCheckAgainst */, 4 /* maxDegreeOfParallelism */, _logger); } // Setup the fixdat @@ -486,7 +486,7 @@ namespace SabreTools.Helper // Now attempt to see if the file has a header FileStream input = File.OpenRead(file); - SkipperRule rule = Skippers.GetMatchingRule(input, "", _logger); + SkipperRule rule = Skipper.GetMatchingRule(input, "", _logger); // If there's a match, get the new information from the stream if (rule.Tests != null && rule.Tests.Count != 0) @@ -495,7 +495,7 @@ namespace SabreTools.Helper MemoryStream output = new MemoryStream(); // Transform the stream and get the information from it - Skippers.TransformStream(input, output, rule, _logger, false, true); + rule.TransformStream(input, output, _logger, false, true); Rom romNH = FileTools.GetStreamInfo(output, output.Length); romNH.Name = "HEAD::" + rom.Name; romNH.MachineName = rom.MachineName; @@ -610,14 +610,14 @@ namespace SabreTools.Helper } // Now get the transformed file if it exists - SkipperRule rule = Skippers.GetMatchingRule(input, "", _logger); + SkipperRule rule = Skipper.GetMatchingRule(input, "", _logger); // If we have have a non-empty rule, apply it if (rule.Tests != null && rule.Tests.Count != 0) { // Otherwise, apply the rule to the file string newinput = input + ".new"; - Skippers.TransformFile(input, newinput, rule, _logger); + rule.TransformFile(input, newinput, _logger); Rom drom = FileTools.GetFileInfo(newinput, _logger); // If we have a blank RomData, it's an error diff --git a/SabreTools.Helper/Skippers/Skippers.cs b/SabreTools.Helper/Objects/Skippers/Skipper.cs similarity index 66% rename from SabreTools.Helper/Skippers/Skippers.cs rename to SabreTools.Helper/Objects/Skippers/Skipper.cs index 8d6ef39c..2e338cd4 100644 --- a/SabreTools.Helper/Skippers/Skippers.cs +++ b/SabreTools.Helper/Objects/Skippers/Skipper.cs @@ -6,8 +6,16 @@ using System.Xml; namespace SabreTools.Helper { - public class Skippers + public class Skipper { + #region Fields + + public string Name; + public string Author; + public string Version; + public List Rules; + public string SourceFile; + // Local paths public const string LocalPath = "Skippers"; @@ -25,50 +33,30 @@ namespace SabreTools.Helper } } - /// - /// Populate the entire list of header Skippers - /// - /// - /// http://mamedev.emulab.it/clrmamepro/docs/xmlheaders.txt - /// http://www.emulab.it/forum/index.php?topic=127.0 - /// - private static void PopulateSkippers() - { - if (_list == null) - { - _list = new List(); - } + #endregion - foreach (string skipperFile in Directory.EnumerateFiles(LocalPath, "*", SearchOption.AllDirectories)) - { - _list.Add(PopulateSkippersHelper(Path.GetFullPath(skipperFile))); - } + #region Constructors + + public Skipper() + { + Name = ""; + Author = ""; + Version = ""; + Rules = new List(); + SourceFile = ""; } - /// - /// 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) + public Skipper(string filename) { - Skipper skipper = new Skipper - { - Rules = new List(), - SourceFile = Path.GetFileName(filename), - }; - - if (!File.Exists(filename)) - { - return skipper; - } + Rules = new List(); + SourceFile = Path.GetFileNameWithoutExtension(filename); Logger logger = new Logger(false, ""); XmlReader xtr = FileTools.GetXmlTextReader(filename, logger); if (xtr == null) { - return skipper; + return; } bool valid = false; @@ -87,13 +75,13 @@ namespace SabreTools.Helper xtr.Read(); break; case "name": - skipper.Name = xtr.ReadElementContentAsString(); + Name = xtr.ReadElementContentAsString(); break; case "author": - skipper.Author = xtr.ReadElementContentAsString(); + Author = xtr.ReadElementContentAsString(); break; case "version": - skipper.Version = xtr.ReadElementContentAsString(); + Version = xtr.ReadElementContentAsString(); break; case "rule": // Get the information from the rule first @@ -103,7 +91,7 @@ namespace SabreTools.Helper EndOffset = 0, Operation = HeaderSkipOperation.None, Tests = new List(), - SourceFile = Path.GetFileName(filename), + SourceFile = Path.GetFileNameWithoutExtension(filename), }; if (xtr.GetAttribute("start_offset") != null) @@ -279,7 +267,7 @@ namespace SabreTools.Helper } // Add the created rule to the skipper - skipper.Rules.Add(rule); + Rules.Add(rule); xtr.Skip(); break; default: @@ -288,14 +276,46 @@ namespace SabreTools.Helper } } - return (valid ? skipper : new Skipper()); + // If we somehow have an invalid file, zero out the fields + if (!valid) + { + Name = null; + Author = null; + Version = null; + Rules = null; + SourceFile = null; + } + } + + #endregion + + #region Static Methods + + /// + /// Populate the entire list of header Skippers + /// + /// + /// http://mamedev.emulab.it/clrmamepro/docs/xmlheaders.txt + /// http://www.emulab.it/forum/index.php?topic=127.0 + /// + private static void PopulateSkippers() + { + if (_list == null) + { + _list = new List(); + } + + foreach (string skipperFile in Directory.EnumerateFiles(LocalPath, "*", SearchOption.AllDirectories)) + { + _list.Add(new Skipper(Path.GetFullPath(skipperFile))); + } } /// /// Get the SkipperRule associated with a given file /// /// Name of the file to be checked - /// Name of the skipper to be used + /// Name of the skipper to be used, blank to find a matching skipper /// Logger object for file and console output /// The SkipperRule that matched the file public static SkipperRule GetMatchingRule(string input, string skipperName, Logger logger) @@ -314,7 +334,7 @@ namespace SabreTools.Helper /// Get the SkipperRule associated with a given stream /// /// Name of the file to be checked - /// Name of the skipper to be used + /// Name of the skipper to be used, blank to find a matching skipper /// Logger object for file and console output /// True if the underlying stream should be kept open, false otherwise /// The SkipperRule that matched the file @@ -329,7 +349,10 @@ namespace SabreTools.Helper foreach (Skipper skipper in tempList) { - if (String.IsNullOrEmpty(skipperName) || (!String.IsNullOrEmpty(skipper.Name) && skipperName.ToLowerInvariant() == skipper.Name.ToLowerInvariant())) + // If we're searching for the skipper OR we have a match to an inputted one + if (String.IsNullOrEmpty(skipperName) + || (!String.IsNullOrEmpty(skipper.Name) && skipperName.ToLowerInvariant() == skipper.Name.ToLowerInvariant()) + || (!String.IsNullOrEmpty(skipper.Name) && skipperName.ToLowerInvariant() == skipper.SourceFile.ToLowerInvariant())) { // Loop through the rules until one is found that works BinaryReader br = new BinaryReader(input); @@ -492,187 +515,6 @@ namespace SabreTools.Helper return skipperRule; } - /// - /// Transform an input file using the given rule - /// - /// Input file name - /// Output file name - /// SkipperRule to apply to the file - /// Logger object for file and console output - /// True if the file was transformed properly, false otherwise - public static bool TransformFile(string input, string output, SkipperRule rule, Logger logger) - { - bool success = true; - - // If the input file doesn't exist, fail - if (!File.Exists(input)) - { - logger.Error("I'm sorry but '" + input + "' doesn't exist!"); - return false; - } - - // Create the output directory if it doesn't already - if (!Directory.Exists(Path.GetDirectoryName(output))) - { - Directory.CreateDirectory(Path.GetDirectoryName(output)); - } - - logger.User("Attempting to apply rule to '" + input + "'"); - success = TransformStream(File.Open(input, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), File.OpenWrite(output), rule, logger); - - // If the output file has size 0, delete it - if (new FileInfo(output).Length == 0) - { - try - { - File.Delete(output); - success = false; - } - catch - { - // Don't log this file deletion error - } - } - - return success; - } - - /// - /// Transform an input stream using the given rule - /// - /// Input stream - /// Output stream - /// SkipperRule to apply to the stream - /// Logger object for file and console output - /// True if the underlying read stream should be kept open, false otherwise - /// True if the underlying write stream should be kept open, false otherwise - /// True if the file was transformed properly, false otherwise - public static bool TransformStream(Stream input, Stream output, SkipperRule rule, Logger logger, bool keepReadOpen = false, bool keepWriteOpen = false) - { - bool success = true; - - // If the sizes are wrong for the values, fail - long extsize = input.Length; - if ((rule.Operation > HeaderSkipOperation.Bitswap && (extsize % 2) != 0) - || (rule.Operation > HeaderSkipOperation.Byteswap && (extsize % 4) != 0) - || (rule.Operation > HeaderSkipOperation.Bitswap && (rule.StartOffset == null || rule.StartOffset % 2 == 0))) - { - logger.Error("The stream did not have the correct size to be transformed!"); - return false; - } - - // Now read the proper part of the file and apply the rule - BinaryWriter bw = null; - BinaryReader br = null; - try - { - logger.User("Applying found rule to input stream"); - bw = new BinaryWriter(output); - br = new BinaryReader(input); - - // Seek to the beginning offset - if (rule.StartOffset == null) - { - success = false; - } - else if (Math.Abs((long)rule.StartOffset) > input.Length) - { - success = false; - } - else if (rule.StartOffset > 0) - { - input.Seek((long)rule.StartOffset, SeekOrigin.Begin); - } - else if (rule.StartOffset < 0) - { - input.Seek((long)rule.StartOffset, SeekOrigin.End); - } - - // Then read and apply the operation as you go - if (success) - { - byte[] buffer = new byte[4]; - int pos = 0; - while (input.Position < (rule.EndOffset != null ? rule.EndOffset : input.Length) - && input.Position < input.Length) - { - byte b = br.ReadByte(); - switch (rule.Operation) - { - case HeaderSkipOperation.Bitswap: - // http://stackoverflow.com/questions/3587826/is-there-a-built-in-function-to-reverse-bit-order - uint r = b; - int s = 7; - for (b >>= 1; b != 0; b >>= 1) - { - r <<= 1; - r |= (byte)(b & 1); - s--; - } - r <<= s; - buffer[pos] = (byte)r; - break; - case HeaderSkipOperation.Byteswap: - if (pos % 2 == 1) - { - buffer[pos - 1] = b; - } - if (pos % 2 == 0) - { - buffer[pos + 1] = b; - } - break; - case HeaderSkipOperation.Wordswap: - buffer[3 - pos] = b; - break; - case HeaderSkipOperation.WordByteswap: - buffer[(pos + 2) % 4] = b; - break; - case HeaderSkipOperation.None: - default: - buffer[pos] = b; - break; - } - - // Set the buffer position to default write to - pos = (pos + 1) % 4; - - // If we filled a buffer, flush to the stream - if (pos == 0) - { - bw.Write(buffer); - bw.Flush(); - buffer = new byte[4]; - } - } - // If there's anything more in the buffer, write only the left bits - for (int i = 0; i < pos; i++) - { - bw.Write(buffer[i]); - } - } - } - catch (Exception ex) - { - logger.Error(ex.ToString()); - return false; - } - finally - { - // If we're not keeping the read stream open, dispose of the binary reader - if (!keepReadOpen) - { - br?.Dispose(); - } - - // If we're not keeping the write stream open, dispose of the binary reader - if (!keepWriteOpen) - { - bw?.Dispose(); - } - } - - return success; - } + #endregion } } diff --git a/SabreTools.Helper/Objects/Skippers/SkipperRule.cs b/SabreTools.Helper/Objects/Skippers/SkipperRule.cs new file mode 100644 index 00000000..c0f50b13 --- /dev/null +++ b/SabreTools.Helper/Objects/Skippers/SkipperRule.cs @@ -0,0 +1,211 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace SabreTools.Helper +{ + public class SkipperRule + { + // Public variables + public long? StartOffset; // null is EOF + public long? EndOffset; // null if EOF + public HeaderSkipOperation Operation; + public List Tests; + public string SourceFile; + + /// + /// Transform an input file using the given rule + /// + /// Input file name + /// Output file name + /// Logger object for file and console output + /// True if the file was transformed properly, false otherwise + public bool TransformFile(string input, string output, Logger logger) + { + bool success = true; + + // If the input file doesn't exist, fail + if (!File.Exists(input)) + { + logger.Error("I'm sorry but '" + input + "' doesn't exist!"); + return false; + } + + // Create the output directory if it doesn't already + if (!Directory.Exists(Path.GetDirectoryName(output))) + { + Directory.CreateDirectory(Path.GetDirectoryName(output)); + } + + logger.User("Attempting to apply rule to '" + input + "'"); + success = TransformStream(File.Open(input, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), File.OpenWrite(output), logger); + + // If the output file has size 0, delete it + if (new FileInfo(output).Length == 0) + { + try + { + File.Delete(output); + success = false; + } + catch + { + // Don't log this file deletion error + } + } + + return success; + } + + /// + /// Transform an input stream using the given rule + /// + /// Input stream + /// Output stream + /// Logger object for file and console output + /// True if the underlying read stream should be kept open, false otherwise + /// True if the underlying write stream should be kept open, false otherwise + /// True if the file was transformed properly, false otherwise + public bool TransformStream(Stream input, Stream output, Logger logger, bool keepReadOpen = false, bool keepWriteOpen = false) + { + bool success = true; + + // If the sizes are wrong for the values, fail + long extsize = input.Length; + if ((Operation > HeaderSkipOperation.Bitswap && (extsize % 2) != 0) + || (Operation > HeaderSkipOperation.Byteswap && (extsize % 4) != 0) + || (Operation > HeaderSkipOperation.Bitswap && (StartOffset == null || StartOffset % 2 == 0))) + { + logger.Error("The stream did not have the correct size to be transformed!"); + return false; + } + + // Now read the proper part of the file and apply the rule + BinaryWriter bw = null; + BinaryReader br = null; + try + { + logger.User("Applying found rule to input stream"); + bw = new BinaryWriter(output); + br = new BinaryReader(input); + + // Seek to the beginning offset + if (StartOffset == null) + { + success = false; + } + else if (Math.Abs((long)StartOffset) > input.Length) + { + success = false; + } + else if (StartOffset > 0) + { + input.Seek((long)StartOffset, SeekOrigin.Begin); + } + else if (StartOffset < 0) + { + input.Seek((long)StartOffset, SeekOrigin.End); + } + + // Then read and apply the operation as you go + if (success) + { + byte[] buffer = new byte[4]; + int pos = 0; + while (input.Position < (EndOffset != null ? EndOffset : input.Length) + && input.Position < input.Length) + { + byte b = br.ReadByte(); + switch (Operation) + { + case HeaderSkipOperation.Bitswap: + // http://stackoverflow.com/questions/3587826/is-there-a-built-in-function-to-reverse-bit-order + uint r = b; + int s = 7; + for (b >>= 1; b != 0; b >>= 1) + { + r <<= 1; + r |= (byte)(b & 1); + s--; + } + r <<= s; + buffer[pos] = (byte)r; + break; + case HeaderSkipOperation.Byteswap: + if (pos % 2 == 1) + { + buffer[pos - 1] = b; + } + if (pos % 2 == 0) + { + buffer[pos + 1] = b; + } + break; + case HeaderSkipOperation.Wordswap: + buffer[3 - pos] = b; + break; + case HeaderSkipOperation.WordByteswap: + buffer[(pos + 2) % 4] = b; + break; + case HeaderSkipOperation.None: + default: + buffer[pos] = b; + break; + } + + // Set the buffer position to default write to + pos = (pos + 1) % 4; + + // If we filled a buffer, flush to the stream + if (pos == 0) + { + bw.Write(buffer); + bw.Flush(); + buffer = new byte[4]; + } + } + // If there's anything more in the buffer, write only the left bits + for (int i = 0; i < pos; i++) + { + bw.Write(buffer[i]); + } + } + } + catch (Exception ex) + { + logger.Error(ex.ToString()); + return false; + } + finally + { + // If we're not keeping the read stream open, dispose of the binary reader + if (!keepReadOpen) + { + br?.Dispose(); + } + + // If we're not keeping the write stream open, dispose of the binary reader + if (!keepWriteOpen) + { + bw?.Dispose(); + } + } + + return success; + } + } + + /// + /// Intermediate class for storing Skipper Test information + /// + public struct SkipperTest + { + 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/SabreTools.Helper.csproj b/SabreTools.Helper/SabreTools.Helper.csproj index ffe965f3..7f6faf31 100644 --- a/SabreTools.Helper/SabreTools.Helper.csproj +++ b/SabreTools.Helper/SabreTools.Helper.csproj @@ -113,6 +113,8 @@ + + True True @@ -133,14 +135,12 @@ True Resources.fr-FR.resx - - diff --git a/SabreTools.Helper/Tools/FileTools.cs b/SabreTools.Helper/Tools/FileTools.cs index 4f2f14c0..c801a46a 100644 --- a/SabreTools.Helper/Tools/FileTools.cs +++ b/SabreTools.Helper/Tools/FileTools.cs @@ -156,9 +156,9 @@ namespace SabreTools.Helper /// True if SHA-1 hashes should not be calcluated, false otherwise (default) /// Set a >0 number for getting hash for part of the file, 0 otherwise (default) /// True if the file Date should be included, false otherwise (default) - /// True if headers should be removed from files if possible, false otherwise (default) + /// Populated string representing the name of the skipper to use, a blank string to use the first available checker, null otherwise /// Populated RomData object if success, empty one on error - public static Rom GetFileInfo(string input, Logger logger, bool noMD5 = false, bool noSHA1 = false, long offset = 0, bool date = false, bool tryRemoveHeader = false) + public static Rom GetFileInfo(string input, Logger logger, bool noMD5 = false, bool noSHA1 = false, long offset = 0, bool date = false, string header = null) { // Add safeguard if file doesn't exist if (!File.Exists(input)) @@ -168,9 +168,9 @@ namespace SabreTools.Helper // Get the information from the file stream Rom rom = new Rom(); - if (tryRemoveHeader) + if (header != null) { - SkipperRule rule = Skippers.GetMatchingRule(input, "", logger); + SkipperRule rule = Skipper.GetMatchingRule(input, Path.GetFileNameWithoutExtension(header), logger); // If there's a match, get the new information from the stream if (rule.Tests != null && rule.Tests.Count != 0) @@ -180,7 +180,7 @@ namespace SabreTools.Helper FileStream inputStream = File.OpenRead(input); // Transform the stream and get the information from it - Skippers.TransformStream(inputStream, outputStream, rule, logger, keepReadOpen: false, keepWriteOpen: true); + rule.TransformStream(inputStream, outputStream, logger, keepReadOpen: false, keepWriteOpen: true); rom = GetStreamInfo(outputStream, outputStream.Length); // Dispose of the streams @@ -328,7 +328,7 @@ namespace SabreTools.Helper logger.User("\nGetting skipper information for '" + file + "'"); // Get the skipper rule that matches the file, if any - SkipperRule rule = Skippers.GetMatchingRule(file, "", logger); + SkipperRule rule = Skipper.GetMatchingRule(file, "", logger); // If we have an empty rule, return false if (rule.Tests == null || rule.Tests.Count == 0 || rule.Operation != HeaderSkipOperation.None) @@ -352,7 +352,7 @@ namespace SabreTools.Helper // Apply the rule to the file string newfile = (outDir == "" ? Path.GetFullPath(file) + ".new" : Path.Combine(outDir, Path.GetFileName(file))); - Skippers.TransformFile(file, newfile, rule, logger); + rule.TransformFile(file, newfile, logger); // If the output file doesn't exist, return false if (!File.Exists(newfile)) diff --git a/SabreTools/Partials/SabreTools_Inits.cs b/SabreTools/Partials/SabreTools_Inits.cs index fd263936..9ca2414f 100644 --- a/SabreTools/Partials/SabreTools_Inits.cs +++ b/SabreTools/Partials/SabreTools_Inits.cs @@ -71,7 +71,7 @@ namespace SabreTools /// True if dates should be archived for all files, false otherwise /// Name of the directory to create a temp folder in (blank is current directory /// True if files should be copied to the temp directory before hashing, false otherwise - /// True if headers should be removed from files if possible, false otherwise + /// Populated string representing the name of the skipper to use, a blank string to use the first available checker, null otherwise /// Integer representing the maximum amount of parallelization to be used private static void InitDatFromDir(List inputs, string filename, @@ -93,7 +93,7 @@ namespace SabreTools bool addFileDates, string tempDir, bool copyFiles, - bool removeHeader, + string headerToCheckAgainst, int maxDegreeOfParallelism) { ForcePacking fp = ForcePacking.None; @@ -139,7 +139,7 @@ namespace SabreTools string basePath = Path.GetFullPath(path); bool success = datdata.PopulateDatFromDir(basePath, noMD5, noSHA1, removeDateFromAutomaticName, parseArchivesAsFiles, enableGzip, - addBlankFilesForEmptyFolder, addFileDates, tempDir, copyFiles, removeHeader, maxDegreeOfParallelism, _logger); + addBlankFilesForEmptyFolder, addFileDates, tempDir, copyFiles, headerToCheckAgainst, maxDegreeOfParallelism, _logger); // If it was a success, write the DAT out if (success) diff --git a/SabreTools/SabreTools.cs b/SabreTools/SabreTools.cs index a4ba6d43..784908dc 100644 --- a/SabreTools/SabreTools.cs +++ b/SabreTools/SabreTools.cs @@ -75,7 +75,6 @@ namespace SabreTools rem = false, remext = false, removeDateFromAutomaticName = false, - removeHeader = false, restore = false, romba = false, showBaddumpColumn = false, @@ -95,41 +94,41 @@ namespace SabreTools seq = -1; OutputFormat outputFormat = 0x0; StatOutputFormat statOutputFormat = StatOutputFormat.None; - string addext = "", - author = "", - category = "", - comment = "", - crc = "", - currentAllMerged = "", - currentMissingMerged = "", - currentNewMerged = "", - date = "", - description = "", - email = "", - exta = "", - extb = "", - filename = "", - forcemerge = "", - forcend = "", - forcepack = "", - gamename = "", - header = "", - homepage = "", - name = "", - md5 = "", - outDir = "", - postfix = "", - prefix = "", - repext = "", - romname = "", - romtype = "", - root = "", - rootdir = "", - sha1 = "", - status = "", - tempDir = "", - url = "", - version = ""; + string addext = null, + author = null, + category = null, + comment = null, + crc = null, + currentAllMerged = null, + currentMissingMerged = null, + currentNewMerged = null, + date = null, + description = null, + email = null, + exta = null, + extb = null, + filename = null, + forcemerge = null, + forcend = null, + forcepack = null, + gamename = null, + header = null, + homepage = null, + name = null, + md5 = null, + outDir = null, + postfix = null, + prefix = null, + repext = null, + romname = null, + romtype = null, + root = null, + rootdir = null, + sha1 = null, + status = null, + tempDir = null, + url = null, + version = null; List inputs = new List(); // Determine which switches are enabled (with values if necessary) @@ -308,10 +307,6 @@ namespace SabreTools case "--restore": restore = true; break; - case "-rh": - case "--rem-head": - removeHeader = true; - break; case "-rme": case "--rem-ext": remext = true; @@ -591,7 +586,7 @@ namespace SabreTools addFileDates, tempDir, copyFiles, - removeHeader, + header, maxParallelism); }