mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-11-15 17:00:38 +00:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de17b0c59c | ||
|
|
1663345195 | ||
|
|
5c3184baa7 | ||
|
|
9e39a0cf16 | ||
|
|
36a67139d9 | ||
|
|
33caf06bc1 | ||
|
|
f639f7ac24 | ||
|
|
11f9bf9fd9 | ||
|
|
373cf2d752 | ||
|
|
dc18951d0b | ||
|
|
29b9d27c33 | ||
|
|
f6ade446c6 | ||
|
|
6238fcbb46 | ||
|
|
2f6698edac | ||
|
|
04e8751f9b | ||
|
|
7262f74f7f | ||
|
|
0b6af978ff | ||
|
|
2cacaac9fd | ||
|
|
d39d8f9b61 | ||
|
|
09fd38e776 | ||
|
|
db2a6f63ff | ||
|
|
d9dd16fbb9 | ||
|
|
3c0c31cf10 | ||
|
|
d9bf16deef | ||
|
|
3798dbcb47 | ||
|
|
2a70a9a20e | ||
|
|
6f92f85f5d | ||
|
|
b7851601a4 | ||
|
|
cb2a96c413 | ||
|
|
69c0843a0d | ||
|
|
0171ea9da7 | ||
|
|
e493af25e0 | ||
|
|
62427576e9 | ||
|
|
e80ea00872 | ||
|
|
ce1cd15978 | ||
|
|
2a604bd73a | ||
|
|
bcc0a5bd1e | ||
|
|
32d9e8a09d | ||
|
|
d0f5ac322d | ||
|
|
05c86e4c24 | ||
|
|
1d76967a08 | ||
|
|
b9ffd61252 | ||
|
|
b4e1f6b729 |
1
.github/workflows/build_and_test.yml
vendored
1
.github/workflows/build_and_test.yml
vendored
@@ -20,6 +20,7 @@ jobs:
|
||||
8.0.x
|
||||
9.0.x
|
||||
10.0.x
|
||||
11.0.x
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
|
||||
1
.github/workflows/check_pr.yml
vendored
1
.github/workflows/check_pr.yml
vendored
@@ -15,6 +15,7 @@ jobs:
|
||||
8.0.x
|
||||
9.0.x
|
||||
10.0.x
|
||||
11.0.x
|
||||
|
||||
- name: Build
|
||||
run: dotnet build
|
||||
|
||||
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@@ -10,7 +10,7 @@
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/ExtractionTool/bin/Debug/net10.0/ExtractionTool.dll",
|
||||
"program": "${workspaceFolder}/ExtractionTool/bin/Debug/net11.0/ExtractionTool.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||
@@ -24,7 +24,7 @@
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/InfoPrint/bin/Debug/net10.0/InfoPrint.dll",
|
||||
"program": "${workspaceFolder}/InfoPrint/bin/Debug/net11.0/InfoPrint.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;net11.0</TargetFrameworks>
|
||||
<OutputType>Exe</OutputType>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
|
||||
@@ -10,7 +10,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>3.0.1</Version>
|
||||
<Version>3.3.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Support All Frameworks -->
|
||||
@@ -20,11 +20,11 @@
|
||||
<PropertyGroup Condition="$(TargetFramework.StartsWith(`netcoreapp`)) OR $(TargetFramework.StartsWith(`net5`))">
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net6`)) OR $(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`)) OR $(TargetFramework.StartsWith(`net9`)) OR $(TargetFramework.StartsWith(`net10`))">
|
||||
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net6`)) OR $(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`)) OR $(TargetFramework.StartsWith(`net9`)) OR $(TargetFramework.StartsWith(`net10`)) OR $(TargetFramework.StartsWith(`net11`))">
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(RuntimeIdentifier.StartsWith(`osx-arm`))">
|
||||
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0;net10.0;net11.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- These are needed for dealing with native Windows DLLs -->
|
||||
@@ -48,9 +48,9 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SabreTools.CommandLine" Version="[1.4.0]" />
|
||||
<PackageReference Include="SabreTools.IO" Version="[2.1.0]" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="10.0.8" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))" />
|
||||
<PackageReference Include="SabreTools.CommandLine" Version="1.6.0" />
|
||||
<PackageReference Include="SabreTools.IO" Version="2.4.0" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="11.0.0" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;net11.0</TargetFrameworks>
|
||||
<OutputType>Exe</OutputType>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
|
||||
@@ -10,7 +10,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>3.0.1</Version>
|
||||
<Version>3.3.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Support All Frameworks -->
|
||||
@@ -20,11 +20,11 @@
|
||||
<PropertyGroup Condition="$(TargetFramework.StartsWith(`netcoreapp`)) OR $(TargetFramework.StartsWith(`net5`))">
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net6`)) OR $(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`)) OR $(TargetFramework.StartsWith(`net9`)) OR $(TargetFramework.StartsWith(`net10`))">
|
||||
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net6`)) OR $(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`)) OR $(TargetFramework.StartsWith(`net9`)) OR $(TargetFramework.StartsWith(`net10`)) OR $(TargetFramework.StartsWith(`net11`))">
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(RuntimeIdentifier.StartsWith(`osx-arm`))">
|
||||
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0;net10.0;net11.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -32,9 +32,9 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SabreTools.CommandLine" Version="[1.4.0]" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="[2.0.0]" />
|
||||
<PackageReference Include="SabreTools.IO" Version="[2.1.0]" />
|
||||
<PackageReference Include="SabreTools.CommandLine" Version="1.6.0" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="2.2.0" />
|
||||
<PackageReference Include="SabreTools.IO" Version="2.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -361,6 +361,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
@@ -380,6 +381,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
@@ -406,6 +408,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
@@ -424,6 +427,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = "sha512",
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
@@ -449,6 +453,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
@@ -467,6 +472,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
@@ -493,6 +499,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
@@ -510,6 +517,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
@@ -536,6 +544,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
@@ -554,6 +563,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
@@ -580,6 +590,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
@@ -598,6 +609,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
@@ -624,6 +636,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
@@ -642,6 +655,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
@@ -668,6 +682,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
@@ -686,6 +701,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
@@ -712,6 +728,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
@@ -730,6 +747,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
@@ -756,6 +774,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
@@ -774,6 +793,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
@@ -800,6 +820,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
@@ -818,6 +839,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
@@ -844,6 +866,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
@@ -862,6 +885,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
@@ -888,6 +912,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
@@ -906,6 +931,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
@@ -932,6 +958,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
@@ -950,6 +977,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
@@ -976,6 +1004,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
@@ -994,6 +1023,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
@@ -1020,6 +1050,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = "sha512",
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
@@ -1038,6 +1069,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
@@ -1064,6 +1096,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
@@ -1082,6 +1115,53 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PartialEquals_Rom_PartialBLAKE3_True()
|
||||
{
|
||||
var self = new Rom
|
||||
{
|
||||
Name = "name1",
|
||||
Size = 12345,
|
||||
CRC16 = string.Empty,
|
||||
CRC32 = string.Empty,
|
||||
CRC64 = string.Empty,
|
||||
MD2 = string.Empty,
|
||||
MD4 = string.Empty,
|
||||
MD5 = string.Empty,
|
||||
RIPEMD128 = string.Empty,
|
||||
RIPEMD160 = string.Empty,
|
||||
SHA1 = string.Empty,
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
Name = "name2",
|
||||
Size = 12345,
|
||||
CRC16 = "crc16",
|
||||
CRC32 = "crc32",
|
||||
CRC64 = "crc64",
|
||||
MD2 = "md2",
|
||||
MD4 = "md4",
|
||||
MD5 = "md5",
|
||||
RIPEMD128 = "ripemd128",
|
||||
RIPEMD160 = "ripemd160",
|
||||
SHA1 = "sha1",
|
||||
SHA256 = "sha256",
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
@@ -1108,6 +1188,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
var other = new Rom
|
||||
{
|
||||
@@ -1126,6 +1207,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.PartialEquals(other);
|
||||
@@ -1392,6 +1474,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
Rom other = new Rom
|
||||
{
|
||||
@@ -1408,6 +1491,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = "sha512",
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HashMatch(other);
|
||||
@@ -1432,6 +1516,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
Rom other = new Rom
|
||||
{
|
||||
@@ -1448,6 +1533,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HashMatch(other);
|
||||
@@ -1472,6 +1558,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
Rom other = new Rom
|
||||
{
|
||||
@@ -1488,6 +1575,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HashMatch(other);
|
||||
@@ -1512,6 +1600,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
Rom other = new Rom
|
||||
{
|
||||
@@ -1528,6 +1617,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HashMatch(other);
|
||||
@@ -1552,6 +1642,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
Rom other = new Rom
|
||||
{
|
||||
@@ -1568,6 +1659,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HashMatch(other);
|
||||
@@ -1592,6 +1684,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
Rom other = new Rom
|
||||
{
|
||||
@@ -1608,6 +1701,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HashMatch(other);
|
||||
@@ -1632,6 +1726,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
Rom other = new Rom
|
||||
{
|
||||
@@ -1648,6 +1743,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HashMatch(other);
|
||||
@@ -1672,6 +1768,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
Rom other = new Rom
|
||||
{
|
||||
@@ -1688,6 +1785,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HashMatch(other);
|
||||
@@ -1712,6 +1810,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
Rom other = new Rom
|
||||
{
|
||||
@@ -1728,6 +1827,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HashMatch(other);
|
||||
@@ -1752,6 +1852,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
Rom other = new Rom
|
||||
{
|
||||
@@ -1768,6 +1869,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HashMatch(other);
|
||||
@@ -1792,6 +1894,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
Rom other = new Rom
|
||||
{
|
||||
@@ -1808,6 +1911,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HashMatch(other);
|
||||
@@ -1832,6 +1936,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
Rom other = new Rom
|
||||
{
|
||||
@@ -1848,6 +1953,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HashMatch(other);
|
||||
@@ -1872,6 +1978,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = "sha512",
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
Rom other = new Rom
|
||||
{
|
||||
@@ -1888,6 +1995,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HashMatch(other);
|
||||
@@ -1912,6 +2020,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
Rom other = new Rom
|
||||
{
|
||||
@@ -1928,6 +2037,49 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HashMatch(other);
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HashMatch_Rom_PartialBLAKE3_True()
|
||||
{
|
||||
Rom self = new Rom
|
||||
{
|
||||
CRC16 = string.Empty,
|
||||
CRC32 = string.Empty,
|
||||
CRC64 = string.Empty,
|
||||
MD2 = string.Empty,
|
||||
MD4 = string.Empty,
|
||||
MD5 = string.Empty,
|
||||
RIPEMD128 = string.Empty,
|
||||
RIPEMD160 = string.Empty,
|
||||
SHA1 = string.Empty,
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
Rom other = new Rom
|
||||
{
|
||||
CRC16 = "crc16",
|
||||
CRC32 = "crc32",
|
||||
CRC64 = "crc64",
|
||||
MD2 = "md2",
|
||||
MD4 = "md4",
|
||||
MD5 = "md5",
|
||||
RIPEMD128 = "ripemd128",
|
||||
RIPEMD160 = "ripemd160",
|
||||
SHA1 = "sha1",
|
||||
SHA256 = "sha256",
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HashMatch(other);
|
||||
@@ -1952,6 +2104,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
Rom other = new Rom
|
||||
{
|
||||
@@ -1968,6 +2121,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HashMatch(other);
|
||||
@@ -2162,6 +2316,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -2186,6 +2341,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -2210,6 +2366,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -2234,6 +2391,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -2258,6 +2416,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -2282,6 +2441,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -2306,6 +2466,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -2330,6 +2491,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -2354,6 +2516,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -2378,6 +2541,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -2402,6 +2566,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -2426,6 +2591,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = HashType.SHA384.ZeroString,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -2450,6 +2616,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = HashType.SHA512.ZeroString,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -2474,6 +2641,32 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = HashType.SpamSum.ZeroString,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HasZeroHash_Rom_ZeroBLAKE3_True()
|
||||
{
|
||||
var self = new Rom
|
||||
{
|
||||
CRC16 = string.Empty,
|
||||
CRC32 = string.Empty,
|
||||
CRC64 = string.Empty,
|
||||
MD2 = string.Empty,
|
||||
MD4 = string.Empty,
|
||||
MD5 = string.Empty,
|
||||
RIPEMD128 = string.Empty,
|
||||
RIPEMD160 = string.Empty,
|
||||
SHA1 = string.Empty,
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = HashType.BLAKE3.ZeroString,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -2498,6 +2691,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = HashType.SHA384.ZeroString,
|
||||
SHA512 = HashType.SHA512.ZeroString,
|
||||
SpamSum = HashType.SpamSum.ZeroString,
|
||||
BLAKE3 = HashType.BLAKE3.ZeroString,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -2583,6 +2777,7 @@ namespace SabreTools.Data.Extensions.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
self.FillMissingHashes(other);
|
||||
|
||||
@@ -1,17 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0;net11.0</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="10.1.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.11.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="4.0.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
274
SabreTools.Data.Extensions.Test/UDFExtensionsTests.cs
Normal file
274
SabreTools.Data.Extensions.Test/UDFExtensionsTests.cs
Normal file
@@ -0,0 +1,274 @@
|
||||
using SabreTools.Data.Models.UDF;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.Data.Extensions.Test
|
||||
{
|
||||
public class UDFExtensionsTests
|
||||
{
|
||||
#region DecodeDCharacters
|
||||
|
||||
[Fact]
|
||||
public void DecodeDCharacters_Null_Empty()
|
||||
{
|
||||
byte[]? data = null;
|
||||
Assert.Equal(string.Empty, data.DecodeDCharacters());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DecodeDCharacters_8Bit_Decoded()
|
||||
{
|
||||
byte[] data = [8, 0x41, 0x62, 0xE4];
|
||||
Assert.Equal("Abä", data.DecodeDCharacters());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DecodeDCharacters_16Bit_Decoded()
|
||||
{
|
||||
byte[] data = [16, 0x00, 0x41, 0x30, 0x42];
|
||||
Assert.Equal("Aあ", data.DecodeDCharacters());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DecodeDCharacters_UnknownCompression_Null()
|
||||
{
|
||||
byte[] data = [1, 0x41];
|
||||
Assert.Null(data.DecodeDCharacters());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DecodeDString_UsesLengthByte()
|
||||
{
|
||||
byte[] data = [8, 0x41, 0x42, 0x43, 0x00, 3];
|
||||
Assert.Equal("AB", data.DecodeDString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DecodeDString_ZeroLength_Empty()
|
||||
{
|
||||
byte[] data = [8, 0x41, 0x00, 0];
|
||||
Assert.Equal(string.Empty, data.DecodeDString());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region TryGetSector
|
||||
|
||||
[Fact]
|
||||
public void TryGetSector_Type1_StartPlusBlock()
|
||||
{
|
||||
var volume = CreateVolume(new Type1PartitionMap { PartitionNumber = 0 });
|
||||
bool actual = volume.TryGetSector(UDFExtensions.GetKey(0, 10), out long sector);
|
||||
Assert.True(actual);
|
||||
Assert.Equal(1010, sector);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetSector_Type1_OutsidePartition_False()
|
||||
{
|
||||
var volume = CreateVolume(new Type1PartitionMap { PartitionNumber = 0 });
|
||||
bool actual = volume.TryGetSector(UDFExtensions.GetKey(0, 100), out _);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetSector_UnknownPartitionReference_False()
|
||||
{
|
||||
var volume = CreateVolume(new Type1PartitionMap { PartitionNumber = 0 });
|
||||
bool actual = volume.TryGetSector(UDFExtensions.GetKey(1, 0), out _);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetSector_Metadata_ThroughMetadataFile()
|
||||
{
|
||||
// Metadata File at block 5 of partition 0: blocks 0-1 of the metadata partition are blocks 20-21,
|
||||
// blocks 2-3 are blocks 40-41
|
||||
var volume = CreateVolume(
|
||||
new Type1PartitionMap { PartitionNumber = 0 },
|
||||
new MetadataPartitionMap { PartitionNumber = 0, MetadataFileLocation = 5, MetadataMirrorFileLocation = 6 });
|
||||
volume.FileEntries[UDFExtensions.GetKey(0, 5)] = CreateShortAdEntry((4096, 20), (4096, 40));
|
||||
|
||||
Assert.True(volume.TryGetSector(UDFExtensions.GetKey(1, 1), out long first));
|
||||
Assert.Equal(1021, first);
|
||||
Assert.True(volume.TryGetSector(UDFExtensions.GetKey(1, 2), out long second));
|
||||
Assert.Equal(1040, second);
|
||||
Assert.False(volume.TryGetSector(UDFExtensions.GetKey(1, 4), out _));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetSector_Metadata_FallsBackToMirror()
|
||||
{
|
||||
var volume = CreateVolume(
|
||||
new Type1PartitionMap { PartitionNumber = 0 },
|
||||
new MetadataPartitionMap { PartitionNumber = 0, MetadataFileLocation = 5, MetadataMirrorFileLocation = 6 });
|
||||
volume.FileEntries[UDFExtensions.GetKey(0, 6)] = CreateShortAdEntry((2048, 30));
|
||||
|
||||
Assert.True(volume.TryGetSector(UDFExtensions.GetKey(1, 0), out long sector));
|
||||
Assert.Equal(1030, sector);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetAllocationDescriptors
|
||||
|
||||
[Fact]
|
||||
public void GetAllocationDescriptors_Embedded_Empty()
|
||||
{
|
||||
var entry = new FileEntry();
|
||||
entry.ICBTag.Flags = (ushort)AllocationDescriptorType.EMBEDDED;
|
||||
entry.AllocationDescriptors = [1, 2, 3];
|
||||
|
||||
var actual = new Volume().GetAllocationDescriptors(0, entry);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAllocationDescriptors_ZeroLengthTerminates()
|
||||
{
|
||||
var entry = CreateShortAdEntry((2048, 20), (0, 99), (2048, 40));
|
||||
|
||||
var actual = new Volume().GetAllocationDescriptors(UDFExtensions.GetKey(2, 7), entry);
|
||||
Assert.NotNull(actual);
|
||||
var ad = Assert.Single(actual);
|
||||
Assert.Equal(20u, ad.ExtentLocation.LogicalBlockNumber);
|
||||
Assert.Equal((ushort)2, ad.ExtentLocation.PartitionReferenceNumber);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAllocationDescriptors_MissingAllocationExtent_NullWithKey()
|
||||
{
|
||||
var entry = CreateShortAdEntry((2048, 20), ((3u << 30) | 2048, 50));
|
||||
|
||||
var actual = new Volume().GetAllocationDescriptors(UDFExtensions.GetKey(0, 7), entry, out long missingKey);
|
||||
Assert.Null(actual);
|
||||
Assert.Equal(UDFExtensions.GetKey(0, 50), missingKey);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAllocationDescriptors_AllocationExtentLoop_Null()
|
||||
{
|
||||
var volume = new Volume();
|
||||
var entry = CreateShortAdEntry(((3u << 30) | 2048, 50));
|
||||
volume.AllocationExtentDescriptors[UDFExtensions.GetKey(0, 50)] = new AllocationExtentDescriptor
|
||||
{
|
||||
AllocationDescriptors = CreateShortAdEntry(((3u << 30) | 2048, 50)).AllocationDescriptors,
|
||||
};
|
||||
|
||||
var actual = volume.GetAllocationDescriptors(UDFExtensions.GetKey(0, 7), entry);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IsValidDescriptor
|
||||
|
||||
[Theory]
|
||||
[InlineData(2)]
|
||||
[InlineData(3)]
|
||||
public void IsValidDescriptor_Valid_True(byte version)
|
||||
{
|
||||
byte[] data = CreateDescriptor(version);
|
||||
Assert.True(data.IsValidDescriptor(0, data.Length, 20));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsValidDescriptor_WrongChecksum_False()
|
||||
{
|
||||
byte[] data = CreateDescriptor(2);
|
||||
data[4]++;
|
||||
Assert.False(data.IsValidDescriptor(0, data.Length, 20));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsValidDescriptor_UnknownVersion_False()
|
||||
{
|
||||
byte[] data = CreateDescriptor(4);
|
||||
Assert.False(data.IsValidDescriptor(0, data.Length, 20));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsValidDescriptor_WrongCrc_False()
|
||||
{
|
||||
byte[] data = CreateDescriptor(2);
|
||||
data[16] ^= 0x01;
|
||||
Assert.False(data.IsValidDescriptor(0, data.Length, 20));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsValidDescriptor_CrcPastAvailable_NotChecked()
|
||||
{
|
||||
byte[] data = CreateDescriptor(2);
|
||||
data[16] ^= 0x01;
|
||||
Assert.True(data.IsValidDescriptor(0, 16, 20));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsValidDescriptor_WrongLocation_False()
|
||||
{
|
||||
byte[] data = CreateDescriptor(2);
|
||||
Assert.False(data.IsValidDescriptor(0, data.Length, 21));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Descriptor with tag location 20 whose 3 bytes after the tag have the CRC #3299 (ECMA-167 3/7.2.6)
|
||||
/// </summary>
|
||||
private static byte[] CreateDescriptor(byte version)
|
||||
{
|
||||
byte[] data = new byte[19];
|
||||
data[0] = 1;
|
||||
data[2] = version;
|
||||
data[8] = 0x99;
|
||||
data[9] = 0x32;
|
||||
data[10] = 3;
|
||||
data[12] = 20;
|
||||
data[16] = 0x70;
|
||||
data[17] = 0x6A;
|
||||
data[18] = 0x77;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if (i != 4)
|
||||
data[4] += data[i];
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Volume with partition 0 at sector 1000 (length 50) and the given partition maps
|
||||
/// </summary>
|
||||
private static Volume CreateVolume(params PartitionMap[] maps)
|
||||
{
|
||||
return new Volume
|
||||
{
|
||||
VolumeDescriptorSequence =
|
||||
[
|
||||
new PartitionDescriptor { PartitionNumber = 0, PartitionStartingLocation = 1000, PartitionLength = 50 },
|
||||
new LogicalVolumeDescriptor { LogicalBlockSize = 2048, PartitionMaps = maps },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// File Entry with the given short allocation descriptors (extent length, position)
|
||||
/// </summary>
|
||||
private static FileEntry CreateShortAdEntry(params (uint Length, uint Position)[] extents)
|
||||
{
|
||||
var data = new byte[extents.Length * 8];
|
||||
for (int i = 0; i < extents.Length; i++)
|
||||
{
|
||||
for (int b = 0; b < 4; b++)
|
||||
{
|
||||
data[(i * 8) + b] = (byte)(extents[i].Length >> (8 * b));
|
||||
data[(i * 8) + 4 + b] = (byte)(extents[i].Position >> (8 * b));
|
||||
}
|
||||
}
|
||||
|
||||
var entry = new FileEntry { AllocationDescriptors = data };
|
||||
entry.ICBTag.Flags = (ushort)AllocationDescriptorType.SHORT;
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -296,6 +296,10 @@ namespace SabreTools.Data.Extensions
|
||||
string? otherSpamSum = other.SpamSum;
|
||||
bool conditionalSpamSum = ConditionalHashEquals(selfSpamSum, otherSpamSum);
|
||||
|
||||
string? selfBlake3 = self.BLAKE3;
|
||||
string? otherBlake3 = other.BLAKE3;
|
||||
bool conditionalBlake3 = ConditionalHashEquals(selfBlake3, otherBlake3);
|
||||
|
||||
return conditionalCrc16
|
||||
&& conditionalCrc
|
||||
&& conditionalCrc64
|
||||
@@ -308,7 +312,8 @@ namespace SabreTools.Data.Extensions
|
||||
&& conditionalSha256
|
||||
&& conditionalSha384
|
||||
&& conditionalSha512
|
||||
&& conditionalSpamSum;
|
||||
&& conditionalSpamSum
|
||||
&& conditionalBlake3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -357,6 +362,7 @@ namespace SabreTools.Data.Extensions
|
||||
bool sha384Null = string.IsNullOrEmpty(rom.SHA384);
|
||||
bool sha512Null = string.IsNullOrEmpty(rom.SHA512);
|
||||
bool spamsumNull = string.IsNullOrEmpty(rom.SpamSum);
|
||||
bool blake3Null = string.IsNullOrEmpty(rom.BLAKE3);
|
||||
|
||||
return !crc16Null
|
||||
|| !crc32Null
|
||||
@@ -370,7 +376,8 @@ namespace SabreTools.Data.Extensions
|
||||
|| !sha256Null
|
||||
|| !sha384Null
|
||||
|| !sha512Null
|
||||
|| !spamsumNull;
|
||||
|| !spamsumNull
|
||||
|| !blake3Null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -455,6 +462,9 @@ namespace SabreTools.Data.Extensions
|
||||
string? spamsum = rom.SpamSum;
|
||||
bool spamsumNull = string.IsNullOrEmpty(spamsum) || string.Equals(spamsum, HashType.SpamSum.ZeroString, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
string? blake3 = rom.BLAKE3;
|
||||
bool blake3Null = string.IsNullOrEmpty(blake3) || string.Equals(blake3, HashType.BLAKE3.ZeroString, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
return crc16Null
|
||||
&& crc32Null
|
||||
&& crc64Null
|
||||
@@ -467,7 +477,8 @@ namespace SabreTools.Data.Extensions
|
||||
&& sha256Null
|
||||
&& sha384Null
|
||||
&& sha512Null
|
||||
&& spamsumNull;
|
||||
&& spamsumNull
|
||||
&& blake3Null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -552,6 +563,9 @@ namespace SabreTools.Data.Extensions
|
||||
bool spamsumNull = string.IsNullOrEmpty(self.SpamSum);
|
||||
spamsumNull ^= string.IsNullOrEmpty(other.SpamSum);
|
||||
|
||||
bool blake3Null = string.IsNullOrEmpty(self.BLAKE3);
|
||||
blake3Null ^= string.IsNullOrEmpty(other.BLAKE3);
|
||||
|
||||
return !crc16Null
|
||||
|| !crc32Null
|
||||
|| !crc64Null
|
||||
@@ -564,7 +578,8 @@ namespace SabreTools.Data.Extensions
|
||||
|| !sha256Null
|
||||
|| !sha384Null
|
||||
|| !sha512Null
|
||||
|| !spamsumNull;
|
||||
|| !spamsumNull
|
||||
|| !blake3Null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -696,6 +711,11 @@ namespace SabreTools.Data.Extensions
|
||||
string? otherSpamSum = other.SpamSum;
|
||||
if (string.IsNullOrEmpty(selfSpamSum) && !string.IsNullOrEmpty(otherSpamSum))
|
||||
self.SpamSum = otherSpamSum;
|
||||
|
||||
string? selfBlake3 = self.BLAKE3;
|
||||
string? otherBlake3 = other.BLAKE3;
|
||||
if (string.IsNullOrEmpty(selfBlake3) && !string.IsNullOrEmpty(otherBlake3))
|
||||
self.BLAKE3 = otherBlake3;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;net11.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
@@ -12,7 +12,7 @@
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>3.0.1</Version>
|
||||
<Version>3.3.0</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NetLegacySupport.Numerics" Version="1.0.1" Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`))" />
|
||||
<PackageReference Include="SabreTools.IO" Version="[2.1.0]" />
|
||||
<PackageReference Include="SabreTools.IO" Version="2.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
417
SabreTools.Data.Extensions/UDFExtensions.cs
Normal file
417
SabreTools.Data.Extensions/UDFExtensions.cs
Normal file
@@ -0,0 +1,417 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using SabreTools.Data.Models.UDF;
|
||||
using SabreTools.Numerics.Extensions;
|
||||
|
||||
namespace SabreTools.Data.Extensions
|
||||
{
|
||||
public static class UDFExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Maximum number of Allocation Extent Descriptors followed for one File Entry
|
||||
/// </summary>
|
||||
private const int MaximumAllocationExtents = 1024;
|
||||
|
||||
/// <summary>
|
||||
/// CRC-ITU-T (CCITT, polynomial 0x1021) table for descriptor CRCs
|
||||
/// </summary>
|
||||
private static readonly ushort[] CrcTable = CreateCrcTable();
|
||||
|
||||
/// <summary>
|
||||
/// Get the dictionary key of a logical block address
|
||||
/// </summary>
|
||||
/// <param name="address">Logical block address</param>
|
||||
/// <returns>((long)PartitionReferenceNumber << 32) | LogicalBlockNumber</returns>
|
||||
public static long GetKey(this LogicalBlockAddress address)
|
||||
=> GetKey(address.PartitionReferenceNumber, address.LogicalBlockNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get the dictionary key of a logical block address
|
||||
/// </summary>
|
||||
/// <param name="partitionReferenceNumber">Index of the partition map</param>
|
||||
/// <param name="logicalBlockNumber">Logical block number within the partition</param>
|
||||
/// <returns>((long)partitionReferenceNumber << 32) | logicalBlockNumber</returns>
|
||||
public static long GetKey(ushort partitionReferenceNumber, uint logicalBlockNumber)
|
||||
=> ((long)partitionReferenceNumber << 32) | logicalBlockNumber;
|
||||
|
||||
/// <summary>
|
||||
/// Get the extent type from an allocation descriptor's extent length
|
||||
/// </summary>
|
||||
public static ExtentType GetExtentType(uint extentLength)
|
||||
=> (ExtentType)(extentLength >> Constants.ExtentTypeShift);
|
||||
|
||||
/// <summary>
|
||||
/// Get the extent length in bytes from an allocation descriptor's extent length
|
||||
/// </summary>
|
||||
public static uint GetExtentLength(uint extentLength)
|
||||
=> extentLength & Constants.ExtentLengthMask;
|
||||
|
||||
/// <summary>
|
||||
/// Get the type of the allocation descriptors of an ICB
|
||||
/// </summary>
|
||||
public static AllocationDescriptorType GetAllocationDescriptorType(this ICBTag tag)
|
||||
=> (AllocationDescriptorType)(tag.Flags & Constants.AllocationDescriptorTypeMask);
|
||||
|
||||
/// <summary>
|
||||
/// Get the prevailing Logical Volume Descriptor (highest Volume Descriptor Sequence Number)
|
||||
/// </summary>
|
||||
/// <param name="volume">Volume to search</param>
|
||||
/// <returns>Logical Volume Descriptor on success, null if none was recorded</returns>
|
||||
public static LogicalVolumeDescriptor? GetLogicalVolumeDescriptor(this Volume volume)
|
||||
{
|
||||
LogicalVolumeDescriptor? prevailing = null;
|
||||
foreach (var descriptor in volume.VolumeDescriptorSequence)
|
||||
{
|
||||
if (descriptor is LogicalVolumeDescriptor lvd
|
||||
&& (prevailing is null || lvd.VolumeDescriptorSequenceNumber > prevailing.VolumeDescriptorSequenceNumber))
|
||||
{
|
||||
prevailing = lvd;
|
||||
}
|
||||
}
|
||||
|
||||
return prevailing;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the prevailing Partition Descriptor of a partition (highest Volume Descriptor Sequence Number)
|
||||
/// </summary>
|
||||
/// <param name="volume">Volume to search</param>
|
||||
/// <param name="partitionNumber">Partition number</param>
|
||||
/// <returns>Partition Descriptor on success, null if none was recorded</returns>
|
||||
public static PartitionDescriptor? GetPartitionDescriptor(this Volume volume, ushort partitionNumber)
|
||||
{
|
||||
PartitionDescriptor? prevailing = null;
|
||||
foreach (var descriptor in volume.VolumeDescriptorSequence)
|
||||
{
|
||||
if (descriptor is PartitionDescriptor pd
|
||||
&& pd.PartitionNumber == partitionNumber
|
||||
&& (prevailing is null || pd.VolumeDescriptorSequenceNumber > prevailing.VolumeDescriptorSequenceNumber))
|
||||
{
|
||||
prevailing = pd;
|
||||
}
|
||||
}
|
||||
|
||||
return prevailing;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the partition reference number of the Type 1 partition map for a partition number
|
||||
/// </summary>
|
||||
/// <param name="lvd">Logical Volume Descriptor holding the partition maps</param>
|
||||
/// <param name="partitionNumber">Partition number</param>
|
||||
/// <returns>Partition reference number on success, -1 if there is no such map</returns>
|
||||
public static int GetType1PartitionReference(this LogicalVolumeDescriptor lvd, ushort partitionNumber)
|
||||
{
|
||||
for (int i = 0; i < lvd.PartitionMaps.Length; i++)
|
||||
{
|
||||
if (lvd.PartitionMaps[i] is Type1PartitionMap map && map.PartitionNumber == partitionNumber)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Map a logical block of a partition to a logical sector of the volume
|
||||
/// Supports Type 1 partitions and Metadata Partitions (the Metadata File's File Entry must be in FileEntries)
|
||||
/// </summary>
|
||||
/// <param name="volume">Volume containing the Volume Descriptor Sequence</param>
|
||||
/// <param name="key">Logical block address key, see GetKey</param>
|
||||
/// <param name="sector">Logical sector on success</param>
|
||||
/// <returns>True if the block could be mapped, false otherwise</returns>
|
||||
public static bool TryGetSector(this Volume volume, long key, out long sector)
|
||||
{
|
||||
sector = -1;
|
||||
|
||||
var lvd = volume.GetLogicalVolumeDescriptor();
|
||||
if (lvd is null)
|
||||
return false;
|
||||
|
||||
int partitionReference = (int)(key >> 32);
|
||||
uint block = (uint)key;
|
||||
if (partitionReference < 0 || partitionReference >= lvd.PartitionMaps.Length)
|
||||
return false;
|
||||
|
||||
var map = lvd.PartitionMaps[partitionReference];
|
||||
if (map is Type1PartitionMap type1)
|
||||
{
|
||||
var pd = volume.GetPartitionDescriptor(type1.PartitionNumber);
|
||||
if (pd is null || block >= pd.PartitionLength)
|
||||
return false;
|
||||
|
||||
sector = (long)pd.PartitionStartingLocation + block;
|
||||
return true;
|
||||
}
|
||||
else if (map is MetadataPartitionMap metadata)
|
||||
{
|
||||
// The Metadata File (or its mirror) is recorded in the Type 1 partition of the same partition number
|
||||
int physical = lvd.GetType1PartitionReference(metadata.PartitionNumber);
|
||||
if (physical < 0)
|
||||
return false;
|
||||
|
||||
if (!TryGetMetadataFileBlock(volume, lvd, GetKey((ushort)physical, metadata.MetadataFileLocation), block, out long physicalKey)
|
||||
&& !TryGetMetadataFileBlock(volume, lvd, GetKey((ushort)physical, metadata.MetadataMirrorFileLocation), block, out physicalKey))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return volume.TryGetSector(physicalKey, out sector);
|
||||
}
|
||||
|
||||
// Virtual and Sparable partitions are not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Map a logical block of a Metadata Partition through the Metadata File's allocation descriptors
|
||||
/// </summary>
|
||||
private static bool TryGetMetadataFileBlock(Volume volume, LogicalVolumeDescriptor lvd, long fileKey, uint block, out long physicalKey)
|
||||
{
|
||||
physicalKey = -1;
|
||||
if (!volume.FileEntries.TryGetValue(fileKey, out var fileEntry))
|
||||
return false;
|
||||
|
||||
var descriptors = volume.GetAllocationDescriptors(fileKey, fileEntry);
|
||||
if (descriptors is null)
|
||||
return false;
|
||||
|
||||
uint blockSize = lvd.LogicalBlockSize;
|
||||
long first = 0;
|
||||
foreach (var ad in descriptors)
|
||||
{
|
||||
long blocks = (GetExtentLength(ad.ExtentLength) + blockSize - 1) / blockSize;
|
||||
if (block < first + blocks)
|
||||
{
|
||||
if (GetExtentType(ad.ExtentLength) != ExtentType.RECORDED_AND_ALLOCATED)
|
||||
return false;
|
||||
|
||||
physicalKey = GetKey(ad.ExtentLocation.PartitionReferenceNumber, (uint)(ad.ExtentLocation.LogicalBlockNumber + (block - first)));
|
||||
return true;
|
||||
}
|
||||
|
||||
first += blocks;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the allocation descriptors of a File Entry, including those continued in Allocation Extent Descriptors,
|
||||
/// as long allocation descriptors (short allocation descriptors get the partition of the File Entry)
|
||||
/// </summary>
|
||||
/// <param name="volume">Volume containing the Allocation Extent Descriptors</param>
|
||||
/// <param name="key">Logical block address key of the File Entry</param>
|
||||
/// <param name="fileEntry">File Entry</param>
|
||||
/// <returns>Allocation descriptors (empty for embedded data), null if they are not supported or incomplete</returns>
|
||||
public static List<LongAllocationDescriptor>? GetAllocationDescriptors(this Volume volume, long key, FileEntry fileEntry)
|
||||
=> volume.GetAllocationDescriptors(key, fileEntry, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get the allocation descriptors of a File Entry, including those continued in Allocation Extent Descriptors,
|
||||
/// as long allocation descriptors (short allocation descriptors get the partition of the File Entry)
|
||||
/// </summary>
|
||||
/// <param name="volume">Volume containing the Allocation Extent Descriptors</param>
|
||||
/// <param name="key">Logical block address key of the File Entry</param>
|
||||
/// <param name="fileEntry">File Entry</param>
|
||||
/// <param name="missingKey">Key of the first Allocation Extent Descriptor that is not in the volume, -1 if none</param>
|
||||
/// <returns>Allocation descriptors (empty for embedded data), null if they are not supported or incomplete</returns>
|
||||
public static List<LongAllocationDescriptor>? GetAllocationDescriptors(this Volume volume, long key, FileEntry fileEntry, out long missingKey)
|
||||
{
|
||||
missingKey = -1;
|
||||
|
||||
var type = fileEntry.ICBTag.GetAllocationDescriptorType();
|
||||
if (type == AllocationDescriptorType.EMBEDDED)
|
||||
return [];
|
||||
|
||||
// Extended allocation descriptors are not allowed by UDF
|
||||
if (type != AllocationDescriptorType.SHORT && type != AllocationDescriptorType.LONG)
|
||||
return null;
|
||||
|
||||
List<LongAllocationDescriptor> result = [];
|
||||
ushort partition = (ushort)(key >> 32);
|
||||
byte[] descriptors = fileEntry.AllocationDescriptors;
|
||||
int length = descriptors.Length;
|
||||
|
||||
for (int extents = 0; extents <= MaximumAllocationExtents; extents++)
|
||||
{
|
||||
long nextKey = -1;
|
||||
int size = type == AllocationDescriptorType.SHORT ? 8 : 16;
|
||||
for (int offset = 0; offset + size <= length; offset += size)
|
||||
{
|
||||
var ad = new LongAllocationDescriptor();
|
||||
ad.ExtentLength = descriptors.ToUInt32LittleEndian(offset);
|
||||
if (type == AllocationDescriptorType.SHORT)
|
||||
{
|
||||
ad.ExtentLocation.LogicalBlockNumber = descriptors.ToUInt32LittleEndian(offset + 4);
|
||||
ad.ExtentLocation.PartitionReferenceNumber = partition;
|
||||
}
|
||||
else
|
||||
{
|
||||
ad.ExtentLocation.LogicalBlockNumber = descriptors.ToUInt32LittleEndian(offset + 4);
|
||||
ad.ExtentLocation.PartitionReferenceNumber = descriptors.ToUInt16LittleEndian(offset + 8);
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
ad.ImplementationUse[i] = descriptors[offset + 10 + i];
|
||||
}
|
||||
}
|
||||
|
||||
// A zero length terminates the allocation descriptors
|
||||
if (GetExtentLength(ad.ExtentLength) == 0)
|
||||
return result;
|
||||
|
||||
if (GetExtentType(ad.ExtentLength) == ExtentType.NEXT_EXTENT)
|
||||
{
|
||||
nextKey = ad.ExtentLocation.GetKey();
|
||||
break;
|
||||
}
|
||||
|
||||
result.Add(ad);
|
||||
}
|
||||
|
||||
if (nextKey < 0)
|
||||
return result;
|
||||
|
||||
if (!volume.AllocationExtentDescriptors.TryGetValue(nextKey, out var aed))
|
||||
{
|
||||
missingKey = nextKey;
|
||||
return null;
|
||||
}
|
||||
|
||||
partition = (ushort)(nextKey >> 32);
|
||||
descriptors = aed.AllocationDescriptors;
|
||||
length = descriptors.Length;
|
||||
}
|
||||
|
||||
// Too many continuation extents, assume a loop
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check a descriptor tag: checksum, version, CRC (when it fits into the data) and location
|
||||
/// </summary>
|
||||
/// <remarks>ECMA-167 3/7.2; receiving systems allow descriptor version 2 or 3 (3/7.2.2)</remarks>
|
||||
/// <param name="data">Data holding the descriptor</param>
|
||||
/// <param name="offset">Offset of the descriptor</param>
|
||||
/// <param name="available">Number of bytes of the descriptor available from the offset</param>
|
||||
/// <param name="location">Expected tag location (logical sector or logical block number)</param>
|
||||
/// <returns>True if the tag is valid, false otherwise</returns>
|
||||
public static bool IsValidDescriptor(this byte[] data, int offset, int available, uint location)
|
||||
{
|
||||
byte checksum = 0;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if (i != 4)
|
||||
checksum += data[offset + i];
|
||||
}
|
||||
|
||||
if (checksum != data[offset + 4])
|
||||
return false;
|
||||
|
||||
ushort version = data.ToUInt16LittleEndian(offset + 2);
|
||||
if (version != 2 && version != 3)
|
||||
return false;
|
||||
|
||||
ushort crcLength = data.ToUInt16LittleEndian(offset + 10);
|
||||
if (16 + crcLength <= available)
|
||||
{
|
||||
if (ComputeCrc(data, offset + 16, crcLength) != data.ToUInt16LittleEndian(offset + 8))
|
||||
return false;
|
||||
}
|
||||
|
||||
return data.ToUInt32LittleEndian(offset + 12) == location;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode OSTA Compressed Unicode d-characters (first byte = compression ID)
|
||||
/// </summary>
|
||||
/// <param name="data">Encoded characters</param>
|
||||
/// <returns>Decoded string, empty for no characters, null for an unknown compression ID</returns>
|
||||
public static string? DecodeDCharacters(this byte[]? data)
|
||||
=> DecodeDCharacters(data, data?.Length ?? 0);
|
||||
|
||||
/// <summary>
|
||||
/// Decode an OSTA Compressed Unicode dstring (last byte = number of used bytes)
|
||||
/// </summary>
|
||||
/// <param name="data">Encoded dstring field</param>
|
||||
/// <returns>Decoded string, empty for no characters, null for an unknown compression ID</returns>
|
||||
public static string? DecodeDString(this byte[]? data)
|
||||
{
|
||||
if (data is null || data.Length == 0)
|
||||
return string.Empty;
|
||||
|
||||
int length = data[data.Length - 1];
|
||||
if (length > data.Length - 1)
|
||||
length = data.Length - 1;
|
||||
|
||||
return DecodeDCharacters(data, length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode the first length bytes of OSTA Compressed Unicode d-characters
|
||||
/// </summary>
|
||||
private static string? DecodeDCharacters(byte[]? data, int length)
|
||||
{
|
||||
if (data is null || length == 0)
|
||||
return string.Empty;
|
||||
|
||||
// 254 and 255 are the same encodings, used by UDF for deleted entries
|
||||
byte compressionId = data[0];
|
||||
var builder = new StringBuilder(length);
|
||||
if (compressionId == Constants.CompressionId8 || compressionId == 254)
|
||||
{
|
||||
for (int i = 1; i < length; i++)
|
||||
{
|
||||
builder.Append((char)data[i]);
|
||||
}
|
||||
}
|
||||
else if (compressionId == Constants.CompressionId16 || compressionId == 255)
|
||||
{
|
||||
for (int i = 1; i + 1 < length; i += 2)
|
||||
{
|
||||
builder.Append((char)data.ToUInt16BigEndian(i));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
// TODO: Replace with CRC-16/XMODEM from Hashing once its CRC code is faster
|
||||
/// <summary>
|
||||
/// Compute the CRC-ITU-T of a range of bytes
|
||||
/// </summary>
|
||||
private static ushort ComputeCrc(byte[] data, int offset, int length)
|
||||
{
|
||||
ushort crc = 0;
|
||||
for (int i = offset; i < offset + length; i++)
|
||||
{
|
||||
crc = (ushort)(CrcTable[((crc >> 8) ^ data[i]) & 0xFF] ^ (crc << 8));
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the CRC-ITU-T table
|
||||
/// </summary>
|
||||
private static ushort[] CreateCrcTable()
|
||||
{
|
||||
var table = new ushort[256];
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
ushort crc = (ushort)(i << 8);
|
||||
for (int bit = 0; bit < 8; bit++)
|
||||
{
|
||||
crc = (crc & 0x8000) != 0 ? (ushort)((crc << 1) ^ 0x1021) : (ushort)(crc << 1);
|
||||
}
|
||||
|
||||
table[i] = crc;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,6 +68,9 @@ namespace SabreTools.Data.Models.ClrMamePro
|
||||
/// <remarks>spamsum; Appears after SHA512</remarks>
|
||||
public string? SpamSum { get; set; }
|
||||
|
||||
/// <remarks>blake3; Appears after SHA512</remarks>
|
||||
public string? BLAKE3 { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region DiscImgeCreator Extensions
|
||||
|
||||
15
SabreTools.Data.Models/Hashfile/BLAKE3.cs
Normal file
15
SabreTools.Data.Models/Hashfile/BLAKE3.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
namespace SabreTools.Data.Models.Hashfile
|
||||
{
|
||||
/// <summary>
|
||||
/// BLAKE3 File
|
||||
/// </summary>
|
||||
public class BLAKE3
|
||||
{
|
||||
[Required]
|
||||
public string? Hash { get; set; }
|
||||
|
||||
[Required]
|
||||
public string? File { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -24,5 +24,7 @@ namespace SabreTools.Data.Models.Hashfile
|
||||
public SHA512[]? SHA512 { get; set; }
|
||||
|
||||
public SpamSum[]? SpamSum { get; set; }
|
||||
|
||||
public BLAKE3[]? BLAKE3 { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,11 @@ namespace SabreTools.Data.Models.Logiqx
|
||||
[XmlAttribute("runnable")]
|
||||
public Runnable? Runnable { get; set; }
|
||||
|
||||
/// <remarks>(dir|zip|7z), RomVault extension</remarks>
|
||||
/// TODO: Turn this into an enum like the other flags
|
||||
[XmlAttribute("type")]
|
||||
public string? SetType { get; set; }
|
||||
|
||||
[XmlElement("comment")]
|
||||
public string[]? Comment { get; set; }
|
||||
|
||||
|
||||
@@ -48,6 +48,10 @@ namespace SabreTools.Data.Models.Logiqx
|
||||
[XmlElement("comment")]
|
||||
public string? Comment { get; set; }
|
||||
|
||||
/// <remarks>RomVault extension</remarks>
|
||||
[XmlElement("subset")]
|
||||
public string? Subset { get; set; }
|
||||
|
||||
/// <remarks>Trurip extension</remarks>
|
||||
[XmlElement("type")]
|
||||
public string? Type { get; set; }
|
||||
|
||||
@@ -65,6 +65,10 @@ namespace SabreTools.Data.Models.Logiqx
|
||||
[XmlAttribute("spamsum")]
|
||||
public string? SpamSum { get; set; }
|
||||
|
||||
/// <remarks>Hash extension</remarks>
|
||||
[XmlAttribute("blake3")]
|
||||
public string? BLAKE3 { get; set; }
|
||||
|
||||
/// <remarks>DiscImgeCreator extension</remarks>
|
||||
[XmlAttribute("xxh3_64")]
|
||||
public string? xxHash364 { get; set; }
|
||||
|
||||
@@ -21,5 +21,10 @@ namespace SabreTools.Data.Models.Logiqx
|
||||
/// <remarks>(zip|unzip) "zip"</remarks>
|
||||
[XmlAttribute("forcepacking")]
|
||||
public PackingFlag ForcePacking { get; set; }
|
||||
|
||||
/// <remarks>(noautodir|nogame)</remarks>
|
||||
/// TODO: Turn this into an enum like the other flags
|
||||
[XmlAttribute("dir")]
|
||||
public string? Dir { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ namespace SabreTools.Data.Models.Metadata
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
public string? DirHandling { get; set; }
|
||||
|
||||
public string? Email { get; set; }
|
||||
|
||||
public string? EmulatorVersion { get; set; }
|
||||
@@ -108,6 +110,8 @@ namespace SabreTools.Data.Models.Metadata
|
||||
/// TODO: This needs an internal model OR mapping to fields
|
||||
public OfflineList.Search? Search { get; set; }
|
||||
|
||||
public string? Subset { get; set; }
|
||||
|
||||
public string? System { get; set; }
|
||||
|
||||
public string? Timestamp { get; set; }
|
||||
@@ -135,6 +139,7 @@ namespace SabreTools.Data.Models.Metadata
|
||||
obj.DatVersion = DatVersion;
|
||||
obj.Debug = Debug;
|
||||
obj.Description = Description;
|
||||
obj.DirHandling = DirHandling;
|
||||
obj.Email = Email;
|
||||
obj.EmulatorVersion = EmulatorVersion;
|
||||
obj.FileName = FileName;
|
||||
@@ -166,6 +171,7 @@ namespace SabreTools.Data.Models.Metadata
|
||||
obj.ScreenshotsHeight = ScreenshotsHeight;
|
||||
obj.ScreenshotsWidth = ScreenshotsWidth;
|
||||
obj.Search = Search;
|
||||
obj.Subset = Subset;
|
||||
obj.System = System;
|
||||
obj.Timestamp = Timestamp;
|
||||
obj.Type = Type;
|
||||
@@ -224,6 +230,11 @@ namespace SabreTools.Data.Models.Metadata
|
||||
else if (Description is not null && !Description.Equals(other.Description, StringComparison.OrdinalIgnoreCase))
|
||||
return false;
|
||||
|
||||
if ((DirHandling is null) ^ (other.DirHandling is null))
|
||||
return false;
|
||||
else if (DirHandling is not null && !DirHandling.Equals(other.DirHandling, StringComparison.OrdinalIgnoreCase))
|
||||
return false;
|
||||
|
||||
if ((Email is null) ^ (other.Email is null))
|
||||
return false;
|
||||
else if (Email is not null && !Email.Equals(other.Email, StringComparison.OrdinalIgnoreCase))
|
||||
@@ -336,6 +347,11 @@ namespace SabreTools.Data.Models.Metadata
|
||||
else if (ScreenshotsWidth is not null && !ScreenshotsWidth.Equals(other.ScreenshotsWidth, StringComparison.OrdinalIgnoreCase))
|
||||
return false;
|
||||
|
||||
if ((Subset is null) ^ (other.Subset is null))
|
||||
return false;
|
||||
else if (Subset is not null && !Subset.Equals(other.Subset, StringComparison.OrdinalIgnoreCase))
|
||||
return false;
|
||||
|
||||
if ((System is null) ^ (other.System is null))
|
||||
return false;
|
||||
else if (System is not null && !System.Equals(other.System, StringComparison.OrdinalIgnoreCase))
|
||||
|
||||
@@ -159,6 +159,9 @@ namespace SabreTools.Data.Models.Metadata
|
||||
|
||||
public string? Serial { get; set; }
|
||||
|
||||
/// <remarks>(dir|zip|7z), RomVault extension</remarks>
|
||||
public string? SetType { get; set; }
|
||||
|
||||
public SharedFeat[]? SharedFeat { get; set; }
|
||||
|
||||
public Slot[]? Slot { get; set; }
|
||||
@@ -298,6 +301,7 @@ namespace SabreTools.Data.Models.Metadata
|
||||
obj.SaveType = SaveType;
|
||||
obj.Score = Score;
|
||||
obj.Serial = Serial;
|
||||
obj.SetType = SetType;
|
||||
if (SharedFeat is not null)
|
||||
obj.SharedFeat = Array.ConvertAll(SharedFeat, i => (SharedFeat)i.Clone());
|
||||
if (Slot is not null)
|
||||
@@ -569,6 +573,11 @@ namespace SabreTools.Data.Models.Metadata
|
||||
else if (Serial is not null && !Serial.Equals(other.Serial, StringComparison.OrdinalIgnoreCase))
|
||||
return false;
|
||||
|
||||
if ((SetType is null) ^ (other.SetType is null))
|
||||
return false;
|
||||
else if (SetType is not null && !SetType.Equals(other.SetType, StringComparison.OrdinalIgnoreCase))
|
||||
return false;
|
||||
|
||||
if ((Source is null) ^ (other.Source is null))
|
||||
return false;
|
||||
else if (Source is not null && !Source.Equals(other.Source, StringComparison.OrdinalIgnoreCase))
|
||||
|
||||
@@ -39,6 +39,8 @@ namespace SabreTools.Data.Models.Metadata
|
||||
/// <remarks>ArchiveDotOrg.File</remarks>
|
||||
public string? BitTorrentMagnetHash { get; set; }
|
||||
|
||||
public string? BLAKE3 { get; set; }
|
||||
|
||||
/// <remarks>ArchiveDotOrg.File</remarks>
|
||||
public string? ClothCoverDetectionModuleVersion { get; set; }
|
||||
|
||||
@@ -190,6 +192,9 @@ namespace SabreTools.Data.Models.Metadata
|
||||
/// <remarks>(baddump|nodump|good|verified) "good"</remarks>
|
||||
public ItemStatus? Status { get; set; }
|
||||
|
||||
/// <remarks>Possibly enum; OpenMSX.RomBase</remarks>
|
||||
public string? StatusMisc { get; set; }
|
||||
|
||||
/// <remarks>ArchiveDotOrg.File</remarks>
|
||||
public string? Summation { get; set; }
|
||||
|
||||
@@ -293,6 +298,7 @@ namespace SabreTools.Data.Models.Metadata
|
||||
obj.Bios = Bios;
|
||||
obj.Bitrate = Bitrate;
|
||||
obj.BitTorrentMagnetHash = BitTorrentMagnetHash;
|
||||
obj.BLAKE3 = BLAKE3;
|
||||
obj.ClothCoverDetectionModuleVersion = ClothCoverDetectionModuleVersion;
|
||||
obj.CollectionCatalogNumber = CollectionCatalogNumber;
|
||||
obj.Comment = Comment;
|
||||
@@ -350,6 +356,7 @@ namespace SabreTools.Data.Models.Metadata
|
||||
obj.SpamSum = SpamSum;
|
||||
obj.Start = Start;
|
||||
obj.Status = Status;
|
||||
obj.StatusMisc = StatusMisc;
|
||||
obj.Summation = Summation;
|
||||
obj.TesseractOCR = TesseractOCR;
|
||||
obj.TesseractOCRConverted = TesseractOCRConverted;
|
||||
|
||||
@@ -8,17 +8,37 @@ namespace SabreTools.Data.Models.OpenMSX
|
||||
/// </summary>
|
||||
public abstract class RomBase
|
||||
{
|
||||
[XmlElement("start")]
|
||||
public string? Start { get; set; }
|
||||
/// <remarks>
|
||||
/// "hash" in older versions, "sha1" in newer versions
|
||||
/// </remarks>
|
||||
[XmlAttribute("sha1")]
|
||||
[XmlElement("hash")]
|
||||
public string? SHA1 { get; set; }
|
||||
|
||||
/// <remarks>
|
||||
/// Element in older versions and DTD, attribute in newer versions
|
||||
/// </remarks>
|
||||
[XmlAttribute("type")]
|
||||
[XmlElement("type")]
|
||||
public string? Type { get; set; }
|
||||
|
||||
/// <remarks>SHA-1 hash</remarks>
|
||||
[XmlElement("hash")]
|
||||
public string? Hash { get; set; }
|
||||
/// <remarks>
|
||||
/// Only present in newer versions
|
||||
/// </remarks>
|
||||
[XmlAttribute("status")]
|
||||
public string? Status { get; set; }
|
||||
|
||||
/// <remarks>
|
||||
/// Element in older versions and DTD, attribute in newer versions
|
||||
/// </remarks>
|
||||
[XmlAttribute("remark")]
|
||||
[XmlElement("remark")]
|
||||
public string? Remark { get; set; }
|
||||
|
||||
/// <remarks>
|
||||
/// Only present in older versions
|
||||
/// </remarks>
|
||||
[XmlElement("start")]
|
||||
public string? Start { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,30 +6,63 @@ namespace SabreTools.Data.Models.OpenMSX
|
||||
[XmlRoot("software")]
|
||||
public class Software
|
||||
{
|
||||
/// <remarks>
|
||||
/// Element in older versions and DTD, attribute in newer versions
|
||||
/// </remarks>
|
||||
[Required]
|
||||
[XmlAttribute("title")]
|
||||
[XmlElement("title")]
|
||||
public string? Title { get; set; }
|
||||
|
||||
[XmlElement("genmsxid")]
|
||||
public string? GenMSXID { get; set; }
|
||||
|
||||
/// <remarks>
|
||||
/// Element in older versions and DTD, attribute in newer versions
|
||||
/// </remarks>
|
||||
[Required]
|
||||
[XmlAttribute("system")]
|
||||
[XmlElement("system")]
|
||||
public string? System { get; set; }
|
||||
|
||||
/// <remarks>
|
||||
/// Element in older versions and DTD, attribute in newer versions
|
||||
/// </remarks>
|
||||
[Required]
|
||||
[XmlAttribute("company")]
|
||||
[XmlElement("company")]
|
||||
public string? Company { get; set; }
|
||||
|
||||
/// <remarks>
|
||||
/// Element in older versions and DTD, attribute in newer versions
|
||||
/// </remarks>
|
||||
[Required]
|
||||
[XmlAttribute("year")]
|
||||
[XmlElement("year")]
|
||||
public string? Year { get; set; }
|
||||
|
||||
/// <remarks>
|
||||
/// Element in older versions and DTD, attribute in newer versions
|
||||
/// </remarks>
|
||||
[Required]
|
||||
[XmlAttribute("country")]
|
||||
[XmlElement("country")]
|
||||
public string? Country { get; set; }
|
||||
|
||||
/// <remarks>
|
||||
/// Element in older versions and DTD, attribute in newer versions
|
||||
/// </remarks>
|
||||
[XmlAttribute("genmsxid")]
|
||||
[XmlElement("genmsxid")]
|
||||
public string? GenMSXID { get; set; }
|
||||
|
||||
/// <remarks>
|
||||
/// Present in older versions
|
||||
/// </remarks>
|
||||
[XmlElement("dump")]
|
||||
public Dump[]? Dump { get; set; }
|
||||
|
||||
/// <remarks>
|
||||
/// Present in newer versions
|
||||
/// </remarks>
|
||||
[XmlElement("rom")]
|
||||
public RomBase[]? Rom { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,13 @@ namespace SabreTools.Data.Models.PKZIP
|
||||
/// File data, appears after the encryption header
|
||||
/// if it exists or after the local file header otherwise
|
||||
/// </summary>
|
||||
public byte[] FileData { get; set; } = [];
|
||||
/// Not read into the model, see <see cref="FileDataOffset"/>
|
||||
// public byte[] FileData { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Offset of the file data in the stream
|
||||
/// </summary>
|
||||
public long FileDataOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Data descriptors, appears after the file data
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;net11.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
@@ -12,7 +12,7 @@
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>3.0.1</Version>
|
||||
<Version>3.3.0</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
<PackageReference Include="SabreTools.IO" Version="[2.1.0]" />
|
||||
<PackageReference Include="SabreTools.IO" Version="2.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
24
SabreTools.Data.Models/UDF/AllocationExtentDescriptor.cs
Normal file
24
SabreTools.Data.Models/UDF/AllocationExtentDescriptor.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Allocation Extent Descriptor (4/14.5), continues the allocation descriptors of a File Entry
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class AllocationExtentDescriptor : Descriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Logical block of the previous allocation extent
|
||||
/// </summary>
|
||||
public uint PreviousAllocationExtentLocation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of the allocation descriptors in bytes
|
||||
/// </summary>
|
||||
public uint LengthOfAllocationDescriptors { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allocation descriptors, of the type given in the owning File Entry's ICB tag flags
|
||||
/// </summary>
|
||||
public byte[] AllocationDescriptors { get; set; } = [];
|
||||
}
|
||||
}
|
||||
24
SabreTools.Data.Models/UDF/AnchorVolumeDescriptorPointer.cs
Normal file
24
SabreTools.Data.Models/UDF/AnchorVolumeDescriptorPointer.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Anchor Volume Descriptor Pointer (3/10.2), recorded at sector 256 (and at the end of the volume)
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class AnchorVolumeDescriptorPointer : Descriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Extent of the Main Volume Descriptor Sequence
|
||||
/// </summary>
|
||||
public ExtentDescriptor MainVolumeDescriptorSequenceExtent { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Extent of the Reserve Volume Descriptor Sequence
|
||||
/// </summary>
|
||||
public ExtentDescriptor ReserveVolumeDescriptorSequenceExtent { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Reserved, 480 bytes of 0x00
|
||||
/// </summary>
|
||||
public byte[] Reserved { get; set; } = new byte[480];
|
||||
}
|
||||
}
|
||||
20
SabreTools.Data.Models/UDF/CharacterSetSpecification.cs
Normal file
20
SabreTools.Data.Models/UDF/CharacterSetSpecification.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Character Set Specification (charspec, 1/7.2.1)
|
||||
/// UDF requires CS0 with the information "OSTA Compressed Unicode"
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class CharacterSetSpecification
|
||||
{
|
||||
/// <summary>
|
||||
/// Character set type (0 = CS0)
|
||||
/// </summary>
|
||||
public byte CharacterSetType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Character set information, padded with 0x00
|
||||
/// </summary>
|
||||
public byte[] CharacterSetInformation { get; set; } = new byte[63];
|
||||
}
|
||||
}
|
||||
126
SabreTools.Data.Models/UDF/Constants.cs
Normal file
126
SabreTools.Data.Models/UDF/Constants.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF / ECMA-167 constant values and arrays
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
/// <see href="http://www.osta.org/specs/pdf/udf260.pdf"/>
|
||||
public static class Constants
|
||||
{
|
||||
#region Volume Recognition Constants
|
||||
|
||||
/// <summary>
|
||||
/// Size of a logical sector on optical media
|
||||
/// </summary>
|
||||
public const int SectorSize = 2048;
|
||||
|
||||
/// <summary>
|
||||
/// Sector of the first Volume Structure Descriptor (after the 32KiB System Area)
|
||||
/// </summary>
|
||||
public const int VolumeRecognitionSequenceSector = 16;
|
||||
|
||||
/// <summary>
|
||||
/// Sector of the first Anchor Volume Descriptor Pointer
|
||||
/// </summary>
|
||||
public const int AnchorVolumeDescriptorPointerSector = 256;
|
||||
|
||||
/// <summary>
|
||||
/// Beginning Extended Area Descriptor identifier, "BEA01"
|
||||
/// </summary>
|
||||
public static readonly byte[] BeginningExtendedAreaDescriptor = [0x42, 0x45, 0x41, 0x30, 0x31];
|
||||
|
||||
/// <summary>
|
||||
/// NSR Descriptor identifier for ECMA-167 2nd edition (UDF 1.02 to 1.50), "NSR02"
|
||||
/// </summary>
|
||||
public static readonly byte[] NSR02 = [0x4E, 0x53, 0x52, 0x30, 0x32];
|
||||
|
||||
/// <summary>
|
||||
/// NSR Descriptor identifier for ECMA-167 3rd edition (UDF 2.00 and later), "NSR03"
|
||||
/// </summary>
|
||||
public static readonly byte[] NSR03 = [0x4E, 0x53, 0x52, 0x30, 0x33];
|
||||
|
||||
/// <summary>
|
||||
/// Terminating Extended Area Descriptor identifier, "TEA01"
|
||||
/// </summary>
|
||||
public static readonly byte[] TerminatingExtendedAreaDescriptor = [0x54, 0x45, 0x41, 0x30, 0x31];
|
||||
|
||||
/// <summary>
|
||||
/// ISO 9660 volume descriptor identifier, "CD001" (bridge discs)
|
||||
/// </summary>
|
||||
public static readonly byte[] CD001 = [0x43, 0x44, 0x30, 0x30, 0x31];
|
||||
|
||||
/// <summary>
|
||||
/// Boot Descriptor identifier, "BOOT2"
|
||||
/// </summary>
|
||||
public static readonly byte[] BOOT2 = [0x42, 0x4F, 0x4F, 0x54, 0x32];
|
||||
|
||||
/// <summary>
|
||||
/// ECMA-168 volume descriptor identifier, "CDW02"
|
||||
/// </summary>
|
||||
public static readonly byte[] CDW02 = [0x43, 0x44, 0x57, 0x30, 0x32];
|
||||
|
||||
#endregion
|
||||
|
||||
#region Partition Map Constants
|
||||
|
||||
/// <summary>
|
||||
/// Type 1 Partition Map type
|
||||
/// </summary>
|
||||
public const byte Type1PartitionMap = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Type 2 Partition Map type
|
||||
/// </summary>
|
||||
public const byte Type2PartitionMap = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Partition type identifier of a UDF Metadata Partition (UDF 2.50 and later)
|
||||
/// </summary>
|
||||
public const string MetadataPartitionIdentifier = "*UDF Metadata Partition";
|
||||
|
||||
/// <summary>
|
||||
/// Partition type identifier of a UDF Sparable Partition
|
||||
/// </summary>
|
||||
public const string SparablePartitionIdentifier = "*UDF Sparable Partition";
|
||||
|
||||
/// <summary>
|
||||
/// Partition type identifier of a UDF Virtual Partition
|
||||
/// </summary>
|
||||
public const string VirtualPartitionIdentifier = "*UDF Virtual Partition";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Character Set Constants
|
||||
|
||||
/// <summary>
|
||||
/// OSTA Compressed Unicode, 8 bits per character
|
||||
/// </summary>
|
||||
public const byte CompressionId8 = 8;
|
||||
|
||||
/// <summary>
|
||||
/// OSTA Compressed Unicode, 16 bits per character (big-endian)
|
||||
/// </summary>
|
||||
public const byte CompressionId16 = 16;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Allocation Descriptor Constants
|
||||
|
||||
/// <summary>
|
||||
/// Mask of the extent length in an allocation descriptor (the top two bits hold the extent type)
|
||||
/// </summary>
|
||||
public const uint ExtentLengthMask = 0x3FFFFFFF;
|
||||
|
||||
/// <summary>
|
||||
/// Shift of the extent type in an allocation descriptor's extent length
|
||||
/// </summary>
|
||||
public const int ExtentTypeShift = 30;
|
||||
|
||||
/// <summary>
|
||||
/// Mask of the allocation descriptor type in an ICB tag's flags
|
||||
/// </summary>
|
||||
public const ushort AllocationDescriptorTypeMask = 0x0007;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
14
SabreTools.Data.Models/UDF/Descriptor.cs
Normal file
14
SabreTools.Data.Models/UDF/Descriptor.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// Abstract UDF tagged descriptor, all start with a Descriptor Tag
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public abstract class Descriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Descriptor tag
|
||||
/// </summary>
|
||||
public DescriptorTag DescriptorTag { get; set; } = new();
|
||||
}
|
||||
}
|
||||
50
SabreTools.Data.Models/UDF/DescriptorTag.cs
Normal file
50
SabreTools.Data.Models/UDF/DescriptorTag.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Descriptor Tag (3/7.2), the first 16 bytes of every tagged descriptor
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class DescriptorTag
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of the descriptor
|
||||
/// </summary>
|
||||
public TagIdentifier TagIdentifier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Version of the descriptor, 2 (ECMA-167 2nd edition) or 3 (3rd edition)
|
||||
/// </summary>
|
||||
public ushort DescriptorVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sum modulo 256 of bytes 0-3 and 5-15 of the tag
|
||||
/// </summary>
|
||||
public byte TagChecksum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reserved, 0x00
|
||||
/// </summary>
|
||||
public byte Reserved { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Identification of a set of descriptors
|
||||
/// </summary>
|
||||
public ushort TagSerialNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// CRC-CCITT of the DescriptorCRCLength bytes following the tag
|
||||
/// </summary>
|
||||
public ushort DescriptorCRC { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of bytes after the tag covered by the DescriptorCRC
|
||||
/// </summary>
|
||||
public ushort DescriptorCRCLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of the logical sector (volume structures) or logical block (file structures)
|
||||
/// in which the descriptor is recorded
|
||||
/// </summary>
|
||||
public uint TagLocation { get; set; }
|
||||
}
|
||||
}
|
||||
24
SabreTools.Data.Models/UDF/EntityIdentifier.cs
Normal file
24
SabreTools.Data.Models/UDF/EntityIdentifier.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Entity Identifier (regid, 1/7.4)
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class EntityIdentifier
|
||||
{
|
||||
/// <summary>
|
||||
/// Flags (bit 0: dirty, bit 1: protected)
|
||||
/// </summary>
|
||||
public byte Flags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Identifier, padded with 0x00
|
||||
/// </summary>
|
||||
public byte[] Identifier { get; set; } = new byte[23];
|
||||
|
||||
/// <summary>
|
||||
/// Identifier suffix (UDF domain identifiers: revision as a little-endian ushort, then domain flags)
|
||||
/// </summary>
|
||||
public byte[] IdentifierSuffix { get; set; } = new byte[8];
|
||||
}
|
||||
}
|
||||
306
SabreTools.Data.Models/UDF/Enums.cs
Normal file
306
SabreTools.Data.Models/UDF/Enums.cs
Normal file
@@ -0,0 +1,306 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum for DescriptorTag.TagIdentifier
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public enum TagIdentifier : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// Primary Volume Descriptor (3/10.1)
|
||||
/// </summary>
|
||||
PRIMARY_VOLUME_DESCRIPTOR = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Anchor Volume Descriptor Pointer (3/10.2)
|
||||
/// </summary>
|
||||
ANCHOR_VOLUME_DESCRIPTOR_POINTER = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Volume Descriptor Pointer (3/10.3)
|
||||
/// </summary>
|
||||
VOLUME_DESCRIPTOR_POINTER = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Implementation Use Volume Descriptor (3/10.4)
|
||||
/// </summary>
|
||||
IMPLEMENTATION_USE_VOLUME_DESCRIPTOR = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Partition Descriptor (3/10.5)
|
||||
/// </summary>
|
||||
PARTITION_DESCRIPTOR = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Logical Volume Descriptor (3/10.6)
|
||||
/// </summary>
|
||||
LOGICAL_VOLUME_DESCRIPTOR = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Unallocated Space Descriptor (3/10.8)
|
||||
/// </summary>
|
||||
UNALLOCATED_SPACE_DESCRIPTOR = 7,
|
||||
|
||||
/// <summary>
|
||||
/// Terminating Descriptor (3/10.9)
|
||||
/// </summary>
|
||||
TERMINATING_DESCRIPTOR = 8,
|
||||
|
||||
/// <summary>
|
||||
/// Logical Volume Integrity Descriptor (3/10.10)
|
||||
/// </summary>
|
||||
LOGICAL_VOLUME_INTEGRITY_DESCRIPTOR = 9,
|
||||
|
||||
/// <summary>
|
||||
/// File Set Descriptor (4/14.1)
|
||||
/// </summary>
|
||||
FILE_SET_DESCRIPTOR = 256,
|
||||
|
||||
/// <summary>
|
||||
/// File Identifier Descriptor (4/14.4)
|
||||
/// </summary>
|
||||
FILE_IDENTIFIER_DESCRIPTOR = 257,
|
||||
|
||||
/// <summary>
|
||||
/// Allocation Extent Descriptor (4/14.5)
|
||||
/// </summary>
|
||||
ALLOCATION_EXTENT_DESCRIPTOR = 258,
|
||||
|
||||
/// <summary>
|
||||
/// Indirect Entry (4/14.7)
|
||||
/// </summary>
|
||||
INDIRECT_ENTRY = 259,
|
||||
|
||||
/// <summary>
|
||||
/// Terminal Entry (4/14.8)
|
||||
/// </summary>
|
||||
TERMINAL_ENTRY = 260,
|
||||
|
||||
/// <summary>
|
||||
/// File Entry (4/14.9)
|
||||
/// </summary>
|
||||
FILE_ENTRY = 261,
|
||||
|
||||
/// <summary>
|
||||
/// Extended Attribute Header Descriptor (4/14.10.1)
|
||||
/// </summary>
|
||||
EXTENDED_ATTRIBUTE_HEADER_DESCRIPTOR = 262,
|
||||
|
||||
/// <summary>
|
||||
/// Unallocated Space Entry (4/14.11)
|
||||
/// </summary>
|
||||
UNALLOCATED_SPACE_ENTRY = 263,
|
||||
|
||||
/// <summary>
|
||||
/// Space Bitmap Descriptor (4/14.12)
|
||||
/// </summary>
|
||||
SPACE_BITMAP_DESCRIPTOR = 264,
|
||||
|
||||
/// <summary>
|
||||
/// Partition Integrity Entry (4/14.13)
|
||||
/// </summary>
|
||||
PARTITION_INTEGRITY_ENTRY = 265,
|
||||
|
||||
/// <summary>
|
||||
/// Extended File Entry (4/14.17)
|
||||
/// </summary>
|
||||
EXTENDED_FILE_ENTRY = 266,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enum for FileIdentifierDescriptor.FileCharacteristics (4/14.4.3)
|
||||
/// Bits 5-7: Reserved: 0
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
[Flags]
|
||||
public enum FileCharacteristics : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// No characteristics set
|
||||
/// </summary>
|
||||
NONE = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// The existence of the file shall not be made known to the user (hidden)
|
||||
/// </summary>
|
||||
EXISTENCE = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// The file is a directory
|
||||
/// </summary>
|
||||
DIRECTORY = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// The descriptor shall be ignored (deleted)
|
||||
/// </summary>
|
||||
DELETED = 0x04,
|
||||
|
||||
/// <summary>
|
||||
/// The ICB identifies the parent directory
|
||||
/// </summary>
|
||||
PARENT = 0x08,
|
||||
|
||||
/// <summary>
|
||||
/// The file contains implementation use data (UDF: stream directory metadata)
|
||||
/// </summary>
|
||||
METADATA = 0x10,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enum for ICBTag.FileType (4/14.6.6, UDF 2.3.5.4)
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public enum FileType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Not specified
|
||||
/// </summary>
|
||||
UNSPECIFIED = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Unallocated Space Entry
|
||||
/// </summary>
|
||||
UNALLOCATED_SPACE_ENTRY = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Partition Integrity Entry
|
||||
/// </summary>
|
||||
PARTITION_INTEGRITY_ENTRY = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Indirect Entry
|
||||
/// </summary>
|
||||
INDIRECT_ENTRY = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Directory
|
||||
/// </summary>
|
||||
DIRECTORY = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Sequence of bytes (a regular file)
|
||||
/// </summary>
|
||||
FILE = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Block special device
|
||||
/// </summary>
|
||||
BLOCK_DEVICE = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Character special device
|
||||
/// </summary>
|
||||
CHARACTER_DEVICE = 7,
|
||||
|
||||
/// <summary>
|
||||
/// Extended attributes
|
||||
/// </summary>
|
||||
EXTENDED_ATTRIBUTES = 8,
|
||||
|
||||
/// <summary>
|
||||
/// FIFO file
|
||||
/// </summary>
|
||||
FIFO = 9,
|
||||
|
||||
/// <summary>
|
||||
/// Socket
|
||||
/// </summary>
|
||||
SOCKET = 10,
|
||||
|
||||
/// <summary>
|
||||
/// Terminal Entry
|
||||
/// </summary>
|
||||
TERMINAL_ENTRY = 11,
|
||||
|
||||
/// <summary>
|
||||
/// Symbolic link
|
||||
/// </summary>
|
||||
SYMBOLIC_LINK = 12,
|
||||
|
||||
/// <summary>
|
||||
/// Stream directory
|
||||
/// </summary>
|
||||
STREAM_DIRECTORY = 13,
|
||||
|
||||
/// <summary>
|
||||
/// UDF Virtual Allocation Table
|
||||
/// </summary>
|
||||
VIRTUAL_ALLOCATION_TABLE = 248,
|
||||
|
||||
/// <summary>
|
||||
/// UDF Real-Time file
|
||||
/// </summary>
|
||||
REAL_TIME_FILE = 249,
|
||||
|
||||
/// <summary>
|
||||
/// UDF Metadata File
|
||||
/// </summary>
|
||||
METADATA_FILE = 250,
|
||||
|
||||
/// <summary>
|
||||
/// UDF Metadata Mirror File
|
||||
/// </summary>
|
||||
METADATA_MIRROR_FILE = 251,
|
||||
|
||||
/// <summary>
|
||||
/// UDF Metadata Bitmap File
|
||||
/// </summary>
|
||||
METADATA_BITMAP_FILE = 252,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enum for the allocation descriptor type in ICBTag.Flags (4/14.6.8)
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public enum AllocationDescriptorType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Short Allocation Descriptors (4/14.14.1)
|
||||
/// </summary>
|
||||
SHORT = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Long Allocation Descriptors (4/14.14.2)
|
||||
/// </summary>
|
||||
LONG = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Extended Allocation Descriptors (4/14.14.3)
|
||||
/// </summary>
|
||||
EXTENDED = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The file data is embedded in the allocation descriptors field
|
||||
/// </summary>
|
||||
EMBEDDED = 3,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enum for the extent type in the top two bits of an allocation descriptor's extent length (4/14.14.1.1)
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public enum ExtentType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Extent recorded and allocated
|
||||
/// </summary>
|
||||
RECORDED_AND_ALLOCATED = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Extent not recorded but allocated
|
||||
/// </summary>
|
||||
NOT_RECORDED_BUT_ALLOCATED = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Extent not recorded and not allocated
|
||||
/// </summary>
|
||||
NOT_RECORDED_NOT_ALLOCATED = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The extent is the next extent of allocation descriptors
|
||||
/// </summary>
|
||||
NEXT_EXTENT = 3,
|
||||
}
|
||||
}
|
||||
30
SabreTools.Data.Models/UDF/ExtendedFileEntry.cs
Normal file
30
SabreTools.Data.Models/UDF/ExtendedFileEntry.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Extended File Entry (4/14.17, UDF 2.00 and later), a File Entry with object size,
|
||||
/// creation time and a stream directory
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class ExtendedFileEntry : FileEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Size of the file and its streams in bytes
|
||||
/// </summary>
|
||||
public ulong ObjectSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creation date and time
|
||||
/// </summary>
|
||||
public Timestamp CreationDateAndTime { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Reserved, 0x00000000
|
||||
/// </summary>
|
||||
public uint Reserved { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ICB of the stream directory, length 0 if none
|
||||
/// </summary>
|
||||
public LongAllocationDescriptor StreamDirectoryICB { get; set; } = new();
|
||||
}
|
||||
}
|
||||
19
SabreTools.Data.Models/UDF/ExtentDescriptor.cs
Normal file
19
SabreTools.Data.Models/UDF/ExtentDescriptor.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Extent Descriptor (extent_ad, 3/7.1), an extent of logical sectors
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class ExtentDescriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Length of the extent in bytes
|
||||
/// </summary>
|
||||
public uint ExtentLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Logical sector number of the start of the extent
|
||||
/// </summary>
|
||||
public uint ExtentLocation { get; set; }
|
||||
}
|
||||
}
|
||||
115
SabreTools.Data.Models/UDF/FileEntry.cs
Normal file
115
SabreTools.Data.Models/UDF/FileEntry.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF File Entry (4/14.9), the ICB describing a file or directory and where its data is recorded
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public class FileEntry : Descriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// ICB tag
|
||||
/// </summary>
|
||||
public ICBTag ICBTag { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// User ID
|
||||
/// </summary>
|
||||
public uint Uid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Group ID
|
||||
/// </summary>
|
||||
public uint Gid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Permissions
|
||||
/// </summary>
|
||||
public uint Permissions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of File Identifier Descriptors identifying this ICB
|
||||
/// </summary>
|
||||
public ushort FileLinkCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Record format
|
||||
/// </summary>
|
||||
public byte RecordFormat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Record display attributes
|
||||
/// </summary>
|
||||
public byte RecordDisplayAttributes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Record length
|
||||
/// </summary>
|
||||
public uint RecordLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the file in bytes
|
||||
/// </summary>
|
||||
public ulong InformationLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of recorded logical blocks
|
||||
/// </summary>
|
||||
public ulong LogicalBlocksRecorded { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Access date and time
|
||||
/// </summary>
|
||||
public Timestamp AccessDateAndTime { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Modification date and time
|
||||
/// </summary>
|
||||
public Timestamp ModificationDateAndTime { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Attribute date and time
|
||||
/// </summary>
|
||||
public Timestamp AttributeDateAndTime { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Checkpoint
|
||||
/// </summary>
|
||||
public uint Checkpoint { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ICB of the extended attributes, length 0 if none
|
||||
/// </summary>
|
||||
public LongAllocationDescriptor ExtendedAttributeICB { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Implementation identifier
|
||||
/// </summary>
|
||||
public EntityIdentifier ImplementationIdentifier { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Unique ID
|
||||
/// </summary>
|
||||
public ulong UniqueID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of the extended attributes in bytes
|
||||
/// </summary>
|
||||
public uint LengthOfExtendedAttributes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of the allocation descriptors in bytes
|
||||
/// </summary>
|
||||
public uint LengthOfAllocationDescriptors { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Extended attributes
|
||||
/// </summary>
|
||||
public byte[] ExtendedAttributes { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Allocation descriptors of the type given in the ICB tag flags,
|
||||
/// or the file data itself if the type is AllocationDescriptorType.EMBEDDED
|
||||
/// </summary>
|
||||
public byte[] AllocationDescriptors { get; set; } = [];
|
||||
}
|
||||
}
|
||||
49
SabreTools.Data.Models/UDF/FileIdentifierDescriptor.cs
Normal file
49
SabreTools.Data.Models/UDF/FileIdentifierDescriptor.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF File Identifier Descriptor (4/14.4), a directory entry naming a file or directory and pointing to its ICB
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class FileIdentifierDescriptor : Descriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// File version number
|
||||
/// </summary>
|
||||
public ushort FileVersionNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// File characteristics
|
||||
/// </summary>
|
||||
public FileCharacteristics FileCharacteristics { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of the file identifier in bytes
|
||||
/// </summary>
|
||||
public byte LengthOfFileIdentifier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ICB of the file or directory
|
||||
/// </summary>
|
||||
public LongAllocationDescriptor ICB { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Length of the implementation use in bytes
|
||||
/// </summary>
|
||||
public ushort LengthOfImplementationUse { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implementation use
|
||||
/// </summary>
|
||||
public byte[] ImplementationUse { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// File identifier, d-characters (first byte = compression ID), empty for the parent directory
|
||||
/// </summary>
|
||||
public byte[] FileIdentifier { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Padding to a multiple of 4 bytes
|
||||
/// </summary>
|
||||
public byte[] Padding { get; set; } = [];
|
||||
}
|
||||
}
|
||||
99
SabreTools.Data.Models/UDF/FileSetDescriptor.cs
Normal file
99
SabreTools.Data.Models/UDF/FileSetDescriptor.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF File Set Descriptor (4/14.1), the location of the root directory
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class FileSetDescriptor : Descriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Recording date and time
|
||||
/// </summary>
|
||||
public Timestamp RecordingDateAndTime { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Interchange level
|
||||
/// </summary>
|
||||
public ushort InterchangeLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum interchange level
|
||||
/// </summary>
|
||||
public ushort MaximumInterchangeLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Character set list
|
||||
/// </summary>
|
||||
public uint CharacterSetList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum character set list
|
||||
/// </summary>
|
||||
public uint MaximumCharacterSetList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// File set number
|
||||
/// </summary>
|
||||
public uint FileSetNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// File Set Descriptor number
|
||||
/// </summary>
|
||||
public uint FileSetDescriptorNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Logical volume identifier character set
|
||||
/// </summary>
|
||||
public CharacterSetSpecification LogicalVolumeIdentifierCharacterSet { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Logical volume identifier, dstring (last byte = length)
|
||||
/// </summary>
|
||||
public byte[] LogicalVolumeIdentifier { get; set; } = new byte[128];
|
||||
|
||||
/// <summary>
|
||||
/// File set character set
|
||||
/// </summary>
|
||||
public CharacterSetSpecification FileSetCharacterSet { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// File set identifier, dstring (last byte = length)
|
||||
/// </summary>
|
||||
public byte[] FileSetIdentifier { get; set; } = new byte[32];
|
||||
|
||||
/// <summary>
|
||||
/// Copyright file identifier, dstring (last byte = length)
|
||||
/// </summary>
|
||||
public byte[] CopyrightFileIdentifier { get; set; } = new byte[32];
|
||||
|
||||
/// <summary>
|
||||
/// Abstract file identifier, dstring (last byte = length)
|
||||
/// </summary>
|
||||
public byte[] AbstractFileIdentifier { get; set; } = new byte[32];
|
||||
|
||||
/// <summary>
|
||||
/// ICB of the root directory
|
||||
/// </summary>
|
||||
public LongAllocationDescriptor RootDirectoryICB { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Domain identifier
|
||||
/// </summary>
|
||||
public EntityIdentifier DomainIdentifier { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Next extent of File Set Descriptors, length 0 if none
|
||||
/// </summary>
|
||||
public LongAllocationDescriptor NextExtent { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// ICB of the system stream directory (ECMA-167 3rd edition), length 0 if none
|
||||
/// </summary>
|
||||
public LongAllocationDescriptor SystemStreamDirectoryICB { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Reserved, 32 bytes of 0x00
|
||||
/// </summary>
|
||||
public byte[] Reserved { get; set; } = new byte[32];
|
||||
}
|
||||
}
|
||||
15
SabreTools.Data.Models/UDF/GenericDescriptor.cs
Normal file
15
SabreTools.Data.Models/UDF/GenericDescriptor.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF tagged descriptor of a type that is not parsed further
|
||||
/// (e.g. Implementation Use Volume Descriptor, Unallocated Space Descriptor, Terminating Descriptor)
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class GenericDescriptor : Descriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Contents of the descriptor after the tag, up to the end of the logical sector
|
||||
/// </summary>
|
||||
public byte[] Data { get; set; } = [];
|
||||
}
|
||||
}
|
||||
49
SabreTools.Data.Models/UDF/ICBTag.cs
Normal file
49
SabreTools.Data.Models/UDF/ICBTag.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Information Control Block Tag (icbtag, 4/14.6)
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class ICBTag
|
||||
{
|
||||
/// <summary>
|
||||
/// Prior recorded number of direct entries
|
||||
/// </summary>
|
||||
public uint PriorRecordedNumberOfDirectEntries { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Strategy type (UDF: 4, or 4096 for write-once media)
|
||||
/// </summary>
|
||||
public ushort StrategyType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Strategy parameter, 2 bytes
|
||||
/// </summary>
|
||||
public byte[] StrategyParameter { get; set; } = new byte[2];
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of entries
|
||||
/// </summary>
|
||||
public ushort MaximumNumberOfEntries { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reserved, 0x00
|
||||
/// </summary>
|
||||
public byte Reserved { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// File type
|
||||
/// </summary>
|
||||
public FileType FileType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Parent ICB location
|
||||
/// </summary>
|
||||
public LogicalBlockAddress ParentICBLocation { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Flags, the lower 3 bits hold the AllocationDescriptorType
|
||||
/// </summary>
|
||||
public ushort Flags { get; set; }
|
||||
}
|
||||
}
|
||||
19
SabreTools.Data.Models/UDF/LogicalBlockAddress.cs
Normal file
19
SabreTools.Data.Models/UDF/LogicalBlockAddress.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Recorded Address (lb_addr, 4/7.1), a logical block within a partition
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class LogicalBlockAddress
|
||||
{
|
||||
/// <summary>
|
||||
/// Logical block number, relative to the start of the partition
|
||||
/// </summary>
|
||||
public uint LogicalBlockNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Index of the partition map in the Logical Volume Descriptor
|
||||
/// </summary>
|
||||
public ushort PartitionReferenceNumber { get; set; }
|
||||
}
|
||||
}
|
||||
69
SabreTools.Data.Models/UDF/LogicalVolumeDescriptor.cs
Normal file
69
SabreTools.Data.Models/UDF/LogicalVolumeDescriptor.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Logical Volume Descriptor (3/10.6), block size, partition maps and the location of the File Set Descriptor
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class LogicalVolumeDescriptor : Descriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Volume Descriptor Sequence Number, the highest number prevails
|
||||
/// </summary>
|
||||
public uint VolumeDescriptorSequenceNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Descriptor character set
|
||||
/// </summary>
|
||||
public CharacterSetSpecification DescriptorCharacterSet { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Logical volume identifier, dstring (last byte = length)
|
||||
/// </summary>
|
||||
public byte[] LogicalVolumeIdentifier { get; set; } = new byte[128];
|
||||
|
||||
/// <summary>
|
||||
/// Size of a logical block in bytes
|
||||
/// </summary>
|
||||
public uint LogicalBlockSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Domain identifier ("*OSTA UDF Compliant", suffix holds the UDF revision)
|
||||
/// </summary>
|
||||
public EntityIdentifier DomainIdentifier { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Logical volume contents use (UDF: extent of the File Set Descriptor)
|
||||
/// </summary>
|
||||
public LongAllocationDescriptor LogicalVolumeContentsUse { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Length of the partition maps in bytes
|
||||
/// </summary>
|
||||
public uint MapTableLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of partition maps
|
||||
/// </summary>
|
||||
public uint NumberOfPartitionMaps { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implementation identifier
|
||||
/// </summary>
|
||||
public EntityIdentifier ImplementationIdentifier { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Implementation use, 128 bytes
|
||||
/// </summary>
|
||||
public byte[] ImplementationUse { get; set; } = new byte[128];
|
||||
|
||||
/// <summary>
|
||||
/// Extent of the Logical Volume Integrity Sequence
|
||||
/// </summary>
|
||||
public ExtentDescriptor IntegritySequenceExtent { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Partition maps, a partition reference number is the index into this array
|
||||
/// </summary>
|
||||
public PartitionMap[] PartitionMaps { get; set; } = [];
|
||||
}
|
||||
}
|
||||
25
SabreTools.Data.Models/UDF/LongAllocationDescriptor.cs
Normal file
25
SabreTools.Data.Models/UDF/LongAllocationDescriptor.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Long Allocation Descriptor (long_ad, 4/14.14.2), an extent within any partition of the logical volume
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class LongAllocationDescriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Length of the extent in bytes (lower 30 bits) and the ExtentType (upper 2 bits)
|
||||
/// A length of 0 terminates a sequence of allocation descriptors
|
||||
/// </summary>
|
||||
public uint ExtentLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Logical block address of the start of the extent
|
||||
/// </summary>
|
||||
public LogicalBlockAddress ExtentLocation { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Implementation use (UDF: flags and unique ID bits)
|
||||
/// </summary>
|
||||
public byte[] ImplementationUse { get; set; } = new byte[6];
|
||||
}
|
||||
}
|
||||
45
SabreTools.Data.Models/UDF/MetadataPartitionMap.cs
Normal file
45
SabreTools.Data.Models/UDF/MetadataPartitionMap.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Metadata Partition Map (UDF 2.2.10, UDF 2.50 and later), a partition whose logical blocks
|
||||
/// are the contents of the Metadata File recorded in the underlying partition
|
||||
/// </summary>
|
||||
/// <see href="http://www.osta.org/specs/pdf/udf260.pdf"/>
|
||||
public sealed class MetadataPartitionMap : Type2PartitionMap
|
||||
{
|
||||
/// <summary>
|
||||
/// Logical block of the Metadata File's File Entry in the underlying partition
|
||||
/// </summary>
|
||||
public uint MetadataFileLocation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Logical block of the Metadata Mirror File's File Entry in the underlying partition
|
||||
/// </summary>
|
||||
public uint MetadataMirrorFileLocation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Logical block of the Metadata Bitmap File's File Entry, 0xFFFFFFFF if not recorded
|
||||
/// </summary>
|
||||
public uint MetadataBitmapFileLocation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allocation unit size in logical blocks
|
||||
/// </summary>
|
||||
public uint AllocationUnitSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Alignment unit size in logical blocks
|
||||
/// </summary>
|
||||
public ushort AlignmentUnitSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Flags (bit 0: duplicate metadata flag)
|
||||
/// </summary>
|
||||
public byte Flags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reserved, 5 bytes of 0x00
|
||||
/// </summary>
|
||||
public byte[] Reserved2 { get; set; } = new byte[5];
|
||||
}
|
||||
}
|
||||
64
SabreTools.Data.Models/UDF/PartitionDescriptor.cs
Normal file
64
SabreTools.Data.Models/UDF/PartitionDescriptor.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Partition Descriptor (3/10.5), the physical location of a partition
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class PartitionDescriptor : Descriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Volume Descriptor Sequence Number, the highest number prevails
|
||||
/// </summary>
|
||||
public uint VolumeDescriptorSequenceNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Partition flags (bit 0: space is allocated)
|
||||
/// </summary>
|
||||
public ushort PartitionFlags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Partition number, referenced by the partition maps
|
||||
/// </summary>
|
||||
public ushort PartitionNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Partition contents ("+NSR02" or "+NSR03" for UDF)
|
||||
/// </summary>
|
||||
public EntityIdentifier PartitionContents { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Partition contents use (Partition Header Descriptor for NSR), 128 bytes
|
||||
/// </summary>
|
||||
public byte[] PartitionContentsUse { get; set; } = new byte[128];
|
||||
|
||||
/// <summary>
|
||||
/// Access type (1 = read-only, 2 = write-once, 3 = rewritable, 4 = overwritable)
|
||||
/// </summary>
|
||||
public uint AccessType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Logical sector number of the first sector of the partition
|
||||
/// </summary>
|
||||
public uint PartitionStartingLocation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of the partition in logical sectors
|
||||
/// </summary>
|
||||
public uint PartitionLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implementation identifier
|
||||
/// </summary>
|
||||
public EntityIdentifier ImplementationIdentifier { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Implementation use, 128 bytes
|
||||
/// </summary>
|
||||
public byte[] ImplementationUse { get; set; } = new byte[128];
|
||||
|
||||
/// <summary>
|
||||
/// Reserved, 156 bytes of 0x00
|
||||
/// </summary>
|
||||
public byte[] Reserved { get; set; } = new byte[156];
|
||||
}
|
||||
}
|
||||
19
SabreTools.Data.Models/UDF/PartitionMap.cs
Normal file
19
SabreTools.Data.Models/UDF/PartitionMap.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// Abstract UDF Partition Map (3/10.7)
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public abstract class PartitionMap
|
||||
{
|
||||
/// <summary>
|
||||
/// Partition map type (1 or 2)
|
||||
/// </summary>
|
||||
public byte PartitionMapType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of the partition map in bytes
|
||||
/// </summary>
|
||||
public byte PartitionMapLength { get; set; }
|
||||
}
|
||||
}
|
||||
114
SabreTools.Data.Models/UDF/PrimaryVolumeDescriptor.cs
Normal file
114
SabreTools.Data.Models/UDF/PrimaryVolumeDescriptor.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Primary Volume Descriptor (3/10.1)
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class PrimaryVolumeDescriptor : Descriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Volume Descriptor Sequence Number, the highest number prevails
|
||||
/// </summary>
|
||||
public uint VolumeDescriptorSequenceNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Primary Volume Descriptor Number
|
||||
/// </summary>
|
||||
public uint PrimaryVolumeDescriptorNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Volume identifier, dstring (last byte = length)
|
||||
/// </summary>
|
||||
public byte[] VolumeIdentifier { get; set; } = new byte[32];
|
||||
|
||||
/// <summary>
|
||||
/// Volume sequence number
|
||||
/// </summary>
|
||||
public ushort VolumeSequenceNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum volume sequence number
|
||||
/// </summary>
|
||||
public ushort MaximumVolumeSequenceNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Interchange level
|
||||
/// </summary>
|
||||
public ushort InterchangeLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum interchange level
|
||||
/// </summary>
|
||||
public ushort MaximumInterchangeLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Character set list
|
||||
/// </summary>
|
||||
public uint CharacterSetList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum character set list
|
||||
/// </summary>
|
||||
public uint MaximumCharacterSetList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Volume set identifier, dstring (last byte = length)
|
||||
/// </summary>
|
||||
public byte[] VolumeSetIdentifier { get; set; } = new byte[128];
|
||||
|
||||
/// <summary>
|
||||
/// Descriptor character set
|
||||
/// </summary>
|
||||
public CharacterSetSpecification DescriptorCharacterSet { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Explanatory character set
|
||||
/// </summary>
|
||||
public CharacterSetSpecification ExplanatoryCharacterSet { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Extent of the volume abstract
|
||||
/// </summary>
|
||||
public ExtentDescriptor VolumeAbstract { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Extent of the volume copyright notice
|
||||
/// </summary>
|
||||
public ExtentDescriptor VolumeCopyrightNotice { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Application identifier
|
||||
/// </summary>
|
||||
public EntityIdentifier ApplicationIdentifier { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Recording date and time
|
||||
/// </summary>
|
||||
public Timestamp RecordingDateAndTime { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Implementation identifier
|
||||
/// </summary>
|
||||
public EntityIdentifier ImplementationIdentifier { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Implementation use, 64 bytes
|
||||
/// </summary>
|
||||
public byte[] ImplementationUse { get; set; } = new byte[64];
|
||||
|
||||
/// <summary>
|
||||
/// Predecessor Volume Descriptor Sequence location
|
||||
/// </summary>
|
||||
public uint PredecessorVolumeDescriptorSequenceLocation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Flags (bit 0: volume set identification is common to all volumes of the set)
|
||||
/// </summary>
|
||||
public ushort Flags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reserved, 22 bytes of 0x00
|
||||
/// </summary>
|
||||
public byte[] Reserved { get; set; } = new byte[22];
|
||||
}
|
||||
}
|
||||
20
SabreTools.Data.Models/UDF/ShortAllocationDescriptor.cs
Normal file
20
SabreTools.Data.Models/UDF/ShortAllocationDescriptor.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Short Allocation Descriptor (short_ad, 4/14.14.1), an extent within the partition of the descriptor
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class ShortAllocationDescriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Length of the extent in bytes (lower 30 bits) and the ExtentType (upper 2 bits)
|
||||
/// A length of 0 terminates a sequence of allocation descriptors
|
||||
/// </summary>
|
||||
public uint ExtentLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Logical block number of the start of the extent
|
||||
/// </summary>
|
||||
public uint ExtentPosition { get; set; }
|
||||
}
|
||||
}
|
||||
60
SabreTools.Data.Models/UDF/Timestamp.cs
Normal file
60
SabreTools.Data.Models/UDF/Timestamp.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Timestamp (1/7.3)
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class Timestamp
|
||||
{
|
||||
/// <summary>
|
||||
/// Type (upper 4 bits, 1 = local time) and time zone offset from UTC in minutes
|
||||
/// (lower 12 bits, signed, -2047 = not specified)
|
||||
/// </summary>
|
||||
public ushort TypeAndTimezone { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Year, 1 to 9999
|
||||
/// </summary>
|
||||
public short Year { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Month, 1 to 12
|
||||
/// </summary>
|
||||
public byte Month { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Day, 1 to 31
|
||||
/// </summary>
|
||||
public byte Day { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Hour, 0 to 23
|
||||
/// </summary>
|
||||
public byte Hour { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Minute, 0 to 59
|
||||
/// </summary>
|
||||
public byte Minute { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Second, 0 to 59
|
||||
/// </summary>
|
||||
public byte Second { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Centiseconds, 0 to 99
|
||||
/// </summary>
|
||||
public byte Centiseconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Hundreds of microseconds, 0 to 99
|
||||
/// </summary>
|
||||
public byte HundredsOfMicroseconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Microseconds, 0 to 99
|
||||
/// </summary>
|
||||
public byte Microseconds { get; set; }
|
||||
}
|
||||
}
|
||||
19
SabreTools.Data.Models/UDF/Type1PartitionMap.cs
Normal file
19
SabreTools.Data.Models/UDF/Type1PartitionMap.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Type 1 Partition Map (3/10.7.2), logical blocks map 1:1 onto a Partition Descriptor's sectors
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class Type1PartitionMap : PartitionMap
|
||||
{
|
||||
/// <summary>
|
||||
/// Volume sequence number of the volume containing the partition
|
||||
/// </summary>
|
||||
public ushort VolumeSequenceNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Partition number of the Partition Descriptor
|
||||
/// </summary>
|
||||
public ushort PartitionNumber { get; set; }
|
||||
}
|
||||
}
|
||||
37
SabreTools.Data.Models/UDF/Type2PartitionMap.cs
Normal file
37
SabreTools.Data.Models/UDF/Type2PartitionMap.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Type 2 Partition Map (3/10.7.3, UDF 2.2.8-2.2.10), a partition identified by its partition type identifier
|
||||
/// (e.g. "*UDF Virtual Partition", "*UDF Sparable Partition", "*UDF Metadata Partition")
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
/// <see href="http://www.osta.org/specs/pdf/udf260.pdf"/>
|
||||
public class Type2PartitionMap : PartitionMap
|
||||
{
|
||||
/// <summary>
|
||||
/// Reserved, 2 bytes of 0x00
|
||||
/// </summary>
|
||||
public byte[] Reserved { get; set; } = new byte[2];
|
||||
|
||||
/// <summary>
|
||||
/// Partition type identifier
|
||||
/// </summary>
|
||||
public EntityIdentifier PartitionTypeIdentifier { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Volume sequence number of the volume containing the partition
|
||||
/// </summary>
|
||||
public ushort VolumeSequenceNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Partition number of the underlying Partition Descriptor
|
||||
/// </summary>
|
||||
public ushort PartitionNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Partition type specific data after the partition number, 24 bytes
|
||||
/// Empty for partition types that are parsed further (MetadataPartitionMap)
|
||||
/// </summary>
|
||||
public byte[] PartitionTypeData { get; set; } = [];
|
||||
}
|
||||
}
|
||||
52
SabreTools.Data.Models/UDF/Volume.cs
Normal file
52
SabreTools.Data.Models/UDF/Volume.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// A volume (or disc image) with a UDF / ECMA-167 file system
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Logical sectors and logical blocks are 2048 bytes on optical media
|
||||
/// File system structures are addressed by logical block address (partition reference number + logical block);
|
||||
/// dictionaries are keyed by ((long)PartitionReferenceNumber << 32) | LogicalBlockNumber
|
||||
/// </remarks>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
/// <see href="http://www.osta.org/specs/pdf/udf260.pdf"/>
|
||||
public sealed class Volume
|
||||
{
|
||||
/// <summary>
|
||||
/// Volume Recognition Sequence starting at sector 16
|
||||
/// </summary>
|
||||
public VolumeStructureDescriptor[] VolumeRecognitionSequence { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Anchor Volume Descriptor Pointer
|
||||
/// </summary>
|
||||
public AnchorVolumeDescriptorPointer? AnchorVolumeDescriptorPointer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Volume Descriptor Sequence (Primary, Partition, Logical Volume, ... up to the Terminating Descriptor)
|
||||
/// </summary>
|
||||
public Descriptor[] VolumeDescriptorSequence { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// File Set Descriptor
|
||||
/// </summary>
|
||||
public FileSetDescriptor? FileSetDescriptor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// File Entries (and Extended File Entries) by logical block address
|
||||
/// </summary>
|
||||
public Dictionary<long, FileEntry> FileEntries { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Allocation Extent Descriptors by logical block address
|
||||
/// </summary>
|
||||
public Dictionary<long, AllocationExtentDescriptor> AllocationExtentDescriptors { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// File Identifier Descriptors of each directory, by logical block address of the directory's File Entry
|
||||
/// </summary>
|
||||
public Dictionary<long, FileIdentifierDescriptor[]> Directories { get; set; } = [];
|
||||
}
|
||||
}
|
||||
24
SabreTools.Data.Models/UDF/VolumeDescriptorPointer.cs
Normal file
24
SabreTools.Data.Models/UDF/VolumeDescriptorPointer.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Volume Descriptor Pointer (3/10.3), continues the Volume Descriptor Sequence in another extent
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class VolumeDescriptorPointer : Descriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Volume Descriptor Sequence Number
|
||||
/// </summary>
|
||||
public uint VolumeDescriptorSequenceNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Extent of the next part of the Volume Descriptor Sequence
|
||||
/// </summary>
|
||||
public ExtentDescriptor NextVolumeDescriptorSequenceExtent { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Reserved, 484 bytes of 0x00
|
||||
/// </summary>
|
||||
public byte[] Reserved { get; set; } = new byte[484];
|
||||
}
|
||||
}
|
||||
30
SabreTools.Data.Models/UDF/VolumeStructureDescriptor.cs
Normal file
30
SabreTools.Data.Models/UDF/VolumeStructureDescriptor.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace SabreTools.Data.Models.UDF
|
||||
{
|
||||
/// <summary>
|
||||
/// UDF Volume Structure Descriptor (2/9.1), one logical sector of the Volume Recognition Sequence
|
||||
/// starting at sector 16, e.g. "BEA01", "NSR02"/"NSR03", "TEA01", or "CD001" on bridge discs
|
||||
/// </summary>
|
||||
/// <see href="https://ecma-international.org/wp-content/uploads/ECMA-167_3rd_edition_june_1997.pdf"/>
|
||||
public sealed class VolumeStructureDescriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Structure type
|
||||
/// </summary>
|
||||
public byte StructureType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Standard identifier, 5 bytes
|
||||
/// </summary>
|
||||
public byte[] StandardIdentifier { get; set; } = new byte[5];
|
||||
|
||||
/// <summary>
|
||||
/// Structure version
|
||||
/// </summary>
|
||||
public byte StructureVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Structure data, the rest of the logical sector
|
||||
/// </summary>
|
||||
public byte[] StructureData { get; set; } = [];
|
||||
}
|
||||
}
|
||||
@@ -212,6 +212,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
DatVersion = "datversion",
|
||||
Debug = true,
|
||||
Description = "description",
|
||||
DirHandling = "noautodir",
|
||||
Email = "email",
|
||||
EmulatorVersion = "emulatorversion",
|
||||
FileName = "filename",
|
||||
@@ -243,6 +244,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
ScreenshotsHeight = "screenshotsheight",
|
||||
ScreenshotsWidth = "screenshotsWidth",
|
||||
Search = search,
|
||||
Subset = "subset",
|
||||
System = "system",
|
||||
Timestamp = "timestamp",
|
||||
Type = "type",
|
||||
@@ -327,6 +329,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
SaveType = "savetype",
|
||||
Score = "score",
|
||||
Serial = "serial",
|
||||
SetType = "dir",
|
||||
SharedFeat = [CreateMetadataSharedFeat()],
|
||||
Slot = [CreateMetadataSlot()],
|
||||
SoftwareList = [CreateMetadataSoftwareList()],
|
||||
@@ -778,6 +781,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Bios = "bios",
|
||||
Bitrate = "bitrate",
|
||||
BitTorrentMagnetHash = "btih",
|
||||
BLAKE3 = HashType.BLAKE3.ZeroString,
|
||||
ClothCoverDetectionModuleVersion = "cloth_cover_detection_module_version",
|
||||
CollectionCatalogNumber = "collection-catalog-number",
|
||||
Comment = "comment",
|
||||
@@ -835,6 +839,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
SpamSum = HashType.SpamSum.ZeroString,
|
||||
Start = "start",
|
||||
Status = Data.Models.Metadata.ItemStatus.Good,
|
||||
StatusMisc = "status",
|
||||
Summation = "summation",
|
||||
TesseractOCR = "ocr",
|
||||
TesseractOCRConverted = "ocr_converted",
|
||||
@@ -1004,6 +1009,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal("datversion", datHeader.DatVersion);
|
||||
Assert.True(datHeader.Debug);
|
||||
Assert.Equal("description", datHeader.Description);
|
||||
Assert.Equal("noautodir", datHeader.DirHandling);
|
||||
Assert.Equal("email", datHeader.Email);
|
||||
Assert.Equal("emulatorversion", datHeader.EmulatorVersion);
|
||||
Assert.Equal(Data.Models.Metadata.MergingFlag.Merged, datHeader.ForceMerging);
|
||||
@@ -1033,6 +1039,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal("screenshotsheight", datHeader.ScreenshotsHeight);
|
||||
Assert.Equal("screenshotsWidth", datHeader.ScreenshotsWidth);
|
||||
Assert.NotNull(datHeader.Search);
|
||||
Assert.Equal("subset", datHeader.Subset);
|
||||
Assert.Equal("system", datHeader.System);
|
||||
Assert.Equal("timestamp", datHeader.Timestamp);
|
||||
Assert.Equal("type", datHeader.Type);
|
||||
@@ -1090,6 +1097,8 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal("sampleof", machine.SampleOf);
|
||||
Assert.Equal("savetype", machine.SaveType);
|
||||
Assert.Equal("score", machine.Score);
|
||||
Assert.Equal("serial", machine.Serial);
|
||||
Assert.Equal("dir", machine.SetType);
|
||||
Assert.Equal("source", machine.Source);
|
||||
Assert.Equal("sourcefile", machine.SourceFile);
|
||||
Assert.Equal("sourcerom", machine.SourceRom);
|
||||
@@ -1450,6 +1459,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal("bios", rom.Bios);
|
||||
Assert.Equal("bitrate", rom.Bitrate);
|
||||
Assert.Equal("btih", rom.BitTorrentMagnetHash);
|
||||
Assert.Equal(HashType.BLAKE3.ZeroString, rom.BLAKE3);
|
||||
Assert.Equal("cloth_cover_detection_module_version", rom.ClothCoverDetectionModuleVersion);
|
||||
Assert.Equal("collection-catalog-number", rom.CollectionCatalogNumber);
|
||||
Assert.Equal("comment", rom.Comment);
|
||||
@@ -1507,6 +1517,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal(HashType.SpamSum.ZeroString, rom.SpamSum);
|
||||
Assert.Equal("start", rom.Start);
|
||||
Assert.Equal(Data.Models.Metadata.ItemStatus.Good, rom.Status);
|
||||
Assert.Equal("status", rom.StatusMisc);
|
||||
Assert.Equal("summation", rom.Summation);
|
||||
Assert.Equal("ocr", rom.TesseractOCR);
|
||||
Assert.Equal("ocr_converted", rom.TesseractOCRConverted);
|
||||
|
||||
@@ -344,6 +344,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal("datversion", header.DatVersion);
|
||||
Assert.True(header.Debug);
|
||||
Assert.Equal("description", header.Description);
|
||||
Assert.Equal("noautodir", header.DirHandling);
|
||||
Assert.Equal("email", header.Email);
|
||||
Assert.Equal("emulatorversion", header.EmulatorVersion);
|
||||
Assert.Equal("filename", header.FileName);
|
||||
@@ -374,6 +375,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal("screenshotsheight", header.ScreenshotsHeight);
|
||||
Assert.Equal("screenshotsWidth", header.ScreenshotsWidth);
|
||||
Assert.NotNull(header.Search);
|
||||
Assert.Equal("subset", header.Subset);
|
||||
Assert.Equal("system", header.System);
|
||||
Assert.Equal("timestamp", header.Timestamp);
|
||||
Assert.Equal("type", header.Type);
|
||||
@@ -436,6 +438,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal("savetype", machine.SaveType);
|
||||
Assert.Equal("score", machine.Score);
|
||||
Assert.Equal("serial", machine.Serial);
|
||||
Assert.Equal("dir", machine.SetType);
|
||||
Assert.Equal("source", machine.Source);
|
||||
Assert.Equal("sourcefile", machine.SourceFile);
|
||||
Assert.Equal("sourcerom", machine.SourceRom);
|
||||
@@ -1005,6 +1008,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal("bios", rom.Bios);
|
||||
Assert.Equal("bitrate", rom.Bitrate);
|
||||
Assert.Equal("btih", rom.BitTorrentMagnetHash);
|
||||
Assert.Equal(HashType.BLAKE3.ZeroString, rom.BLAKE3);
|
||||
Assert.Equal("cloth_cover_detection_module_version", rom.ClothCoverDetectionModuleVersion);
|
||||
Assert.Equal("collection-catalog-number", rom.CollectionCatalogNumber);
|
||||
Assert.Equal("comment", rom.Comment);
|
||||
@@ -1062,6 +1066,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal(HashType.SpamSum.ZeroString, rom.SpamSum);
|
||||
Assert.Equal("start", rom.Start);
|
||||
Assert.Equal(Data.Models.Metadata.ItemStatus.Good, rom.Status);
|
||||
Assert.Equal("status", rom.StatusMisc);
|
||||
Assert.Equal("summation", rom.Summation);
|
||||
Assert.Equal("ocr", rom.TesseractOCR);
|
||||
Assert.Equal("ocr_converted", rom.TesseractOCRConverted);
|
||||
|
||||
@@ -1396,7 +1396,8 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
SHA256 = "sha256",
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum"
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
string actual = DatFile.FormatPrefixPostfix(item, machine, fix);
|
||||
@@ -1514,7 +1515,8 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
SHA256 = "sha256",
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum"
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
string actual = DatFile.FormatPrefixPostfix(item, machine, fix);
|
||||
@@ -1550,6 +1552,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Null(rom.SHA384);
|
||||
Assert.Null(rom.SHA512);
|
||||
Assert.Null(rom.SpamSum);
|
||||
Assert.Null(rom.BLAKE3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -1575,6 +1578,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Null(rom.SHA384);
|
||||
Assert.Null(rom.SHA512);
|
||||
Assert.Null(rom.SpamSum);
|
||||
Assert.Null(rom.BLAKE3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -1594,7 +1598,8 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
SHA256 = "null",
|
||||
SHA384 = "null",
|
||||
SHA512 = "null",
|
||||
SpamSum = "null"
|
||||
SpamSum = "null",
|
||||
BLAKE3 = "null",
|
||||
};
|
||||
|
||||
DatItem actual = DatFile.ProcessNullifiedItem(item);
|
||||
@@ -1614,6 +1619,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal(HashType.SHA384.ZeroString, rom.SHA384);
|
||||
Assert.Equal(HashType.SHA512.ZeroString, rom.SHA512);
|
||||
Assert.Equal(HashType.SpamSum.ZeroString, rom.SpamSum);
|
||||
Assert.Equal(HashType.BLAKE3.ZeroString, rom.BLAKE3);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1955,6 +1961,19 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal($"_{hash}", actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDuplicateSuffix_Rom_BLAKE3()
|
||||
{
|
||||
string hash = "hash";
|
||||
DatItem datItem = new Rom
|
||||
{
|
||||
BLAKE3 = hash
|
||||
};
|
||||
|
||||
string actual = DatFile.GetDuplicateSuffix(datItem);
|
||||
Assert.Equal($"_{hash}", actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDuplicateSuffix_Other_Generic()
|
||||
{
|
||||
@@ -2434,7 +2453,8 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
SHA256 = "crc",
|
||||
SHA384 = "crc",
|
||||
SHA512 = "crc",
|
||||
SpamSum = "crc"
|
||||
SpamSum = "crc",
|
||||
BLAKE3 = "crc",
|
||||
};
|
||||
DatFile datFile = new Logiqx(null, useGame: false);
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal(0, stats.GetHashCount(HashType.SHA384));
|
||||
Assert.Equal(0, stats.GetHashCount(HashType.SHA512));
|
||||
Assert.Equal(0, stats.GetHashCount(HashType.SpamSum));
|
||||
Assert.Equal(0, stats.GetHashCount(HashType.BLAKE3));
|
||||
Assert.Equal(0, stats.GetItemCount(Data.Models.Metadata.ItemType.Disk));
|
||||
Assert.Equal(0, stats.GetItemCount(Data.Models.Metadata.ItemType.File));
|
||||
Assert.Equal(0, stats.GetItemCount(Data.Models.Metadata.ItemType.Media));
|
||||
@@ -88,6 +89,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal(1, stats.GetHashCount(HashType.SHA384));
|
||||
Assert.Equal(1, stats.GetHashCount(HashType.SHA512));
|
||||
Assert.Equal(2, stats.GetHashCount(HashType.SpamSum));
|
||||
Assert.Equal(1, stats.GetHashCount(HashType.BLAKE3));
|
||||
Assert.Equal(1, stats.GetItemCount(Data.Models.Metadata.ItemType.Disk));
|
||||
Assert.Equal(1, stats.GetItemCount(Data.Models.Metadata.ItemType.File));
|
||||
Assert.Equal(1, stats.GetItemCount(Data.Models.Metadata.ItemType.Media));
|
||||
@@ -116,6 +118,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal(0, stats.GetHashCount(HashType.SHA384));
|
||||
Assert.Equal(0, stats.GetHashCount(HashType.SHA512));
|
||||
Assert.Equal(0, stats.GetHashCount(HashType.SpamSum));
|
||||
Assert.Equal(0, stats.GetHashCount(HashType.BLAKE3));
|
||||
Assert.Equal(0, stats.GetItemCount(Data.Models.Metadata.ItemType.Disk));
|
||||
Assert.Equal(0, stats.GetItemCount(Data.Models.Metadata.ItemType.File));
|
||||
Assert.Equal(0, stats.GetItemCount(Data.Models.Metadata.ItemType.Media));
|
||||
@@ -151,6 +154,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal(0, stats.GetHashCount(HashType.SHA384));
|
||||
Assert.Equal(0, stats.GetHashCount(HashType.SHA512));
|
||||
Assert.Equal(0, stats.GetHashCount(HashType.SpamSum));
|
||||
Assert.Equal(0, stats.GetHashCount(HashType.BLAKE3));
|
||||
Assert.Equal(0, stats.GetItemCount(Data.Models.Metadata.ItemType.Disk));
|
||||
Assert.Equal(0, stats.GetItemCount(Data.Models.Metadata.ItemType.File));
|
||||
Assert.Equal(0, stats.GetItemCount(Data.Models.Metadata.ItemType.Media));
|
||||
@@ -179,6 +183,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal(1, stats.GetHashCount(HashType.SHA384));
|
||||
Assert.Equal(1, stats.GetHashCount(HashType.SHA512));
|
||||
Assert.Equal(2, stats.GetHashCount(HashType.SpamSum));
|
||||
Assert.Equal(1, stats.GetHashCount(HashType.BLAKE3));
|
||||
Assert.Equal(1, stats.GetItemCount(Data.Models.Metadata.ItemType.Disk));
|
||||
Assert.Equal(1, stats.GetItemCount(Data.Models.Metadata.ItemType.File));
|
||||
Assert.Equal(1, stats.GetItemCount(Data.Models.Metadata.ItemType.Media));
|
||||
@@ -203,6 +208,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal(0, stats.GetHashCount(HashType.SHA384));
|
||||
Assert.Equal(0, stats.GetHashCount(HashType.SHA512));
|
||||
Assert.Equal(0, stats.GetHashCount(HashType.SpamSum));
|
||||
Assert.Equal(0, stats.GetHashCount(HashType.BLAKE3));
|
||||
Assert.Equal(0, stats.GetItemCount(Data.Models.Metadata.ItemType.Disk));
|
||||
Assert.Equal(0, stats.GetItemCount(Data.Models.Metadata.ItemType.File));
|
||||
Assert.Equal(0, stats.GetItemCount(Data.Models.Metadata.ItemType.Media));
|
||||
@@ -238,6 +244,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
Assert.Equal(1, newStats.GetHashCount(HashType.SHA384));
|
||||
Assert.Equal(1, newStats.GetHashCount(HashType.SHA512));
|
||||
Assert.Equal(1, newStats.GetHashCount(HashType.SpamSum));
|
||||
Assert.Equal(1, newStats.GetHashCount(HashType.BLAKE3));
|
||||
Assert.Equal(1, newStats.GetItemCount(Data.Models.Metadata.ItemType.Rom));
|
||||
Assert.Equal(1, newStats.GetStatusCount(ItemStatus.Good));
|
||||
}
|
||||
@@ -317,6 +324,7 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
rom.SHA384 = HashType.SHA384.ZeroString;
|
||||
rom.SHA512 = HashType.SHA512.ZeroString;
|
||||
rom.SpamSum = HashType.SpamSum.ZeroString;
|
||||
rom.BLAKE3 = HashType.BLAKE3.ZeroString;
|
||||
|
||||
return rom;
|
||||
}
|
||||
|
||||
@@ -700,6 +700,31 @@ namespace SabreTools.Metadata.DatFiles.Test
|
||||
]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Blake3File_SupportedTypes()
|
||||
{
|
||||
var datFile = new Blake3File(null);
|
||||
var actual = datFile.SupportedTypes;
|
||||
Assert.True(actual.SequenceEqual([
|
||||
Data.Models.Metadata.ItemType.Rom,
|
||||
]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Blake3File_GetMissingRequiredFields_Rom()
|
||||
{
|
||||
var datItem = new Rom();
|
||||
var datFile = new Blake3File(null);
|
||||
|
||||
var actual = datFile.GetMissingRequiredFields(datItem);
|
||||
|
||||
Assert.NotNull(actual);
|
||||
Assert.True(actual.SequenceEqual([
|
||||
nameof(Data.Models.Metadata.Rom.Name),
|
||||
nameof(Data.Models.Metadata.Rom.BLAKE3),
|
||||
]));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Listrom
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0;net11.0</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="[2.0.0]" />
|
||||
<PackageReference Include="coverlet.collector" Version="10.1.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.11.1" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="2.2.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="4.0.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -104,6 +104,8 @@ namespace SabreTools.Metadata.DatFiles
|
||||
Header.Debug = header.Debug;
|
||||
if (Header.Description is null)
|
||||
Header.Description = header.Description;
|
||||
if (Header.DirHandling is null)
|
||||
Header.DirHandling = header.DirHandling;
|
||||
if (Header.Email is null)
|
||||
Header.Email = header.Email;
|
||||
if (Header.EmulatorVersion is null)
|
||||
@@ -156,6 +158,8 @@ namespace SabreTools.Metadata.DatFiles
|
||||
Header.ScreenshotsWidth = header.ScreenshotsWidth;
|
||||
if (Header.System is null)
|
||||
Header.System = header.System;
|
||||
if (Header.Subset is null)
|
||||
Header.Subset = header.Subset;
|
||||
if (Header.Timestamp is null)
|
||||
Header.Timestamp = header.Timestamp;
|
||||
if (Header.Type is null)
|
||||
|
||||
@@ -593,7 +593,8 @@ namespace SabreTools.Metadata.DatFiles
|
||||
sha384 = string.Empty,
|
||||
sha512 = string.Empty,
|
||||
size = string.Empty,
|
||||
spamsum = string.Empty;
|
||||
spamsum = string.Empty,
|
||||
blake3 = string.Empty;
|
||||
|
||||
// Ensure we have the proper values for replacement
|
||||
if (item is Disk disk)
|
||||
@@ -633,6 +634,7 @@ namespace SabreTools.Metadata.DatFiles
|
||||
sha512 = rom.SHA512 ?? string.Empty;
|
||||
size = rom.Size.ToString() ?? string.Empty;
|
||||
spamsum = rom.SpamSum ?? string.Empty;
|
||||
blake3 = rom.BLAKE3 ?? string.Empty;
|
||||
}
|
||||
|
||||
// Now do bulk replacement where possible
|
||||
@@ -657,7 +659,8 @@ namespace SabreTools.Metadata.DatFiles
|
||||
.Replace("%sha384%", sha384)
|
||||
.Replace("%sha512%", sha512)
|
||||
.Replace("%size%", size)
|
||||
.Replace("%spamsum%", spamsum);
|
||||
.Replace("%spamsum%", spamsum)
|
||||
.Replace("%blake3%", blake3);
|
||||
|
||||
return fix;
|
||||
}
|
||||
@@ -681,6 +684,14 @@ namespace SabreTools.Metadata.DatFiles
|
||||
if (rom.CRC32 != "null")
|
||||
return rom;
|
||||
|
||||
// If the item has a SHA-1 but no size
|
||||
if (rom.Size is null && rom.SHA1 is not null && rom.SHA1 != "null")
|
||||
return rom;
|
||||
|
||||
// If the item has a SHA-256 but no size
|
||||
if (rom.Size is null && rom.SHA256 is not null && rom.SHA256 != "null")
|
||||
return rom;
|
||||
|
||||
// If the Rom has "null" characteristics, ensure all fields
|
||||
rom.Name = rom.Name == "null" ? "-" : rom.Name;
|
||||
rom.Size = 0;
|
||||
@@ -697,6 +708,7 @@ namespace SabreTools.Metadata.DatFiles
|
||||
rom.SHA384 = rom.SHA384 == "null" ? HashType.SHA384.ZeroString : null;
|
||||
rom.SHA512 = rom.SHA512 == "null" ? HashType.SHA512.ZeroString : null;
|
||||
rom.SpamSum = rom.SpamSum == "null" ? HashType.SpamSum.ZeroString : null;
|
||||
rom.BLAKE3 = rom.BLAKE3 == "null" ? HashType.BLAKE3.ZeroString : null;
|
||||
|
||||
return rom;
|
||||
}
|
||||
@@ -979,7 +991,7 @@ namespace SabreTools.Metadata.DatFiles
|
||||
{
|
||||
// If we have a 0-size or blank rom, then we ignore
|
||||
long? size = rom.Size;
|
||||
if (size == 0 || size is null)
|
||||
if ((size == 0 || size is null) && rom.SHA1 is null && rom.SHA256 is null)
|
||||
{
|
||||
string itemString = JsonConvert.SerializeObject(datItem, Formatting.None);
|
||||
_logger.Verbose($"Item '{itemString}' was skipped because it had an invalid size");
|
||||
@@ -1127,6 +1139,10 @@ namespace SabreTools.Metadata.DatFiles
|
||||
if (!string.IsNullOrEmpty(spamSum))
|
||||
return $"_{spamSum}";
|
||||
|
||||
string? blake3 = datItem.BLAKE3;
|
||||
if (!string.IsNullOrEmpty(blake3))
|
||||
return $"_{blake3}";
|
||||
|
||||
return "_1";
|
||||
}
|
||||
|
||||
|
||||
@@ -84,6 +84,12 @@ namespace SabreTools.Metadata.DatFiles
|
||||
set => _internal.Description = value;
|
||||
}
|
||||
|
||||
public string? DirHandling
|
||||
{
|
||||
get => _internal.DirHandling;
|
||||
set => _internal.DirHandling = value;
|
||||
}
|
||||
|
||||
public string? Email
|
||||
{
|
||||
get => _internal.Email;
|
||||
@@ -282,6 +288,12 @@ namespace SabreTools.Metadata.DatFiles
|
||||
[JsonIgnore]
|
||||
public bool SearchSpecified => Search is not null;
|
||||
|
||||
public string? Subset
|
||||
{
|
||||
get => _internal.Subset;
|
||||
set => _internal.Subset = value;
|
||||
}
|
||||
|
||||
public string? System
|
||||
{
|
||||
get => _internal.System;
|
||||
|
||||
@@ -353,6 +353,12 @@ namespace SabreTools.Metadata.DatFiles
|
||||
ModifyHashCount(HashType.SHA384, string.IsNullOrEmpty(rom.SHA384) ? 0 : 1);
|
||||
ModifyHashCount(HashType.SHA512, string.IsNullOrEmpty(rom.SHA512) ? 0 : 1);
|
||||
ModifyHashCount(HashType.SpamSum, string.IsNullOrEmpty(rom.SpamSum) ? 0 : 1);
|
||||
#if NET7_0_OR_GREATER
|
||||
ModifyHashCount(HashType.BLAKE3, string.IsNullOrEmpty(rom.BLAKE3) ? 0 : 1);
|
||||
#else
|
||||
// HACK because BLAKE3 is not supported below .NET 7
|
||||
ModifyHashCount(HashType.CRC1_ZERO, string.IsNullOrEmpty(rom.BLAKE3) ? 0 : 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
ModifyStatusCount(ItemStatus.BadDump, status == ItemStatus.BadDump ? 1 : 0);
|
||||
@@ -430,6 +436,12 @@ namespace SabreTools.Metadata.DatFiles
|
||||
ModifyHashCount(HashType.SHA384, string.IsNullOrEmpty(rom.SHA384) ? 0 : -1);
|
||||
ModifyHashCount(HashType.SHA512, string.IsNullOrEmpty(rom.SHA512) ? 0 : -1);
|
||||
ModifyHashCount(HashType.SpamSum, string.IsNullOrEmpty(rom.SpamSum) ? 0 : -1);
|
||||
#if NET7_0_OR_GREATER
|
||||
ModifyHashCount(HashType.BLAKE3, string.IsNullOrEmpty(rom.BLAKE3) ? 0 : -1);
|
||||
#else
|
||||
// HACK because BLAKE3 is not supported below .NET 7
|
||||
ModifyHashCount(HashType.CRC1_ZERO, string.IsNullOrEmpty(rom.BLAKE3) ? 0 : -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
ModifyStatusCount(ItemStatus.BadDump, status == ItemStatus.BadDump ? -1 : 0);
|
||||
|
||||
@@ -169,6 +169,11 @@ namespace SabreTools.Metadata.DatFiles
|
||||
/// </summary>
|
||||
RedumpSpamSum,
|
||||
|
||||
/// <summary>
|
||||
/// BLAKE3 hash list
|
||||
/// </summary>
|
||||
RedumpBLAKE3,
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
56
SabreTools.Metadata.DatFiles/Formats/Blake3File.cs
Normal file
56
SabreTools.Metadata.DatFiles/Formats/Blake3File.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System.Collections.Generic;
|
||||
using SabreTools.Hashing;
|
||||
using SabreTools.Metadata.DatItems;
|
||||
using SabreTools.Metadata.DatItems.Formats;
|
||||
|
||||
namespace SabreTools.Metadata.DatFiles.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an BLAKE3 hashfile
|
||||
/// </summary>
|
||||
public sealed class Blake3File : Hashfile
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Data.Models.Metadata.ItemType[] SupportedTypes
|
||||
=> [
|
||||
Data.Models.Metadata.ItemType.Rom,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Constructor designed for casting a base DatFile
|
||||
/// </summary>
|
||||
/// <param name="datFile">Parent DatFile to copy from</param>
|
||||
public Blake3File(DatFile? datFile) : base(datFile)
|
||||
{
|
||||
#if NET7_0_OR_GREATER
|
||||
_hash = HashType.BLAKE3;
|
||||
#else
|
||||
// HACK because BLAKE3 is not supported below .NET 7
|
||||
_hash = HashType.CRC1_ZERO;
|
||||
#endif
|
||||
Header.DatFormat = DatFormat.RedumpBLAKE3;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected internal override List<string>? GetMissingRequiredFields(DatItem datItem)
|
||||
{
|
||||
List<string> missingFields = [];
|
||||
|
||||
switch (datItem)
|
||||
{
|
||||
case Rom rom:
|
||||
if (string.IsNullOrEmpty(rom.Name))
|
||||
missingFields.Add(nameof(Data.Models.Metadata.Rom.Name));
|
||||
if (string.IsNullOrEmpty(rom.BLAKE3))
|
||||
missingFields.Add(nameof(Data.Models.Metadata.Rom.BLAKE3));
|
||||
break;
|
||||
|
||||
default:
|
||||
// Item type is not supported
|
||||
break;
|
||||
}
|
||||
|
||||
return missingFields;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,9 +88,12 @@ namespace SabreTools.Metadata.DatFiles.Formats
|
||||
case Rom rom:
|
||||
if (string.IsNullOrEmpty(rom.Name))
|
||||
missingFields.Add(nameof(Data.Models.Metadata.Rom.Name));
|
||||
if (rom.Size is null || rom.Size < 0)
|
||||
if ((rom.Size is null || rom.Size < 0)
|
||||
&& (rom.SHA1 is null || rom.SHA1 == "null")
|
||||
&& (rom.SHA256 is null || rom.SHA1 == "null"))
|
||||
missingFields.Add(nameof(Data.Models.Metadata.Rom.Size));
|
||||
if (string.IsNullOrEmpty(rom.CRC16)
|
||||
if (string.IsNullOrEmpty(rom.BLAKE3)
|
||||
&& string.IsNullOrEmpty(rom.CRC16)
|
||||
&& string.IsNullOrEmpty(rom.CRC32)
|
||||
&& string.IsNullOrEmpty(rom.CRC64)
|
||||
&& string.IsNullOrEmpty(rom.MD2)
|
||||
|
||||
@@ -282,9 +282,12 @@ namespace SabreTools.Metadata.DatFiles.Formats
|
||||
case Rom rom:
|
||||
if (string.IsNullOrEmpty(rom.Name))
|
||||
missingFields.Add(nameof(Data.Models.Metadata.Rom.Name));
|
||||
if (rom.Size is null || rom.Size < 0)
|
||||
if ((rom.Size is null || rom.Size < 0)
|
||||
&& (rom.SHA1 is null || rom.SHA1 == "null")
|
||||
&& (rom.SHA256 is null || rom.SHA1 == "null"))
|
||||
missingFields.Add(nameof(Data.Models.Metadata.Rom.Size));
|
||||
if (string.IsNullOrEmpty(rom.CRC16)
|
||||
if (string.IsNullOrEmpty(rom.BLAKE3)
|
||||
&& string.IsNullOrEmpty(rom.CRC16)
|
||||
&& string.IsNullOrEmpty(rom.CRC32)
|
||||
&& string.IsNullOrEmpty(rom.CRC64)
|
||||
&& string.IsNullOrEmpty(rom.MD2)
|
||||
|
||||
@@ -29,17 +29,22 @@ namespace SabreTools.Metadata.DatFiles.Formats
|
||||
<![CDATA[
|
||||
The softwaredb.xml file contains information about rom mapper types
|
||||
|
||||
- Copyright 2003 Nicolas Beyaert (Initial Database)
|
||||
- Copyright 2004-2013 BlueMSX Team
|
||||
- Copyright 2005-2023 openMSX Team
|
||||
- Generation MSXIDs by www.generation-msx.nl
|
||||
Copyright 2003 Nicolas Beyaert (Initial Database)
|
||||
Copyright 2004-2013 BlueMSX Team
|
||||
Copyright 2005-2026 openMSX Team
|
||||
|
||||
- Thanks go out to:
|
||||
- - Generation MSX/Sylvester for the incredible source of information
|
||||
- p_gimeno and diedel for their help adding and valdiating ROM additions
|
||||
Generation MSXIDs by www.generation-msx.nl
|
||||
|
||||
Thanks go out to:
|
||||
- Generation MSX / Sylvester for the incredible source of information
|
||||
- p_gimeno and diedel for their help adding and validating ROM additions
|
||||
- GDX for additional ROM info and validations and corrections
|
||||
- TFH / Filehunter for his sharing of information
|
||||
- MP83 for deep dives into software and corrections
|
||||
- bsittler for preservation and sharing of information
|
||||
|
||||
|
||||
Important: This file is auto generated using a database.
|
||||
The Database is located at https://romdb.vampier.net/
|
||||
]]>";
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -93,7 +93,9 @@ namespace SabreTools.Metadata.DatFiles.Formats
|
||||
case Rom rom:
|
||||
if (string.IsNullOrEmpty(rom.Name))
|
||||
missingFields.Add(nameof(Data.Models.Metadata.Rom.Name));
|
||||
if (rom.Size is null || rom.Size < 0)
|
||||
if ((rom.Size is null || rom.Size < 0)
|
||||
&& (rom.SHA1 is null || rom.SHA1 == "null")
|
||||
&& (rom.SHA256 is null || rom.SHA1 == "null"))
|
||||
missingFields.Add(nameof(Data.Models.Metadata.Rom.Size));
|
||||
if (string.IsNullOrEmpty(rom.CRC32)
|
||||
&& string.IsNullOrEmpty(rom.MD5)
|
||||
|
||||
@@ -482,6 +482,7 @@ namespace SabreTools.Metadata.DatFiles
|
||||
rom.SHA384 = null; // HashType.SHA384.ZeroString;
|
||||
rom.SHA512 = null; // HashType.SHA512.ZeroString;
|
||||
rom.SpamSum = null; // HashType.SpamSum.ZeroString;
|
||||
rom.BLAKE3 = null; // HashType.BLAKE3.ZeroString;
|
||||
}
|
||||
|
||||
// If the file has no size and it's not the above case, skip and log
|
||||
|
||||
@@ -40,6 +40,15 @@ namespace SabreTools.Metadata.DatFiles
|
||||
private readonly Dictionary<string, List<DatItem>?> _items = [];
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Internal dictionary for the class
|
||||
/// </summary>
|
||||
#if NET40_OR_GREATER || NETCOREAPP || NETSTANDARD2_0_OR_GREATER
|
||||
private readonly ConcurrentDictionary<string, object> _itemsLocks = [];
|
||||
#else
|
||||
private readonly Dictionary<string, object> _itemsLocks = [];
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Logging object
|
||||
/// </summary>
|
||||
@@ -163,6 +172,7 @@ namespace SabreTools.Metadata.DatFiles
|
||||
rom.SHA384 = null; // HashType.SHA384.ZeroString;
|
||||
rom.SHA512 = null; // HashType.SHA512.ZeroString;
|
||||
rom.SpamSum = null; // HashType.SpamSum.ZeroString;
|
||||
rom.BLAKE3 = null; // HashType.BLAKE3.ZeroString;
|
||||
}
|
||||
|
||||
// If the file has no size and it's not the above case, skip and log
|
||||
@@ -190,7 +200,14 @@ namespace SabreTools.Metadata.DatFiles
|
||||
// If only adding statistics, we add an empty key for games and then just item stats
|
||||
if (statsOnly)
|
||||
{
|
||||
EnsureBucketingKey(key);
|
||||
// Add an empty key
|
||||
#if NET40_OR_GREATER || NETCOREAPP || NETSTANDARD2_0_OR_GREATER
|
||||
_items.GetOrAdd(key, []);
|
||||
#else
|
||||
if (!_items.ContainsKey(key))
|
||||
_items[key] = [];
|
||||
#endif
|
||||
|
||||
DatStatistics.AddItemStatistics(item);
|
||||
}
|
||||
else
|
||||
@@ -293,7 +310,16 @@ namespace SabreTools.Metadata.DatFiles
|
||||
public bool RemoveItem(string key, DatItem value, int index)
|
||||
{
|
||||
// Explicit lock for some weird corner cases
|
||||
lock (key)
|
||||
#if NET40_OR_GREATER || NETCOREAPP || NETSTANDARD2_0_OR_GREATER
|
||||
object lockObj = _itemsLocks.GetOrAdd(key, _ => new object());
|
||||
#else
|
||||
if (!_itemsLocks.ContainsKey(key))
|
||||
_itemsLocks[key] = new object();
|
||||
|
||||
object lockObj = _itemsLocks[key];
|
||||
#endif
|
||||
|
||||
lock (lockObj)
|
||||
{
|
||||
// If the key doesn't exist, return
|
||||
#if NET40_OR_GREATER || NETCOREAPP || NETSTANDARD2_0_OR_GREATER
|
||||
@@ -337,10 +363,24 @@ namespace SabreTools.Metadata.DatFiles
|
||||
internal void AddItem(string key, DatItem value)
|
||||
{
|
||||
// Explicit lock for some weird corner cases
|
||||
lock (key)
|
||||
#if NET40_OR_GREATER || NETCOREAPP || NETSTANDARD2_0_OR_GREATER
|
||||
object lockObj = _itemsLocks.GetOrAdd(key, _ => new object());
|
||||
#else
|
||||
if (!_itemsLocks.ContainsKey(key))
|
||||
_itemsLocks[key] = new object();
|
||||
|
||||
object lockObj = _itemsLocks[key];
|
||||
#endif
|
||||
|
||||
lock (lockObj)
|
||||
{
|
||||
// Ensure the key exists
|
||||
EnsureBucketingKey(key);
|
||||
#if NET40_OR_GREATER || NETCOREAPP || NETSTANDARD2_0_OR_GREATER
|
||||
_items.GetOrAdd(key, []);
|
||||
#else
|
||||
if (!_items.ContainsKey(key))
|
||||
_items[key] = [];
|
||||
#endif
|
||||
|
||||
// If item is null, don't add it
|
||||
if (value is null)
|
||||
@@ -639,21 +679,6 @@ namespace SabreTools.Metadata.DatFiles
|
||||
return roms.FindIndex(datItem.Equals) > -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure the key exists in the items dictionary
|
||||
/// </summary>
|
||||
/// <param name="key">Key to ensure</param>
|
||||
private void EnsureBucketingKey(string key)
|
||||
{
|
||||
// If the key is missing from the dictionary, add it
|
||||
#if NET40_OR_GREATER || NETCOREAPP || NETSTANDARD2_0_OR_GREATER
|
||||
_items.GetOrAdd(key, []);
|
||||
#else
|
||||
if (!_items.ContainsKey(key))
|
||||
_items[key] = [];
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the highest-order Field value that represents the statistics
|
||||
/// </summary>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;net11.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
@@ -12,7 +12,7 @@
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>3.0.1</Version>
|
||||
<Version>3.3.0</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
@@ -46,8 +46,8 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MinValueTupleBridge" Version="0.2.1" Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`))" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="[2.0.0]" />
|
||||
<PackageReference Include="SabreTools.IO" Version="[2.1.0]" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="2.2.0" />
|
||||
<PackageReference Include="SabreTools.IO" Version="2.4.0" />
|
||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" Condition="$(TargetFramework.StartsWith(`net40`)) OR $(TargetFramework.StartsWith(`net45`))" />
|
||||
<PackageReference Include="System.ValueTuple" Version="4.6.2" Condition="$(TargetFramework.StartsWith(`net46`)) OR $(TargetFramework.StartsWith(`net47`)) OR $(TargetFramework.StartsWith(`net48`))" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -290,6 +290,10 @@ namespace SabreTools.Metadata.DatItems.Test
|
||||
[InlineData(ItemKey.SpamSum, false, true, "3::")]
|
||||
[InlineData(ItemKey.SpamSum, true, false, "3::")]
|
||||
[InlineData(ItemKey.SpamSum, true, true, "3::")]
|
||||
[InlineData(ItemKey.BLAKE3, false, false, "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")]
|
||||
[InlineData(ItemKey.BLAKE3, false, true, "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")]
|
||||
[InlineData(ItemKey.BLAKE3, true, false, "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")]
|
||||
[InlineData(ItemKey.BLAKE3, true, true, "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")]
|
||||
public void GetKeyDB_DefaultImplementation(ItemKey bucketedBy, bool lower, bool norename, string expected)
|
||||
{
|
||||
Source source = new Source(0);
|
||||
@@ -363,6 +367,10 @@ namespace SabreTools.Metadata.DatItems.Test
|
||||
[InlineData(ItemKey.SpamSum, false, true, "BASE64")]
|
||||
[InlineData(ItemKey.SpamSum, true, false, "base64")]
|
||||
[InlineData(ItemKey.SpamSum, true, true, "base64")]
|
||||
[InlineData(ItemKey.BLAKE3, false, false, "DEADBEEF")]
|
||||
[InlineData(ItemKey.BLAKE3, false, true, "DEADBEEF")]
|
||||
[InlineData(ItemKey.BLAKE3, true, false, "deadbeef")]
|
||||
[InlineData(ItemKey.BLAKE3, true, true, "deadbeef")]
|
||||
public void GetKeyDB_CustomImplementation(ItemKey bucketedBy, bool lower, bool norename, string expected)
|
||||
{
|
||||
Source source = new Source(0);
|
||||
@@ -383,7 +391,8 @@ namespace SabreTools.Metadata.DatItems.Test
|
||||
SHA256 = "DEADBEEF",
|
||||
SHA384 = "DEADBEEF",
|
||||
SHA512 = "DEADBEEF",
|
||||
SpamSum = "BASE64"
|
||||
SpamSum = "BASE64",
|
||||
BLAKE3 = "DEADBEEF",
|
||||
};
|
||||
|
||||
string actual = datItem.GetKey(bucketedBy, machine, source, lower, norename);
|
||||
|
||||
@@ -260,6 +260,10 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
[InlineData(ItemKey.SpamSum, false, true, "3::")]
|
||||
[InlineData(ItemKey.SpamSum, true, false, "3::")]
|
||||
[InlineData(ItemKey.SpamSum, true, true, "3::")]
|
||||
[InlineData(ItemKey.BLAKE3, false, false, "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")]
|
||||
[InlineData(ItemKey.BLAKE3, false, true, "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")]
|
||||
[InlineData(ItemKey.BLAKE3, true, false, "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")]
|
||||
[InlineData(ItemKey.BLAKE3, true, true, "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")]
|
||||
public void GetKeyDBTest(ItemKey bucketedBy, bool lower, bool norename, string expected)
|
||||
{
|
||||
Source source = new Source(0);
|
||||
|
||||
@@ -337,6 +337,10 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
[InlineData(ItemKey.SpamSum, false, true, "3::")]
|
||||
[InlineData(ItemKey.SpamSum, true, false, "3::")]
|
||||
[InlineData(ItemKey.SpamSum, true, true, "3::")]
|
||||
[InlineData(ItemKey.BLAKE3, false, false, "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")]
|
||||
[InlineData(ItemKey.BLAKE3, false, true, "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")]
|
||||
[InlineData(ItemKey.BLAKE3, true, false, "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")]
|
||||
[InlineData(ItemKey.BLAKE3, true, true, "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")]
|
||||
public void GetKeyDBTest(ItemKey bucketedBy, bool lower, bool norename, string expected)
|
||||
{
|
||||
Source source = new Source(0);
|
||||
|
||||
@@ -330,6 +330,10 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
[InlineData(ItemKey.SpamSum, false, true, "DEADBEEF")]
|
||||
[InlineData(ItemKey.SpamSum, true, false, "deadbeef")]
|
||||
[InlineData(ItemKey.SpamSum, true, true, "deadbeef")]
|
||||
[InlineData(ItemKey.BLAKE3, false, false, "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")]
|
||||
[InlineData(ItemKey.BLAKE3, false, true, "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")]
|
||||
[InlineData(ItemKey.BLAKE3, true, false, "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")]
|
||||
[InlineData(ItemKey.BLAKE3, true, true, "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")]
|
||||
public void GetKeyDBTest(ItemKey bucketedBy, bool lower, bool norename, string expected)
|
||||
{
|
||||
Source source = new Source(0);
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
Assert.Null(self.SHA384);
|
||||
Assert.Null(self.SHA512);
|
||||
Assert.Null(self.SpamSum);
|
||||
Assert.Null(self.BLAKE3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -49,7 +50,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = "sha256",
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum"
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
self.FillMissingInformation(other);
|
||||
@@ -67,6 +69,7 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
Assert.Equal("sha384", self.SHA384);
|
||||
Assert.Equal("sha512", self.SHA512);
|
||||
Assert.Equal("spamsum", self.SpamSum);
|
||||
Assert.Equal("blake3", self.BLAKE3);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -98,7 +101,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasHashes();
|
||||
@@ -122,7 +126,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasHashes();
|
||||
@@ -146,7 +151,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasHashes();
|
||||
@@ -170,7 +176,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasHashes();
|
||||
@@ -194,7 +201,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasHashes();
|
||||
@@ -218,7 +226,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasHashes();
|
||||
@@ -242,7 +251,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasHashes();
|
||||
@@ -266,7 +276,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasHashes();
|
||||
@@ -290,7 +301,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasHashes();
|
||||
@@ -314,7 +326,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = "sha256",
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasHashes();
|
||||
@@ -338,7 +351,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = "sha384",
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasHashes();
|
||||
@@ -362,7 +376,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = "sha512",
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasHashes();
|
||||
@@ -386,7 +401,33 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = "spamsum"
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasHashes();
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HasHashes_BLAKE3_True()
|
||||
{
|
||||
Rom self = new Rom
|
||||
{
|
||||
CRC16 = string.Empty,
|
||||
CRC32 = string.Empty,
|
||||
CRC64 = string.Empty,
|
||||
MD2 = string.Empty,
|
||||
MD4 = string.Empty,
|
||||
MD5 = string.Empty,
|
||||
RIPEMD128 = string.Empty,
|
||||
RIPEMD160 = string.Empty,
|
||||
SHA1 = string.Empty,
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HasHashes();
|
||||
@@ -410,7 +451,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = "sha256",
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum"
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HasHashes();
|
||||
@@ -446,7 +488,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = "sha256",
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum"
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -470,7 +513,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -494,7 +538,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -518,7 +563,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -542,7 +588,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -566,7 +613,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -590,7 +638,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -614,7 +663,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -638,7 +688,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -662,7 +713,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -686,7 +738,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = HashType.SHA256.ZeroString,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -710,7 +763,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = HashType.SHA384.ZeroString,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -734,7 +788,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = HashType.SHA512.ZeroString,
|
||||
SpamSum = string.Empty
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -758,7 +813,33 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = HashType.SpamSum.ZeroString
|
||||
SpamSum = HashType.SpamSum.ZeroString,
|
||||
BLAKE3 = string.Empty,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HasZeroHash_ZeroBLAKE3_True()
|
||||
{
|
||||
Rom self = new Rom
|
||||
{
|
||||
CRC16 = string.Empty,
|
||||
CRC32 = string.Empty,
|
||||
CRC64 = string.Empty,
|
||||
MD2 = string.Empty,
|
||||
MD4 = string.Empty,
|
||||
MD5 = string.Empty,
|
||||
RIPEMD128 = string.Empty,
|
||||
RIPEMD160 = string.Empty,
|
||||
SHA1 = string.Empty,
|
||||
SHA256 = string.Empty,
|
||||
SHA384 = string.Empty,
|
||||
SHA512 = string.Empty,
|
||||
SpamSum = string.Empty,
|
||||
BLAKE3 = HashType.BLAKE3.ZeroString,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -782,7 +863,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = HashType.SHA256.ZeroString,
|
||||
SHA384 = HashType.SHA384.ZeroString,
|
||||
SHA512 = HashType.SHA512.ZeroString,
|
||||
SpamSum = HashType.SpamSum.ZeroString
|
||||
SpamSum = HashType.SpamSum.ZeroString,
|
||||
BLAKE3 = HashType.BLAKE3.ZeroString,
|
||||
};
|
||||
|
||||
bool actual = self.HasZeroHash();
|
||||
@@ -855,6 +937,10 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
[InlineData(ItemKey.SpamSum, false, true, "DEADBEEF")]
|
||||
[InlineData(ItemKey.SpamSum, true, false, "deadbeef")]
|
||||
[InlineData(ItemKey.SpamSum, true, true, "deadbeef")]
|
||||
[InlineData(ItemKey.BLAKE3, false, false, "DEADBEEF")]
|
||||
[InlineData(ItemKey.BLAKE3, false, true, "DEADBEEF")]
|
||||
[InlineData(ItemKey.BLAKE3, true, false, "deadbeef")]
|
||||
[InlineData(ItemKey.BLAKE3, true, true, "deadbeef")]
|
||||
public void GetKeyDBTest(ItemKey bucketedBy, bool lower, bool norename, string expected)
|
||||
{
|
||||
Source source = new Source(0);
|
||||
@@ -875,7 +961,8 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
|
||||
SHA256 = "DEADBEEF",
|
||||
SHA384 = "DEADBEEF",
|
||||
SHA512 = "DEADBEEF",
|
||||
SpamSum = "DEADBEEF"
|
||||
SpamSum = "DEADBEEF",
|
||||
BLAKE3 = "DEADBEEF",
|
||||
};
|
||||
|
||||
string actual = datItem.GetKey(bucketedBy, machine, source, lower, norename);
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0;net11.0</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="[2.0.0]" />
|
||||
<PackageReference Include="coverlet.collector" Version="10.1.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.11.1" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="2.2.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="4.0.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -191,6 +191,10 @@ namespace SabreTools.Metadata.DatItems
|
||||
// Now determine what the key should be based on the bucketedBy value
|
||||
switch (bucketedBy)
|
||||
{
|
||||
case ItemKey.BLAKE3:
|
||||
key = HashType.BLAKE3.ZeroString;
|
||||
break;
|
||||
|
||||
case ItemKey.CRC16:
|
||||
key = HashType.CRC16.ZeroString;
|
||||
break;
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace SabreTools.Metadata.DatItems
|
||||
|
||||
Machine,
|
||||
|
||||
BLAKE3,
|
||||
CRC16,
|
||||
CRC32,
|
||||
CRC64,
|
||||
|
||||
@@ -74,6 +74,12 @@ namespace SabreTools.Metadata.DatItems.Formats
|
||||
set => _internal.BitTorrentMagnetHash = value;
|
||||
}
|
||||
|
||||
public string? BLAKE3
|
||||
{
|
||||
get => _internal.BLAKE3;
|
||||
set => _internal.BLAKE3 = value;
|
||||
}
|
||||
|
||||
public string? ClothCoverDetectionModuleVersion
|
||||
{
|
||||
get => _internal.ClothCoverDetectionModuleVersion;
|
||||
@@ -436,6 +442,12 @@ namespace SabreTools.Metadata.DatItems.Formats
|
||||
set => _internal.Status = value;
|
||||
}
|
||||
|
||||
public string? StatusMisc
|
||||
{
|
||||
get => _internal.StatusMisc;
|
||||
set => _internal.StatusMisc = value;
|
||||
}
|
||||
|
||||
public string? Summation
|
||||
{
|
||||
get => _internal.Summation;
|
||||
@@ -858,6 +870,10 @@ namespace SabreTools.Metadata.DatItems.Formats
|
||||
// Now determine what the key should be based on the bucketedBy value
|
||||
switch (bucketedBy)
|
||||
{
|
||||
case ItemKey.BLAKE3:
|
||||
key = BLAKE3;
|
||||
break;
|
||||
|
||||
case ItemKey.CRC16:
|
||||
key = CRC16;
|
||||
break;
|
||||
|
||||
@@ -320,6 +320,12 @@ namespace SabreTools.Metadata.DatItems
|
||||
set => _internal.Serial = value;
|
||||
}
|
||||
|
||||
public string? SetType
|
||||
{
|
||||
get => _internal.SetType;
|
||||
set => _internal.SetType = value;
|
||||
}
|
||||
|
||||
public string? Source
|
||||
{
|
||||
get => _internal.Source;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;net11.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
@@ -12,7 +12,7 @@
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>3.0.1</Version>
|
||||
<Version>3.3.0</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
@@ -32,8 +32,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="[2.0.0]" />
|
||||
<PackageReference Include="SabreTools.IO" Version="[2.1.0]" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="2.2.0" />
|
||||
<PackageReference Include="SabreTools.IO" Version="2.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using SabreTools.Data.Models.Metadata;
|
||||
using SabreTools.Hashing;
|
||||
using Xunit;
|
||||
@@ -1022,6 +1023,20 @@ namespace SabreTools.Metadata.Filter.Test
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("en-US")]
|
||||
[InlineData("de-DE")]
|
||||
[InlineData("fr-FR")]
|
||||
public void Matches_DisplayRefresh_CurrentCultureIgnored(string culture)
|
||||
{
|
||||
CultureInfo.CurrentCulture = new CultureInfo(culture);
|
||||
var filter = new FilterObject("display.refresh", "123.45", Operation.Equals);
|
||||
Display obj = new Display { Refresh = 123.45 };
|
||||
|
||||
bool actual = filter.Matches(obj);
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Driver
|
||||
@@ -1103,6 +1118,7 @@ namespace SabreTools.Metadata.Filter.Test
|
||||
[InlineData("header.datversion", "datversion")]
|
||||
[InlineData("header.debug", "yes")]
|
||||
[InlineData("header.description", "description")]
|
||||
[InlineData("header.dir", "noautodir")]
|
||||
[InlineData("header.email", "email")]
|
||||
[InlineData("header.emulatorversion", "emulatorversion")]
|
||||
[InlineData("header.filename", "filename")]
|
||||
@@ -1131,6 +1147,7 @@ namespace SabreTools.Metadata.Filter.Test
|
||||
[InlineData("header.schemalocation", "schemalocation")]
|
||||
[InlineData("header.screenshotsheight", "screenshotsheight")]
|
||||
[InlineData("header.screenshotswidth", "screenshotswidth")]
|
||||
[InlineData("header.subset", "subset")]
|
||||
[InlineData("header.system", "system")]
|
||||
[InlineData("header.timestamp", "timestamp")]
|
||||
[InlineData("header.type", "type")]
|
||||
@@ -1150,6 +1167,7 @@ namespace SabreTools.Metadata.Filter.Test
|
||||
DatVersion = "datversion",
|
||||
Debug = true,
|
||||
Description = "description",
|
||||
DirHandling = "noautodir",
|
||||
Email = "email",
|
||||
EmulatorVersion = "emulatorversion",
|
||||
FileName = "filename",
|
||||
@@ -1176,6 +1194,7 @@ namespace SabreTools.Metadata.Filter.Test
|
||||
SchemaLocation = "schemalocation",
|
||||
ScreenshotsHeight = "screenshotsheight",
|
||||
ScreenshotsWidth = "screenshotswidth",
|
||||
Subset = "subset",
|
||||
System = "system",
|
||||
Timestamp = "timestamp",
|
||||
Type = "type",
|
||||
@@ -1290,6 +1309,8 @@ namespace SabreTools.Metadata.Filter.Test
|
||||
[InlineData("machine.sampleof", "sampleof")]
|
||||
[InlineData("machine.savetype", "savetype")]
|
||||
[InlineData("machine.score", "score")]
|
||||
[InlineData("machine.serial", "serial")]
|
||||
[InlineData("machine.settype", "dir")]
|
||||
[InlineData("machine.source", "source")]
|
||||
[InlineData("machine.sourcefile", "sourcefile")]
|
||||
[InlineData("machine.sourcerom", "sourcerom")]
|
||||
@@ -1360,6 +1381,7 @@ namespace SabreTools.Metadata.Filter.Test
|
||||
SaveType = "savetype",
|
||||
Score = "score",
|
||||
Serial = "serial",
|
||||
SetType = "dir",
|
||||
Source = "source",
|
||||
SourceFile = "sourcefile",
|
||||
SourceRom = "sourcerom",
|
||||
@@ -1582,6 +1604,7 @@ namespace SabreTools.Metadata.Filter.Test
|
||||
[InlineData("rom.bitrate", "bitrate")]
|
||||
[InlineData("rom.bittorrentmagnethash", "btih")]
|
||||
[InlineData("rom.btih", "btih")]
|
||||
[InlineData("rom.blake3", "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262")]
|
||||
[InlineData("rom.cloth_cover_detection_module_version", "cloth_cover_detection_module_version")]
|
||||
[InlineData("rom.clothcoverdetectionmoduleversion", "cloth_cover_detection_module_version")]
|
||||
[InlineData("rom.collection-catalog-number", "collection-catalog-number")]
|
||||
@@ -1653,6 +1676,7 @@ namespace SabreTools.Metadata.Filter.Test
|
||||
[InlineData("rom.spamsum", "3::")]
|
||||
[InlineData("rom.start", "start")]
|
||||
[InlineData("rom.status", "good")]
|
||||
[InlineData("rom.status_misc", "status")]
|
||||
[InlineData("rom.summation", "summation")]
|
||||
[InlineData("rom.ocr", "ocr")]
|
||||
[InlineData("rom.tesseractocr", "ocr")]
|
||||
@@ -1719,6 +1743,7 @@ namespace SabreTools.Metadata.Filter.Test
|
||||
Bios = "bios",
|
||||
Bitrate = "bitrate",
|
||||
BitTorrentMagnetHash = "btih",
|
||||
BLAKE3 = HashType.BLAKE3.ZeroString,
|
||||
ClothCoverDetectionModuleVersion = "cloth_cover_detection_module_version",
|
||||
CollectionCatalogNumber = "collection-catalog-number",
|
||||
Comment = "comment",
|
||||
@@ -1776,6 +1801,7 @@ namespace SabreTools.Metadata.Filter.Test
|
||||
SpamSum = HashType.SpamSum.ZeroString,
|
||||
Start = "start",
|
||||
Status = ItemStatus.Good,
|
||||
StatusMisc = "status",
|
||||
Summation = "summation",
|
||||
TesseractOCR = "ocr",
|
||||
TesseractOCRConverted = "ocr_converted",
|
||||
@@ -2074,6 +2100,20 @@ namespace SabreTools.Metadata.Filter.Test
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("en-US")]
|
||||
[InlineData("de-DE")]
|
||||
[InlineData("fr-FR")]
|
||||
public void Matches_VideoRefresh_CurrentCultureIgnored(string culture)
|
||||
{
|
||||
CultureInfo.CurrentCulture = new CultureInfo(culture);
|
||||
var filter = new FilterObject("video.refresh", "123.45", Operation.Equals);
|
||||
Video obj = new Video { Refresh = 123.45 };
|
||||
|
||||
bool actual = filter.Matches(obj);
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0;net11.0</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -18,10 +19,16 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="10.1.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.9.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="4.0.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -309,6 +309,8 @@ namespace SabreTools.Metadata.Filter
|
||||
"datversion",
|
||||
"debug",
|
||||
"description",
|
||||
"dir",
|
||||
"dirhandling",
|
||||
"email",
|
||||
"emulatorversion",
|
||||
"filename",
|
||||
@@ -337,6 +339,7 @@ namespace SabreTools.Metadata.Filter
|
||||
"screenshotsheight",
|
||||
"screenshotswidth",
|
||||
"skipper",
|
||||
"subset",
|
||||
"system",
|
||||
"timestamp",
|
||||
"type",
|
||||
@@ -421,6 +424,8 @@ namespace SabreTools.Metadata.Filter
|
||||
"sampleof",
|
||||
"savetype",
|
||||
"score",
|
||||
"serial",
|
||||
"settype",
|
||||
"source",
|
||||
"sourcefile",
|
||||
"sourcerom",
|
||||
@@ -540,6 +545,7 @@ namespace SabreTools.Metadata.Filter
|
||||
"bitrate",
|
||||
"bittorrentmagnethash",
|
||||
"btih",
|
||||
"blake3",
|
||||
"cloth_cover_detection_module_version",
|
||||
"clothcoverdetectionmoduleversion",
|
||||
"collection-catalog-number",
|
||||
@@ -619,6 +625,7 @@ namespace SabreTools.Metadata.Filter
|
||||
"spamsum",
|
||||
"start",
|
||||
"status",
|
||||
"status_misc",
|
||||
"summation",
|
||||
"tesseractocr",
|
||||
"tesseractocrconverted",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using SabreTools.Data.Extensions;
|
||||
using SabreTools.Data.Models.Metadata;
|
||||
@@ -1134,7 +1135,7 @@ namespace SabreTools.Metadata.Filter
|
||||
return true;
|
||||
case "refresh":
|
||||
case "freq":
|
||||
checkValue = obj.Refresh?.ToString();
|
||||
checkValue = obj.Refresh?.ToString(CultureInfo.InvariantCulture);
|
||||
return true;
|
||||
case "rotate":
|
||||
case "orientation":
|
||||
@@ -1280,6 +1281,10 @@ namespace SabreTools.Metadata.Filter
|
||||
case "description":
|
||||
checkValue = obj.Description;
|
||||
return true;
|
||||
case "dir":
|
||||
case "dirhandling":
|
||||
checkValue = obj.DirHandling;
|
||||
return true;
|
||||
case "email":
|
||||
checkValue = obj.Email;
|
||||
return true;
|
||||
@@ -1365,6 +1370,9 @@ namespace SabreTools.Metadata.Filter
|
||||
checkValue = obj.ScreenshotsWidth;
|
||||
return true;
|
||||
// Header.Search is intentionally skipped
|
||||
case "subset":
|
||||
checkValue = obj.Subset;
|
||||
return true;
|
||||
case "system":
|
||||
checkValue = obj.System;
|
||||
return true;
|
||||
@@ -1603,6 +1611,9 @@ namespace SabreTools.Metadata.Filter
|
||||
case "serial":
|
||||
checkValue = obj.Serial;
|
||||
return true;
|
||||
case "settype":
|
||||
checkValue = obj.SetType;
|
||||
return true;
|
||||
case "source":
|
||||
checkValue = obj.Source;
|
||||
return true;
|
||||
@@ -1901,6 +1912,9 @@ namespace SabreTools.Metadata.Filter
|
||||
case "bittorrentmagnethash":
|
||||
checkValue = obj.BitTorrentMagnetHash;
|
||||
return true;
|
||||
case "blake3":
|
||||
checkValue = obj.BLAKE3;
|
||||
return true;
|
||||
case "cloth_cover_detection_module_version":
|
||||
case "clothcoverdetectionmoduleversion":
|
||||
checkValue = obj.ClothCoverDetectionModuleVersion;
|
||||
@@ -2086,6 +2100,9 @@ namespace SabreTools.Metadata.Filter
|
||||
case "status":
|
||||
checkValue = obj.Status?.AsStringValue();
|
||||
return true;
|
||||
case "status_misc":
|
||||
checkValue = obj.StatusMisc;
|
||||
return true;
|
||||
case "summation":
|
||||
checkValue = obj.Summation;
|
||||
return true;
|
||||
@@ -2496,7 +2513,7 @@ namespace SabreTools.Metadata.Filter
|
||||
return true;
|
||||
case "refresh":
|
||||
case "freq":
|
||||
checkValue = obj.Refresh?.ToString();
|
||||
checkValue = obj.Refresh?.ToString(CultureInfo.InvariantCulture);
|
||||
return true;
|
||||
case "displaytype":
|
||||
case "screen":
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;net11.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
@@ -12,7 +12,7 @@
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>3.0.1</Version>
|
||||
<Version>3.3.0</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
@@ -36,7 +36,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SabreTools.IO" Version="[2.1.0]" />
|
||||
<PackageReference Include="SabreTools.IO" Version="2.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;net11.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
@@ -13,7 +13,7 @@
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>3.0.1</Version>
|
||||
<Version>3.3.0</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
@@ -37,8 +37,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SabreTools.Hashing" Version="[2.0.0]" />
|
||||
<PackageReference Include="SabreTools.IO" Version="[2.1.0]" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="2.2.0" />
|
||||
<PackageReference Include="SabreTools.IO" Version="2.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,17 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0;net11.0</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="10.1.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.11.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="4.0.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;net11.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
@@ -12,7 +12,7 @@
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>3.0.1</Version>
|
||||
<Version>3.3.0</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
|
||||
@@ -115,6 +115,7 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
xxHash364 = "xxhash364",
|
||||
xxHash3128 = "xxhash3128",
|
||||
Region = "region",
|
||||
@@ -378,6 +379,7 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
Assert.Equal("sha384", rom.SHA384);
|
||||
Assert.Equal("sha512", rom.SHA512);
|
||||
Assert.Equal("spamsum", rom.SpamSum);
|
||||
Assert.Equal("blake3", rom.BLAKE3);
|
||||
Assert.Equal("xxhash364", rom.xxHash364);
|
||||
Assert.Equal("xxhash3128", rom.xxHash3128);
|
||||
Assert.Equal("region", rom.Region);
|
||||
|
||||
@@ -213,6 +213,29 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
Validate(newSpamsum);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RoundTripBLAKE3Test()
|
||||
{
|
||||
// Get the cross-model serializer
|
||||
var serializer = new Hashfile();
|
||||
|
||||
// Build the data
|
||||
Data.Models.Hashfile.Hashfile hf = Build(HashType.BLAKE3);
|
||||
|
||||
// Serialize to generic model
|
||||
Data.Models.Metadata.MetadataFile? metadata = serializer.Serialize(hf);
|
||||
Assert.NotNull(metadata);
|
||||
|
||||
// Serialize back to original model
|
||||
Data.Models.Hashfile.Hashfile? newHf = serializer.Deserialize(metadata, HashType.BLAKE3);
|
||||
|
||||
// Validate the data
|
||||
Assert.NotNull(newHf);
|
||||
Assert.NotNull(newHf.BLAKE3);
|
||||
var newBlake3 = Assert.Single(newHf.BLAKE3);
|
||||
Validate(newBlake3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build model for serialization and deserialization
|
||||
/// </summary>
|
||||
@@ -236,6 +259,8 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
return new Data.Models.Hashfile.Hashfile { SHA512 = [new Data.Models.Hashfile.SHA512 { Hash = "hash", File = "file" }] };
|
||||
else if (hashType == HashType.SpamSum)
|
||||
return new Data.Models.Hashfile.Hashfile { SpamSum = [new Data.Models.Hashfile.SpamSum { Hash = "hash", File = "file" }] };
|
||||
else if (hashType == HashType.BLAKE3)
|
||||
return new Data.Models.Hashfile.Hashfile { BLAKE3 = [new Data.Models.Hashfile.BLAKE3 { Hash = "hash", File = "file" }] };
|
||||
else
|
||||
throw new ArgumentOutOfRangeException(nameof(hashType));
|
||||
}
|
||||
@@ -329,5 +354,15 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
Assert.Equal("hash", spamsum.Hash);
|
||||
Assert.Equal("file", spamsum.File);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate a BLAKE3
|
||||
/// </summary>
|
||||
private static void Validate(Data.Models.Hashfile.BLAKE3? blake3)
|
||||
{
|
||||
Assert.NotNull(blake3);
|
||||
Assert.Equal("hash", blake3.Hash);
|
||||
Assert.Equal("file", blake3.File);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
ForceMerging = Data.Models.Metadata.MergingFlag.Merged,
|
||||
ForceNodump = Data.Models.Metadata.NodumpFlag.Required,
|
||||
ForcePacking = Data.Models.Metadata.PackingFlag.Zip,
|
||||
Dir = "noautodir",
|
||||
};
|
||||
|
||||
var clrmamepro = new Data.Models.Logiqx.ClrMamePro
|
||||
@@ -115,6 +116,7 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
Url = "url",
|
||||
Comment = "comment",
|
||||
Type = "type",
|
||||
Subset = "subset",
|
||||
RomVault = romvault,
|
||||
ClrMamePro = clrmamepro,
|
||||
RomCenter = romcenter,
|
||||
@@ -171,6 +173,7 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
SHA384 = "sha384",
|
||||
SHA512 = "sha512",
|
||||
SpamSum = "spamsum",
|
||||
BLAKE3 = "blake3",
|
||||
xxHash364 = "xxhash364",
|
||||
xxHash3128 = "xxhash3128",
|
||||
Merge = "merge",
|
||||
@@ -252,6 +255,7 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
gameBase.Id = "id";
|
||||
gameBase.CloneOfId = "cloneofid";
|
||||
gameBase.Runnable = Data.Models.Metadata.Runnable.Yes;
|
||||
gameBase.SetType = "dir";
|
||||
gameBase.Comment = ["comment"];
|
||||
gameBase.Description = "description";
|
||||
gameBase.Year = "year";
|
||||
@@ -314,6 +318,7 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
Assert.Equal("url", header.Url);
|
||||
Assert.Equal("comment", header.Comment);
|
||||
Assert.Equal("type", header.Type);
|
||||
Assert.Equal("subset", header.Subset);
|
||||
Validate(header.RomVault);
|
||||
Validate(header.ClrMamePro);
|
||||
Validate(header.RomCenter);
|
||||
@@ -329,6 +334,7 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
Assert.Equal(Data.Models.Metadata.MergingFlag.Merged, rv.ForceMerging);
|
||||
Assert.Equal(Data.Models.Metadata.NodumpFlag.Required, rv.ForceNodump);
|
||||
Assert.Equal(Data.Models.Metadata.PackingFlag.Zip, rv.ForcePacking);
|
||||
Assert.Equal("noautodir", rv.Dir);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -380,6 +386,7 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
Assert.Equal("id", gb.Id);
|
||||
Assert.Equal("cloneofid", gb.CloneOfId);
|
||||
Assert.Equal(Data.Models.Metadata.Runnable.Yes, gb.Runnable);
|
||||
Assert.Equal("dir", gb.SetType);
|
||||
|
||||
Assert.NotNull(gb.Comment);
|
||||
string comment = Assert.Single(gb.Comment);
|
||||
@@ -504,6 +511,7 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
Assert.Equal("sha384", rom.SHA384);
|
||||
Assert.Equal("sha512", rom.SHA512);
|
||||
Assert.Equal("spamsum", rom.SpamSum);
|
||||
Assert.Equal("blake3", rom.BLAKE3);
|
||||
Assert.Equal("xxhash364", rom.xxHash364);
|
||||
Assert.Equal("xxhash3128", rom.xxHash3128);
|
||||
Assert.Equal("merge", rom.Merge);
|
||||
|
||||
@@ -40,11 +40,19 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
Content = "content",
|
||||
};
|
||||
|
||||
var standalone_rom = new Data.Models.OpenMSX.Rom
|
||||
{
|
||||
SHA1 = "sha1",
|
||||
Type = "type",
|
||||
Status = "status",
|
||||
Remark = "remark",
|
||||
};
|
||||
|
||||
var rom = new Data.Models.OpenMSX.Rom
|
||||
{
|
||||
Start = "start",
|
||||
Type = "type",
|
||||
Hash = "hash",
|
||||
SHA1 = "hash",
|
||||
Remark = "remark",
|
||||
};
|
||||
|
||||
@@ -59,7 +67,7 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
{
|
||||
Start = "start",
|
||||
Type = "type",
|
||||
Hash = "hash",
|
||||
SHA1 = "hash",
|
||||
Remark = "remark",
|
||||
};
|
||||
|
||||
@@ -74,7 +82,7 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
{
|
||||
Start = "start",
|
||||
Type = "type",
|
||||
Hash = "hash",
|
||||
SHA1 = "hash",
|
||||
Remark = "remark",
|
||||
};
|
||||
|
||||
@@ -94,6 +102,7 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
Year = "year",
|
||||
Country = "country",
|
||||
Dump = [dump_rom, dump_megarom, dump_sccpluscart],
|
||||
Rom = [standalone_rom],
|
||||
};
|
||||
|
||||
return new Data.Models.OpenMSX.SoftwareDb
|
||||
@@ -122,6 +131,10 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
{
|
||||
Validate(dump);
|
||||
}
|
||||
|
||||
Assert.NotNull(software.Rom);
|
||||
var rom = Assert.Single(software.Rom);
|
||||
ValidateStandalone(rom);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -154,7 +167,19 @@ namespace SabreTools.Serialization.CrossModel.Test
|
||||
Assert.NotNull(rombase);
|
||||
Assert.Equal("start", rombase.Start);
|
||||
Assert.Equal("type", rombase.Type);
|
||||
Assert.Equal("hash", rombase.Hash);
|
||||
Assert.Equal("hash", rombase.SHA1);
|
||||
Assert.Equal("remark", rombase.Remark);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate a RomBase
|
||||
/// </summary>
|
||||
private static void ValidateStandalone(Data.Models.OpenMSX.RomBase? rombase)
|
||||
{
|
||||
Assert.NotNull(rombase);
|
||||
Assert.Equal("sha1", rombase.SHA1);
|
||||
Assert.Equal("type", rombase.Type);
|
||||
Assert.Equal("status", rombase.Status);
|
||||
Assert.Equal("remark", rombase.Remark);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0;net11.0</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="[2.0.0]" />
|
||||
<PackageReference Include="coverlet.collector" Version="10.1.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.11.1" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="2.2.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="4.0.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -290,6 +290,7 @@ namespace SabreTools.Serialization.CrossModel
|
||||
SHA384 = item.SHA384,
|
||||
SHA512 = item.SHA512,
|
||||
SpamSum = item.SpamSum,
|
||||
BLAKE3 = item.BLAKE3,
|
||||
xxHash364 = item.xxHash364,
|
||||
xxHash3128 = item.xxHash3128,
|
||||
Merge = item.Merge,
|
||||
|
||||
@@ -270,6 +270,7 @@ namespace SabreTools.Serialization.CrossModel
|
||||
SHA384 = item.SHA384,
|
||||
SHA512 = item.SHA512,
|
||||
SpamSum = item.SpamSum,
|
||||
BLAKE3 = item.BLAKE3,
|
||||
xxHash364 = item.xxHash364,
|
||||
xxHash3128 = item.xxHash3128,
|
||||
Merge = item.Merge,
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace SabreTools.Serialization.CrossModel
|
||||
var sha384s = new List<SHA384>();
|
||||
var sha512s = new List<SHA512>();
|
||||
var spamsums = new List<SpamSum>();
|
||||
var blake3s = new List<BLAKE3>();
|
||||
|
||||
foreach (var hashfile in hashfiles)
|
||||
{
|
||||
@@ -61,6 +62,8 @@ namespace SabreTools.Serialization.CrossModel
|
||||
sha512s.AddRange(hashfile.SHA512);
|
||||
if (hashfile.SpamSum is not null && hashfile.SpamSum.Length > 0)
|
||||
spamsums.AddRange(hashfile.SpamSum);
|
||||
if (hashfile.BLAKE3 is not null && hashfile.BLAKE3.Length > 0)
|
||||
blake3s.AddRange(hashfile.BLAKE3);
|
||||
}
|
||||
|
||||
var hashfileItem = new Data.Models.Hashfile.Hashfile();
|
||||
@@ -87,6 +90,8 @@ namespace SabreTools.Serialization.CrossModel
|
||||
hashfileItem.SHA512 = [.. sha512s];
|
||||
if (spamsums.Count > 0)
|
||||
hashfileItem.SpamSum = [.. spamsums];
|
||||
if (blake3s.Count > 0)
|
||||
hashfileItem.BLAKE3 = [.. blake3s];
|
||||
|
||||
return hashfileItem;
|
||||
}
|
||||
@@ -135,6 +140,14 @@ namespace SabreTools.Serialization.CrossModel
|
||||
SpamSum = hash == HashType.SpamSum
|
||||
? Array.ConvertAll(roms, ConvertToSpamSum)
|
||||
: null,
|
||||
#if NET7_0_OR_GREATER
|
||||
BLAKE3 = hash == HashType.BLAKE3
|
||||
#else
|
||||
// HACK because BLAKE3 is not supported below .NET 7
|
||||
BLAKE3 = hash == HashType.CRC1_ZERO
|
||||
#endif
|
||||
? Array.ConvertAll(roms, ConvertToBLAKE3)
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -280,5 +293,18 @@ namespace SabreTools.Serialization.CrossModel
|
||||
};
|
||||
return spamsum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert from <see cref="Models.Metadata.Rom"/> to <see cref="BLAKE3"/>
|
||||
/// </summary>
|
||||
private static BLAKE3 ConvertToBLAKE3(Data.Models.Metadata.Rom item)
|
||||
{
|
||||
var spamsum = new BLAKE3
|
||||
{
|
||||
Hash = item.BLAKE3,
|
||||
File = item.Name,
|
||||
};
|
||||
return spamsum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user