mirror of
https://github.com/SabreTools/Reheader.git
synced 2026-02-04 05:35:57 +00:00
Add project files.
This commit is contained in:
25
Reheader.sln
Normal file
25
Reheader.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.28803.156
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reheader", "Reheader\Reheader.csproj", "{113C73A6-2299-4987-8215-464D446AB8BC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{113C73A6-2299-4987-8215-464D446AB8BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{113C73A6-2299-4987-8215-464D446AB8BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{113C73A6-2299-4987-8215-464D446AB8BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{113C73A6-2299-4987-8215-464D446AB8BC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {5ECC5E34-310A-4002-B289-8207B530D284}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
129
Reheader/Enumerations.cs
Normal file
129
Reheader/Enumerations.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Reheader
|
||||
{
|
||||
public enum GameConsole
|
||||
{
|
||||
NONE,
|
||||
|
||||
Dendy,
|
||||
Famicom,
|
||||
NesNtsc,
|
||||
NesPal,
|
||||
Playchoice,
|
||||
VsSystem,
|
||||
}
|
||||
|
||||
public enum Mirroring
|
||||
{
|
||||
NONE,
|
||||
|
||||
Vertical,
|
||||
Horizontal,
|
||||
FourScreen,
|
||||
|
||||
// Unknown
|
||||
A,
|
||||
}
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get long name representation for a GameConsole
|
||||
/// </summary>
|
||||
/// <param name="console">GameConsole value</param>
|
||||
/// <returns>Long name representation of input, if possible</returns>
|
||||
public static string Name(this GameConsole console)
|
||||
{
|
||||
switch (console)
|
||||
{
|
||||
case GameConsole.Dendy:
|
||||
return "Steepler Dendy";
|
||||
case GameConsole.Famicom:
|
||||
return "Nintendo Famicom";
|
||||
case GameConsole.NesNtsc:
|
||||
return "Nintendo Entertainment System (NTSC)";
|
||||
case GameConsole.NesPal:
|
||||
return "Nintendo Entertainment System (PAL)";
|
||||
case GameConsole.Playchoice:
|
||||
return "Nintendo PlayChoice-10";
|
||||
case GameConsole.VsSystem:
|
||||
return "Nintendo Vs. System";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get long name representation for a Mirroring
|
||||
/// </summary>
|
||||
/// <param name="mirroring">Mirroring value</param>
|
||||
/// <returns>Long name representation of input, if possible</returns>
|
||||
public static string Name(this Mirroring mirroring)
|
||||
{
|
||||
switch (mirroring)
|
||||
{
|
||||
case Mirroring.Vertical:
|
||||
return "Vertical";
|
||||
case Mirroring.Horizontal:
|
||||
return "Horizontal";
|
||||
case Mirroring.A:
|
||||
return "A (Unknown)";
|
||||
case Mirroring.FourScreen:
|
||||
return "Four-Screen VRAM";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get GameConsole value from a string
|
||||
/// </summary>
|
||||
/// <param name="console">String value</param>
|
||||
/// <returns>GameConsole representation of the input, if possible</returns>
|
||||
public static GameConsole GameConsoleFromString(string console)
|
||||
{
|
||||
switch (console)
|
||||
{
|
||||
case "Dendy":
|
||||
return GameConsole.Dendy;
|
||||
case "Famicom":
|
||||
return GameConsole.Famicom;
|
||||
case "NesNtsc":
|
||||
return GameConsole.NesNtsc;
|
||||
case "NesPal":
|
||||
return GameConsole.NesPal;
|
||||
case "Playchoice":
|
||||
return GameConsole.Playchoice;
|
||||
case "VsSystem":
|
||||
return GameConsole.VsSystem;
|
||||
default:
|
||||
return GameConsole.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Mirroring value from a string
|
||||
/// </summary>
|
||||
/// <param name="mirroring">String value</param>
|
||||
/// <returns>Mirroring representation of the input, if possible</returns>
|
||||
public static Mirroring MirroringFromString(string mirroring)
|
||||
{
|
||||
switch (mirroring)
|
||||
{
|
||||
case "h":
|
||||
return Mirroring.Horizontal;
|
||||
case "v":
|
||||
return Mirroring.Vertical;
|
||||
case "4":
|
||||
return Mirroring.FourScreen;
|
||||
case "a":
|
||||
return Mirroring.A;
|
||||
default:
|
||||
return Mirroring.NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
188
Reheader/HeaderInfo.cs
Normal file
188
Reheader/HeaderInfo.cs
Normal file
@@ -0,0 +1,188 @@
|
||||
using System;
|
||||
|
||||
namespace Reheader
|
||||
{
|
||||
public class HeaderInfo
|
||||
{
|
||||
public string CRC { get; set; }
|
||||
|
||||
public GameConsole System { get; set; }
|
||||
|
||||
public string Board { get; set; }
|
||||
|
||||
public string PCB { get; set; }
|
||||
|
||||
public string Chip { get; set; }
|
||||
|
||||
public int Mapper { get; set; }
|
||||
|
||||
public int PrgRomSizeKb { get; set; }
|
||||
|
||||
public int ChrRomSizeKb { get; set; }
|
||||
|
||||
public int ChrRamSizeKb { get; set; }
|
||||
|
||||
public int WorkRamSizeKb { get; set; }
|
||||
|
||||
public int SaveRamSizeKb { get; set; }
|
||||
|
||||
public bool Battery { get; set; }
|
||||
|
||||
public Mirroring Mirroring { get; set; }
|
||||
|
||||
public string ControllerType { get; set; }
|
||||
|
||||
public string BusConflicts { get; set; }
|
||||
|
||||
public int SubMapper { get; set; }
|
||||
|
||||
public string VsSystemType { get; set; }
|
||||
|
||||
public string PpuModel { get; set; }
|
||||
|
||||
public HeaderInfo(string csvLine)
|
||||
{
|
||||
if (string.IsNullOrEmpty(csvLine))
|
||||
return;
|
||||
|
||||
var csvElements = csvLine.Split(',');
|
||||
|
||||
if (csvElements.Length != 18)
|
||||
return;
|
||||
|
||||
this.CRC = csvElements[0];
|
||||
this.System = Extensions.GameConsoleFromString(csvElements[1]);
|
||||
this.Board = csvElements[2];
|
||||
this.PCB = csvElements[3];
|
||||
this.Chip = csvElements[4];
|
||||
this.Mapper = Int32.Parse(string.IsNullOrWhiteSpace(csvElements[5]) ? "-1" : csvElements[5]);
|
||||
this.PrgRomSizeKb = Int32.Parse(string.IsNullOrWhiteSpace(csvElements[6]) ? "-1" : csvElements[6]);
|
||||
this.ChrRomSizeKb = Int32.Parse(string.IsNullOrWhiteSpace(csvElements[7]) ? "-1" : csvElements[7]);
|
||||
this.ChrRamSizeKb = Int32.Parse(string.IsNullOrWhiteSpace(csvElements[8]) ? "-1" : csvElements[8]);
|
||||
this.WorkRamSizeKb = Int32.Parse(string.IsNullOrWhiteSpace(csvElements[9]) ? "-1" : csvElements[9]);
|
||||
this.SaveRamSizeKb = Int32.Parse(string.IsNullOrWhiteSpace(csvElements[10]) ? "-1" : csvElements[10]);
|
||||
this.Battery = (csvElements[11] == "1");
|
||||
this.Mirroring = Extensions.MirroringFromString(csvElements[12]);
|
||||
this.ControllerType = csvElements[13];
|
||||
this.BusConflicts = csvElements[14];
|
||||
this.SubMapper = Int32.Parse(string.IsNullOrWhiteSpace(csvElements[15]) ? "-1" : csvElements[15]);
|
||||
this.VsSystemType = csvElements[16];
|
||||
this.PpuModel = csvElements[17];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate an iNES 1.0 or 2.0 header for the current Header information
|
||||
/// </summary>
|
||||
/// <param name="versionTwo">True if iNES 2.0 header should be created, false for iNES 1.0</param>
|
||||
/// <returns>Byte array representing the header, null on error</returns>
|
||||
public byte[] GenerateHeader(bool versionTwo)
|
||||
{
|
||||
if (this.CRC == null)
|
||||
return null;
|
||||
|
||||
byte[] header = new byte[16];
|
||||
|
||||
// NES signature
|
||||
header[0] = 0x4e;
|
||||
header[1] = 0x45;
|
||||
header[2] = 0x53;
|
||||
header[3] = 0x1a;
|
||||
|
||||
// PRG ROM in 16KB units
|
||||
header[4] = (byte)(this.PrgRomSizeKb / 16);
|
||||
|
||||
// CHR ROM in 8KB units
|
||||
header[5] = (byte)(this.ChrRamSizeKb > 0 ? 0 : this.ChrRomSizeKb / 8);
|
||||
|
||||
// Mirroring, Battery, Trainer, Mapper
|
||||
header[6] = 0;
|
||||
|
||||
// Mirroring
|
||||
if (this.Mirroring == Mirroring.Horizontal)
|
||||
header[6] &= 0x00;
|
||||
else if (this.Mirroring == Mirroring.Vertical)
|
||||
header[6] &= 0x01;
|
||||
else if (this.Mirroring == Mirroring.FourScreen)
|
||||
header[6] &= 0x08;
|
||||
|
||||
// Battery
|
||||
if (this.Battery)
|
||||
header[6] &= 0x02;
|
||||
|
||||
// Trainer
|
||||
//if (this.Trainer)
|
||||
// header[6] &= 0x04;
|
||||
|
||||
// Lower nibble of mapper
|
||||
header[6] &= (byte)(((byte)(this.Mapper & 0x0F)) << 4);
|
||||
|
||||
// VS/Playchoice, NES 2.0, Mapper
|
||||
header[7] = 0;
|
||||
|
||||
// VS Unisystem and PlayChoice-10
|
||||
if (this.System == GameConsole.VsSystem)
|
||||
header[7] &= 0x01;
|
||||
else if (this.System == GameConsole.Playchoice)
|
||||
header[7] &= 0x02;
|
||||
|
||||
// NES 2.0 Format
|
||||
if (versionTwo)
|
||||
header[7] &= 0x08;
|
||||
|
||||
// Upper nibble of mapper
|
||||
header[7] &= (byte)(this.Mapper & 0xF0);
|
||||
|
||||
// iNES 1.0 Format
|
||||
if (!versionTwo)
|
||||
{
|
||||
// PRG-RAM size
|
||||
header[8] = (byte)(this.WorkRamSizeKb / 8);
|
||||
|
||||
// TV System
|
||||
header[9] = 0;
|
||||
if (this.System == GameConsole.Famicom || this.System == GameConsole.NesNtsc)
|
||||
header[9] &= 0x00;
|
||||
else if (this.System == GameConsole.Dendy || this.System == GameConsole.NesPal)
|
||||
header[9] &= 0x01;
|
||||
|
||||
// TV system, PRG-RAM presence, bus conflicts
|
||||
header[10] = 0;
|
||||
|
||||
// TV System... again
|
||||
if (this.System == GameConsole.Famicom || this.System == GameConsole.NesNtsc)
|
||||
header[9] &= 0x00;
|
||||
else if (this.System == GameConsole.Dendy || this.System == GameConsole.NesPal)
|
||||
header[9] &= 0x02;
|
||||
|
||||
// PRG-RAM presence
|
||||
if (this.WorkRamSizeKb > 0)
|
||||
header[9] &= 0x10;
|
||||
|
||||
// Bus conflicts
|
||||
if (!string.IsNullOrEmpty(this.BusConflicts) && this.BusConflicts != "N")
|
||||
header[9] &= 0x20;
|
||||
|
||||
// Padding
|
||||
}
|
||||
// iNES 2.0 Format
|
||||
else
|
||||
{
|
||||
// Mapper MSB, Submapper
|
||||
header[8] = 0;
|
||||
|
||||
// Uppermost nibble of mapper
|
||||
header[8] &= (byte)((byte)(this.Mapper & 0xF00) >> 8);
|
||||
|
||||
// Submapper
|
||||
header[8] &= (byte)(this.SubMapper << 4);
|
||||
|
||||
// PRG-ROM/CHR-ROM size MSB
|
||||
//...
|
||||
|
||||
// https://wiki.nesdev.com/w/index.php/NES_2.0
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
}
|
||||
}
|
||||
15553
Reheader/MesenDB.txt
Normal file
15553
Reheader/MesenDB.txt
Normal file
File diff suppressed because it is too large
Load Diff
153
Reheader/OptimizedCRC.cs
Normal file
153
Reheader/OptimizedCRC.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2012-2015 Eugene Larchenko (spct@mail.ru)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Reheader
|
||||
{
|
||||
public class OptimizedCRC : IDisposable
|
||||
{
|
||||
private const uint kCrcPoly = 0xEDB88320;
|
||||
private const uint kInitial = 0xFFFFFFFF;
|
||||
private const int CRC_NUM_TABLES = 8;
|
||||
private static readonly uint[] Table;
|
||||
|
||||
static OptimizedCRC()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
Table = new uint[256 * CRC_NUM_TABLES];
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
uint r = (uint)i;
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
|
||||
}
|
||||
Table[i] = r;
|
||||
}
|
||||
for (; i < 256 * CRC_NUM_TABLES; i++)
|
||||
{
|
||||
uint r = Table[i - 256];
|
||||
Table[i] = Table[r & 0xFF] ^ (r >> 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public uint UnsignedValue;
|
||||
|
||||
public OptimizedCRC()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset CRC
|
||||
/// </summary>
|
||||
public void Init()
|
||||
{
|
||||
UnsignedValue = kInitial;
|
||||
}
|
||||
|
||||
public int Value
|
||||
{
|
||||
get { return (int)~UnsignedValue; }
|
||||
}
|
||||
|
||||
public void Update(byte[] data, int offset, int count)
|
||||
{
|
||||
new ArraySegment<byte>(data, offset, count); // check arguments
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var table = OptimizedCRC.Table;
|
||||
|
||||
uint crc = UnsignedValue;
|
||||
|
||||
for (; (offset & 7) != 0 && count != 0; count--)
|
||||
{
|
||||
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
|
||||
}
|
||||
|
||||
if (count >= 8)
|
||||
{
|
||||
/*
|
||||
* Idea from 7-zip project sources (http://7-zip.org/sdk.html)
|
||||
*/
|
||||
|
||||
int end = (count - 8) & ~7;
|
||||
count -= end;
|
||||
end += offset;
|
||||
|
||||
while (offset != end)
|
||||
{
|
||||
crc ^= (uint)(data[offset] + (data[offset + 1] << 8) + (data[offset + 2] << 16) + (data[offset + 3] << 24));
|
||||
uint high = (uint)(data[offset + 4] + (data[offset + 5] << 8) + (data[offset + 6] << 16) + (data[offset + 7] << 24));
|
||||
offset += 8;
|
||||
|
||||
crc = table[(byte)crc + 0x700]
|
||||
^ table[(byte)(crc >>= 8) + 0x600]
|
||||
^ table[(byte)(crc >>= 8) + 0x500]
|
||||
^ table[/*(byte)*/(crc >> 8) + 0x400]
|
||||
^ table[(byte)(high) + 0x300]
|
||||
^ table[(byte)(high >>= 8) + 0x200]
|
||||
^ table[(byte)(high >>= 8) + 0x100]
|
||||
^ table[/*(byte)*/(high >> 8) + 0x000];
|
||||
}
|
||||
}
|
||||
|
||||
while (count-- != 0)
|
||||
{
|
||||
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
|
||||
}
|
||||
|
||||
UnsignedValue = crc;
|
||||
}
|
||||
|
||||
static public int Compute(byte[] data, int offset, int count)
|
||||
{
|
||||
var crc = new OptimizedCRC();
|
||||
crc.Update(data, offset, count);
|
||||
return crc.Value;
|
||||
}
|
||||
|
||||
static public int Compute(byte[] data)
|
||||
{
|
||||
return Compute(data, 0, data.Length);
|
||||
}
|
||||
|
||||
static public int Compute(ArraySegment<byte> block)
|
||||
{
|
||||
return Compute(block.Array, block.Offset, block.Count);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
UnsignedValue = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
Reheader/Program.cs
Normal file
19
Reheader/Program.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace Reheader
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
if (args.Length == 0)
|
||||
{
|
||||
Console.WriteLine("Usage: Reheader.exe <file|dir> ...");
|
||||
return;
|
||||
}
|
||||
|
||||
var reheader = new Reheader();
|
||||
reheader.Process(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
8
Reheader/Properties/launchSettings.json
Normal file
8
Reheader/Properties/launchSettings.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"profiles": {
|
||||
"Reheader": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "\"C:\\Users\\Matt\\GitHub\\Reheader\\Reheader\\bin\\Debug\\netcoreapp2.1\\games\""
|
||||
}
|
||||
}
|
||||
}
|
||||
150
Reheader/Reheader.cs
Normal file
150
Reheader/Reheader.cs
Normal file
@@ -0,0 +1,150 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Reheader
|
||||
{
|
||||
public class Reheader
|
||||
{
|
||||
private const string mappingFile = "MesenDB.txt";
|
||||
private readonly Dictionary<string, HeaderInfo> headerMapping = new Dictionary<string, HeaderInfo>();
|
||||
|
||||
public Reheader()
|
||||
{
|
||||
if (!File.Exists(mappingFile))
|
||||
return;
|
||||
|
||||
// Populate the header mapping dictionary
|
||||
using (TextReader reader = File.OpenText(mappingFile))
|
||||
{
|
||||
string line = string.Empty;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
// Comment lines start with #
|
||||
if (line.StartsWith("#"))
|
||||
continue;
|
||||
|
||||
var headerInfo = new HeaderInfo(line);
|
||||
headerMapping.Add(headerInfo.CRC, headerInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process a list of paths that may contain unheadered NES files
|
||||
/// </summary>
|
||||
/// <param name="paths"></param>
|
||||
public void Process(string[] paths)
|
||||
{
|
||||
foreach (string path in paths)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
if (!this.AddHeader(Path.GetFullPath(path), Path.GetFullPath(path) + "-headered"))
|
||||
Console.WriteLine($"Could not find a header for {path}");
|
||||
}
|
||||
else if (Directory.Exists(path))
|
||||
{
|
||||
foreach (string file in Directory.EnumerateFiles(Path.GetFullPath(path), "*", SearchOption.AllDirectories))
|
||||
if (!this.AddHeader(Path.GetFullPath(file), Path.GetFullPath(file) + "-headered"))
|
||||
Console.WriteLine($"Could not find a header for {file}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"{path} is not a file or directory");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add an iNES header to a given input file, if applicable
|
||||
/// </summary>
|
||||
/// <param name="infile">Input file to check and header</param>
|
||||
/// <param name="outfile">Output file path</param>
|
||||
/// <returns>True if a header was able to be generated and added, false otherwise</returns>
|
||||
private bool AddHeader(string infile, string outfile)
|
||||
{
|
||||
Console.WriteLine($"Processing {infile}");
|
||||
|
||||
if (!File.Exists(infile))
|
||||
return false;
|
||||
|
||||
// Get the CRC hash of the file
|
||||
string crc = GetCRCFromFile(infile).ToUpperInvariant();
|
||||
|
||||
// See if that's a known CRC
|
||||
if (!headerMapping.ContainsKey(crc))
|
||||
return false;
|
||||
|
||||
// Get the mapping
|
||||
var header = headerMapping[crc];
|
||||
|
||||
// Get the new bytes
|
||||
var headerBytes = header.GenerateHeader(false);
|
||||
|
||||
using (BinaryReader reader = new BinaryReader(File.OpenRead(infile)))
|
||||
using (BinaryWriter writer = new BinaryWriter(File.Create(outfile)))
|
||||
{
|
||||
// Write the header
|
||||
writer.Write(headerBytes);
|
||||
|
||||
// Now the rest
|
||||
var tempBytes = reader.ReadBytes((int)reader.BaseStream.Length);
|
||||
writer.Write(tempBytes);
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
Console.WriteLine($"Found header for {infile}. Wrote new file to {outfile}.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the CRC32 hash for a file, if possible
|
||||
/// </summary>
|
||||
/// <param name="file">Path to the file</param>
|
||||
/// <returns>String representation of the CRC32 hash of the file</returns>
|
||||
private string GetCRCFromFile(string file)
|
||||
{
|
||||
using (OptimizedCRC crc = new OptimizedCRC())
|
||||
using (BinaryReader reader = new BinaryReader(File.OpenRead(file)))
|
||||
{
|
||||
byte[] buffer = new byte[8 * 1024];
|
||||
int read = Int32.MaxValue;
|
||||
while ((read = reader.Read(buffer, 0, buffer.Length)) > 0)
|
||||
{
|
||||
crc.Update(buffer, 0, read);
|
||||
}
|
||||
|
||||
crc.Update(buffer, 0, 0);
|
||||
byte[] crcHash = BitConverter.GetBytes(crc.Value).Reverse().ToArray();
|
||||
|
||||
return ByteArrayToString(crcHash);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a byte array to a hex string
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte array to convert</param>
|
||||
/// <returns>Hex string representing the byte array</returns>
|
||||
/// <link>http://stackoverflow.com/questions/311165/how-do-you-convert-byte-array-to-hexadecimal-string-and-vice-versa</link>
|
||||
private string ByteArrayToString(byte[] bytes)
|
||||
{
|
||||
// If we get null in, we send null out
|
||||
if (bytes == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
string hex = BitConverter.ToString(bytes);
|
||||
return hex.Replace("-", string.Empty).ToLowerInvariant();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
17
Reheader/Reheader.csproj
Normal file
17
Reheader/Reheader.csproj
Normal file
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFrameworks>net462</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win10-x64;win7-x86</RuntimeIdentifiers>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="MesenDB.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user