28 Commits
Author SHA1 Message Date
DeterousandGitHub b1cb4bccd4 Update README.md 2025-08-19 21:28:39 +09:00
DeterousandGitHub 2379e7ef5a Verify command 2025-08-19 21:27:28 +09:00
DeterousandGitHub ce5b610f92 Print All option for info
`-a`/`--all` for irdkit info command
2025-08-19 11:37:11 +09:00
DeterousandGitHub 048d70b473 Bump version 2024-11-16 12:24:15 +09:00
Matt NadareskiandGitHub 0761450a8d Update SabreTools libraries and add .NET 9 support (#1)
* Update SabreTools libraries and add .NET 9 support

* Update build script

* Handle net9.0-specific complaints
2024-11-16 11:45:12 +09:00
Deterous 82d53db68f Bump version 2024-04-11 18:18:45 +09:00
Deterous f8a9c8515d Relax ISO requirements 2024-04-11 18:18:17 +09:00
Deterous 0ef06c36e9 Fix rename functionality, mention in reademe 2024-03-25 13:27:56 +09:00
Deterous c1c25b5f5e Fix issue from moving to ST.Hashing 2024-03-13 12:45:20 +09:00
Deterous c175fedbdb Fix bug for small encrypted regions 2024-03-12 19:42:23 +09:00
Deterous f7879bf9e8 Finalise old dotnet support 2024-03-12 19:08:42 +09:00
Deterous fed9d6ea57 Trim DiscUtils further 2024-03-06 14:14:37 +09:00
Deterous 41946b6bc5 Use trimmed DiscUtils 2024-03-06 12:09:30 +09:00
Deterous d585c4b534 Update ST.Hashing version 2024-03-06 12:09:15 +09:00
Deterous 1886e14a9b Use a trimmed DiscUtils 2024-03-05 23:34:38 +09:00
Deterous e8f4d88711 Use ST.Hashing for SHA1 2024-03-05 15:15:40 +09:00
Deterous 0dbc483a91 Use ST.Hashing for MD5 2024-03-05 15:02:27 +09:00
Deterous b6bb5f0582 Attempt to support net40 with ST.Hashing 2024-03-05 14:52:30 +09:00
Deterous ea3f6d3f96 Support .NET Framework using Newtonsoft 2024-03-05 13:02:25 +09:00
Deterous 4aa6aca25e Support building LibIRD with older .NET Core 2024-03-05 12:33:18 +09:00
Deterous a93c727ba2 Fix spacing 2024-03-05 12:11:34 +09:00
Deterous 55cab8202d Subsume used DiscUtils libraries 2024-03-05 12:01:25 +09:00
Deterous 1fa7380f06 Move DiscUtils to within LibIRD subfolder 2024-03-05 11:01:54 +09:00
DeterousandGitHub a0acd91a55 Update README.md 2024-03-01 12:35:06 +09:00
Deterous 6edb959e49 Bump IRDKit to v0.6.1 2024-02-27 13:24:08 +09:00
Deterous 96b36fcabe Add rename functionality 2024-02-27 12:49:14 +09:00
Deterous 9d03dbb7b1 Perform hashing in one read pass 2024-02-20 16:37:15 +09:00
Deterous c7b49d0c80 Initial work towards one-pass hashing 2024-02-19 21:38:06 +09:00
16 changed files with 1252 additions and 534 deletions
+73
View File
@@ -0,0 +1,73 @@
name: Build
on:
push: {}
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
project: [IRDKit]
runtime: [win-x86, win-x64, win-arm64, linux-x64, linux-arm64, osx-x64, osx-arm64]
framework: [net8.0]
steps:
- uses: actions/checkout@v4
with:
submodules: 'true'
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Build
run: dotnet publish ${{ matrix.project }}/${{ matrix.project }}.csproj -f ${{ matrix.framework }} -r ${{ matrix.runtime }} -c Release -p:DebugType=None -p:DebugSymbols=false
- name: Upload build
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}
path: ${{ matrix.project }}/bin/Release/${{ matrix.framework }}/${{ matrix.runtime }}/publish/*
pack:
runs-on: windows-latest
strategy:
matrix:
project: [LibIRD]
steps:
- uses: actions/checkout@v4
with:
submodules: 'true'
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v2
- name: Setup NuGet
uses: NuGet/setup-nuget@v1
with:
nuget-version: 'latest'
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Restore NuGet packages
run: nuget restore LibIRD/LibIRD.csproj
- name: Build
run: msbuild ${{ matrix.project }}/${{ matrix.project }}.csproj /p:Configuration=Release
- name: Pack
run: dotnet pack ${{ matrix.project }}/${{ matrix.project }}.csproj -c Release -o ./artifacts
- name: Upload nupkg
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.project }}
path: ./artifacts/*.nupkg
+1 -1
View File
@@ -1,3 +1,3 @@
[submodule "DiscUtils"]
path = DiscUtils
path = LibIRD/DiscUtils
url = https://github.com/Deterous/DiscUtils
+24
View File
@@ -0,0 +1,24 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "shell",
"args": [
"build",
// Ask dotnet build to generate full paths for file names.
"/property:GenerateFullPaths=true",
// Do not generate summary otherwise it leads to duplicate errors in Problems panel
"/consoleloggerparameters:NoSummary"
],
"group": "build",
"presentation": {
"reveal": "silent"
},
"problemMatcher": "$msCompile"
}
]
}
Submodule DiscUtils deleted from 299030c20b
+16 -9
View File
@@ -1,20 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Assembly Properties -->
<OutputType>Exe</OutputType>
<TargetName>irdkit</TargetName>
<AssemblyName>irdkit</AssemblyName>
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<LangVersion>latest</LangVersion>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>0.5.0</Version>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<PublishSingleFile>true</PublishSingleFile>
<SelfContained>false</SelfContained>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>0.9.5</Version>
<!-- Package Properties -->
<Authors>Deterous</Authors>
<Description>Library for ISO Rebuild Data</Description>
<Copyright>Copyright (c) Deterous 2023-2024</Copyright>
<Copyright>Copyright (c) Deterous 2023-2025</Copyright>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/Deterous/LibIRD</RepositoryUrl>
<RepositoryType>git</RepositoryType>
@@ -27,11 +32,13 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LibIRD\LibIRD.csproj" PrivateAssets="All" />
<ProjectReference Include="..\DiscUtils\Library\DiscUtils.Core\DiscUtils.Core.csproj" PrivateAssets="All" />
<ProjectReference Include="..\DiscUtils\Library\DiscUtils.Iso9660\DiscUtils.Iso9660.csproj" PrivateAssets="All" />
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.3.3" />
<PackageReference Include="SabreTools.Hashing" Version="1.5.0" />
<PackageReference Include="SabreTools.RedumpLib" Version="1.7.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LibIRD\LibIRD.csproj" />
</ItemGroup>
</Project>
+325 -91
View File
@@ -1,16 +1,14 @@
using CommandLine;
using DiscUtils;
using DiscUtils.Iso9660;
using LibIRD;
using SabreTools.RedumpLib.Web;
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.IO.Hashing;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Xml.Linq;
using CommandLine;
using LibIRD;
using SabreTools.Hashing;
using SabreTools.RedumpLib.Web;
namespace IRDKit
{
@@ -24,7 +22,7 @@ namespace IRDKit
[Verb("create", HelpText = "Create an IRD from an ISO")]
public class CreateOptions
{
[Value(0, Required = true, HelpText = "Path to an ISO file, or directory of ISO files")]
[Value(0, Required = true, HelpText = "Path to ISO file(s), or directory of ISO files")]
public IEnumerable<string> ISOPath { get; set; }
[Option('o', "output", HelpText = "Path to the IRD file to be created (will overwrite)")]
@@ -55,12 +53,15 @@ namespace IRDKit
[Verb("info", HelpText = "Print information from an IRD or ISO")]
public class InfoOptions
{
[Value(0, Required = true, HelpText = "Path to an IRD or ISO file, or directory of IRD and/or ISO files")]
[Value(0, Required = true, HelpText = "Path to IRD/ISO file(s), or directory of IRD/ISO files")]
public IEnumerable<string> InPath { get; set; }
[Option('o', "output", HelpText = "Path to the text or json file to be created (will overwrite)")]
public string OutPath { get; set; }
[Option('a', "all", HelpText = "Print the entire contents of the IRD")]
public bool All { get; set; }
[Option('j', "json", HelpText = "Print IRD or ISO information as a JSON object")]
public bool Json { get; set; }
@@ -84,6 +85,47 @@ namespace IRDKit
public string OutPath { get; set; }
}
/// <summary>
/// IRD rename command
/// </summary>
[Verb("rename", HelpText = "Rename one or more IRD files according to the redump PS3 DAT")]
public class RenameOptions
{
[Value(0, Required = true, HelpText = "Path to IRD file(s), or directory of IRD files")]
public IEnumerable<string> IRDPath { get; set; }
[Option('d', "datfile", Required = true, HelpText = "Path to the redump PS3 Datfile")]
public string DATPath { get; set; }
[Option('s', "serial", HelpText = "Appends disc serial to new IRD filename")]
public bool Serial { get; set; }
[Option('e', "version", HelpText = "Appends disc version to new IRD filename")]
public bool Ver { get; set; }
[Option('c', "crc", HelpText = "Appends ISO CRC to new IRD filename")]
public bool CRC { get; set; }
[Option('r', "recurse", HelpText = "Recurse through all subdirectories and rename all IRDs")]
public bool Recurse { get; set; }
[Option('v', "verbose", HelpText = "Print more information about the renaming")]
public bool Verbose { get; set; }
}
/// <summary>
/// IRD verify command
/// </summary>
[Verb("verify", HelpText = "Verify a folder using an IRD")]
public class VerifyOptions
{
[Value(0, Required = true, HelpText = "Path to IRD file to use for validation")]
public string IRDPath { get; set; }
[Value(1, Required = true, HelpText = "Folder path to validate")]
public string FolderPath { get; set; }
}
#endregion
#region Program
@@ -98,7 +140,7 @@ namespace IRDKit
Console.OutputEncoding = Encoding.UTF8;
// Parse arguments
var result = Parser.Default.ParseArguments<CreateOptions, InfoOptions, DiffOptions>(args).WithParsed(Run);
var result = Parser.Default.ParseArguments<CreateOptions, InfoOptions, DiffOptions, RenameOptions, VerifyOptions>(args).WithParsed(Run);
}
/// <summary>
@@ -173,7 +215,7 @@ namespace IRDKit
if (!File.Exists(isoPath))
{
Console.Error.WriteLine($"ISO not found: {isoPath}");
return;
continue;
}
string irdPath;
@@ -257,7 +299,7 @@ namespace IRDKit
string lastIRD = irdFiles.Last();
foreach (string file in irdFiles)
{
PrintInfo(file, opt.Json, (noISO && file.Equals(lastIRD)), opt.OutPath);
PrintInfo(file, opt.Json, (noISO && file.Equals(lastIRD)), opt.OutPath, opt.All);
}
@@ -269,7 +311,7 @@ namespace IRDKit
{
PrintISO(file, opt.Json, file.Equals(lastISO), opt.OutPath);
}
catch (InvalidFileSystemException)
catch (IOException)
{
// Not a valid ISO file despite extension, assume file is an IRD
if (!opt.Json)
@@ -299,7 +341,7 @@ namespace IRDKit
}
// Print info from given file
PrintInfo(filePath, opt.Json, true, opt.OutPath);
PrintInfo(filePath, opt.Json, true, opt.OutPath, opt.All);
if (opt.OutPath != null && opt.OutPath != "")
Console.WriteLine($"Info saved to {opt.OutPath}");
@@ -330,6 +372,153 @@ namespace IRDKit
break;
// Process options from a 'rename' command
case RenameOptions opt:
// Validate required parameters
if (opt.IRDPath == null || !opt.IRDPath.Any())
{
Console.Error.WriteLine("Provide a valid IRD path to rename");
return;
}
// Read DAT file
XDocument datfile = DatParser(opt.DATPath);
if (datfile == null)
{
Console.Error.WriteLine("Unable to parse DAT file");
return;
}
foreach (string irdPath in opt.IRDPath)
{
// Validate IRD path
if (string.IsNullOrEmpty(irdPath))
continue;
// If directory, search for all ISOs in current directory
if (Directory.Exists(irdPath))
{
// If recurse option enabled, search recursively
IEnumerable<string> irdFiles;
if (opt.Recurse)
{
if (opt.Verbose && irdPath == ".")
Console.WriteLine($"Recursively renaming IRDs in current directory");
else if (opt.Verbose)
Console.WriteLine($"Recursively renaming IRDs in {irdPath}");
irdFiles = Directory.EnumerateFiles(irdPath, "*.ird", SearchOption.AllDirectories);
}
else
{
if (opt.Verbose && irdPath == ".")
Console.WriteLine($"Renaming IRDs in current directory");
else if (opt.Verbose)
Console.WriteLine($"Renaming IRDs in {irdPath}");
irdFiles = Directory.EnumerateFiles(irdPath, "*.ird", SearchOption.TopDirectoryOnly);
}
// Warn if no files are found
if (!irdFiles.Any())
{
if (opt.Recurse)
Console.Error.WriteLine($"No IRDs found in {irdPath} (ensure .ird extension)");
else
Console.Error.WriteLine($"No IRDs found in {irdPath} (ensure .ird extension, or try use -r)");
continue;
}
// Rename all IRD files found
foreach (string file in irdFiles.OrderBy(x => x))
{
try
{
RenameIRD(file, datfile, serial: opt.Serial, ver: opt.Ver, crc: opt.CRC, verbose: opt.Verbose);
}
catch (Exception e)
{
Console.Error.WriteLine(e);
}
}
}
else
{
// Check that given file exists
if (!File.Exists(irdPath))
{
Console.Error.WriteLine($"IRD not found: {irdPath}");
continue;
}
// Rename provided IRD path
try
{
RenameIRD(irdPath, datfile, serial: opt.Serial, ver: opt.Ver, crc: opt.CRC, verbose: opt.Verbose);
}
catch (Exception e)
{
Console.Error.WriteLine(e);
}
}
}
break;
// Process options from a 'rename' command
case VerifyOptions opt:
string verifyIRDPath = opt.IRDPath;
string verifyFolderPath = opt.FolderPath;
// Validate required parameters
if (string.IsNullOrEmpty(verifyIRDPath))
{
Console.Error.WriteLine("Provide a IRD path to verify with");
return;
}
if (string.IsNullOrEmpty(verifyFolderPath))
{
Console.Error.WriteLine("Provide a folder path to verify");
return;
}
bool switched = false;
if (!File.Exists(verifyIRDPath))
{
// Check if arguments are switched
if (File.Exists(verifyFolderPath))
{
switched = true;
string temp = verifyIRDPath;
verifyIRDPath = verifyFolderPath;
verifyFolderPath = temp;
}
else
{
Console.Error.WriteLine("Provide a valid IRD file to verify with");
return;
}
}
if (!Directory.Exists(verifyFolderPath))
{
if (switched)
{
Console.Error.WriteLine("Provide a valid IRD file to verify with");
return;
}
else
{
Console.Error.WriteLine("Provide a valid folder path to verify");
return;
}
}
VerifyIRD(verifyIRDPath, verifyFolderPath);
break;
// Unknown command
default:
break;
@@ -345,8 +534,9 @@ namespace IRDKit
/// </summary>
/// <param name="inPath">File to retrieve info from</param>
/// <param name="json">Whether to format output as JSON (true) or plain text (false)</param>
/// <param name="single">Whether to print a single JSON object or not</param>
/// <param name="outPath">File to output info to</param>
public static void PrintInfo(string inPath, bool json, bool single = true, string outPath = null)
public static void PrintInfo(string inPath, bool json, bool single = true, string outPath = null, bool printAll = false)
{
// Check if file is an ISO
bool isISO = String.Compare(Path.GetExtension(inPath), ".iso", StringComparison.OrdinalIgnoreCase) == 0;
@@ -357,7 +547,7 @@ namespace IRDKit
PrintISO(inPath, json, single, outPath);
return;
}
catch (InvalidFileSystemException)
catch (IOException)
{
// Not a valid ISO file despite extension, try open as IRD
}
@@ -373,10 +563,10 @@ namespace IRDKit
File.AppendAllText(outPath, $"\"{Path.GetFileName(inPath)}\": ");
else
Console.Write($"\"{Path.GetFileName(inPath)}\": ");
ird.PrintJson(outPath, single);
ird.PrintJson(outPath, single, printAll);
}
else
IRD.Read(inPath).Print(outPath, Path.GetFileName(inPath));
IRD.Read(inPath).Print(outPath, Path.GetFileName(inPath), printAll);
if (json)
return;
@@ -399,6 +589,7 @@ namespace IRDKit
/// </summary>
/// <param name="isoPath">Path to ISO file</param>
/// <param name="json">Whether to format output as JSON (true) or plain text (false)</param>
/// <param name="single">Whether to print a single JSON object or not</param>
/// <param name="outPath">File to output info to</param>
/// <exception cref="FileNotFoundException"></exception>
/// <exception cref="InvalidFileSystemException"></exception>
@@ -407,18 +598,18 @@ namespace IRDKit
// Open ISO file for reading
using FileStream fs = new(isoPath, FileMode.Open, FileAccess.Read);
// Validate ISO file stream
if (fs == null || !CDReader.Detect(fs))
if (fs == null || !LibIRD.DiscUtils.Iso9660.CDReader.Detect(fs))
{
Console.Error.WriteLine($"{isoPath} is not a valid ISO file");
return;
}
// Create new ISO reader
using CDReader reader = new(fs, true, true);
using LibIRD.DiscUtils.Iso9660.CDReader reader = new(fs);
// Write PS3_DISC.SFB info
try
{
using DiscUtils.Streams.SparseStream s = reader.OpenFile("\\PS3_DISC.SFB", FileMode.Open, FileAccess.Read);
using LibIRD.DiscUtils.Streams.SparseStream s = reader.OpenFile("\\PS3_DISC.SFB", FileMode.Open, FileAccess.Read);
PS3_DiscSFB ps3_DiscSFB = new(s);
if (json)
{
@@ -455,7 +646,7 @@ namespace IRDKit
// Write PARAM.SFO info
try
{
using DiscUtils.Streams.SparseStream s = reader.OpenFile("\\PS3_GAME\\PARAM.SFO", FileMode.Open, FileAccess.Read);
using LibIRD.DiscUtils.Streams.SparseStream s = reader.OpenFile("\\PS3_GAME\\PARAM.SFO", FileMode.Open, FileAccess.Read);
ParamSFO paramSFO = new(s);
if (json)
{
@@ -587,7 +778,7 @@ namespace IRDKit
for (int i = 0; i < regionCount; i++)
{
if (!IRD1.RegionHashes[i].SequenceEqual(IRD2.RegionHashes[i]))
printText.AppendLine($"Region {i} Hash: {Convert.ToHexString(IRD1.RegionHashes[i])} vs {Convert.ToHexString(IRD2.RegionHashes[i])}");
printText.AppendLine($"Region {i} Hash: {LibIRD.IRD.ByteArrayToHexString(IRD1.RegionHashes[i])} vs {LibIRD.IRD.ByteArrayToHexString(IRD2.RegionHashes[i])}");
}
// Print the difference in number of files, if not 0
@@ -603,7 +794,7 @@ namespace IRDKit
if (j == -1)
missingOffsets2.Add(IRD1.FileKeys[i]);
if (j != -1 && !IRD1.FileHashes[i].SequenceEqual(IRD2.FileHashes[j]))
printText.AppendLine($"File Hash at Offset {IRD1.FileKeys[i]}: {Convert.ToHexString(IRD1.FileHashes[i])} vs {Convert.ToHexString(IRD2.FileHashes[j])}");
printText.AppendLine($"File Hash at Offset {IRD1.FileKeys[i]}: {LibIRD.IRD.ByteArrayToHexString(IRD1.FileHashes[i])} vs {LibIRD.IRD.ByteArrayToHexString(IRD2.FileHashes[j])}");
}
for (int i = 0; i < IRD2.FileKeys.Length; i++)
{
@@ -615,7 +806,7 @@ namespace IRDKit
if (missingOffsets1.Count > 0)
printText.AppendLine($"File Offsets not Present in {irdPath1}: {string.Join(", ", missingOffsets1)}");
if (missingOffsets2.Count > 0)
printText.AppendLine($"File Offsets not Present in {irdPath2}: {string.Join(", ", missingOffsets2)}");
printText.AppendLine($"File Offsets not Present in {irdPath2}: {string.Join(", ", missingOffsets2)}");
// Print any extra config data difference
if (IRD1.ExtraConfig != IRD2.ExtraConfig)
@@ -631,15 +822,15 @@ namespace IRDKit
// Print any data 1 key difference
if (!IRD1.Data1Key.SequenceEqual(IRD2.Data1Key))
printText.AppendLine($"Data 1 Key: {Convert.ToHexString(IRD1.Data1Key)} vs {Convert.ToHexString(IRD2.Data1Key)}");
printText.AppendLine($"Data 1 Key: {LibIRD.IRD.ByteArrayToHexString(IRD1.Data1Key)} vs {LibIRD.IRD.ByteArrayToHexString(IRD2.Data1Key)}");
// Print any data 2 key difference
if (!IRD1.Data2Key.SequenceEqual(IRD2.Data2Key))
printText.AppendLine($"Data 2 Key: {Convert.ToHexString(IRD1.Data2Key)} vs {Convert.ToHexString(IRD2.Data2Key)}");
printText.AppendLine($"Data 2 Key: {LibIRD.IRD.ByteArrayToHexString(IRD1.Data2Key)} vs {LibIRD.IRD.ByteArrayToHexString(IRD2.Data2Key)}");
// Print any PIC difference
if (!IRD1.PIC.SequenceEqual(IRD2.PIC))
printText.AppendLine($"PIC: {Convert.ToHexString(IRD1.PIC)} vs {Convert.ToHexString(IRD2.PIC)}");
printText.AppendLine($"PIC: {LibIRD.IRD.ByteArrayToHexString(IRD1.PIC)} vs {LibIRD.IRD.ByteArrayToHexString(IRD2.PIC)}");
// Write formatted string to file if output path provided, otherwise to console
if (outPath != null)
@@ -648,6 +839,32 @@ namespace IRDKit
Console.WriteLine(printText.ToString());
}
/// <summary>
/// Verify a folder matches against an IRD
/// </summary>
/// <param name="irdPath">IRD path to verify with</param>
/// <param name="folderPath">Folder containing files to verify against</param>
public static void VerifyIRD(string irdPath, string folderPath)
{
// Get file paths and their hashes to verify with
var fileHashes = IRD.Read(irdPath).GetFileHashes();
// Check that all files and their hashes exist in the folder path
foreach (var kvp in fileHashes)
{
string filePath = Path.Combine(folderPath, kvp.Key);
if (!File.Exists(filePath))
{
Console.WriteLine($"{filePath} doesn't exist");
continue;
}
var hash = HashTool.GetFileHashArray(filePath, HashType.MD5);
if (!hash.SequenceEqual(kvp.Value))
Console.WriteLine($"{filePath}: {IRD.ByteArrayToHexString(hash)}");
}
Console.WriteLine("Verification complete!");
}
/// <summary>
/// Creates an IRD file from an ISO file
/// </summary>
@@ -691,7 +908,7 @@ namespace IRDKit
try
{
// Get disc key from hex string
byte[] discKey = Convert.FromHexString(hexKey);
byte[] discKey = LibIRD.IRD.HexStringToByteArray(hexKey);
if (discKey == null || discKey.Length != 16)
Console.Error.WriteLine($"{hexKey} is not a valid key, detecting key automatically...");
else
@@ -704,16 +921,11 @@ namespace IRDKit
return irdPath;
}
}
catch (ArgumentException e)
catch (Exception e)
{
Console.Error.WriteLine(e.Message + ", failed to create IRD");
return null;
}
catch (FileNotFoundException)
{
Console.Error.WriteLine("File not found, failed to create IRD");
return null;
}
}
// Create new reproducible redump-style IRD with a given key file
@@ -732,7 +944,7 @@ namespace IRDKit
Console.Error.WriteLine($"{hexKey} is not a valid key, detecting key automatically...");
else
{
Console.WriteLine($"Creating {irdPath} with Key: {Convert.ToHexString(discKey)}");
Console.WriteLine($"Creating {irdPath} with Key: {LibIRD.IRD.ByteArrayToHexString(discKey)}");
IRD ird1 = new ReIRD(isoPath, discKey, layerbreak);
ird1.Write(irdPath);
if (verbose)
@@ -740,16 +952,11 @@ namespace IRDKit
return irdPath;
}
}
catch (ArgumentException e)
catch (Exception e)
{
Console.Error.WriteLine(e.Message + ", failed to create IRD");
return null;
}
catch (FileNotFoundException)
{
Console.Error.WriteLine("File not found, failed to create IRD");
return null;
}
}
// Create new reproducible redump-style IRD with a given GetKey log
@@ -764,16 +971,11 @@ namespace IRDKit
ird1.Print();
return irdPath;
}
catch (ArgumentException e)
catch (Exception e)
{
Console.Error.WriteLine(e.Message + ", failed to create IRD");
return null;
}
catch (FileNotFoundException)
{
Console.Error.WriteLine("File not found, failed to create IRD");
return null;
}
}
// No key provided, try search for .key file
@@ -790,7 +992,7 @@ namespace IRDKit
Console.Error.WriteLine($"{hexKey} is not a valid key, detecting key automatically...");
else
{
Console.WriteLine($"Creating {irdPath} with Key: {Convert.ToHexString(discKey)}");
Console.WriteLine($"Creating {irdPath} with Key: {LibIRD.IRD.ByteArrayToHexString(discKey)}");
IRD ird1 = new ReIRD(isoPath, discKey, layerbreak);
ird1.Write(irdPath);
if (verbose)
@@ -798,16 +1000,11 @@ namespace IRDKit
return irdPath;
}
}
catch (ArgumentException e)
catch (Exception e)
{
Console.Error.WriteLine(e.Message + ", failed to create IRD");
return null;
}
catch (FileNotFoundException)
{
Console.Error.WriteLine("File not found, failed to create IRD");
return null;
}
}
// No key provided, try search for .getkey.log file
@@ -825,16 +1022,11 @@ namespace IRDKit
ird1.Print();
return irdPath;
}
catch (ArgumentException e)
catch (Exception e)
{
Console.Error.WriteLine(e.Message + ", failed to create IRD");
return null;
}
catch (FileNotFoundException)
{
Console.Error.WriteLine("File not found, failed to create IRD");
return null;
}
}
// No key provided, try get key from redump.org
@@ -842,22 +1034,16 @@ namespace IRDKit
Console.WriteLine("No key provided... Searching for key on redump.org");
// Compute CRC32 hash
byte[] crc32;
uint crc32UInt;
using (FileStream fs = File.OpenRead(isoPath))
{
Crc32 hasher = new();
hasher.Append(fs);
crc32 = hasher.GetCurrentHash();
crc32UInt = BitConverter.ToUInt32(crc32);
// Change endianness
Array.Reverse(crc32);
}
string crc32_hash = Convert.ToHexString(crc32).ToLower();
byte[] crc32 = HashTool.GetFileHashArray(isoPath, HashType.CRC32);
string crc32String = LibIRD.IRD.ByteArrayToHexString(crc32).ToLowerInvariant();
// Convert to UInt for use as UID in IRD
Array.Reverse(crc32);
uint crc32UInt = BitConverter.ToUInt32(crc32, 0);
// Search for ISO on redump.org
RedumpHttpClient redump = new();
List<int> ids = redump.CheckSingleSitePage("http://redump.org/discs/system/ps3/quicksearch/" + crc32_hash).ConfigureAwait(false).GetAwaiter().GetResult();
RedumpClient redump = new();
List<int> ids = redump.CheckSingleSitePage("http://redump.org/discs/system/ps3/quicksearch/" + crc32String).ConfigureAwait(false).GetAwaiter().GetResult();
int id;
if (ids.Count == 0)
{
@@ -867,16 +1053,10 @@ namespace IRDKit
else if (ids.Count > 1)
{
// More than one result for the CRC32 hash, compute SHA1 hash instead
byte[] sha1;
using (FileStream fs = File.OpenRead(isoPath))
{
SHA1 hasher = SHA1.Create();
sha1 = hasher.ComputeHash(fs);
}
string sha1_hash = Convert.ToHexString(sha1).ToLower();
string sha1String = HashTool.GetFileHash(isoPath, HashType.SHA1);
// Search redump.org for SHA1 hash
List<int> ids2 = redump.CheckSingleSitePage("http://redump.org/discs/system/ps3/quicksearch/" + sha1_hash).ConfigureAwait(false).GetAwaiter().GetResult();
List<int> ids2 = redump.CheckSingleSitePage("http://redump.org/discs/system/ps3/quicksearch/" + sha1String).ConfigureAwait(false).GetAwaiter().GetResult();
if (ids2.Count == 0)
{
Console.Error.WriteLine("ISO not found in redump and no valid key provided, cannot create IRD");
@@ -896,15 +1076,15 @@ namespace IRDKit
}
// Download key file from redump.org
byte[] key = redump.GetByteArrayAsync($"http://redump.org/disc/{id}/key").ConfigureAwait(false).GetAwaiter().GetResult();
if (key.Length != 16)
byte[] key = redump.DownloadData($"http://redump.org/disc/{id}/key").ConfigureAwait(false).GetAwaiter().GetResult();
if (key == null || key.Length != 16)
{
Console.Error.WriteLine("Invalid key obtained from redump and no valid key provided, cannot create IRD");
return null;
}
// Create IRD with key from redump
Console.WriteLine($"Creating {irdPath} with Key from redump.org: {Convert.ToHexString(key)}");
Console.WriteLine($"Creating {irdPath} with Key from redump.org: {LibIRD.IRD.ByteArrayToHexString(key)}");
try
{
IRD ird = new ReIRD(isoPath, key, layerbreak, crc32UInt);
@@ -913,19 +1093,73 @@ namespace IRDKit
ird.Print();
return irdPath;
}
catch (ArgumentException e)
catch (Exception e)
{
Console.Error.WriteLine(e.Message + ", failed to create IRD");
return null;
}
catch (FileNotFoundException)
}
public static XDocument DatParser(string datpath = null)
{
try
{
if (!File.Exists(datpath))
return null;
return XDocument.Load(datpath);
}
catch
{
Console.Error.WriteLine("File not found, failed to create IRD");
return null;
}
}
#endregion
public static string GetDatFilename(IRD ird, XDocument datfile)
{
string crc32 = ird.UID.ToString("X8").ToLower();
XElement node = datfile.Root.Elements("game").Where(e => e.Element("rom").Attribute("crc").Value == crc32).FirstOrDefault() ?? throw new ArgumentException("Cannot find ISO in redump DAT");
return node.Attribute("name").Value;
}
public static void RenameIRD(string irdPath, XDocument datfile, bool serial = false, bool ver = false, bool crc = false, bool verbose = false)
{
IRD ird = IRD.Read(irdPath);
if (ird.ExtraConfig != 0x0001)
throw new ArgumentException($"{irdPath} is not a redump-style IRD");
string filename = GetDatFilename(ird, datfile) ?? throw new ArgumentException($"Cannot determine DAT filename for {irdPath}");
if (serial)
filename += $" [{ird.TitleID.Substring(0, 4).Replace('\0', ' ')}-{ird.TitleID.Substring(4, 5).Replace('\0', ' ')}]";
if (ver)
filename += $" [{ird.DiscVersion.Replace('\0', ' ')}]";
if (crc)
filename += $" [{ird.UID:X8}]";
// Rename irdPath to filename
string directory = Path.GetDirectoryName(Path.GetFullPath(filename));
string filepath;
if (!string.IsNullOrEmpty(directory))
filepath = Path.Combine(Path.GetDirectoryName(irdPath), filename + ".ird");
else
filepath = filename + ".ird";
// Rename IRD to new name
if (irdPath != filepath)
{
if (verbose)
Console.WriteLine($"Renaming {Path.GetFileName(irdPath)} to {Path.GetFileName(filepath)}");
File.Move(irdPath, filepath);
}
else
{
if (verbose)
Console.WriteLine($"Skipping {Path.GetFileName(irdPath)}, already named correctly");
}
}
#endregion
#region Helper Functions
+7
View File
@@ -32,6 +32,7 @@ For all options, run `irdkit help info`
To print info about an ISO or IRD file, run `irdkit info game.iso` or `irdkit info game.ird`
The info can be printed to a file, e.g. `-o out.txt` or `--output=`
The info can be formatted as a JSON with `-j` or `--json`
To print all info in the IRD use `-a` or `--all`
## Comparing IRDs
@@ -39,3 +40,9 @@ For all options, run `irdkit help diff`
To compare two IRDs, run `irdkit diff game1.ird game2.ird`
The comparison can be printed to a file, e.g. `-o out.txt` or `--output=`
## Renaming IRDs
For all options, run `irdkit help rename`
To rename an IRD (or folder of IRDs) according to a redump DAT, run `irdkit rename -d redump.dat game.ird`
+2 -18
View File
@@ -11,16 +11,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
.gitattributes = .gitattributes
.gitignore = .gitignore
.gitmodules = .gitmodules
LICENSE.txt = LICENSE.txt
publish-irdkit.ps1 = publish-irdkit.ps1
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiscUtils.Core", "DiscUtils\Library\DiscUtils.Core\DiscUtils.Core.csproj", "{9E71F5CD-887D-4A61-8460-9F7E8F110B46}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiscUtils.Iso9660", "DiscUtils\Library\DiscUtils.Iso9660\DiscUtils.Iso9660.csproj", "{9E1EF05F-388B-42C6-A4E7-98BE20C7C8EC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiscUtils.Streams", "DiscUtils\Library\DiscUtils.Streams\DiscUtils.Streams.csproj", "{E8D0B8B0-F165-4FA1-AC7B-194F5F48A5F9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -35,18 +31,6 @@ Global
{9060E3AF-E4FB-436F-93A1-5C47389CB88E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9060E3AF-E4FB-436F-93A1-5C47389CB88E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9060E3AF-E4FB-436F-93A1-5C47389CB88E}.Release|Any CPU.Build.0 = Release|Any CPU
{9E71F5CD-887D-4A61-8460-9F7E8F110B46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9E71F5CD-887D-4A61-8460-9F7E8F110B46}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9E71F5CD-887D-4A61-8460-9F7E8F110B46}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9E71F5CD-887D-4A61-8460-9F7E8F110B46}.Release|Any CPU.Build.0 = Release|Any CPU
{9E1EF05F-388B-42C6-A4E7-98BE20C7C8EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9E1EF05F-388B-42C6-A4E7-98BE20C7C8EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9E1EF05F-388B-42C6-A4E7-98BE20C7C8EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9E1EF05F-388B-42C6-A4E7-98BE20C7C8EC}.Release|Any CPU.Build.0 = Release|Any CPU
{E8D0B8B0-F165-4FA1-AC7B-194F5F48A5F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E8D0B8B0-F165-4FA1-AC7B-194F5F48A5F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E8D0B8B0-F165-4FA1-AC7B-194F5F48A5F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E8D0B8B0-F165-4FA1-AC7B-194F5F48A5F9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+1
Submodule LibIRD/DiscUtils added at 445a572137
+756 -318
View File
File diff suppressed because it is too large Load Diff
+19 -21
View File
@@ -1,18 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Assembly Properties -->
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<LangVersion>latest</LangVersion>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>0.5.0</Version>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>0.9.5</Version>
<PackageOutputPath>../nupkg</PackageOutputPath>
<!-- Avoid inexact read with 'System.IO.Stream.Read' -->
<NoWarn>CA2022</NoWarn>
<!-- Package Properties -->
<Authors>Deterous</Authors>
<Description>Library for ISO Rebuild Data</Description>
<Copyright>Copyright (c) Deterous 2023-2024</Copyright>
<Copyright>Copyright (c) Deterous 2023-2025</Copyright>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/Deterous/LibIRD/</RepositoryUrl>
<RepositoryType>git</RepositoryType>
@@ -24,21 +28,15 @@
<ItemGroup>
<None Include="./README.md" Pack="true" PackagePath="" />
</ItemGroup>
<!-- Support for old .NET versions -->
<ItemGroup Condition="$(TargetFramework.StartsWith(`net2`))">
<PackageReference Include="Net30.LinqBridge" Version="1.3.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DiscUtils\Library\DiscUtils.Core\DiscUtils.Core.csproj" PrivateAssets="All" />
<ProjectReference Include="..\DiscUtils\Library\DiscUtils.Iso9660\DiscUtils.Iso9660.csproj" PrivateAssets="All" />
<ProjectReference Include="..\DiscUtils\Library\DiscUtils.Streams\DiscUtils.Streams.csproj" PrivateAssets="All" />
<PackageReference Include="System.IO.Hashing" Version="8.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SabreTools.Hashing" Version="1.5.0" />
</ItemGroup>
<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="BuildOnlySettings;ResolveReferences">
<ItemGroup>
<BuildOutputInPackage Include="@(ReferenceCopyLocalPaths-&gt;WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')-&gt;WithMetadataValue('PrivateAssets', 'All'))" />
</ItemGroup>
</Target>
</Project>
+3 -8
View File
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.Json;
using Newtonsoft.Json;
namespace LibIRD
{
@@ -68,7 +68,7 @@ namespace LibIRD
// Read SFB file version
byte[] buf = br.ReadBytes(2);
Array.Reverse(buf);
Version = BitConverter.ToUInt16(buf);
Version = BitConverter.ToUInt16(buf, 0);
// Process all field headers
sfbStream.Seek(0x20, SeekOrigin.Begin);
@@ -131,11 +131,6 @@ namespace LibIRD
}
}
/// <summary>
/// Define JSON options once
/// </summary>
private readonly JsonSerializerOptions JsonOpts = new() { WriteIndented = true };
/// <summary>
/// Prints parameters extracted from PS3_DISC.SFB to a json object
/// </summary>
@@ -143,7 +138,7 @@ namespace LibIRD
public void PrintJson(string jsonPath = null)
{
// Serialise PS3_Disc.SFB data to a JSON object
string json = JsonSerializer.Serialize(Field, JsonOpts);
string json = JsonConvert.SerializeObject(Field, Formatting.Indented);
// If no path given, output to console
if (jsonPath == null)
+2 -7
View File
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.Json;
using Newtonsoft.Json;
namespace LibIRD
{
@@ -154,11 +154,6 @@ namespace LibIRD
}
}
/// <summary>
/// Define JSON options once
/// </summary>
private readonly JsonSerializerOptions JsonOpts = new() { WriteIndented = true };
/// <summary>
/// Prints parameters extracted from PARAM.SFO to a json object
/// </summary>
@@ -166,7 +161,7 @@ namespace LibIRD
public void PrintJson(string jsonPath = null)
{
// Serialise PS3_Disc.SFB data to a JSON object
string json = JsonSerializer.Serialize(Field, JsonOpts);
string json = JsonConvert.SerializeObject(Field, Formatting.Indented);
// If no path given, output to console
if (jsonPath == null)
+7 -46
View File
@@ -1,7 +1,5 @@
using DiscUtils.Iso9660;
using System;
using System;
using System.IO;
using System.IO.Hashing;
namespace LibIRD
{
@@ -59,11 +57,7 @@ namespace LibIRD
/// </summary>
/// <param name="isoPath">Path to the ISO</param>
/// <param name="getKeyLog">Path to the GetKey log file</param>
public ReIRD(string isoPath, string getKeyLog) : base(isoPath, getKeyLog, true)
{
// Generate Unique Identifier using ISO CRC32
UID = GenerateUID(isoPath);
}
public ReIRD(string isoPath, string getKeyLog) : base(isoPath, getKeyLog, true) { }
/// <summary>
/// Constructor with optional additional region to generate a specific Disc ID
@@ -75,8 +69,8 @@ namespace LibIRD
/// <param name="region">Disc Region</param>
public ReIRD(string isoPath, byte[] key, long? layerbreak = null, uint? uid = null, Region region = Region.NONE) : base()
{
// Generate Unique Identifier using ISO CRC32
UID = uid == null ? GenerateUID(isoPath) : (uint)uid;
// If the ISO CRC32 is provided, use it as the Unique ID
UID = uid == null ? 0x00000000 : (uint)uid;
// Determine ISO file size
long size = CalculateSize(isoPath);
@@ -135,11 +129,11 @@ namespace LibIRD
if (layerbreak >= 2 * BDLayerSize || layerbreak % SectorSize != 0)
throw new ArgumentException("Unexpected layerbreak value", nameof(size));
}
else
else if (size > BDLayerSize)
{
// If no layerbreak provided, ensure ISO is not BD-Video hybrid
using FileStream fs = new FileStream(isoPath, FileMode.Open, FileAccess.Read) ?? throw new FileNotFoundException(isoPath);
CDReader reader = new(fs, true, true);
DiscUtils.Iso9660.CDReader reader = new(fs);
if (reader.DirectoryExists("\\BDMV"))
throw new ArgumentException("Layerbreak must be provided for BD-Video hybrid discs");
// Assume disc has default layerbreak
@@ -188,7 +182,7 @@ namespace LibIRD
l0es[0], l0es[1], l0es[2], l0es[3],
// 32 bytes of zeros
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Initial portion of PIC again, for 2nd layer
// ["DI"] [v1] [11unit][DI num]
0x44, 0x49, 0x01, 0x11, 0x00, 0x01, 0x20, 0x00,
@@ -236,39 +230,6 @@ namespace LibIRD
return pic;
}
/// <summary>
/// Generates the UID field by computing the CRC32 hash of the ISO
/// </summary>
/// <param name="isoPath">Path to the ISO</param>
/// <exception cref="FileNotFoundException"></exception>
private static uint GenerateUID(string isoPath)
{
// Check file exists
FileInfo iso;
try
{
iso = new FileInfo(isoPath);
}
catch (Exception e)
{
throw new ArgumentException("Invalid ISO Path: " + e.Message);
}
if (!iso.Exists)
throw new FileNotFoundException(nameof(isoPath));
// Compute CRC32 hash
byte[] crc32;
using (FileStream fs = File.OpenRead(isoPath))
{
Crc32 hasher = new();
hasher.Append(fs);
crc32 = hasher.GetCurrentHash();
}
// Redump ISO CRC32 hash is used as the Unique ID in the reproducible IRD
return BitConverter.ToUInt32(crc32, 0);
}
/// <summary>
/// Calculates ISO file size
/// </summary>
+2
View File
@@ -13,6 +13,8 @@ IRDKit is a tool that allows direct use of LibIRD functionality from a command l
- Printing info about all ISOs and IRDs in a folder: `irdkit info .`
- Creating an IRD from an ISO: `irdkit create game.iso`
- Finding differences between two IRDs: `irdkit diff game1.ird game2.ird`
- Renaming an IRD or folder of IRDs using a redump DAT: `irdkit rename -d redump.dat game.ird`
- Verify a JB Folder with an IRD: `irdkit verify game.ird folder`
For detailed usage, read more [here](IRDKit).
+14 -14
View File
@@ -1,15 +1,15 @@
dotnet publish -c Release -f net8.0 -r win-x86 --self-contained=false -p:PublishSingleFile=true -p:DebugType=None IRDKit\IRDKit.csproj
dotnet publish -c Release -f net8.0 -r win-x64 --self-contained=false -p:PublishSingleFile=true -p:DebugType=None IRDKit\IRDKit.csproj
dotnet publish -c Release -f net8.0 -r win-arm64 --self-contained=false -p:PublishSingleFile=true -p:DebugType=None IRDKit\IRDKit.csproj
dotnet publish -c Release -f net8.0 -r linux-x64 --self-contained=false -p:PublishSingleFile=true -p:DebugType=None IRDKit\IRDKit.csproj
dotnet publish -c Release -f net8.0 -r linux-arm64 --self-contained=false -p:PublishSingleFile=true -p:DebugType=None IRDKit\IRDKit.csproj
dotnet publish -c Release -f net8.0 -r osx-x64 --self-contained=false -p:PublishSingleFile=true -p:DebugType=None IRDKit\IRDKit.csproj
dotnet publish -c Release -f net8.0 -r osx-arm64 --self-contained=false -p:PublishSingleFile=true -p:DebugType=None IRDKit\IRDKit.csproj
dotnet publish -c Release -f net9.0 -r win-x86 --self-contained=false -p:PublishSingleFile=true -p:DebugType=None IRDKit\IRDKit.csproj
dotnet publish -c Release -f net9.0 -r win-x64 --self-contained=false -p:PublishSingleFile=true -p:DebugType=None IRDKit\IRDKit.csproj
dotnet publish -c Release -f net9.0 -r win-arm64 --self-contained=false -p:PublishSingleFile=true -p:DebugType=None IRDKit\IRDKit.csproj
dotnet publish -c Release -f net9.0 -r linux-x64 --self-contained=false -p:PublishSingleFile=true -p:DebugType=None IRDKit\IRDKit.csproj
dotnet publish -c Release -f net9.0 -r linux-arm64 --self-contained=false -p:PublishSingleFile=true -p:DebugType=None IRDKit\IRDKit.csproj
dotnet publish -c Release -f net9.0 -r osx-x64 --self-contained=false -p:PublishSingleFile=true -p:DebugType=None IRDKit\IRDKit.csproj
dotnet publish -c Release -f net9.0 -r osx-arm64 --self-contained=false -p:PublishSingleFile=true -p:DebugType=None IRDKit\IRDKit.csproj
Compress-Archive -Path "./IRDKit/bin/Release/net8.0/win-x86/publish/irdkit.exe" -Destination "./irdkit-win-x86.zip" -CompressionLevel "Optimal"
Compress-Archive -Path "./IRDKit/bin/Release/net8.0/win-x64/publish/irdkit.exe" -Destination "./irdkit-win-x64.zip" -CompressionLevel "Optimal"
Compress-Archive -Path "./IRDKit/bin/Release/net8.0/win-arm64/publish/irdkit.exe" -Destination "./irdkit-win-arm64.zip" -CompressionLevel "Optimal"
Compress-Archive -Path "./IRDKit/bin/Release/net8.0/linux-x64/publish/irdkit" -Destination "./irdkit-linux-x64.zip" -CompressionLevel "Optimal"
Compress-Archive -Path "./IRDKit/bin/Release/net8.0/linux-arm64/publish/irdkit" -Destination "./irdkit-linux-arm64.zip" -CompressionLevel "Optimal"
Compress-Archive -Path "./IRDKit/bin/Release/net8.0/osx-x64/publish/irdkit" -Destination "./irdkit-osx-x64.zip" -CompressionLevel "Optimal"
Compress-Archive -Path "./IRDKit/bin/Release/net8.0/osx-arm64/publish/irdkit" -Destination "./irdkit-osx-arm64.zip" -CompressionLevel "Optimal"
Compress-Archive -Path "./IRDKit/bin/Release/net9.0/win-x86/publish/irdkit.exe" -Destination "./irdkit-win-x86.zip" -CompressionLevel "Optimal"
Compress-Archive -Path "./IRDKit/bin/Release/net9.0/win-x64/publish/irdkit.exe" -Destination "./irdkit-win-x64.zip" -CompressionLevel "Optimal"
Compress-Archive -Path "./IRDKit/bin/Release/net9.0/win-arm64/publish/irdkit.exe" -Destination "./irdkit-win-arm64.zip" -CompressionLevel "Optimal"
Compress-Archive -Path "./IRDKit/bin/Release/net9.0/linux-x64/publish/irdkit" -Destination "./irdkit-linux-x64.zip" -CompressionLevel "Optimal"
Compress-Archive -Path "./IRDKit/bin/Release/net9.0/linux-arm64/publish/irdkit" -Destination "./irdkit-linux-arm64.zip" -CompressionLevel "Optimal"
Compress-Archive -Path "./IRDKit/bin/Release/net9.0/osx-x64/publish/irdkit" -Destination "./irdkit-osx-x64.zip" -CompressionLevel "Optimal"
Compress-Archive -Path "./IRDKit/bin/Release/net9.0/osx-arm64/publish/irdkit" -Destination "./irdkit-osx-arm64.zip" -CompressionLevel "Optimal"