Add hashing tool implementation, for fun

This commit is contained in:
Matt Nadareski
2025-09-23 14:15:27 -04:00
parent 95589df904
commit 32cd0e73ed
11 changed files with 1103 additions and 13 deletions

View File

@@ -31,7 +31,7 @@ jobs:
uses: ncipollo/release-action@v1.14.0
with:
allowUpdates: True
artifacts: "*.nupkg,*.snupkg"
artifacts: "*.nupkg,*.snupkg,*.zip"
body: 'Last built commit: ${{ github.sha }}'
name: 'Rolling Release'
prerelease: True

28
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,28 @@
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/Hasher/bin/Debug/net9.0/Hasher.dll",
"args": [],
"cwd": "${workspaceFolder}",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false,
"justMyCode": false
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}"
}
]
}

34
Hasher/Hasher.csproj Normal file
View File

@@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
<OutputType>Exe</OutputType>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>1.5.0</Version>
</PropertyGroup>
<!-- Support All Frameworks -->
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net4`))">
<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith(`netcoreapp`)) OR $(TargetFramework.StartsWith(`net5`))">
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net6`)) OR $(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`)) OR $(TargetFramework.StartsWith(`net9`))">
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(RuntimeIdentifier.StartsWith(`osx-arm`))">
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\SabreTools.Hashing\SabreTools.Hashing.csproj" />
</ItemGroup>
</Project>

168
Hasher/Options.cs Normal file
View File

@@ -0,0 +1,168 @@
using System;
using System.Collections.Generic;
using SabreTools.Hashing;
namespace Hasher
{
/// <summary>
/// Set of options for the test executable
/// </summary>
/// TODO: Add file output
internal sealed class Options
{
#region Properties
/// <summary>
/// Enable debug output for relevant operations
/// </summary>
public bool Debug { get; private set; } = false;
/// <summary>
/// List of all hash types to process
/// </summary>
public List<HashType> HashTypes { get; private set; } = [];
/// <summary>
/// Set of input paths to use for operations
/// </summary>
public List<string> InputPaths { get; private set; } = [];
/// <summary>
/// Print all available hashes and then quit
/// </summary>
/// <remarks>Ignores all other flags if found</remarks>
public bool PrintAvailableHashes { get; private set; } = false;
#endregion
#region Instance Variables
/// <summary>
/// Special flag to enable all hash types
/// </summary>
/// <remarks>Skips adding hash types specified otherwise</remarks>
private bool _allHashTypesEnabled = false;
#endregion
/// <summary>
/// Parse commandline arguments into an Options object
/// </summary>
public static Options? ParseOptions(string[] args)
{
// If we have invalid arguments
if (args == null || args.Length == 0)
return null;
// Create an Options object
var options = new Options();
// Parse the features
int index = 0;
for (; index < args.Length; index++)
{
string arg = args[index];
bool featureFound = false;
switch (arg)
{
case "-?":
case "-h":
case "--help":
return null;
default:
break;
}
// If the flag wasn't a feature
if (!featureFound)
break;
}
// Parse the options and paths
for (; index < args.Length; index++)
{
string arg = args[index];
switch (arg)
{
case "-d":
case "--debug":
options.Debug = true;
break;
case "-l":
case "--list":
options.PrintAvailableHashes = true;
break;
case "-t":
case "--type":
string value = index + 1 < args.Length ? args[++index] : string.Empty;
if (value.Equals("all", StringComparison.OrdinalIgnoreCase))
{
options._allHashTypesEnabled = true;
break;
}
if (!options._allHashTypesEnabled)
{
HashType? hashType = value.GetHashType();
if (hashType != null && !options.HashTypes.Contains(hashType.Value))
options.HashTypes.Add(item: hashType.Value);
}
break;
default:
options.InputPaths.Add(arg);
break;
}
}
// Validate we have any input paths to work on
if (options.InputPaths.Count == 0)
{
Console.WriteLine("At least one path is required!");
return null;
}
// If the all hashes flag was enabled
if (options._allHashTypesEnabled)
{
options.HashTypes = [.. (HashType[])Enum.GetValues(typeof(HashType))];
}
// If no hash types are provided, set defaults
if (options.HashTypes.Count == 0)
{
options.HashTypes.Add(HashType.CRC32);
options.HashTypes.Add(HashType.MD5);
options.HashTypes.Add(HashType.SHA1);
options.HashTypes.Add(HashType.SHA256);
}
return options;
}
/// <summary>
/// Display help text
/// </summary>
public static void DisplayHelp()
{
Console.WriteLine("File Hashing Program");
Console.WriteLine();
Console.WriteLine("Hasher <options> file|directory ...");
Console.WriteLine();
Console.WriteLine("Options:");
Console.WriteLine("-?, -h, --help Display this help text and quit");
Console.WriteLine("-d, --debug Enable debug mode");
Console.WriteLine("-l, --list List all available hashes and quit");
Console.WriteLine("-t, --type [TYPE] Output file hashes");
Console.WriteLine();
Console.WriteLine("If no hash types are provided, this tool will default");
Console.WriteLine("to outputting CRC-32, MD5, SHA-1, and SHA-256.");
Console.WriteLine("Optionally, all supported hashes can be output");
Console.WriteLine("by specifying a value of 'all'.");
}
}
}

134
Hasher/Program.cs Normal file
View File

@@ -0,0 +1,134 @@
using System;
using System.IO;
using System.Text;
using SabreTools.Hashing;
namespace Hasher
{
public static class Program
{
public static void Main(string[] args)
{
// Get the options from the arguments
var options = Options.ParseOptions(args);
// If we have an invalid state
if (options == null)
{
Options.DisplayHelp();
return;
}
// If a printing option was defined
if (options.PrintAvailableHashes)
{
PrintAvailableHashes();
return;
}
// Loop through the input paths
foreach (string inputPath in options.InputPaths)
{
PrintPathHashes(inputPath, options);
}
}
/// <summary>
/// Print all available hashes along with their short names
/// </summary>
/// TODO: Print all supported variants of names?
private static void PrintAvailableHashes()
{
Console.WriteLine("Hash Name Parameter Name ");
Console.WriteLine("--------------------------------------------------------------");
var hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
foreach (var hashType in hashTypes)
{
// Derive the parameter name
string paramName = $"{hashType}";
paramName = paramName.Replace("-", string.Empty);
paramName = paramName.Replace(" ", string.Empty);
paramName = paramName.Replace("/", "_");
paramName = paramName.Replace("\\", "_");
paramName = paramName.ToLowerInvariant();
Console.WriteLine($"{hashType.GetHashName()?.PadRight(39, ' ')} {paramName}");
}
}
/// <summary>
/// Wrapper to print hashes for a single path
/// </summary>
/// <param name="path">File or directory path</param>
/// <param name="options">User-defined options</param>
private static void PrintPathHashes(string path, Options options)
{
Console.WriteLine($"Checking possible path: {path}");
// Check if the file or directory exists
if (File.Exists(path))
{
PrintFileHashes(path, options);
}
else if (Directory.Exists(path))
{
foreach (string file in Directory.GetFiles(path, "*", SearchOption.AllDirectories))
{
PrintFileHashes(file, options);
}
}
else
{
Console.WriteLine($"{path} does not exist, skipping...");
}
}
/// <summary>
/// Print information for a single file, if possible
/// </summary>
/// <param name="file">File path</param>
/// <param name="options">User-defined options</param>
private static void PrintFileHashes(string file, Options options)
{
Console.WriteLine($"Attempting to hash {file}, this may take a while...");
Console.WriteLine();
// If the file doesn't exist
if (!File.Exists(file))
{
Console.WriteLine($"{file} does not exist, skipping...");
return;
}
try
{
// Get all file hashes for flexibility
var hashes = HashTool.GetFileHashes(file);
if (hashes == null)
{
if (options.Debug) Console.WriteLine($"Hashes for {file} could not be retrieved");
return;
}
// Output subset of available hashes
var builder = new StringBuilder();
foreach (HashType hashType in options.HashTypes)
{
// TODO: Make helper to pretty-print hash type names
if (hashes.TryGetValue(hashType, out string? hash) && hash != null)
builder.AppendLine($"{hashType}: {hash}");
}
// Create and print the output data
string hashData = builder.ToString();
Console.WriteLine(hashData);
}
catch (Exception ex)
{
Console.WriteLine(options.Debug ? ex : "[Exception opening file, please try again]");
return;
}
}
}
}

View File

@@ -39,3 +39,22 @@ External implementations of hash and checksum types may not be compatible with a
| [System.Security.Cryptography](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography) | MD5, SHA-1, SHA-256, SHA-384, SHA-512, SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256 | Built-in library; SHA3-256, SHA3-384, SHA3-512, SHAKE128, and SHAKE256 are `net8.0` and above only for [supported platforms](https://learn.microsoft.com/en-us/dotnet/standard/security/cross-platform-cryptography) |
**Note:** If all you care about is performance, I encourage you to forego this library and use the ones listed above directly instead.
## Hasher
**Hasher** is a reference implementation for hashing and checksumming features of the library, packaged as a standalone executable for all supported platforms. It will attempt to select the correct hashing types based on input and then print the calculated values to standard output.
```
Hasher <options> file|directory ...
Options:
-?, -h, --help Display this help text and quit
-d, --debug Enable debug mode
-l, --list List all available hashes and quit
-t, --type [TYPE] Output file hashes
If no hash types are provided, this tool will default
to outputting CRC-32, MD5, SHA-1, and SHA-256.
Optionally, all supported hashes can be output
by specifying a value of 'all'.
```

View File

@@ -7,22 +7,56 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SabreTools.Hashing", "Sabre
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SabreTools.Hashing.Test", "SabreTools.Hashing.Test\SabreTools.Hashing.Test.csproj", "{A2BCBFDE-685B-4817-B724-050A99E02601}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hasher", "Hasher\Hasher.csproj", "{5DAC74F2-22AB-409B-B828-2FD3851586A3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Debug|x64.ActiveCfg = Debug|Any CPU
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Debug|x64.Build.0 = Debug|Any CPU
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Debug|x86.ActiveCfg = Debug|Any CPU
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Debug|x86.Build.0 = Debug|Any CPU
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Release|Any CPU.Build.0 = Release|Any CPU
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Release|x64.ActiveCfg = Release|Any CPU
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Release|x64.Build.0 = Release|Any CPU
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Release|x86.ActiveCfg = Release|Any CPU
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Release|x86.Build.0 = Release|Any CPU
{A2BCBFDE-685B-4817-B724-050A99E02601}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A2BCBFDE-685B-4817-B724-050A99E02601}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A2BCBFDE-685B-4817-B724-050A99E02601}.Debug|x64.ActiveCfg = Debug|Any CPU
{A2BCBFDE-685B-4817-B724-050A99E02601}.Debug|x64.Build.0 = Debug|Any CPU
{A2BCBFDE-685B-4817-B724-050A99E02601}.Debug|x86.ActiveCfg = Debug|Any CPU
{A2BCBFDE-685B-4817-B724-050A99E02601}.Debug|x86.Build.0 = Debug|Any CPU
{A2BCBFDE-685B-4817-B724-050A99E02601}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A2BCBFDE-685B-4817-B724-050A99E02601}.Release|Any CPU.Build.0 = Release|Any CPU
{A2BCBFDE-685B-4817-B724-050A99E02601}.Release|x64.ActiveCfg = Release|Any CPU
{A2BCBFDE-685B-4817-B724-050A99E02601}.Release|x64.Build.0 = Release|Any CPU
{A2BCBFDE-685B-4817-B724-050A99E02601}.Release|x86.ActiveCfg = Release|Any CPU
{A2BCBFDE-685B-4817-B724-050A99E02601}.Release|x86.Build.0 = Release|Any CPU
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Debug|x64.ActiveCfg = Debug|Any CPU
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Debug|x64.Build.0 = Debug|Any CPU
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Debug|x86.ActiveCfg = Debug|Any CPU
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Debug|x86.Build.0 = Debug|Any CPU
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Release|Any CPU.Build.0 = Release|Any CPU
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Release|x64.ActiveCfg = Release|Any CPU
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Release|x64.Build.0 = Release|Any CPU
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Release|x86.ActiveCfg = Release|Any CPU
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,9 @@
#if NET20
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
internal sealed class ExtensionAttribute : Attribute {}
}
#endif

View File

@@ -0,0 +1,441 @@
namespace SabreTools.Hashing
{
public static class Extensions
{
/// <summary>
/// Get the name of a given hash type, if possible
/// </summary>
/// TODO: This should be automated instead of hardcoded
public static string? GetHashName(this HashType hashType)
{
return hashType switch
{
HashType.Adler32 => "Mark Adler's 32-bit checksum",
#if NET7_0_OR_GREATER
HashType.BLAKE3 => "BLAKE3 512-bit digest",
#endif
HashType.CRC1_ZERO => "CRC-1/ZERO [Parity bit with 0 start]",
HashType.CRC1_ONE => "CRC-1/ONE [Parity bit with 1 start]",
HashType.CRC3_GSM => "CRC-3/GSM",
HashType.CRC3_ROHC => "CRC-3/ROHC",
HashType.CRC4_G704 => "CRC-4/G-704 [CRC-4/ITU]",
HashType.CRC4_INTERLAKEN => "CRC-4/INTERLAKEN",
HashType.CRC5_EPCC1G2 => "CRC-5/EPC-C1G2 [CRC-5/EPC]",
HashType.CRC5_G704 => "CRC-5/G-704 [CRC-5/ITU]",
HashType.CRC5_USB => "CRC-5/USB",
HashType.CRC6_CDMA2000A => "CRC-6/CDMA2000-A",
HashType.CRC6_CDMA2000B => "CRC-6/CDMA2000-B",
HashType.CRC6_DARC => "CRC-6/DARC",
HashType.CRC6_G704 => "CRC-6/G-704 [CRC-6/ITU]",
HashType.CRC6_GSM => "CRC-6/GSM",
HashType.CRC7_MMC => "CRC-7/MMC [CRC-7]",
HashType.CRC7_ROHC => "CRC-7/ROHC",
HashType.CRC7_UMTS => "CRC-7/UMTS",
HashType.CRC8 => "CRC-8",
HashType.CRC8_AUTOSAR => "CRC-8/AUTOSAR",
HashType.CRC8_BLUETOOTH => "CRC-8/BLUETOOTH",
HashType.CRC8_CDMA2000 => "CRC-8/CDMA2000",
HashType.CRC8_DARC => "CRC-8/DARC",
HashType.CRC8_DVBS2 => "CRC-8/DVB-S2",
HashType.CRC8_GSMA => "CRC-8/GSM-A",
HashType.CRC8_GSMB => "CRC-8/GSM-B",
HashType.CRC8_HITAG => "CRC-8/HITAG",
HashType.CRC8_I4321 => "CRC-8/I-432-1 [CRC-8/ITU]",
HashType.CRC8_ICODE => "CRC-8/I-CODE",
HashType.CRC8_LTE => "CRC-8/LTE",
HashType.CRC8_MAXIMDOW => "CRC-8/MAXIM-DOW [CRC-8/MAXIM, DOW-CRC]",
HashType.CRC8_MIFAREMAD => "CRC-8/MIFARE-MAD",
HashType.CRC8_NRSC5 => "CRC-8/NRSC-5",
HashType.CRC8_OPENSAFETY => "CRC-8/OPENSAFETY",
HashType.CRC8_ROHC => "CRC-8/ROHC",
HashType.CRC8_SAEJ1850 => "CRC-8/SAE-J1850",
HashType.CRC8_SMBUS => "CRC-8/SMBUS [CRC-8]",
HashType.CRC8_TECH3250 => "CRC-8/TECH-3250 [CRC-8/AES, CRC-8/EBU]",
HashType.CRC8_WCDMA => "CRC-8/WCDMA",
HashType.CRC10_ATM => "CRC-10/ATM [CRC-10, CRC-10/I-610]",
HashType.CRC10_CDMA2000 => "CRC-10/CDMA2000",
HashType.CRC10_GSM => "CRC-10/GSM",
HashType.CRC11_FLEXRAY => "CRC-11/FLEXRAY [CRC-11]",
HashType.CRC11_UMTS => "CRC-11/UMTS",
HashType.CRC12_CDMA2000 => "CRC-12/CDMA2000",
HashType.CRC12_DECT => "CRC-12/DECT [X-CRC-12]",
HashType.CRC12_GSM => "CRC-12/GSM",
HashType.CRC12_UMTS => "CRC-12/UMTS [CRC-12/3GPP]",
HashType.CRC13_BBC => "CRC-13/BBC",
HashType.CRC14_DARC => "CRC-14/DARC",
HashType.CRC14_GSM => "CRC-14/GSM",
HashType.CRC15_CAN => "CRC-15/CAN [CRC-15]",
HashType.CRC15_MPT1327 => "CRC-15/MPT1327",
HashType.CRC16 => "CRC-16",
HashType.CRC16_ARC => "CRC-16/ARC [ARC, CRC-16, CRC-16/LHA, CRC-IBM]",
HashType.CRC16_CDMA2000 => "CRC-16/CDMA2000",
HashType.CRC16_CMS => "CRC-16/CMS",
HashType.CRC16_DDS110 => "CRC-16/DDS-110",
HashType.CRC16_DECTR => "CRC-16/DECT-R [R-CRC-16]",
HashType.CRC16_DECTX => "CRC-16/DECT-X [X-CRC-16]",
HashType.CRC16_DNP => "CRC-16/DNP",
HashType.CRC16_EN13757 => "CRC-16/EN-13757",
HashType.CRC16_GENIBUS => "CRC-16/GENIBUS [CRC-16/DARC, CRC-16/EPC, CRC-16/EPC-C1G2, CRC-16/I-CODE]",
HashType.CRC16_GSM => "CRC-16/GSM",
HashType.CRC16_IBM3740 => "CRC-16/IBM-3740 [CRC-16/AUTOSAR, CRC-16/CCITT-FALSE]",
HashType.CRC16_IBMSDLC => "CRC-16/IBM-SDLC [CRC-16/ISO-HDLC, CRC-16/ISO-IEC-14443-3-B, CRC-16/X-25, CRC-B, X-25]",
HashType.CRC16_ISOIEC144433A => "CRC-16/ISO-IEC-14443-3-A [CRC-A]",
HashType.CRC16_KERMIT => "CRC-16/KERMIT [CRC-16/BLUETOOTH, CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-16/V-41-LSB, CRC-CCITT, KERMIT]",
HashType.CRC16_LJ1200 => "CRC-16/LJ1200",
HashType.CRC16_M17 => "CRC-16/M17",
HashType.CRC16_MAXIMDOW => "CRC-16/MAXIM-DOW [CRC-16/MAXIM]",
HashType.CRC16_MCRF4XX => "CRC-16/MCRF4XX",
HashType.CRC16_MODBUS => "CRC-16/MODBUS [MODBUS]",
HashType.CRC16_NRSC5 => "CRC-16/NRSC-5",
HashType.CRC16_OPENSAFETYA => "CRC-16/OPENSAFETY-A",
HashType.CRC16_OPENSAFETYB => "CRC-16/OPENSAFETY-B",
HashType.CRC16_PROFIBUS => "CRC-16/PROFIBUS [CRC-16/IEC-61158-2]",
HashType.CRC16_RIELLO => "CRC-16/RIELLO",
HashType.CRC16_SPIFUJITSU => "CRC-16/SPI-FUJITSU [CRC-16/AUG-CCITT]",
HashType.CRC16_T10DIF => "CRC-16/T10-DIF",
HashType.CRC16_TELEDISK => "CRC-16/TELEDISK",
HashType.CRC16_TMS37157 => "CRC-16/TMS37157",
HashType.CRC16_UMTS => "CRC-16/UMTS [CRC-16/BUYPASS, CRC-16/VERIFONE]",
HashType.CRC16_USB => "CRC-16/USB",
HashType.CRC16_XMODEM => "CRC-16/XMODEM [CRC-16/ACORN, CRC-16/LTE, CRC-16/V-41-MSB, XMODEM, ZMODEM]",
HashType.CRC17_CANFD => "CRC-17/CAN-FD",
HashType.CRC21_CANFD => "CRC-21/CAN-FD",
HashType.CRC24_BLE => "CRC-24/BLE",
HashType.CRC24_FLEXRAYA => "CRC-24/FLEXRAY-A",
HashType.CRC24_FLEXRAYB => "CRC-24/FLEXRAY-B",
HashType.CRC24_INTERLAKEN => "CRC-24/INTERLAKEN",
HashType.CRC24_LTEA => "CRC-24/LTE-A",
HashType.CRC24_LTEB => "CRC-24/LTE-B",
HashType.CRC24_OPENPGP => "CRC-24/OPENPGP",
HashType.CRC24_OS9 => "CRC-24/OS-9",
HashType.CRC30_CDMA => "CRC-30/CDMA",
HashType.CRC31_PHILIPS => "CRC-31/PHILIPS",
HashType.CRC32 => "CRC-32",
HashType.CRC32_AIXM => "CRC-32/AIXM",
HashType.CRC32_AUTOSAR => "CRC-32/AUTOSAR",
HashType.CRC32_BASE91D => "CRC-32/BASE91-D",
HashType.CRC32_BZIP2 => "BZIP2",
HashType.CRC32_CDROMEDC => "CRC-32/CD-ROM-EDC",
HashType.CRC32_CKSUM => "CRC-32/CKSUM",
HashType.CRC32_ISCSI => "CRC-32/ISCSI",
HashType.CRC32_ISOHDLC => "CRC-32/ISO-HDLC",
HashType.CRC32_JAMCRC => "CRC-32/JAMCRC",
HashType.CRC32_MEF => "CRC-32/MEF",
HashType.CRC32_MPEG2 => "CRC-32/MPEG-2",
HashType.CRC32_XFER => "CRC-32/XFER",
HashType.CRC40_GSM => "CRC-40/GSM",
HashType.CRC64 => "CRC-64",
HashType.CRC64_ECMA182 => "CRC-64/ECMA-182, Microsoft implementation",
HashType.CRC64_GOISO => "CRC-64/GO-ISO",
HashType.CRC64_MS => "CRC-64/MS",
HashType.CRC64_NVME => "CRC-64/NVME",
HashType.CRC64_REDIS => "CRC-64/REDIS",
HashType.CRC64_WE => "CRC-64/WE",
HashType.CRC64_XZ => "CRC-64/XZ",
HashType.Fletcher16 => "John G. Fletcher's 16-bit checksum",
HashType.Fletcher32 => "John G. Fletcher's 32-bit checksum",
HashType.Fletcher64 => "John G. Fletcher's 64-bit checksum",
HashType.FNV0_32 => "FNV hash (Variant 0, 32-bit)",
HashType.FNV0_64 => "FNV hash (Variant 0, 64-bit)",
HashType.FNV1_32 => "FNV hash (Variant 1, 32-bit)",
HashType.FNV1_64 => "FNV hash (Variant 1, 64-bit)",
HashType.FNV1a_32 => "FNV hash (Variant 1a, 32-bit)",
HashType.FNV1a_64 => "FNV hash (Variant 1a, 64-bit)",
HashType.MD2 => "MD2 message-digest algorithm",
HashType.MD4 => "MD4 message-digest algorithm",
HashType.MD5 => "MD5 message-digest algorithm",
HashType.RIPEMD128 => "RIPEMD-128 hash",
HashType.RIPEMD160 => "RIPEMD-160 hash",
HashType.RIPEMD256 => "RIPEMD-256 hash",
HashType.RIPEMD320 => "RIPEMD-320 hash",
HashType.SHA1 => "SHA-1 hash",
HashType.SHA256 => "SHA-256 hash",
HashType.SHA384 => "SHA-384 hash",
HashType.SHA512 => "SHA-512 hash",
#if NET8_0_OR_GREATER
HashType.SHA3_256 => "SHA3-256 hash",
HashType.SHA3_384 => "SHA3-384 hash",
HashType.SHA3_512 => "SHA3-512 hash",
HashType.SHAKE128 => "SHAKE128 SHA-3 family hash (256-bit)",
HashType.SHAKE256 => "SHAKE256 SHA-3 family hash (512-bit)",
#endif
HashType.SpamSum => "spamsum fuzzy hash",
HashType.Tiger128_3 => "Tiger 128-bit hash, 3 passes",
HashType.Tiger128_4 => "Tiger 128-bit hash, 4 passes",
HashType.Tiger160_3 => "Tiger 160-bit hash, 3 passes",
HashType.Tiger160_4 => "Tiger 160-bit hash, 4 passes",
HashType.Tiger192_3 => "Tiger 192-bit hash, 3 passes",
HashType.Tiger192_4 => "Tiger 192-bit hash, 4 passes",
HashType.Tiger2_128_3 => "Tiger2 128-bit hash, 3 passes",
HashType.Tiger2_128_4 => "Tiger2 128-bit hash, 4 passes",
HashType.Tiger2_160_3 => "Tiger2 160-bit hash, 3 passes",
HashType.Tiger2_160_4 => "Tiger2 160-bit hash, 4 passes",
HashType.Tiger2_192_3 => "Tiger2 192-bit hash, 3 passes",
HashType.Tiger2_192_4 => "Tiger2 192-bit hash, 4 passes",
HashType.XxHash32 => "xxHash32 hash",
HashType.XxHash64 => "xxHash64 hash",
#if NET462_OR_GREATER || NETCOREAPP
HashType.XxHash3 => "XXH3 64-bit hash",
HashType.XxHash128 => "XXH128 128-bit hash",
#endif
_ => $"{hashType}",
};
}
/// <summary>
/// Get the hash type associated to a string, if possible
/// </summary>
/// TODO: This should be automated instead of hardcoded
public static HashType? GetHashType(this string? str)
{
// Ignore invalid strings
if (string.IsNullOrEmpty(str))
return null;
// Normalize the string before matching
str = str!.Replace("-", string.Empty);
str = str.Replace(" ", string.Empty);
str = str.Replace("/", "_");
str = str.Replace("\\", "_");
str = str.ToLowerInvariant();
// Match based on potential names
return str switch
{
"adler" or "adler32" => HashType.Adler32,
#if NET7_0_OR_GREATER
"blake3" => HashType.BLAKE3,
#endif
"crc1_0" or "crc1_zero" => HashType.CRC1_ZERO,
"crc1_1" or "crc1_one" => HashType.CRC1_ONE,
"crc3_gsm" => HashType.CRC3_GSM,
"crc3_rohc" => HashType.CRC3_ROHC,
"crc4_g704" or "crc4_itu" => HashType.CRC4_G704,
"crc4_interlaken" => HashType.CRC4_INTERLAKEN,
"crc5_epc" or "crc5_epcc1g2" => HashType.CRC5_EPCC1G2,
"crc5_g704" or "crc5_itu" => HashType.CRC5_G704,
"crc5_usb" => HashType.CRC5_USB,
"crc6_cdma2000a" => HashType.CRC6_CDMA2000A,
"crc6_cdma2000b" => HashType.CRC6_CDMA2000B,
"crc6_darc" => HashType.CRC6_DARC,
"crc6_g704" or "crc6_itu" => HashType.CRC6_G704,
"crc6_gsm" => HashType.CRC6_GSM,
"crc7" or "crc7_mmc" => HashType.CRC7_MMC,
"crc7_rohc" => HashType.CRC7_ROHC,
"crc7_umts" => HashType.CRC7_UMTS,
"crc8" => HashType.CRC8,
"crc8_autosar" => HashType.CRC8_AUTOSAR,
"crc8_bluetooth" => HashType.CRC8_BLUETOOTH,
"crc8_cdma2000" => HashType.CRC8_CDMA2000,
"crc8_darc" => HashType.CRC8_DARC,
"crc8_dvbs2" => HashType.CRC8_DVBS2,
"crc8_gsma" => HashType.CRC8_GSMA,
"crc8_gsmb" => HashType.CRC8_GSMB,
"crc8_hitag" => HashType.CRC8_HITAG,
"crc8_i4321" or "crc8_itu" => HashType.CRC8_I4321,
"crc8_icode" => HashType.CRC8_ICODE,
"crc8_lte" => HashType.CRC8_LTE,
"crc8_maximdow" or "crc8_maxim" or "dowcrc" => HashType.CRC8_MAXIMDOW,
"crc8_mifaremad" => HashType.CRC8_MIFAREMAD,
"crc8_nrsc5" => HashType.CRC8_NRSC5,
"crc8_opensafety" => HashType.CRC8_OPENSAFETY,
"crc8_rohc" => HashType.CRC8_ROHC,
"crc8_saej1850" => HashType.CRC8_SAEJ1850,
"crc8_smbus" => HashType.CRC8_SMBUS,
"crc8_tech3250" or "crc8_aes" or "crc8_ebu" => HashType.CRC8_TECH3250,
"crc8_wcdma" => HashType.CRC8_WCDMA,
"crc10_atm" or "crc10" or "crc10_i610" => HashType.CRC10_ATM,
"crc10_cdma2000" => HashType.CRC10_CDMA2000,
"crc10_gsm" => HashType.CRC10_GSM,
"crc11_flexray" or "crc11" => HashType.CRC11_FLEXRAY,
"crc11_umts" => HashType.CRC11_UMTS,
"crc12_cdma2000" => HashType.CRC12_CDMA2000,
"crc12_dect" or "xcrc12" => HashType.CRC12_DECT,
"crc12_gsm" => HashType.CRC12_GSM,
"crc12_umts" or "crc12_3gpp" => HashType.CRC12_UMTS,
"crc13_bbc" => HashType.CRC13_BBC,
"crc14_darc" => HashType.CRC14_DARC,
"crc14_gsm" => HashType.CRC14_GSM,
"crc15_can" or "crc15" => HashType.CRC15_CAN,
"crc15_mpt1327" => HashType.CRC15_MPT1327,
"crc16" => HashType.CRC16,
"crc16_arc" or "arc" or "crc16_lha" or "crcibm" => HashType.CRC16_ARC,
"crc16_cdma2000" => HashType.CRC16_CDMA2000,
"crc16_cms" => HashType.CRC16_CMS,
"crc16_dds110" => HashType.CRC16_DDS110,
"crc16_dectr" or "rcrc16" => HashType.CRC16_DECTR,
"crc16_dectx" or "xcrc16" => HashType.CRC16_DECTX,
"crc16_dnp" => HashType.CRC16_DNP,
"crc16_en13757" => HashType.CRC16_EN13757,
"crc16_genibus" or "crc16_darc" or "crc16_epc" or "crc16_epcc1g2" or "crc16_icode" => HashType.CRC16_GENIBUS,
"crc16_gsm" => HashType.CRC16_GSM,
"crc16_ibm3740" or "crc16_autosar" or "crc16_cittfalse" => HashType.CRC16_IBM3740,
"crc16_ibmsdlc" or "crc16_isohdlc" or "crc16_isoiec144433b" or "crc16_x25" or "crcb" or "x25" => HashType.CRC16_IBMSDLC,
"crc16_isoiec144433a" or "crca" => HashType.CRC16_ISOIEC144433A,
"crc16_kermit" or "crc16_bluetooth" or "crc16_ccitt" or "crc16_ccitttrue" or "crc16_v41lsb" or "crcccitt" or "kermit" => HashType.CRC16_KERMIT,
"crc16_lj1200" => HashType.CRC16_LJ1200,
"crc16_m17" => HashType.CRC16_M17,
"crc16_maximdow" or "crc16_maxim" => HashType.CRC16_MAXIMDOW,
"crc16_mcrf4xx" => HashType.CRC16_MCRF4XX,
"crc16_modbus" or "modbus" => HashType.CRC16_MODBUS,
"crc16_nrsc5" => HashType.CRC16_NRSC5,
"crc16_opensafetya" => HashType.CRC16_OPENSAFETYA,
"crc16_opensafetyb" => HashType.CRC16_OPENSAFETYB,
"crc16_profibus" or "crc16_iec611582" => HashType.CRC16_PROFIBUS,
"crc16_riello" => HashType.CRC16_RIELLO,
"crc16_spifujitsu" or "crc16_augccitt" => HashType.CRC16_SPIFUJITSU,
"crc16_t10dif" => HashType.CRC16_T10DIF,
"crc16_teledisk" => HashType.CRC16_TELEDISK,
"crc16_tms37157" => HashType.CRC16_TMS37157,
"crc16_umts" or "crc16_buypass" or "crc16_verifone" => HashType.CRC16_UMTS,
"crc16_usb" => HashType.CRC16_USB,
"crc16_xmodem" or "crc16_acorn" or "crc16_lte" or "crc16_v41msb" or "xmodem" or "zmodem" => HashType.CRC16_XMODEM,
"crc17_canfd" => HashType.CRC17_CANFD,
"crc21_canfd" => HashType.CRC21_CANFD,
"crc24_ble" => HashType.CRC24_BLE,
"crc24_flexraya" => HashType.CRC24_FLEXRAYA,
"crc24_flexrayb" => HashType.CRC24_FLEXRAYB,
"crc24_interlaken" => HashType.CRC24_INTERLAKEN,
"crc24_ltea" => HashType.CRC24_LTEA,
"crc24_lteb" => HashType.CRC24_LTEB,
"crc24_openpgp" => HashType.CRC24_OPENPGP,
"crc24_os9" => HashType.CRC24_OS9,
"crc30_cdma" => HashType.CRC30_CDMA,
"crc31_philips" => HashType.CRC31_PHILIPS,
"crc32" => HashType.CRC32,
"crc32_aixm" => HashType.CRC32_AIXM,
"crc32_autosar" => HashType.CRC32_AUTOSAR,
"crc32_base91d" => HashType.CRC32_BASE91D,
"crc32_bzip2" => HashType.CRC32_BZIP2,
"crc32_cdromedc" => HashType.CRC32_CDROMEDC,
"crc32_cksum" => HashType.CRC32_CKSUM,
"crc32_iscsi" => HashType.CRC32_ISCSI,
"crc32_isohdlc" => HashType.CRC32_ISOHDLC,
"crc32_jamcrc" => HashType.CRC32_JAMCRC,
"crc32_mef" => HashType.CRC32_MEF,
"crc32_mpeg2" => HashType.CRC32_MPEG2,
"crc32_xfer" => HashType.CRC32_XFER,
"crc40_gsm" => HashType.CRC40_GSM,
"crc64" => HashType.CRC64,
"crc64_ecma182" => HashType.CRC64_ECMA182,
"crc64_goiso" => HashType.CRC64_GOISO,
"crc64_ms" => HashType.CRC64_MS,
"crc64_nvme" => HashType.CRC64_NVME,
"crc64_redis" => HashType.CRC64_REDIS,
"crc64_we" => HashType.CRC64_WE,
"crc64_xz" => HashType.CRC64_XZ,
"fletcher16" => HashType.Fletcher16,
"fletcher32" => HashType.Fletcher32,
"fletcher64" => HashType.Fletcher64,
"fnv0_32" => HashType.FNV0_32,
"fnv0_64" => HashType.FNV0_64,
"fnv1_32" => HashType.FNV1_32,
"fnv1_64" => HashType.FNV1_64,
"fnv1a_32" => HashType.FNV1a_32,
"fnv1a_64" => HashType.FNV1a_64,
"md2" => HashType.MD2,
"md4" => HashType.MD4,
"md5" => HashType.MD5,
"ripemd128" => HashType.RIPEMD128,
"ripemd160" => HashType.RIPEMD160,
"ripemd256" => HashType.RIPEMD256,
"ripemd320" => HashType.RIPEMD320,
"sha1" => HashType.SHA1,
"sha256" => HashType.SHA256,
"sha384" => HashType.SHA384,
"sha512" => HashType.SHA512,
#if NET8_0_OR_GREATER
"sha3_256" => HashType.SHA3_256,
"sha3_384" => HashType.SHA3_384,
"sha3_512" => HashType.SHA3_512,
"shake128" => HashType.SHAKE128,
"shake256" => HashType.SHAKE256,
#endif
"spamsum" => HashType.SpamSum,
"tiger128_3" => HashType.Tiger128_3,
"tiger128_4" => HashType.Tiger128_4,
"tiger160_3" => HashType.Tiger160_3,
"tiger160_4" => HashType.Tiger160_4,
"tiger192_3" => HashType.Tiger192_3,
"tiger192_4" => HashType.Tiger192_4,
"tiger2_128_3" => HashType.Tiger2_128_3,
"tiger2_128_4" => HashType.Tiger2_128_4,
"tiger2_160_3" => HashType.Tiger2_160_3,
"tiger2_160_4" => HashType.Tiger2_160_4,
"tiger2_192_3" => HashType.Tiger2_192_3,
"tiger2_192_4" => HashType.Tiger2_192_4,
"xxh" or "xxh32" or "xxh_32" or "xxhash" or "xxhash32" or "xxhash_32" => HashType.XxHash32,
"xxh64" or "xxh_64" or "xxhash64" or "xxhash_64" => HashType.XxHash64,
#if NET462_OR_GREATER || NETCOREAPP
"xxh3" or "xxh3_64" or "xxhash3" or "xxhash_3" => HashType.XxHash3,
"xxh128" or "xxh_128" or "xxhash128" or "xxhash_128" => HashType.XxHash128,
#endif
_ => null,
};
}
}
}

View File

@@ -1,19 +1,32 @@
#! /bin/bash
#!/bin/bash
# This batch file assumes the following:
# - .NET 9.0 (or newer) SDK is installed and in PATH
# - zip is installed and in PATH
# - Git is installed and in PATH
#
# If any of these are not satisfied, the operation may fail
# in an unpredictable way and result in an incomplete output.
# Optional parameters
USE_ALL=false
INCLUDE_DEBUG=false
NO_BUILD=false
while getopts "b" OPTION
do
NO_ARCHIVE=false
while getopts "udba" OPTION; do
case $OPTION in
u)
USE_ALL=true
;;
d)
INCLUDE_DEBUG=true
;;
b)
NO_BUILD=true
;;
a)
NO_ARCHIVE=true
;;
*)
echo "Invalid option provided"
exit 1
@@ -24,13 +37,115 @@ done
# Set the current directory as a variable
BUILD_FOLDER=$PWD
# Set the current commit hash
COMMIT=$(git log --pretty=%H -1)
# Output the selected options
echo "Selected Options:"
echo " Use all frameworks (-u) $USE_ALL"
echo " Include debug builds (-d) $INCLUDE_DEBUG"
echo " No build (-b) $NO_BUILD"
echo " No archive (-a) $NO_ARCHIVE"
echo " "
# Create the build matrix arrays
FRAMEWORKS=("net9.0")
RUNTIMES=("win-x86" "win-x64" "win-arm64" "linux-x64" "linux-arm64" "osx-x64" "osx-arm64")
# Use expanded lists, if requested
if [ $USE_ALL = true ]; then
FRAMEWORKS=("net20" "net35" "net40" "net452" "net462" "net472" "net48" "netcoreapp3.1" "net5.0" "net6.0" "net7.0" "net8.0" "net9.0")
fi
# Create the filter arrays
SINGLE_FILE_CAPABLE=("net5.0" "net6.0" "net7.0" "net8.0" "net9.0")
VALID_APPLE_FRAMEWORKS=("net6.0" "net7.0" "net8.0" "net9.0")
VALID_CROSS_PLATFORM_FRAMEWORKS=("netcoreapp3.1" "net5.0" "net6.0" "net7.0" "net8.0" "net9.0")
VALID_CROSS_PLATFORM_RUNTIMES=("win-arm64" "linux-x64" "linux-arm64" "osx-x64" "osx-arm64")
# Only build if requested
if [ $NO_BUILD = false ]
then
if [ $NO_BUILD = false ]; then
# Restore Nuget packages for all builds
echo "Restoring Nuget packages"
dotnet restore
# Create Nuget Package
dotnet pack SabreTools.Hashing/SabreTools.Hashing.csproj --output $BUILD_FOLDER
fi
# Build Hasher
for FRAMEWORK in "${FRAMEWORKS[@]}"; do
for RUNTIME in "${RUNTIMES[@]}"; do
# Output the current build
echo "===== Build Hasher - $FRAMEWORK, $RUNTIME ====="
# If we have an invalid combination of framework and runtime
if [[ ! $(echo ${VALID_CROSS_PLATFORM_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then
if [[ $(echo ${VALID_CROSS_PLATFORM_RUNTIMES[@]} | fgrep -w $RUNTIME) ]]; then
echo "Skipped due to invalid combination"
continue
fi
fi
# If we have Apple silicon but an unsupported framework
if [[ ! $(echo ${VALID_APPLE_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then
if [ $RUNTIME = "osx-arm64" ]; then
echo "Skipped due to no Apple Silicon support"
continue
fi
fi
# Only .NET 5 and above can publish to a single file
if [[ $(echo ${SINGLE_FILE_CAPABLE[@]} | fgrep -w $FRAMEWORK) ]]; then
# Only include Debug if set
if [ $INCLUDE_DEBUG = true ]; then
dotnet publish Hasher/Hasher.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
fi
dotnet publish Hasher/Hasher.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
else
# Only include Debug if set
if [ $INCLUDE_DEBUG = true ]; then
dotnet publish Hasher/Hasher.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT
fi
dotnet publish Hasher/Hasher.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:DebugType=None -p:DebugSymbols=false
fi
done
done
fi
# Only create archives if requested
if [ $NO_ARCHIVE = false ]; then
# Create Hasher archives
for FRAMEWORK in "${FRAMEWORKS[@]}"; do
for RUNTIME in "${RUNTIMES[@]}"; do
# Output the current build
echo "===== Archive Hasher - $FRAMEWORK, $RUNTIME ====="
# If we have an invalid combination of framework and runtime
if [[ ! $(echo ${VALID_CROSS_PLATFORM_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then
if [[ $(echo ${VALID_CROSS_PLATFORM_RUNTIMES[@]} | fgrep -w $RUNTIME) ]]; then
echo "Skipped due to invalid combination"
continue
fi
fi
# If we have Apple silicon but an unsupported framework
if [[ ! $(echo ${VALID_APPLE_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then
if [ $RUNTIME = "osx-arm64" ]; then
echo "Skipped due to no Apple Silicon support"
continue
fi
fi
# Only include Debug if set
if [ $INCLUDE_DEBUG = true ]; then
cd $BUILD_FOLDER/Hasher/bin/Debug/${FRAMEWORK}/${RUNTIME}/publish/
zip -r $BUILD_FOLDER/Hasher_${FRAMEWORK}_${RUNTIME}_debug.zip .
fi
cd $BUILD_FOLDER/Hasher/bin/Release/${FRAMEWORK}/${RUNTIME}/publish/
zip -r $BUILD_FOLDER/Hasher_${FRAMEWORK}_${RUNTIME}_release.zip .
done
done
# Reset the directory
cd $BUILD_FOLDER
fi

View File

@@ -6,21 +6,129 @@
# Optional parameters
param(
[Parameter(Mandatory = $false)]
[Alias("UseAll")]
[switch]$USE_ALL,
[Parameter(Mandatory = $false)]
[Alias("IncludeDebug")]
[switch]$INCLUDE_DEBUG,
[Parameter(Mandatory = $false)]
[Alias("NoBuild")]
[switch]$NO_BUILD
[switch]$NO_BUILD,
[Parameter(Mandatory = $false)]
[Alias("NoArchive")]
[switch]$NO_ARCHIVE
)
# Set the current directory as a variable
$BUILD_FOLDER = $PSScriptRoot
# Set the current commit hash
$COMMIT = git log --pretty=format:"%H" -1
# Output the selected options
Write-Host "Selected Options:"
Write-Host " Use all frameworks (-UseAll) $USE_ALL"
Write-Host " Include debug builds (-IncludeDebug) $INCLUDE_DEBUG"
Write-Host " No build (-NoBuild) $NO_BUILD"
Write-Host " No archive (-NoArchive) $NO_ARCHIVE"
Write-Host " "
# Create the build matrix arrays
$FRAMEWORKS = @('net9.0')
$RUNTIMES = @('win-x86', 'win-x64', 'win-arm64', 'linux-x64', 'linux-arm64', 'osx-x64', 'osx-arm64')
# Use expanded lists, if requested
if ($USE_ALL.IsPresent) {
$FRAMEWORKS = @('net20', 'net35', 'net40', 'net452', 'net462', 'net472', 'net48', 'netcoreapp3.1', 'net5.0', 'net6.0', 'net7.0', 'net8.0', 'net9.0')
}
# Create the filter arrays
$SINGLE_FILE_CAPABLE = @('net5.0', 'net6.0', 'net7.0', 'net8.0', 'net9.0')
$VALID_APPLE_FRAMEWORKS = @('net6.0', 'net7.0', 'net8.0', 'net9.0')
$VALID_CROSS_PLATFORM_FRAMEWORKS = @('netcoreapp3.1', 'net5.0', 'net6.0', 'net7.0', 'net8.0', 'net9.0')
$VALID_CROSS_PLATFORM_RUNTIMES = @('win-arm64', 'linux-x64', 'linux-arm64', 'osx-x64', 'osx-arm64')
# Only build if requested
if (!$NO_BUILD.IsPresent)
{
if (!$NO_BUILD.IsPresent) {
# Restore Nuget packages for all builds
Write-Host "Restoring Nuget packages"
dotnet restore
# Create Nuget Package
dotnet pack SabreTools.Hashing\SabreTools.Hashing.csproj --output $BUILD_FOLDER
# Build Hasher
foreach ($FRAMEWORK in $FRAMEWORKS) {
foreach ($RUNTIME in $RUNTIMES) {
# Output the current build
Write-Host "===== Build Hasher - $FRAMEWORK, $RUNTIME ====="
# If we have an invalid combination of framework and runtime
if ($VALID_CROSS_PLATFORM_FRAMEWORKS -notcontains $FRAMEWORK -and $VALID_CROSS_PLATFORM_RUNTIMES -contains $RUNTIME) {
Write-Host "Skipped due to invalid combination"
continue
}
# If we have Apple silicon but an unsupported framework
if ($VALID_APPLE_FRAMEWORKS -notcontains $FRAMEWORK -and $RUNTIME -eq 'osx-arm64') {
Write-Host "Skipped due to no Apple Silicon support"
continue
}
# Only .NET 5 and above can publish to a single file
if ($SINGLE_FILE_CAPABLE -contains $FRAMEWORK) {
# Only include Debug if set
if ($INCLUDE_DEBUG.IsPresent) {
dotnet publish Hasher\Hasher.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
}
dotnet publish Hasher\Hasher.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
}
else {
# Only include Debug if set
if ($INCLUDE_DEBUG.IsPresent) {
dotnet publish Hasher\Hasher.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT
}
dotnet publish Hasher\Hasher.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:DebugType=None -p:DebugSymbols=false
}
}
}
}
# Only create archives if requested
if (!$NO_ARCHIVE.IsPresent) {
# Create Hasher archives
foreach ($FRAMEWORK in $FRAMEWORKS) {
foreach ($RUNTIME in $RUNTIMES) {
# Output the current build
Write-Host "===== Archive Hasher - $FRAMEWORK, $RUNTIME ====="
# If we have an invalid combination of framework and runtime
if ($VALID_CROSS_PLATFORM_FRAMEWORKS -notcontains $FRAMEWORK -and $VALID_CROSS_PLATFORM_RUNTIMES -contains $RUNTIME) {
Write-Host "Skipped due to invalid combination"
continue
}
# If we have Apple silicon but an unsupported framework
if ($VALID_APPLE_FRAMEWORKS -notcontains $FRAMEWORK -and $RUNTIME -eq 'osx-arm64') {
Write-Host "Skipped due to no Apple Silicon support"
continue
}
# Only include Debug if set
if ($INCLUDE_DEBUG.IsPresent) {
Set-Location -Path $BUILD_FOLDER\Hasher\bin\Debug\${FRAMEWORK}\${RUNTIME}\publish\
7z a -tzip $BUILD_FOLDER\Hasher_${FRAMEWORK}_${RUNTIME}_debug.zip *
}
Set-Location -Path $BUILD_FOLDER\Hasher\bin\Release\${FRAMEWORK}\${RUNTIME}\publish\
7z a -tzip $BUILD_FOLDER\Hasher_${FRAMEWORK}_${RUNTIME}_release.zip *
}
}
# Reset the directory
Set-Location -Path $PSScriptRoot
}