mirror of
https://github.com/claunia/SabreTools.git
synced 2025-12-16 19:14:27 +00:00
[Skippers] Make header skippers more complete
This commit is contained in:
@@ -76,7 +76,7 @@ namespace SabreTools
|
|||||||
// If it's a single file, just check it
|
// If it's a single file, just check it
|
||||||
if (File.Exists(file))
|
if (File.Exists(file))
|
||||||
{
|
{
|
||||||
DetectRemoveHeader(file);
|
DetectSkipperAndTransform(file);
|
||||||
}
|
}
|
||||||
// If it's a directory, recursively check all
|
// If it's a directory, recursively check all
|
||||||
else if (Directory.Exists(file))
|
else if (Directory.Exists(file))
|
||||||
@@ -85,7 +85,7 @@ namespace SabreTools
|
|||||||
{
|
{
|
||||||
if (sub != ".." && sub != ".")
|
if (sub != ".." && sub != ".")
|
||||||
{
|
{
|
||||||
DetectRemoveHeader(sub);
|
DetectSkipperAndTransform(sub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,12 +123,15 @@ namespace SabreTools
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Detect and remove header from the given file
|
/// Detect header skipper compliance and create an output file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="file">Name of the file to be parsed</param>
|
/// <param name="file">Name of the file to be parsed</param>
|
||||||
private static void DetectRemoveHeader(string file)
|
/// <returns>True if the output file was created, false otherwise</returns>
|
||||||
|
private static bool DetectSkipperAndTransform(string file)
|
||||||
{
|
{
|
||||||
// First get the HeaderType, if any
|
logger.User("\nGetting skipper information for '" + file + "'");
|
||||||
|
|
||||||
|
// Then, if the file was headered, store it to the database
|
||||||
int headerSize = -1;
|
int headerSize = -1;
|
||||||
HeaderType type = Skippers.GetFileHeaderType(file, out headerSize, logger);
|
HeaderType type = Skippers.GetFileHeaderType(file, out headerSize, logger);
|
||||||
|
|
||||||
@@ -150,15 +153,30 @@ namespace SabreTools
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write out the remaining bytes to new file
|
// Then find an apply the exact rule to the file
|
||||||
logger.User("Creating unheadered file: " + file + ".new");
|
SkipperRule rule = Skippers.MatchesSkipper(file, "", logger);
|
||||||
Output.RemoveBytesFromFile(file, file + ".new", headerSize, 0);
|
|
||||||
logger.User("Unheadered file created!");
|
// If we have an empty rule, return false
|
||||||
|
if (rule.Tests == null || rule.Tests.Count == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, apply the rule ot the file
|
||||||
|
Skippers.TransformFile(file, file + ".new", rule, logger);
|
||||||
|
|
||||||
|
// If the output file doesn't exist, return false
|
||||||
|
if (!File.Exists(file + ".new"))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Now add the information to the database if it's not already there
|
// Now add the information to the database if it's not already there
|
||||||
Rom rom = RomTools.GetSingleFileInfo(file + ".new");
|
Rom rom = RomTools.GetSingleFileInfo(file + ".new");
|
||||||
AddHeaderToDatabase(hstr, rom.SHA1, type);
|
AddHeaderToDatabase(hstr, rom.SHA1, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace SabreTools.Helper
|
|||||||
public class Skippers
|
public class Skippers
|
||||||
{
|
{
|
||||||
// Local paths
|
// Local paths
|
||||||
private const string _skippersPath = "Skippers";
|
public const string Path = "Skippers";
|
||||||
|
|
||||||
// Header skippers represented by a list of skipper objects
|
// Header skippers represented by a list of skipper objects
|
||||||
private static List<Skipper> _list;
|
private static List<Skipper> _list;
|
||||||
@@ -56,9 +56,9 @@ namespace SabreTools.Helper
|
|||||||
_list = new List<Skipper>();
|
_list = new List<Skipper>();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (string skipperFile in Directory.EnumerateFiles(_skippersPath, "*", SearchOption.AllDirectories))
|
foreach (string skipperFile in Directory.EnumerateFiles(Path, "*", SearchOption.AllDirectories))
|
||||||
{
|
{
|
||||||
_list.Add(PopulateSkippersHelper(Path.GetFullPath(skipperFile)));
|
_list.Add(PopulateSkippersHelper(System.IO.Path.GetFullPath(skipperFile)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +69,10 @@ namespace SabreTools.Helper
|
|||||||
/// <returns>The Skipper object associated with the file</returns>
|
/// <returns>The Skipper object associated with the file</returns>
|
||||||
private static Skipper PopulateSkippersHelper(string filename)
|
private static Skipper PopulateSkippersHelper(string filename)
|
||||||
{
|
{
|
||||||
Skipper skipper = new Skipper();
|
Skipper skipper = new Skipper
|
||||||
|
{
|
||||||
|
Rules = new List<SkipperRule>(),
|
||||||
|
};
|
||||||
|
|
||||||
if (!File.Exists(filename))
|
if (!File.Exists(filename))
|
||||||
{
|
{
|
||||||
@@ -98,6 +101,7 @@ namespace SabreTools.Helper
|
|||||||
{
|
{
|
||||||
case "detector":
|
case "detector":
|
||||||
valid = true;
|
valid = true;
|
||||||
|
xtr.Read();
|
||||||
break;
|
break;
|
||||||
case "name":
|
case "name":
|
||||||
skipper.Name = xtr.ReadElementContentAsString();
|
skipper.Name = xtr.ReadElementContentAsString();
|
||||||
@@ -127,9 +131,7 @@ namespace SabreTools.Helper
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
long temp = 0;
|
rule.StartOffset = Convert.ToInt64(offset, 16);
|
||||||
Int64.TryParse(offset, out temp);
|
|
||||||
rule.StartOffset = temp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (xtr.GetAttribute("end_offset") != null)
|
if (xtr.GetAttribute("end_offset") != null)
|
||||||
@@ -141,9 +143,7 @@ namespace SabreTools.Helper
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
long temp = 0;
|
rule.EndOffset = Convert.ToInt64(offset, 16);
|
||||||
Int64.TryParse(offset, out temp);
|
|
||||||
rule.EndOffset = temp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (xtr.GetAttribute("operation") != null)
|
if (xtr.GetAttribute("operation") != null)
|
||||||
@@ -217,9 +217,7 @@ namespace SabreTools.Helper
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
long temp = 0;
|
test.Offset = Convert.ToInt64(offset, 16);
|
||||||
Int64.TryParse(offset, out temp);
|
|
||||||
test.Offset = temp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (subreader.GetAttribute("value") != null)
|
if (subreader.GetAttribute("value") != null)
|
||||||
@@ -269,9 +267,7 @@ namespace SabreTools.Helper
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
long temp = 0;
|
test.Size = Convert.ToInt64(size, 16);
|
||||||
Int64.TryParse(size, out temp);
|
|
||||||
test.Size = temp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (subreader.GetAttribute("operator") != null)
|
if (subreader.GetAttribute("operator") != null)
|
||||||
@@ -330,28 +326,15 @@ namespace SabreTools.Helper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Loop through and find a Skipper that has the right name
|
// Loop through and find a Skipper that has the right name
|
||||||
Skipper matchedSkipper = new Skipper();
|
logger.User("Beginning search for matching header skip rules");
|
||||||
foreach (Skipper skipper in List)
|
foreach (Skipper skipper in List)
|
||||||
{
|
{
|
||||||
if (!String.IsNullOrEmpty(skipper.Name) && skippername.ToLowerInvariant() == skipper.Name.ToLowerInvariant())
|
if (String.IsNullOrEmpty(skippername) || (!String.IsNullOrEmpty(skipper.Name) && skippername.ToLowerInvariant() == skipper.Name.ToLowerInvariant()))
|
||||||
{
|
{
|
||||||
matchedSkipper = skipper;
|
// Loop through the rules until one is found that works
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have a blank skipper, return a blank skipper rule
|
|
||||||
if (String.IsNullOrEmpty(matchedSkipper.Name) || matchedSkipper.Rules == null)
|
|
||||||
{
|
|
||||||
logger.Warning("No header skipper by the name of '" + skippername + "' can be found");
|
|
||||||
return skipperRule;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, loop through the rules until one is found that works
|
|
||||||
using (BinaryReader br = new BinaryReader(File.OpenRead(input)))
|
using (BinaryReader br = new BinaryReader(File.OpenRead(input)))
|
||||||
{
|
{
|
||||||
logger.User("Beginning search for matching header skip rules");
|
foreach (SkipperRule rule in skipper.Rules)
|
||||||
foreach (SkipperRule rule in matchedSkipper.Rules)
|
|
||||||
{
|
{
|
||||||
// Always reset the stream back to the original place
|
// Always reset the stream back to the original place
|
||||||
br.BaseStream.Seek(0, SeekOrigin.Begin);
|
br.BaseStream.Seek(0, SeekOrigin.Begin);
|
||||||
@@ -487,6 +470,8 @@ namespace SabreTools.Helper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If we have a blank rule, inform the user
|
// If we have a blank rule, inform the user
|
||||||
if (skipperRule.Tests == null)
|
if (skipperRule.Tests == null)
|
||||||
@@ -507,6 +492,8 @@ namespace SabreTools.Helper
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static bool TransformFile(string input, string output, SkipperRule rule, Logger logger)
|
public static bool TransformFile(string input, string output, SkipperRule rule, Logger logger)
|
||||||
{
|
{
|
||||||
|
bool success = true;
|
||||||
|
|
||||||
// If the input file doesn't exist, fail
|
// If the input file doesn't exist, fail
|
||||||
if (!File.Exists(input))
|
if (!File.Exists(input))
|
||||||
{
|
{
|
||||||
@@ -515,9 +502,9 @@ namespace SabreTools.Helper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the output directory if it doesn't already
|
// Create the output directory if it doesn't already
|
||||||
if (!Directory.Exists(Path.GetDirectoryName(output)))
|
if (!Directory.Exists(System.IO.Path.GetDirectoryName(output)))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(output));
|
Directory.CreateDirectory(System.IO.Path.GetDirectoryName(output));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the sizes are wrong for the values, fail
|
// If the sizes are wrong for the values, fail
|
||||||
@@ -533,17 +520,18 @@ namespace SabreTools.Helper
|
|||||||
// Now read the proper part of the file and apply the rule
|
// Now read the proper part of the file and apply the rule
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
logger.User("Applying found rule to file '" + input + "'");
|
||||||
using (BinaryWriter bw = new BinaryWriter(File.OpenWrite(output)))
|
using (BinaryWriter bw = new BinaryWriter(File.OpenWrite(output)))
|
||||||
using (BinaryReader br = new BinaryReader(File.OpenRead(input)))
|
using (BinaryReader br = new BinaryReader(File.OpenRead(input)))
|
||||||
{
|
{
|
||||||
// Seek to the beginning offset
|
// Seek to the beginning offset
|
||||||
if (rule.StartOffset == null)
|
if (rule.StartOffset == null)
|
||||||
{
|
{
|
||||||
return false;
|
success = false;
|
||||||
}
|
}
|
||||||
else if (Math.Abs((long)rule.StartOffset) > br.BaseStream.Length)
|
else if (Math.Abs((long)rule.StartOffset) > br.BaseStream.Length)
|
||||||
{
|
{
|
||||||
return false;
|
success = false;
|
||||||
}
|
}
|
||||||
else if (rule.StartOffset > 0)
|
else if (rule.StartOffset > 0)
|
||||||
{
|
{
|
||||||
@@ -555,12 +543,14 @@ namespace SabreTools.Helper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Then read and apply the operation as you go
|
// Then read and apply the operation as you go
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
byte[] buffer = new byte[4];
|
byte[] buffer = new byte[4];
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
while (br.BaseStream.Position <= (rule.EndOffset != null ? rule.EndOffset : br.BaseStream.Length)
|
while (br.BaseStream.Position < (rule.EndOffset != null ? rule.EndOffset : br.BaseStream.Length)
|
||||||
&& br.BaseStream.Position <= br.BaseStream.Length)
|
&& br.BaseStream.Position < br.BaseStream.Length)
|
||||||
{
|
{
|
||||||
uint b = br.ReadUInt32();
|
byte b = br.ReadByte();
|
||||||
switch (rule.Operation)
|
switch (rule.Operation)
|
||||||
{
|
{
|
||||||
case HeaderSkipOperation.Bitswap:
|
case HeaderSkipOperation.Bitswap:
|
||||||
@@ -579,22 +569,22 @@ namespace SabreTools.Helper
|
|||||||
case HeaderSkipOperation.Byteswap:
|
case HeaderSkipOperation.Byteswap:
|
||||||
if (pos % 2 == 1)
|
if (pos % 2 == 1)
|
||||||
{
|
{
|
||||||
buffer[pos - 1] = (byte)b;
|
buffer[pos - 1] = b;
|
||||||
}
|
}
|
||||||
if (pos % 2 == 0)
|
if (pos % 2 == 0)
|
||||||
{
|
{
|
||||||
buffer[pos + 1] = (byte)b;
|
buffer[pos + 1] = b;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HeaderSkipOperation.Wordswap:
|
case HeaderSkipOperation.Wordswap:
|
||||||
buffer[3 - pos] = (byte)b;
|
buffer[3 - pos] = b;
|
||||||
break;
|
break;
|
||||||
case HeaderSkipOperation.WordByteswap:
|
case HeaderSkipOperation.WordByteswap:
|
||||||
buffer[(pos + 2) % 4] = (byte)b;
|
buffer[(pos + 2) % 4] = b;
|
||||||
break;
|
break;
|
||||||
case HeaderSkipOperation.None:
|
case HeaderSkipOperation.None:
|
||||||
default:
|
default:
|
||||||
buffer[pos] = (byte)b;
|
buffer[pos] = b;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -605,16 +595,18 @@ namespace SabreTools.Helper
|
|||||||
if (pos == 0)
|
if (pos == 0)
|
||||||
{
|
{
|
||||||
bw.Write(buffer);
|
bw.Write(buffer);
|
||||||
|
bw.Flush();
|
||||||
buffer = new byte[4];
|
buffer = new byte[4];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there's anything more in the buffer, write only the left bits
|
// If there's anything more in the buffer, write only the left bits
|
||||||
for (int i = 0; i < pos; i++)
|
for (int i = 0; i < pos; i++)
|
||||||
{
|
{
|
||||||
bw.Write(buffer[i]);
|
bw.Write(buffer[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -622,7 +614,20 @@ namespace SabreTools.Helper
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
// If the output file has size 0, delete it
|
||||||
|
if (new FileInfo(output).Length == 0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Delete(output);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Don't log this file deletion error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -658,7 +663,7 @@ namespace SabreTools.Helper
|
|||||||
XmlDocument doc = new XmlDocument();
|
XmlDocument doc = new XmlDocument();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
doc.LoadXml(File.ReadAllText(Path.Combine(_skippersPath, skipper + ".xml")));
|
doc.LoadXml(File.ReadAllText(System.IO.Path.Combine(Path, skipper + ".xml")));
|
||||||
}
|
}
|
||||||
catch (XmlException ex)
|
catch (XmlException ex)
|
||||||
{
|
{
|
||||||
@@ -744,7 +749,6 @@ namespace SabreTools.Helper
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
logger.Warning("The mapping for '" + test.ToString() + "' cannot be found!");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -375,14 +375,15 @@ namespace SabreTools
|
|||||||
ArchiveTools.WriteToArchive(input, _outdir, found);
|
ArchiveTools.WriteToArchive(input, _outdir, found);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now get the headerless file if it exists
|
// Now get the transformed file if it exists
|
||||||
int hs = 0;
|
SkipperRule rule = Skippers.MatchesSkipper(input, "", _logger);
|
||||||
Skippers.GetFileHeaderType(input, out hs, _logger);
|
|
||||||
if (hs > 0)
|
// If we have have a non-empty rule, apply it
|
||||||
|
if (rule.Tests != null && rule.Tests.Count != 0)
|
||||||
{
|
{
|
||||||
|
// Otherwise, apply the rule ot the file
|
||||||
string newinput = input + ".new";
|
string newinput = input + ".new";
|
||||||
_logger.Log("Creating unheadered file: '" + newinput + "'");
|
Skippers.TransformFile(input, input + ".new", rule, _logger);
|
||||||
Output.RemoveBytesFromFile(input, newinput, hs, 0);
|
|
||||||
Rom drom = RomTools.GetSingleFileInfo(newinput);
|
Rom drom = RomTools.GetSingleFileInfo(newinput);
|
||||||
|
|
||||||
// If we have a blank RomData, it's an error
|
// If we have a blank RomData, it's an error
|
||||||
|
|||||||
Reference in New Issue
Block a user