diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml
index 13f7e64..7c65946 100644
--- a/.github/workflows/build_and_test.yml
+++ b/.github/workflows/build_and_test.yml
@@ -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
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..29bcc25
--- /dev/null
+++ b/.vscode/launch.json
@@ -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}"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Hasher/Hasher.csproj b/Hasher/Hasher.csproj
new file mode 100644
index 0000000..036daf5
--- /dev/null
+++ b/Hasher/Hasher.csproj
@@ -0,0 +1,34 @@
+
+
+
+ net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0
+ Exe
+ false
+ true
+ false
+ latest
+ enable
+ true
+ true
+ 1.5.0
+
+
+
+
+ win-x86;win-x64
+
+
+ win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64
+
+
+ win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64
+
+
+ net6.0;net7.0;net8.0;net9.0
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Hasher/Options.cs b/Hasher/Options.cs
new file mode 100644
index 0000000..995eef7
--- /dev/null
+++ b/Hasher/Options.cs
@@ -0,0 +1,168 @@
+using System;
+using System.Collections.Generic;
+using SabreTools.Hashing;
+
+namespace Hasher
+{
+ ///
+ /// Set of options for the test executable
+ ///
+ /// TODO: Add file output
+ internal sealed class Options
+ {
+ #region Properties
+
+ ///
+ /// Enable debug output for relevant operations
+ ///
+ public bool Debug { get; private set; } = false;
+
+ ///
+ /// List of all hash types to process
+ ///
+ public List HashTypes { get; private set; } = [];
+
+ ///
+ /// Set of input paths to use for operations
+ ///
+ public List InputPaths { get; private set; } = [];
+
+ ///
+ /// Print all available hashes and then quit
+ ///
+ /// Ignores all other flags if found
+ public bool PrintAvailableHashes { get; private set; } = false;
+
+ #endregion
+
+ #region Instance Variables
+
+ ///
+ /// Special flag to enable all hash types
+ ///
+ /// Skips adding hash types specified otherwise
+ private bool _allHashTypesEnabled = false;
+
+ #endregion
+
+ ///
+ /// Parse commandline arguments into an Options object
+ ///
+ 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;
+ }
+
+ ///
+ /// Display help text
+ ///
+ public static void DisplayHelp()
+ {
+ Console.WriteLine("File Hashing Program");
+ Console.WriteLine();
+ Console.WriteLine("Hasher 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'.");
+ }
+ }
+}
diff --git a/Hasher/Program.cs b/Hasher/Program.cs
new file mode 100644
index 0000000..e911b9f
--- /dev/null
+++ b/Hasher/Program.cs
@@ -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);
+ }
+ }
+
+ ///
+ /// Print all available hashes along with their short names
+ ///
+ /// 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}");
+ }
+ }
+
+ ///
+ /// Wrapper to print hashes for a single path
+ ///
+ /// File or directory path
+ /// User-defined options
+ 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...");
+ }
+ }
+
+ ///
+ /// Print information for a single file, if possible
+ ///
+ /// File path
+ /// User-defined options
+ 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;
+ }
+ }
+ }
+}
diff --git a/README.MD b/README.MD
index 047cce5..9079695 100644
--- a/README.MD
+++ b/README.MD
@@ -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 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'.
+```
diff --git a/SabreTools.Hashing.sln b/SabreTools.Hashing.sln
index b5fcb40..986a877 100644
--- a/SabreTools.Hashing.sln
+++ b/SabreTools.Hashing.sln
@@ -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
diff --git a/SabreTools.Hashing/ExtensionAttribute.cs b/SabreTools.Hashing/ExtensionAttribute.cs
new file mode 100644
index 0000000..b40aaca
--- /dev/null
+++ b/SabreTools.Hashing/ExtensionAttribute.cs
@@ -0,0 +1,9 @@
+#if NET20
+
+namespace System.Runtime.CompilerServices
+{
+ [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
+ internal sealed class ExtensionAttribute : Attribute {}
+}
+
+#endif
diff --git a/SabreTools.Hashing/Extensions.cs b/SabreTools.Hashing/Extensions.cs
new file mode 100644
index 0000000..9477f01
--- /dev/null
+++ b/SabreTools.Hashing/Extensions.cs
@@ -0,0 +1,441 @@
+namespace SabreTools.Hashing
+{
+ public static class Extensions
+ {
+ ///
+ /// Get the name of a given hash type, if possible
+ ///
+ /// 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}",
+ };
+ }
+
+ ///
+ /// Get the hash type associated to a string, if possible
+ ///
+ /// 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,
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/publish-nix.sh b/publish-nix.sh
index a2bc965..0c83c53 100755
--- a/publish-nix.sh
+++ b/publish-nix.sh
@@ -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
\ No newline at end of file
+
+ # 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
diff --git a/publish-win.ps1 b/publish-win.ps1
index 4d349d2..7ac94a2 100644
--- a/publish-win.ps1
+++ b/publish-win.ps1
@@ -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
}