diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 044d1db8..69a187c6 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -10,7 +10,7 @@ jobs: strategy: matrix: - project: [ProtectionScan, Test] + project: [ExtractionTool, ProtectionScan, Test] runtime: [win-x86, win-x64, win-arm64, linux-x64, linux-arm64, osx-x64] framework: [net8.0] #[net20, net35, net40, net452, net472, net48, netcoreapp3.1, net5.0, net6.0, net7.0, net8.0] conf: [Release, Debug] diff --git a/BinaryObjectScanner.sln b/BinaryObjectScanner.sln index 69a17a5d..256be9e4 100644 --- a/BinaryObjectScanner.sln +++ b/BinaryObjectScanner.sln @@ -20,6 +20,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BinaryObjectScanner", "Bina EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProtectionScan", "ProtectionScan\ProtectionScan.csproj", "{14CC56E0-7D56-497C-BF3D-4C06FA169831}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtractionTool", "ExtractionTool\ExtractionTool.csproj", "{89767A19-043F-4251-805B-B2CBC48E2B79}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -38,6 +40,10 @@ Global {14CC56E0-7D56-497C-BF3D-4C06FA169831}.Debug|Any CPU.Build.0 = Debug|Any CPU {14CC56E0-7D56-497C-BF3D-4C06FA169831}.Release|Any CPU.ActiveCfg = Release|Any CPU {14CC56E0-7D56-497C-BF3D-4C06FA169831}.Release|Any CPU.Build.0 = Release|Any CPU + {89767A19-043F-4251-805B-B2CBC48E2B79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {89767A19-043F-4251-805B-B2CBC48E2B79}.Debug|Any CPU.Build.0 = Debug|Any CPU + {89767A19-043F-4251-805B-B2CBC48E2B79}.Release|Any CPU.ActiveCfg = Release|Any CPU + {89767A19-043F-4251-805B-B2CBC48E2B79}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ExtractionTool/ExtractionTool.csproj b/ExtractionTool/ExtractionTool.csproj new file mode 100644 index 00000000..5a1dfdd5 --- /dev/null +++ b/ExtractionTool/ExtractionTool.csproj @@ -0,0 +1,42 @@ + + + + net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0 + Exe + false + false + latest + enable + true + true + + + + + 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 + + + + + $(DefineConstants);WIN + + + + + + + + + + + + \ No newline at end of file diff --git a/ExtractionTool/Options.cs b/ExtractionTool/Options.cs new file mode 100644 index 00000000..18956c25 --- /dev/null +++ b/ExtractionTool/Options.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace ExtractionTool +{ + /// + /// Set of options for the test executable + /// + internal sealed class Options + { + #region Properties + + /// + /// Enable debug output for relevant operations + /// + public bool Debug { get; private set; } = false; + + /// + /// Set of input paths to use for operations + /// + public List InputPaths { get; private set; } = []; + + /// + /// Output path for archive extraction + /// + public string OutputPath { get; private set; } = string.Empty; + + #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 options and paths + for (int index = 0; index < args.Length; index++) + { + string arg = args[index]; + switch (arg) + { + case "-?": + case "-h": + case "--help": + return null; + + case "-d": + case "--debug": + options.Debug = true; + break; + + case "-o": + case "--outdir": + options.OutputPath = index + 1 < args.Length ? args[++index] : string.Empty; + 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; + } + + // Validate the output path + bool validPath = ValidateExtractionPath(options); + if (!validPath) + return null; + + return options; + } + + /// + /// Display help text + /// + public static void DisplayHelp() + { + Console.WriteLine("Extraction Tool"); + Console.WriteLine(); + Console.WriteLine("ExtractionTool.exe 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("-o, --outdir [PATH] Set output path for extraction (required)"); + } + + /// + /// Validate the extraction path + /// + private static bool ValidateExtractionPath(Options options) + { + // Null or empty output path + if (string.IsNullOrEmpty(options.OutputPath)) + { + Console.WriteLine("Output directory required for extraction!"); + Console.WriteLine(); + return false; + } + + // Malformed output path or invalid location + try + { + options.OutputPath = Path.GetFullPath(options.OutputPath); + Directory.CreateDirectory(options.OutputPath); + } + catch + { + Console.WriteLine("Output directory could not be created!"); + Console.WriteLine(); + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/ExtractionTool/Program.cs b/ExtractionTool/Program.cs new file mode 100644 index 00000000..f6a38820 --- /dev/null +++ b/ExtractionTool/Program.cs @@ -0,0 +1,441 @@ +using System; +using System.IO; +using BinaryObjectScanner.FileType; +using SabreTools.IO.Extensions; +using WrapperFactory = SabreTools.Serialization.Wrappers.WrapperFactory; +using WrapperType = SabreTools.Serialization.Wrappers.WrapperType; + +namespace ExtractionTool +{ + class Program + { + static void Main(string[] args) + { +#if NET462_OR_GREATER || NETCOREAPP + // Register the codepages + System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); +#endif + + // Get the options from the arguments + var options = Options.ParseOptions(args); + + // If we have an invalid state + if (options == null) + { + Options.DisplayHelp(); + return; + } + + // Loop through the input paths + foreach (string inputPath in options.InputPaths) + { + ExtractPath(inputPath, options.OutputPath, options.Debug); + } + } + + /// + /// Wrapper to extract data for a single path + /// + /// File or directory path + /// Output directory path + /// Enable including debug information + private static void ExtractPath(string path, string outputDirectory, bool includeDebug) + { + Console.WriteLine($"Checking possible path: {path}"); + + // Check if the file or directory exists + if (File.Exists(path)) + { + ExtractFile(path, outputDirectory, includeDebug); + } + else if (Directory.Exists(path)) + { + foreach (string file in IOExtensions.SafeEnumerateFiles(path, "*", SearchOption.AllDirectories)) + { + ExtractFile(file, outputDirectory, includeDebug); + } + } + else + { + Console.WriteLine($"{path} does not exist, skipping..."); + } + } + + /// + /// Print information for a single file, if possible + /// + private static void ExtractFile(string file, string outputDirectory, bool includeDebug) + { + Console.WriteLine($"Attempting to extract all files from {file}"); + using Stream stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + + // Get the extension for certain checks + string extension = Path.GetExtension(file).ToLower().TrimStart('.'); + + // Get the first 16 bytes for matching + byte[] magic = new byte[16]; + try + { + stream.Read(magic, 0, 16); + stream.Seek(0, SeekOrigin.Begin); + } + catch (Exception ex) + { + if (includeDebug) Console.WriteLine(ex); + return; + } + + // Get the file type + WrapperType ft = WrapperFactory.GetFileType(magic, extension); + + // Executables technically can be "extracted", but let's ignore that + // TODO: Support executables that include other stuff + + // 7-zip + if (ft == WrapperType.SevenZip) + { + // Build the archive information + Console.WriteLine("Extracting 7-zip contents"); + Console.WriteLine(); + +#if NET20 || NET35 || NET40 || NET452 + Console.WriteLine("Extraction is not supported for this framework!"); + Console.WriteLine(); +#else + // Extract using the FileType + var sevenZip = new SevenZip(); + sevenZip.Extract(stream, file, outputDirectory, includeDebug: true); +#endif + } + + // BFPK archive + else if (ft == WrapperType.BFPK) + { + // Build the BFPK information + Console.WriteLine("Extracting BFPK contents"); + Console.WriteLine(); + + // Extract using the FileType + var bfpk = new BFPK(); + bfpk.Extract(stream, file, outputDirectory, includeDebug: true); + } + + // BSP + else if (ft == WrapperType.BSP) + { + // Build the BSP information + Console.WriteLine("Extracting BSP contents"); + Console.WriteLine(); + + // Extract using the FileType + var bsp = new BSP(); + bsp.Extract(stream, file, outputDirectory, includeDebug: true); + } + + // bzip2 + else if (ft == WrapperType.BZip2) + { + // Build the bzip2 information + Console.WriteLine("Extracting bzip2 contents"); + Console.WriteLine(); + +#if NET20 || NET35 || NET40 || NET452 + Console.WriteLine("Extraction is not supported for this framework!"); + Console.WriteLine(); +#else + // Extract using the FileType + var bzip2 = new BZip2(); + bzip2.Extract(stream, file, outputDirectory, includeDebug: true); +#endif + } + + // CFB + else if (ft == WrapperType.CFB) + { + // Build the installer information + Console.WriteLine("Extracting CFB contents"); + Console.WriteLine(); + +#if NET20 || NET35 + Console.WriteLine("Extraction is not supported for this framework!"); + Console.WriteLine(); +#else + // Extract using the FileType + var cfb = new CFB(); + cfb.Extract(stream, file, outputDirectory, includeDebug: true); +#endif + } + + // GCF + else if (ft == WrapperType.GCF) + { + // Build the GCF information + Console.WriteLine("Extracting GCF contents"); + Console.WriteLine(); + + // Extract using the FileType + var gcf = new GCF(); + gcf.Extract(stream, file, outputDirectory, includeDebug: true); + } + + // gzip + else if (ft == WrapperType.GZIP) + { + // Build the gzip information + Console.WriteLine("Extracting gzip contents"); + Console.WriteLine(); + +#if NET20 || NET35 || NET40 || NET452 + Console.WriteLine("Extraction is not supported for this framework!"); + Console.WriteLine(); +#else + // Extract using the FileType + var gzip = new GZIP(); + gzip.Extract(stream, file, outputDirectory, includeDebug: true); +#endif + } + + // InstallShield Archive V3 (Z) + else if (ft == WrapperType.InstallShieldArchiveV3) + { + // Build the InstallShield Archive V3 information + Console.WriteLine("Extracting InstallShield Archive V3 contents"); + Console.WriteLine(); + + // Extract using the FileType + var isav3 = new InstallShieldArchiveV3(); + isav3.Extract(stream, file, outputDirectory, includeDebug: true); + } + + // IS-CAB archive + else if (ft == WrapperType.InstallShieldCAB) + { + // Build the archive information + Console.WriteLine("Extracting IS-CAB contents"); + Console.WriteLine(); + + // Extract using the FileType + var iscab = new InstallShieldCAB(); + iscab.Extract(stream, file, outputDirectory, includeDebug: true); + } + + // Microsoft Cabinet archive + else if (ft == WrapperType.MicrosoftCAB) + { + // Build the cabinet information + Console.WriteLine("Extracting MS-CAB contents"); + Console.WriteLine(); + +#if NET20 || NET35 || !WIN + Console.WriteLine("Extraction is not supported for this framework!"); + Console.WriteLine(); +#else + // Extract using the FileType + var mscab = new MicrosoftCAB(); + mscab.Extract(stream, file, outputDirectory, includeDebug: true); +#endif + } + + // Microsoft LZ / LZ32 + else if (ft == WrapperType.MicrosoftLZ) + { + // Build the Microsoft LZ / LZ32 information + Console.WriteLine("Extracting Microsoft LZ / LZ32 contents"); + Console.WriteLine(); + + // Extract using the FileType + var lz = new MicrosoftLZ(); + lz.Extract(stream, file, outputDirectory, includeDebug: true); + } + + // MoPaQ (MPQ) archive + else if (ft == WrapperType.MoPaQ) + { + // Build the cabinet information + Console.WriteLine("Extracting MoPaQ contents"); + Console.WriteLine(); + +#if NET20 || NET35 || NET40 || !WIN + Console.WriteLine("Extraction is not supported for this framework!"); + Console.WriteLine(); +#else + // Extract using the FileType + var mpq = new MPQ(); + mpq.Extract(stream, file, outputDirectory, includeDebug: true); +#endif + } + + // PAK + else if (ft == WrapperType.PAK) + { + // Build the archive information + Console.WriteLine("Extracting PAK contents"); + Console.WriteLine(); + + // Extract using the FileType + var pak = new PAK(); + pak.Extract(stream, file, outputDirectory, includeDebug: true); + } + + // PFF + else if (ft == WrapperType.PFF) + { + // Build the archive information + Console.WriteLine("Extracting PFF contents"); + Console.WriteLine(); + + // Extract using the FileType + var pff = new PFF(); + pff.Extract(stream, file, outputDirectory, includeDebug: true); + } + + // PKZIP + else if (ft == WrapperType.PKZIP) + { + // Build the archive information + Console.WriteLine("Extracting PKZIP contents"); + Console.WriteLine(); + +#if NET20 || NET35 || NET40 || NET452 + Console.WriteLine("Extraction is not supported for this framework!"); + Console.WriteLine(); +#else + // Extract using the FileType + var pkzip = new PKZIP(); + pkzip.Extract(stream, file, outputDirectory, includeDebug: true); +#endif + } + + // Quantum + else if (ft == WrapperType.Quantum) + { + // Build the archive information + Console.WriteLine("Extracting Quantum contents"); + Console.WriteLine(); + + // Extract using the FileType + var quantum = new Quantum(); + quantum.Extract(stream, file, outputDirectory, includeDebug: true); + } + + // RAR + else if (ft == WrapperType.RAR) + { + // Build the archive information + Console.WriteLine("Extracting RAR contents"); + Console.WriteLine(); + +#if NET20 || NET35 || NET40 || NET452 + Console.WriteLine("Extraction is not supported for this framework!"); + Console.WriteLine(); +#else + // Extract using the FileType + var rar = new RAR(); + rar.Extract(stream, file, outputDirectory, includeDebug: true); +#endif + } + + // SGA + else if (ft == WrapperType.SGA) + { + // Build the archive information + Console.WriteLine("Extracting SGA contents"); + Console.WriteLine(); + + // Extract using the FileType + var sga = new SGA(); + sga.Extract(stream, file, outputDirectory, includeDebug: true); + } + + // Tape Archive + else if (ft == WrapperType.TapeArchive) + { + // Build the archive information + Console.WriteLine("Extracting Tape Archive contents"); + Console.WriteLine(); + +#if NET20 || NET35 || NET40 || NET452 + Console.WriteLine("Extraction is not supported for this framework!"); + Console.WriteLine(); +#else + // Extract using the FileType + var tar = new TapeArchive(); + tar.Extract(stream, file, outputDirectory, includeDebug: true); +#endif + } + + // VBSP + else if (ft == WrapperType.VBSP) + { + // Build the archive information + Console.WriteLine("Extracting VBSP contents"); + Console.WriteLine(); + + // Extract using the FileType + var vbsp = new VBSP(); + vbsp.Extract(stream, file, outputDirectory, includeDebug: true); + } + + // VPK + else if (ft == WrapperType.VPK) + { + // Build the archive information + Console.WriteLine("Extracting VPK contents"); + Console.WriteLine(); + + // Extract using the FileType + var vpk = new VPK(); + vpk.Extract(stream, file, outputDirectory, includeDebug: true); + } + + // WAD + else if (ft == WrapperType.WAD) + { + // Build the archive information + Console.WriteLine("Extracting WAD contents"); + Console.WriteLine(); + + // Extract using the FileType + var wad = new WAD(); + wad.Extract(stream, file, outputDirectory, includeDebug: true); + } + + // xz + else if (ft == WrapperType.XZ) + { + // Build the xz information + Console.WriteLine("Extracting xz contents"); + Console.WriteLine(); + +#if NET20 || NET35 || NET40 || NET452 + Console.WriteLine("Extraction is not supported for this framework!"); + Console.WriteLine(); +#else + // Extract using the FileType + var xz = new XZ(); + xz.Extract(stream, file, outputDirectory, includeDebug: true); +#endif + } + + // XZP + else if (ft == WrapperType.XZP) + { + // Build the archive information + Console.WriteLine("Extracting XZP contents"); + Console.WriteLine(); + + // Extract using the FileType + var xzp = new XZP(); + xzp.Extract(stream, file, outputDirectory, includeDebug: true); + } + + // Everything else + else + { + Console.WriteLine("Not a supported extractable file format, skipping..."); + Console.WriteLine(); + return; + } + } + } +} diff --git a/publish-nix.sh b/publish-nix.sh index 0c61ce07..804b6199 100644 --- a/publish-nix.sh +++ b/publish-nix.sh @@ -69,6 +69,45 @@ if [ $NO_BUILD = false ]; then # Create Nuget Package dotnet pack BinaryObjectScanner/BinaryObjectScanner.csproj --output $BUILD_FOLDER + # Build ExtractionTool + for FRAMEWORK in "${FRAMEWORKS[@]}"; do + for RUNTIME in "${RUNTIMES[@]}"; do + # Output the current build + echo "===== Build ExtractionTool - $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 building all + if [ $USE_ALL = true ]; then + dotnet publish ExtractionTool/ExtractionTool.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true + fi + dotnet publish ExtractionTool/ExtractionTool.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 building all + if [ $USE_ALL = true ]; then + dotnet publish ExtractionTool/ExtractionTool.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT + fi + dotnet publish ExtractionTool/ExtractionTool.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:DebugType=None -p:DebugSymbols=false + fi + done + done + # Build ProtectionScan for FRAMEWORK in "${FRAMEWORKS[@]}"; do for RUNTIME in "${RUNTIMES[@]}"; do @@ -150,6 +189,50 @@ fi # Only create archives if requested if [ $NO_ARCHIVE = false ]; then + # Create ExtractionTool archives + for FRAMEWORK in "${FRAMEWORKS[@]}"; do + for RUNTIME in "${RUNTIMES[@]}"; do + # Output the current build + echo "===== Archive ExtractionTool - $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 building all + if [ $USE_ALL = true ]; then + cd $BUILD_FOLDER/ExtractionTool/bin/Debug/${FRAMEWORK}/${RUNTIME}/publish/ + if [[ $(echo ${NON_DLL_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then + zip -r $BUILD_FOLDER/ExtractionTool_${FRAMEWORK}_${RUNTIME}_debug.zip . -x 'CascLib.dll' -x 'mspack.dll' -x 'StormLib.dll' + elif [[ $(echo ${NON_DLL_RUNTIMES[@]} | fgrep -w $RUNTIME) ]]; then + zip -r $BUILD_FOLDER/ExtractionTool_${FRAMEWORK}_${RUNTIME}_debug.zip . -x 'CascLib.dll' -x 'mspack.dll' -x 'StormLib.dll' + else + zip -r $BUILD_FOLDER/ExtractionTool_${FRAMEWORK}_${RUNTIME}_debug.zip . + fi + fi + cd $BUILD_FOLDER/ExtractionTool/bin/Release/${FRAMEWORK}/${RUNTIME}/publish/ + if [[ $(echo ${NON_DLL_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then + zip -r $BUILD_FOLDER/ExtractionTool_${FRAMEWORK}_${RUNTIME}_release.zip . -x 'CascLib.dll' -x 'mspack.dll' -x 'StormLib.dll' + elif [[ $(echo ${NON_DLL_RUNTIMES[@]} | fgrep -w $RUNTIME) ]]; then + zip -r $BUILD_FOLDER/ExtractionTool_${FRAMEWORK}_${RUNTIME}_release.zip . -x 'CascLib.dll' -x 'mspack.dll' -x 'StormLib.dll' + else + zip -r $BUILD_FOLDER/ExtractionTool_${FRAMEWORK}_${RUNTIME}_release.zip . + fi + done + done + # Create ProtectionScan archives for FRAMEWORK in "${FRAMEWORKS[@]}"; do for RUNTIME in "${RUNTIMES[@]}"; do diff --git a/publish-win.ps1 b/publish-win.ps1 index a14d7f56..1424b840 100644 --- a/publish-win.ps1 +++ b/publish-win.ps1 @@ -60,6 +60,42 @@ if (!$NO_BUILD.IsPresent) { # Create Nuget Package dotnet pack BinaryObjectScanner\BinaryObjectScanner.csproj --output $BUILD_FOLDER + # Build ExtractionTool + foreach ($FRAMEWORK in $FRAMEWORKS) { + foreach ($RUNTIME in $RUNTIMES) { + # Output the current build + Write-Host "===== Build ExtractionTool - $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 building all + if ($USE_ALL.IsPresent) { + dotnet publish ExtractionTool\ExtractionTool.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true + } + dotnet publish ExtractionTool\ExtractionTool.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 building all + if ($USE_ALL.IsPresent) { + dotnet publish ExtractionTool\ExtractionTool.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT + } + dotnet publish ExtractionTool\ExtractionTool.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:DebugType=None -p:DebugSymbols=false + } + } + } + # Build ProtectionScan foreach ($FRAMEWORK in $FRAMEWORKS) { foreach ($RUNTIME in $RUNTIMES) { @@ -135,6 +171,45 @@ if (!$NO_BUILD.IsPresent) { # Only create archives if requested if (!$NO_ARCHIVE.IsPresent) { + # Create ExtractionTool archives + foreach ($FRAMEWORK in $FRAMEWORKS) { + foreach ($RUNTIME in $RUNTIMES) { + # Output the current build + Write-Host "===== Archive ExtractionTool - $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 building all + if ($USE_ALL.IsPresent) { + Set-Location -Path $BUILD_FOLDER\ExtractionTool\bin\Debug\${FRAMEWORK}\${RUNTIME}\publish\ + if ($NON_DLL_FRAMEWORKS -contains $FRAMEWORK -or $NON_DLL_RUNTIMES -contains $RUNTIME) { + 7z a -tzip -x'!CascLib.dll' -x'!mspack.dll' -x'!StormLib.dll' $BUILD_FOLDER\ExtractionTool_${FRAMEWORK}_${RUNTIME}_debug.zip * + } + else { + 7z a -tzip $BUILD_FOLDER\ExtractionTool_${FRAMEWORK}_${RUNTIME}_debug.zip * + } + } + + Set-Location -Path $BUILD_FOLDER\ExtractionTool\bin\Release\${FRAMEWORK}\${RUNTIME}\publish\ + if ($NON_DLL_FRAMEWORKS -contains $FRAMEWORK -or $NON_DLL_RUNTIMES -contains $RUNTIME) { + 7z a -tzip -x'!CascLib.dll' -x'!mspack.dll' -x'!StormLib.dll' $BUILD_FOLDER\ExtractionTool_${FRAMEWORK}_${RUNTIME}_release.zip * + } + else { + 7z a -tzip $BUILD_FOLDER\ExtractionTool_${FRAMEWORK}_${RUNTIME}_release.zip * + } + } + } + # Create ProtectionScan archives foreach ($FRAMEWORK in $FRAMEWORKS) { foreach ($RUNTIME in $RUNTIMES) {