[Skipper] Rearrange Skipper methods without changing logic

This commit is contained in:
Matt Nadareski
2016-10-03 21:16:59 -07:00
parent d71b38d90a
commit d8ff7f7943
11 changed files with 348 additions and 342 deletions

View File

@@ -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 <a href="https://github.com/mnadareski/wizzardRedux">here</a>.
<!-- "tbh... i have no real idea what sabretools is xD. my best guess some prehistoric sort of swiss army knife" - Executer -->
<h3>Features</h3>
For the most complete set of information, see the <a href="https://raw.githubusercontent.com/mnadareski/wizzardDesktop/master/SabreTools.Helper/README.1ST">README.1ST</a> file. Currently, the SabreTools suite consists of the following programs:

View File

@@ -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();

View File

@@ -1,46 +0,0 @@
using System.Collections.Generic;
namespace SabreTools.Helper
{
#region Skipper structs
/// <summary>
/// Intermediate struct for holding header skipper information
/// </summary>
public struct Skipper
{
public string Name;
public string Author;
public string Version;
public List<SkipperRule> Rules;
public string SourceFile;
}
/// <summary>
/// Intermediate struct for holding header skipper rule information
/// </summary>
public struct SkipperRule
{
public long? StartOffset; // null is EOF
public long? EndOffset; // null if EOF
public HeaderSkipOperation Operation;
public List<SkipperTest> Tests;
public string SourceFile;
}
/// <summary>
/// Intermediate struct for holding header test information
/// </summary>
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
}

View File

@@ -4564,11 +4564,12 @@ namespace SabreTools.Helper
/// <param name="addDate">True if dates should be archived for all files, false otherwise</param>
/// <param name="tempDir">Name of the directory to create a temp folder in (blank is current directory)</param>
/// <param name="copyFiles">True if files should be copied to the temp directory before hashing, false otherwise</param>
/// <param name="tryRemoveHeader">True if headers should be removed from files if possible, false otherwise</param>
/// <param name="headerToCheckAgainst">Populated string representing the name of the skipper to use, a blank string to use the first available checker, null otherwise</param>
/// <param name="maxDegreeOfParallelism">Integer representing the maximum amount of parallelization to be used</param>
/// <param name="logger">Logger object for console and file output</param>
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
/// <param name="addDate">True if dates should be archived for all files, false otherwise</param>
/// <param name="tempDir">Name of the directory to create a temp folder in (blank is current directory)</param>
/// <param name="copyFiles">True if files should be copied to the temp directory before hashing, false otherwise</param>
/// <param name="tryRemoveHeader">True if headers should be removed from files if possible, false otherwise</param>
/// <param name="headerToCheckAgainst">Populated string representing the name of the skipper to use, a blank string to use the first available checker, null otherwise</param>
/// <param name="maxDegreeOfParallelism">Integer representing the maximum amount of parallelization to be used</param>
/// <param name="logger">Logger object for console and file output</param>
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
/// <param name="noMD5">True if MD5 hashes should be skipped over, false otherwise</param>
/// <param name="noSHA1">True if SHA-1 hashes should be skipped over, false otherwise</param>
/// <param name="addDate">True if dates should be archived for all files, false otherwise</param>
/// <param name="tryRemoveHeader">True if headers should be removed from files if possible, false otherwise</param>
/// <param name="headerToCheckAgainst">Populated string representing the name of the skipper to use, a blank string to use the first available checker, null otherwise</param>
/// <param name="logger">Logger object for console and file output</param>
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);
}

View File

@@ -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

View File

@@ -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<SkipperRule> Rules;
public string SourceFile;
// Local paths
public const string LocalPath = "Skippers";
@@ -25,50 +33,30 @@ namespace SabreTools.Helper
}
}
/// <summary>
/// Populate the entire list of header Skippers
/// </summary>
/// <remarks>
/// http://mamedev.emulab.it/clrmamepro/docs/xmlheaders.txt
/// http://www.emulab.it/forum/index.php?topic=127.0
/// </remarks>
private static void PopulateSkippers()
#endregion
#region Constructors
public Skipper()
{
if (_list == null)
{
_list = new List<Skipper>();
Name = "";
Author = "";
Version = "";
Rules = new List<SkipperRule>();
SourceFile = "";
}
foreach (string skipperFile in Directory.EnumerateFiles(LocalPath, "*", SearchOption.AllDirectories))
public Skipper(string filename)
{
_list.Add(PopulateSkippersHelper(Path.GetFullPath(skipperFile)));
}
}
/// <summary>
/// Populate an individual Skipper from file
/// </summary>
/// <param name="filename">Name of the file to be read from</param>
/// <returns>The Skipper object associated with the file</returns>
private static Skipper PopulateSkippersHelper(string filename)
{
Skipper skipper = new Skipper
{
Rules = new List<SkipperRule>(),
SourceFile = Path.GetFileName(filename),
};
if (!File.Exists(filename))
{
return skipper;
}
Rules = new List<SkipperRule>();
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<SkipperTest>(),
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
/// <summary>
/// Populate the entire list of header Skippers
/// </summary>
/// <remarks>
/// http://mamedev.emulab.it/clrmamepro/docs/xmlheaders.txt
/// http://www.emulab.it/forum/index.php?topic=127.0
/// </remarks>
private static void PopulateSkippers()
{
if (_list == null)
{
_list = new List<Skipper>();
}
foreach (string skipperFile in Directory.EnumerateFiles(LocalPath, "*", SearchOption.AllDirectories))
{
_list.Add(new Skipper(Path.GetFullPath(skipperFile)));
}
}
/// <summary>
/// Get the SkipperRule associated with a given file
/// </summary>
/// <param name="input">Name of the file to be checked</param>
/// <param name="skipperName">Name of the skipper to be used</param>
/// <param name="skipperName">Name of the skipper to be used, blank to find a matching skipper</param>
/// <param name="logger">Logger object for file and console output</param>
/// <returns>The SkipperRule that matched the file</returns>
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
/// </summary>
/// <param name="input">Name of the file to be checked</param>
/// <param name="skipperName">Name of the skipper to be used</param>
/// <param name="skipperName">Name of the skipper to be used, blank to find a matching skipper</param>
/// <param name="logger">Logger object for file and console output</param>
/// <param name="keepOpen">True if the underlying stream should be kept open, false otherwise</param>
/// <returns>The SkipperRule that matched the file</returns>
@@ -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;
}
/// <summary>
/// Transform an input file using the given rule
/// </summary>
/// <param name="input">Input file name</param>
/// <param name="output">Output file name</param>
/// <param name="rule">SkipperRule to apply to the file</param>
/// <param name="logger">Logger object for file and console output</param>
/// <returns>True if the file was transformed properly, false otherwise</returns>
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;
}
/// <summary>
/// Transform an input stream using the given rule
/// </summary>
/// <param name="input">Input stream</param>
/// <param name="output">Output stream</param>
/// <param name="rule">SkipperRule to apply to the stream</param>
/// <param name="logger">Logger object for file and console output</param>
/// <param name="keepReadOpen">True if the underlying read stream should be kept open, false otherwise</param>
/// <param name="keepWriteOpen">True if the underlying write stream should be kept open, false otherwise</param>
/// <returns>True if the file was transformed properly, false otherwise</returns>
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
}
}

View File

@@ -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<SkipperTest> Tests;
public string SourceFile;
/// <summary>
/// Transform an input file using the given rule
/// </summary>
/// <param name="input">Input file name</param>
/// <param name="output">Output file name</param>
/// <param name="logger">Logger object for file and console output</param>
/// <returns>True if the file was transformed properly, false otherwise</returns>
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;
}
/// <summary>
/// Transform an input stream using the given rule
/// </summary>
/// <param name="input">Input stream</param>
/// <param name="output">Output stream</param>
/// <param name="logger">Logger object for file and console output</param>
/// <param name="keepReadOpen">True if the underlying read stream should be kept open, false otherwise</param>
/// <param name="keepWriteOpen">True if the underlying write stream should be kept open, false otherwise</param>
/// <returns>True if the file was transformed properly, false otherwise</returns>
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;
}
}
/// <summary>
/// Intermediate class for storing Skipper Test information
/// </summary>
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;
}
}

View File

@@ -113,6 +113,8 @@
<Compile Include="Objects\SimpleSort.cs" />
<Compile Include="Objects\Archive\ZipFileEntry.cs" />
<Compile Include="Objects\Archive\ZipFile.cs" />
<Compile Include="Objects\Skippers\Skipper.cs" />
<Compile Include="Objects\Skippers\SkipperRule.cs" />
<Compile Include="Resources\Resources.de-DE.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
@@ -133,14 +135,12 @@
<DesignTime>True</DesignTime>
<DependentUpon>Resources.fr-FR.resx</DependentUpon>
</Compile>
<Compile Include="Skippers\Skippers.cs" />
<Compile Include="Tools\ArchiveTools.cs" />
<Compile Include="Tools\FileTools.cs" />
<Compile Include="Tools\DatabaseTools.cs" />
<Compile Include="Data\Enums.cs" />
<Compile Include="Objects\Logger.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Data\Structs.cs" />
<Compile Include="Tools\Style.cs" />
<Compile Include="Data\Build.cs" />
</ItemGroup>

View File

@@ -156,9 +156,9 @@ namespace SabreTools.Helper
/// <param name="noSHA1">True if SHA-1 hashes should not be calcluated, false otherwise (default)</param>
/// <param name="offset">Set a >0 number for getting hash for part of the file, 0 otherwise (default)</param>
/// <param name="date">True if the file Date should be included, false otherwise (default)</param>
/// <param name="tryRemoveHeader">True if headers should be removed from files if possible, false otherwise (default)</param>
/// <param name="header">Populated string representing the name of the skipper to use, a blank string to use the first available checker, null otherwise</param>
/// <returns>Populated RomData object if success, empty one on error</returns>
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))

View File

@@ -71,7 +71,7 @@ namespace SabreTools
/// <param name="addFileDates">True if dates should be archived for all files, false otherwise</param>
/// <param name="tempDir">Name of the directory to create a temp folder in (blank is current directory</param>
/// <param name="copyFiles">True if files should be copied to the temp directory before hashing, false otherwise</param>
/// <param name="removeHeader">True if headers should be removed from files if possible, false otherwise</param>
/// <param name="headerToCheckAgainst">Populated string representing the name of the skipper to use, a blank string to use the first available checker, null otherwise</param>
/// <param name="maxDegreeOfParallelism">Integer representing the maximum amount of parallelization to be used</param>
private static void InitDatFromDir(List<string> 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)

View File

@@ -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<string> inputs = new List<string>();
// 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);
}